Элементы управления камерой вручную для захвата фотографий и видео
В этой статье показано, как использовать элементы управления устройствами вручную для включения расширенных сценариев фото и видеосъемки, включая стабилизацию оптического изображения и плавное масштабирование.
Элементы управления, рассмотренные в этой статье, добавляются в приложение с помощью одного и того же шаблона. Сначала проверьте, поддерживается ли элемент управления на текущем устройстве, на котором работает ваше приложение. Если элемент управления поддерживается, задайте нужный режим для элемента управления. Как правило, если определенный элемент управления не поддерживается на текущем устройстве, следует отключить или скрыть элемент пользовательского интерфейса, позволяющий пользователю включить эту функцию.
Код, приведенный в этой статье, был адаптирован из примера пакета SDK для элементов управления камерой вручную. Вы можете скачать пример, чтобы увидеть код, используемый в контексте, или использовать этот пример в качестве отправной точки для собственного приложения.
Примечание.
В этой статье рассматриваются основные понятия и код, описанные в разделе "Базовый" фото, видео и аудиозапись с помощью MediaCapture, в котором описаны шаги по реализации базового фото и видеозахвата. Рекомендуется ознакомиться с основным шаблоном захвата мультимедиа в этой статье, прежде чем перейти к более сложным сценариям захвата. В коде этой статьи предполагается, что приложение уже имеет экземпляр MediaCapture, который был правильно инициализирован.
Все API управления устройствами, рассмотренные в этой статье, являются членами пространства имен Windows.Media.Devices.
using Windows.Media.Devices;
Экспозиция
Функция ExposureControl позволяет задать скорость затвора, используемую во время фото- или видеоснимка.
В этом примере используется ползунок для настройки текущего значения экспозиции и флажка для переключения автоматической настройки экспозиции.
<Slider Name="ExposureSlider" ValueChanged="ExposureSlider_ValueChanged"/>
<TextBlock Name="ExposureTextBlock" Text="{Binding ElementName=ExposureSlider,Path=Value}"/>
<CheckBox Name="ExposureAutoCheckBox" Content="Auto" Checked="ExposureCheckBox_CheckedChanged" Unchecked="ExposureCheckBox_CheckedChanged"/>
Проверьте, поддерживает ли текущее устройство захвата Объект ExposureControl , проверив поддерживаемое свойство. Если элемент управления поддерживается, можно отобразить и включить пользовательский интерфейс для этой функции. Установите установленное состояние флажка, чтобы указать, активна ли автоматическая корректировка экспозиции в настоящее время для значения свойства Auto.
Значение экспозиции должно находиться в диапазоне, поддерживаемом устройством, и должно быть увеличением поддерживаемого размера шага. Получите поддерживаемые значения для текущего устройства, проверив свойства Min, Max и Step, которые используются для задания соответствующих свойств элемента управления ползунка.
Задайте для элемента управления ползунок текущее значение Объекта ExposureControl после отмены регистрации обработчика событий ValueChanged, чтобы событие не активировало при установке значения.
var exposureControl = _mediaCapture.VideoDeviceController.ExposureControl;
if (exposureControl.Supported)
{
ExposureAutoCheckBox.Visibility = Visibility.Visible;
ExposureSlider.Visibility = Visibility.Visible;
ExposureAutoCheckBox.IsChecked = exposureControl.Auto;
ExposureSlider.Minimum = exposureControl.Min.Ticks;
ExposureSlider.Maximum = exposureControl.Max.Ticks;
ExposureSlider.StepFrequency = exposureControl.Step.Ticks;
ExposureSlider.ValueChanged -= ExposureSlider_ValueChanged;
var value = exposureControl.Value;
ExposureSlider.Value = value.Ticks;
ExposureSlider.ValueChanged += ExposureSlider_ValueChanged;
}
else
{
ExposureAutoCheckBox.Visibility = Visibility.Collapsed;
ExposureSlider.Visibility = Visibility.Collapsed;
}
В обработчике событий ValueChanged получите текущее значение элемента управления и задайте значение экспозиции путем вызова SetValueAsync.
private async void ExposureSlider_ValueChanged(object sender, Windows.UI.Xaml.Controls.Primitives.RangeBaseValueChangedEventArgs e)
{
var value = TimeSpan.FromTicks((long)(sender as Slider).Value);
await _mediaCapture.VideoDeviceController.ExposureControl.SetValueAsync(value);
}
В обработчике событий CheckedChanged флажка автоматического воздействия включите или отключите автоматическую настройку экспозиции, вызвав SetAutoAsync и передав логическое значение.
private async void ExposureCheckBox_CheckedChanged(object sender, RoutedEventArgs e)
{
if(! _isPreviewing)
{
// Auto exposure only supported while preview stream is running.
return;
}
var autoExposure = ((sender as CheckBox).IsChecked == true);
await _mediaCapture.VideoDeviceController.ExposureControl.SetAutoAsync(autoExposure);
}
Внимание
Режим автоматической экспозиции поддерживается только во время выполнения потока предварительной версии. Убедитесь, что поток предварительной версии запущен перед включением автоматического воздействия.
Компенсация воздействия
Функция ExposureControl позволяет задать компенсацию воздействия, используемую во время фото или видеосъемки.
В этом примере используется элемент управления Ползунок для настройки текущего значения компенсации воздействия.
<Slider Name="EvSlider" ValueChanged="EvSlider_ValueChanged"/>
<TextBlock Text="{Binding ElementName=EvSlider,Path=Value}" Name="EvTextBlock"/>
Проверьте, поддерживает ли текущее устройство записи Объект ExposureControl , проверив поддерживаемое свойство. Если элемент управления поддерживается, можно отобразить и включить пользовательский интерфейс для этой функции.
Значение компенсации воздействия должно находиться в диапазоне, поддерживаемом устройством, и должно быть увеличением поддерживаемого размера шага. Получите поддерживаемые значения для текущего устройства, проверив свойства Min, Max и Step, которые используются для задания соответствующих свойств элемента управления ползунка.
Задайте для элемента управления ползунка текущее значение Объекта ExposureControl после отмены регистрации обработчика событий ValueChanged, чтобы событие не активировался при установке значения.
var exposureCompensationControl = _mediaCapture.VideoDeviceController.ExposureCompensationControl;
if (exposureCompensationControl.Supported)
{
EvSlider.Visibility = Visibility.Visible;
EvSlider.Minimum = exposureCompensationControl.Min;
EvSlider.Maximum = exposureCompensationControl.Max;
EvSlider.StepFrequency = exposureCompensationControl.Step;
EvSlider.ValueChanged -= EvSlider_ValueChanged;
EvSlider.Value = exposureCompensationControl.Value;
EvSlider.ValueChanged += EvSlider_ValueChanged;
}
else
{
EvSlider.Visibility = Visibility.Collapsed;
}
В обработчике событий ValueChanged получите текущее значение элемента управления и задайте значение экспозиции путем вызова SetValueAsync.
private async void EvSlider_ValueChanged(object sender, Windows.UI.Xaml.Controls.Primitives.RangeBaseValueChangedEventArgs e)
{
var value = (sender as Slider).Value;
await _mediaCapture.VideoDeviceController.ExposureCompensationControl.SetValueAsync((float)value);
}
Flash
FlashControl позволяет включить или отключить вспышку или включить автоматическую вспышку, где система динамически определяет, следует ли использовать вспышку. Этот элемент управления также позволяет включить автоматическое сокращение красных глаз на устройствах, поддерживающих его. Все эти параметры применяются к записи фотографий. TorchControl — это отдельный элемент управления для включения или выключения факела для записи видео.
В этом примере используется набор переключателей, позволяющий пользователю переключаться между параметрами включения, отключения и автоматической вспышки. Также предоставляется флажок, позволяющий переключаться на сокращение красных глаз и видео факел.
<RadioButton Name="FlashOnRadioButton" Content="On" Checked="FlashOnRadioButton_Checked"/>
<RadioButton Name="FlashAutoRadioButton" Content="Auto" Checked="FlashAutoRadioButton_Checked"/>
<RadioButton Name="FlashOffRadioButton" Content="Off" Checked="FlashOffRadioButton_Checked"/>
<CheckBox Name="RedEyeFlashCheckBox" Content="Red Eye" Visibility="Collapsed" Checked="RedEyeFlashCheckBox_CheckedChanged" Unchecked="RedEyeFlashCheckBox_CheckedChanged"/>
<CheckBox Name="TorchCheckBox" Content="Video Light" Visibility="Collapsed" Checked="TorchCheckBox_CheckedChanged" Unchecked="TorchCheckBox_CheckedChanged"/>
Проверьте, поддерживает ли текущее устройство записи FlashControl , проверив поддерживаемое свойство. Если элемент управления поддерживается, можно отобразить и включить пользовательский интерфейс для этой функции. Если flashControl поддерживается, автоматическое сокращение красных глаз может быть или не поддерживается, поэтому перед включением пользовательского интерфейса проверьте свойство RedEyeReductionSupported. Так как TorchControl отличается от элемента управления флэш-памятью, необходимо также проверить его поддерживаемое свойство перед его использованием.
В обработчике событий Checked для каждой из переключателей флэш-памяти включите или отключите соответствующий параметр флэш-памяти. Обратите внимание, что для постоянного использования флэш-памяти необходимо задать для свойства Enabled значение true, а свойство Auto — false.
var flashControl = _mediaCapture.VideoDeviceController.FlashControl;
if (flashControl.Supported)
{
FlashAutoRadioButton.Visibility = Visibility.Visible;
FlashOnRadioButton.Visibility = Visibility.Visible;
FlashOffRadioButton.Visibility = Visibility.Visible;
FlashAutoRadioButton.IsChecked = true;
if (flashControl.RedEyeReductionSupported)
{
RedEyeFlashCheckBox.Visibility = Visibility.Visible;
}
// Video light is not strictly part of flash, but users might expect to find it there
if (_mediaCapture.VideoDeviceController.TorchControl.Supported)
{
TorchCheckBox.Visibility = Visibility.Visible;
}
}
else
{
FlashAutoRadioButton.Visibility = Visibility.Collapsed;
FlashOnRadioButton.Visibility = Visibility.Collapsed;
FlashOffRadioButton.Visibility = Visibility.Collapsed;
}
private void FlashOnRadioButton_Checked(object sender, RoutedEventArgs e)
{
_mediaCapture.VideoDeviceController.FlashControl.Enabled = true;
_mediaCapture.VideoDeviceController.FlashControl.Auto = false;
}
private void FlashAutoRadioButton_Checked(object sender, RoutedEventArgs e)
{
_mediaCapture.VideoDeviceController.FlashControl.Enabled = true;
_mediaCapture.VideoDeviceController.FlashControl.Auto = true;
}
private void FlashOffRadioButton_Checked(object sender, RoutedEventArgs e)
{
_mediaCapture.VideoDeviceController.FlashControl.Enabled = false;
}
В обработчике для флажка сокращения красных глаз задайте для свойства RedEyeReduction соответствующее значение.
private void RedEyeFlashCheckBox_CheckedChanged(object sender, RoutedEventArgs e)
{
_mediaCapture.VideoDeviceController.FlashControl.RedEyeReduction = (RedEyeFlashCheckBox.IsChecked == true);
}
Наконец, в обработчике для флажка "Факел видео" задайте для свойства Enabled соответствующее значение.
private void TorchCheckBox_CheckedChanged(object sender, RoutedEventArgs e)
{
_mediaCapture.VideoDeviceController.TorchControl.Enabled = (TorchCheckBox.IsChecked == true);
if(! (_isPreviewing && _isRecording))
{
System.Diagnostics.Debug.WriteLine("Torch may not emit light if preview and video capture are not running.");
}
}
Примечание.
На некоторых устройствах факел не будет выдавать свет, даже если параметр TorchControl.Enabled имеет значение true, если устройство не имеет предварительного просмотра потоков и активно записывает видео. Рекомендуемый порядок операций — включить предварительный просмотр видео, включить факел, установив значение true, а затем инициировать запись видео. На некоторых устройствах факел будет светиться после запуска предварительной версии. На других устройствах факел может не светиться до начала видеозахвата.
Фокус
Три различных часто используемых метода для настройки фокуса камеры поддерживаются объектом FocusControl , непрерывным автофокусом, касанием фокуса и фокусом вручную. Приложение камеры может поддерживать все три этих метода, но для удобочитаемости в этой статье рассматривается каждый метод отдельно. В этом разделе также описывается, как включить свет с фокусом.
Непрерывная автофокусировка
Включение непрерывного автофокуса предписывает камере динамически настраивать фокус, чтобы попытаться сохранить тему фото или видео в фокусе. В этом примере переключатель используется для переключения непрерывной автоматической фокусировки и выключения.
<RadioButton Content="CAF" Name="CafFocusRadioButton" Checked="CafFocusRadioButton_Checked"/>
Проверьте, поддерживает ли текущее устройство записи FocusControl , проверив поддерживаемое свойство. Затем определите, поддерживается ли непрерывная автофокусировка, проверив список SupportedFocusModes, чтобы узнать, содержит ли оно значение FocusMode.Continuous, а если да, отображается переключатель непрерывного автофокуса.
var focusControl = _mediaCapture.VideoDeviceController.FocusControl;
if (focusControl.Supported)
{
CafFocusRadioButton.Visibility = focusControl.SupportedFocusModes.Contains(FocusMode.Continuous)
? Visibility.Visible : Visibility.Collapsed;
}
else
{
CafFocusRadioButton.Visibility = Visibility.Collapsed;
}
В обработчике событий Checked для переключателя непрерывного автофокуса используйте свойство VideoDeviceController.FocusControl, чтобы получить экземпляр элемента управления. Вызовите UnlockAsync, чтобы разблокировать элемент управления в случае, если приложение ранее назвало LockAsync, чтобы включить один из других режимов фокусировки.
Создайте объект FocusSettings и задайте для свойства Mode значение "Непрерывный". Задайте свойству AutoFocusRange значение, подходящее для сценария приложения или выбранного пользователем из пользовательского интерфейса. Передайте объект FocusSettings в метод Configure, а затем вызовите FocusAsync, чтобы инициировать непрерывный автофокус.
private async void CafFocusRadioButton_Checked(object sender, RoutedEventArgs e)
{
if(! _isPreviewing)
{
// Autofocus only supported while preview stream is running.
return;
}
var focusControl = _mediaCapture.VideoDeviceController.FocusControl;
await focusControl.UnlockAsync();
var settings = new FocusSettings { Mode = FocusMode.Continuous, AutoFocusRange = AutoFocusRange.FullRange };
focusControl.Configure(settings);
await focusControl.FocusAsync();
}
Внимание
Режим автофокуса поддерживается только во время выполнения потока предварительной версии. Убедитесь, что поток предварительной версии запущен перед включением непрерывной автофокусировки.
Коснитесь фокуса
Метод касания к фокусу использует FocusControl и RegionsOfInterestControl, чтобы указать кадр захвата, в котором устройство захвата должно сосредоточиться. Область фокуса определяется пользователем, касающимся экрана, отображающего поток предварительного просмотра.
В этом примере используется переключатель для включения и отключения режима касания к фокусу.
<RadioButton Content="Tap" Name="TapFocusRadioButton" Checked="TapFocusRadioButton_Checked"/>
Проверьте, поддерживает ли текущее устройство записи FocusControl , проверив поддерживаемое свойство. РегионOfInterestControl должен поддерживаться и поддерживать по крайней мере один регион, чтобы использовать этот метод. Проверьте свойства AutoFocusSupported и MaxRegions, чтобы определить, следует ли отображать или скрывать переключатель для касания к фокусу.
var focusControl = _mediaCapture.VideoDeviceController.FocusControl;
if (focusControl.Supported)
{
TapFocusRadioButton.Visibility = (_mediaCapture.VideoDeviceController.RegionsOfInterestControl.AutoFocusSupported &&
_mediaCapture.VideoDeviceController.RegionsOfInterestControl.MaxRegions > 0)
? Visibility.Visible : Visibility.Collapsed;
}
else
{
TapFocusRadioButton.Visibility = Visibility.Collapsed;
}
В обработчике событий Checked для переключателя "касание к фокусу" используйте свойство VideoDeviceController.FocusControl, чтобы получить экземпляр элемента управления. Вызов LockAsync, чтобы заблокировать элемент управления в случае, если приложение ранее назвало UnlockAsync, чтобы включить непрерывную автофокусировку, а затем дождитесь, пока пользователь коснитесь экрана, чтобы изменить фокус.
private async void TapFocusRadioButton_Checked(object sender, RoutedEventArgs e)
{
// Lock focus in case Continuous Autofocus was active when switching to Tap-to-focus
var focusControl = _mediaCapture.VideoDeviceController.FocusControl;
await focusControl.LockAsync();
// Wait for user tap
}
Этот пример фокусируется на регионе, когда пользователь нажимает экран, а затем удаляет фокус из этого региона, когда пользователь снова нажимает, например переключатель. Используйте логическую переменную для отслеживания текущего состояния переключения.
bool _isFocused = false;
Следующий шаг — прослушивать событие, когда пользователь нажимает экран, обрабатывая событие CaptureElement, которое в настоящее время отображает поток предварительного просмотра записи. Если камера в настоящее время не просматривается или если режим касания к фокусу отключен, вернитесь из обработчика без каких-либо действий.
Если переменная отслеживания _isFocused переключается на false, и если камера в настоящее время не находится в процессе фокуса (определяется свойством FocusState в FocusControl), запустите процесс касания к фокусу. Получите позицию касания пользователя из аrgs события, переданного обработчику. В этом примере также используется эта возможность для выбора размера региона, который будет сосредоточен на. В этом случае размер составляет 1/4 наименьшего измерения элемента захвата. Передайте положение касания и размер региона в вспомогательный метод TapToFocus , определенный в следующем разделе.
Если для переключателя _isFocused задано значение true, пользователь должен очистить фокус из предыдущего региона. Это делается в вспомогательном методе TapUnfocus , показанном ниже.
private async void PreviewControl_Tapped(object sender, TappedRoutedEventArgs e)
{
if (!_isPreviewing || (TapFocusRadioButton.IsChecked != true)) return;
if (!_isFocused && _mediaCapture.VideoDeviceController.FocusControl.FocusState != MediaCaptureFocusState.Searching)
{
var smallEdge = Math.Min(Window.Current.Bounds.Width, Window.Current.Bounds.Height);
// Choose to make the focus rectangle 1/4th the length of the shortest edge of the window
var size = new Size(smallEdge / 4, smallEdge / 4);
var position = e.GetPosition(sender as UIElement);
// Note that at this point, a rect at "position" with size "size" could extend beyond the preview area. The following method will reposition the rect if that is the case
await TapToFocus(position, size);
}
else
{
await TapUnfocus();
}
}
В вспомогательном методе TapToFocus сначала установите переключатель _isFocused на значение true, чтобы следующий касание экрана отпустит фокус из области касания.
Следующая задача в этом вспомогательном методе — определить прямоугольник в потоке предварительной версии, который будет назначен элементу управления фокусом. Для этого требуется два шага. Первым шагом является определение прямоугольника, который поток предварительного просмотра занимает в элементе управления CaptureElement . Это зависит от измерений потока предварительного просмотра и ориентации устройства. Вспомогательный метод GetPreviewStreamRectInControl, показанный в конце этого раздела, выполняет эту задачу и возвращает прямоугольник, содержащий поток предварительного просмотра.
Следующая задача в TapToFocus — преобразовать расположение касания и нужный размер прямоугольника фокуса, которые были определены в обработчике событий CaptureElement.Tapped , в координаты в потоке записи. Вспомогательный метод ConvertUiTapToPreviewRect , показанный далее в этом разделе, выполняет это преобразование и возвращает прямоугольник в координатах потока записи, где фокус будет запрошен.
Теперь, когда целевой прямоугольник был получен, создайте объект RegionOfInterest, задав свойству Bounds целевой прямоугольник, полученный на предыдущих шагах.
Получите элемент FocusControl устройства записи. Создайте объект FocusSettings и задайте режим и AutoFocusRange нужным значениям после проверки, чтобы убедиться, что они поддерживаются FocusControl. Вызовите configure on the FocusControl , чтобы сделать параметры активными и сигнализировать устройству, чтобы начать фокусироваться на указанном регионе.
Затем получите устройство записи RegionOfInterestControl и вызовите SetRegionsAsync, чтобы задать активный регион. На устройствах, поддерживающих его, можно задать несколько регионов, но в этом примере только один регион.
Наконец, вызовите FocusAsync в FocusControl , чтобы инициировать фокусирование.
Внимание
При реализации касания для фокуса порядок операций важен. Эти API следует вызывать в следующем порядке:
public async Task TapToFocus(Point position, Size size)
{
_isFocused = true;
var previewRect = GetPreviewStreamRectInControl();
var focusPreview = ConvertUiTapToPreviewRect(position, size, previewRect);
// Note that this Region Of Interest could be configured to also calculate exposure
// and white balance within the region
var regionOfInterest = new RegionOfInterest
{
AutoFocusEnabled = true,
BoundsNormalized = true,
Bounds = focusPreview,
Type = RegionOfInterestType.Unknown,
Weight = 100,
};
var focusControl = _mediaCapture.VideoDeviceController.FocusControl;
var focusRange = focusControl.SupportedFocusRanges.Contains(AutoFocusRange.FullRange) ? AutoFocusRange.FullRange : focusControl.SupportedFocusRanges.FirstOrDefault();
var focusMode = focusControl.SupportedFocusModes.Contains(FocusMode.Single) ? FocusMode.Single : focusControl.SupportedFocusModes.FirstOrDefault();
var settings = new FocusSettings { Mode = focusMode, AutoFocusRange = focusRange };
focusControl.Configure(settings);
var roiControl = _mediaCapture.VideoDeviceController.RegionsOfInterestControl;
await roiControl.SetRegionsAsync(new[] { regionOfInterest }, true);
await focusControl.FocusAsync();
}
В вспомогательном методе TapUnfocus получите RegionOfInterestControl и вызовите ClearRegionsAsync, чтобы очистить регион, зарегистрированный с помощью элемента управления в вспомогательном методе TapToFocus. Затем получите FocusControl и вызовите FocusAsync, чтобы устройство перенаправлялось без интересующего региона.
private async Task TapUnfocus()
{
_isFocused = false;
var roiControl = _mediaCapture.VideoDeviceController.RegionsOfInterestControl;
await roiControl.ClearRegionsAsync();
var focusControl = _mediaCapture.VideoDeviceController.FocusControl;
await focusControl.FocusAsync();
}
Вспомогательный метод GetPreviewStreamRectInControl использует разрешение потока предварительного просмотра и ориентацию устройства для определения прямоугольника в элементе предварительного просмотра, содержащего поток предварительного просмотра, обрезая все почтовые поля, которые элемент управления может обеспечить для поддержания пропорции потока. Этот метод использует переменные-члены класса, определенные в базовом примере кода захвата мультимедиа, найденного в базовом коде фото, видео и аудиозаписи с помощью MediaCapture.
public Rect GetPreviewStreamRectInControl()
{
var result = new Rect();
var previewResolution = _mediaCapture.VideoDeviceController.GetMediaStreamProperties(MediaStreamType.VideoPreview) as VideoEncodingProperties;
// In case this function is called before everything is initialized correctly, return an empty result
if (PreviewControl == null || PreviewControl.ActualHeight < 1 || PreviewControl.ActualWidth < 1 ||
previewResolution == null || previewResolution.Height == 0 || previewResolution.Width == 0)
{
return result;
}
var streamWidth = previewResolution.Width;
var streamHeight = previewResolution.Height;
// For portrait orientations, the width and height need to be swapped
if (_displayOrientation == DisplayOrientations.Portrait || _displayOrientation == DisplayOrientations.PortraitFlipped)
{
streamWidth = previewResolution.Height;
streamHeight = previewResolution.Width;
}
// Start by assuming the preview display area in the control spans the entire width and height both (this is corrected in the next if for the necessary dimension)
result.Width = PreviewControl.ActualWidth;
result.Height = PreviewControl.ActualHeight;
// If UI is "wider" than preview, letterboxing will be on the sides
if ((PreviewControl.ActualWidth / PreviewControl.ActualHeight > streamWidth / (double)streamHeight))
{
var scale = PreviewControl.ActualHeight / streamHeight;
var scaledWidth = streamWidth * scale;
result.X = (PreviewControl.ActualWidth - scaledWidth) / 2.0;
result.Width = scaledWidth;
}
else // Preview stream is "wider" than UI, so letterboxing will be on the top+bottom
{
var scale = PreviewControl.ActualWidth / streamWidth;
var scaledHeight = streamHeight * scale;
result.Y = (PreviewControl.ActualHeight - scaledHeight) / 2.0;
result.Height = scaledHeight;
}
return result;
}
Вспомогательный метод ConvertUiTapToPreviewRect принимает в качестве аргументов расположение события касания, требуемый размер области фокуса и прямоугольник, содержащий поток предварительного просмотра, полученный из вспомогательного метода GetPreviewStreamRectInControl . Этот метод использует эти значения и текущую ориентацию устройства для вычисления прямоугольника в потоке предварительной версии, содержащего нужный регион. Еще раз этот метод использует переменные-члены класса, определенные в базовом примере кода захвата мультимедиа, найденного в разделе "Фотографии и видео" с помощью MediaCapture.
private Rect ConvertUiTapToPreviewRect(Point tap, Size size, Rect previewRect)
{
// Adjust for the resulting focus rectangle to be centered around the position
double left = tap.X - size.Width / 2, top = tap.Y - size.Height / 2;
// Get the information about the active preview area within the CaptureElement (in case it's letterboxed)
double previewWidth = previewRect.Width, previewHeight = previewRect.Height;
double previewLeft = previewRect.Left, previewTop = previewRect.Top;
// Transform the left and top of the tap to account for rotation
switch (_displayOrientation)
{
case DisplayOrientations.Portrait:
var tempLeft = left;
left = top;
top = previewRect.Width - tempLeft;
break;
case DisplayOrientations.LandscapeFlipped:
left = previewRect.Width - left;
top = previewRect.Height - top;
break;
case DisplayOrientations.PortraitFlipped:
var tempTop = top;
top = left;
left = previewRect.Width - tempTop;
break;
}
// For portrait orientations, the information about the active preview area needs to be rotated
if (_displayOrientation == DisplayOrientations.Portrait || _displayOrientation == DisplayOrientations.PortraitFlipped)
{
previewWidth = previewRect.Height;
previewHeight = previewRect.Width;
previewLeft = previewRect.Top;
previewTop = previewRect.Left;
}
// Normalize width and height of the focus rectangle
var width = size.Width / previewWidth;
var height = size.Height / previewHeight;
// Shift rect left and top to be relative to just the active preview area
left -= previewLeft;
top -= previewTop;
// Normalize left and top
left /= previewWidth;
top /= previewHeight;
// Ensure rectangle is fully contained within the active preview area horizontally
left = Math.Max(left, 0);
left = Math.Min(1 - width, left);
// Ensure rectangle is fully contained within the active preview area vertically
top = Math.Max(top, 0);
top = Math.Min(1 - height, top);
// Create and return resulting rectangle
return new Rect(left, top, width, height);
}
Фокус вручную
Метод фокусировки вручную использует ползунок для задания текущей глубины фокуса устройства захвата. Переключатель используется для включения фокуса вручную и выключения.
<Slider Name="FocusSlider" IsEnabled="{Binding ElementName=ManualFocusRadioButton,Path=IsChecked}" ValueChanged="FocusSlider_ValueChanged"/>
<TextBlock Text="{Binding ElementName=FocusSlider,Path=Value,FallbackValue='0'}"/>
<RadioButton Content="Manual" Name="ManualFocusRadioButton" Checked="ManualFocusRadioButton_Checked" IsChecked="False"/>
Проверьте, поддерживает ли текущее устройство записи FocusControl , проверив поддерживаемое свойство. Если элемент управления поддерживается, можно отобразить и включить пользовательский интерфейс для этой функции.
Значение фокуса должно находиться в диапазоне, поддерживаемом устройством, и должно быть увеличением поддерживаемого размера шага. Получите поддерживаемые значения для текущего устройства, проверив свойства Min, Max и Step, которые используются для задания соответствующих свойств элемента управления ползунка.
Задайте для элемента управления ползунок текущее значение FocusControl после отмены регистрации обработчика событий ValueChanged, чтобы событие не активировался при установке значения.
var focusControl = _mediaCapture.VideoDeviceController.FocusControl;
if (focusControl.Supported)
{
FocusSlider.Visibility = Visibility.Visible;
ManualFocusRadioButton.Visibility = Visibility.Visible;
FocusSlider.Minimum = focusControl.Min;
FocusSlider.Maximum = focusControl.Max;
FocusSlider.StepFrequency = focusControl.Step;
FocusSlider.ValueChanged -= FocusSlider_ValueChanged;
FocusSlider.Value = focusControl.Value;
FocusSlider.ValueChanged += FocusSlider_ValueChanged;
}
else
{
FocusSlider.Visibility = Visibility.Collapsed;
ManualFocusRadioButton.Visibility = Visibility.Collapsed;
}
В обработчике событий Checked для переключателя фокуса вручную получите объект FocusControl и вызов LockAsync в случае, если приложение ранее разблокировало фокус с вызовом UnlockAsync.
private async void ManualFocusRadioButton_Checked(object sender, RoutedEventArgs e)
{
var focusControl = _mediaCapture.VideoDeviceController.FocusControl;
await focusControl.LockAsync();
}
В обработчике событий ValueChanged ползунка фокуса вручную получите текущее значение элемента управления и задайте значение фокуса путем вызова SetValueAsync.
private async void FocusSlider_ValueChanged(object sender, Windows.UI.Xaml.Controls.Primitives.RangeBaseValueChangedEventArgs e)
{
var value = (sender as Slider).Value;
await _mediaCapture.VideoDeviceController.FocusControl.SetValueAsync((uint)value);
}
Включение света фокуса
На устройствах, поддерживающих его, вы можете включить свет фокуса, чтобы помочь фокусу устройства. В этом примере используется флажок для включения или отключения освещения фокуса.
<CheckBox Content="Assist Light" Name="FocusLightCheckBox" IsEnabled="{Binding ElementName=TapFocusRadioButton,Path=IsChecked}"
Checked="FocusLightCheckBox_CheckedChanged" Unchecked="FocusLightCheckBox_CheckedChanged"/>
Проверьте, поддерживает ли текущее устройство записи FlashControl , проверив поддерживаемое свойство. Кроме того, проверьте помощникLightSupported , чтобы убедиться, что индикатор поддержки также поддерживается. Если они поддерживаются, можно отобразить и включить пользовательский интерфейс для этой функции.
var focusControl = _mediaCapture.VideoDeviceController.FocusControl;
if (focusControl.Supported)
{
FocusLightCheckBox.Visibility = (_mediaCapture.VideoDeviceController.FlashControl.Supported &&
_mediaCapture.VideoDeviceController.FlashControl.AssistantLightSupported) ? Visibility.Visible : Visibility.Collapsed;
}
else
{
FocusLightCheckBox.Visibility = Visibility.Collapsed;
}
В обработчике событий CheckedChanged получите объект FlashControl устройств записи. Задайте свойство AssistantLightEnabled, чтобы включить или отключить свет фокуса.
private void FocusLightCheckBox_CheckedChanged(object sender, RoutedEventArgs e)
{
var flashControl = _mediaCapture.VideoDeviceController.FlashControl;
flashControl.AssistantLightEnabled = (FocusLightCheckBox.IsChecked == true);
}
Скорость ISO
IsoSpeedControl позволяет задать скорость ISO, используемую во время фото или видеосъемки.
В этом примере используется ползунок для настройки текущего значения компенсации воздействия и флажка для переключения автоматической корректировки скорости ISO.
<Slider Name="IsoSlider" ValueChanged="IsoSlider_ValueChanged"/>
<TextBlock Text="{Binding ElementName=IsoSlider,Path=Value}" Visibility="{Binding ElementName=IsoSlider,Path=Visibility}"/>
<CheckBox Name="IsoAutoCheckBox" Content="Auto" Checked="IsoAutoCheckBox_CheckedChanged" Unchecked="IsoAutoCheckBox_CheckedChanged"/>
Проверьте, поддерживает ли текущее устройство захвата IsoSpeedControl , проверив поддерживаемое свойство. Если элемент управления поддерживается, можно отобразить и включить пользовательский интерфейс для этой функции. Установите установленное состояние флажка, чтобы указать, активна ли автоматическая корректировка скорости ISO в настоящее время для значения свойства Auto.
Значение скорости ISO должно находиться в диапазоне, поддерживаемом устройством, и должно быть увеличением поддерживаемого размера шага. Получите поддерживаемые значения для текущего устройства, проверив свойства Min, Max и Step, которые используются для задания соответствующих свойств элемента управления ползунка.
Задайте для элемента управления ползунок текущее значение IsoSpeedControl после отмены регистрации обработчика событий ValueChanged, чтобы событие не активировался при установке значения.
private void UpdateIsoControlCapabilities()
{
var isoSpeedControl = _mediaCapture.VideoDeviceController.IsoSpeedControl;
if (isoSpeedControl.Supported)
{
IsoAutoCheckBox.Visibility = Visibility.Visible;
IsoSlider.Visibility = Visibility.Visible;
IsoAutoCheckBox.IsChecked = isoSpeedControl.Auto;
IsoSlider.Minimum = isoSpeedControl.Min;
IsoSlider.Maximum = isoSpeedControl.Max;
IsoSlider.StepFrequency = isoSpeedControl.Step;
IsoSlider.ValueChanged -= IsoSlider_ValueChanged;
IsoSlider.Value = isoSpeedControl.Value;
IsoSlider.ValueChanged += IsoSlider_ValueChanged;
}
else
{
IsoAutoCheckBox.Visibility = Visibility.Collapsed;
IsoSlider.Visibility = Visibility.Collapsed;
}
}
В обработчике событий ValueChanged получите текущее значение элемента управления и задайте значение скорости ISO путем вызова SetValueAsync.
private async void IsoSlider_ValueChanged(object sender, Windows.UI.Xaml.Controls.Primitives.RangeBaseValueChangedEventArgs e)
{
var value = (sender as Slider).Value;
await _mediaCapture.VideoDeviceController.IsoSpeedControl.SetValueAsync((uint)value);
}
В обработчике событий CheckedChanged флажка автоматической скорости ISO включите автоматическую настройку скорости ISO, вызвав SetAutoAsync. Включите автоматическую настройку скорости ISO путем вызова SetValueAsync и передачи текущего значения элемента управления ползунка.
private async void IsoAutoCheckBox_CheckedChanged(object sender, RoutedEventArgs e)
{
var autoIso = (sender as CheckBox).IsChecked == true;
if (autoIso)
{
await _mediaCapture.VideoDeviceController.IsoSpeedControl.SetAutoAsync();
}
else
{
await _mediaCapture.VideoDeviceController.IsoSpeedControl.SetValueAsync((uint)IsoSlider.Value);
}
}
Стабилизация оптического изображения
Стабилизация оптического изображения (OIS) стабилизирует захваченный видеопоток путем механических манипуляций с устройством захвата оборудования, что может обеспечить более высокий результат, чем цифровая стабилизация. На устройствах, которые не поддерживают OIS, вы можете использовать VideoStabilizationEffect для цифровой стабилизации на захваченном видео. Дополнительные сведения см. в разделе "Эффекты" для записи видео.
Определите, поддерживается ли OIS на текущем устройстве, проверив свойство OpticalImageStabilizationControl.Supported .
Элемент управления OIS поддерживает три режима: включено, отключено и автоматическое, что означает, что устройство динамически определяет, улучшит ли OIS захват мультимедиа и, если да, включает OIS. Чтобы определить, поддерживается ли определенный режим на устройстве, проверьте, содержит ли коллекция OpticalImageStabilizationControl.SupportedModes нужный режим.
Включите или отключите OIS, задав для параметра OpticalImageStabilizationControl.Mode нужный режим.
private void SetOpticalImageStabilizationMode(OpticalImageStabilizationMode mode)
{
if (!_mediaCapture.VideoDeviceController.OpticalImageStabilizationControl.Supported)
{
ShowMessageToUser("Optical image stabilization not available");
return;
}
var stabilizationModes = _mediaCapture.VideoDeviceController.OpticalImageStabilizationControl.SupportedModes;
if (!stabilizationModes.Contains(mode))
{
ShowMessageToUser("Optical image stabilization setting not supported");
return;
}
_mediaCapture.VideoDeviceController.OpticalImageStabilizationControl.Mode = mode;
}
Частота питания
Некоторые устройства камеры поддерживают обработку мерцания, которая зависит от знания частоты питания линий управления в текущей среде. Некоторые устройства поддерживают автоматическое определение частоты питания, а другие требуют, чтобы частота была задана вручную. В следующем примере кода показано, как определить поддержку частоты питания на устройстве и при необходимости задать частоту вручную.
Во-первых, вызовите метод VideoDeviceController TryGetPowerlineFrequency, передав выходной параметр типа PowerlineFrequency; если этот вызов завершается сбоем, элемент управления частотой питания не поддерживается на текущем устройстве. Если эта функция поддерживается, можно определить, доступен ли автоматический режим на устройстве, пытаясь настроить автоматический режим. Для этого вызовите TrySetPowerlineFrequency и передайте значение Auto. Если вызов выполнен успешно, это означает, что поддерживается частота автоматической линии питания. Если контроллер частоты питания поддерживается на устройстве, но автоматическое обнаружение частоты не установлено, вы по-прежнему можете вручную задать частоту с помощью TrySetPowerlineFrequency. В этом примере MyCustomFrequencyLookup — это настраиваемый метод, реализуемый для определения правильной частоты текущего расположения устройства.
PowerlineFrequency getFrequency;
if (! _mediaCapture.VideoDeviceController.TryGetPowerlineFrequency(out getFrequency))
{
// Powerline frequency is not supported on this device.
return;
}
if (! _mediaCapture.VideoDeviceController.TrySetPowerlineFrequency(PowerlineFrequency.Auto))
{
// Set the frequency manually
PowerlineFrequency setFrequency = MyCustomFrequencyLookup();
if (_mediaCapture.VideoDeviceController.TrySetPowerlineFrequency(setFrequency))
{
System.Diagnostics.Debug.WriteLine(String.Format("Powerline frequency manually set to {0}.", setFrequency));
}
}
Баланс белого цвета
WhiteBalanceControl позволяет задать баланс белого цвета, используемый во время фото или видеозахвата.
В этом примере используется элемент управления ComboBox для выбора из встроенных предустановок цветовой температуры и ползунка для ручной корректировки баланса.
<Slider Name="WbSlider" ValueChanged="WbSlider_ValueChanged"/>
<TextBlock Name="WbTextBox" Text="{Binding ElementName=WbSlider,Path=Value}" Visibility="{Binding ElementName=WbSlider,Path=Visibility}"/>
<ComboBox Name="WbComboBox" SelectionChanged="WbComboBox_SelectionChanged"/>
Проверьте, поддерживает ли текущее устройство записи WhiteBalanceControl, проверив поддерживаемое свойство. Если элемент управления поддерживается, можно отобразить и включить пользовательский интерфейс для этой функции. Задайте для элементов поля со списком значения перечисления ColorTemperaturePreset . И задайте для выбранного элемента текущее значение свойства Preset .
Для ручного управления значение белого баланса должно находиться в диапазоне, поддерживаемом устройством, и должно быть шагом поддерживаемого размера шага. Получите поддерживаемые значения для текущего устройства, проверив свойства Min, Max и Step, которые используются для задания соответствующих свойств элемента управления ползунка. Перед включением ручного управления убедитесь, что диапазон между минимальными и максимальными поддерживаемыми значениями больше размера шага. Если это не так, ручной элемент управления не поддерживается на текущем устройстве.
Задайте для элемента управления ползунка текущее значение WhiteBalanceControl после отмены регистрации обработчика событий ValueChanged, чтобы событие не активировало при установке значения.
var whiteBalanceControl = _mediaCapture.VideoDeviceController.WhiteBalanceControl;
if (whiteBalanceControl.Supported)
{
WbSlider.Visibility = Visibility.Visible;
WbComboBox.Visibility = Visibility.Visible;
if (WbComboBox.ItemsSource == null)
{
WbComboBox.ItemsSource = Enum.GetValues(typeof(ColorTemperaturePreset)).Cast<ColorTemperaturePreset>();
}
WbComboBox.SelectedItem = whiteBalanceControl.Preset;
if (whiteBalanceControl.Max - whiteBalanceControl.Min > whiteBalanceControl.Step)
{
WbSlider.Minimum = whiteBalanceControl.Min;
WbSlider.Maximum = whiteBalanceControl.Max;
WbSlider.StepFrequency = whiteBalanceControl.Step;
WbSlider.ValueChanged -= WbSlider_ValueChanged;
WbSlider.Value = whiteBalanceControl.Value;
WbSlider.ValueChanged += WbSlider_ValueChanged;
}
else
{
WbSlider.Visibility = Visibility.Collapsed;
}
}
else
{
WbSlider.Visibility = Visibility.Collapsed;
WbComboBox.Visibility = Visibility.Collapsed;
}
В обработчике событий SelectionChanged предустановленного поля со списком цветовой температуры получите выбранный набор и задайте значение элемента управления, вызвав SetPresetAsync. Если выбранное предварительно настроенное значение не является ручным, отключите ползунок балансировщика белого баланса вручную.
private async void WbComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if(!_isPreviewing)
{
// Do not set white balance values unless the preview stream is running.
return;
}
var selected = (ColorTemperaturePreset)WbComboBox.SelectedItem;
WbSlider.IsEnabled = (selected == ColorTemperaturePreset.Manual);
await _mediaCapture.VideoDeviceController.WhiteBalanceControl.SetPresetAsync(selected);
}
В обработчике событий ValueChanged получите текущее значение элемента управления и задайте значение белого баланса путем вызова SetValueAsync.
private async void WbSlider_ValueChanged(object sender, Windows.UI.Xaml.Controls.Primitives.RangeBaseValueChangedEventArgs e)
{
if (!_isPreviewing)
{
// Do not set white balance values unless the preview stream is running.
return;
}
var value = (sender as Slider).Value;
await _mediaCapture.VideoDeviceController.WhiteBalanceControl.SetValueAsync((uint)value);
}
Внимание
Настройка баланса белого цвета поддерживается только при выполнении потока предварительной версии. Убедитесь, что поток предварительной версии выполняется перед заданием значения или предустановки баланса.
Внимание
Значение предустановки ColorTemperaturePreset.Auto указывает системе автоматически настраивать уровень балансировки белого баланса. В некоторых сценариях, таких как запись последовательности фотографий, где уровни баланса белого баланса должны быть одинаковыми для каждого кадра, может потребоваться заблокировать элемент управления текущим автоматическим значением. Для этого вызовите SetPresetAsync и укажите предустановку вручную и не устанавливайте значение элемента управления с помощью SetValueAsync. Это приведет к блокировке текущего значения устройства. Не пытайтесь считывать текущее значение элемента управления, а затем передайте возвращаемое значение в SetValueAsync , так как это значение не гарантируется правильно.
Масштабирование
ZoomControl позволяет задать уровень масштабирования, используемый во время фото или видеосъемки.
В этом примере для настройки текущего уровня масштабирования используется элемент управления Ползунок . В следующем разделе показано, как настроить масштаб на основе жеста сцепление на экране.
<Slider Name="ZoomSlider" Grid.Row="0" Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Stretch" ValueChanged="ZoomSlider_ValueChanged"/>
<TextBlock Grid.Row="1" HorizontalAlignment="Center" Text="{Binding ElementName=ZoomSlider,Path=Value}"/>
Проверьте, поддерживает ли текущее устройство записи ZoomControl , проверив поддерживаемое свойство. Если элемент управления поддерживается, можно отобразить и включить пользовательский интерфейс для этой функции.
Значение уровня масштабирования должно находиться в диапазоне, поддерживаемом устройством, и должно быть увеличением поддерживаемого размера шага. Получите поддерживаемые значения для текущего устройства, проверив свойства Min, Max и Step, которые используются для задания соответствующих свойств элемента управления ползунка.
Задайте для элемента управления ползунок текущее значение ZoomControl после отмены регистрации обработчика событий ValueChanged, чтобы событие не активировало при установке значения.
var zoomControl = _mediaCapture.VideoDeviceController.ZoomControl;
if (zoomControl.Supported)
{
ZoomSlider.Visibility = Visibility.Visible;
ZoomSlider.Minimum = zoomControl.Min;
ZoomSlider.Maximum = zoomControl.Max;
ZoomSlider.StepFrequency = zoomControl.Step;
ZoomSlider.ValueChanged -= ZoomSlider_ValueChanged;
ZoomSlider.Value = zoomControl.Value;
ZoomSlider.ValueChanged += ZoomSlider_ValueChanged;
}
else
{
ZoomSlider.Visibility = Visibility.Collapsed;
}
В обработчике событий ValueChanged создайте новый экземпляр класса ZoomSettings, задав свойству Value текущее значение элемента управления ползунка масштабирования. Если свойство SupportedModes объекта ZoomControl содержит ZoomTransitionMode.Smooth, это означает, что устройство поддерживает плавные переходы между уровнями масштабирования. Так как этот режим обеспечивает лучший пользовательский интерфейс, обычно требуется использовать это значение для свойства Mode объекта ZoomSettings.
Наконец, измените текущие параметры масштабирования, передав объект ZoomSettings в метод Configure объекта ZoomControl.
private void ZoomSlider_ValueChanged(object sender, Windows.UI.Xaml.Controls.Primitives.RangeBaseValueChangedEventArgs e)
{
var level = (float)ZoomSlider.Value;
var settings = new ZoomSettings { Value = level };
var zoomControl = _mediaCapture.VideoDeviceController.ZoomControl;
if (zoomControl.SupportedModes.Contains(ZoomTransitionMode.Smooth))
{
settings.Mode = ZoomTransitionMode.Smooth;
}
else
{
settings.Mode = zoomControl.SupportedModes.First();
}
zoomControl.Configure(settings);
}
Плавное масштабирование с помощью жеста сцепление
Как описано в предыдущем разделе, на устройствах, поддерживающих его, режим плавного масштабирования позволяет устройству захвата плавно переходить между уровнями цифрового масштабирования, что позволяет пользователю динамически настраивать уровень масштабирования во время операции захвата без дискретных и jarring переходов. В этом разделе описывается, как настроить уровень масштабирования в ответ на жест сцепление.
Сначала определите, поддерживается ли элемент управления цифровым масштабом на текущем устройстве, проверив свойство ZoomControl.Supported . Затем определите, доступен ли режим плавного масштабирования, проверив zoomControl.SupportedModes, чтобы узнать, содержит ли оно значение ZoomTransitionMode.Smooth.
private bool IsSmoothZoomSupported()
{
if (!_mediaCapture.VideoDeviceController.ZoomControl.Supported)
{
ShowMessageToUser("Digital zoom is not supported on this device.");
return false;
}
var zoomModes = _mediaCapture.VideoDeviceController.ZoomControl.SupportedModes;
if (!zoomModes.Contains(ZoomTransitionMode.Smooth))
{
ShowMessageToUser("Smooth zoom not supported");
return false;
}
return true;
}
На устройстве с поддержкой нескольких сенсорных устройств типичный сценарий заключается в настройке коэффициента масштабирования на основе жеста с двумя пальцами. Задайте свойству ManipulationMode элемента управления CaptureElement значение ManipulationModes.Scale, чтобы включить жест сцепления. Затем зарегистрируйтесь для события ManipulationDelta , которое возникает при изменении размера жеста закрепления.
private void RegisterPinchGestureHandler()
{
if (!IsSmoothZoomSupported())
{
return;
}
// Enable pinch/zoom gesture for the preview control
PreviewControl.ManipulationMode = ManipulationModes.Scale;
PreviewControl.ManipulationDelta += PreviewControl_ManipulationDelta;
}
В обработчике события ManipulationDelta обновите коэффициент масштабирования на основе изменения жеста скрепления пользователя. Значение ManipulationDelta.Scale представляет изменение масштаба жеста сцепление, так что небольшое увеличение размера сцепление немного больше 1,0, а небольшое уменьшение размера сцепление немного меньше 1,0. В этом примере текущее значение элемента управления масштабированием умножается на разностную шкалу.
Перед настройкой коэффициента масштабирования необходимо убедиться, что значение не меньше минимального значения, поддерживаемого устройством, как указано в свойстве ZoomControl.Min. Кроме того, убедитесь, что значение меньше или равно значению ZoomControl.Max . Наконец, необходимо убедиться, что коэффициент масштабирования является нескольким размером шага масштабирования, поддерживаемым устройством, как указано свойством Step . Если коэффициент масштабирования не соответствует этим требованиям, исключение будет возникать при попытке установить уровень масштабирования на устройстве захвата.
Задайте уровень масштабирования на устройстве захвата, создав новый объект ZoomSettings. Задайте для свойства Mode значение ZoomTransitionMode.Smooth, а затем задайте для свойства Value нужный коэффициент масштабирования. Наконец, вызовите ZoomControl.Configure , чтобы задать новое значение масштабирования на устройстве. Устройство будет плавно переходить к новому значению масштабирования.
private void PreviewControl_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
var zoomControl = _mediaCapture.VideoDeviceController.ZoomControl;
// Example zoom factor calculation based on size of scale gesture
var zoomFactor = zoomControl.Value * e.Delta.Scale;
if (zoomFactor < zoomControl.Min) zoomFactor = zoomControl.Min;
if (zoomFactor > zoomControl.Max) zoomFactor = zoomControl.Max;
zoomFactor = zoomFactor - (zoomFactor % zoomControl.Step);
var settings = new ZoomSettings();
settings.Mode = ZoomTransitionMode.Smooth;
settings.Value = zoomFactor;
_mediaCapture.VideoDeviceController.ZoomControl.Configure(settings);
}