Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
O objeto separador ASF é um componente de camada WMContainer que analisa o objeto de dados ASF de um ficheiro ASF (Formato de Sistemas Avançados).
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:
- IMFASFSplitter::ParseData que inicia o processo de análise enviando o buffer que contém pacotes de dados para o separador.
- IMFASFSplitter::GetNextSample que recolhe amostras de fluxo que foram geradas a partir do buffer passado para o separador.
Localizando o deslocamento de dados
Antes de iniciar o processo de análise, o aplicativo deve localizar o objeto de dados dentro do 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 IMFASFContentInfo::GetHeaderSize método. Este método requer um buffer que contém os primeiros 30 bytes do cabeçalho ASF. Retorna o tamanho do cabeçalho inteiro que indica o offset para o primeiro pacote de dados. Esse valor também inclui o tamanho do cabeçalho Data Object de 50 bytes.
Depois de inicializar o objeto ContentInfo, você pode obter o descritor de apresentação chamando IMFASFContentInfo::GeneratePresentationDescriptore, em seguida, 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 de cabeçalho 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 parâmetro para ParseData, que dá início ao 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 carga útil — os dados reais de mídia digital. Em um cenário de busca, o aplicativo pode desejar que o separador comece a analisar em um pacote de dados específico. Para fazer isso, pode usar o indexador ASF para recuperar o deslocamento. O indexador retorna um valor de offset que começa na extremidade 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 se 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 um 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 reversa na chamada para ParseData, passe o deslocamento no parâmetro cbLength, que especifica o comprimento dos dados e defina cbBufferOffset como zero.
Gerando amostras 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 o todo ou fragmentos do objeto de dados. A saída do divisor é uma série de amostras de mídia que contêm dados do pacote.
Para passar dados de entrada para o divisor, crie um buffer de mídia e preencha-o com dados da seção Data Object do arquivo ASF. (Para obter mais informações sobre buffers de mídia, consulte Media Buffers.) Em seguida, passe o buffer de mídia para o método IMFASFSplitter::P arseData. Pode também especificar:
- O deslocamento para o buffer onde o divisor deve começar a analisar. 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 analisar. Se esse valor for zero, o divisor analisará até atingir o final do buffer, conforme especificado pelo métodoIMFMediaBuffer::GetCurrentLength.
O divisor gera amostras de mídia fazendo referência aos dados nos buffers de mídia. O cliente pode recuperar as amostras 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, tal significa que há mais amostras para recuperar e a aplicação pode chamar GetNextSample novamente. Caso contrário, chame ParseData para passar mais dados para o divisor. Para as amostras geradas, o divisor define as seguintes informações:
- O divisor define um carimbo de data/hora em todas as amostras que gera. O tempo de amostra representa o tempo de apresentação e não inclui o tempo de pré-rolagem. O aplicativo pode chamar IMFSample::GetSampleTime para obter o tempo de apresentação, em unidades de 100 nanossegundos.
- Se ocorrer uma quebra durante a geração da amostra, o divisor define o atributo MFSampleExtension_Discontinuity na primeira amostra após a descontinuidade. As descontinuidades geralmente são causadas por pacotes descartados em uma ligação de rede, dados de ficheiros corrompidos ou o divisor de sinal alternando de um fluxo de origem para outro.
- Para vídeo, o divisor verifica se a amostra tem uma frame-chave. Se isso acontecer, o divisor define o atributo MFSampleExtension_CleanPoint na amostra.
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 que é 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. Este método reinicia o divisor e limpa qualquer quadro parcial que esteja à espera de ser concluído. Isso é útil em um cenário de busca onde 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 Data Object 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;
}
Tópicos relacionados