Compartir a través de


Generación de ejemplos de flujo a partir de un objeto de datos ASF existente

El objeto divisor ASF es un componente de capa WMContainer que analiza el objeto de datos ASF de un archivo de formato de sistemas avanzados (ASF).

Antes de pasar paquetes de datos al divisor, la aplicación debe inicializar, configurar y seleccionar secuencias en el divisor para prepararlo para el proceso de análisis. Para obtener información, vea Crear el objeto splitter asf y configurar el objeto divisor ASF.

Los métodos necesarios para analizar el objeto de datos asf son:

Buscar el desplazamiento de datos

Antes de iniciar el proceso de análisis, la aplicación debe buscar el objeto de datos en el archivo ASF. Hay dos maneras de obtener el desplazamiento del objeto de datos desde el principio del archivo:

  • Antes de inicializar el objeto ContentInfo, puede llamar al método IMFASFContentInfo::GetHeaderSize . Este método requiere un búfer que contenga los primeros 30 bytes del encabezado ASF. Devuelve el tamaño de todo el encabezado que indica el desplazamiento al primer paquete de datos. Este valor también incluye el tamaño del encabezado objeto de datos de 50 bytes.

  • Después de inicializar el objeto ContentInfo, puede obtener el descriptor de presentación llamando a IMFASFContentInfo::GeneratePresentationDescriptor y, a continuación, consultando el descriptor de presentación para el atributo MF_PD_ASF_DATA_START_OFFSET . El valor de este atributo es el tamaño del encabezado.

    Nota:

    El atributo MF_PD_ASF_DATA_LENGTH en el descriptor de presentación especifica la longitud del objeto de datos asf.

     

En ambos casos, el valor devuelto es el tamaño del objeto header más el tamaño de la sección de encabezado del objeto de datos. Por lo tanto, el valor resultante es el desplazamiento al inicio de los paquetes de datos en el objeto de datos ASF. Cuando empiece a enviar datos al divisor, los datos deben comenzar en este desplazamiento desde el principio del archivo ASF.

El valor de desplazamiento se pasa como un parámetro a ParseData que inicia el proceso de análisis.

El objeto de datos se divide en paquetes de datos. Cada paquete de datos contiene un encabezado de paquete de datos que proporciona información de análisis de paquetes y los datos de carga, los datos de medios digitales reales. En un escenario de búsqueda, es posible que la aplicación quiera que el divisor empiece a analizar en un paquete de datos determinado. Para ello, puede usar el indexador ASF para recuperar el desplazamiento. El indexador devuelve un valor de desplazamiento que comienza en el límite del paquete. Si no usa el indexador, asegúrese de que el desplazamiento se inicia al principio del encabezado del paquete de datos. Si se pasa un desplazamiento no válido al divisor, por ejemplo, el valor no apunta al límite del paquete, las llamadas a ParseHeader y GetNextSample se realizan correctamente, pero GetNextSample no recupera ningún ejemplo y se recibe NULL en el parámetro pSample .

Si el divisor está configurado para analizarse en la dirección inversa, el divisor siempre comienza a analizar al final del búfer multimedia que se pasa a ParseData. Por lo tanto, para el análisis inverso en la llamada a ParseData, pase el desplazamiento en el parámetro cbLength , que especifica la longitud de los datos y establece cbBufferOffset en cero.

Generación de ejemplos para paquetes de datos asf

Una aplicación inicia el proceso de análisis pasando los paquetes de datos al divisor. La entrada del divisor es una serie de búferes multimedia que contienen todo o fragmentos del objeto de datos. La salida del divisor es una serie de ejemplos multimedia que contienen los datos del paquete.

Para pasar datos de entrada al divisor, cree un búfer multimedia y llene con datos de la sección Objeto de datos del archivo ASF. (Para obtener más información sobre los búferes multimedia, vea Búferes de medios). A continuación, pase el búfer de medios al método IMFASFSplitter::P arseData . También puede especificar:

  • Desplazamiento en el búfer donde el divisor debe iniciar el análisis. Si el desplazamiento es cero, el análisis comienza al principio del búfer. Para obtener información sobre cómo establecer el desplazamiento de datos, vea la sección "Buscar el desplazamiento de datos" de este tema.
  • Cantidad de datos que se van a analizar. Si este valor es cero, el divisor analiza hasta que llega al final del búfer, según lo especificado por el método IMFMediaBuffer::GetCurrentLength .

El divisor genera ejemplos multimedia haciendo referencia a los datos de los búferes multimedia. El cliente puede recuperar los ejemplos de salida llamando a IMFASFSplitter::GetNextSample en un bucle hasta que no haya más datos para analizar. Si GetNextSample devuelve la marca ASF_STATUSFLAGS_INCOMPLETE en el parámetro pdwStatusFlags , significa que hay más ejemplos para recuperar y la aplicación puede llamar a GetNextSample de nuevo. De lo contrario, llame a ParseData para pasar más datos al divisor. Para los ejemplos generados, el divisor establece la siguiente información:

  • El divisor establece una marca de tiempo en todas las muestras que genera. La hora de ejemplo representa la hora de presentación y no incluye la hora de inscripción previa. La aplicación puede llamar a IMFSample::GetSampleTime para obtener el tiempo de presentación, en unidades de 100 nanosegundos.
  • Si se produce una interrupción durante la generación de muestras, el divisor establece el atributo MFSampleExtension_Discontinuity en el primer ejemplo después de la discontinuidad. Normalmente, las discontinuidades se deben a paquetes descartados en una conexión de red, datos de archivos dañados o al divisor que cambia de un flujo de origen a otro.
  • En el caso del vídeo, el divisor comprueba si el ejemplo contiene un fotograma clave. Si es así, el divisor establece el atributo MFSampleExtension_CleanPoint en el ejemplo.

Si el divisor analiza paquetes de datos que se reciben de un servidor multimedia, es posible que la longitud del paquete sea variable. En este caso, el cliente debe llamar a ParseData para cada paquete y establecer el atributo MFASFSPLITTER_PACKET_BOUNDARY en cada búfer que se envía al divisor. Este atributo indica al divisor si el búfer multimedia contiene el inicio de un paquete ASF. Establezca el atributo en TRUE si el búfer contiene el inicio de un nuevo paquete. Si el búfer contiene una continuación del paquete anterior, establezca el atributo en FALSE. Los búferes no pueden abarcar varios paquetes.

Antes de pasar nuevos búferes multimedia al divisor, la aplicación debe llamar a IMFASFSplitter::Flush. Este método restablece el divisor y borra cualquier fotograma parcial que esté esperando que se complete. Esto resulta útil en un escenario de búsqueda en el que el desplazamiento se encuentra en una ubicación diferente.

Ejemplo

En el ejemplo de código siguiente se muestra cómo analizar paquetes de datos. En este ejemplo se analiza desde el principio del objeto de datos hasta el final de la secuencia y se muestra información sobre los ejemplos que contienen fotogramas clave. Para obtener un ejemplo completo que usa este código, vea Tutorial: Lectura de un archivo 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 de ASF