📄 samplecgb.cpp
字号:
//------------------------------------------------------------------------------
// File: SampleCGB.cpp
//
// Desc: DirectShow sample code - Sample capture graph builder class
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------------
#include <streams.h>
#include "ks.h"
#include "ksproxy.h"
#include <atlbase.h>
#include "SampleCGB.h"
//
// ISampleCaptureGraphBuilder is trying to connect the video pin to the MPEG2 demux.
// The possible configurations are:
//
//
//
// 1. capture filter- > audio / video encoder & multiplexer -> MPEG2 demux
//
// ---------------------- --------------------------------------- ---------------
// | v| ---> | | | |
// | Capture Filter | | Audio / video encoder & Multiplexer | ->| MPEG2 demux |
// | a| ---> | | | |
// ---------------------- --------------------------------------- ---------------
//
//
//
//
//
// -> audio encoder ->
// 2. capture filter multiplexer -> MPEG2 demux
// -> video encoder ->
//
// ----------------------- ----------------- ---------------- ---------------
// | a| -> | audio encoder | -> | | | |
// | | ----------------- | | | |
// | capture filter | | multiplexer | -> | MPEG2 demux |
// | | ----------------- | | | |
// | v| -> | video encoder | -> | | | |
// ----------------------- ----------------- ---------------- ---------------
//
//
//
//
//
// a
// 3. capture filter - audio & video encoder -> multiplexer -> MPEG2 demux
// v
//
// ----------------------- ----------------- ---------------- ---------------
// | a| -> | audio encoder | -> | | | |
// | | | | | | | |
// | capture filter | | | | multiplexer | -> | MPEG2 demux |
// | | | | | | | |
// | v| -> | video encoder | -> | | | |
// ----------------------- ----------------- ---------------- ---------------
//
//
//
//
// 4. capture filter -> MPEG2 demux
//
// ------------------------------ ----------------
// | MPEG2 PS | ---> | |
// | Capture Filter | | MPEG2 demux |
// | | | |
// ------------------------------ ----------------
//
//
//
// How the algorithm works:
// 1. the video pin doesn't stream MPEG2
// 1. tries to connect the pin to an encoder
// 2. tries to connect the encoder directly to the MPEG2 demux
// 3. if not possible, tries to find a multiplexor that can be connected to the
// encoder and MPEG2 demux
// 4. connect audio pin to the MPEG2 demux using the same algorithm as in
// video pin case
//
// 2. if pin streams MPEG2 PS, then connect it to the MPEG2 demux
// 3. program the MPEG2 demux
// 4. render the video and the audio pin from the MPEG2 demux
//
static
BYTE
Mpeg2ProgramVideo [] = {
0x00, 0x00, 0x00, 0x00, // .hdr.rcSource.left = 0x00000000
0x00, 0x00, 0x00, 0x00, // .hdr.rcSource.top = 0x00000000
0xD0, 0x02, 0x00, 0x00, // .hdr.rcSource.right = 0x000002d0
0xE0, 0x01, 0x00, 0x00, // .hdr.rcSource.bottom = 0x000001e0
0x00, 0x00, 0x00, 0x00, // .hdr.rcTarget.left = 0x00000000
0x00, 0x00, 0x00, 0x00, // .hdr.rcTarget.top = 0x00000000
0x00, 0x00, 0x00, 0x00, // .hdr.rcTarget.right = 0x00000000
0x00, 0x00, 0x00, 0x00, // .hdr.rcTarget.bottom = 0x00000000
0x00, 0x09, 0x3D, 0x00, // .hdr.dwBitRate = 0x003d0900
0x00, 0x00, 0x00, 0x00, // .hdr.dwBitErrorRate = 0x00000000
0x63, 0x17, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, // .hdr.AvgTimePerFrame = 0x0000000000051763
0x00, 0x00, 0x00, 0x00, // .hdr.dwInterlaceFlags = 0x00000000
0x00, 0x00, 0x00, 0x00, // .hdr.dwCopyProtectFlags = 0x00000000
0x04, 0x00, 0x00, 0x00, // .hdr.dwPictAspectRatioX = 0x00000004
0x03, 0x00, 0x00, 0x00, // .hdr.dwPictAspectRatioY = 0x00000003
0x00, 0x00, 0x00, 0x00, // .hdr.dwReserved1 = 0x00000000
0x00, 0x00, 0x00, 0x00, // .hdr.dwReserved2 = 0x00000000
0x28, 0x00, 0x00, 0x00, // .hdr.bmiHeader.biSize = 0x00000028
0xD0, 0x02, 0x00, 0x00, // .hdr.bmiHeader.biWidth = 0x000002d0
0xE0, 0x01, 0x00, 0x00, // .hdr.bmiHeader.biHeight = 0x00000000
0x00, 0x00, // .hdr.bmiHeader.biPlanes = 0x0000
0x00, 0x00, // .hdr.bmiHeader.biBitCount = 0x0000
0x00, 0x00, 0x00, 0x00, // .hdr.bmiHeader.biCompression = 0x00000000
0x00, 0x00, 0x00, 0x00, // .hdr.bmiHeader.biSizeImage = 0x00000000
0xD0, 0x07, 0x00, 0x00, // .hdr.bmiHeader.biXPelsPerMeter = 0x000007d0
0x27, 0xCF, 0x00, 0x00, // .hdr.bmiHeader.biYPelsPerMeter = 0x0000cf27
0x00, 0x00, 0x00, 0x00, // .hdr.bmiHeader.biClrUsed = 0x00000000
0x00, 0x00, 0x00, 0x00, // .hdr.bmiHeader.biClrImportant = 0x00000000
0x98, 0xF4, 0x06, 0x00, // .dwStartTimeCode = 0x0006f498
0x56, 0x00, 0x00, 0x00, // .cbSequenceHeader = 0x00000056
0x02, 0x00, 0x00, 0x00, // .dwProfile = 0x00000002
0x02, 0x00, 0x00, 0x00, // .dwLevel = 0x00000002
0x00, 0x00, 0x00, 0x00, // .Flags = 0x00000000
// .dwSequenceHeader [1]
0x00, 0x00, 0x01, 0xB3, 0x2D, 0x01, 0xE0, 0x24,
0x09, 0xC4, 0x23, 0x81, 0x10, 0x11, 0x11, 0x12,
0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14,
0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x15,
0x15, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16,
0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
0x18, 0x18, 0x18, 0x19, 0x18, 0x18, 0x18, 0x19,
0x1A, 0x1A, 0x1A, 0x1A, 0x19, 0x1B, 0x1B, 0x1B,
0x1B, 0x1B, 0x1C, 0x1C, 0x1C, 0x1C, 0x1E, 0x1E,
0x1E, 0x1F, 0x1F, 0x21, 0x00, 0x00, 0x01, 0xB5,
0x14, 0x82, 0x00, 0x01, 0x00, 0x00
} ;
static
BYTE
MPEG1AudioFormat [] = {
0x50, 0x00, 0x02, 0x00, 0x80, 0xBB, 0x00, 0x00,
0x00, 0x7D, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
0x16, 0x00, 0x02, 0x00, 0x00, 0xE8, 0x03, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x1C, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
} ;
HRESULT
ISampleCaptureGraphBuilder::AllocCapFile( LPCOLESTR lpwstr, DWORDLONG dwlSize )
{
return graphBuilder2_->AllocCapFile( lpwstr, dwlSize );
}
HRESULT
ISampleCaptureGraphBuilder::ControlStream( const GUID *pCategory,
const GUID *pType,
IBaseFilter *pFilter,
REFERENCE_TIME *pstart,
REFERENCE_TIME *pstop,
WORD wStartCookie,
WORD wStopCookie )
{
return graphBuilder2_->ControlStream( pCategory, pType, pFilter,
pstart, pstop, wStartCookie, wStopCookie );
}
HRESULT
ISampleCaptureGraphBuilder::CopyCaptureFile( LPOLESTR lpwstrOld,
LPOLESTR lpwstrNew,
int fAllowEscAbort,
IAMCopyCaptureFileProgress *pCallback)
{
return graphBuilder2_->CopyCaptureFile( lpwstrOld, lpwstrNew,
fAllowEscAbort, pCallback );
}
HRESULT ISampleCaptureGraphBuilder::FindInterface(const GUID *pCategory,
const GUID *pType,
IBaseFilter *pf,
REFIID riid,
void **ppint
)
{
return graphBuilder2_->FindInterface( pCategory, pType, pf, riid, ppint );
}
HRESULT
ISampleCaptureGraphBuilder::FindPin( IUnknown *pSource,
PIN_DIRECTION pindir,
const GUID *pCategory,
const GUID *pType,
BOOL fUnconnected,
int num,
IPin **ppPin)
{
return graphBuilder2_->FindPin( pSource, pindir, pCategory, pType,
fUnconnected, num, ppPin );
}
HRESULT ISampleCaptureGraphBuilder::GetFiltergraph( IGraphBuilder **ppfg )
{
return graphBuilder2_->GetFiltergraph( ppfg );
}
HRESULT
ISampleCaptureGraphBuilder::RenderStream( const GUID *pCategory,
const GUID *pType,
IUnknown *pSource,
IBaseFilter *pIntermediate,
IBaseFilter *pSink)
{
if( !pType || !::IsEqualGUID( MEDIATYPE_Stream, *pType ) )
{
return graphBuilder2_->RenderStream( pCategory, pType, pSource,
pIntermediate, pSink );
}
HRESULT hr;
if( !graph_ )
{
hr = GetFiltergraph( &graph_ );
if( FAILED( hr ) )
{
return hr;
}
}
//
// try to build MPEG2 graph
//
CComPtr< IBaseFilter > captureFilter;
hr = pSource->QueryInterface( & captureFilter );
if( FAILED( hr ) )
{
return E_INVALIDARG;
}
hr = BuildMPEG2Segment( captureFilter);
if( pSink || FAILED( hr ) )
{
return hr;
}
hr = ConfigureMPEG2Demux( pMPEG2Demux_ );
if( FAILED( hr ) )
{
return hr;
}
hr = RenderStream(NULL, &MEDIATYPE_Video, pMPEG2Demux_, NULL, NULL );
if( FAILED( hr ) )
{
return hr;
}
hr = RenderStream(NULL, &MEDIATYPE_Audio, pMPEG2Demux_, NULL, NULL );
if( FAILED( hr ) )
{
return hr;
}
return S_OK;
}
HRESULT
ISampleCaptureGraphBuilder::SetFiltergraph( IGraphBuilder *pfg )
{
return graphBuilder2_->SetFiltergraph( pfg );
}
HRESULT
ISampleCaptureGraphBuilder::SetOutputFileName( const GUID *pType,
LPCOLESTR lpwstrFile,
IBaseFilter **ppf,
IFileSinkFilter **pSink )
{
if( ! pType || ! lpwstrFile || !ppf || !pSink )
{
return E_INVALIDARG;
}
if( !::IsEqualGUID( *pType, MEDIASUBTYPE_Mpeg2 ) )
{
return graphBuilder2_->SetOutputFileName(pType, lpwstrFile, ppf, pSink );
}
HRESULT hr;
if( !graph_ )
{
hr = GetFiltergraph( &graph_ );
if( FAILED( hr ) )
{
return hr;
}
}
//
// Configure the dump filter
//
CComPtr< IFileSinkFilter > pDump;
hr = pDump.CoCreateInstance( CLSID_Dump );
if( FAILED( hr ) )
{
return hr;
}
hr = pDump->SetFileName( lpwstrFile, NULL );
if( FAILED( hr ) )
{
return hr;
}
hr = pDump.QueryInterface( &pMPEG2Demux_ );
if( FAILED( hr ) )
{
return hr;
}
hr = graph_->AddFilter( pMPEG2Demux_, L"Dump" );
if( FAILED( hr ) )
{
pMPEG2Demux_ = NULL;
return hr;
}
*pSink = pDump;
return S_OK;
}
//
// A device can stream directly MPEG2 stream,
// or it can be linked with a video codec and multiplexer
//
//
//
// Loop through every media type supported by this pin
// to see if there is one which can be considered MPEG2
//
BOOL ISampleCaptureGraphBuilder::IsMPEG2Pin( CComPtr<IPin> pPin )
{
if( !pPin )
{
return FALSE; // NULL pointer
}
CComPtr<IEnumMediaTypes> pMediaTypes;
HRESULT hr = pPin->EnumMediaTypes( &pMediaTypes );
if( FAILED( hr ) )
{
return FALSE;
}
hr = pMediaTypes->Reset();
if( FAILED( hr ) )
{
return FALSE;
}
ULONG fetched;
AM_MEDIA_TYPE *mediaType;
while( S_OK == pMediaTypes->Next( 1, &mediaType, &fetched ) )
{
if(
(
::IsEqualGUID( mediaType->majortype, MEDIATYPE_Video ) ||
::IsEqualGUID( mediaType->majortype, MEDIATYPE_Stream )
)
&&
(
::IsEqualGUID( mediaType->subtype, MEDIASUBTYPE_MPEG2_VIDEO ) ||
::IsEqualGUID( mediaType->subtype, MEDIASUBTYPE_MPEG2_PROGRAM )
)
)
{
DeleteMediaType( mediaType );
return TRUE;
}
DeleteMediaType( mediaType );
}
return FALSE;
}
BOOL ISampleCaptureGraphBuilder::IsVideoPin( CComPtr<IPin> pPin )
{
return HasMediaType( pPin, MEDIATYPE_Video );
}
HRESULT ISampleCaptureGraphBuilder::GetEncodersByCategory( CComPtr<IEnumMoniker>& pEncoders )
{
CComPtr<ICreateDevEnum> pDeviceEnum;
HRESULT hr = pDeviceEnum.CoCreateInstance( CLSID_SystemDeviceEnum );
if( FAILED( hr ) )
{
return hr;
}
return pDeviceEnum->CreateClassEnumerator( KSCATEGORY_ENCODER, &pEncoders, 0 );
}
HRESULT
ISampleCaptureGraphBuilder::GetEncodersByEnumerating(
CComPtr< IPin > pPin,
const REGPINMEDIUM& pinMedium,
CComPtr<IEnumMoniker>& pEncoders )
{
CComPtr<IFilterMapper2> pFilterMapper2;
HRESULT hr = pFilterMapper2.CoCreateInstance( CLSID_FilterMapper2 );
if( FAILED( hr ) )
{
return hr;
}
hr = pFilterMapper2->EnumMatchingFilters(
&pEncoders,
NULL,
FALSE,
0, //any merit
TRUE,
0,
NULL,
&pinMedium,
NULL,
FALSE,
TRUE,
0,
NULL,
NULL,
NULL );
return hr;
}
//
// looks for an MPEG2 pin
//
HRESULT
ISampleCaptureGraphBuilder::FindMPEG2Pin(
CComPtr<IBaseFilter> pFilter,
CComPtr<IPin>& pPin )
{
if( !pFilter )
{
return E_POINTER;
}
CComPtr<IEnumPins> pEnumPins;
HRESULT hr = pFilter->EnumPins( &pEnumPins );
if( FAILED( hr ) )
{
return hr;
}
CComPtr<IPin> pTempPin;
ULONG fetched;
PIN_DIRECTION dir;
hr = pEnumPins->Reset( );
while( pTempPin.Release(), S_OK == pEnumPins->Next( 1, &pTempPin, &fetched ) )
{
hr = pTempPin->QueryDirection( &dir );
if( FAILED( hr ) || PINDIR_INPUT == dir )
{
continue;
}
if( IsMPEG2Pin( pTempPin ) )
{
pPin = pTempPin;
return S_OK;
}
}
return E_FAIL;
}
//
// search the encoder that has this special medium
// video == TRUE -- look for a video pin
// video == FALSE -- look for a audio pin
//
HRESULT ISampleCaptureGraphBuilder::FindPin(
CComPtr<IBaseFilter> pFilter,
const REGPINMEDIUM& regPinMedium,
PIN_DIRECTION direction,
BOOL video,
CComPtr<IPin>& pPin)
{
if( !pFilter )
{
return E_POINTER;
}
CComPtr<IEnumPins> pEnumPins;
HRESULT hr = pFilter->EnumPins( &pEnumPins );
if( FAILED( hr ) )
{
return hr;
}
CComPtr<IPin> pTempPin;
ULONG fetched;
REGPINMEDIUM regPinMediumTemp;
PIN_DIRECTION dir;
hr = pEnumPins->Reset( );
while( pTempPin.Release(), S_OK == pEnumPins->Next( 1, &pTempPin, &fetched ) )
{
ASSERT( pTempPin );
hr = pTempPin->QueryDirection( &dir );
if( FAILED( hr ) || dir != direction )
{
continue;
}
hr = GetMedium( pTempPin, regPinMediumTemp );
if( FAILED( hr ) )
{
continue;
}
if( !IsVideoPin( pTempPin ) )
{
continue;
}
if( ::IsEqualGUID( regPinMediumTemp.clsMedium, regPinMedium.clsMedium ) &&
regPinMediumTemp.dw1 == regPinMedium.dw1 )
{
pPin = pTempPin;
return S_OK;
}
}
return E_FAIL;
}
//
// Get a special medium from this pin.
// If there is not one, return GUID_NULL.
// Returns the first one it finds special
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -