搭配基礎串流使用 Demux

[與此頁面相關的功能 DirectShow是舊版功能。 它已被 MediaPlayerIMFMediaEngineMedia Foundation 中的音訊/視訊擷取取代。 這些功能已針對Windows 10和Windows 11進行優化。 Microsoft 強烈建議新程式碼盡可能使用 MediaPlayerIMFMediaEngine音訊/視訊擷取 ,而不是 DirectShow。 Microsoft 建議使用舊版 API 的現有程式碼盡可能重寫為使用新的 API。

當 MPEG-2 demux 傳遞 PES 承載時,它會以媒體樣本批次傳送 ES 位元組資料流程。 預設範例大小為 8K。 demux 會在每個 PES 界限上啟動新的媒體範例,但可能會將單一 PES 承載分成數個範例。 例如,如果 PES 承載是 20K,則會在兩個 8K 範例中傳遞,後面接著一個 4K 範例。 demux 不會檢查位元組資料流程的內容。 解碼器最多可以剖析序列標頭,並尋找格式變更。

當 demux 篩選器的輸出針腳連接到解碼器時,它會提供在建立針腳時指定的媒體類型。 由於 demux 不會檢查 ES 位元組資料流程,因此不會驗證媒體類型。 理論上,MPEG-2 解碼器應該只能夠與填入的主要類型和子類型連線,以指出資料類型。 解碼器應該接著檢查抵達媒體範例的序列標頭。 不過,在實務上,除非媒體類型包含完整的格式區塊,否則許多解碼器都不會連線。

例如,假設 PID 0x31包含 MPEG-2 主要設定檔影片。 您至少必須執行下列步驟。

首先,建立 MPEG-2 視訊的媒體類型。 目前保留格式區塊:

AM_MEDIA_TYPE mt;
ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
mt.majortype = MEDIATYPE_Video ;
mt.subtype = MEDIASUBTYPE_MPEG2_VIDEO;
// Possibly create a format block (not shown here).

接下來,在 demux 上建立輸出針腳:

// Query the demux filter for IMpeg2Demultiplexer.
IMpeg2Demultiplexer *pDemux;
hr = pFilter->QueryInterface(IID_IMpeg2Demultiplexer, (void**)&pDemux);
if (SUCCEEDED(hr))
{
    // Create a new output pin.
    IPin *pPin0;
    hr = pDemux->CreateOutputPin(&mt, L"Video Pin", &pPin0);
    if (SUCCEEDED(hr))
    {
        ....
    }
}

然後,查詢 IMPEG2PIDMap 介面的新針腳,並呼叫 MapPID。 指定 PID 數位0x30,並指定 PES 承載的MEDIA_ELEMENTARY_STREAM。

// Query the pin for IMPEG2PIDMap. This implicitly configures the
// demux to carry a transport stream. 
IMPEG2PIDMap *pPidMap;
hr = pPin0->QueryInterface(IID_IMPEG2PIDMap, (void**)&pPidMap);
if (SUCCEEDED(hr))
{
    // Assign PID 0x31 to pin 0. Set the type to "PES payload."
    ULONG Pid = 0x031;
    hr = pPidMap->MapPID(1, &Pid, MEDIA_ELEMENTARY_STREAM);
    pPidMap->Release();
}

最後,完成時釋放所有介面:

pPin0->Release();
pDemux->Release();

以下是設定媒體類型的更完整範例,包括格式區塊。 此範例仍假設 MPEG-2 主要設定檔影片。 詳細資料會根據資料流程內容而有所不同:

// Set up a byte array to hold the first sequence header. 
// This may or may not be required, depending on the decoder.
BYTE SeqHdr[] = { ... };  // Contains the sequence header (not shown).

AM_MEDIA_TYPE mt;
ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
mt.majortype = MEDIATYPE_Video ;
mt.subtype = MEDIASUBTYPE_MPEG2_VIDEO;
mt.formattype = FORMAT_MPEG2Video;

// Allocate the format block, including space for the sequence header. 
mt.cbFormat = sizeof(MPEG2VIDEOINFO) + sizeof(SeqHdr);
mt.pbFormat = (BYTE*)CoTaskMemAlloc(mt.cbFormat);
if (mt.pbFormat == NULL)
{
    // Out of memory; return an error code.
}
ZeroMemory(mt.pbFormat, mt.cbFormat);

// Cast the buffer pointer to an MPEG2VIDEOINFO struct.
MPEG2VIDEOINFO *pMVIH = (MPEG2VIDEOINFO*)mt.pbFormat;

RECT rcSrc = {0, 480, 0, 720};        // Source rectangle.
pMVIH->hdr.rcSource = rcSrc;
pMVIH->hdr.dwBitRate = 4000000;       // Bit rate.
pMVIH->hdr.AvgTimePerFrame = 333667;  // 29.97 fps.
pMVIH->hdr.dwPictAspectRatioX = 4;    // 4:3 aspect ratio.
pMVIH->hdr.dwPictAspectRatioY = 3;

// BITMAPINFOHEADER information.
pMVIH->hdr.bmiHeader.biSize = 40;
pMVIH->hdr.bmiHeader.biWidth = 720;
pMVIH->hdr.bmiHeader.biHeight = 480;

pMVIH->dwLevel = AM_MPEG2Profile_Main;  // MPEG-2 profile. 
pMVIH->dwProfile = AM_MPEG2Level_Main;  // MPEG-2 level.

// Copy the sequence header into the format block.
pMVIH->cbSequenceHeader = sizeof(SeqHdr); // Size of sequence header.
memcpy(pMVIH->dwSequenceHeader, SeqHdr, sizeof(SeqHdr));

使用 MPEG-2 Demultiplexer