DirectShow过滤器开发-视频源过滤器

本过滤器输出几种常用编码方式的视频,视频内容为迈克尔杰克逊歌曲,时长4分48秒。创建了8个引脚。1个音频引脚,媒体类型为PCM;7个视频引脚,媒体类型分别为DX50,FLV1,H264,MJPG,XVID,WMV2,WMV3。本过滤器用于测试其它过滤器输入媒体类型。过滤器图片如下:

视频定位后没有直接找关键帧,定位后搜索指定样本反应速度不是很快,代码还有改进的空间。初次创建过滤器耗时比较长。下载本过滤器DLL。

过滤器DLL的全部代码

DLL.h

cpp 复制代码
#ifndef  DLL_FILE
#define DLL_FILE

#include "strmbase10.h"//过滤器基础类定义文件

#if _DEBUG
#pragma comment(lib, "strmbasd10.lib")//过滤器基础类实现文件调试版本
#else
#pragma comment(lib, "strmbase10.lib")//过滤器基础类实现文件发布版本
#endif

#include "resource.h"
#include "dvdmedia.h"
#include "wmcodecdsp.h"

// {FC685FD7-17B1-4D08-84E7-A573726F9F66}
DEFINE_GUID(CLSID_Source,
	0xfc685fd7, 0x17b1, 0x4d08, 0x84, 0xe7, 0xa5, 0x73, 0x72, 0x6f, 0x9f, 0x66);

DEFINE_GUID(DX50,
	0x30355844, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);

DEFINE_GUID(FLV1,
	0x31564c46, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);

DEFINE_GUID(XVID,
	0x44495658, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);



class CFilter;

class CVideoPin : public CSourceStream
{
	friend class CFilter;
public:
	CVideoPin(HRESULT *phr, CSource *pParent, LPCWSTR pPinName, int mType);
	~CVideoPin();
	HRESULT OnThreadCreate();
	HRESULT OnThreadStartPlay(void);
	HRESULT OnThreadDestroy(void);
	HRESULT FillBuffer(IMediaSample *pms);
	HRESULT DecideBufferSize(IMemAllocator * pAlloc, ALLOCATOR_PROPERTIES * pRequest);//确定缓冲区大小
	HRESULT SetMediaType(const CMediaType *pMediaType);
	HRESULT CheckMediaType(const CMediaType *pMediaType);
	HRESULT GetMediaType(int iPosition, CMediaType *pmt);
	HRESULT BreakConnect();
	HRESULT CompleteConnect(IPin *pReceivePin);
	CFilter* pCFilter;//过滤器指针
	int type;//引脚索引
	HGLOBAL hMem;
	BYTE* pStar = NULL;//视频样本起始内存位置
	BYTE* pEnd = NULL;//视频样本结束内存位置
	BYTE* pCur = NULL;//当前读取位置内存指针
};

class CAudioPin : public CSourceStream
{
	friend class CFilter;
public:
	CAudioPin(HRESULT *phr, CSource *pParent, LPCWSTR pPinName);
	~CAudioPin();
	HRESULT OnThreadCreate();
	HRESULT OnThreadStartPlay(void);
	HRESULT OnThreadDestroy(void);
	HRESULT FillBuffer(IMediaSample *pms);
	HRESULT DecideBufferSize(IMemAllocator * pAlloc, ALLOCATOR_PROPERTIES * pRequest);//确定缓冲区大小
	HRESULT SetMediaType(const CMediaType *pMediaType);
	HRESULT CheckMediaType(const CMediaType *pMediaType);
	HRESULT GetMediaType(int iPosition, CMediaType *pmt);
	CFilter* pCFilter;//过滤器指针
	BYTE* pStar = NULL;//音频数据起始地址
	BYTE* pEnd = NULL;//音频样本结束内存位置
	HGLOBAL hMem; //资源句柄
	BYTE* pCur;//音频数据当前读取位置
	LONGLONG star, end;//音频样本时间戳
};

class CFilter : public CSource, public IMediaSeeking
{
public:
	CFilter(LPUNKNOWN pUnk, HRESULT *phr);
	~CFilter();
	static CUnknown * WINAPI CreateInstance(LPUNKNOWN pUnk, HRESULT *phr);
	DECLARE_IUNKNOWN
	STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv);
	DWORD m_dwSeekingCaps = AM_SEEKING_CanSeekForwards | AM_SEEKING_CanSeekBackwards | AM_SEEKING_CanSeekAbsolute | AM_SEEKING_CanGetStopPos | AM_SEEKING_CanGetDuration;
	HRESULT STDMETHODCALLTYPE CheckCapabilities(DWORD *pCapabilities);
	HRESULT STDMETHODCALLTYPE ConvertTimeFormat(LONGLONG *pTarget, const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat);
	HRESULT STDMETHODCALLTYPE GetAvailable(LONGLONG *pEarliest, LONGLONG *pLatest);
	HRESULT STDMETHODCALLTYPE GetCapabilities(DWORD *pCapabilities);
	HRESULT STDMETHODCALLTYPE GetCurrentPosition(LONGLONG *pCurrent);
	HRESULT STDMETHODCALLTYPE GetDuration(LONGLONG *pDuration);
	HRESULT STDMETHODCALLTYPE GetPositions(LONGLONG *pCurrent, LONGLONG *pStop);
	HRESULT STDMETHODCALLTYPE GetPreroll(LONGLONG *pllPreroll);
	HRESULT STDMETHODCALLTYPE GetRate(double *pdRate);
	HRESULT STDMETHODCALLTYPE GetStopPosition(LONGLONG *pStop);
	HRESULT STDMETHODCALLTYPE GetTimeFormat(GUID *pFormat);
	HRESULT STDMETHODCALLTYPE IsFormatSupported(const GUID *pFormat);
	HRESULT STDMETHODCALLTYPE IsUsingTimeFormat(const GUID *pFormat);
	HRESULT STDMETHODCALLTYPE QueryPreferredFormat(GUID *pFormat);
	HRESULT STDMETHODCALLTYPE SetPositions(LONGLONG *pCurrent, DWORD dwCurrentFlags, LONGLONG *pStop, DWORD dwStopFlags);
	HRESULT STDMETHODCALLTYPE SetRate(double dRate);
	HRESULT STDMETHODCALLTYPE SetTimeFormat(const GUID *pFormat);
	CVideoPin* pDX50;//DX50视频输出引脚
	CVideoPin* pFLV1;//FLV1视频输出引脚
	CVideoPin* pH264;//H264视频输出引脚
	CVideoPin* pMJPG;//MJPG视频输出引脚
	CVideoPin* pXVID;//XVID视频输出引脚
	CVideoPin* pWMV2;//WMV2视频输出引脚
	CVideoPin* pWMV3;//WMV2视频输出引脚
	CAudioPin* pPCM;//PCM音频输出引脚
	int Connected = -1;//已连接引脚的索引
	LONGLONG DUR;//视频时长。单位110纳秒
	LONGLONG CUR;//当前位置。单位110纳秒
	LONGLONG ResetPos = 0;//新位置
};



#endif //DLL_FILE

CFilter.cpp

cpp 复制代码
#include "DLL.h"


CFilter::CFilter(LPUNKNOWN lpunk, HRESULT *phr) : CSource(NAME("RGB视频源"), lpunk, CLSID_Source)
{
	pDX50 = new CVideoPin(phr, this, L"DX50", 0);//创建DX50视频输出引脚
	pFLV1 = new CVideoPin(phr, this, L"FLV1", 1);//创建FLV1视频输出引脚
	pH264 = new CVideoPin(phr, this, L"H264", 2);//创建H264视频输出引脚
	pMJPG = new CVideoPin(phr, this, L"MJPG", 3);//创建MJPG视频输出引脚
	pXVID = new CVideoPin(phr, this, L"XVID", 4);//创建XVID视频输出引脚
	pWMV2 = new CVideoPin(phr, this, L"WMV2", 5);//创建WMV2视频输出引脚
	pWMV3 = new CVideoPin(phr, this, L"WMV3", 6);//创建WMV3视频输出引脚
	pPCM = new CAudioPin(phr, this, L"PCM");//创建音频输出引脚
	DUR = 2881000000;//视频时长,单位100纳秒
}

CFilter::~CFilter()
{

}

STDMETHODIMP CFilter::NonDelegatingQueryInterface(REFIID iid, void ** ppv)
{
	if (iid == IID_IMediaSeeking)
	{
		return GetInterface(static_cast<IMediaSeeking*>(this), ppv);
	}
	else
		return CBaseFilter::NonDelegatingQueryInterface(iid, ppv);
}

CUnknown * WINAPI CFilter::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr)
{
	return new CFilter(pUnk, phr);//创建过滤器
}

HRESULT STDMETHODCALLTYPE CFilter::CheckCapabilities(DWORD *pCapabilities)//查询流是否具有指定的Seek功能
{
	CheckPointer(pCapabilities, E_POINTER);
	return (~m_dwSeekingCaps & *pCapabilities) ? S_FALSE : S_OK;
}

HRESULT STDMETHODCALLTYPE CFilter::ConvertTimeFormat(LONGLONG *pTarget, const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat)//从一种时间格式转换为另一种时间格式
{
	CheckPointer(pTarget, E_POINTER);
	if (pTargetFormat == 0 || *pTargetFormat == TIME_FORMAT_MEDIA_TIME)
	{
		*pTarget = Source;
		return S_OK;
	}
	return E_INVALIDARG;
}

HRESULT STDMETHODCALLTYPE CFilter::GetAvailable(LONGLONG *pEarliest, LONGLONG *pLatest)//获取有效Seek的时间范围
{
	if (pEarliest)
	{
		*pEarliest = 0;
	}
	if (pLatest)
	{
		CAutoLock lock(m_pLock);
		*pLatest = DUR;
	}
	return S_OK;
}

HRESULT STDMETHODCALLTYPE CFilter::GetCapabilities(DWORD *pCapabilities)//检索流的所有Seek功能
{
	CheckPointer(pCapabilities, E_POINTER);
	*pCapabilities = m_dwSeekingCaps;
	return S_OK;
}

HRESULT STDMETHODCALLTYPE CFilter::GetCurrentPosition(LONGLONG *pCurrent)//获取相对于流总持续时间的当前位置
{
	*pCurrent = CUR;
	return S_OK;
}

HRESULT STDMETHODCALLTYPE CFilter::GetDuration(LONGLONG *pDuration)//获取流的持续时间
{
	CheckPointer(pDuration, E_POINTER);
	CAutoLock lock(m_pLock);
	*pDuration = DUR;
	return S_OK;
}

HRESULT STDMETHODCALLTYPE CFilter::GetPositions(LONGLONG *pCurrent, LONGLONG *pStop)//获取相对于流总持续时间的当前位置和停止位置
{
	CheckPointer(pCurrent, E_POINTER); CheckPointer(pStop, E_POINTER);
	*pCurrent = CUR; *pStop = DUR;
	return S_OK;
}

HRESULT STDMETHODCALLTYPE CFilter::GetPreroll(LONGLONG *pllPreroll)//获取将在开始位置之前排队的数据量
{
	CheckPointer(pllPreroll, E_POINTER);
	*pllPreroll = 0;
	return S_OK;
}

HRESULT STDMETHODCALLTYPE CFilter::GetRate(double *pdRate)//获取播放速率
{
	CheckPointer(pdRate, E_POINTER);
	CAutoLock lock(m_pLock);
	*pdRate = 1.0;
	return S_OK;
}

HRESULT STDMETHODCALLTYPE CFilter::GetStopPosition(LONGLONG *pStop)//获取相对于流的持续时间的停止播放时间
{
	CheckPointer(pStop, E_POINTER);
	CAutoLock lock(m_pLock);
	*pStop = DUR;
	return S_OK;
}

HRESULT STDMETHODCALLTYPE CFilter::GetTimeFormat(GUID *pFormat)//获取当前用于Seek操作的时间格式
{
	CheckPointer(pFormat, E_POINTER);
	*pFormat = TIME_FORMAT_MEDIA_TIME;
	return S_OK;
}

HRESULT STDMETHODCALLTYPE CFilter::IsFormatSupported(const GUID *pFormat)//确定Seek操作是否支持指定的时间格式
{
	CheckPointer(pFormat, E_POINTER);
	return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE;
}

HRESULT STDMETHODCALLTYPE CFilter::IsUsingTimeFormat(const GUID *pFormat)//确定Seek操作当前是否使用指定的时间格式
{
	CheckPointer(pFormat, E_POINTER);
	return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE;
}

HRESULT STDMETHODCALLTYPE CFilter::QueryPreferredFormat(GUID *pFormat)//获取首选的Seek时间格式
{
	CheckPointer(pFormat, E_POINTER);
	*pFormat = TIME_FORMAT_MEDIA_TIME;
	return S_OK;
}

HRESULT STDMETHODCALLTYPE CFilter::SetPositions(LONGLONG *pCurrent, DWORD dwCurrentFlags, LONGLONG *pStop, DWORD dwStopFlags)//设置当前位置和停止位置
{
	CheckPointer(pCurrent, E_POINTER); HRESULT hr;
	DWORD dwCurrentPos = dwCurrentFlags & AM_SEEKING_PositioningBitsMask;
	if (dwCurrentPos == AM_SEEKING_AbsolutePositioning && *pCurrent >= 0 && *pCurrent < DUR)
	{
		ResetPos = *pCurrent;  *pStop = DUR - *pCurrent;
		CVideoPin* pVideoPin = NULL;
		switch (Connected)
		{
		case 0:
			pVideoPin = pDX50;
			break;
		case 1:
			pVideoPin = pFLV1;
			break;
		case 2:
			pVideoPin = pH264;
			break;
		case 3:
			pVideoPin = pMJPG;
			break;
		case 4:
			pVideoPin = pXVID;
			break;
		case 5:
			pVideoPin = pWMV2;
			break;
		case 6:
			pVideoPin = pWMV3;
			break;
		}
		if (pVideoPin)
		{
			hr = pVideoPin->DeliverBeginFlush();                                                      hr = pPCM->DeliverBeginFlush();
			hr = pVideoPin->Stop();                                                                                   hr = pPCM->Stop();
			hr = pVideoPin->DeliverEndFlush();                                                         hr = pPCM->DeliverEndFlush();
			hr = pVideoPin->Run();                                                                                    hr = pPCM->Run();
		}
		return S_OK;
	}
	return E_INVALIDARG;
}

HRESULT STDMETHODCALLTYPE CFilter::SetRate(double dRate)//设置播放速率
{
	if (dRate == 1.0)return S_OK;
	else return S_FALSE;
}

HRESULT STDMETHODCALLTYPE CFilter::SetTimeFormat(const GUID *pFormat)//设置后续Seek操作的时间格式
{
	CheckPointer(pFormat, E_POINTER);
	return *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : E_INVALIDARG;
}

CAudioPin.cpp

cpp 复制代码
#include "DLL.h"


CAudioPin::CAudioPin(HRESULT *phr, CSource *pParent, LPCWSTR pPinName) : CSourceStream(NAME("PCM"), phr, pParent, pPinName)
{
	pCFilter = (CFilter*)pParent;
}

CAudioPin::~CAudioPin()
{
	FreeResource(hMem);//释放音频数据占用的内存
}

HRESULT CAudioPin::GetMediaType(int iPosition, CMediaType *pmt)//在枚举输出引脚,连接引脚时调用
{
	if (iPosition == 0)
	{
		pmt->majortype = MEDIATYPE_Audio;//主要类型
		pmt->subtype = MEDIASUBTYPE_PCM;//子类型
		pmt->formattype = FORMAT_WaveFormatEx;//格式类型
		pmt->bFixedSizeSamples = TRUE;//样本是固定大小
		pmt->bTemporalCompression = FALSE;//使用时间压缩
		pmt->lSampleSize = 0;//样本大小
		pmt->pUnk = NULL;//IUnknown指针
		pmt->cbFormat = sizeof(WAVEFORMATEX);//格式块的大小
		WAVEFORMATEX* p = (WAVEFORMATEX*)CoTaskMemAlloc(sizeof(WAVEFORMATEX));//为格式块分配内存
		pmt->pbFormat = (BYTE*)p;//格式块的指针
		p->wFormatTag = WAVE_FORMAT_PCM;//编码方式
		p->nChannels = 2;//声道数
		p->nSamplesPerSec = 44100;//采样率
		p->nAvgBytesPerSec = 44100 * 4;//数据传输率
		p->nBlockAlign = 4;//块对齐
		p->wBitsPerSample = 16;//样本位数
		p->cbSize = 0;//附加信息大小
		return S_OK;
	}
	return VFW_S_NO_MORE_ITEMS;
}

HRESULT CAudioPin::DecideBufferSize(IMemAllocator * pAlloc, ALLOCATOR_PROPERTIES * pRequest)
{
	HRESULT hr;
	pRequest->cBuffers = 1;//1个缓冲区
	pRequest->cbBuffer = 44100 * 4;//缓冲区的大小为1秒音频数据大小
	ALLOCATOR_PROPERTIES Actual;
	hr = pAlloc->SetProperties(pRequest, &Actual);
	if (FAILED(hr))return hr;
	if (Actual.cbBuffer < pRequest->cbBuffer)// 这个分配器是否不合适
	{
		return E_FAIL;
	}
	return NOERROR;
}

HRESULT CAudioPin::SetMediaType(const CMediaType *pMediaType)
{
	return CSourceStream::SetMediaType(pMediaType); 
}

HRESULT CAudioPin::CheckMediaType(const CMediaType *pMediaType)
{
	if (pMediaType->majortype == MEDIATYPE_Audio && pMediaType->subtype == MEDIASUBTYPE_PCM && pMediaType->formattype == FORMAT_WaveFormatEx)
		return S_OK;
	return S_FALSE;
}

HRESULT CAudioPin::OnThreadCreate()
{
	HRSRC hRes = FindResource(g_hInst, MAKEINTRESOURCE(IDR_DAT1), L"DAT");
	hMem = LoadResource(g_hInst, hRes);//加载资源到内存
	pStar = (BYTE*)LockResource(hMem);//获取音频数据的起始内存地址
	pEnd = pStar + SizeofResource(g_hInst, hRes);//获取音频数据的结束位置地址
	pCFilter->ResetPos = 0;
	return S_OK;
}

HRESULT CAudioPin::OnThreadStartPlay(void)
{
	pCur = pStar;
	star = pCFilter->ResetPos / 10000000; end = star + 10000000;
	pCur += pCFilter->ResetPos / 10000000 * 44100 * 4;
	return DeliverNewSegment(0, pCFilter->DUR - pCFilter->ResetPos, 1.0);
}

HRESULT CAudioPin::FillBuffer(IMediaSample *pms)
{
	if (pCur >= pEnd )//如果到达末尾
	{
		DeliverEndOfStream();
		return S_FALSE;//流结束
	}
	long len;
	if (pEnd - pCur < 44100 * 4)//如果剩余的音频数据不足44100 * 4字节大小
	{
		len = pEnd - pCur;
	}
	else
	{
		len= 44100 * 4;
	}
	BYTE* pData = NULL;
	pms->GetPointer(&pData);
	CopyMemory(pData, pCur, len);
	pms->SetTime(&star, &end);//设置引脚样本时间戳
	pms->SetSyncPoint(TRUE);//设置同步点标志
	pms->SetActualDataLength(len);//设置有效数据大小
	star += 10000000; end += 10000000; pCur += 44100 * 4;
	return S_OK;
}

HRESULT CAudioPin::OnThreadDestroy(void)
{
	FreeResource(hMem);//释放内存中的资源
	return S_OK;
};

CVideoPin.cpp

cpp 复制代码
#include "DLL.h"


CVideoPin::CVideoPin(HRESULT *phr, CSource *pParent, LPCWSTR pPinName, int mType) : CSourceStream(L"视频源", phr, pParent, pPinName)
{
	pCFilter = (CFilter*)pParent; type = mType;
}

CVideoPin::~CVideoPin()
{

}

HRESULT CVideoPin::GetMediaType(int iPosition, CMediaType *pmt)//在枚举输出引脚,连接引脚时调用
{
	if (iPosition == 0)
	{
		VIDEOINFOHEADER* p = NULL; MPEG2VIDEOINFO* p0 = NULL; VIDEOINFOHEADER2* p1 = NULL;
		DWORD dw[39] = { 16777216, 524307815, 1074222742, 585157527, 196608, 50331650, 1092308992, 7375376, 1744896000, 8404174, 3707764736, 951041123, 2147489024, 3722304989, 3722304989, 3722304989, 3722304989, 3722304989, 3722304989, 3722304989, 3722304989, 3722304989, 3722304989, 3722304989, 3722304989, 3722304989, 3722304989, 3722304989, 3722304989, 3722304989, 3722304989, 3722304989, 3722304989, 3722304989, 3722304989, 3722304989, 3722304989, 3722304989, 3722304989 };//序列头数组,H264使用
		BYTE pB[4] = { 167, 255, 180, 128 };//WMV2使用
		BYTE pC[5] = { 75, 249, 72, 1, 32 };//WMV3使用
		switch (type)
		{
		case 0://DX50
			pmt->majortype = MEDIATYPE_Video;
			pmt->subtype = DX50;
			pmt->formattype = FORMAT_VideoInfo2;
			pmt->bFixedSizeSamples = FALSE;
			pmt->bTemporalCompression = TRUE;
			pmt->lSampleSize = 1633920;
			pmt->pUnk = NULL;
			pmt->cbFormat = 112;
			p1 = (VIDEOINFOHEADER2*)CoTaskMemAlloc(pmt->cbFormat);
			pmt->pbFormat = (BYTE*)p1;//格式块的指针
			p1->rcSource = { 0,0,0,0 };
			p1->rcTarget = { 0,0,0,0 };
			p1->dwBitRate = 0;
			p1->dwBitErrorRate = 0;
			p1->AvgTimePerFrame = 500000;
			p1->dwInterlaceFlags = 1;
			p1->dwControlFlags = 0;
			p1->dwPictAspectRatioX = 0;// 115;
			p1->dwPictAspectRatioY = 0;// 74;
			p1->dwControlFlags = 0;
			p1->dwReserved1 = 0;
			p1->dwReserved2 = 0;
			p1->bmiHeader.biSize = 40;//图像信息结构大小
			p1->bmiHeader.biWidth = 920;//图像宽度
			p1->bmiHeader.biHeight = 592;//图像高度
			p1->bmiHeader.biPlanes = 1;//平面数
			p1->bmiHeader.biBitCount = 24;//每个像素位数
			p1->bmiHeader.biCompression = 808802372;//编码方式
			p1->bmiHeader.biSizeImage = 1633920;//图像的字节大小
			p1->bmiHeader.biXPelsPerMeter = 0;//水平分辨率
			p1->bmiHeader.biYPelsPerMeter = 0;//垂直分辨率
			p1->bmiHeader.biClrUsed = 0;//颜色表中颜色数量
			p1->bmiHeader.biClrImportant = 0;//重要颜色数量
			return S_OK;
		case 1://FLV1
			pmt->majortype = MEDIATYPE_Video;
			pmt->subtype = FLV1;
			pmt->formattype = FORMAT_VideoInfo2;
			pmt->bFixedSizeSamples = FALSE;
			pmt->bTemporalCompression = TRUE;
			pmt->lSampleSize = 1633920;
			pmt->pUnk = NULL;
			pmt->cbFormat = 112;
			p1 = (VIDEOINFOHEADER2*)CoTaskMemAlloc(pmt->cbFormat);
			pmt->pbFormat = (BYTE*)p1;//格式块的指针
			p1->rcSource = { 0,0,0,0 };
			p1->rcTarget = { 0,0,0,0 };
			p1->dwBitRate = 0;
			p1->dwBitErrorRate = 0;
			p1->AvgTimePerFrame = 500000;
			p1->dwInterlaceFlags = 1;
			p1->dwControlFlags = 0;
			p1->dwPictAspectRatioX = 115;
			p1->dwPictAspectRatioY = 74;
			p1->dwControlFlags = 0;
			p1->dwReserved1 = 0;
			p1->dwReserved2 = 0;
			p1->bmiHeader.biSize = 40;//图像信息结构大小
			p1->bmiHeader.biWidth = 920;//图像宽度
			p1->bmiHeader.biHeight = 592;//图像高度
			p1->bmiHeader.biPlanes = 1;//平面数
			p1->bmiHeader.biBitCount = 24;//每个像素位数
			p1->bmiHeader.biCompression = 827739206;//编码方式
			p1->bmiHeader.biSizeImage = 1633920;//图像的字节大小
			p1->bmiHeader.biXPelsPerMeter = 0;//水平分辨率
			p1->bmiHeader.biYPelsPerMeter = 0;//垂直分辨率
			p1->bmiHeader.biClrUsed = 0;//颜色表中颜色数量
			p1->bmiHeader.biClrImportant = 0;//重要颜色数量
			return S_OK;
		case 2://H264
			pmt->majortype = MEDIATYPE_Video;
			pmt->subtype = MEDIASUBTYPE_H264;
			pmt->formattype = FORMAT_MPEG2_VIDEO;
			pmt->bFixedSizeSamples = FALSE;
			pmt->bTemporalCompression = TRUE;
			pmt->lSampleSize = 1;
			pmt->pUnk = NULL;
			pmt->cbFormat = 175;
			p0 = (MPEG2VIDEOINFO*)CoTaskMemAlloc(pmt->cbFormat);
			pmt->pbFormat = (BYTE*)p0;//格式块的指针
			p0->hdr.rcSource = { 0,0,0,0 };//源矩形
			p0->hdr.rcTarget = { 0,0,0,0 };//目标矩形
			p0->hdr.dwBitRate = 0;//数据传输率
			p0->hdr.dwBitErrorRate = 0;//数据错误率
			p0->hdr.AvgTimePerFrame = 500000;//帧显示时间
			p0->hdr.dwInterlaceFlags = 0;//扫描方式标志
			p0->hdr.dwCopyProtectFlags = 0;//限制流的复制
			p0->hdr.dwPictAspectRatioX = 0;//以英寸为单位的图像宽度
			p0->hdr.dwPictAspectRatioY = 0;//以英寸为单位的图像高度
			p0->hdr.dwControlFlags = 0;//控制标志
			p0->hdr.dwReserved1 = 0;
			p0->hdr.dwReserved2 = 0;
			p0->hdr.bmiHeader.biSize = 40;//图像信息结构大小
			p0->hdr.bmiHeader.biWidth = 920;//图像宽度
			p0->hdr.bmiHeader.biHeight = 592;//图像高度
			p0->hdr.bmiHeader.biPlanes = 1;//平面数
			p0->hdr.bmiHeader.biBitCount = 0;//每个像素位数
			p0->hdr.bmiHeader.biCompression=875967048;//编码方式
			p0->hdr.bmiHeader.biSizeImage = 0;//图像的字节大小
			p0->hdr.bmiHeader.biXPelsPerMeter = 0;//水平分辨率
			p0->hdr.bmiHeader.biYPelsPerMeter = 0;//垂直分辨率
			p0->hdr.bmiHeader.biClrUsed = 0;//颜色表中颜色数量
			p0->hdr.bmiHeader.biClrImportant = 0;//重要颜色数量
			p0->dwStartTimeCode = 0;//开始时间码
			p0->cbSequenceHeader = 39;//序列头的长度
			p0->dwProfile = 77;//配置文件类型
			p0->dwLevel = 0;//级别类型
			p0->dwFlags = 0;//标志
			CopyMemory(&p0->dwSequenceHeader, dw, 39);
			return S_OK;
		case 3://MJPG
			pmt->majortype = MEDIATYPE_Video;
			pmt->subtype = MEDIASUBTYPE_MJPG;
			pmt->formattype = FORMAT_VideoInfo2;
			pmt->bFixedSizeSamples = FALSE;
			pmt->bTemporalCompression = FALSE;
			pmt->lSampleSize = 1633920;
			pmt->pUnk = NULL;
			pmt->cbFormat = 112;
			p1 = (VIDEOINFOHEADER2*)CoTaskMemAlloc(pmt->cbFormat);
			pmt->pbFormat = (BYTE*)p1;//格式块的指针
			p1->rcSource = { 0,0,0,0 };
			p1->rcTarget = { 0,0,0,0 };
			p1->dwBitRate = 0;
			p1->dwBitErrorRate = 0;
			p1->AvgTimePerFrame = 500000;
			p1->dwInterlaceFlags = 1;
			p1->dwControlFlags = 0;
			p1->dwPictAspectRatioX = 115;
			p1->dwPictAspectRatioY = 74;
			p1->dwControlFlags = 0;
			p1->dwReserved1 = 0;
			p1->dwReserved2 = 0;
			p1->bmiHeader.biSize = 40;//图像信息结构大小
			p1->bmiHeader.biWidth = 920;//图像宽度
			p1->bmiHeader.biHeight = 592;//图像高度
			p1->bmiHeader.biPlanes = 1;//平面数
			p1->bmiHeader.biBitCount = 24;//每个像素位数
			p1->bmiHeader.biCompression = 1196444237;//编码方式
			p1->bmiHeader.biSizeImage = 1633920;//图像的字节大小
			p1->bmiHeader.biXPelsPerMeter = 0;//水平分辨率
			p1->bmiHeader.biYPelsPerMeter = 0;//垂直分辨率
			p1->bmiHeader.biClrUsed = 0;//颜色表中颜色数量
			p1->bmiHeader.biClrImportant = 0;//重要颜色数量
			return S_OK;
		case 4://XVID
			pmt->majortype = MEDIATYPE_Video;
			pmt->subtype = XVID;
			pmt->formattype = FORMAT_VideoInfo;
			pmt->bFixedSizeSamples = FALSE;
			pmt->bTemporalCompression = TRUE;
			pmt->lSampleSize = 0;
			pmt->pUnk = NULL;
			pmt->cbFormat = sizeof(VIDEOINFOHEADER);
			p = (VIDEOINFOHEADER*)CoTaskMemAlloc(pmt->cbFormat);
			pmt->pbFormat = (BYTE*)p;//格式块的指针
			p->rcSource = { 0,0,0,0 };
			p->rcTarget = { 0,0,0,0 };
			p->dwBitRate = 0;
			p->dwBitErrorRate = 0;
			p->AvgTimePerFrame = 500000;
			p->bmiHeader.biSize = 40;//图像信息结构大小
			p->bmiHeader.biWidth = 920;//图像宽度
			p->bmiHeader.biHeight = 592;//图像高度
			p->bmiHeader.biPlanes = 1;//平面数
			p->bmiHeader.biBitCount = 12;//每个像素位数
			p->bmiHeader.biCompression = 1145656920;//编码方式
			p->bmiHeader.biSizeImage = 0;//图像的字节大小
			p->bmiHeader.biXPelsPerMeter = 0;//水平分辨率
			p->bmiHeader.biYPelsPerMeter = 0;//垂直分辨率
			p->bmiHeader.biClrUsed = 0;//颜色表中颜色数量
			p->bmiHeader.biClrImportant = 0;//重要颜色数量
			return S_OK;
		case 5://WMV2
			pmt->majortype = MEDIATYPE_Video;
			pmt->subtype = MEDIASUBTYPE_WMV2;
			pmt->formattype = FORMAT_VideoInfo2;
			pmt->bFixedSizeSamples = FALSE;
			pmt->bTemporalCompression = TRUE;
			pmt->lSampleSize = 1633920;
			pmt->pUnk = NULL;
			pmt->cbFormat = 116;
			p1 = (VIDEOINFOHEADER2*)CoTaskMemAlloc(pmt->cbFormat);
			pmt->pbFormat = (BYTE*)p1;//格式块的指针
			p1->rcSource = { 0,0,0,0 };
			p1->rcTarget = { 0,0,0,0 };
			p1->dwBitRate = 0;
			p1->dwBitErrorRate = 0;
			p1->AvgTimePerFrame = 500000;
			p1->dwInterlaceFlags = 1;
			p1->dwControlFlags = 0;
			p1->dwPictAspectRatioX = 115;
			p1->dwPictAspectRatioY = 74;
			p1->dwControlFlags = 0;
			p1->dwReserved1 = 0;
			p1->dwReserved2 = 0;
			p1->bmiHeader.biSize = 44;//图像信息结构大小
			p1->bmiHeader.biWidth = 920;//图像宽度
			p1->bmiHeader.biHeight = 592;//图像高度
			p1->bmiHeader.biPlanes = 1;//平面数
			p1->bmiHeader.biBitCount = 24;//每个像素位数
			p1->bmiHeader.biCompression = 844516695;//编码方式
			p1->bmiHeader.biSizeImage = 1633920;//图像的字节大小
			p1->bmiHeader.biXPelsPerMeter = 0;//水平分辨率
			p1->bmiHeader.biYPelsPerMeter = 0;//垂直分辨率
			p1->bmiHeader.biClrUsed = 0;//颜色表中颜色数量
			p1->bmiHeader.biClrImportant = 0;//重要颜色数量
			CopyMemory(pmt->pbFormat + 112, pB, 4);
			return S_OK;
		case 6://WMV3
			pmt->majortype = MEDIATYPE_Video;
			pmt->subtype = MEDIASUBTYPE_WMV3;
			pmt->formattype = FORMAT_VideoInfo2;
			pmt->bFixedSizeSamples = FALSE;
			pmt->bTemporalCompression = TRUE;
			pmt->lSampleSize = 0;
			pmt->pUnk = NULL;
			pmt->cbFormat = 117;
			p1 = (VIDEOINFOHEADER2*)CoTaskMemAlloc(pmt->cbFormat);
			pmt->pbFormat = (BYTE*)p1;//格式块的指针
			p1->rcSource = { 0,0,0,0 };
			p1->rcTarget = { 0,0,0,0 };
			p1->dwBitRate = 3000000;
			p1->dwBitErrorRate = 0;
			p1->AvgTimePerFrame = 500000;
			p1->dwInterlaceFlags = 0;
			p1->dwControlFlags = 0;
			p1->dwPictAspectRatioX = 115;
			p1->dwPictAspectRatioY = 74;
			p1->dwControlFlags = 0;
			p1->dwReserved1 = 0;
			p1->dwReserved2 = 0;
			p1->bmiHeader.biSize = 45;//图像信息结构大小
			p1->bmiHeader.biWidth = 920;//图像宽度
			p1->bmiHeader.biHeight = 592;//图像高度
			p1->bmiHeader.biPlanes = 1;//平面数
			p1->bmiHeader.biBitCount = 0;//每个像素位数
			p1->bmiHeader.biCompression = 861293911;//编码方式
			p1->bmiHeader.biSizeImage = 0;//图像的字节大小
			p1->bmiHeader.biXPelsPerMeter = 0;//水平分辨率
			p1->bmiHeader.biYPelsPerMeter = 0;//垂直分辨率
			p1->bmiHeader.biClrUsed = 0;//颜色表中颜色数量
			p1->bmiHeader.biClrImportant = 0;//重要颜色数量
			CopyMemory(pmt->pbFormat + 112, pC, 5);
			return S_OK;
		}
	}
	return S_FALSE;
}

HRESULT CVideoPin::DecideBufferSize(IMemAllocator * pAlloc, ALLOCATOR_PROPERTIES * pRequest)
{
	HRESULT hr;
	pRequest->cBuffers = 1;//1个缓冲区
	pRequest->cbBuffer = 10000000;//设置缓冲区10M大小
	ALLOCATOR_PROPERTIES Actual;
	hr = pAlloc->SetProperties(pRequest, &Actual);
	if (FAILED(hr))return hr;
	if (Actual.cbBuffer < pRequest->cbBuffer)// 这个分配器是否不合适
	{
		return E_FAIL;
	}
	return NOERROR;
}

HRESULT CVideoPin::SetMediaType(const CMediaType *pMediaType)
{
	return CSourceStream::SetMediaType(pMediaType);
}

HRESULT CVideoPin::CheckMediaType(const CMediaType *pMediaType)
{
	if (pCFilter->Connected != -1)return S_FALSE;//确保只连接1个视频引脚
	if (pMediaType->majortype == MEDIATYPE_Video )
	{
		switch (type)
		{
		case 0://DX50
			if (pMediaType->subtype == DX50 && pMediaType->formattype == FORMAT_VideoInfo2)
				return S_OK;
			break;
		case 1://FLV1
			if (pMediaType->subtype == FLV1 && pMediaType->formattype == FORMAT_VideoInfo2)
				return S_OK;
			break;
		case 2://H264
			if (pMediaType->subtype == MEDIASUBTYPE_H264 && pMediaType->formattype == FORMAT_MPEG2Video)
				return S_OK;
			break;
		case 3://MJPG
			if (pMediaType->subtype == MEDIASUBTYPE_MJPG && pMediaType->formattype == FORMAT_VideoInfo2)
				return S_OK;
			break;
		case 4://XVID
			if (pMediaType->subtype == XVID && pMediaType->formattype == FORMAT_VideoInfo)
				return S_OK;
			break;
		case 5://WMV2
			if (pMediaType->subtype == MEDIASUBTYPE_WMV2 && pMediaType->formattype == FORMAT_VideoInfo2)
				return S_OK;
			break;
		case 6://WMV3
			if (pMediaType->subtype == MEDIASUBTYPE_WMV3 && pMediaType->formattype == FORMAT_VideoInfo2)
				return S_OK;
			break;
		}
	}
	return S_FALSE;
}

HRESULT CVideoPin::BreakConnect()//断开连接时调用
{
	BOOL B0 = pCFilter->pDX50->IsConnected();
	BOOL B1 = pCFilter->pFLV1->IsConnected();
	BOOL B2 = pCFilter->pH264->IsConnected();
	BOOL B3 = pCFilter->pMJPG->IsConnected();
	BOOL B4 = pCFilter->pXVID->IsConnected();
	BOOL B5 = pCFilter->pWMV2->IsConnected();
	BOOL B6 = pCFilter->pWMV3->IsConnected();
	if (!B0 && !B1 && !B2 && !B3 && !B4 && !B5 && !B6)//如果没有1个视频引脚完成连接
		pCFilter->Connected = -1;
	return CSourceStream::BreakConnect();
}

HRESULT CVideoPin::CompleteConnect(IPin *pReceivePin)//完成连接时调用
{
	if (wcscmp(Name(), L"DX50") == 0)pCFilter->Connected = 0;
	if (wcscmp(Name(), L"FLV1") == 0)pCFilter->Connected = 1;
	if (wcscmp(Name(), L"H264") == 0)pCFilter->Connected = 2;
	if (wcscmp(Name(), L"MJPG") == 0)pCFilter->Connected = 3;
	if (wcscmp(Name(), L"XVID") == 0)pCFilter->Connected = 4;
	if (wcscmp(Name(), L"WMV2") == 0)pCFilter->Connected = 5;
	if (wcscmp(Name(), L"WMV3") == 0)pCFilter->Connected = 6;
	return CSourceStream::CompleteConnect(pReceivePin);
}

HRESULT CVideoPin::OnThreadCreate()
{
	DeliverBeginFlush();
	HRSRC hRes;
	switch (type)
	{
	case 0://DX50
		hRes = FindResource(g_hInst, MAKEINTRESOURCE(IDR_DAT9), L"DAT");//DX50样本
		break;
	case 1://FLV1
		hRes = FindResource(g_hInst, MAKEINTRESOURCE(IDR_DAT10), L"DAT");//DX50样本
		break;
	case 2://H264
		hRes = FindResource(g_hInst, MAKEINTRESOURCE(IDR_DAT6), L"DAT");//H264样本
		break;
	case 3://MJPG
		hRes = FindResource(g_hInst, MAKEINTRESOURCE(IDR_DAT11), L"DAT");//MJPG样本
		break;
	case 4://XVID
		hRes = FindResource(g_hInst, MAKEINTRESOURCE(IDR_DAT5), L"DAT");//XVID样本
		break;
	case 5://WMV2
		hRes = FindResource(g_hInst, MAKEINTRESOURCE(IDR_DAT7), L"DAT");//WMV2样本
		break;
	case 6://WMV3
		hRes = FindResource(g_hInst, MAKEINTRESOURCE(IDR_DAT8), L"DAT");//WMV3样本
		break;
	}
	hMem = LoadResource(g_hInst, hRes);
	pStar = (BYTE*)LockResource(hMem);//获取视频样本的起始内存地址
	pEnd = pStar + SizeofResource(g_hInst, hRes);
	DeliverEndFlush();
	pCFilter->ResetPos = 0;
	return S_OK;
}

HRESULT CVideoPin::OnThreadStartPlay(void)
{
	pCur = pStar;
	if (pCFilter->ResetPos)
	{
	Agan:
		LONGLONG star;
		CopyMemory(&star, pCur, 8); //时间戳开始时间
		pCur += 16;
		BYTE K;
		CopyMemory(&star, &K, 1); //关键帧标志
		pCur += 1;
		long Len;
		CopyMemory(&Len, pCur, 4);//样本大小
		pCur += 4 + Len;
		if (star < pCFilter->ResetPos)goto Agan;//在内存中搜索定位后的样本开始位置
	}
	return DeliverNewSegment(0, pCFilter->DUR-pCFilter->ResetPos, 1.0);
}

HRESULT CVideoPin::FillBuffer(IMediaSample *pms)
{
	LONGLONG star, end;
	CopyMemory(&star, pCur, 8); //时间戳开始时间
	pCur += 8;
	CopyMemory(&end, pCur, 8);//时间戳结束时间
	pCur += 8;
	BYTE SP;
	CopyMemory(&SP, pCur, 1);//关键帧标志
	pCur += 1;
	long Len;
	CopyMemory(&Len, pCur, 4);//样本大小
	pCur += 4;
	BYTE* pBuffer = NULL;
	pms->GetPointer(&pBuffer);
	CopyMemory(pBuffer, pCur, Len);//从内存复制样本
	pCur += Len;
	star -= pCFilter->ResetPos; end -= pCFilter->ResetPos;
	pms->SetTime(&star, &end);//设置样本时间戳
	pms->SetSyncPoint(SP);//设置同步点标志
	pms->SetActualDataLength(Len);//设置样本有效数据大小
	if (pCur >= pEnd)//如果读取到末尾
	{
		DeliverEndOfStream();//发送流结束通知
		return S_FALSE;//流结束
	}
	return S_OK;
}

HRESULT CVideoPin::OnThreadDestroy(void)
{
	FreeResource(hMem);//释放内存中的资源
	return S_OK; 
};
相关推荐
程序猿编码3 小时前
榨干 RTX5090 算力!Qwen3 专用单卡推理引擎,手写C++/CUDA 算子实现 MTP 推测解码
开发语言·c++·大模型推理·qwen3·多模态推理
西飘客3 小时前
vs 怎么根据dll 生成lib文件
c++·qt
程序员老陆4 小时前
深入理解 C++ thread_local:线程私有存储的正确打开方式
开发语言·c++·程序设计
美狐美颜sdk5 小时前
直播APP源码可以直接接入视频美颜sdk吗?技术方案详解
android·人工智能·音视频·美颜sdk·直播美颜sdk
揽秀亭长6 小时前
从音频到五线谱|扒谱过程中的关键技术环节
人工智能·音视频
java资料站7 小时前
二、Spring AI Alibaba · ChatModel
java·windows·spring
半杯咖啡半行码8 小时前
C++ 编程与 STL 模板:从泛型编程到内存安全详解
开发语言·c++
北冥you鱼8 小时前
Go 语言空接口(interface{})使用场景与最佳实践
开发语言·windows·golang
xh didida9 小时前
Linux -- 基础IO
linux·服务器·开发语言·c++