Compartilhar via


Usando o Demux com fluxos elementares

[O recurso associado a esta página, DirectShow, é um recurso herdado. Ele foi substituído por MediaPlayer, IMFMediaEngine e Captura de Áudio/Vídeo na Media Foundation. Esses recursos foram otimizados para Windows 10 e Windows 11. A Microsoft recomenda fortemente que o novo código use MediaPlayer, IMFMediaEngine e Captura de Áudio/Vídeo no Media Foundation em vez de DirectShow, quando possível. A Microsoft sugere que o código existente que usa as APIs herdadas seja reescrito para usar as novas APIs, se possível.]

Quando o mpeg-2 demux fornece cargas PES, ele envia o fluxo de bytes do ES em lotes de exemplos de mídia. O tamanho de exemplo padrão é 8K. O demux inicia um novo exemplo de mídia em cada limite do PES, mas pode dividir uma única carga PES em vários exemplos. Por exemplo, se um conteúdo PES for 20K, ele será entregue em dois exemplos de 8K seguidos por um exemplo de 4K. O demux não examina o conteúdo do fluxo de bytes. Cabe ao decodificador analisar os cabeçalhos de sequência e procurar alterações de formato.

Quando o pin de saída do filtro demux se conecta ao decodificador, ele oferece o tipo de mídia especificado quando o pino foi criado. Como o demux não examina o fluxo de bytes do ES, ele não valida o tipo de mídia. Em teoria, um decodificador MPEG-2 deve ser capaz de se conectar apenas com o tipo principal e o subtipo preenchidos, para indicar o tipo de dados. Em seguida, o decodificador deve examinar os cabeçalhos de sequência que chegam aos exemplos de mídia. No entanto, na prática, muitos decodificadores não se conectarão, a menos que o tipo de mídia inclua um bloco de formato completo.

Por exemplo, suponha que o 0x31 DO PID contenha o vídeo de perfil de main MPEG-2. No mínimo, você precisaria executar as etapas a seguir.

Primeiro, crie um tipo de mídia para vídeo MPEG-2. Deixando de lado o bloco de formato por enquanto:

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).

Em seguida, crie um pino de saída no 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))
    {
        ....
    }
}

Em seguida, consulte o novo pin para a interface IMPEG2PIDMap e chame MapPID. Especifique o número do PID 0x30 e MEDIA_ELEMENTARY_STREAM para conteúdos PES.

// 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();
}

Por fim, libere todas as interfaces quando terminar:

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

Aqui está um exemplo mais completo de como definir o tipo de mídia, incluindo o bloco de formato. Este exemplo ainda pressupõe um vídeo de perfil de main MPEG-2. Os detalhes variarão dependendo do conteúdo do fluxo:

// 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));

Usando o MpEG-2 Demultiplexer