Capturar áudio de jogo, vídeo, capturas de tela e metadados

Este artigo descreve como capturar vídeo no jogo, áudio e capturas de tela, e como enviar os metadados que o incorporará a mídia capturada e de difusão, permitindo que o app e outros criem experiências dinâmicas sincronizadas com eventos de jogo.

Há duas maneiras diferentes de o jogo ser capturado em um aplicativo UWP. O usuário pode iniciar a captura usando a interface do usuário do sistema interno. A mídia capturada usando essa técnica é ingerida no ecossistema de jogos da Microsoft, pode ser exibida e compartilhada por meio de experiências de primeira parte, como o aplicativo Xbox, e não é diretamente útil para seu aplicativo ou para os usuários. As primeiras seções deste artigo mostrarão como habilitar e desabilitar a captura de app implementada pelo sistema e como receber notificações quando a captura do app for iniciada ou interrompida.

A outra forma de capturar a mídia é usando as APIs do namespace Windows.Media.AppRecording. Se a captura for habilitada no dispositivo, o app poderá começar a captura do jogo e, após algum tempo, você poderá interromper a captura, momento em que a mídia será gravada em um arquivo. Se o usuário tiver habilitado a captura histórica, você também poderá registrar o jogo já ocorrido especificando uma hora de início no passado e uma duração de gravação. Essas duas técnicas produzem um arquivo de vídeo que pode ser acessado pelo app e, dependendo do local onde você optar por salvar os arquivos, pelo usuário. As seções intermediárias deste artigo conduzem você pela implementação desses cenários.

O namespace Windows.Media.Capture fornece APIs para criação de metadados que descreve o jogo que está sendo capturado ou transmitido. Isso pode incluir texto ou valores numéricos, com um rótulo de texto identificando cada item de dados. Os metadados podem representar um "evento" que ocorre em um momento específico, por exemplo, quando o usuário termina uma volta em um jogo de corrida, ou um "estado" que persiste em um intervalo de tempo, como o mapa de jogo atual do usuário que está jogando. Os metadados são gravados em um cache que é alocado e gerenciado para o app pelo sistema. Os metadados são incorporados em fluxos de transmissão e arquivos de vídeo capturados, incluindo a captura de sistema interno ou técnicas personalizadas de captura de app. As seções finais deste artigo mostram como gravar metadados de jogo.

Observação

Como os metadados de jogo podem ser incorporados em arquivos de mídia que podem ser compartilhados na rede, fora do controle do usuário, você não deve incluir informações de identificação pessoal ou outros dados potencialmente confidenciais nos metadados.

Habilitar e desabilitar a captura de app do sistema

A captura de app do sistema é iniciada pelo usuário com a interface do usuário do sistema interno. Os arquivos são ingeridos pelo ecossistema de jogos do Windows e não estão disponíveis para seu aplicativo ou usuário, exceto por meio de experiências de primeira parte, como o aplicativo Xbox. Seu app pode desabilitar e habilitar a captura de app iniciada pelo sistema, permitindo que você impeça a captura de determinado conteúdo ou jogo pelo usuário.

Para habilitar ou desabilitar a captura de app do sistema, basta chamar o método estático AppCapture.SetAllowedAsync e passar false para desabilitar a captura ou true para habilitar a captura.

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

Receber notificações quando a captura de app do sistema for iniciada e interrompida

Para receber uma notificação quando a captura de app do sistema começar ou terminar, primeiro obtenha uma instância da classe AppCapture chamando o método de fábrica GetForCurrentView. Em seguida, registre um manipulador para o evento 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);

No manipulador do evento CapturingChanged, verifique as propriedades IsCapturingAudio e IsCapturingVideo para determinar se o áudio ou o vídeo está sendo capturado, respectivamente. Convém atualizar a interface do usuário do app para indicar o status de captura atual.

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

Adicionar as Extensões de Área de Trabalho do Windows para a UWP ao app

As APIs de gravação de áudio e vídeo e de criação de capturas de tela diretamente no app, encontradas no namespace Windows.Media.AppRecording, não estão incluídas no contrato de API Universal. Para acessar as APIs, você deve adicionar ao app uma referência às Extensões de Área de Trabalho do Windows para a UWP executando as etapas a seguir.

  1. No Visual Studio, em Gerenciador de Soluções, expanda o projeto UWP, clique com botão direito do mouse em Referências e selecione Adicionar Referência....
  2. Expanda o nó Universal do Windows e selecione Extensões.
  3. Na lista de extensões, marque a caixa de seleção ao lado da entrada *Extensões de Área de Trabalho do Windows para a UWP que corresponde à compilação de destino do projeto. Para os recursos de transmissão de app, a versão deve ser 1709 ou superior.
  4. Clique em OK.

Obter uma instância do AppRecordingManager

A classe AppRecordingManager é a API central que você usará para gerenciar a gravação de app. Obtenha uma instância dessa classe chamando o método de fábrica GetDefault. Antes de usar qualquer uma das APIs do namespace Windows.Media.AppRecording, você deve verificar elas estão presentes no dispositivo atual. As APIs não estão disponíveis em dispositivos que executam uma versão do sistema operacional anterior ao Windows 10, versão 1709. Em vez de procurar uma versão específica do sistema operacional, use o método ApiInformation.IsApiContractPresent method to query for the Windows.Media.AppBroadcasting.AppRecordingContract versão 1.0. Se esse contrato estiver presente, as APIs de gravação estarão disponíveis no dispositivo. O exemplo de código neste artigo procura as APIs uma vez e, em seguida, verifica se o AppRecordingManager é null antes das operações subsequentes.

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

Determinar se o app pode realizar uma gravação no momento

O app pode não capturar o áudio ou o vídeo por vários motivos, inclusive se o dispositivo atual não atender aos requisitos de hardware para gravação ou se outro app estiver realizando a transmissão. Antes de iniciar uma gravação, verifique se o app é capaz de realizar a gravação. Chame o método GetStatus do objeto AppRecordingManager e verifique a propriedade CanRecord do objeto AppRecordingStatus retornado. Se CanRecord retornar false, o que significa que seu aplicativo não pode gravar no momento, você pode marcar a propriedade Details para determinar o motivo. Dependendo do motivo, convém exibir o status para o usuário ou mostrar instruções para permitir que o app realize a gravação.

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

Iniciar e parar a gravação do app em um arquivo manualmente

Após verificar se o app é capaz de realizar uma gravação, você pode iniciar uma nova gravação, chamando o método StartRecordingToFileAsync do objeto AppRecordingManager.

No exemplo a seguir, o primeiro bloco then é executado quando a tarefa assíncrona apresenta falha. O segundo bloco then tenta acessar o resultado da tarefa e, se o resultado for null, a tarefa foi concluída. Em ambos os casos, o método auxiliar OnRecordingComplete, mostrado abaixo, é chamado para manipular o resultado.

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

Quando a operação de gravação for concluída, verifique a propriedade Succeeded do objeto AppRecordingResult retornado para determinar se a operação de registro foi bem-sucedida. Em caso afirmativo, verifique a propriedade IsFileTruncated para determinar se, por motivos de armazenamento, o sistema foi forçado a truncar o arquivo capturado. Você pode verificar a propriedade Duration para descobrir a duração real do arquivo gravado, que poderá ser menor que a duração da operação de gravação se o arquivo estiver truncado.

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

Os exemplos a seguir mostram alguns códigos básicos para iniciar e interromper a operação de gravação mostrada no exemplo anterior.

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

Gravar um período histórico para um arquivo

Se o usuário tiver habilitado a gravação histórica para o app nas configurações do sistema, você poderá gravar um período de jogo que tenha ocorrido anteriormente. Um exemplo anterior neste artigo mostrou como confirmar se o app pode gravar um jogo atualmente. Há uma verificação adicional para determinar se a captura histórica está habilitada. Mais uma vez, chame GetStatus e verifique a propriedade CanRecordTimeSpan do objeto AppRecordingStatus retornado. Esse exemplo também retorna a propriedade HistoricalBufferDuration do AppRecordingStatus, que será usado para determinar uma hora de início válida para a operação de gravação.

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

Para capturar um período histórico, você deve especificar uma hora de início para a gravação e uma duração. A hora de início é fornecida como um struct DateTime. A hora de início deve ser anterior à hora atual e estar no intervalo do buffer de gravação histórica. Neste exemplo, o tamanho do buffer é recuperado enquanto é feita a verificação para saber se a gravação histórica está habilitada, o que é mostrado no exemplo de código anterior. A duração da gravação histórica é fornecida como struct TimeSpan , que também deve ser igual ou menor que a duração do buffer histórico. Após determinar a hora de início e a duração desejadas, chame RecordTimeSpanToFileAsync para iniciar a operação de gravação.

Assim como realizar a gravação com parada e interrupção manuais, quando uma gravação histórica é concluída, você pode verificar a propriedade Succeeded do objeto AppRecordingResult retornado para determinar se a operação de gravação foi bem-sucedida e as propriedades IsFileTruncated e Duration para descobrir a duração real do arquivo gravado, que poderá ter uma duração menor do que o período solicitado se o arquivo estiver truncado.

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

}

O exemplo a seguir mostra alguns códigos básicos para iniciar a operação de gravação histórica mostrada no exemplo anterior.

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

Salvar imagens de captura de tela em arquivos

O app pode iniciar uma criação de captura de tela que salvará o conteúdo atual da janela do app em um único arquivo de imagem ou em vários arquivos de imagem com codificações de imagem diferentes. Para especificar as codificações de imagem que você gostaria de usar, crie uma lista de cadeias de caracteres em que cada uma represente um tipo de imagem. As propriedades do ImageEncodingSubtypes fornecem a cadeia de caracteres correta para cada tipo de imagem com suporte, como MediaEncodingSubtypes.Png ou MediaEncodingSubtypes.JpegXr.

Inicie a captura de tela chamando o método SaveScreenshotToFilesAsync do objeto AppRecordingManager. O primeiro parâmetro desse método é um StorageFolder em que os arquivos de imagem serão salvos. O segundo parâmetro é um prefixo de nome de arquivo ao qual o sistema acrescentará a extensão de cada tipo de imagem salvo, como ".png".

O terceiro parâmetro de SaveScreenshotToFilesAsync é necessário para que o sistema possa fazer a conversão de colorspace adequada se a janela atual a ser capturada estiver exibindo o conteúdo HDR. Se houver conteúdo HDR, esse parâmetro deverá ser definido como AppRecordingSaveScreenshotOption.HdrContentVisible. Caso contrário, use AppRecordingSaveScreenshotOption.None. O parâmetro final do método é a lista de formatos de imagem no qual a tela deve ser capturada.

Quando a chamada assíncrona para SaveScreenshotToFilesAsync é concluída, ela retorna um objeto AppRecordingSavedScreenshotInfo que fornece o StorageFile e o valor associado de MediaEncodingSubtypes, indicando o tipo de imagem de cada imagem salva.

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

O exemplo a seguir mostra alguns códigos básicos para iniciar a operação de captura de tela mostrada no exemplo anterior.

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

Adicionar metadados de jogos para a captura iniciada por app e o sistema

As próximas seções deste artigo descrevem como fornecer metadados que o sistema incorporará no fluxo MP4 de jogos capturados ou transmitidos. Os metadados podem ser incorporados em mídias capturadas por meio da interface do usuário do sistema interno e em mídias capturadas pelo app com AppRecordingManager. Esses metadados podem ser extraídos pelo seu app e por outros apps durante a reprodução de mídia para proporcionar experiências contextuais sincronizadas com o jogo capturado ou transmitido.

Obter uma instância de AppCaptureMetadataWriter

A classe principal para gerenciamento de metadados de captura de app é AppCaptureMetadataWriter. Antes de inicializar uma instância dessa classe, use o método ApiInformation.IsApiContractPresent para consultar o Windows.Media.Capture.AppCaptureMetadataContract versão 1.0 e verificar se a API está disponível no dispositivo atual.

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

Gravar metadados no cache do sistema para o app

Cada item de metadados tem um rótulo de cadeia de caracteres, que identifica o item de metadados, um valor de dados associado, que pode ser uma cadeia de caracteres, um número inteiro ou um valor double, e um valor da enumeração AppCaptureMetadataPriority, que indica a prioridade relativa do item de dados. Um item de metadados pode ser considerado um "evento", que ocorre em um dado momento, ou um "estado", que mantém um valor durante um período. Os metadados são gravados em um cache de memória, que é alocado e gerenciado pelo sistema para o app. O sistema aplica um limite de tamanho ao cache de memória de metadados e, quando o limite for atingido, ele limpará dados com base na prioridade de gravação de cada item de metadados. A próxima seção deste artigo mostra como gerenciar a alocação de memória de metadados do app.

Um app típico pode optar por gravar alguns metadados no início da sessão de captura para fornecer algum contexto dos dados subsequentes. Nesse cenário, é recomendável que você use dados de "eventos" instantâneos. Este exemplo chama AddStringEvent, AddDoubleEvent e AddInt32Event para definir os valores instantâneas de cada tipo de dados.

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

Um cenário comum para o uso de dados de "estado" que persistem ao longo do tempo é os rastreamento do mapa do jogo no qual o jogador está inserido. Este exemplo chama StartStringState para definir o valor de estado.

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

Chame StopState para gravar que um estado específico terminou.

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

Você pode substituir um estado definindo um novo valor com um rótulo de estado existente.

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

Você pode encerrar todos os estados atualmente abertos chamando StopAllStates.

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

Gerenciar o limite de armazenamento de cache de metadados

Os metadados gravados com AppCaptureMetadataWriter são armazenados em cache pelo sistema até que sejam gravados no streaming de mídia associado. O sistema define um limite de tamanho para o cache de metadados de cada app. Depois que o limite de tamanho de cache for atingido, o sistema começará a limpeza de metadados armazenados em cache. O sistema excluirá os metadados gravados com o valor de prioridade AppCaptureMetadataPriority.Informational antes de excluir metadados com a prioridade AppCaptureMetadataPriority.Important .

A qualquer momento, você pode verificar o número de bytes disponíveis no cache de metadados do app chamando RemainingStorageBytesAvailable. Você pode optar por definir seu próprio limite definido por app, após o qual você poderá optar por reduzir a quantidade de metadados gravados no cache. O exemplo a seguir mostra uma simples implementação desse padrão.

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

Receber notificações quando o sistema limpa os metadados

Você pode se registrar para receber uma notificação quando o sistema começar a limpar metadados para seu aplicativo registrando um manipulador para o evento MetadataPurged .

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

}

No manipulador do evento MetadataPurged, você pode liberar algum espaço no cache de metadados encerrando os estados de prioridade mais baixa, implementar a lógica definida pelo app para reduzir a quantidade de metadados gravada no cache ou não fazer nada e deixar que o sistema continue limpando o cache com base na prioridade de gravação.

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

}