次の方法で共有


インデクサーを使用して新しいインデックスを書き込む

このトピックでは、Advanced Systems Format (ASF) ファイルのインデックスを作成する方法について説明します。

ASF インデックスを作成するための一般的な手順を次に示します。

  1. インデクサーの作成と構成」で説明されているように、ASF インデクサー オブジェクトの新しいインスタンスを初期化します。
  2. 必要に応じて、インデクサーを構成します。
  3. ASF データ パケットをインデクサーに送信します。
  4. インデックスをコミットします。
  5. インデクサーから完成したインデックスを取得し、ストリームに書き込みます。

インデクサーを構成する

インデクサーを使用して新しいインデックス オブジェクトを書き込むには、インデクサー オブジェクトが IMFASFIndexer::Initialize で初期化される前に、IMFASFIndexer::SetFlags の呼び出しでフラグを設定MFASF_INDEXER_WRITE_NEW_INDEX必要があります。

インデクサーがインデックスを書き込むよう構成されている場合、呼び出し元はインデックスを作成するストリームを選択します。 既定では、インデクサーはすべてのストリームに対して Index オブジェクトの作成を試みます。 既定の時間間隔は 1 秒です。

IMFASFIndexer::SetIndexStatus を使用して、インデクサー オブジェクトのストリームとインデックスの種類の既定の選択をオーバーライドできます。

次のコード例は、 SetIndexStatus の呼び出し前のASF_INDEX_DESCRIPTORとASF_INDEX_IDENTIFIERの初期化を示しています。

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);

インデックス識別子には、インデックスの種類がプレゼンテーション時間ベースであることを示すために、その GUID インデックスの種類がGUID_NULLに設定されている必要があります。 インデックス識別子は、インデックスを作成する ASF ストリームのストリーム番号で初期化する必要もあります。 インデックス識別子が設定されたら、それを使用してインデックス記述子を初期化します。

インデックス記述子構造体には、 SetIndexStatus の呼び出しの前に設定する必要があるメンバーがあります。 識別子 は、ストリーム番号とインデックスの種類を識別する ASF_INDEX_IDENTIFIER 構造体です。 cPerEntryBytes は、各インデックス エントリに使用されるバイト数です。 値がMFASFINDEXER_PER_ENTRY_BYTES_DYNAMICの場合、インデックス エントリのサイズは可変です。 dwInterval はインデックス作成間隔です。 MFASFINDEXER_NO_FIXED_INTERVAL の値は、固定インデックス作成間隔がないことを示します。

ASF データ パケットをインデクサーに送信する

インデクサーは WMContainer レベル のオブジェクトであるため、パケット生成時にマルチプレクサーと組み合わせて使用する必要があります。

GetNextPacket から返されたパケットは、GenerateIndexEntries の呼び出しを通じてインデクサー オブジェクトに送信できます。ここで、送信される各パケットのインデックス エントリを作成します。

次のコードは、これを行う方法を示しています。

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;
}

詳細については、「 新しい ASF データ パケットの生成」を参照してください。

インデックスをコミットする

最後のパケットにインデックス エントリが作成された後、インデックスをコミットする必要があります。 これは、 IMFASFIndexer::CommitIndex の呼び出しで行われます。 CommitIndex は、ASF ファイルの内容を記述する ContentInfo オブジェクトへのポインターを受け取ります。 インデックスをコミットすると、インデックス作成が完了し、ファイル サイズとシーク可能性に関する新しい情報でヘッダーが更新されます。

完了したインデックスを取得する

インデクサーから完成したインデックスを取得するには、次の手順に従います。

  1. インデックスのサイズを取得するには、 IMFASFIndexer::GetIndexWriteSpace を呼び出します。
  2. MFCreateMemoryBuffer を呼び出してメディア バッファーを作成します。 インデックス全体を保持するのに十分な大きさのバッファーを割り当て、より小さなバッファーを割り当てて、インデックスをチャンク単位で取得することができます。
  3. インデックス データを取得するには 、IMFASFIndexer::GetCompletedIndex を呼び出します。 最初の呼び出しで、 cbOffsetWithinIndex パラメーターを 0 に設定します。 インデックスをチャンク単位で取得する場合は、前の呼び出しのデータのサイズで cbOffsetWithinIndex を毎回インクリメントします。
  4. IMFMediaBuffer::Lock を呼び出して、インデックス データとデータのサイズへのポインターを取得します。
  5. インデックス データを ASF ファイルに書き込みます。
  6. IMFMediaBuffer::Unlock を呼び出してメディア バッファーのロックを解除します。
  7. インデックス全体を書き込むまで、手順 3 から 6 を繰り返します。

これらの手順を示すコードは次のようになります。

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;
};

ASF インデクサー