다음을 통해 공유


기본 스트림과 함께 Demux 사용

[이 페이지와 연결된 기능인 DirectShow는 레거시 기능입니다. MediaPlayer, IMFMediaEngineMedia Foundation의 오디오/비디오 캡처로 대체되었습니다. 이러한 기능은 Windows 10 및 Windows 11 최적화되었습니다. 가능한 경우 새 코드에서 DirectShow 대신 MediaPlayer, IMFMediaEngine오디오/비디오 캡처를 사용하는 것이 좋습니다. 가능한 경우 레거시 API를 사용하는 기존 코드를 다시 작성하여 새 API를 사용하도록 제안합니다.]

MPEG-2 demux가 PES 페이로드를 제공하면 ES 바이트 스트림을 미디어 샘플 일괄 처리로 보냅니다. 기본 샘플 크기는 8K입니다. demux는 각 PES 경계에서 새 미디어 샘플을 시작하지만 단일 PES 페이로드를 여러 샘플로 분할할 수 있습니다. 예를 들어 PES 페이로드가 20K인 경우 8K 샘플 2개와 4K 샘플 1개로 제공됩니다. 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 사용