Capturar áudio de jogo, vídeo, capturas de tela e metadadosCapture game audio, video, screenshots, and metadata

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.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.

Há duas maneiras diferentes de o jogo ser capturado em um aplicativo UWP.There are two different ways that gameplay can be captured in a UWP app. O usuário pode iniciar a captura usando a interface do usuário do sistema interno.The user can initiate capture using the built-in system UI. A mídia que é capturada usando essa técnica é ingerida no ecossistema de jogos da Microsoft, pode ser exibida e compartilhada por meio de experiências de terceiros, como o aplicativo Xbox, e não é diretamente disponíveis ao seu aplicativo ou aos usuários.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. 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.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.

A outra forma de capturar a mídia é usando as APIs do namespace Windows.Media.AppRecording.The other way to capture media is to use the APIs of the Windows.Media.AppRecording namespace. 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.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. 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.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. 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.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. As seções intermediárias deste artigo conduzem você pela implementação desses cenários.The middle sections of this article walk you through the implemenation of these scenarios.

O namespace Windows.Media.Capture fornece APIs para criação de metadados que descreve o jogo que está sendo capturado ou transmitido.The Windows.Media.Capture namespace provides APIs for creating metadata that describes the gameplay being captured or broadcast. Isso pode incluir texto ou valores numéricos, com um rótulo de texto identificando cada item de dados.This can include text or numeric values, with a text label identifying each data item. 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.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. Os metadados são gravados em um cache que é alocado e gerenciado para o app pelo sistema.The metadata is written to a cache that is allocated and managed for your app by the system. 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.The metadata is embedded into broadcast streams and captured video files, including both the built-in system capture or custom app capture techniques. As seções finais deste artigo mostram como gravar metadados de jogo.The final sections of this article show you how to write gameplay metadata.

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.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.

Habilitar e desabilitar a captura de app do sistemaEnable and disable system app capture

A captura de app do sistema é iniciada pelo usuário com a interface do usuário do sistema interno.System app capture is initiated by the user with the built-in system UI. Os arquivos são ingeridos pelo ecossistema de jogos do Windows e não estão disponíveis para seu aplicativo ou para o usuário, exceto por meio de experiências de primeira parte, como o aplicativo 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. 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.Your app can disable and enable system-initiated app capture, allowing you to prevent the user from capturing certain content or gameplay.

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

Receber notificações quando a captura de app do sistema for iniciada e interrompidaReceive notifications when system app capture starts and stops

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.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. Em seguida, registre um manipulador para o evento 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);

No manipulador do evento CapturingChanged, verifique as propriedades IsCapturingAudio e IsCapturingVideo para determinar se o áudio ou o vídeo está sendo capturado, respectivamente.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. Convém atualizar a interface do usuário do app para indicar o status de captura atual.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);
}

Adicionar as Extensões de Área de Trabalho do Windows para a UWP ao appAdd the Windows Desktop Extensions for the UWP to your 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.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. 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.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. 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....In Visual Studio, in Solution Explorer, expand your UWP project and right-click References and then select Add Reference....
  2. Expanda o nó Universal do Windows e selecione Extensões.Expand the Universal Windows node and select Extensions.
  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.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. Para os recursos de transmissão de app, a versão deve ser 1709 ou superior.For the app broadcast features, the version must be 1709 or greater.
  4. Clique em OK.Click OK.

Obter uma instância do AppRecordingManagerGet an instance of AppRecordingManager

A classe AppRecordingManager é a API central que você usará para gerenciar a gravação de app.The AppRecordingManager class is the central API you will use to manage app recording. Obtenha uma instância dessa classe chamando o método de fábrica GetDefault.Get an instance of this class by calling the factory method GetDefault. Antes de usar qualquer uma das APIs do namespace Windows.Media.AppRecording, você deve verificar elas estão presentes no dispositivo atual.Before using any of the APIs in the Windows.Media.AppRecording namespace, you should check for their presence on the current device. 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.The APIs are not available on devices running an OS version earlier than Windows 10, version 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.Rather than check for a specific OS version, use the ApiInformation.IsApiContractPresent method to query for the Windows.Media.AppBroadcasting.AppRecordingContract version 1.0. Se esse contrato estiver presente, as APIs de gravação estarão disponíveis no dispositivo.If this contract is present, then the recording APIs are available on the device. 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.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();
}

Determinar se o app pode realizar uma gravação no momentoDetermine if your app can currently record

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.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. Antes de iniciar uma gravação, verifique se o app é capaz de realizar a gravação.Before initiating a recording, you can check to see if your app is currently able to record. Chame o método GetStatus do objeto AppRecordingManager e verifique a propriedade CanRecord do objeto AppRecordingStatus retornado.Call the GetStatus method of the AppRecordingManager object and then check the CanRecord property of the returned AppRecordingStatus object. Se canrecord retornar false, o que significa que seu aplicativo não pode gravar no momento, você pode verificar a propriedade Details para determinar o motivo.If CanRecord returns false, meaning that your app can't currently record, you can check the Details property to determine the reason. 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.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;
}

Iniciar e parar a gravação do app em um arquivo manualmenteManually start and stop recording your app to a file

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.After verifying that your app is able to record, you can start a new recording by calling the StartRecordingToFileAsync method of the AppRecordingManager object.

No exemplo a seguir, o primeiro bloco then é executado quando a tarefa assíncrona apresenta falha.In the following example, the first then block executes when the asynchronous task fails. O segundo bloco then tenta acessar o resultado da tarefa e, se o resultado for null, a tarefa foi concluída.The second then block attempts to access the result of the task and, if the result is null, then the task has completed. Em ambos os casos, o método auxiliar OnRecordingComplete, mostrado abaixo, é chamado para manipular o resultado.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();
        }
    });
}

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.When the recording operation completes, check the Succeeded property of the returned AppRecordingResult object to determine if the record operation was successful. Em caso afirmativo, verifique a propriedade IsFileTruncated para determinar se, por motivos de armazenamento, o sistema foi forçado a truncar o arquivo capturado.If so, you can check the IsFileTruncated property to determine if, for storage reasons, the system was forced to truncate the captured file. 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.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;
    }
}

Os exemplos a seguir mostram alguns códigos básicos para iniciar e interromper a operação de gravação mostrada no exemplo anterior.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();
}

Gravar um período histórico para um arquivoRecord a historical time span to a file

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.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. Um exemplo anterior neste artigo mostrou como confirmar se o app pode gravar um jogo atualmente.A previous example in this article showed how to confirm that your app can currently record gameplay. Há uma verificação adicional para determinar se a captura histórica está habilitada.There is an additional check to determine if historical capture is enabled. Mais uma vez, chame GetStatus e verifique a propriedade CanRecordTimeSpan do objeto AppRecordingStatus retornado.Once again, call GetStatus and check the CanRecordTimeSpan property of the returned AppRecordingStatus object. 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.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;
}

Para capturar um período histórico, você deve especificar uma hora de início para a gravação e uma duração.To capture a historical timespan, you must specify a start time for the recording and a duration. A hora de início é fornecida como um struct DateTime.The start time is provided as a DateTime struct. A hora de início deve ser anterior à hora atual e estar no intervalo do buffer de gravação histórica.The start time must be a time before the current time, within the length of the historical recording buffer. 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.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. A duração da gravação histórica é fornecida como um struct TimeSpan, que também deve ser igual ou menor do que a duração do buffer histórico.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. Após determinar a hora de início e a duração desejadas, chame RecordTimeSpanToFileAsync para iniciar a operação de gravação.Once you have determined your desired start time and duration, call RecordTimeSpanToFileAsync to start the recording operation.

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

}

O exemplo a seguir mostra alguns códigos básicos para iniciar a operação de gravação histórica mostrada no exemplo anterior.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);
});

Salvar imagens de captura de tela em arquivosSave screenshot images to files

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.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. 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.To specify the image encodings you would like to use, create a list of strings where each represents an image type. As propriedades do ImageEncodingSubtypes fornecem a cadeia de caracteres correta para cada tipo de imagem com suporte, como MediaEncodingSubtypes.Png ou MediaEncodingSubtypes.JpegXr.The properties of the ImageEncodingSubtypes provide the correct string for each supported image type, such as MediaEncodingSubtypes.Png or MediaEncodingSubtypes.JpegXr.

Inicie a captura de tela chamando o método SaveScreenshotToFilesAsync do objeto AppRecordingManager.Initiate screen capture by calling the SaveScreenshotToFilesAsync method of the AppRecordingManager object. O primeiro parâmetro desse método é um StorageFolder em que os arquivos de imagem serão salvos.The first parameter to this method is a StorageFolder where the image files will be saved. 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".The second parameter is a filename prefix to which the system will append the extension for each image type saved, such as ".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.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. Se houver conteúdo HDR, esse parâmetro deverá ser definido como AppRecordingSaveScreenshotOption.HdrContentVisible.If HDR content is present, this parameter should be set to AppRecordingSaveScreenshotOption.HdrContentVisible. Caso contrário, use AppRecordingSaveScreenshotOption.None.Otherwise, use AppRecordingSaveScreenshotOption.None. O parâmetro final do método é a lista de formatos de imagem no qual a tela deve ser capturada.The final parameter to the method is the list of image formats to which the screen should be captured.

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

O exemplo a seguir mostra alguns códigos básicos para iniciar a operação de captura de tela mostrada no exemplo anterior.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");

Adicionar metadados de jogos para a captura iniciada por app e o sistemaAdd game metadata for system and app-initiated capture

As próximas seções deste artigo descrevem como fornecer metadados que o sistema incorporará no fluxo MP4 de jogos capturados ou transmitidos.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. 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.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. 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.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.

Obter uma instância de AppCaptureMetadataWriterGet an instance of AppCaptureMetadataWriter

A classe principal para gerenciamento de metadados de captura de app é AppCaptureMetadataWriter.The primary class for managing app capture metadata is 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.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();
}

Gravar metadados no cache do sistema para o appWrite metadata to the system cache for your 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.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. 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.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. Os metadados são gravados em um cache de memória, que é alocado e gerenciado pelo sistema para o app.Metadata is written to a memory cache that is allocated and managed for your app by the system. 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.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. A próxima seção deste artigo mostra como gerenciar a alocação de memória de metadados do app.The next section of this article shows how to manage your app's metadata memory allocation.

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.A typical app may choose to write some metadata at the beginning of the capture session to provide some context for the subsequent data. Nesse cenário, é recomendável que você use dados de "eventos" instantâneos.For this scenario it is recommended that you use instantaneous "event" data. Este exemplo chama AddStringEvent, AddDoubleEvent e AddInt32Event para definir os valores instantâneas de cada tipo de dados.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);
    }
}

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.A common scenario for using "state" data that persists over time is to track the game map that the player is currently within. Este exemplo chama StartStringState para definir o valor de estado.This example calls StartStringState to set the state value.

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

Chame StopState para gravar que um estado específico terminou.Call StopState to record that a particular state has ended.

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

Você pode encerrar todos os estados atualmente abertos chamando StopAllStates.You can end all currently open states by calling StopAllStates.

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

Gerenciar o limite de armazenamento de cache de metadadosManage metadata cache storage limit

Os metadados gravados com AppCaptureMetadataWriter são armazenados em cache pelo sistema até que sejam gravados no streaming de mídia associado.The metadata that you write with AppCaptureMetadataWriter is cached by the system until it is written to the associated media stream. O sistema define um limite de tamanho para o cache de metadados de cada app.The system defines a size limit for each app's metadata cache. Depois que o limite de tamanho de cache for atingido, o sistema começará a limpeza de metadados armazenados em cache.Once the cache size limit has been reached, the system will begin purging cached metadata. O sistema excluirá os metadados que foram gravados com o valor de prioridade AppCaptureMetadataPriority. informativo antes de excluir os metadados com a prioridade AppCaptureMetadataPriority. importante .The system will delete metadata that was written with AppCaptureMetadataPriority.Informational priority value before deleting metadata with the AppCaptureMetadataPriority.Important priority.

A qualquer momento, você pode verificar o número de bytes disponíveis no cache de metadados do app chamando RemainingStorageBytesAvailable.At any point, you can check to see the number of bytes available in your app's metadata cache by calling 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.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. O exemplo a seguir mostra uma simples implementação desse padrão.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);
    }
}

Receber notificações quando o sistema limpa os metadadosReceive notifications when the system purges metadata

Você pode se registrar para receber uma notificação quando o sistema começar a limpar os metadados para seu aplicativo registrando um manipulador para o evento 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);

}

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

}