화면 캡처

Windows. Graphics.Capture 네임스페이스는 디스플레이 또는 애플리케이션 창에서 프레임을 획득하고, 비디오 스트림 또는 스냅샷을 만들어 공동 작업 및 대화형 환경을 빌드하는 API를 제공합니다.

화면 캡처를 사용하면 개발자는 최종 사용자가 캡처할 디스플레이 또는 애플리케이션 창을 선택할 수 있도록 보안 시스템 UI를 호출하고, 시스템에서 활성 캡처된 항목 주위에 노란색 알림 테두리를 그립니다. 여러 동시 캡처 세션의 경우 캡처되는 각 항목 주위에 노란색 테두리가 그려집니다.

메모

화면 캡처 API는 Windows 데스크톱 디바이스 및 Windows Mixed Reality 몰입형 헤드셋에서만 지원됩니다.

이 문서에서는 디스플레이 또는 애플리케이션 창의 단일 이미지를 캡처하는 것에 대해 설명합니다.

화면 캡처 지원 확인

캡처를 시도하기 전에 현재 디바이스에서 화면 캡처를 지원하는지 확인합니다. GraphicsCaptureSession에서 IsSupported 메서드를 사용하여 화면 캡처를 사용할 수 있는지 확인합니다.

// Check if screen capture is supported
if (!GraphicsCaptureSession.IsSupported())
{
    // Hide capture UI
    CaptureControlsPanel.Visibility = Visibility.Collapsed;
    PreviewPlaceholderText.Text = "Screen capture isn't supported on this device.";
    UpdateStatus("Screen capture isn't supported on this device.");
    return;
}

디바이스가 하드웨어 요구 사항을 충족하지 않는 경우를 포함하여 화면 캡처가 지원되지 않는 몇 가지 이유가 있습니다.

시스템 UI를 시작하여 화면 캡처 시작

GraphicsCapturePicker 클래스를 사용하여 시스템 선택기 UI를 호출합니다. 최종 사용자는 이 UI를 사용하여 캡처할 디스플레이 또는 애플리케이션 창을 선택합니다. 선택기는 캡처 세션을 만드는 데 사용되는 GraphicsCaptureItem 을 반환합니다.

WinUI 3 앱에서는 PickSingleItemAsync를 호출하기 전에 창 핸들을 사용하여 선택기를 초기화해야 합니다.

// Launch picker and start capture
var picker = new GraphicsCapturePicker();
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
WinRT.Interop.InitializeWithWindow.Initialize(picker, hwnd);
GraphicsCaptureItem item = await picker.PickSingleItemAsync();
if (item != null)
{
    StartCaptureInternal(item);
}

캡처 프레임 풀 만들기 및 캡처 세션

GraphicsCaptureItem을 사용하여 D3D 디바이스, 지원되는 픽셀 형식(DXGI_FORMAT_B8G8R8A8_UNORM), 원하는 프레임 수(정수일 수 있음) 및 프레임 크기로 Direct3D11CaptureFramePool을 만듭니다. GraphicsCaptureItem 클래스의 Size 속성을 프레임의 크기로 사용할 수 있습니다.

// Create frame pool and capture session
_framePool = Direct3D11CaptureFramePool.Create(
    _canvasDevice,
    CaptureDirectXPixelFormat.B8G8R8A8UIntNormalized,
    BufferCount,
    item.Size);
_session = _framePool.CreateCaptureSession(item);

메모

Windows HD 색을 사용하는 시스템에서 콘텐츠 픽셀 형식이 반드시 DXGI_FORMAT_B8G8R8A8_UNORM 아닐 수도 있습니다. HDR 콘텐츠를 캡처할 때 픽셀 오버클래핑(즉, 캡처된 콘텐츠가 씻겨 나감)을 방지하려면 CanvasBitmap과 같은 대상 대상인 Direct3D11CaptureFramePool을 포함하여 캡처 파이프라인의 모든 구성 요소에 DXGI_FORMAT_R16G16B16A16_FLOAT 사용하는 것이 좋습니다. 필요에 따라 HDR 콘텐츠 형식 또는 HDR-SDR 톤 매핑에 저장하는 등의 추가 처리가 필요할 수 있습니다. 이 문서에서는 SDR 콘텐츠 캡처에 중점을 둡니다. 자세한 내용은 동적 범위 디스플레이 및 고급 색이 높은 DirectX 사용을 참조하세요.

사용자가 애플리케이션 창을 캡처하거나 시스템 UI에 표시하는 데 명시적으로 동의하면 GraphicsCaptureItem 을 여러 캡처 세션과 연결할 수 있습니다. 이렇게 하면 애플리케이션에서 다양한 환경에 대해 동일한 항목을 캡처하도록 선택할 수 있습니다.

캡처 프레임 획득

프레임 풀 및 캡처 세션을 만든 상태에서 GraphicsCaptureSession 인스턴스에서 StartCapture를 호출하여 캡처 프레임을 앱에 보내기 시작하도록 시스템에 알립니다.

Direct3D11CaptureFrame 개체인 이러한 캡처 프레임을 획득하려면 Direct3D11CaptureFramePool.FrameArrived 이벤트를 사용합니다.

// Handle frame arrival
_framePool.FrameArrived += OnFrameArrived;

새 프레임을 사용할 수 있게 될 때마다 이 이벤트가 발생하므로 FrameArrived의 UI 스레드에서 많은 작업을 수행하지 않는 것이 좋습니다. UI 스레드에서 FrameArrived 를 수신 대기하도록 선택한 경우 이벤트가 발생할 때마다 얼마나 많은 작업을 수행하는지 염두에 두어야 합니다.

또는 필요한 모든 프레임을 가져올 때까지 Direct3D11CaptureFramePool.TryGetNextFrame 메서드를 사용하여 프레임을 수동으로 끌어올 수 있습니다.

Direct3D11CaptureFrame 개체에는 ContentSize, SurfaceSystemRelativeTime 속성이 포함됩니다. SystemRelativeTime은 다른 미디어 요소를 동기화하는 데 사용할 수 있는 QPC(QueryPerformanceCounter) 시간입니다.

프로세스 캡처 프레임

Direct3D11CaptureFramePool의 각 프레임은 TryGetNextFrame을 호출할 때 체크 아웃되고 Direct3D11CaptureFrame 개체의 수명에 따라 다시 체크 인됩니다. 관리되는 애플리케이션의 경우 Direct3D11CaptureFrame.Dispose 메서드를 사용하는 것이 좋습니다. Direct3D11CaptureFrameIDisposable을 구현하므로 프레임을 삭제하면 버퍼가 풀에 반환됩니다.

애플리케이션은 Direct3D11CaptureFrame 개체에 대한 참조를 저장해서는 안 되며 프레임이 다시 체크 인된 후 기본 Direct3D 화면에 대한 참조를 저장해서는 안 됩니다.

이 예제에서 각 프레임은 Win2D 라이브러리의 일부인 CanvasBitmap으로 변환됩니다.

// Convert frame to Win2D bitmap and display
CanvasBitmap canvasBitmap = CanvasBitmap.CreateFromDirect3D11Surface(
    _canvasDevice,
    frame.Surface);

기본 Direct3D 화면은 Direct3D11CaptureFramePool을 만들거나 다시 만들 때 항상 지정된 크기입니다. 콘텐츠가 프레임보다 크면 콘텐츠가 프레임 크기로 잘립니다. 콘텐츠가 프레임보다 작으면 프레임의 나머지 부분에 정의되지 않은 데이터가 포함됩니다. 정의되지 않은 콘텐츠가 표시되지 않도록 애플리케이션은 해당 Direct3D11CaptureFrameContentSize 속성을 사용하여 하위 사각형 영역을 복사하는 것이 좋습니다.

스크린샷 저장

CanvasBitmap이 있으면 이미지 파일로 저장할 수 있습니다. 다음 예제에서는 FileSavePicker 사용하여 현재 프레임을 PNG 파일로 저장합니다. WinUI 3 앱에서는 창 핸들을 사용하여 선택기를 초기화해야 합니다.

// Save screenshot
var savePicker = new FileSavePicker();
savePicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
savePicker.SuggestedFileName = "screen-capture";
savePicker.FileTypeChoices.Add("PNG image", new List<string> { ".png" });
WinRT.Interop.InitializeWithWindow.Initialize(savePicker, _hwnd);
StorageFile? file = await savePicker.PickSaveFileAsync();
if (file is not null)
{
    using var fileStream = await file.OpenAsync(FileAccessMode.ReadWrite);
    await frameToSave.SaveAsync(fileStream, CanvasBitmapFileFormat.Png, 1f);
}

캡처 항목 크기 변경 또는 디바이스 손실에 반응

캡처 프로세스 중에 애플리케이션은 Direct3D11CaptureFramePool의 측면을 변경할 수 있습니다. 여기에는 새 Direct3D 디바이스 제공, 프레임 버퍼 크기 변경 또는 풀 내의 버퍼 수 변경이 포함됩니다. 이러한 각 시나리오에서 Direct3D11CaptureFramePool 개체의 Recreate 메서드를 사용하는 것이 좋습니다.

Recreate가 호출되면 모든 기존 프레임이 삭제됩니다. 이는 기본 Direct3D 표면이 애플리케이션에 더 이상 액세스할 수 없는 디바이스에 속하는 프레임을 전달하지 않도록 하기 위한 것입니다. 이러한 이유로 Recreate를 호출하기 전에 보류 중인 모든 프레임을 처리하는 것이 현명할 수 있습니다.

WinUI 3 고려 사항

UWP에서 WinUI 3(Windows 앱 SDK)로 화면 캡처 코드를 마이그레이션할 때는 다음과 같은 차이점을 염두에 두어야 합니다.

  • 창 핸들 초기화GraphicsCapturePickerFileSavePicker와 같은 선택기는 InitializeWithWindow를 사용해 창 핸들로 초기화해야 합니다. 자세한 내용은 HWND(창 핸들 검색)를 참조하세요.
  • UI 스레드의 컴퍼지션 API - WinUI 3에서는 DispatcherQueue.TryEnqueue를 사용하여 CanvasComposition 표면 작업(예: CompositionDrawingSurface에 그리기)을 UI 스레드로 디스패치해야 합니다. 프레임 캡처 및 비트맵 만들기는 프레임 풀의 백그라운드 스레드에서 발생할 수 있지만 UI 스레드에서 컴퍼지션 시각적 개체를 업데이트해야 합니다.
  • Namespace 변경 내용Microsoft.UI.Composition 대신 Microsoft.UI.Xaml.Hosting, Microsoft.UI.DispatchingWindows.UI 사용합니다. Windows.Graphics.Capture 네임스페이스는 변경되지 않은 상태로 유지됩니다.

참고하십시오