Поделиться через


Обработка ориентации устройства с помощью MediaCapture

Когда приложение захватывает фотографию или видео, которое предназначено для просмотра за пределами приложения, например сохранение файла на устройстве пользователя или совместное использование в Интернете, важно закодировать изображение соответствующими метаданными ориентации, чтобы при отображении изображения на другом приложении или устройстве он был правильно ориентирован. Определение правильной ориентации данных для включения в файл мультимедиа может быть сложной задачей, поскольку существует несколько переменных, которые следует учитывать, включая ориентацию корпуса устройства, ориентацию дисплея и размещение камеры на шасси (будь то передней или задней камеры).

Чтобы упростить процесс обработки ориентации, рекомендуется использовать вспомогательный класс CameraRotationHelper, для которого представлено полное определение в конце этой статьи. Этот класс можно добавить в проект, а затем выполнить действия, описанные в этой статье, чтобы добавить поддержку ориентации в приложение камеры. Вспомогательный класс также упрощает поворот элементов управления в пользовательском интерфейсе камеры, чтобы они правильно отображались с точки зрения пользователя.

Примечание.

Эта статья основана на коде и концепциях, описанных в статье Basic photo, video и audio capture with MediaCapture. Рекомендуется ознакомиться с основными понятиями использования класса MediaCapture перед добавлением поддержки ориентации в приложение.

Пространства имен, используемые в этой статье

В примере кода в этой статье используются API из следующих пространств имен, которые следует включить в код.

using Windows.Devices.Enumeration;
using Windows.UI.Core;

Первым шагом в добавлении поддержки ориентации в приложение является блокировка дисплея, чтобы он не поворачивался автоматически при повороте устройства. Автоматическая смена пользовательского интерфейса хорошо подходит для большинства типов приложений, но она не подходит для пользователей, когда предварительная версия камеры поворачивается. Заблокируйте ориентацию отображения, задав свойство DisplayInformation.AutoRotationPreferences значение DisplayOrientations.Landscape.

DisplayInformation.AutoRotationPreferences = DisplayOrientations.Landscape;

Отслеживание расположения устройства камеры

Чтобы вычислить правильную ориентацию для захваченного носителя, приложение должно определить расположение устройства камеры на корпусе. Добавьте логическую переменную члена для отслеживания того, является ли камера внешней для устройства, например USB-веб-камерой. Добавьте другую логическую переменную для отслеживания того, следует ли отображать предварительную версию, то есть, если используется фронтальная камера. Кроме того, добавьте переменную для хранения объекта DeviceInformation , представляющего выбранную камеру.

private bool _externalCamera;
private bool _mirroringPreview;
DeviceInformation _cameraDevice;

Выбор устройства камеры и инициализация объекта MediaCapture

В статье Basic photo, video и audio capture with MediaCapture показано, как инициализировать объект MediaCapture с несколькими строками кода. Для поддержки ориентации камеры мы добавим несколько дополнительных шагов в процесс инициализации.

Сначала вызовите DeviceInformation.FindAllAsync , передавая селектор устройства DeviceClass.VideoCapture , чтобы получить список всех доступных устройств захвата видео. Затем выберите первое устройство в списке, где известно расположение панели камеры и где оно соответствует заданному значению, которое в этом примере является передней камерой. Если камера не найдена на нужной панели, используется первая или используемая по умолчанию камера.

Если устройство камеры найдено, создается новый объект MediaCaptureInitializationSettings, а для свойства VideoDeviceId задано выбранное устройство. Затем создайте объект MediaCapture и вызовите InitializeAsync, передавая объект параметров, чтобы сообщить системе использовать выбранную камеру.

Наконец, проверьте, имеет ли выбранная панель устройств значение NULL или неизвестно. Если это так, камера является внешней, то есть ее поворот не связан с поворотом устройства. Если панель известна и находится на передней части корпуса устройства, мы знаем, что предварительный просмотр должен быть зеркальным, поэтому для отслеживания переменной задано это значение.

var allVideoDevices = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);
DeviceInformation desiredDevice = allVideoDevices.FirstOrDefault(x => x.EnclosureLocation != null 
    && x.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Front);
_cameraDevice = desiredDevice ?? allVideoDevices.FirstOrDefault();


if (_cameraDevice == null)
{
    System.Diagnostics.Debug.WriteLine("No camera device found!");
    return;
}

var settings = new MediaCaptureInitializationSettings { VideoDeviceId = _cameraDevice.Id };

mediaCapture = new MediaCapture();
mediaCapture.RecordLimitationExceeded += MediaCapture_RecordLimitationExceeded;
mediaCapture.Failed += MediaCapture_Failed;

try
{
    await mediaCapture.InitializeAsync(settings);
}
catch (UnauthorizedAccessException)
{
    System.Diagnostics.Debug.WriteLine("The app was denied access to the camera");
    return;
}

// Handle camera device location
if (_cameraDevice.EnclosureLocation == null || 
    _cameraDevice.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Unknown)
{
    _externalCamera = true;
}
else
{
    _externalCamera = false;
    _mirroringPreview = (_cameraDevice.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Front);
}

Инициализация класса CameraRotationHelper

Теперь мы начинаем использовать класс CameraRotationHelper . Объявите переменную члена класса для хранения объекта. Вызовите конструктор, передавая расположение корпуса выбранной камеры. Вспомогательный класс использует эти сведения для вычисления правильной ориентации для захваченного носителя, потока предварительного просмотра и пользовательского интерфейса. Зарегистрируйте обработчик для события OrientationChanged вспомогательного класса, которое будет возникать при необходимости обновить ориентацию пользовательского интерфейса или потока предварительной версии.

private CameraRotationHelper _rotationHelper;
_rotationHelper = new CameraRotationHelper(_cameraDevice.EnclosureLocation);
_rotationHelper.OrientationChanged += RotationHelper_OrientationChanged;

Добавление данных ориентации в поток предварительной версии камеры

Добавление правильной ориентации в метаданные потока предварительной версии не влияет на то, как предварительный просмотр отображается пользователю, но помогает системе кодировать все кадры, захваченные из потока предварительного просмотра.

Вы запускаете предварительную версию камеры, вызвав MediaCapture.StartPreviewAsync. Прежде чем это сделать, проверьте переменную члена, чтобы узнать, следует ли отображать предварительный просмотр (для передней камеры). Если это так, задайте для свойства FlowDirection объекта CaptureElement с именем PreviewControl в этом примере значение FlowDirection.RightToLeft. После запуска предварительной версии вызовите вспомогательный метод SetPreviewRotationAsync , чтобы задать поворот предварительного просмотра. Ниже приведена реализация этого метода.

PreviewControl.Source = mediaCapture;
PreviewControl.FlowDirection = _mirroringPreview ? FlowDirection.RightToLeft : FlowDirection.LeftToRight;

await mediaCapture.StartPreviewAsync();
await SetPreviewRotationAsync();

Мы устанавливаем поворот предварительного просмотра в отдельном методе, чтобы его можно было обновить при изменении ориентации телефона без повторной инициализации потока предварительного просмотра. Если камера является внешней для устройства, действие не выполняется. В противном случае метод CameraRotationHelper GetCameraPreviewOrientation вызывается и возвращает правильную ориентацию для потока предварительного просмотра.

Чтобы задать метаданные, свойства потока предварительной версии извлекаются путем вызова VideoDeviceController.GetMediaStreamProperties. Затем создайте GUID, представляющий атрибут преобразования Media Foundation (MFT) для поворота видеопотока. В C++ можно использовать константу MF_MT_VIDEO_ROTATION, но в C# необходимо вручную указать значение GUID.

Добавьте значение свойства в объект свойств потока, указав GUID в качестве ключа и поворот предварительного просмотра в качестве значения. Это свойство ожидает, что значения будут находиться в единицах градусов счетчика, поэтому метод CameraRotationHelper ConvertSimpleOrientationToClockwiseDegrees используется для преобразования простого значения ориентации. Наконец, вызовите SetEncodingPropertiesAsync , чтобы применить новое свойство поворота к потоку.

private async Task SetPreviewRotationAsync()
{
    if (!_externalCamera)
    {
        // Add rotation metadata to the preview stream to make sure the aspect ratio / dimensions match when rendering and getting preview frames
        var rotation = _rotationHelper.GetCameraPreviewOrientation();
        var props = mediaCapture.VideoDeviceController.GetMediaStreamProperties(MediaStreamType.VideoPreview);
        Guid RotationKey = new Guid("C380465D-2271-428C-9B83-ECEA3B4A85C1");
        props.Properties.Add(RotationKey, CameraRotationHelper.ConvertSimpleOrientationToClockwiseDegrees(rotation));
        await mediaCapture.SetEncodingPropertiesAsync(MediaStreamType.VideoPreview, props, null);
    }
}

Затем добавьте обработчик события CameraRotationHelper.OrientationChanged . Это событие передается в аргументе, который позволяет узнать, нужно ли повернуть поток предварительной версии. Если ориентация устройства была изменена на лицо вверх или вниз, это значение будет false. Если предварительный просмотр необходимо повернуть, вызовите SetPreviewRotationAsync , который был определен ранее.

Затем в обработчике событий OrientationChanged обновите пользовательский интерфейс при необходимости. Получите текущую рекомендуемую ориентацию пользовательского интерфейса из вспомогательного класса, вызвав GetUIOrientation и преобразуя значение в по часовой стрелке, которое используется для преобразований XAML. Создайте rotateTransform из значения ориентации и задайте свойство RenderTransform элементов управления XAML. В зависимости от макета пользовательского интерфейса вам может потребоваться внести дополнительные корректировки в дополнение к простому повороту элементов управления. Кроме того, помните, что все обновления пользовательского интерфейса должны быть сделаны в потоке пользовательского интерфейса, поэтому этот код следует поместить в вызов RunAsync.

private async void RotationHelper_OrientationChanged(object sender, bool updatePreview)
{
    if (updatePreview)
    {
        await SetPreviewRotationAsync();
    }
    await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => {
        // Rotate the buttons in the UI to match the rotation of the device
        var angle = CameraRotationHelper.ConvertSimpleOrientationToClockwiseDegrees(_rotationHelper.GetUIOrientation());
        var transform = new RotateTransform { Angle = angle };

        // The RenderTransform is safe to use (i.e. it won't cause layout issues) in this case, because these buttons have a 1:1 aspect ratio
        CapturePhotoButton.RenderTransform = transform;
        CapturePhotoButton.RenderTransform = transform;
    });
}

Запись фотографии с данными ориентации

В статье Basic photo, video и audio capture with MediaCapture показано, как записать фотографию в файл путем записи в поток в памяти, а затем с помощью декодировщика для чтения данных изображения из потока и кодировщика для перекодирования данных изображения в файл. Данные ориентации, полученные из класса CameraRotationHelper , можно добавить в файл изображения во время операции транскодирования.

В следующем примере фотография записывается в InMemoryRandomAccessStream с вызовом CapturePhotoToStreamAsync, а bitmapDecoder создается из потока. Затем создается файл StorageFile и открывается для повторного обработки IRandomAccessStream для записи в файл.

Перед перекодированием файла ориентация фотографии извлекается из вспомогательного метода класса GetCameraCaptureOrientation. Этот метод возвращает объект SimpleOrientation, который преобразуется в объект PhotoOrientation с вспомогательным методом ConvertSimpleOrientationToPhotoOrientation. Затем создается новый объект BitmapPropertySet , а свойство добавляется, где ключ — System.Photo.Orientation, а значение — ориентация фотографии, выраженная как BitmapTypedValue. System.Photo.Orientation — это одно из многих свойств Windows, которые можно добавить как метаданные в файл изображения. Список всех свойств, связанных с фотографией, см. в разделе "Свойства Windows " Фото". Дополнительные сведения о работе с метаданными в изображениях см. в разделе "Метаданные изображения".

Наконец, набор свойств, включающий данные ориентации, задается для кодировщика с помощью вызова SetPropertiesAsync, и изображение перекодировано вызовом FlushAsync.

private async Task CapturePhotoWithOrientationAsync()
{
    var captureStream = new InMemoryRandomAccessStream();

    try
    {
        await mediaCapture.CapturePhotoToStreamAsync(ImageEncodingProperties.CreateJpeg(), captureStream);
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine("Exception when taking a photo: {0}", ex.ToString());
        return;
    }


    var decoder = await BitmapDecoder.CreateAsync(captureStream);
    var file = await KnownFolders.PicturesLibrary.CreateFileAsync("SimplePhoto.jpeg", CreationCollisionOption.GenerateUniqueName);

    using (var outputStream = await file.OpenAsync(FileAccessMode.ReadWrite))
    {
        var encoder = await BitmapEncoder.CreateForTranscodingAsync(outputStream, decoder);
        var photoOrientation = CameraRotationHelper.ConvertSimpleOrientationToPhotoOrientation(
            _rotationHelper.GetCameraCaptureOrientation());
        var properties = new BitmapPropertySet {
            { "System.Photo.Orientation", new BitmapTypedValue(photoOrientation, PropertyType.UInt16) } };
        await encoder.BitmapProperties.SetPropertiesAsync(properties);
        await encoder.FlushAsync();
    }
}

Запись видео с данными ориентации

Основные видеозахваты описаны в статье "Базовый" фото, видео и аудиозапись с помощью MediaCapture. Добавление данных ориентации в кодировку захваченного видео выполняется с помощью того же метода, что и описано ранее в разделе о добавлении данных ориентации в поток предварительного просмотра.

В следующем примере создается файл, в который записываются записанные видео. Профиль кодирования MP4 создается с помощью статического метода CreateMp4. Правильная ориентация видео получена из класса CameraRotationHelper с вызовом GetCameraCaptureOrientation , так как свойство поворота требует, чтобы ориентация была выражена в градусах со счетчиком, вспомогательный метод ConvertSimpleOrientationToClockwiseDegrees вызывается для преобразования значения ориентации. Затем создайте GUID, представляющий атрибут преобразования Media Foundation (MFT) для поворота видеопотока. В C++ можно использовать константу MF_MT_VIDEO_ROTATION, но в C# необходимо вручную указать значение GUID. Добавьте значение свойства в объект свойств потока, указав GUID в качестве ключа и поворота в качестве значения. Наконец, вызовите StartRecordToStorageFileAsync , чтобы начать запись видео в кодировке с данными ориентации.

private async Task StartRecordingWithOrientationAsync()
{
    try
    {
        var videoFile = await KnownFolders.VideosLibrary.CreateFileAsync("SimpleVideo.mp4", CreationCollisionOption.GenerateUniqueName);

        var encodingProfile = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Auto);

        var rotationAngle = CameraRotationHelper.ConvertSimpleOrientationToClockwiseDegrees(
            _rotationHelper.GetCameraCaptureOrientation());
        Guid RotationKey = new Guid("C380465D-2271-428C-9B83-ECEA3B4A85C1");
        encodingProfile.Video.Properties.Add(RotationKey, PropertyValue.CreateInt32(rotationAngle));

        await mediaCapture.StartRecordToStorageFileAsync(encodingProfile, videoFile);
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine("Exception when starting video recording: {0}", ex.ToString());
    }
}

Полный список кода CameraRotationHelper

Следующий фрагмент кода содержит полный код класса CameraRotationHelper , который управляет датчиками ориентации оборудования, вычисляет правильные значения ориентации для фотографий и видео и предоставляет вспомогательные методы для преобразования между различными представлениями ориентации, используемыми различными функциями Windows. Если вы следуйте инструкциям, приведенным в приведенной выше статье, вы можете добавить этот класс в проект как есть без необходимости вносить какие-либо изменения. Конечно, вы можете легко настроить следующий код в соответствии с потребностями конкретного сценария.

Этот вспомогательный класс использует simpleOrientationSensor устройства для определения текущей ориентации корпуса устройства и класса DisplayInformation для определения текущей ориентации дисплея. Каждый из этих классов предоставляет события, возникающие при изменении текущей ориентации. Панель, на которой подключено устройство захвата — переднее, заднее или внешнее — используется для определения необходимости зеркального отображения потока предварительного просмотра. Кроме того, свойство EnclosureLocation.RotationAngleInDegreesClockwise , поддерживаемое некоторыми устройствами, используется для определения ориентации, в которой камера подключена на чехлах.

Для получения рекомендуемых значений ориентации для указанных задач приложения камеры можно использовать следующие методы:

  • GetUIOrientation — возвращает рекомендуемую ориентацию для элементов пользовательского интерфейса камеры.
  • GetCameraCaptureOrientation — возвращает предлагаемую ориентацию для кодирования в метаданные изображения.
  • GetCameraPreviewOrientation — возвращает рекомендуемую ориентацию для потока предварительной версии, чтобы обеспечить естественный пользовательский интерфейс.
class CameraRotationHelper
{
    private EnclosureLocation _cameraEnclosureLocation;
    private DisplayInformation _displayInformation = DisplayInformation.GetForCurrentView();
    private SimpleOrientationSensor _orientationSensor = SimpleOrientationSensor.GetDefault();
    public event EventHandler<bool> OrientationChanged;

    public CameraRotationHelper(EnclosureLocation cameraEnclosureLocation)
    {
        _cameraEnclosureLocation = cameraEnclosureLocation;
        if (!IsEnclosureLocationExternal(_cameraEnclosureLocation))
        {
            _orientationSensor.OrientationChanged += SimpleOrientationSensor_OrientationChanged;
        }
        _displayInformation.OrientationChanged += DisplayInformation_OrientationChanged;
    }

    private void SimpleOrientationSensor_OrientationChanged(SimpleOrientationSensor sender, SimpleOrientationSensorOrientationChangedEventArgs args)
    {
        if (args.Orientation != SimpleOrientation.Faceup && args.Orientation != SimpleOrientation.Facedown)
        {
            HandleOrientationChanged(false);
        }
    }

    private void DisplayInformation_OrientationChanged(DisplayInformation sender, object args)
    {
        HandleOrientationChanged(true);
    }

    private void HandleOrientationChanged(bool updatePreviewStreamRequired)
    {
        var handler = OrientationChanged;
        if (handler != null)
        {
            handler(this, updatePreviewStreamRequired);
        }
    }

    public static bool IsEnclosureLocationExternal(EnclosureLocation enclosureLocation)
    {
        return (enclosureLocation == null || enclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Unknown);
    }

    private bool IsCameraMirrored()
    {
        // Front panel cameras are mirrored by default
        return (_cameraEnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Front);
    }

    private SimpleOrientation GetCameraOrientationRelativeToNativeOrientation()
    {
        // Get the rotation angle of the camera enclosure
        return ConvertClockwiseDegreesToSimpleOrientation((int)_cameraEnclosureLocation.RotationAngleInDegreesClockwise);
    }

    // Gets the rotation to rotate ui elements
    public SimpleOrientation GetUIOrientation()
    {
        if (IsEnclosureLocationExternal(_cameraEnclosureLocation))
        {
            // Cameras that are not attached to the device do not rotate along with it, so apply no rotation
            return SimpleOrientation.NotRotated;
        }

        // Return the difference between the orientation of the device and the orientation of the app display
        var deviceOrientation = _orientationSensor.GetCurrentOrientation();
        var displayOrientation = ConvertDisplayOrientationToSimpleOrientation(_displayInformation.CurrentOrientation);
        return SubOrientations(displayOrientation, deviceOrientation);
    }

    // Gets the rotation of the camera to rotate pictures/videos when saving to file
    public SimpleOrientation GetCameraCaptureOrientation()
    {
        if (IsEnclosureLocationExternal(_cameraEnclosureLocation))
        {
            // Cameras that are not attached to the device do not rotate along with it, so apply no rotation
            return SimpleOrientation.NotRotated;
        }

        // Get the device orienation offset by the camera hardware offset
        var deviceOrientation = _orientationSensor.GetCurrentOrientation();
        var result = SubOrientations(deviceOrientation, GetCameraOrientationRelativeToNativeOrientation());

        // If the preview is being mirrored for a front-facing camera, then the rotation should be inverted
        if (IsCameraMirrored())
        {
            result = MirrorOrientation(result);
        }
        return result;
    }

    // Gets the rotation of the camera to display the camera preview
    public SimpleOrientation GetCameraPreviewOrientation()
    {
        if (IsEnclosureLocationExternal(_cameraEnclosureLocation))
        {
            // Cameras that are not attached to the device do not rotate along with it, so apply no rotation
            return SimpleOrientation.NotRotated;
        }

        // Get the app display rotation offset by the camera hardware offset
        var result = ConvertDisplayOrientationToSimpleOrientation(_displayInformation.CurrentOrientation);
        result = SubOrientations(result, GetCameraOrientationRelativeToNativeOrientation());

        // If the preview is being mirrored for a front-facing camera, then the rotation should be inverted
        if (IsCameraMirrored())
        {
            result = MirrorOrientation(result);
        }
        return result;
    }

    public static PhotoOrientation ConvertSimpleOrientationToPhotoOrientation(SimpleOrientation orientation)
    {
        switch (orientation)
        {
            case SimpleOrientation.Rotated90DegreesCounterclockwise:
                return PhotoOrientation.Rotate90;
            case SimpleOrientation.Rotated180DegreesCounterclockwise:
                return PhotoOrientation.Rotate180;
            case SimpleOrientation.Rotated270DegreesCounterclockwise:
                return PhotoOrientation.Rotate270;
            case SimpleOrientation.NotRotated:
            default:
                return PhotoOrientation.Normal;
        }
    }

    public static int ConvertSimpleOrientationToClockwiseDegrees(SimpleOrientation orientation)
    {
        switch (orientation)
        {
            case SimpleOrientation.Rotated90DegreesCounterclockwise:
                return 270;
            case SimpleOrientation.Rotated180DegreesCounterclockwise:
                return 180;
            case SimpleOrientation.Rotated270DegreesCounterclockwise:
                return 90;
            case SimpleOrientation.NotRotated:
            default:
                return 0;
        }
    }

    private SimpleOrientation ConvertDisplayOrientationToSimpleOrientation(DisplayOrientations orientation)
    {
        SimpleOrientation result;
        switch (orientation)
        {
            case DisplayOrientations.Landscape:
                result = SimpleOrientation.NotRotated;
                break;
            case DisplayOrientations.PortraitFlipped:
                result = SimpleOrientation.Rotated90DegreesCounterclockwise;
                break;
            case DisplayOrientations.LandscapeFlipped:
                result = SimpleOrientation.Rotated180DegreesCounterclockwise;
                break;
            case DisplayOrientations.Portrait:
            default:
                result = SimpleOrientation.Rotated270DegreesCounterclockwise;
                break;
        }

        // Above assumes landscape; offset is needed if native orientation is portrait
        if (_displayInformation.NativeOrientation == DisplayOrientations.Portrait)
        {
            result = AddOrientations(result, SimpleOrientation.Rotated90DegreesCounterclockwise);
        }

        return result;
    }

    private static SimpleOrientation MirrorOrientation(SimpleOrientation orientation)
    {
        // This only affects the 90 and 270 degree cases, because rotating 0 and 180 degrees is the same clockwise and counter-clockwise
        switch (orientation)
        {
            case SimpleOrientation.Rotated90DegreesCounterclockwise:
                return SimpleOrientation.Rotated270DegreesCounterclockwise;
            case SimpleOrientation.Rotated270DegreesCounterclockwise:
                return SimpleOrientation.Rotated90DegreesCounterclockwise;
        }
        return orientation;
    }

    private static SimpleOrientation AddOrientations(SimpleOrientation a, SimpleOrientation b)
    {
        var aRot = ConvertSimpleOrientationToClockwiseDegrees(a);
        var bRot = ConvertSimpleOrientationToClockwiseDegrees(b);
        var result = (aRot + bRot) % 360;
        return ConvertClockwiseDegreesToSimpleOrientation(result);
    }

    private static SimpleOrientation SubOrientations(SimpleOrientation a, SimpleOrientation b)
    {
        var aRot = ConvertSimpleOrientationToClockwiseDegrees(a);
        var bRot = ConvertSimpleOrientationToClockwiseDegrees(b);
        //add 360 to ensure the modulus operator does not operate on a negative
        var result = (360 + (aRot - bRot)) % 360;
        return ConvertClockwiseDegreesToSimpleOrientation(result);
    }

    private static VideoRotation ConvertSimpleOrientationToVideoRotation(SimpleOrientation orientation)
    {
        switch (orientation)
        {
            case SimpleOrientation.Rotated90DegreesCounterclockwise:
                return VideoRotation.Clockwise270Degrees;
            case SimpleOrientation.Rotated180DegreesCounterclockwise:
                return VideoRotation.Clockwise180Degrees;
            case SimpleOrientation.Rotated270DegreesCounterclockwise:
                return VideoRotation.Clockwise90Degrees;
            case SimpleOrientation.NotRotated:
            default:
                return VideoRotation.None;
        }
    }

    private static SimpleOrientation ConvertClockwiseDegreesToSimpleOrientation(int orientation)
    {
        switch (orientation)
        {
            case 270:
                return SimpleOrientation.Rotated90DegreesCounterclockwise;
            case 180:
                return SimpleOrientation.Rotated180DegreesCounterclockwise;
            case 90:
                return SimpleOrientation.Rotated270DegreesCounterclockwise;
            case 0:
            default:
                return SimpleOrientation.NotRotated;
        }
    }
}