Partilhar via


Gerando exemplos de fluxo de um objeto de dados ASF existente

O objeto divisor ASF é um componente de camada WMContainer que analisa o Objeto de Dados ASF de um arquivo ASF (Advanced Systems Format).

Antes de passar pacotes de dados para o divisor, o aplicativo deve inicializar, configurar e selecionar fluxos no divisor para prepará-lo para o processo de análise. Para obter informações, consulte Criando o objeto divisor ASF e Configurando o objeto divisor ASF.

Os métodos necessários para analisar o Objeto de Dados ASF são:

Localizando o deslocamento de dados

Antes de iniciar o processo de análise, o aplicativo deve localizar o Objeto de Dados no arquivo ASF. Há duas maneiras de obter o deslocamento do Objeto de Dados desde o início do arquivo:

  • Antes de inicializar o objeto ContentInfo, você pode chamar o método IMFASFContentInfo::GetHeaderSize . Esse método requer um buffer que contém os primeiros 30 bytes do cabeçalho ASF. Ele retorna o tamanho de todo o cabeçalho que indica o deslocamento para o primeiro pacote de dados. Esse valor também inclui o tamanho do cabeçalho objeto de dados de 50 bytes.

  • Depois de inicializar o objeto ContentInfo, você poderá obter o descritor de apresentação chamando IMFASFContentInfo::GeneratePresentationDescriptor e consultando o descritor de apresentação para o atributo MF_PD_ASF_DATA_START_OFFSET . O valor desse atributo é o tamanho do cabeçalho.

    Observação

    O atributo MF_PD_ASF_DATA_LENGTH no descritor de apresentação especifica o comprimento do Objeto de Dados ASF.

     

Em ambos os casos, o valor retornado é o tamanho do Objeto Header mais o tamanho da seção de cabeçalho do Objeto de Dados. Portanto, o valor resultante é o deslocamento para o início dos pacotes de dados no Objeto de Dados ASF. Quando você começa a enviar dados para o divisor, os dados devem começar nesse deslocamento desde o início do arquivo ASF.

O valor de deslocamento é passado como um parâmetro para ParseData que inicia o processo de análise.

O Objeto de Dados é dividido em pacotes de dados. Cada pacote de dados contém um cabeçalho de pacote de dados que fornece informações de análise de pacotes e os dados de conteúdo — os dados reais da mídia digital. Em um cenário de busca, o aplicativo pode querer que o divisor inicie a análise em um pacote de dados específico. Para fazer isso, você pode usar o Indexador ASF usado para recuperar o deslocamento. O indexador retorna um valor de deslocamento que começa no limite do pacote. Se você não estiver usando o indexador, verifique se o deslocamento começa no início do cabeçalho do pacote de dados. Se um deslocamento inválido for passado para o divisor, como o valor não apontar para o limite do pacote, as chamadas ParseHeader e GetNextSample serão bem-sucedidas, mas GetNextSample não recuperará nenhum exemplo e NULL será recebido no parâmetro pSample .

Se o divisor estiver configurado para analisar na direção inversa, o divisor sempre iniciará a análise no final do buffer de mídia que é passado para ParseData. Portanto, para análise inversa na chamada para ParseData, passe o deslocamento no parâmetro cbLength , que especifica o comprimento dos dados e define cbBufferOffset como zero.

Gerando exemplos para pacotes de dados ASF

Um aplicativo inicia o processo de análise passando os pacotes de dados para o divisor. A entrada para o divisor é uma série de buffers de mídia que contêm todos os fragmentos ou do Objeto de Dados. A saída do divisor é uma série de exemplos de mídia que contêm os dados do pacote.

Para passar dados de entrada para o divisor, crie um buffer de mídia e preencha-os com dados da seção Objeto de Dados do arquivo ASF. (Para obter mais informações sobre buffers de mídia, consulte Buffers de mídia.) Em seguida, passe o buffer de mídia para o método IMFASFSplitter::P arseData . Você também pode especificar:

  • O deslocamento para o buffer em que o divisor deve iniciar a análise. Se o deslocamento for zero, a análise começará no início do buffer. Para obter informações sobre como definir o deslocamento de dados, consulte a seção "Localizando o deslocamento de dados" neste tópico.
  • A quantidade de dados a serem analisados. Se esse valor for zero, o divisor analisará até chegar ao final do buffer, conforme especificado pelo método IMFMediaBuffer::GetCurrentLength .

O divisor gera exemplos de mídia fazendo referência aos dados nos buffers de mídia. O cliente pode recuperar os exemplos de saída chamando IMFASFSplitter::GetNextSample em um loop até que não haja mais dados para analisar. Se GetNextSample retornar o sinalizador ASF_STATUSFLAGS_INCOMPLETE no parâmetro pdwStatusFlags , isso significa que há mais exemplos a serem recuperados e o aplicativo poderá chamar GetNextSample novamente. Caso contrário, chame ParseData para passar mais dados para o divisor. Para os exemplos gerados, o divisor define as seguintes informações:

  • O divisor define um carimbo de data/hora em todos os exemplos gerados. O tempo de exemplo representa o tempo de apresentação e não inclui o tempo de pré-registro. O aplicativo pode chamar IMFSample::GetSampleTime para obter o tempo de apresentação, em unidades de 100 nanossegundos.
  • Se ocorrer uma interrupção durante a geração de exemplo, o divisor definirá o atributo MFSampleExtension_Discontinuity no primeiro exemplo após a descontinuidade. As descontinuações geralmente são causadas por pacotes descartados em uma conexão de rede, dados de arquivo corrompidos ou o divisor alternando de um fluxo de origem para outro.
  • Para vídeo, o divisor verifica se o exemplo contém um quadro-chave. Se isso acontecer, o divisor definirá o atributo MFSampleExtension_CleanPoint no exemplo.

Se o divisor estiver analisando pacotes de dados recebidos de um servidor de mídia, é possível que o comprimento do pacote seja variável. Nesse caso, o cliente deve chamar ParseData para cada pacote e definir o atributo MFASFSPLITTER_PACKET_BOUNDARY em cada buffer enviado para o divisor. Esse atributo indica ao divisor se o buffer de mídia contém o início de um pacote ASF. Defina o atributo como TRUE se o buffer contiver o início de um novo pacote. Se o buffer contiver uma continuação do pacote anterior, defina o atributo como FALSE. Os buffers não podem abranger vários pacotes.

Antes de passar novos buffers de mídia para o divisor, o aplicativo deve chamar IMFASFSplitter::Flush. Esse método redefine o divisor e limpa qualquer quadro parcial que esteja aguardando para ser concluído. Isso é útil em um cenário de busca em que o deslocamento está em um local diferente.

Exemplo

O exemplo de código a seguir mostra como analisar pacotes de dados. Este exemplo analisa desde o início do Objeto de Dados até o final do fluxo e exibe informações sobre os exemplos que contêm quadros-chave. Para obter um exemplo completo que usa esse código, consulte Tutorial: Lendo um arquivo ASF.

// Parse the video stream and display information about the video samples.
//
// The current read position of the byte stream must be at the start of the ASF
// Data Object.

HRESULT DisplayKeyFrames(IMFByteStream *pStream, IMFASFSplitter *pSplitter)
{
    const DWORD cbReadSize = 2048;  // Read size (arbitrary value)

    IMFMediaBuffer *pBuffer = NULL;
    IMFSample *pSample = NULL;

    HRESULT hr = S_OK;
    while (SUCCEEDED(hr))
    {
        // The parser must get a newly allocated buffer each time.
        hr = MFCreateMemoryBuffer(cbReadSize, &pBuffer);
        if (FAILED(hr))
        {
            break;
        }

        // Read data into the buffer.
        hr = ReadFromByteStream(pStream, pBuffer, cbReadSize);
        if (FAILED(hr)) 
        {
            break; 
        }

        // Get the amound of data that was read.
        DWORD cbData;
        hr = pBuffer->GetCurrentLength(&cbData);
        if (FAILED(hr)) 
        { 
            break; 
        }

        if (cbData == 0)
        {
            break; // End of file.
        }

        // Send the data to the ASF splitter.
        hr = pSplitter->ParseData(pBuffer, 0, 0);
        SafeRelease(&pBuffer);
        if (FAILED(hr)) 
        { 
            break; 
        }

        // Pull samples from the splitter.
        DWORD parsingStatus = 0;
        do
        {
            WORD streamID;
            hr = pSplitter->GetNextSample(&parsingStatus, &streamID, &pSample);
            if (FAILED(hr)) 
            { 
                break; 
            }
            if (pSample == NULL)
            {
                // No samples yet. Parse more data.
                break;
            }
            if (IsRandomAccessPoint(pSample))
            {
                DisplayKeyFrame(pSample);
            }
            SafeRelease(&pSample);
            
        } while (parsingStatus & ASF_STATUSFLAGS_INCOMPLETE);
    }
    SafeRelease(&pSample);
    SafeRelease(&pBuffer);
    return hr;
}

Divisor ASF