擷取遊戲音訊、影片、螢幕擷取畫面和中繼資料Capture game audio, video, screenshots, and metadata

本文說明如何擷取遊戲影片、音訊和螢幕擷取畫面,以及如何提交系統將會嵌入所擷取和廣播的媒體中的元資料,讓您的 App 和其他人可建立與遊戲活動同步的動態遊戲體驗。This article describes how to capture game video, audio, and screenshots, and how to submit metadata that the system will embed in captured and broadcast media, allowing your app and others to create dynamic experiences that are synchronized to gameplay events.

有兩種不同方式可在 UWP app 中擷取遊戲。There are two different ways that gameplay can be captured in a UWP app. 使用者可以使用內建的系統 UI 起始擷取。The user can initiate capture using the built-in system UI. 使用這項技術所捕捉的媒體會內嵌到 Microsoft 遊戲生態系統中,您可以透過第一方的體驗(例如 Xbox 應用程式)來查看和共用,而且不能直接用於您的應用程式或使用者。Media that is captured using this technique is ingested into the Microsoft gaming ecosystem, can be viewed and shared through first-party experiences such as the Xbox app, and is not directly availble to your app or to users. 本文的第一節顯示如何啟用和停用系統實作的 App 擷取,以及如何在 App 擷取開始或停止時接收通知。The first sections of this article will show you how to enable and disable system-implemented app capture and how to receive notifications when app capture starts or stops.

擷取媒體的其他方式是使用 Windows.Media.AppRecording 命名空間的 API。The other way to capture media is to use the APIs of the Windows.Media.AppRecording namespace. 如果在裝置上啟用擷取,您的 App 可以開始擷取遊戲,然後在經過一段時間後,您可以停止擷取,此時媒體會寫入檔案。If capturing is enabled on the device, your app can start capturing gameplay and then, after some time has passed, you can stop the capture, at which point the media is written to a file. 如果使用者已啟用歷史擷取,您也可以錄製已經發生的遊戲,只要指定過去的開始時間和要錄製的持續時間即可。If the user has enabled historical capture, then you can also record gameplay that has already occured by specifying a start time in the past and a duration to record. 這兩種技術都會產生您的 App 和使用者可以存取的影片檔案,並根據您選擇的位置儲存檔案。Both of these techniques produce an video file that can be accessed by your app, and depending on where you choose to save the files, by the user. 本文的中間章節會帶領您實作這些案例。The middle sections of this article walk you through the implemenation of these scenarios.

Windows.Media.Capture 命名空間提供 API,用於建立描述將擷取或廣播之遊戲的元資料。The Windows.Media.Capture namespace provides APIs for creating metadata that describes the gameplay being captured or broadcast. 這可包含文字或數值,還有識別每個資料項目的文字標籤。This can include text or numeric values, with a text label identifying each data item. 元資料可以代表單一時刻發生的「事件」,例如在使用者完成賽車遊戲的一圈時,或者也可以代表持續一段時間的「狀態」,例如目前使用者正在玩的遊戲中的地圖。Metadata can represent an "event" which occurs at a single moment, such as when the user finishes a lap in a racing game, or it can represent a "state" that persists over a span of time, such as the current game map the user is playing in. 元資料是寫入快取中,而快取則是由系統為您的 App 進行配置和管理。The metadata is written to a cache that is allocated and managed for your app by the system. 元資料是內嵌到廣播串流及擷取的影片檔案中,同時包括內建的系統擷取或自訂的 App 擷取技術。The metadata is embedded into broadcast streams and captured video files, including both the built-in system capture or custom app capture techniques. 本文的最後一節顯示如何撰寫遊戲元資料。The final sections of this article show you how to write gameplay metadata.

注意

因為遊戲元資料可內嵌到可能透過網路共用的媒體檔案,使用者無法加以控制,所以不應在元資料中包含可識別個人的資訊或其他潛在的敏感資料。Because the gameplay metadata can be embedded in media files that can potentially be shared over the network, out of the user's control, you should not include personally identifiable information or other potentially sensitive data in the metadata.

啟用和停用系統 App 擷取Enable and disable system app capture

系統 App 擷取是由使用者使用內建的系統 UI 起始System app capture is initiated by the user with the built-in system UI. 這些檔案是由 Windows 遊戲生態系統所內嵌,並不適用于您的應用程式或使用者,除了透過第一方體驗(如 Xbox 應用程式)之外。The files are ingested by the Windows gaming ecosystem and is not available to your app or the user, except for through first party experiences like the Xbox app. 您的 App 可以停用和啟用系統起始的 App 擷取,讓您得以防止使用者擷取特定內容或遊戲。Your app can disable and enable system-initiated app capture, allowing you to prevent the user from capturing certain content or gameplay.

若要啟用或停用系統 App 擷取,只要呼叫靜態方法 AppCapture.SetAllowedAsync 並傳送 false 來停用擷取或傳送 true 啟用擷取。To enable or disable system app capture, simply call the static method AppCapture.SetAllowedAsync and passing false to disable capture or true to enable capture.

Windows::Media::Capture::AppCapture::SetAllowedAsync(allowed);

當系統 App 擷取開始和停止時收到通知Receive notifications when system app capture starts and stops

若要在系統 App 擷取開始或結束時收到通知,請先透過呼叫 Factory 方法 GetForCurrentView 來取得 AppCapture 類別的執行個體。To receive a notification when system app capture begins or ends, first get an instance of the AppCapture class by calling the factory method GetForCurrentView. 接著,註冊 CapturingChanged 事件的處理常式。Next, register a handler for the CapturingChanged event.

Windows::Media::Capture::AppCapture^ appCapture = Windows::Media::Capture::AppCapture::GetForCurrentView();
appCapture->CapturingChanged +=
    ref new TypedEventHandler<Windows::Media::Capture::AppCapture^, Platform::Object^>(this, &App::OnCapturingChanged);

CapturingChanged 事件的處理常式中,您可以檢查 IsCapturingAudioIsCapturingVideo 屬性,以判斷是否分別擷取音訊或影片。In the handler for the CapturingChanged event, you can check the IsCapturingAudio and the IsCapturingVideo properties to determine if audio or video are being captured respectively. 若要指出目前的擷取狀態,您可以更新您的 App 的 UI。You may want to update your app's UI to indicate the current capturing status.

void App::OnCapturingChanged(Windows::Media::Capture::AppCapture^ sender, Platform::Object^ args)
{
    Platform::String^ captureStatusText = "";
    if (sender->IsCapturingAudio)
    {
        captureStatusText += "Capturing audio.";
    }
    if (sender->IsCapturingVideo)
    {
        captureStatusText += "Capturing video.";
    }
    UpdateStatusText(captureStatusText);
}

將 UWP 的 Windows 桌面延伸新增到您的 AppAdd the Windows Desktop Extensions for the UWP to your app

直接從您的 App 錄製音訊和影片的 API 和擷取螢幕擷取畫面的 API,可在 Windows.Media.AppRecording 命名空間中找到,並未包含在通用 API 協定中。The APIs for recording audio and video and for capturing screenshots directly from your app, found in the Windows.Media.AppRecording namespace, are not included in the Universal API contract. 若要存取 API,您必須利用下列步驟將 UWP 的 Windows 桌面延伸的參考新增到您的 App。To access the APIs, you must add a reference to the Windows Desktop Extensions for the UWP to your app with the following steps.

  1. 在 Visual Studio 中,請在 [方案總管] 中展開 UWP 專案,以滑鼠右鍵按一下 [參考],然後選取 [加入參考...]In Visual Studio, in Solution Explorer, expand your UWP project and right-click References and then select Add Reference....
  2. 展開 [通用 Windows] 節點,然後選取 [延伸]Expand the Universal Windows node and select Extensions.
  3. 在延伸清單中,核取符合您專案的目標組建的 [UWP 的 Windows 桌面延伸] 項目旁的核取方塊。In the list of extensions check the checkbox next to the Windows Desktop Extensions for the UWP entry that matches the target build for your project. 若是 App 的廣播功能,版本必須是 1709 或以上。For the app broadcast features, the version must be 1709 or greater.
  4. 按一下 [確定] 。Click OK.

取得 AppRecordingManager 的執行個體Get an instance of AppRecordingManager

AppRecordingManager 類別是您將用來管理 App 錄製的中央 API。The AppRecordingManager class is the central API you will use to manage app recording. 透過呼叫 Factory 方法 GetDefault 取得的此類別的執行個體。Get an instance of this class by calling the factory method GetDefault. 使用 Windows.Media.AppRecording 命名空間中的任何 API 之前,應該檢查其是否存在於目前的裝置上。Before using any of the APIs in the Windows.Media.AppRecording namespace, you should check for their presence on the current device. API 在執行 Windows 10 版本 1709 之前的作業系統版本的裝置上無法使用。The APIs are not available on devices running an OS version earlier than Windows 10, version 1709. 與其檢查特定的作業系統版本,不如使用 ApiInformation.IsApiContractPresent 方法來查詢 Windows.Media.AppBroadcasting.AppRecordingContract 1.0 版。Rather than check for a specific OS version, use the ApiInformation.IsApiContractPresent method to query for the Windows.Media.AppBroadcasting.AppRecordingContract version 1.0. 如果有此協定,則可在裝置上錄製 API。If this contract is present, then the recording APIs are available on the device. 本文中的範例程式碼會檢查一次 API,然後在進行後續作業之前檢查 AppRecordingManager 是否為 null。The example code in this article checks for the APIs once and then checks if the AppRecordingManager is null before subsequent operations.

if (Windows::Foundation::Metadata::ApiInformation::IsApiContractPresent(
    "Windows.Media.AppRecording.AppRecordingContract", 1, 0))
{
    m_appRecordingManager = AppRecordingManager::GetDefault();
}

判斷您的 App 目前是否可以錄製Determine if your app can currently record

有幾個原因您的 App 可能目前無法擷取音訊或影片,包括目前的裝置是否不符合錄製的硬體需求,或者其他 App 目前正在廣播中。There are several reasons that your app may not currently be able to capture audio or video, including if the current device doesn't meet the hardware requirements for recording or if another app is currently broadcasting. 在起始錄製之前,您可以檢查您的 App 是否目前無法錄製。Before initiating a recording, you can check to see if your app is currently able to record. 呼叫 AppRecordingManager 物件的 GetStatus 方法,然後檢查傳回之 AppRecordingStatus 物件的 CanRecord 屬性。Call the GetStatus method of the AppRecordingManager object and then check the CanRecord property of the returned AppRecordingStatus object. 如果 CanRecord 傳回 false,表示您的應用程式目前無法錄製,您可以查看 詳細資料 屬性來判斷原因。If CanRecord returns false, meaning that your app can't currently record, you can check the Details property to determine the reason. 根據原因而定,您可能想要對使用者顯示狀態,或顯示啟用 App 錄製的指示。Depending on the reason, you may want to display the status to the user or show instructions for enabling app recording.

bool App::CanRecord()
{

    if (m_appRecordingManager == nullptr)
    {
        return false;
    }

    AppRecordingStatus^ recordingStatus = m_appRecordingManager->GetStatus();

    if (!recordingStatus->CanRecord)
    {
        AppRecordingStatusDetails^ details = recordingStatus->Details;
    
        if (details->IsAnyAppBroadcasting)
        {
            UpdateStatusText("Another app is currently broadcasting.");
            return false;
        }

        if (details->IsCaptureResourceUnavailable)
        {
            UpdateStatusText("The capture resource is currently unavailable.");
            return false;
        }

        if (details->IsGameStreamInProgress)
        {
            UpdateStatusText("A game stream is currently in progress.");
            return false;
        }

        if (details->IsGpuConstrained)
        {
            // Typically, this means that the GPU software does not include an H264 encoder
            UpdateStatusText("The GPU does not support app recording.");
            return false;
        }

        
        if (details->IsAppInactive)
        {
            // Broadcasting can only be started when the application's window is the active window.
            UpdateStatusText("The app window to be recorded is not active.");
            return false;
        }

        if (details->IsBlockedForApp)
        {
            UpdateStatusText("Recording is blocked for this app.");
            return false;
        }

        if (details->IsDisabledByUser)
        {
            UpdateStatusText("The user has disabled GameBar in Windows Settings.");
            return false;
        }

        if (details->IsDisabledBySystem)
        {
            UpdateStatusText("Recording is disabled by the system.");
            return false;
        }

        
        return false;
    }


    return true;
}

手動開始和停止錄製您的 App 到檔案中Manually start and stop recording your app to a file

確認您的 App 可以錄製之後,即可透過呼叫 AppRecordingManager 物件的 StartRecordingToFileAsync 方法開始新的錄製。After verifying that your app is able to record, you can start a new recording by calling the StartRecordingToFileAsync method of the AppRecordingManager object.

在下列範例中,當非同步工作失敗時,第一個 then 會封鎖執行。In the following example, the first then block executes when the asynchronous task fails. 第二個 then 會封鎖嘗試存取工作的結果,如果結果為 null,則工作已完成。The second then block attempts to access the result of the task and, if the result is null, then the task has completed. 在這兩個案例中,如下所示,會呼叫 OnRecordingComplete 協助程式方法來處理結果。In both cases, the OnRecordingComplete helper method, shown below, is called to handle the result.

void App::StartRecordToFile(Windows::Storage::StorageFile^ file)
{

    if (m_appRecordingManager == nullptr)
    {
        return;
    }

    if (!CanRecord())
    {
        return;
    }


    // Start a recording operation to record starting from 
    // now until the operation fails or is cancelled. 
    m_recordOperation = m_appRecordingManager->StartRecordingToFileAsync(file);

    create_task(m_recordOperation).then(
        [this](AppRecordingResult^ result)
    {
        OnRecordingComplete();
    }).then([this](task<void> t)
    {
        try
        {
            t.get();
        }
        catch (const task_canceled&)
        {
            OnRecordingComplete();
        }
    });
}

當錄製作業完成時,檢查傳回之 AppRecordingResult 物件的 Succeeded 屬性,以判斷錄製作業是否成功。When the recording operation completes, check the Succeeded property of the returned AppRecordingResult object to determine if the record operation was successful. 若成功,您可以檢查 IsFileTruncated 屬性來判斷系統是否基於儲存空間的原因被迫截斷所擷取的檔案。If so, you can check the IsFileTruncated property to determine if, for storage reasons, the system was forced to truncate the captured file. 您可以檢查 Duration 屬性,以了解錄製檔案的實際持續時間,如果檔案被截斷,可能比錄製作業的持續時間較短。You can check the Duration property to discover the actual duration of the recorded file which, if the file is truncated, may be shorter than the duration of the recording operation.

void App::OnRecordingComplete()
{
    if (m_recordOperation)
    {
        auto result = m_recordOperation->GetResults();

        if (result->Succeeded)
        {
            Windows::Foundation::TimeSpan duration = result->Duration;
            boolean isTruncated = result->IsFileTruncated;

            UpdateStatusText("Recording completed.");
        }
        else
        {
            // If the recording failed, ExtendedError 
            // can be retrieved and used for diagnostic purposes 
            HResult extendedError = result->ExtendedError;
            LogTelemetryMessage("Error during recording: " + extendedError);
        }

        m_recordOperation = nullptr;
    }
}

下列範例顯示先前範例中開始和停止錄製作業的一些基本程式碼。The following examples show some basic code for starting and stopping the recording operation shown in the previous example.

StorageFolder^ storageFolder = ApplicationData::Current->LocalFolder;
concurrency::create_task(storageFolder->CreateFileAsync("recordtofile_example.mp4", CreationCollisionOption::ReplaceExisting)).then(
    [this](StorageFile^ file)
{
    StartRecordToFile(file);
});
void App::FinishRecordToFile()
{
    m_recordOperation->Cancel();
}

錄製歷史時間範圍到檔案Record a historical time span to a file

如果使用者已在系統設定中為您的 App 啟用歷史錄製,您可以錄製之前已玩過遊戲的時間範圍。If the user has enabled historical recording for your app in the system settings, you can record a time span of gameplay that has previously transpired. 本文中的上一個範例顯示如何確認您的 App 目前是否可以錄製遊戲。A previous example in this article showed how to confirm that your app can currently record gameplay. 還有其他檢查可以判斷是否啟用歷史擷取。There is an additional check to determine if historical capture is enabled. 同樣地,呼叫 GetStatus,並檢查傳回之 AppRecordingStatus 物件的 CanRecordTimeSpan 屬性。Once again, call GetStatus and check the CanRecordTimeSpan property of the returned AppRecordingStatus object. 此範例也傳回 AppRecordingStatusHistoricalBufferDuration 屬性,將用來判斷錄製作業的有效開始時間。This example also returns the HistoricalBufferDuration property of the AppRecordingStatus which will be used to determine a valid start time for the recording operation.

bool App::CanRecordTimeSpan(TimeSpan &historicalDurationBuffer)
{

    if (m_appRecordingManager == nullptr)
    {
        return false;
    }

    AppRecordingStatus^ recordingStatus = m_appRecordingManager->GetStatus();
    if (recordingStatus->Details->IsTimeSpanRecordingDisabled)
    {
        UpdateStatusText("Historical time span recording is disabled by the system.");
        return false;
    }

    historicalDurationBuffer = recordingStatus->HistoricalBufferDuration;

    return true;
}

若要擷取歷史時間範圍,您必須指定錄製的開始時間和持續時間。To capture a historical timespan, you must specify a start time for the recording and a duration. 開始時間是以 DateTime 結構提供。The start time is provided as a DateTime struct. 開始時間必須是在目前的時間之前,歷史錄製緩衝的長度之內。The start time must be a time before the current time, within the length of the historical recording buffer. 就此範例而言,擷取緩衝長度是檢查的一部分,如上一個程式碼範例所示,可查看歷史錄製是否啟用。For this example, the buffer length is retrieved as part of the check to see if historical recording is enabled, which is shown in the previous code example. 歷史錄製的持續時間是以 TimeSpan 結構提供,也應該等於或小於歷史緩衝的持續時間。The duration of the historical recording is provided as TimeSpan struct, which should also be equal to or smaller than the duration of the historical buffer. 一旦您確定您想要的開始時間和持續時間後,呼叫 RecordTimeSpanToFileAsync 以開始錄製作業。Once you have determined your desired start time and duration, call RecordTimeSpanToFileAsync to start the recording operation.

如同手動開始和停止錄製,當歷史錄製完成時,您可以檢查傳回之 AppRecordingResult 物件的 Succeeded 屬性來判斷錄製作業是否成功,並且可以檢查 IsFileTruncatedDuration 屬性,了解所錄製檔案的實際持續時間,檔案若被截斷,可能比所要求時間範圍的持續時間來得短。Like recording with manual start and stop, when a historical recording completes, you can check the Succeeded property of the returned AppRecordingResult object to determine if the record operation was successful, and you can check the IsFileTruncated and Duration property to discover the actual duration of the recorded file which, if the file is truncated, may be shorter than the duration of the requested time window.

void App::RecordTimeSpanToFile(Windows::Storage::StorageFile^ file)
{


    if (m_appRecordingManager == nullptr)
    {
        return;
    }

    if (!CanRecord())
    {
        return;
    }

    Windows::Foundation::TimeSpan historicalBufferDuration;
    if (!CanRecordTimeSpan(historicalBufferDuration))
    {
        return;
    }
    

    AppRecordingStatus^ recordingStatus = m_appRecordingManager->GetStatus();
    
    Windows::Globalization::Calendar^ calendar = ref new Windows::Globalization::Calendar();
    calendar->SetToNow();

    Windows::Foundation::DateTime nowTime = calendar->GetDateTime();

    int secondsToRecord = min(30, historicalBufferDuration.Duration / 10000000);
    calendar->AddSeconds(-1 * secondsToRecord);

    Windows::Foundation::DateTime  startTime = calendar->GetDateTime();

    Windows::Foundation::TimeSpan duration;

    duration.Duration = nowTime.UniversalTime - startTime.UniversalTime;

    create_task(m_appRecordingManager->RecordTimeSpanToFileAsync(startTime, duration, file)).then(
        [this](AppRecordingResult^ result)
    {
        if (result->Succeeded)
        {
            Windows::Foundation::TimeSpan duration = result->Duration;
            boolean isTruncated = result->IsFileTruncated;
            UpdateStatusText("Recording completed.");
        }
        else
        {
            // If the recording failed, ExtendedError
            // can be retrieved and used for diagnostic purposes
            HResult extendedError = result->ExtendedError;
            LogTelemetryMessage("Error during recording: " + extendedError);
        }
    });

}

下列範例顯示先前範例中起始歷史錄製作業的一些基本程式碼。The following example shows some basic code for initiating the historical record operation shown in the previous example.

StorageFolder^ storageFolder = ApplicationData::Current->LocalFolder;
concurrency::create_task(storageFolder->CreateFileAsync("recordtimespantofile_example.mp4", CreationCollisionOption::ReplaceExisting)).then(
    [this](StorageFile^ file)
{
    RecordTimeSpanToFile(file);
});

儲存螢幕擷取畫面的影像到檔案Save screenshot images to files

您的 App 可以起始螢幕擷取畫面的擷取,將 App 視窗的目前內容儲存到一個影像檔或到不同影像編碼的多個影像檔。Your app can initiate a screenshot capture that will save the current contents of the app's window to one image file or to multiple image files with different image encodings. 若要指定您想要使用的影像編碼,請建立一份字串清單,其中每個字串代表一種影像類型。To specify the image encodings you would like to use, create a list of strings where each represents an image type. ImageEncodingSubtypes 的屬性為每一種支援的影像類型 (例如 MediaEncodingSubtypes.PngMediaEncodingSubtypes.JpegXr) 提供正確的字串。The properties of the ImageEncodingSubtypes provide the correct string for each supported image type, such as MediaEncodingSubtypes.Png or MediaEncodingSubtypes.JpegXr.

透過呼叫 AppRecordingManager 物件的 SaveScreenshotToFilesAsync 方法,來起始螢幕擷取。Initiate screen capture by calling the SaveScreenshotToFilesAsync method of the AppRecordingManager object. 此方法的第一個參數是 StorageFolder,影像檔案將會儲存在其中。The first parameter to this method is a StorageFolder where the image files will be saved. 第二個參數是檔案名稱前置詞,系統將為每種儲存的影像類型附加副檔名,例如「.png」。The second parameter is a filename prefix to which the system will append the extension for each image type saved, such as ".png".

如果要擷取的目前視窗顯示 HDR 內容,SaveScreenshotToFilesAsync 的第三個參數是系統為了能夠執行正確的色彩空間轉換所必要的。The third parameter to SaveScreenshotToFilesAsync is necessary for the system to be able to do the proper colorspace conversion if the current window to be captured is displaying HDR content. 如果有 HDR 內容,此參數應該設定為 AppRecordingSaveScreenshotOption.HdrContentVisibleIf HDR content is present, this parameter should be set to AppRecordingSaveScreenshotOption.HdrContentVisible. 否則,請使用 AppRecordingSaveScreenshotOption.NoneOtherwise, use AppRecordingSaveScreenshotOption.None. 此方法的最後一個參數,是應該擷取之螢幕的影像格式清單。The final parameter to the method is the list of image formats to which the screen should be captured.

當非同步呼叫 SaveScreenshotToFilesAsync 完成時,它會傳回 AppRecordingSavedScreenshotInfo 物件,其為每個儲存的影像提供 StorageFile 和表示影像類型的相關 MediaEncodingSubtypes 值。When the asynchronous call to SaveScreenshotToFilesAsync completes, it returns a AppRecordingSavedScreenshotInfo object that provides the StorageFile and associated MediaEncodingSubtypes value indicating the image type for each saved image.

void App::SaveScreenShotToFiles(Windows::Storage::StorageFolder^ folder, Platform::String^ filenamePrefix)
{

    if (m_appRecordingManager == nullptr)
    {
        return;
    }


    Windows::Foundation::Collections::IVectorView<Platform::String^>^ supportedFormats = 
        m_appRecordingManager->SupportedScreenshotMediaEncodingSubtypes;

    
    Platform::Collections::Vector<Platform::String^>^ requestedFormats = 
        ref new Platform::Collections::Vector<Platform::String^>();

    for (Platform::String^ format : requestedFormats)
    {
        if (format == Windows::Media::MediaProperties::MediaEncodingSubtypes::Png)
        {
            requestedFormats->Append(format);
        }
        else if (format == Windows::Media::MediaProperties::MediaEncodingSubtypes::JpegXr)
        {
            requestedFormats->Append(format);
        }
    }


    create_task(m_appRecordingManager->SaveScreenshotToFilesAsync(folder, filenamePrefix, AppRecordingSaveScreenshotOption::None,
        requestedFormats->GetView())).then(
            [this](AppRecordingSaveScreenshotResult^ result)
    {
        if (result->Succeeded)
        {
            Windows::Foundation::Collections::IVectorView<AppRecordingSavedScreenshotInfo^>^ returnedScreenshots = result->SavedScreenshotInfos;

            for (AppRecordingSavedScreenshotInfo^ screenshotInfo : returnedScreenshots)
            {
                Windows::Storage::StorageFile^ file = screenshotInfo->File;
                Platform::String^ type = screenshotInfo->MediaEncodingSubtype;
            }
        }
        else
        {
            // If the recording failed, ExtendedError 
            // can be retrieved and used for diagnostic purposes 
            HResult extendedError = result->ExtendedError;
            LogTelemetryMessage("Error during screenshot: " + extendedError);
        }
    });
}

下列範例顯示先前範例中起始螢幕擷取畫面作業的一些基本程式碼。The following example shows some basic code for initiating the screenshot operation shown in the previous example.

StorageFolder^ storageFolder = ApplicationData::Current->LocalFolder;
SaveScreenShotToFiles(storageFolder, "screen_capture");

新增適用於系統和應用程式起始之擷取的遊戲元資料Add game metadata for system and app-initiated capture

本文的下列章節描述如何提供元資料,讓系統嵌入所擷取或廣播的遊戲的 MP4 串流。The following sections of this article describe how to provide metadata that the system will embed into the MP4 stream of captured or broadcast gameplay. 元資料可嵌入使用內建的系統 UI 擷取的媒體和 App 使用 AppRecordingManager 擷取的媒體。Metadata can be embedded in media that is captured using the built-in system UI and media that is captured by the app with AppRecordingManager. 這個元資料可在媒體播放期間由您的 App 和其他 App 擷取,以便提供與所擷取或廣播的遊戲同步的內容感知體驗。This metadata can be extracted by your app and other apps during media playback in order to provide contextually-aware experiences that are synchronized with the captured or broadcast gameplay.

取得 AppCaptureMetadataWriter 的執行個體Get an instance of AppCaptureMetadataWriter

管理 App 擷取元資料的主要類別是 AppCaptureMetadataWriterThe primary class for managing app capture metadata is AppCaptureMetadataWriter. 初始化此類別的執行個體之前,請使用 ApiInformation.IsApiContractPresent 方法查詢 Windows.Media.Capture.AppCaptureMetadataContract 版本 1.0,以確認 API 可在目前的裝置上使用。Before initializing an instance of this class, use the ApiInformation.IsApiContractPresent method to query for the Windows.Media.Capture.AppCaptureMetadataContract version 1.0 to verify that the API is available on the current device.

if (Windows::Foundation::Metadata::ApiInformation::IsApiContractPresent("Windows.Media.Capture.AppCaptureMetadataContract", 1, 0))
{
    m_appCaptureMetadataWriter = ref new AppCaptureMetadataWriter();
}

為您的 App 將元資料寫入系統快取Write metadata to the system cache for your app

每個元資料項目都有字串標籤,識別元資料項目、相關聯的資料值,其可能是字串、整數或雙精確度值,以及來自 AppCaptureMetadataPriority 列舉的值,其指出資料項目的相關優先順序。Each metadata item has a string label, identifying the metadata item, an associated data value which can be a string, an integer, or a double value, and a value from the AppCaptureMetadataPriority enumeration indicating the relative priority of the data item. 元資料項目可能被視為「事件」,即發生在單一時間點,或保持一個值一段時間的「狀態」。A metadata item can either be considered an "event", which occurs at a single point in time, or a "state" which maintains a value over a time window. 元資料是寫入記憶體中,而記憶體則是由系統為您的 App 進行配置和管理。Metadata is written to a memory cache that is allocated and managed for your app by the system. 系統會對元資料記憶體快取強制執行大小限制,並且在達到上限時,根據每個寫入的元資料項目的優先順序清除資料。The system enforces a size limit on the metadata memory cache and, when the limit is reached, will purge data based on the priority with which each metadata item was written. 本文的下一個章節將顯示如何管理您的 App 元資料記憶體配置。The next section of this article shows how to manage your app's metadata memory allocation.

一般的 App 可以選擇在擷取工作階段的開頭寫入一些元資料,以提供後續的資料一些內容。A typical app may choose to write some metadata at the beginning of the capture session to provide some context for the subsequent data. 對於本案例,建議使用瞬間的「事件」資料。For this scenario it is recommended that you use instantaneous "event" data. 此範例呼叫 AddStringEventAddDoubleEventAddInt32Event,來為每一種資料類型設定瞬間值。This example calls AddStringEvent, AddDoubleEvent, and AddInt32Event to set instantaneous values for each data type.

void App::StartSession(Platform::String^ sessionId, double averageFps, int resolutionWidth, int resolutionHeight)
{
    if (m_appCaptureMetadataWriter != nullptr)
    {
        m_appCaptureMetadataWriter->AddStringEvent("sessionId", sessionId, AppCaptureMetadataPriority::Informational);
        m_appCaptureMetadataWriter->AddDoubleEvent("averageFps", averageFps, AppCaptureMetadataPriority::Informational);
        m_appCaptureMetadataWriter->AddInt32Event("resolutionWidth", resolutionWidth, AppCaptureMetadataPriority::Informational);
        m_appCaptureMetadataWriter->AddInt32Event("resolutionHeight", resolutionHeight, AppCaptureMetadataPriority::Informational);
    }
}

使用持續一段時間的「狀態」的常見案例,是去追蹤目前玩家還在其中的遊戲地圖。A common scenario for using "state" data that persists over time is to track the game map that the player is currently within. 這個範例呼叫 StartStringState 來設定狀態值。This example calls StartStringState to set the state value.

void App::StartMap(Platform::String^ mapName)
{
    m_appCaptureMetadataWriter->StartStringState("map", mapName, AppCaptureMetadataPriority::Important);
}

呼叫 StopState 以錄製已經結束的特定狀態。Call StopState to record that a particular state has ended.

void App::EndMap(Platform::String^ mapName)
{
    m_appCaptureMetadataWriter->StopState("map");
}

您可以透過使用現有的狀態標籤設定新值,來覆寫狀態。You can overwrite a state by setting a new value with an existing state label.

void App::LevelUp(int newLevel)
{
    m_appCaptureMetadataWriter->StartInt32State("currentLevel", newLevel, AppCaptureMetadataPriority::Important);
}

您可以藉由呼叫 StopAllStates 來結束所有打開的狀態。You can end all currently open states by calling StopAllStates.

void App::RaceComplete()
{
    m_appCaptureMetadataWriter->StopAllStates();
}

管理元資料快取儲存空間的限制Manage metadata cache storage limit

您使用 AppCaptureMetadataWriter 撰寫的元資料,會由系統快取直到其寫入相關聯的媒體串流。The metadata that you write with AppCaptureMetadataWriter is cached by the system until it is written to the associated media stream. 系統會定義每個 App 元資料快取的大小限制。The system defines a size limit for each app's metadata cache. 一旦達到快取的大小限制,系統會開始清除快取的元資料。Once the cache size limit has been reached, the system will begin purging cached metadata. 系統會先刪除以 AppCaptureMetadataPriority 撰寫的中繼資料,再刪除具有 AppCaptureMetadataPriority 的中繼資料。 重要 優先順序。The system will delete metadata that was written with AppCaptureMetadataPriority.Informational priority value before deleting metadata with the AppCaptureMetadataPriority.Important priority.

任何時候,您都可以透過呼叫 RemainingStorageBytesAvailable 來查看您的 App 元資料快取中可用的位元組數。At any point, you can check to see the number of bytes available in your app's metadata cache by calling RemainingStorageBytesAvailable. 您可以選擇設定您自己的 App 定義的閾值,之後您可以選擇減少要寫入快取的元資料量。You can choose to set your own app-defined threshold after which you can choose to reduce the amount of metadata that you write to the cache. 下列範例顯示此模式的簡單實作。The following example shows a simple implementation of this pattern.

void App::CheckMetadataStorage()
{
    INT64 storageRemaining = m_appCaptureMetadataWriter->RemainingStorageBytesAvailable;

    if (storageRemaining < m_myLowStorageLevelInBytes)
    {
        m_writeLowPriorityMetadata = false;
    }
}
void App::ComboExecuted(Platform::String^ comboName)
{
    if (m_writeLowPriorityMetadata)
    {
        m_appCaptureMetadataWriter->AddStringEvent("combo", comboName, AppCaptureMetadataPriority::Informational);
    }
}

當系統清除元資料時收到通知Receive notifications when the system purges metadata

您可以註冊,以在系統開始清除應用程式的中繼資料時收到通知,方法是註冊 MetadataPurged 事件的處理常式。You can register to receive a notification when the system begins purging metadata for your app by registering a handler for the MetadataPurged event.

if (m_appCaptureMetadataWriter != nullptr)
{
    m_appCaptureMetadataWriter->MetadataPurged += 
        ref new TypedEventHandler<AppCaptureMetadataWriter^, Platform::Object^>(this, &App::OnMetadataPurged);

}

MetadataPurged 事件的處理常式中,您可以透過結束較低優先順序的狀態,在元資料快取中清出一些空間,您可以實作 App 定義的邏輯,來減少寫入快取中的元資料量,或者您可以什麼都不做,讓系統繼續根據所撰寫的優先順序清除快取。In the handler for the MetadataPurged event, you can clear up some room in the metadata cache by ending lower-priority states, you can implement app-defined logic for reducing the amount of metadata you write to the cache, or you can do nothing and let the system continue to purge the cache based on the priority with which it was written.

void App::OnMetadataPurged(Windows::Media::Capture::AppCaptureMetadataWriter^ sender, Platform::Object^ args)
{
    // Reduce metadata by stopping a low-priority state.
    //m_appCaptureMetadataWriter->StopState("map");

    // Reduce metadata by stopping all states.
    //m_appCaptureMetadataWriter->StopAllStates();

    // Change app-specific behavior to write less metadata.
    //m_writeLowPriorityMetadata = false;

    // Take no action. Let the system purge data as needed. Record event for telemetry.
    OutputDebugString(TEXT("Low-priority metadata purged."));

}