ゲームのオーディオ、ビデオ、スクリーンショット、メタデータのキャプチャ

この記事では、ゲームのビデオ、オーディオ、スクリーン ショットをキャプチャする方法や、キャプチャおよびブロードキャストされるメディアにシステムが埋め込むメタデータを送信して、アプリや他のユーザーがゲームプレイのイベントに同期する動的なエクスペリエンスを作成できるようにする方法について説明します。

UWP アプリでゲームプレイをキャプチャするには、2 つの方法があります。 ユーザーは、組み込みのシステム UI を使用してキャプチャを開始できます。 この手法を使用してキャプチャされたメディアは、Microsoft ゲーム エコシステムに取り込まれ、Xbox アプリなど、ファースト パーティのエクスペリエンスを通して表示、共有されます。アプリやユーザーが、直接使用することはできません。 この記事の最初のセクションでは、システムに実装されたアプリのキャプチャを有効または無効にする方法と、アプリのキャプチャが開始または停止されたときに通知を受信する方法を示します。

メディアをキャプチャするもう 1 つの方法は、Windows.Media.AppRecording 名前空間の API を使用する方法です。 デバイスでキャプチャが有効になっている場合、アプリはゲームプレイのキャプチャを開始し、しばらく時間が経過した後、キャプチャを停止できます。その時点で、メディアはファイルに書き込まれます。 ユーザーが履歴のキャプチャを有効にしている場合、過去の開始時刻と記録の継続時間を指定することによって、既に発生したゲームプレイも記録できます。 これらのいずれの手法でも、アプリでアクセスできるビデオ ファイルが生成されます。また、ファイルを保存するために選択した場所によっては、ユーザーがアクセスできるビデオ ファイルが生成されます。 この記事の中ほどのセクションでは、これらのシナリオを実装する手順について説明します。

Windows.Media.Capture 名前空間は、キャプチャまたはブロードキャストされるゲームプレイを説明するメタデータを作成するための API を提供します。 これには、テキストや数値を、各データ項目を識別するテキスト ラベルと共に含めることができます。 メタデータは、1 つの時点で発生する "イベント" (ユーザーがレーシング ゲームでコースを走り終えたときなど) を表すことができます。また、一定期間保持される "状態" (ユーザーがプレイしている現在のゲーム マップなど) を表すこともできます。 メタデータは、システムによってアプリ用に割り当てられて管理されるキャッシュに書き込まれます。 メタデータは、組み込みのシステム キャプチャとカスタム アプリによるキャプチャのいずれの手法でも、ブロードキャスト ストリームやキャプチャしたビデオ ファイルに埋め込まれます。 この記事の最後のセクションでは、ゲームプレイのメタデータを書き込む方法について説明します。

注意

ゲームプレイのメタデータは、潜在的に、ネットワーク上でユーザーの制御の範囲外で共有できるメディア ファイルに埋め込まれる可能性があるため、個人を特定できる情報やその他の潜在的な機密データをメタデータに含めないでください。

システムによるアプリのキャプチャを有効または無効にする

システムによるアプリのキャプチャは、ユーザーによって、組み込みのシステム UI を使用して開始されます。 ファイルは、Windows ゲーム エコシステムによって取り込まれ、アプリやユーザーから使用することはできません。ただし、Xbox アプリなどのファースト パーティ エクスペリエンスによる場合は例外です。 アプリでは、システムによって開始されるアプリのキャプチャを無効または有効にすることができ、ユーザーが特定のコンテンツやゲームプレイをキャプチャできないように設定できます。

システムによるアプリのキャプチャを有効または無効にするには、静的メソッド AppCapture.SetAllowedAsync を呼び出して、キャプチャを無効にする場合は false を、キャプチャを有効にする場合は true を渡すだけです。

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

システムによるアプリのキャプチャが開始および停止したときに通知を受信する

システムによるアプリのキャプチャが開始または終了されたときに通知を受信するには、最初に、ファクトリ メソッド GetForCurrentView を呼び出すことによって、AppCapture クラスのインスタンスを取得します。 次に、CapturingChanged イベントのハンドラーを登録します。

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 イベントのハンドラーで、IsCapturingAudio プロパティと IsCapturingVideo プロパティを調べて、それぞれオーディオまたはビデオがキャプチャされているかどうかを確認できます。 現在のキャプチャの状態を示すために、アプリの UI を更新することが必要になる場合があります。

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 デスクトップ拡張機能をアプリに追加する

アプリから直接、オーディオとビデオを記録するための API やスクリーンショットをキャプチャするための API は、Windows.Media.AppRecording 名前空間にあり、ユニバーサル API コントラクトには含まれていません。 この API にアクセスするには、次の手順に従って、UWP 用の Windows デスクトップ拡張機能への参照をアプリに追加する必要があります。

  1. Visual Studio のソリューション エクスプローラーで、UWP プロジェクトを展開し、[参照] を右クリックして、[参照の追加] を選択します。
  2. [ユニバーサル Windows] ノードを展開し、[拡張機能] を選択します。
  3. 拡張機能の一覧で、プロジェクトのターゲット ビルドに一致する [Windows Desktop Extensions for the UWP] エントリの横にあるチェック ボックスをオンにします。 アプリのブロードキャスト機能を使用するには、バージョンが 1709 以上である必要があります。
  4. [OK] をクリックします。

AppRecordingManager のインスタンスを取得する

AppRecordingManager クラスは、アプリの記録を管理するために使用する中心的な API です。 ファクトリ メソッド GetDefault を呼び出すことによって、このクラスのインスタンスを取得します。 Windows.Media.AppRecording名前空間の API のいずれかを使用する前に、現在のデバイスでこれらが存在することを確認する必要があります。 この API は、Windows 10 バージョン 1709 より前のバージョンの OS を実行しているデバイスでは利用できません。 特定の OS バージョンを確認するのではなく、ApiInformation.IsApiContractPresent メソッドで、Windows.Media.AppBroadcasting.AppRecordingContract バージョン 1.0 を照会します。 このコントラクトが存在する場合は、デバイスで記録 API を利用できます。 この記事のコード例では、API を 1 回確認し、それ以降の操作の前に、AppRecordingManager が null であるかどうかを確認します。

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

アプリが現在記録できるかどうかを確認する

現在、アプリでオーディオやビデオをキャプチャできない場合は、いくつかの原因があります。たとえば、現在のデバイスが記録のハードウェア要件を満たしていない場合や、別のアプリが現在ブロードキャストしている場合です。 記録を開始する前に、アプリが現在記録できるかどうかを確認できます。 AppRecordingManager オブジェクトの GetStatus メソッドを呼び出して、返された AppRecordingStatus オブジェクトの CanRecord プロパティを確認します。 CanRecord からアプリで現在記録できないことを意味する false が返される場合、Details プロパティを確認すると、理由を特定できます。 理由に応じて、ユーザーに対してステータスを表示したり、アプリの記録を有効にするための手順を示したりすることができます。

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;
}

ファイルへのアプリの記録を手動で開始および停止する

アプリが記録できることを確認した後、AppRecordingManager オブジェクトの StartRecordingToFileAsync メソッドを呼び出すことによって、新しい記録を開始することができます。

次の例で、最初の then ブロックは、非同期タスクが失敗したときに実行されます。 2 番目の then ブロックは、タスクの結果へのアクセスを試行します。結果が null の場合、タスクは完了しています。 いずれの場合も、次に示す OnRecordingComplete ヘルパー メソッドが呼び出されて、結果が処理されます。

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 プロパティを確認して、記録操作が成功したかどうかを判断します。 成功している場合、IsFileTruncated プロパティを確認して、記憶域上の理由から、システムがキャプチャされたファイルを強制的に切り詰めたかどうかを判断できます。 Duration プロパティを確認して、記録されたファイルの実際の継続時間を検出できます。ファイルが切り詰められている場合、実際の継続時間は記録操作の継続時間よりも短い場合があります。

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;
    }
}

次の例では、前の例で示した記録操作を開始および停止するためのいくつかの基本的なコードを示します。

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();
}

履歴の期間をファイルに記録する

ユーザーが、システムの設定でアプリの履歴の記録を有効にしている場合、既に経過したゲームプレイの期間を記録できます。 この記事の前の例では、アプリが現在ゲームプレイを記録できることを確認する方法を示しました。 履歴のキャプチャが有効になっているかどうかを判断するには、追加の確認を行います。 もう一度 GetStatus を呼び出して、返された AppRecordingStatus オブジェクトの CanRecordTimeSpan プロパティを確認します。 この例では、AppRecordingStatusHistoricalBufferDuration プロパティも返されます。このプロパティは、記録操作の有効な開始時刻を確認するために使用されます。

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;
}

履歴の期間をキャプチャするには、記録の開始時刻と継続時間を指定する必要があります。 開始時刻は、DateTime 構造体として提供されます。 開始時刻は、記録バッファーの長さの範囲内で、現在の時刻よりも前の時刻である必要があります。 この例では、バッファーの長さは、前のコード例に示されている、履歴の記録が有効になっているかどうかの確認の一環として取得されます。 履歴の記録の継続時間は、TimeSpan 構造体として提供されます。これも、履歴のバッファーの継続時間以下である必要があります。 目的の開始時刻と継続時間を確認したら、RecordTimeSpanToFileAsync を呼び出して、記録操作を開始します。

手動で記録を開始および停止する場合と同様に、履歴の記録が完了したときに、返された AppRecordingResult オブジェクトの Succeeded プロパティを確認して、記録操作が成功したかどうかを判断できます。また、IsFileTruncated プロパティと Duration プロパティを確認して、記録されたファイルの実際の継続時間を検出できます。ファイルが切り詰められている場合、実際の継続時間は要求された継続時間よりも短い場合があります。

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);
        }
    });

}

次の例では、前の例で示した履歴の記録操作を開始するためのいくつかの基本的なコードを示します。

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

スクリーンショットの画像をファイルに保存する

アプリでスクリーンショットのキャプチャを開始できます。アプリのウィンドウの現在の内容を、1 つの画像ファイルに保存することも、異なる画像エンコードで複数の画像ファイルに保存することもできます。 使用する画像エンコードを指定するには、それぞれが画像の種類を表す文字列の一覧を作成します。 ImageEncodingSubtypes のプロパティは、サポートされている画像の種類ごとに、適切な文字列 (MediaEncodingSubtypes.PngMediaEncodingSubtypes.JpegXr など) を提供します。

画面キャプチャを開始するには、AppRecordingManager オブジェクトの SaveScreenshotToFilesAsync メソッドを呼び出します。 このメソッドの最初のパラメーターは、画像ファイルの保存場所を示す StorageFolder です。 2 番目のパラメーターは、システムが、保存される各画像の種類の拡張子 (".png" など) を追加する、ファイル名のプレフィックスです。

SaveScreenshotToFilesAsync の 3 番目のパラメーターは、キャプチャされる現在のウィンドウが HDR コンテンツを表示している場合に、システムが適切な色空間変換を実行できるようにするために必要です。 HDR コンテンツが存在する場合は、このパラメーターを AppRecordingSaveScreenshotOption.HdrContentVisible に設定する必要があります。 それ以外の場合は、AppRecordingSaveScreenshotOption.None を使用します。 このメソッドの最後のパラメーターは、画面をキャプチャするか画像形式の一覧です。

SaveScreenshotToFilesAsync の非同期呼び出しが完了すると、AppRecordingSavedScreenshotInfo オブジェクトが返されます。このオブジェクトは、StorageFile と、保存された各画像の種類を示す MediaEncodingSubtypes 値を提供します。

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);
        }
    });
}

次の例では、前の例で示したスクリーンショットの操作を開始するためのいくつかの基本的なコードを示します。

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

システムやアプリによるキャプチャのゲーム メタデータを追加する

この記事の以下のセクションでは、キャプチャまたはブロードキャストされるゲームプレイの MP4 ストリームにシステムが埋め込むメタデータを提供する方法について説明します。 メタデータは、組み込みのシステム UI を使用してキャプチャされたメディアや、AppRecordingManager を使用してアプリでキャプチャされたメディアに埋め込むことができます。 このメタデータを、メディアの再生中にアプリや他のアプリで抽出して、キャプチャまたはブロードキャストされたゲームプレイと同期する、コンテキストに対応したエクスペリエンスを提供することができます。

AppCaptureMetadataWriter のインスタンスを取得する

アプリのキャプチャ メタデータを管理するためのプライマリ クラスは、AppCaptureMetadataWriter です。 このクラスのインスタンスを初期化する前に、ApiInformation.IsApiContractPresent メソッドを使用して、Windows.Media.Capture.AppCaptureMetadataContract バージョン 1.0 を照会し、この API が現在のデバイスで利用できることを確認します。

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

アプリのシステム キャッシュにメタデータを書き込む

各メタデータ項目には 1 つのラベルがあり、メタデータ項目、関連するデータ値 (文字列、整数、または double 型の値)、データ項目の相対的な優先順位を示す AppCaptureMetadataPriority 列挙の値が識別されます。 メタデータ項目は、ある時点で発生する "イベント" またはある時間枠で値を維持する "状態" と見なすことができます。 メタデータは、システムによってアプリ用に割り当てられて管理されるメモリ キャッシュに書き込まれます。 システムは、メタデータのメモリ キャッシュにサイズ制限を適用し、制限に達すると、各メタデータに書き込まれている優先順位に基づいてデータを削除します。 この記事の次のセクションでは、アプリのメタデータのメモリ割り当てを管理する方法を示します。

一般的なアプリでは、キャプチャ セッションの最初に特定のメタデータを書き込んで、以降のデータのコンテキストを提供することを選択できます。 このシナリオでは、瞬間的な "イベント" データを使用することをお勧めします。 この例では、AddStringEventAddDoubleEvent、およびAddInt32Event を呼び出して、各データ型の瞬間的な値を設定します。

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);
    }
}

一定時間継続する "状態" データを使用する一般的なシナリオとして、プレイヤーが現在プレイしているゲーム マップの追跡があります。 この例では、StartStringState を呼び出して状態の値を設定します。

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

特定の状態が終了したことを記録するには、StopState を呼び出します。

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

状態は、既存の状態ラベルを持つ新しい値を設定して上書きできます。

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

StopAllStates を呼び出すことによって、現在開いているすべての状態を終了できます。

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

メタデータ キャッシュの記憶域の制限を管理する

AppCaptureMetadataWriter を使用して書き込むメタデータは、関連付けられているメディア ストリームに書き込まれるまで、システムによってキャッシュされます。 システムでは、各アプリのメタデータ キャッシュのサイズ制限を定義しています。 キャッシュのサイズ制限に達すると、システムはキャッシュされたメタデータの削除を開始します。 システムは、AppCaptureMetadataPriority.Important の優先順位が設定されているメタデータを削除する前に、AppCaptureMetadataPriority.Informational の優先順位の値を指定して書き込まれたメタデータを削除します。

いつでも、RemainingStorageBytesAvailable を呼び出すことによって、アプリのメタデータ キャッシュで利用可能なバイト数を確認できます。 独自のアプリで定義されたしきい値を設定することを選択し、その後でキャッシュに書き込むメタデータの量を減らすことを選択できます。 次の例は、このパターンの簡単な実装を示しています。

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);
    }
}

システムがメタデータを削除するときに通知を受け取る

MetadataPurged イベントのハンドラーを登録することで、システムがアプリのメタデータの削除を開始するときに、通知を受け取るように登録できます。

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

}

MetadataPurged イベントのハンドラーで、優先順位の低い状態を終了してメタデータ キャッシュの空き容量を増やすことも、キャッシュに書き込むメタデータの量を削減するためにアプリで定義されたロジックを実装することも、何もせずに書き込み時の優先順位に基づいてシステムによるキャッシュの削除を継続することもできます。

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."));

}