インデクサーを使用して ASF ファイル内でシークする
ASF インデクサー は、Advanced Systems Format (ASF) ファイルのインデックス オブジェクトの読み取りまたは書き込みに使用される WMContainer レイヤー コンポーネントです。 このトピックでは、ASF インデクサーを使用して ASF ファイル内でシークする方法について説明します。
ASF ファイルの構造については、「 ASF ファイルの構造」を参照してください。
シーク用のインデクサーの初期化
シークのために ASF インデクサーを初期化するには:
- MFCreateASFIndexer を呼び出して、ASF インデクサーの新しいインスタンスを作成します。
- インデクサーを初期化するには、 IMFASFIndexer::Initialize を呼び出します。 このメソッドは、ASF ヘッダーから情報を取得して、インデックスが作成される ASF ストリームを決定します。 既定では、インデクサー オブジェクトはシーク用に構成されています。
- IMFASFIndexer::GetIndexPosition を呼び出して、ASF ファイル内のインデックスのオフセットを検索します。
- MFCreateASFIndexerByteStream 関数を呼び出して、インデックスを読み取るためのバイト ストリームを作成します。 この関数への入力は、ASF ファイルを含むバイト ストリームへのポインターであり、(前の手順の) インデックスのオフセットです。
- IMFASFIndexer::SetIndexByteStreams を呼び出して、インデクサーにインデックス バイト ストリームを設定します。
これらの手順を示すコードは次のようになります。
HRESULT CreateASFIndexer(
IMFByteStream *pContentByteStream, // Pointer to the content byte stream
IMFASFContentInfo *pContentInfo,
IMFASFIndexer **ppIndexer
)
{
IMFASFIndexer *pIndexer = NULL;
IMFByteStream *pIndexerByteStream = NULL;
QWORD qwLength = 0, qwIndexOffset = 0, qwBytestreamLength = 0;
// Create the indexer.
HRESULT hr = MFCreateASFIndexer(&pIndexer);
if (FAILED(hr))
{
goto done;
}
//Initialize the indexer to work with this ASF library
hr = pIndexer->Initialize(pContentInfo);
if (FAILED(hr))
{
goto done;
}
//Check if the index exists. You can only do this after creating the indexer
//Get byte stream length
hr = pContentByteStream->GetLength(&qwLength);
if (FAILED(hr))
{
goto done;
}
//Get index offset
hr = pIndexer->GetIndexPosition(pContentInfo, &qwIndexOffset);
if (FAILED(hr))
{
goto done;
}
if ( qwIndexOffset >= qwLength)
{
//index object does not exist, release the indexer
goto done;
}
else
{
// initialize the indexer
// Create a byte stream that the Indexer will use to read in
// and parse the indexers.
hr = MFCreateASFIndexerByteStream(
pContentByteStream,
qwIndexOffset,
&pIndexerByteStream
);
if (FAILED(hr))
{
goto done;
}
}
hr = pIndexer->SetIndexByteStreams(&pIndexerByteStream, 1);
if (FAILED(hr))
{
goto done;
}
// Return the pointer to the caller.
*ppIndexer = pIndexer;
(*ppIndexer)->AddRef();
done:
SafeRelease(&pIndexer);
SafeRelease(&pIndexerByteStream);
return hr;
}
シーク位置を取得します。
- 特定のストリームにインデックスが作成されているかどうかを確認するには、 IMFASFIndexer::GetIndexStatus を呼び出します。 ストリームのインデックスが作成されている場合、 pfIsIndexed パラメーターは 値 TRUE を受け取ります。それ以外の場合は、 値 FALSE を受け取ります。
- 既定では、インデクサーは前方シークを使用します。 逆シーク (つまり、ファイルの末尾からシーク) の場合は、 IMFASFIndexer::SetFlags を呼び出し、 MFASF_INDEXER_READ_FOR_REVERSEPLAYBACK フラグを設定します。 それ以外の場合、この手順はスキップしてください。
- ストリームのインデックスが作成されている場合は、 IMFASFIndexer::GetSeekPositionForValue を呼び出して、指定したプレゼンテーション時間のシーク位置を取得します。 このメソッドは、ASF インデックスを読み取り、要求された時刻に最も近いインデックス エントリを検索します。 メソッドは、インデックス エントリで指定されたデータ パケットのバイト オフセットを返します。 バイト オフセットは、ASF データ オブジェクトの先頭に対する相対位置です。
GetSeekPositionForValue メソッドは、ASF_INDEX_IDENTIFIER構造体へのポインターを受け取ります。 この構造体は、インデックスの種類とストリーム識別子を指定します。 現在、インデックスの種類はGUID_NULLする必要があります。これは、時間ベースのインデックス作成を指定します。
次のコードは、ストリーム識別子とターゲット プレゼンテーション時間を指定してシーク位置を取得します。 呼び出しが成功すると、 pcbDataOffset パラメーターのデータ オフセットと 、phnsApproxSeekTime のおおよその実際のシーク時間が返されます。
HRESULT GetSeekPositionWithIndexer(
IMFASFIndexer *pIndexer,
WORD wStreamNumber,
MFTIME hnsSeekTime, // Desired seek time, in 100-nsec.
BOOL bReverse,
QWORD *pcbDataOffset, // Receives the offset in bytes.
MFTIME *phnsApproxSeekTime // Receives the approximate seek time.
)
{
// Query whether the stream is indexed.
ASF_INDEX_IDENTIFIER IndexIdentifier = { GUID_NULL, wStreamNumber };
BOOL fIsIndexed = FALSE;
ASF_INDEX_DESCRIPTOR descriptor;
DWORD cbIndexDescriptor = sizeof(descriptor);
HRESULT hr = pIndexer->GetIndexStatus(
&IndexIdentifier,
&fIsIndexed,
(BYTE*)&descriptor,
&cbIndexDescriptor
);
if (hr == MF_E_BUFFERTOOSMALL)
{
hr = S_OK;
}
else if (FAILED(hr))
{
goto done;
}
if (!fIsIndexed)
{
hr = MF_E_ASF_NOINDEX;
goto done;
}
if (bReverse)
{
hr = pIndexer->SetFlags(MFASF_INDEXER_READ_FOR_REVERSEPLAYBACK);
if (FAILED(hr))
{
goto done;
}
}
// Get the offset from the indexer.
PROPVARIANT var;
var.vt = VT_I8;
var.hVal.QuadPart = hnsSeekTime;
hr = pIndexer->GetSeekPositionForValue(
&var,
&IndexIdentifier,
pcbDataOffset,
phnsApproxSeekTime,
0
);
done:
return hr;
}
関連トピック