Comece com Super Resolução de Vídeo por IA (VSR)

A VSR (Super Resolução de Vídeo) é uma tecnologia de amostragem de vídeo baseada em IA que aprimora de forma inteligente fluxos de vídeo de baixa resolução de pessoas, restaurando nitidez e detalhes que, de outra forma, seriam perdidos devido a limitações de largura de banda, condições de rede ruins, compactação ou conteúdo de origem de baixa qualidade.

Adicionar recursos do VSR ao seu aplicativo habilita cenários, incluindo o seguinte:

  • Melhorando a qualidade do vídeo em conexões de rede precárias
  • Otimização de largura de banda para reduzir os custos da CDN
  • Cenários de alta largura de banda, como chamadas de vídeo em grupo com vários participantes
  • Melhorando a qualidade do vídeo nas redes sociais na edição, upload ou exibição

O recurso VSR está disponível em Copilot+ PCs com uma NPU e nos dispositivos que atendem às especificações de CPU recomendadas. Para obter mais informações, consulte Desenvolva aplicativos de IA para PCs Copilot+ e a tabela de hardware com suporte.

Hardware com suporte

Hardware Status Detalhes
NPU (Copilot+ PC) ✅ Disponível Melhor desempenho. Consulte Copilot+ PCs guia do desenvolvedor.
CPU ✅ Disponível Melhor em dispositivos que atendem às especificações recomendadas da CPU. O VSR ainda tentará funcionar em dispositivos com especificações mais modestas, mas a qualidade e a taxa de quadros em tempo real podem ser prejudicadas.
GPU ❌ Sem suporte O VSR não está disponível na GPU.

Note

A seleção de hardware é automática. Em um Copilot+ PC com uma NPU, o VSR sempre é executado na NPU. Em dispositivos não Copilot+, o VSR é executado na CPU automaticamente — não há nenhum desenvolvedor ou usuário final aceitando selecionar a CPU em um dispositivo Copilot+. Isso corresponde ao padrão usado por outras APIs de IA do Windows; consulte Hardware compatível para ter uma visão geral entre APIs.

Essas APIs VSR usam modelos de ML (Machine Learning) e foram projetadas especificamente para cenários como chamadas de vídeo, aplicativos de conferência, vídeos sociais e vídeos curtos que apresentam rostos humanos falando.

Atualmente, o VSR dá suporte aos seguintes intervalos de resolução, formato e FPS:

Attribute Conteúdo com suporte
Resolução de entrada 240p – 1440p
Resolução de saída 480p – 1440p (4K para processamento de vídeo offline)
Intervalo FPS (quadros por segundo) 15 fps – 60 fps
Formato de pixel de entrada BGR (API imagebuffer), NV12 (API Direct3D)
Formato de píxel de saída BGR (API do ImageBuffer), BGRA e NV12 (API Direct3D)

O modelo VSR é entregue como parte do SDK do Aplicativo Windows, portanto, não há nenhuma etapa de consentimento de download ou de primeira execução em dispositivos de CPU. O VSR funcionará em qualquer CPU na qual o restante das APIs de IA do Windows funcione, mas a qualidade do escalonamento em tempo real e a taxa de quadros dependem da CPU do host.

Para obter um bom desempenho da CPU, tenha como alvo dispositivos que atendam a todas as seguintes especificações recomendadas:

  • 4 ou mais núcleos físicos
  • 3 GHz ou relógio base superior
  • 32 MB ou mais de cache L3

Essas são recomendações, não mínimos rígidos – a API ainda tentará dimensionar em dispositivos de especificação inferior. Aplicativos destinados a uma ampla gama de CPUs devem verificar a CPU durante o tempo de execução e, se o dispositivo não atingir o nível recomendado, recorrer a um pipeline sem VSR ou exibir ao usuário um aviso sobre a troca entre qualidade e desempenho.

Note

GetReadyState e a verificação de especificações da CPU respondem perguntas diferentes e devem ser usadas em conjunto. GetReadyState indica se a VSR é compatível com o dispositivo (modelo carregado, drivers presentes, se a política de hardware o permite). A verificação de especificação da CPU informa se o VSR será executado bem o suficiente para sua experiência de usuário. Use GetReadyState para decidir se é necessário acionar a VSR; use a verificação da CPU para decidir entre a VSR e uma alternativa leve (como a ampliação bilinear) em hardware no limite.

Verificar o nível de suporte da CPU

O exemplo de C# a seguir usa Windows Management Instrumentation (WMI) para consultar a classe Win32_Processor e retorna true quando o dispositivo atende às especificações recomendadas. O exemplo usa o pacote NuGet System.Management publicado pela Microsoft — o wrapper padrão do .NET para WMI — para chamar a WMI a partir de C#.

using System;
using System.Management;

private static bool MeetsRecommendedCpuSpecs()
{
    const int RecommendedCores      = 4;
    const int RecommendedClockMhz   = 3000;
    const int RecommendedL3CacheKb  = 32 * 1024; // 32 MB

    int totalCores   = 0;
    int maxClockMhz  = 0;
    int maxL3CacheKb = 0;

    using var searcher = new ManagementObjectSearcher(
        "SELECT NumberOfCores, MaxClockSpeed, L3CacheSize FROM Win32_Processor");

    foreach (ManagementObject processor in searcher.Get())
    {
        totalCores   += Convert.ToInt32(processor["NumberOfCores"]);
        maxClockMhz   = Math.Max(maxClockMhz,   Convert.ToInt32(processor["MaxClockSpeed"]));
        maxL3CacheKb  = Math.Max(maxL3CacheKb,  Convert.ToInt32(processor["L3CacheSize"]));
    }

    return totalCores   >= RecommendedCores
        && maxClockMhz  >= RecommendedClockMhz
        && maxL3CacheKb >= RecommendedL3CacheKb;
}

Use o resultado para orientar as decisões de UX — por exemplo, mostrar um aviso sobre a compensação entre qualidade e desempenho, usar por padrão uma resolução de saída mais baixa ou ignorar totalmente o VSR em dispositivos que não atendem às recomendações.

Anotações sobre a verificação do WMI

  • Armazene o resultado em cache. A primeira consulta WMI demora ~50 a 200 ms devido à inicialização do COM. As consultas subsequentes são rápidas, mas o padrão mais limpo é executar MeetsRecommendedCpuSpecs uma vez na inicialização e armazenar em cache o booliano durante o tempo de vida do processo. O hardware da CPU não é alterado no runtime.
  • MaxClockSpeed é o relógio base nominal, não o relógio de aumento. Uma CPU de 2,5 GHz que atinge até 4,5 GHz em modo turbo vai relatar 2500 e falhar na verificação de 3 GHz. Isso é intencional: a taxa de transferência sustentada importa mais do que o aumento de pico para cargas de trabalho de IA de fluxo, como a VSR, portanto, o relógio base é o sinal certo.
  • Alternativa para verificações de sub-milissegundos. Se você precisar evitar a dependência de System.Management ou se o custo do WMI for inaceitável (por exemplo, em um caminho crítico de inicialização), os mesmos dados estarão disponíveis por meio de APIs nativas do Windows: GetLogicalProcessorInformationEx retorna o número de núcleos e os tamanhos de cache, e a velocidade nominal do clock é exposta em HKLM\HARDWARE\DESCRIPTION\System\CentralProcessor\0 (valor ~MHz). Elas retornam em tempo abaixo de milissegundos, mas exigem mais código.

Criar uma sessão do VideoScaler

O exemplo a seguir mostra como criar uma sessão VSR. Primeiro, obtenha uma instância de ExecutionProviderCatalog e chame EnsureAndRegisterCertifiedAsync para carregar os modelos disponíveis. Chame GetReadyState na classe VideoScaler para determinar se o dimensionador de vídeo está pronto para processar quadros. Caso contrário, chame EnsureReadyAsync para inicializar o dimensionador de vídeo.

using Microsoft.Windows.AI;
using Microsoft.Windows.AI.MachineLearning;
using Microsoft.Windows.AI.Video;

private VideoScaler? _videoScaler;

protected override async Task LoadModelAsync(SampleNavigationParameters sampleParams)
{
    try
    {

        var catalog = ExecutionProviderCatalog.GetDefault();
        await catalog.EnsureAndRegisterCertifiedAsync();

        var readyState = VideoScaler.GetReadyState();
        if (readyState == AIFeatureReadyState.NotSupportedOnCurrentSystem)
        {
            // VSR cannot run on this device. Fall back to a non-VSR pipeline
            // (for example, a bilinear or bicubic upscaler) or hide the feature.
            ShowException(null, "Video Super Resolution is not supported on this device.");
            return;
        }
        if (readyState == AIFeatureReadyState.NotReady)
        {
            var operation = await VideoScaler.EnsureReadyAsync();

            if (operation.Status != AIFeatureReadyResultState.Success)
            {
                ShowException(null, "Video Scaler is not available.");
                return;
            }
        }

        _videoScaler = await VideoScaler.CreateAsync();
    }
    catch (Exception ex)
    {
        ShowException(ex, "Failed to load model.");
    }

    sampleParams.NotifyCompletion();
}

Escalonar um VideoFrame

O exemplo de código a seguir usa o método VideoScaler.Scale para aumentar os dados de imagem contidos em um objeto VideoFrame . Você pode obter o VideoFrame de uma câmera usando a classe MediaFrameReader . Para mais informações, consulte Processamento de quadros de mídia com MediaFrameReader. Você também pode usar o controle CameraPreview do Kit de Ferramentas da Comunidade WinUI para obter objetos VideoFrame da câmera.

Em seguida, um Direct3DSurface é obtido do quadro de vídeo de entrada e outro Direct3DSurface é criado para a saída de ampliação de escala. VideoScaler.Scale é chamado para aumentar a resolução do quadro. Neste exemplo, um controle Imagem na interface do usuário do app é atualizado com o frame ampliado.

 private async Task ProcessFrame(VideoFrame videoFrame)
{
    // Process the frame with super resolution model
    var processedBitmap = await Task.Run(async () =>
    {
        int width = 0;
        int height = 0;
        var inputD3dSurface = videoFrame.Direct3DSurface;
        if (inputD3dSurface != null)
        {
            Debug.Assert(inputD3dSurface.Description.Format == Windows.Graphics.DirectX.DirectXPixelFormat.NV12, "input in NV12 format");
            width = inputD3dSurface.Description.Width;
            height = inputD3dSurface.Description.Height;
        }
        else
        {
            var softwareBitmap = videoFrame.SoftwareBitmap;
            if (softwareBitmap == null)
            {
                return null;
            }

            Debug.Assert(softwareBitmap.BitmapPixelFormat == BitmapPixelFormat.Nv12, "input in NV12 format");

            width = softwareBitmap.PixelWidth;
            height = softwareBitmap.PixelHeight;
        }

        try
        {
            if (inputD3dSurface == null)
            {
                // Create Direct3D11-backed VideoFrame for input
                using var inputVideoFrame = VideoFrame.CreateAsDirect3D11SurfaceBacked(
                    Windows.Graphics.DirectX.DirectXPixelFormat.NV12,
                    width,
                    height);

                if (inputVideoFrame.Direct3DSurface == null)
                {
                    return null;
                }

                // Copy the software bitmap to the Direct3D-backed frame
                await videoFrame.CopyToAsync(inputVideoFrame);

                inputD3dSurface = inputVideoFrame.Direct3DSurface;
            }

            // Create or resize output surface (BGRA8 format for display)
            if (_outputD3dSurface == null || _outputWidth != width || _outputHeight != height)
            {
                _outputD3dSurface?.Dispose();

                // DXGI_FORMAT_B8G8R8A8_UNORM = 87
                _outputD3dSurface = Direct3DExtensions.CreateDirect3DSurface(87, width, height);
                _outputWidth = width;
                _outputHeight = height;
            }

            // Scale the frame using VideoScaler
            var result = _videoScaler!.Scale(inputD3dSurface, _outputD3dSurface, new VideoScalerOptions());

            if (result.Status == VideoScalerStatus.Success)
            {
                var outputBitmap = await SoftwareBitmap.CreateCopyFromSurfaceAsync(
                    _outputD3dSurface,
                    BitmapAlphaMode.Premultiplied);

                return outputBitmap;
            }
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine($"ProcessFrame error: {ex.Message}");
        }

        return null;
    });

    if (processedBitmap == null)
    {
        return;
    }

    DispatcherQueue.TryEnqueue(async () =>
    {
        using (processedBitmap)
        {
            var source = new SoftwareBitmapSource();
            await source.SetBitmapAsync(processedBitmap);
            ProcessedVideoImage.Source = source;
        }
    });
}

Dimensionar um SoftwareBitmap usando o ImageBuffer

O exemplo de código a seguir demonstra o uso da classe VideoScaler para dimensionar um SoftwareBitmap. Este exemplo não representa um uso típico das APIs vsr. Ele é menos performante do que usar o Direct3D. Mas você pode usar este exemplo para experimentar as APIs do VSR sem configurar uma câmera ou pipeline de streaming de vídeo. Como o dimensionador de vídeo requer um BGR8 ao usar um ImageBuffer, alguns métodos auxiliares são necessários para converter o formato de pixel do SoftwareBitmap fornecido.

O código de exemplo neste artigo baseia-se no componente VSR dos exemplos da API de IA do Windows

    public SoftwareBitmap ScaleVideoFrame(SoftwareBitmap inputFrame)
    {
        ImageBuffer inputImageBuffer = SoftwareBitmapExtensions.ConvertToBgr8ImageBuffer(inputFrame);
        var size = (uint)(inputFrame.PixelWidth * inputFrame.PixelHeight * 3);
        IBuffer outputBuffer = new global::Windows.Storage.Streams.Buffer(size);
        outputBuffer.Length = size;
        ImageBuffer outputImageBuffer = ImageBuffer.CreateForBuffer(
            outputBuffer,
            ImageBufferPixelFormat.Bgr8,
            inputFrame.PixelWidth,
            inputFrame.PixelHeight,
            inputFrame.PixelWidth * 3);
        var result = _videoScaler!.ScaleImageBuffer(inputImageBuffer, outputImageBuffer, new VideoScalerOptions());
        if (result.Status != VideoScalerStatus.Success)
        {
            throw new Exception($"Failed to scale video frame: {result.Status}");
        }

        return SoftwareBitmapExtensions.ConvertBgr8ImageBufferToBgra8SoftwareBitmap(outputImageBuffer);
    }

Métodos de extensão de bitmap de software

Os métodos auxiliares a seguir convertem um SoftwareBitmap entre os formatos BGRA8 e BGR8 para corresponder aos requisitos de entrada e saída do escalar de vídeo.

public static ImageBuffer ConvertToBgr8ImageBuffer(SoftwareBitmap input)
    {
        var bgraBitmap = input;
        if (input.BitmapPixelFormat != BitmapPixelFormat.Bgra8)
        {
            bgraBitmap = SoftwareBitmap.Convert(input, BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied);
        }

        int width = bgraBitmap.PixelWidth;
        int height = bgraBitmap.PixelHeight;

        byte[] bgraBuffer = new byte[width * height * 4];
        bgraBitmap.CopyToBuffer(bgraBuffer.AsBuffer());

        byte[] bgrBuffer = new byte[width * height * 3];
        for (int i = 0, j = 0; i < bgraBuffer.Length; i += 4, j += 3)
        {
            bgrBuffer[j] = bgraBuffer[i];
            bgrBuffer[j + 1] = bgraBuffer[i + 1];
            bgrBuffer[j + 2] = bgraBuffer[i + 2];
        }

        return ImageBuffer.CreateForBuffer(
            bgrBuffer.AsBuffer(),
            ImageBufferPixelFormat.Bgr8,
            width,
            height,
            width * 3);
    }

    public static SoftwareBitmap ConvertBgr8ImageBufferToBgra8SoftwareBitmap(ImageBuffer bgrImageBuffer)
    {
        if (bgrImageBuffer.PixelFormat != ImageBufferPixelFormat.Bgr8)
        {
            throw new ArgumentException("Input ImageBuffer must be in Bgr8 format");
        }

        int width = bgrImageBuffer.PixelWidth;
        int height = bgrImageBuffer.PixelHeight;

        // Get BGR data from ImageBuffer
        byte[] bgrBuffer = new byte[width * height * 3];
        bgrImageBuffer.CopyToByteArray(bgrBuffer);

        // Create BGRA buffer (4 bytes per pixel)
        byte[] bgraBuffer = new byte[width * height * 4];

        for (int i = 0, j = 0; i < bgrBuffer.Length; i += 3, j += 4)
        {
            bgraBuffer[j] = bgrBuffer[i];     // B
            bgraBuffer[j + 1] = bgrBuffer[i + 1]; // G
            bgraBuffer[j + 2] = bgrBuffer[i + 2]; // R
            bgraBuffer[j + 3] = 255;              // A (full opacity)
        }

        // Create SoftwareBitmap and copy data
        var softwareBitmap = new SoftwareBitmap(
            BitmapPixelFormat.Bgra8,
            width,
            height,
            BitmapAlphaMode.Premultiplied);

        softwareBitmap.CopyFromBuffer(bgraBuffer.AsBuffer());

        return softwareBitmap;
    }

IA responsável

Seguimos princípios e práticas fundamentais descritos nos Padrões de IA Responsável da Microsoft para garantir que essas APIs sejam confiáveis, seguras e criadas com responsabilidade. Para obter mais detalhes sobre como implementar recursos de IA em seu aplicativo, consulte Desenvolvimento responsável de IA do Generative no Windows.

Essas APIs VSR usam modelos de ML (Machine Learning), foram projetadas especificamente para cenários como aplicativos de chamada e conferência de vídeo e vídeos sociais e de formato curto que apresentam rostos humanos falando. Portanto, não recomendamos o uso dessas APIs para vídeos nos seguintes cenários:

  • Onde o vídeo contém conteúdo potencialmente confidencial e upscaling poderia introduzir detalhes enganosos ou alterar identidade ou características faciais, como imagens de indivíduos, símbolos culturais ou símbolos religiosos.
  • Quando o vídeo fiel e sem restrições é crítico, como para imagens médicas, evidências legais ou forenses, ou verificação de identidade.

Consulte também