次の方法で共有


インデクサーを使用して ASF ファイル内でシークする

ASF インデクサー は、Advanced Systems Format (ASF) ファイルのインデックス オブジェクトの読み取りまたは書き込みに使用される WMContainer レイヤー コンポーネントです。 このトピックでは、ASF インデクサーを使用して ASF ファイル内でシークする方法について説明します。

ASF ファイルの構造については、「 ASF ファイルの構造」を参照してください。

シーク用のインデクサーの初期化

シークのために ASF インデクサーを初期化するには:

  1. MFCreateASFIndexer を呼び出して、ASF インデクサーの新しいインスタンスを作成します。
  2. インデクサーを初期化するには、 IMFASFIndexer::Initialize を呼び出します。 このメソッドは、ASF ヘッダーから情報を取得して、インデックスが作成される ASF ストリームを決定します。 既定では、インデクサー オブジェクトはシーク用に構成されています。
  3. IMFASFIndexer::GetIndexPosition を呼び出して、ASF ファイル内のインデックスのオフセットを検索します。
  4. MFCreateASFIndexerByteStream 関数を呼び出して、インデックスを読み取るためのバイト ストリームを作成します。 この関数への入力は、ASF ファイルを含むバイト ストリームへのポインターであり、(前の手順の) インデックスのオフセットです。
  5. 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;
}

シーク位置を取得します。

  1. 特定のストリームにインデックスが作成されているかどうかを確認するには、 IMFASFIndexer::GetIndexStatus を呼び出します。 ストリームのインデックスが作成されている場合、 pfIsIndexed パラメーターは 値 TRUE を受け取ります。それ以外の場合は、 値 FALSE を受け取ります。
  2. 既定では、インデクサーは前方シークを使用します。 逆シーク (つまり、ファイルの末尾からシーク) の場合は、 IMFASFIndexer::SetFlags を呼び出し、 MFASF_INDEXER_READ_FOR_REVERSEPLAYBACK フラグを設定します。 それ以外の場合、この手順はスキップしてください。
  3. ストリームのインデックスが作成されている場合は、 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;
}

ASF インデクサー