インデクサーを使用して新しいインデックスを書き込む
このトピックでは、Advanced Systems Format (ASF) ファイルのインデックスを作成する方法について説明します。
ASF インデックスを作成するための一般的な手順を次に示します。
- 「 インデクサーの作成と構成」で説明されているように、ASF インデクサー オブジェクトの新しいインスタンスを初期化します。
- 必要に応じて、インデクサーを構成します。
- ASF データ パケットをインデクサーに送信します。
- インデックスをコミットします。
- インデクサーから完成したインデックスを取得し、ストリームに書き込みます。
インデクサーを構成する
インデクサーを使用して新しいインデックス オブジェクトを書き込むには、インデクサー オブジェクトが 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 オブジェクトへのポインターを受け取ります。 インデックスをコミットすると、インデックス作成が完了し、ファイル サイズとシーク可能性に関する新しい情報でヘッダーが更新されます。
完了したインデックスを取得する
インデクサーから完成したインデックスを取得するには、次の手順に従います。
- インデックスのサイズを取得するには、 IMFASFIndexer::GetIndexWriteSpace を呼び出します。
- MFCreateMemoryBuffer を呼び出してメディア バッファーを作成します。 インデックス全体を保持するのに十分な大きさのバッファーを割り当て、より小さなバッファーを割り当てて、インデックスをチャンク単位で取得することができます。
- インデックス データを取得するには 、IMFASFIndexer::GetCompletedIndex を呼び出します。 最初の呼び出しで、 cbOffsetWithinIndex パラメーターを 0 に設定します。 インデックスをチャンク単位で取得する場合は、前の呼び出しのデータのサイズで cbOffsetWithinIndex を毎回インクリメントします。
- IMFMediaBuffer::Lock を呼び出して、インデックス データとデータのサイズへのポインターを取得します。
- インデックス データを ASF ファイルに書き込みます。
- IMFMediaBuffer::Unlock を呼び出してメディア バッファーのロックを解除します。
- インデックス全体を書き込むまで、手順 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;
};
関連トピック