Compartir a través de


Usar el indexador para escribir un nuevo índice

En este tema se muestra cómo escribir un índice para un archivo de formato de sistemas avanzados (ASF).

Este es el procedimiento general para crear un índice ASF:

  1. Inicialice una nueva instancia del objeto indexador ASF, tal y como se describe en Creación y configuración del indexador.
  2. Opcionalmente, configure el indexador.
  3. Envíe paquetes de datos ASF al indexador.
  4. Confirme el índice.
  5. Obtenga el índice completado del indexador y escríbalo en una secuencia.

Configuración del indexador

Para usar el indexador para escribir un nuevo objeto de índice, el objeto indexador debe tener la marca MFASF_INDEXER_WRITE_NEW_INDEX establecida con una llamada a IMFASFIndexer::SetFlags antes de que se inicialice con IMFASFIndexer::Initialize.

Cuando el indexador está configurado para escribir un índice, el autor de la llamada elige las secuencias que se van a indexar. De forma predeterminada, el indexador intenta crear un objeto de índice para todas las secuencias. El intervalo de tiempo predeterminado es un segundo.

IMFASFIndexer::SetIndexStatus se puede usar para invalidar la elección predeterminada del objeto indexador de flujos y tipos de índice.

En el código de ejemplo siguiente se muestra la inicialización de un ASF_INDEX_DESCRIPTOR y un ASF_INDEX_IDENTIFIER antes de una llamada a SetIndexStatus.

ASF_INDEX_DESCRIPTOR IndexerType;
ZeroMemory(&IndexerType, sizeof(ASF_INDEX_DESCRIPTOR));

ASF_INDEX_IDENTIFIER IndexIdentifier;
ZeroMemory(&IndexIdentifier, sizeof(ASF_INDEX_IDENTIFIER));

IndexIdentifier.guidIndexType = GUID_NULL;
IndexIdentifier.wStreamNumber = 1;

IndexerType.Identifier = IndexIdentifier;
IndexerType.cPerEntryBytes  = MFASFINDEXER_PER_ENTRY_BYTES_DYNAMIC;
IndexerType.dwInterval  = MFASFINDEXER_NO_FIXED_INTERVAL;

hr = pIndexer->SetIndexStatus((BYTE*)&IndexerType, sizeof(ASF_INDEX_DESCRIPTOR), TRUE);

El identificador de índice debe tener su tipo de índice GUID establecido en GUID_NULL para indicar que el tipo de índice se basará en el tiempo de presentación. El identificador de índice también se debe inicializar con el número de secuencia de la secuencia ASF que se va a indexar. Una vez establecido el identificador de índice, úselo para inicializar el descriptor de índice.

La estructura del descriptor de índice tiene miembros que se deben establecer antes de la llamada a SetIndexStatus. El identificador es una estructura ASF_INDEX_IDENTIFIER que identifica el número de secuencia y el tipo de índice. cPerEntryBytes es el número de bytes usados para cada entrada de índice. Si el valor es MFASFINDEXER_PER_ENTRY_BYTES_DYNAMIC, las entradas de índice tienen un tamaño variable. dwInterval es el intervalo de indexación. Un valor de MFASFINDEXER_NO_FIXED_INTERVAL indica que no hay ningún intervalo fijo de indexación.

Envío de paquetes de datos de ASF al indexador

Dado que el indexador es un objeto de nivel WMContainer, se debe usar junto con el multiplexador durante la generación de paquetes.

Los paquetes devueltos desde GetNextPacket se pueden enviar al objeto indexador a través de llamadas a GenerateIndexEntries donde crea entradas de índice para cada paquete enviado.

En el código siguiente se muestra cómo se puede hacer esto:

HRESULT SendSampleToMux(
    IMFASFMultiplexer *pMux,
    IMFASFIndexer *pIndex,
    IMFSample *pSample,
    WORD wStream,
    IMFByteStream *pDestStream
    )
{
    IMFSample *pOutputSample = NULL;
    IMFMediaBuffer *pDataPacket = NULL;

    DWORD dwMuxStatus = ASF_STATUSFLAGS_INCOMPLETE;

    HRESULT hr = pMux->ProcessSample(wStream, pSample, 0);
    if (FAILED(hr))
    {
        goto done;
    }

    while (dwMuxStatus & ASF_STATUSFLAGS_INCOMPLETE)
    {
        hr = pMux->GetNextPacket(&dwMuxStatus, &pOutputSample);
        if (FAILED(hr))
        {
            goto done;
        }

        if (pOutputSample)
        {
            // Send the data packet to the indexer
            hr = pIndex->GenerateIndexEntries(pOutputSample);
            if (FAILED(hr))
            {
                goto done;
            }

            // Convert the sample to a contiguous buffer.
            hr = pOutputSample->ConvertToContiguousBuffer(&pDataPacket);
            if (FAILED(hr))
            {
                goto done;
            }

            // Write the buffer to the byte stream.
            hr = WriteBufferToByteStream(pDestStream, pDataPacket, NULL);
            if (FAILED(hr))
            {
                goto done;
            }
        }

        SafeRelease(&pOutputSample);
        SafeRelease(&pDataPacket);
    }

done:
    SafeRelease(&pOutputSample);
    SafeRelease(&pDataPacket);
    return hr;
}

Para obtener más información, vea Generar nuevos paquetes de datos ASF.

Confirmar el índice

Después de que el último paquete haya creado una entrada de índice para él, se debe confirmar el índice. Esto se realiza con una llamada a IMFASFIndexer::CommitIndex. CommitIndex toma un puntero al objeto ContentInfo que describe el contenido del archivo ASF. Confirmar el índice finaliza la indexación y actualiza el encabezado con nueva información sobre el tamaño de archivo y la búsqueda.

Obtención del índice completado

Para obtener el índice completado del indexador, realice los pasos siguientes:

  1. Llame a IMFASFIndexer::GetIndexWriteSpace para obtener el tamaño del índice.
  2. Llame a MFCreateMemoryBuffer para crear un búfer multimedia. Puede asignar un búfer lo suficientemente grande como para contener todo el índice, de asignar un búfer más pequeño y obtener el índice en fragmentos.
  3. Llame a IMFASFIndexer::GetCompletedIndex para obtener los datos del índice. En la primera llamada, establezca el parámetro cbOffsetWithinIndex en cero. Si obtiene el índice en fragmentos, incremente cbOffsetWithinIndex cada vez por el tamaño de los datos de la llamada anterior.
  4. Llame a IMFMediaBuffer::Lock para obtener un puntero a los datos de índice y el tamaño de los datos.
  5. Escriba los datos de índice en el archivo ASF.
  6. Llame a IMFMediaBuffer::Unlock para desbloquear el búfer multimedia.
  7. Repita los pasos del 3 al 6 hasta que haya escrito todo el índice.

El siguiente código muestra estos pasos:

HRESULT WriteASFIndex(IMFASFIndexer *pIndex,IMFByteStream *pStream)
{
    const DWORD cbChunkSize = 4096;

    IMFMediaBuffer *pBuffer = NULL;

    QWORD cbIndex = 0;
    DWORD cbIndexWritten = 0;

    HRESULT hr = pIndex->GetIndexWriteSpace(&cbIndex);
    if (FAILED(hr))
    {
        goto done;
    }

    hr = MFCreateMemoryBuffer(cbChunkSize, &pBuffer);
    if (FAILED(hr))
    {
        goto done;
    }

    while (cbIndexWritten < cbIndex)
    {
        BYTE *pData = NULL;
        DWORD cbData = 0;
        DWORD cbWritten = 0;

        hr = pIndex->GetCompletedIndex(pBuffer, cbIndexWritten);
        if (FAILED(hr))
        {
            goto done;
        }

        hr = pBuffer->Lock(&pData, NULL, &cbData);
        if (FAILED(hr))
        {
            goto done;
        }

        hr = pStream->Write(pData, cbData, &cbWritten);

        (void)pBuffer->Unlock();

        if (FAILED(hr))
        {
            goto done;
        }

        cbIndexWritten += cbData;
    }

done:
    SafeRelease(&pBuffer);
    return hr;
};

Indexador asf