MediaCapture용 형식, 해상도 및 프레임 속도 선택Set format, resolution, and frame rate for MediaCapture

이 문서에서는 IMediaEncodingProperties 인터페이스를 사용 하 여 카메라 미리 보기 스트림과 캡처한 사진 및 비디오의 해상도 및 프레임 주기를 설정 하는 방법을 보여 줍니다.This article shows you how to use the IMediaEncodingProperties interface to set the resolution and frame rate of the camera preview stream and captured photos and video. 또한 미리 보기 스트림의 가로 세로 비율이 캡처된 미디어와 일치 하는지 확인 하는 방법도 보여 줍니다.It also shows how to ensure that the aspect ratio of the preview stream matches that of the captured media.

카메라 프로필은 카메라의 스트림 속성을 검색 하 고 설정 하는 고급 방법을 제공 하지만 모든 장치에 대해 지원 되지 않습니다.Camera profiles offer a more advanced way of discovering and setting the stream properties of the camera, but they are not supported for all devices. 자세한 내용은 카메라 프로필을 참조 하세요.For more information, see Camera profiles.

이 문서의 코드는 CameraResolution 샘플에서 도입 되었습니다.The code in this article was adapted from the CameraResolution sample. 샘플을 다운로드 하 여 컨텍스트에서 사용 되는 코드를 확인 하거나 사용자 고유의 앱에 대 한 시작 지점으로 샘플을 사용할 수 있습니다.You can download the sample to see the code used in context or to use the sample as a starting point for your own app.

참고

이 문서는 기본 사진 및 비디오 캡처를 구현 하는 단계를 설명 하는 MediaCapture을 사용 하 여 기본 사진, 비디오 및 오디오 캡처에 설명 된 개념 및 코드를 기반으로 합니다.This article builds on concepts and code discussed in Basic photo, video, and audio capture with MediaCapture, which describes the steps for implementing basic photo and video capture. 고급 캡처 시나리오로 전환 하기 전에 해당 문서의 기본적인 미디어 캡처 패턴을 숙지 하는 것이 좋습니다.It is recommended that you familiarize yourself with the basic media capture pattern in that article before moving on to more advanced capture scenarios. 이 문서의 코드는 앱에 이미 올바르게 초기화 된 MediaCapture 인스턴스가 있다고 가정 합니다.The code in this article assumes that your app already has an instance of MediaCapture that has been properly initialized.

미디어 인코딩 속성 도우미 클래스A media encoding properties helper class

IMediaEncodingProperties 인터페이스의 기능을 래핑하는 간단한 도우미 클래스를 만들면 특정 조건을 충족 하는 인코딩 속성 집합을 쉽게 선택할 수 있습니다.Creating a simple helper class to wrap the functionality of the IMediaEncodingProperties interface makes it easier to select a set of encoding properties that meet particular criteria. 이 도우미 클래스는 인코딩 속성 기능의 다음 동작 때문에 특히 유용 합니다.This helper class is particularly useful due to the following behavior of the encoding properties feature:

경고    VideoDeviceController 메서드는 VideoRecord 또는 Photo와 같은 mediastreamtype 열거의 멤버를 사용 하 고 캡처된 사진 또는 비디오의 해상도와 같이 스트림 인코딩 설정을 전달 하는 ImageEncodingProperties 또는 VideoEncodingProperties 개체의 목록을 반환 합니다.Warning   The VideoDeviceController.GetAvailableMediaStreamProperties method takes a member of the MediaStreamType enumeration, such as VideoRecord or Photo, and returns a list of either ImageEncodingProperties or VideoEncodingProperties objects that convey the stream encoding settings, such as the resolution of the captured photo or video. GetAvailableMediaStreamProperties 호출 결과에는 지정 된 mediastreamtype 값에 관계 없이 ImageEncodingProperties 또는 VideoEncodingProperties 가 포함 될 수 있습니다.The results of calling GetAvailableMediaStreamProperties may include ImageEncodingProperties or VideoEncodingProperties regardless of what MediaStreamType value is specified. 따라서 항상 반환 된 각 값의 형식을 확인 하 고 속성 값에 액세스 하기 전에 적절 한 형식으로 캐스팅 해야 합니다.For this reason, you should always check the type of each returned value and cast it to the appropriate type before attempting to access any of the property values.

아래에 정의 된 도우미 클래스는 ImageEncodingProperties 또는 VideoEncodingProperties 에 대 한 형식 검사 및 캐스트를 처리 하므로 앱 코드에서 두 형식을 구분할 필요가 없습니다.The helper class defined below handles the type checking and casting for ImageEncodingProperties or VideoEncodingProperties so that your app code doesn't need to distinguish between the two types. 이 외에도 도우미 클래스는 속성의 가로 세로 비율, 프레임 비율 (비디오 인코딩 속성의 경우에만 해당) 및 응용 프로그램의 UI에서 인코딩 속성을 더 쉽게 표시할 수 있는 친숙 한 이름에 대 한 속성을 노출 합니다.In addition to this, the helper class exposes properties for the aspect ratio of the properties, the frame rate (for video encoding properties only), and a friendly name that makes it easier to display the encoding properties in the app's UI.

도우미 클래스의 소스 파일에는 Windows. MediaProperties 네임 스페이스를 포함 해야 합니다.You must include the Windows.Media.MediaProperties namespace in the source file for the helper class.

using Windows.Media.MediaProperties;
using Windows.Media.Capture.Frames;
class StreamPropertiesHelper
{
    private IMediaEncodingProperties _properties;

    public StreamPropertiesHelper(IMediaEncodingProperties properties)
    {
        if (properties == null)
        {
            throw new ArgumentNullException(nameof(properties));
        }

        // This helper class only uses VideoEncodingProperties or VideoEncodingProperties
        if (!(properties is ImageEncodingProperties) && !(properties is VideoEncodingProperties))
        {
            throw new ArgumentException("Argument is of the wrong type. Required: " + typeof(ImageEncodingProperties).Name
                + " or " + typeof(VideoEncodingProperties).Name + ".", nameof(properties));
        }

        // Store the actual instance of the IMediaEncodingProperties for setting them later
        _properties = properties;
    }

    public uint Width
    {
        get
        {
            if (_properties is ImageEncodingProperties)
            {
                return (_properties as ImageEncodingProperties).Width;
            }
            else if (_properties is VideoEncodingProperties)
            {
                return (_properties as VideoEncodingProperties).Width;
            }

            return 0;
        }
    }

    public uint Height
    {
        get
        {
            if (_properties is ImageEncodingProperties)
            {
                return (_properties as ImageEncodingProperties).Height;
            }
            else if (_properties is VideoEncodingProperties)
            {
                return (_properties as VideoEncodingProperties).Height;
            }

            return 0;
        }
    }

    public uint FrameRate
    {
        get
        {
            if (_properties is VideoEncodingProperties)
            {
                if ((_properties as VideoEncodingProperties).FrameRate.Denominator != 0)
                {
                    return (_properties as VideoEncodingProperties).FrameRate.Numerator / 
                        (_properties as VideoEncodingProperties).FrameRate.Denominator;
                }
           }

            return 0;
        }
    }

    public double AspectRatio
    {
        get { return Math.Round((Height != 0) ? (Width / (double)Height) : double.NaN, 2); }
    }

    public IMediaEncodingProperties EncodingProperties
    {
        get { return _properties; }
    }

    public string GetFriendlyName(bool showFrameRate = true)
    {
        if (_properties is ImageEncodingProperties ||
            !showFrameRate)
        {
            return Width + "x" + Height + " [" + AspectRatio + "] " + _properties.Subtype;
        }
        else if (_properties is VideoEncodingProperties)
        {
            return Width + "x" + Height + " [" + AspectRatio + "] " + FrameRate + "FPS " + _properties.Subtype;
        }

        return String.Empty;
    }
    
}

미리 보기 및 캡처 스트림이 독립적인 지 확인Determine if the preview and capture streams are independent

일부 장치에서는 미리 보기 스트림과 캡처 스트림 모두에 동일한 하드웨어 pin이 사용 됩니다.On some devices, the same hardware pin is used for both preview and capture streams. 이러한 장치에서 한 인코딩 속성을 설정 하는 것도 다른 장치를 설정 합니다.On these devices, setting the encoding properties of one will also set the other. 캡처 및 미리 보기에 대해 다른 하드웨어 pin을 사용 하는 장치에서는 각 스트림에 대해 독립적으로 속성을 설정할 수 있습니다.On devices that use different hardware pins for capture and preview, the properties can be set for each stream independently. 미리 보기 및 캡처 스트림이 독립적인 지 확인 하려면 다음 코드를 사용 합니다.Use the following code to determine if the preview and capture streams are independent. 이 테스트의 결과에 따라 독립적으로 스트림 설정을 사용 하거나 사용 하지 않도록 UI를 조정 해야 합니다.You should adjust your UI to enable or disable the setting of the streams independently based on the result of this test.

private void CheckIfStreamsAreIdentical()
{
    if (_mediaCapture.MediaCaptureSettings.VideoDeviceCharacteristic == VideoDeviceCharacteristic.AllStreamsIdentical ||
        _mediaCapture.MediaCaptureSettings.VideoDeviceCharacteristic == VideoDeviceCharacteristic.PreviewRecordStreamsIdentical)
    {
        ShowMessageToUser("Preview and video streams for this device are identical. Changing one will affect the other");
    }
}

사용 가능한 스트림 속성 목록 가져오기Get a list of available stream properties

앱의 MediaCapture 개체에 대 한 VideoDeviceController 을 가져온 다음 GetAvailableMediaStreamProperties 를 호출 하 고 mediastreamtype 값, VideoPreview, VideoRecord또는 Photo중 하나를 전달 하 여 캡처 장치에 사용할 수 있는 스트림 속성의 목록을 가져옵니다.Get a list of the available stream properties for a capture device by getting the VideoDeviceController for your app's MediaCapture object and then calling GetAvailableMediaStreamProperties and passing in one of the MediaStreamType values, VideoPreview, VideoRecord, or Photo. 이 예제에서는 Linq 구문을 사용 하 여 GetAvailableMediaStreamProperties에서 반환 된 각 IMediaEncodingProperties 값에 대해이 문서 앞에서 정의 된 stream 도우미 개체 목록을 IMediaEncodingProperties 만듭니다.In this example, Linq syntax is used to create a list of StreamPropertiesHelper objects, defined previously in this article, for each of the IMediaEncodingProperties values returned from GetAvailableMediaStreamProperties. 이 예제에서는 먼저 Linq 확장 메서드를 사용 하 여 먼저 해상도에 따라 반환 된 속성을 정렬 한 다음 프레임 속도로 정렬 합니다.This example first uses Linq extension methods to order the returned properties based first on resolution and then on frame rate.

앱에 특정 해상도 또는 프레임 요금 요구 사항이 있는 경우 프로그래밍 방식으로 미디어 인코딩 속성 집합을 선택할 수 있습니다.If your app has specific resolution or frame rate requirements, you can select a set of media encoding properties programmatically. 표준 카메라 앱은 대신 UI에서 사용 가능한 속성 목록을 표시 하 고 사용자가 원하는 설정을 선택할 수 있습니다.A typical camera app will instead expose the list of available properties in the UI and allow the user to select their desired settings. 목록에서 StreamComboBoxItem helper 개체 목록의 각 항목에 대 한 ComboBoxItem 생성 됩니다.A ComboBoxItem is created for each item in the list of StreamPropertiesHelper objects in the list. 콘텐츠는 도우미 클래스에서 반환 되는 이름으로 설정 되 고 태그는 도우미 클래스 자체로 설정 되므로 나중에 연결 된 인코딩 속성을 검색 하는 데 사용할 수 있습니다.The content is set to the friendly name returned by the helper class and the tag is set to the helper class itself so it can be used later to retrieve the associated encoding properties. 그런 다음 메서드에 전달 된 ComboBox 에 각 ComboBoxItem 추가 됩니다.Each ComboBoxItem is then added to the ComboBox passed into the method.

private void PopulateStreamPropertiesUI(MediaStreamType streamType, ComboBox comboBox, bool showFrameRate = true)
{
    // Query all properties of the specified stream type 
    IEnumerable<StreamPropertiesHelper> allStreamProperties = 
        _mediaCapture.VideoDeviceController.GetAvailableMediaStreamProperties(streamType).Select(x => new StreamPropertiesHelper(x));

    // Order them by resolution then frame rate
    allStreamProperties = allStreamProperties.OrderByDescending(x => x.Height * x.Width).ThenByDescending(x => x.FrameRate);

    // Populate the combo box with the entries
    foreach (var property in allStreamProperties)
    {
        ComboBoxItem comboBoxItem = new ComboBoxItem();
        comboBoxItem.Content = property.GetFriendlyName(showFrameRate);
        comboBoxItem.Tag = property;
        comboBox.Items.Add(comboBoxItem);
    }
}

원하는 스트림 속성 설정Set the desired stream properties

SetMediaStreamPropertiesAsync를 호출 하 여 원하는 인코딩 속성을 사용 하도록 비디오 장치 컨트롤러에 지시 하 고 photo, video 또는 preview 속성을 설정 해야 하는지 여부를 나타내는 mediastreamtype 값을 전달 합니다.Tell the video device controller to use your desired encoding properties by calling SetMediaStreamPropertiesAsync, passing in the MediaStreamType value indicating whether the photo, video, or preview properties should be set. 이 예제에서는 사용자가 PopulateStreamPropertiesUI helper 메서드로 채워진 ComboBox 개체 중 하나에서 항목을 선택할 때 요청 된 인코딩 속성을 설정 합니다.This example sets the requested encoding properties when the user selects an item in one of the ComboBox objects populated with the PopulateStreamPropertiesUI helper method.

private async void PreviewSettings_Changed(object sender, RoutedEventArgs e)
{
    if (_isPreviewing)
    {
        var selectedItem = (sender as ComboBox).SelectedItem as ComboBoxItem;
        var encodingProperties = (selectedItem.Tag as StreamPropertiesHelper).EncodingProperties;
        await _mediaCapture.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.VideoPreview, encodingProperties);
    }
}
private async void PhotoSettings_Changed(object sender, RoutedEventArgs e)
{
    if (_isPreviewing)
    {
        var selectedItem = (sender as ComboBox).SelectedItem as ComboBoxItem;
        var encodingProperties = (selectedItem.Tag as StreamPropertiesHelper).EncodingProperties;
        await _mediaCapture.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.Photo, encodingProperties);
    }
}
private async void VideoSettings_Changed(object sender, RoutedEventArgs e)
{
    if (_isPreviewing)
    {
        var selectedItem = (sender as ComboBox).SelectedItem as ComboBoxItem;
        var encodingProperties = (selectedItem.Tag as StreamPropertiesHelper).EncodingProperties;
        await _mediaCapture.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.VideoRecord, encodingProperties);
    }
}

미리 보기 및 캡처 스트림의 가로 세로 비율과 일치Match the aspect ratio of the preview and capture streams

일반적인 카메라 앱은 사용자가 비디오 또는 사진 캡처 해상도를 선택할 수 있는 UI를 제공 하지만 프로그래밍 방식으로 미리 보기 해상도를 설정 합니다.A typical camera app will provide UI for the user to select the video or photo capture resolution but will programmatically set the preview resolution. 앱에 가장 적합 한 미리 보기 스트림 해상도를 선택 하기 위한 몇 가지 전략이 있습니다.There are a few different strategies for selecting the best preview stream resolution for your app:

  • 사용 가능한 가장 높은 미리 보기 해상도를 선택 하면 UI 프레임 워크가 미리 보기의 필요한 크기 조정을 수행할 수 있습니다.Select the highest available preview resolution, letting the UI framework perform any necessary scaling of the preview.

  • 캡처 해상도와 가장 가까운 미리 보기 해상도를 선택 하 여 미리 보기에 캡처된 최종 미디어에 가장 가까운 표현이 표시 되도록 합니다.Select the preview resolution closest to the capture resolution so that the preview displays the closest representation to the final captured media.

  • CaptureElement 크기에 가장 가까운 미리 보기 해상도를 선택 하 여 필요한 것 보다 많은 픽셀이 미리 보기 스트림 파이프라인을 통과 하지 않도록 합니다.Select the preview resolution closest to the size of the CaptureElement so that no more pixels than necessary are going through the preview stream pipeline.

중요    일부 장치에서는 카메라의 미리 보기 스트림과 캡처 스트림에 대해 다른 가로 세로 비율을 설정할 수 있습니다.Important   It is possible, on some devices, to set a different aspect ratio for the camera's preview stream and capture stream. 이 불일치로 인해 프레임을 자르는 경우 미리 보기에 표시 되지 않는 콘텐츠가 캡처된 미디어에 표시 될 수 있으며,이로 인해 사용자 환경이 저하 될 수 있습니다.Frame cropping caused by this mismatch can result in content being present in the captured media that was not visible in the preview which can result in a negative user experience. 미리 보기 및 캡처 스트림에는 작은 허용 오차 창 내에서 동일한 가로 세로 비율을 사용 하는 것이 좋습니다.It is strongly recommended that you use the same aspect ratio, within a small tolerance window, for the preview and capture streams. 가로 세로 비율이 가깝게 일치 하는 경우 캡처 및 미리 보기에 대해 완전히 다른 해결 방법을 사용할 수 있습니다.It is fine to have entirely different resolutions enabled for capture and preview as long as the aspect ratio match closely.

사진 또는 비디오 캡처 스트림이 미리 보기 스트림의 가로 세로 비율과 일치 하는지 확인 하기 위해이 예제에서는 VideoDeviceController 를 호출 하 고 VideoPreview 열거형 값을 전달 하 여 미리 보기 스트림에 대 한 현재 스트림 속성을 요청 합니다.To ensure that the photo or video capture streams match the aspect ratio of the preview stream, this example calls VideoDeviceController.GetMediaStreamProperties and passes in the VideoPreview enum value to request the current stream properties for the preview stream. 다음에는 작은 가로 비율 허용 오차 창이 정의 되어 있으므로 미리 보기 스트림과 정확히 일치 하지 않는 가로 세로 비율을 포함할 수 있습니다.Next a small aspect ratio tolerance window is defined so that we can include aspect ratios that are not exactly the same as the preview stream, as long as they are close. 그런 다음, Linq 확장 메서드는 가로 세로 비율이 미리 보기 스트림의 정의 된 허용 범위 내에 있는 Streamobjects 도우미 개체만 선택 하는 데 사용 됩니다.Next, a Linq extension method is used to select just the StreamPropertiesHelper objects where the aspect ratio is within the defined tolerance range of the preview stream.

private void MatchPreviewAspectRatio(MediaStreamType streamType, ComboBox comboBox)
{
    // Query all properties of the specified stream type
    IEnumerable<StreamPropertiesHelper> allVideoProperties = 
        _mediaCapture.VideoDeviceController.GetAvailableMediaStreamProperties(streamType).Select(x => new StreamPropertiesHelper(x));

    // Query the current preview settings
    StreamPropertiesHelper previewProperties = new StreamPropertiesHelper(_mediaCapture.VideoDeviceController.GetMediaStreamProperties(MediaStreamType.VideoPreview));

    // Get all formats that have the same-ish aspect ratio as the preview
    // Allow for some tolerance in the aspect ratio comparison
    const double ASPECT_RATIO_TOLERANCE = 0.015;
    var matchingFormats = allVideoProperties.Where(x => Math.Abs(x.AspectRatio - previewProperties.AspectRatio) < ASPECT_RATIO_TOLERANCE);

    // Order them by resolution then frame rate
    allVideoProperties = matchingFormats.OrderByDescending(x => x.Height * x.Width).ThenByDescending(x => x.FrameRate);

    // Clear out old entries and populate the video combo box with new matching entries
    comboBox.Items.Clear();
    foreach (var property in allVideoProperties)
    {
        ComboBoxItem comboBoxItem = new ComboBoxItem();
        comboBoxItem.Content = property.GetFriendlyName();
        comboBoxItem.Tag = property;
        comboBox.Items.Add(comboBoxItem);
    }
    comboBox.SelectedIndex = -1;
}