次の方法で共有


既存の ASF データ オブジェクトからのストリーム サンプルの生成

ASF スプリッター オブジェクトは、高度なシステム形式 (ASF) ファイルの ASF データ オブジェクトを解析する WMContainer レイヤー コンポーネントです。

データ パケットをスプリッターに渡す前に、アプリケーションは、解析プロセス用に準備するために、スプリッターのストリームを初期化、構成、および選択する必要があります。 詳細については、ASF スプリッター オブジェクトの作成と ASF スプリッター オブジェクトの構成を参照してください

ASF データ オブジェクトの解析に必要なメソッドは次のとおりです。

  • IMFASFSplitter::Pデータ パケットを含むバッファーをスプリッターにプッシュすることによって解析プロセスを開始するarseData。
  • IMFASFSplitter::GetNextSample :スプリッターに渡されるバッファーから生成されたストリーム サンプルを収集します。

データ オフセットの検索

解析プロセスを開始する前に、アプリケーションは ASF ファイル内のデータ オブジェクトを見つける必要があります。 ファイルの先頭からデータ オブジェクトのオフセットを取得するには、次の 2 つの方法があります。

  • ContentInfo オブジェクトを初期化する前に、 IMFASFContentInfo::GetHeaderSize メソッドを呼び出すことができます。 このメソッドには、ASF ヘッダーの最初の 30 バイトを含むバッファーが必要です。 最初のデータ パケットへのオフセットを示すヘッダー全体のサイズを返します。 この値には、50 バイトの Data Object ヘッダー サイズも含まれます。

  • ContentInfo オブジェクトを初期化したら、 IMFASFContentInfo::GeneratePresentationDescriptor を呼び出し、プレゼンテーション記述子に 対してMF_PD_ASF_DATA_START_OFFSET 属性のクエリを実行することで、プレゼンテーション記述子を取得できます。 この属性の値はヘッダー サイズです。

    Note

    プレゼンテーション記述子の MF_PD_ASF_DATA_LENGTH 属性は、ASF データ オブジェクトの長さを指定します。

     

どちらの場合も、戻り値は Header オブジェクトのサイズとデータ オブジェクトのヘッダー セクションのサイズです。 したがって、結果の値は、ASF データ オブジェクト内のデータ パケットの先頭へのオフセットになります。 スプリッターへのデータの送信を開始するときは、ASF ファイルの先頭からこのオフセットからデータを開始する必要があります。

オフセット値は、解析プロセスを開始する ParseData にパラメーターとして渡されます。

データ オブジェクトは、データ パケットに分割されます。 各データ パケットには、パケット解析情報とペイロード データ (実際のデジタル メディア データ) を提供するデータ パケット ヘッダーが含まれています。 シークのシナリオでは、アプリケーションでスプリッターが特定のデータ パケットで解析を開始する必要がある場合があります。 これを行うには、ASF インデクサーを使用してオフセットを取得できます。 インデクサーは、パケット境界から始まるオフセット値を返します。 インデクサーを使用していない場合は、オフセットがデータ パケット ヘッダーの先頭から始まっていることを確認します。 値がパケット境界を指していないなどの無効なオフセットがスプリッターに渡された場合、ParseHeaderGetNextSample の呼び出しは成功しますが、GetNextSample はサンプルを取得せず、pSample パラメーターで NULL を受け取ります。

スプリッターが逆方向に解析するように構成されている場合、スプリッターは、 ParseData に渡されるメディア バッファーの末尾で常に解析を開始します。 したがって、 ParseData の呼び出しで逆解析を行う場合は、 cbLength パラメーターにオフセットを渡します。このパラメーターは、データの長さを指定し 、cbBufferOffset を 0 に設定します。

ASF データ パケットのサンプルの生成

アプリケーションは、データ パケットをスプリッターに渡すことによって解析プロセスを開始します。 スプリッターへの入力は、データ オブジェクトの全体またはフラグメントを含む一連のメディア バッファーです。 スプリッターからの出力は、パケット データを含む一連のメディア サンプルです。

入力データをスプリッターに渡すには、メディア バッファーを作成し、ASF ファイルの Data Object セクションのデータを入力します。 (メディア バッファーの詳細については、「 メディア バッファー」を参照してください)。次に、メディア バッファーを IMFASFSplitter::P arseData メソッドに 渡します。 次を指定することもできます。

  • スプリッターが解析を開始するバッファーへのオフセット。 オフセットが 0 の場合、解析はバッファーの先頭から開始されます。 データ オフセットの設定については、このトピックの「データ オフセットの検索」セクションを参照してください。
  • 解析するデータの量。 この値が 0 の場合、 IMFMediaBuffer::GetCurrentLength メソッドで指定されているように、スプリッターはバッファーの末尾に到達するまで解析します。

スプリッターは、メディア バッファー内のデータを参照してメディア サンプルを生成します。 クライアントは、解析するデータがなくなったらループで IMFASFSplitter::GetNextSample を呼び出すことによって、出力サンプルを取得できます。 GetNextSamplepdwStatusFlags パラメーターでASF_STATUSFLAGS_INCOMPLETE フラグを返す場合は、取得するサンプルが他にもあるため、アプリケーションは GetNextSample をもう一度呼び出すことができます。 それ以外の場合は、 ParseData を呼び出して、より多くのデータをスプリッターに渡します。 生成されたサンプルの場合、スプリッターは次の情報を設定します。

  • スプリッターは、生成されるすべてのサンプルにタイム スタンプを設定します。 サンプル時間はプレゼンテーション時間を表し、プリロール時間は含まれません。 アプリケーションは IMFSample::GetSampleTime を呼び出して、プレゼンテーション時間を 100 ナノ秒単位で取得できます。
  • サンプル生成中に中断が発生した場合、スプリッターは不連続性の後の最初のサンプルに MFSampleExtension_Discontinuity 属性を設定します。 不連続性は通常、ネットワーク接続上のパケットのドロップ、ファイル データの破損、または 1 つのソース ストリームから別のソース ストリームへのスプリッターの切り替えによって発生します。
  • ビデオの場合、スプリッターはサンプルにキー フレームが含まれているかどうかを確認します。 その場合、スプリッターはサンプルの 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 スプリッター