从现有 ASF 数据对象生成流示例

ASF 拆分器 对象是一个 WMContainer 层组件,用于分析高级系统格式的 ASF 数据对象 (ASF) 文件。

在将数据包传递给拆分器之前,应用程序必须在拆分器上初始化、配置和选择流,以便为分析过程做好准备。 有关信息,请参阅 创建 ASF 拆分器对象配置 ASF 拆分器对象

分析 ASF 数据对象所需的方法是:

查找数据偏移量

在开始分析过程之前,应用程序必须在 ASF 文件中找到数据对象。 可通过两种方法从文件开头获取数据对象的偏移量:

在这两种情况下,返回的值都是标头对象的大小加上数据对象的标头部分的大小。 因此,生成的值是 ASF 数据对象中数据包开始的偏移量。 开始向拆分器发送数据时,数据必须从 ASF 文件开头的此偏移量开始。

偏移值作为参数传递给启动分析过程的 ParseData

数据对象划分为数据包。 每个数据包都包含一个数据包标头,该标头提供数据包分析信息和有效负载数据-实际数字媒体数据。 在查找方案中,应用程序可能希望拆分器开始分析特定数据包。 为此,可以使用 ASF 索引器来检索偏移量。 索引器返回从数据包边界开始的偏移值。 如果不使用索引器,请确保偏移量从数据包标头的开头开始。 如果向拆分器传递了无效的偏移量,例如值未指向数据包边界,则 ParseHeaderGetNextSample 调用成功,但 GetNextSample 不会检索任何样本,并且 pSample 参数中收到 NULL

如果拆分器配置为反向分析,则拆分器始终在传递给 ParseData 的媒体缓冲区的末尾开始分析。 因此,对于 对 ParseData 的调用中的反向分析,请传递 cbLength 参数中的偏移量,该参数指定数据的长度并将 cbBufferOffset 设置为零。

为 ASF 数据包生成示例

应用程序通过将数据包传递给拆分器来启动分析过程。 拆分器输入是一系列包含数据对象的整个 或 片段的媒体缓冲区。 拆分器输出是一系列包含数据包数据的媒体示例。

若要将输入数据传递给拆分器,请创建一个媒体缓冲区,并使用 ASF 文件的“数据对象”部分中的数据填充该缓冲区。 (有关媒体缓冲区的详细信息,请参阅 Media Buffers.) 然后将媒体缓冲区传递给 IMFASFSplitter::P arseData 方法。 您还可以指定:

  • 拆分器应开始分析的缓冲区的偏移量。 如果偏移量为零,则分析从缓冲区的开头开始。 有关设置数据偏移量的信息,请参阅本主题中的“查找数据偏移量”部分。
  • 要分析的数据量。 如果此值为零,拆分器将分析,直到它到达 由 IMFMediaBuffer::GetCurrentLength 方法指定的缓冲区末尾。

拆分器通过引用媒体缓冲区中的数据来生成媒体样本。 客户端可以通过在循环中调用 IMFASFSplitter::GetNextSample 来检索输出样本,直到没有更多要分析的数据。 如果 GetNextSample 返回 pdwStatusFlags 参数中的ASF_STATUSFLAGS_INCOMPLETE标志,则意味着还有更多示例要检索,应用程序可以再次调用 GetNextSample 。 否则,请调用 ParseData 将更多数据传递给拆分器。 对于生成的示例,拆分器设置以下信息:

  • 拆分器为其生成的所有样本设置时间戳。 示例时间表示演示时间,不包括预滚动时间。 应用程序可以调用 IMFSample::GetSampleTime 来获取呈现时间(以 100 纳秒为单位)。
  • 如果在样本生成期间发生中断,拆分器在中断后对第一个样本设置 MFSampleExtension_Discontinuity 属性。 中断通常是由网络连接上的数据包丢弃、文件数据损坏或拆分器从一个源流切换到另一个源流引起的。
  • 对于视频,拆分器会检查示例是否包含关键帧。 如果存在,拆分器将设置示例上的 MFSampleExtension_CleanPoint 属性。

如果拆分器正在分析从媒体服务器接收的数据包,则数据包长度可能可变。 在这种情况下,客户端必须为每个数据包调用 ParseData ,并在发送到拆分器的每个缓冲区上设置 MFASFSPLITTER_PACKET_BOUNDARY 属性。 此属性向拆分器指示媒体缓冲区是否包含 ASF 数据包的开头。 如果缓冲区包含新数据包的开始,请将 属性设置为 TRUE 。 如果缓冲区包含上一个数据包的延续,请将 属性设置为 FALSE。 缓冲区不能跨越多个数据包。

在将新的媒体缓冲区传递给拆分器之前,应用程序必须调用 IMFASFSplitter::Flush。 此方法重置拆分器并清除等待完成的任何部分帧。 这在查找偏移量位于不同位置的方案中非常有用。

示例

下面的代码示例演示如何分析数据包。 此示例分析从数据对象的开头到流的末尾,并显示有关包含关键帧的示例的信息。 有关使用此代码的完整示例,请参阅 教程:读取 ASF 文件

// Parse the video stream and display information about the video samples.
//
// The current read position of the byte stream must be at the start of the ASF
// Data Object.

HRESULT DisplayKeyFrames(IMFByteStream *pStream, IMFASFSplitter *pSplitter)
{
    const DWORD cbReadSize = 2048;  // Read size (arbitrary value)

    IMFMediaBuffer *pBuffer = NULL;
    IMFSample *pSample = NULL;

    HRESULT hr = S_OK;
    while (SUCCEEDED(hr))
    {
        // The parser must get a newly allocated buffer each time.
        hr = MFCreateMemoryBuffer(cbReadSize, &pBuffer);
        if (FAILED(hr))
        {
            break;
        }

        // Read data into the buffer.
        hr = ReadFromByteStream(pStream, pBuffer, cbReadSize);
        if (FAILED(hr)) 
        {
            break; 
        }

        // Get the amound of data that was read.
        DWORD cbData;
        hr = pBuffer->GetCurrentLength(&cbData);
        if (FAILED(hr)) 
        { 
            break; 
        }

        if (cbData == 0)
        {
            break; // End of file.
        }

        // Send the data to the ASF splitter.
        hr = pSplitter->ParseData(pBuffer, 0, 0);
        SafeRelease(&pBuffer);
        if (FAILED(hr)) 
        { 
            break; 
        }

        // Pull samples from the splitter.
        DWORD parsingStatus = 0;
        do
        {
            WORD streamID;
            hr = pSplitter->GetNextSample(&parsingStatus, &streamID, &pSample);
            if (FAILED(hr)) 
            { 
                break; 
            }
            if (pSample == NULL)
            {
                // No samples yet. Parse more data.
                break;
            }
            if (IsRandomAccessPoint(pSample))
            {
                DisplayKeyFrame(pSample);
            }
            SafeRelease(&pSample);
            
        } while (parsingStatus & ASF_STATUSFLAGS_INCOMPLETE);
    }
    SafeRelease(&pSample);
    SafeRelease(&pBuffer);
    return hr;
}

ASF 拆分器