使用索引器在 ASF 文件中查找

ASF 索引器 是 WMContainer 层组件,用于在 ASF) 文件中读取或写入高级系统格式 (索引对象。 本主题提供有关使用 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,以指定基于时间的索引。

以下代码在给定流标识符和目标呈现时间的情况下获取查找位置。 如果调用成功,它将返回数据偏移量(在 phnsApproxSeekTime 中)和 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 索引器