搭配基礎串流使用 Demux
[與此頁面相關的功能 DirectShow是舊版功能。 它已被 MediaPlayer、 IMFMediaEngine和 Media Foundation 中的音訊/視訊擷取取代。 這些功能已針對Windows 10和Windows 11進行優化。 Microsoft 強烈建議新程式碼盡可能使用 MediaPlayer、 IMFMediaEngine 和 音訊/視訊擷取 ,而不是 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));
相關主題