欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 培训 > DirectShow过滤器开发-写MP4视频文件过滤器(再写)

DirectShow过滤器开发-写MP4视频文件过滤器(再写)

2025/4/20 4:45:23 来源:https://blog.csdn.net/h3974/article/details/145097678  浏览:    关键词:DirectShow过滤器开发-写MP4视频文件过滤器(再写)

下载本过滤器DLL
本过滤器将H264视频流,AAC音频流写入MP4视频文件。

过滤器信息

过滤器名称:写MP4
过滤器GUID:{C7462A3A-DDE2-4F7E-B04E-BC323838F22B}
DLL注册函数名:DllRegisterServer
删除注册函数名:DllUnregisterServer
过滤器有2个输入引脚。

输入引脚1标识:Video
输入引脚1媒体类型:
主要类型:MEDIATYPE_Video
子类型:MEDIASUBTYPE_H264

输入引脚2标识:Audio
输入引脚2媒体类型:
主要类型:MEDIATYPE_Audio
子类型:MEDIASUBTYPE_MPEG_HEAAC

过滤器开发信息

过滤器从CBaseFilter派生,视频音频引脚从CBaseInputPin派生。Receive为引脚接收函数,记录引脚样本时间戳的结束时间,称之为当前时间,如果视频当前时间小,写视频样本,并阻塞音频接收函数,至音频当前时间小时,写音频样本,并阻塞视频接收函数;这样,写视频样本和写音频样本按时间大小交替进行。
视频引脚接收的H264样本为若干NALU单元,单元以4字节的“0001”开头,写入MP4文件时,需替换为单元大小,也占4字节。定义了自定义可增长数组MyArray,声明样本大小,样本偏移量,关键帧序号数组对象;将样本大小,样本偏移量,关键帧序号添加到对应数组。视频样本是否是关键帧,通过样本是否有同步点标志判断。过滤器运行时,首先引脚Active函数被调用,在该函数中,创建MP4输出文件,写ftyp box,mdat box;mdat box直接使用扩展box,目的是简化代码,因为文件大小可能超过4字节表示的大小。过滤器停止时,引脚Inactive函数被调用,在该函数中发出“停止”信号,以终止写样本,写mdat box扩展大小,然后写moov box,根据获取到的流参数,填写相应box参数,序列参数集(sps),图像参数集(pps)从视频引脚SetMediaType函数中获取,视频轨道创建了stsd box,stts box,stss box,stsc box,stsz box,co64 box。通过相应的数组中的元素填写相应box每个条目。直接使用co64 box而不是stco box,目的也是为了简化代码。没有创建ctts box,时间信息保存在样本中,没有去除。试验证明,此方法是可行的。

过滤器DLL的全部代码

DLL.h


#ifndef  DLL_FILE
#define DLL_FILE#include "strmbase10.h"//过滤器基础类定义文件#if _DEBUG
#pragma comment(lib, "strmbasd10.lib")//过滤器基础类实现文件调试版本
#else
#pragma comment(lib, "strmbase10.lib")//过滤器基础类实现文件发布版本
#endif#include "wmcodecdsp.h"
#include "strsafe.h"// {C7462A3A-DDE2-4F7E-B04E-BC323838F22B}
DEFINE_GUID(CLSID_WriteMP4,0xc7462a3a, 0xdde2, 0x4f7e, 0xb0, 0x4e, 0xbc, 0x32, 0x38, 0x38, 0xf2, 0x2b);template <class T> void SafeRelease(T** ppT)
{if (*ppT){(*ppT)->Release();*ppT = NULL;}
}#define MAX_INDEX 10000class MyArray//自定义ULONGLONG数组
{int index;//INDEX数组的索引UINT* pINDEX = NULL;//该数组中元素记录1024数组的地址
public:ULONGLONG Count;//元素数量MyArray(UINT* p){pINDEX = p; index = -1; Count = 0;}~MyArray(){DeleteAll();}void Add(ULONGLONG UL){if (Count % 1024==0){index++;if (index > MAX_INDEX -1){MessageBox(0, L"超过数组允许最大数量", L"写MP4", 0); index--; return;}pINDEX[index] = (UINT) new ULONGLONG[1024];}ULONGLONG* p = (ULONGLONG*)pINDEX[index];p[Count % 1024] = UL;Count++;}ULONGLONG GetAt(UINT i){ULONGLONG* p = (ULONGLONG*)pINDEX[i / 1024];return p[i % 1024];}void DeleteAll(){for (int i = 0; i < index + 1; i++){ULONGLONG* p = (ULONGLONG*)pINDEX[i];delete[] p;}index = -1; Count = 0;}
};class CFilter;
class CAudioPin;class CVideoPin : public CBaseInputPin
{friend class CFilter;friend class CAudioPin;
public:CVideoPin(CFilter *pFilter, HRESULT *phr, LPCWSTR pPinName);~CVideoPin();HRESULT CheckMediaType(const CMediaType *pmt);HRESULT SetMediaType(const CMediaType *pmt);STDMETHODIMP Receive(IMediaSample *pSample);HRESULT Active();HRESULT Inactive();STDMETHODIMP EndOfStream();CFilter *pCFilter;HANDLE hFile = NULL;//输出文件句柄HANDLE WriteCompleted = NULL;//“视频写样本完成”事件句柄HANDLE hStop;//“停止”事件句柄LONGLONG CurTime = 0;//视频流当前时间,单位100纳秒BOOL END;//为TRUE时,标记流结束HRESULT InitFile();//初始化MP4输出文件BOOL First = FALSE;//为TRUE时,为第1帧void WriteVideo(IMediaSample *pSample);//写视频样本void WriteAudio(IMediaSample *pSample);//写音频样本LONGLONG MdatSizePos;//记录mdat扩展大小位置void WriteMoov();//写moov boxUINT VideoCount;//视频帧数量UINT AudioCount;//音频样本数量UINT Uint1[MAX_INDEX]; UINT Uint2[MAX_INDEX]; UINT Uint3[MAX_INDEX]; UINT Uint4[MAX_INDEX]; UINT Uint5[MAX_INDEX];//自定义数组使用,该数组中元素记录1024数组的地址MyArray VideoKeyFram;//视频关键帧序号数组MyArray VideoOffsetAry;//视频样本偏移量数组MyArray VideoSizeAry;//视频样本大小数组MyArray AudioOffsetAry;//音频样本偏移量数组MyArray AudioSizeAry;//音频样本大小数组DWORD cbSequenceHeader = 0;//序列头的长度BYTE* pSequenceHeader = NULL;//序列头数组DWORD Profile = 0;//配置文件DWORD Level = 0;//级别LONG  biWidth;//图像的宽度LONG  biHeight;//图像的高度WORD BitCount;//位深度
};class CAudioPin : public CBaseInputPin
{friend class CFilter;friend class CVideoPin;
public:CAudioPin(CFilter *pFilter, HRESULT *phr, LPCWSTR pPinName);~CAudioPin();HRESULT CheckMediaType(const CMediaType *pmt);HRESULT SetMediaType(const CMediaType *pmt);STDMETHODIMP Receive(IMediaSample *pSample);STDMETHODIMP EndOfStream();CFilter *pCFilter;HANDLE WriteCompleted = NULL;//“音频写样本完成”事件句柄LONGLONG CurTime = 0;//音频流当前时间,单位100纳秒BOOL END;//为TRUE时,标记流结束DWORD SamplesPerSec;//采样率WORD nChannels;//声道数WORD wBitsPerSample;//样本位数
};class CFilter : public CBaseFilter, public CCritSec, public IFileSinkFilter
{friend class CAudioPin;friend class CVideoPin;
public:CFilter(LPWSTR lpName, LPUNKNOWN pUnk, HRESULT *phr);virtual ~CFilter();DECLARE_IUNKNOWNSTDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv);virtual HRESULT STDMETHODCALLTYPE  SetFileName(LPCOLESTR pszFileName, const AM_MEDIA_TYPE *pmt);virtual HRESULT STDMETHODCALLTYPE  GetCurFile(LPOLESTR * ppszFileName, AM_MEDIA_TYPE *pmt);static CUnknown * WINAPI CreateInstance(LPUNKNOWN, HRESULT *);int GetPinCount();CBasePin *GetPin(int n);CVideoPin* pCVideoPin = NULL;//视频输入引脚指针CAudioPin* pCAudioPin = NULL;  //音频输入引脚指针WCHAR* m_pFileName = NULL;//要创作的MP4文件路径
};UINT Find0001(BYTE* p, UINT len);#endif //DLL_FILE

DLL.cpp

#include "DLL.h"const AMOVIESETUP_MEDIATYPE VideoPinTypes =
{&MEDIATYPE_Video,                           //主要类型&MEDIASUBTYPE_H264                          //子类型
};const AMOVIESETUP_MEDIATYPE AudioPinTypes =
{&MEDIATYPE_Audio,                           //主要类型&MEDIASUBTYPE_MPEG_HEAAC                    //子类型
};const AMOVIESETUP_PIN sudPin[] =         // 引脚信息
{{L"Vudio",                        //引脚名称FALSE,                           //渲染引脚FALSE,                           //输出引脚FALSE,                           //具有该引脚的零个实例FALSE,                           //可以创建一个以上引脚的实例&CLSID_NULL,                     //该引脚连接的过滤器的类标识NULL,                            //该引脚连接的引脚名称1,                              //引脚支持的媒体类型数&VideoPinTypes                  //媒体类型信息},{L"Audio",                        //引脚名称FALSE,                           //渲染引脚FALSE,                           //输出引脚FALSE,                           //具有该引脚的零个实例FALSE,                          //可以创建一个以上引脚的实例&CLSID_NULL,                    //该引脚连接的过滤器的类标识NULL,                           //该引脚连接的引脚名称1,                              //引脚支持的媒体类型数&AudioPinTypes                  //媒体类型信息}
};const AMOVIESETUP_FILTER WriteMP4 =    //过滤器的注册信息
{&CLSID_WriteMP4,                  //过滤器的类标识L"写MP4",                         //过滤器的名称MERIT_DO_NOT_USE,                 //过滤器优先值2,                                //引脚数量sudPin                            //引脚信息
};CFactoryTemplate g_Templates[] =
{{L"写MP4"                             //对象(这里为过滤器)名称, &CLSID_WriteMP4                   //对象CLSID的指针, CFilter::CreateInstance           //创建对象实例的函数的指针, NULL                              //指向从DLL入口点调用的函数的指针, &WriteMP4                         //指向AMOVIESETUP_FILTER结构的指针}
};int g_cTemplates = 1;STDAPI DllRegisterServer()//注册DLL
{return AMovieDllRegisterServer2(TRUE);
}STDAPI DllUnregisterServer()//删除DLL注册
{return AMovieDllRegisterServer2(FALSE);
}extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);BOOL APIENTRY DllMain(HANDLE hModule, DWORD  dwReason, LPVOID lpReserved)
{return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved);
}

CFilter.cpp

#include "DLL.h"CFilter::CFilter(LPWSTR lpName, LPUNKNOWN pUnk, HRESULT *phr) : CBaseFilter(lpName, pUnk, (CCritSec *) this, CLSID_WriteMP4)
{pCVideoPin = new CVideoPin(this, phr, L"Video"); //创建视频输入引脚pCAudioPin = new CAudioPin(this, phr, L"Audio");//创建音频输入引脚
}CFilter::~CFilter()
{if (m_pFileName != NULL)delete[] m_pFileName;
}CUnknown * WINAPI CFilter::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr)
{return new CFilter(L"写MP4", pUnk, phr);//创建过滤器
}int CFilter::GetPinCount()
{return 2;
}CBasePin *CFilter::GetPin(int n)
{if (n == 0)return pCVideoPin;if (n == 1)return pCAudioPin;return NULL;
}STDMETHODIMP CFilter::NonDelegatingQueryInterface(REFIID iid, void ** ppv)
{if (iid == IID_IFileSinkFilter){return GetInterface(static_cast<IFileSinkFilter*>(this), ppv);}elsereturn CBaseFilter::NonDelegatingQueryInterface(iid, ppv);
}HRESULT CFilter::GetCurFile(LPOLESTR *ppszFileName, AM_MEDIA_TYPE *pmt)
{CheckPointer(ppszFileName, E_POINTER);*ppszFileName = NULL;if (m_pFileName != NULL){size_t len = 1 + lstrlenW(m_pFileName);*ppszFileName = (LPOLESTR)QzTaskMemAlloc(sizeof(WCHAR) * (len));if (*ppszFileName != NULL){HRESULT hr = StringCchCopyW(*ppszFileName, len, m_pFileName);}}return S_OK;
}HRESULT CFilter::SetFileName(LPCOLESTR pszFileName, const AM_MEDIA_TYPE *pmt)
{CheckPointer(pszFileName, E_POINTER);if (wcslen(pszFileName) > MAX_PATH || wcslen(pszFileName)<4)return ERROR_FILENAME_EXCED_RANGE;size_t len = 1 + lstrlenW(pszFileName);m_pFileName = new WCHAR[len];if (m_pFileName == 0)return E_OUTOFMEMORY;HRESULT hr = StringCchCopyW(m_pFileName, len, pszFileName);if (m_pFileName[len - 2] != '4' || m_pFileName[len - 3] != 'p' || m_pFileName[len - 4] != 'm' || m_pFileName[len - 5] != '.')//如果不是MP4文件{delete m_pFileName; m_pFileName = NULL;return VFW_E_INVALID_FILE_FORMAT;//设置文件名失败}return S_OK;
}

CVideoPin.cpp

#include "DLL.h"
#include "dvdmedia.h"CVideoPin::CVideoPin(CFilter *pFilter, HRESULT *phr, LPCWSTR pPinName) : CBaseInputPin(NAME("Video"), pFilter, pFilter, phr, pPinName)
, VideoKeyFram(Uint1), VideoOffsetAry(Uint2), VideoSizeAry(Uint3), AudioOffsetAry(Uint4), AudioSizeAry(Uint5)
{pCFilter = pFilter;WriteCompleted = CreateEvent(NULL, TRUE, FALSE, NULL);//手动重置,初始无信号hStop = CreateEvent(NULL, TRUE, FALSE, NULL);//手动重置,初始无信号
}CVideoPin::~CVideoPin()
{if (pSequenceHeader)delete[] pSequenceHeader;
}void Write1(HANDLE hFile, BYTE byte)
{WriteFile(hFile, &byte, 1, NULL, NULL);
}void Write2(HANDLE hFile, WORD w)
{BYTE hi = (BYTE)((w & 0xFF00) >> 8); BYTE lo = (BYTE)(w & 0xFF);WriteFile(hFile, &hi, 1, NULL, NULL); WriteFile(hFile, &lo, 1, NULL, NULL);
}void Write3(HANDLE hFile, UINT u)
{BYTE mByte1, mByte2, mByte3;mByte1 = (BYTE)((u & 0xFF0000) >> 16); mByte2 = (BYTE)((u & 0xFF00) >> 8); mByte3 = (BYTE)(u & 0xFF);WriteFile(hFile, &mByte1, 1, NULL, NULL); WriteFile(hFile, &mByte2, 1, NULL, NULL); WriteFile(hFile, &mByte3, 1, NULL, NULL);
}void Write4(HANDLE hFile, UINT u)
{BYTE mByte1, mByte2, mByte3, mByte4;mByte1 = (BYTE)((u & 0xFF000000) >> 24); mByte2 = (BYTE)((u & 0xFF0000) >> 16); mByte3 = (BYTE)((u & 0xFF00) >> 8); mByte4 = (BYTE)(u & 0xFF);WriteFile(hFile, &mByte1, 1, NULL, NULL); WriteFile(hFile, &mByte2, 1, NULL, NULL); WriteFile(hFile, &mByte3, 1, NULL, NULL); WriteFile(hFile, &mByte4, 1, NULL, NULL);
}void Write8(HANDLE hFile, ULONGLONG ul)
{BYTE mByte1, mByte2, mByte3, mByte4, mByte5, mByte6, mByte7, mByte8;mByte1 = (BYTE)((ul & 0xFF00000000000000) >> 56); mByte2 = (BYTE)((ul & 0xFF000000000000) >> 48); mByte3 = (BYTE)((ul & 0xFF0000000000) >> 40);mByte4 = (BYTE)((ul & 0xFF00000000) >> 32);mByte5 = (BYTE)((ul & 0xFF000000) >> 24); mByte6 = (BYTE)((ul & 0xFF0000) >> 16); mByte7 = (BYTE)((ul & 0xFF00) >> 8); mByte8 = (BYTE)(ul & 0xFF);WriteFile(hFile, &mByte1, 1, NULL, NULL); WriteFile(hFile, &mByte2, 1, NULL, NULL); WriteFile(hFile, &mByte3, 1, NULL, NULL); WriteFile(hFile, &mByte4, 1, NULL, NULL);WriteFile(hFile, &mByte5, 1, NULL, NULL); WriteFile(hFile, &mByte6, 1, NULL, NULL); WriteFile(hFile, &mByte7, 1, NULL, NULL); WriteFile(hFile, &mByte8, 1, NULL, NULL);
}LONGLONG GetFilePos(HANDLE hFile)//获取文件当前位置
{LARGE_INTEGER move;move.QuadPart = 0;LARGE_INTEGER CUR;SetFilePointerEx(hFile, move, &CUR, FILE_CURRENT);return CUR.QuadPart;
}HRESULT WriteEight(HANDLE hFile, LONGLONG Pos, ULONGLONG* p)//在指定位置写入8字节,并将文件指针返回到原来的位置
{LONGLONG Cur = GetFilePos(hFile);//获取当前位置LARGE_INTEGER Move;Move.QuadPart = Pos;SetFilePointerEx(hFile, Move, NULL, FILE_BEGIN);//移动到指定位置Write8(hFile, *p);//写入8字节Move.QuadPart = Cur;SetFilePointerEx(hFile, Move, NULL, FILE_BEGIN);//返回到原来的位置return S_OK;
}HRESULT CVideoPin::CheckMediaType(const CMediaType *pmt)
{if (pmt->majortype == MEDIATYPE_Video && pmt->subtype == MEDIASUBTYPE_H264 && pmt->formattype == FORMAT_MPEG2Video){return S_OK;}elsereturn S_FALSE;
}HRESULT CVideoPin::SetMediaType(const CMediaType *pmt)
{MPEG2VIDEOINFO* pInfo = (MPEG2VIDEOINFO*)pmt->pbFormat;cbSequenceHeader = pInfo->cbSequenceHeader;//序列头的长度if (pSequenceHeader)delete[] pSequenceHeader;pSequenceHeader = new BYTE[cbSequenceHeader];CopyMemory(pSequenceHeader, pInfo->dwSequenceHeader, cbSequenceHeader);//序列头数组Profile = pInfo->dwProfile;//配置文件Level = pInfo->dwLevel;//级别biWidth = pInfo->hdr.bmiHeader.biWidth;//图像的宽度biHeight = pInfo->hdr.bmiHeader.biHeight;//图像的高度BitCount = pInfo->hdr.bmiHeader.biBitCount;//位深度return CBaseInputPin::SetMediaType(pmt);
}HRESULT CVideoPin::Receive(IMediaSample * pSample)//接收函数
{
Agan:DWORD dw1 = WaitForSingleObject(WriteCompleted, 0);//检测“视频写样本完成”信号DWORD dw2 = WaitForSingleObject(hStop, 0);//检测“停止”信号if (dw2 == WAIT_OBJECT_0){return S_FALSE;//如果有“停止”信号,返回S_FALSE以终止流}if (pCFilter->pCAudioPin->END)//如果音频流已结束{WriteVideo(pSample);return S_OK;}if (dw1 != WAIT_OBJECT_0)//没有“视频写样本完成”信号{goto Agan;//重新检测(阻塞)}WriteVideo(pSample);//写视频样本if (CurTime <= pCFilter->pCAudioPin->CurTime)//如果视频当前时间小于或等于音频当前时间{ResetEvent(pCFilter->pCAudioPin->WriteCompleted);//设置“音频写样本完成”无信号SetEvent(WriteCompleted);//设置“视频写样本完成”有信号}else//如果音频当前时间小{ResetEvent(WriteCompleted);//设置“视频写样本完成”无信号SetEvent(pCFilter->pCAudioPin->WriteCompleted);//设置“音频写样本完成”有信号}return CBaseInputPin::Receive(pSample);
}UINT Find0001(BYTE* p, UINT len)
{int find = 0; BYTE* P = p;
Agan:BYTE by[4];CopyMemory(by, P, 4);if (by[0] == 0 && by[1] == 0 && by[2] == 0 && by[3] == 1){return find;}P += 1; find += 1;if ((UINT)find > len - 1)return 0;goto Agan;
}int GetNaluSize(BYTE* p, UINT len, UINT* pSize, int* pType)//返回NALU单元数量,将单元长度存储在pSize数组中
{BYTE by[4]; p += 4; len -= 4; int NuIndex = 0; UINT size = 0;while (len > 0){CopyMemory(by, p, 4);if (by[0] == 0 && by[1] == 0 && by[2] == 0 && by[3] == 1){p += 4; len -= 4;pSize[NuIndex] = size; NuIndex++; size = 0;  continue;}p += 1; size += 1; len -= 1;}pSize[NuIndex] = size;return NuIndex+1;
}void WriteSize(BYTE* p, UINT Size)
{BYTE pB1[4]; BYTE pB2[24];CopyMemory(pB1, &Size, 4);pB2[0] = pB1[3]; pB2[1] = pB1[2]; pB2[2] = pB1[1]; pB2[3] = pB1[0];CopyMemory(p, pB2, 4);
}void CVideoPin::WriteVideo(IMediaSample *pSample)//写视频样本
{BYTE* pBy = NULL;HRESULT  hr = pSample->GetPointer(&pBy);//获取视频引脚样本缓冲区指针long len = pSample->GetActualDataLength();//获取有效数据长度HRESULT SyncPoint = pSample->IsSyncPoint();//获取同步点标志LONGLONG star, end;hr = pSample->GetTime(&star, &end);//获取时间戳CurTime = end; VideoCount++;if (SyncPoint == S_OK)//如果有同步点标志{VideoKeyFram.Add((ULONGLONG)VideoCount);//将关键帧序号添加到数组}VideoSizeAry.Add((ULONGLONG)len);//将样本大小添加到数组VideoOffsetAry.Add((ULONGLONG)GetFilePos(hFile));//将样本偏移量添加到数组UINT pUint[16]; int pType[16];//下面代码将所有“0001”起始码替换为NALU单元大小int count = GetNaluSize(pBy, len, pUint,pType);BYTE* p = pBy;for (int i = 0; i < count; i++){WriteSize(p, pUint[i]); p += 4 + pUint[i];}WriteFile(hFile, pBy, len, NULL, NULL);//写视频样本到文件
}void CVideoPin::WriteAudio(IMediaSample *pSample)//写音频样本
{BYTE* pBy = NULL;HRESULT  hr = pSample->GetPointer(&pBy);//获取视频引脚样本缓冲区指针long len = pSample->GetActualDataLength();//获取有效数据长度LONGLONG star, end;hr = pSample->GetTime(&star, &end);//获取时间戳pCFilter->pCAudioPin->CurTime = end; AudioCount++;AudioSizeAry.Add((ULONGLONG)len);//将样本大小添加到数组AudioOffsetAry.Add((ULONGLONG)GetFilePos(hFile));//将样本偏移量添加到数组WriteFile(hFile, pBy, len, NULL, NULL);//写数据
}#define EC_VIDEOSTREAMEND EC_USER+1222//自定义”视频流结束“事件通知STDMETHODIMP CVideoPin::EndOfStream()
{pCFilter->NotifyEvent(EC_VIDEOSTREAMEND, NULL, NULL);//发送自定义“视频流结束”事件通知END = TRUE;return CBaseInputPin::EndOfStream();
}HRESULT CVideoPin::Active()
{InitFile();// 初始化MP4输出文件First = TRUE;return CBaseInputPin::Active();
}HRESULT CVideoPin::Inactive()
{SetEvent(hStop);Sleep(50);//确保视频音频写样本已停止WriteMoov();return CBaseInputPin::Inactive();
}HRESULT CVideoPin::InitFile()// 初始化MP4输出文件
{if (pCFilter->m_pFileName == NULL){MessageBox(0, L"没有指定输出文件", L"写AVI", MB_OK); return S_FALSE;}hFile = CreateFile(pCFilter->m_pFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);//创建输出文件if (INVALID_HANDLE_VALUE == hFile){MessageBox(0, L"创建输出文件失败", L"写AVI", MB_OK);hFile = NULL;return S_FALSE;}Write4(hFile, 24);//ftyp box大小WriteFile(hFile, "ftyp", 4, NULL, NULL);//ftyp box标识WriteFile(hFile, "isom", 4, NULL, NULL);//文件规范Write4(hFile, 1);//版本号WriteFile(hFile, "isomavc1", 8, NULL, NULL);//兼容规范Write4(hFile, 1);//mdat box大小WriteFile(hFile, "mdat", 4, NULL, NULL);//mdat box标识MdatSizePos = GetFilePos(hFile);//获取扩展mdat大小位置ULONGLONG mdat_largSize = 0;Write8(hFile, mdat_largSize);//写扩展mdat大小,此时未指定实际值ULONGLONG Ex = 0;Write8(hFile, Ex);//写扩展mdat属性END = FALSE; pCFilter->pCAudioPin->END = FALSE; pCFilter->pCAudioPin->CurTime = 0; CurTime = 0; VideoCount = 0; AudioCount = 0;ResetEvent(hStop);//设置“停止”无信号SetEvent(WriteCompleted);//设置“视频写样本完成”有信号ResetEvent(pCFilter->pCAudioPin->WriteCompleted);//设置“音频写样本完成”无信号return S_OK; 
}void CVideoPin::WriteMoov()//写moov box
{ULONGLONG mdat_largSize = GetFilePos(hFile) - 24;//获取扩展mdat大小WriteEight(hFile, MdatSizePos, &mdat_largSize);//写扩展mdat大小,并将文件指针返回到当前位置UINT find1 = Find0001(pSequenceHeader, cbSequenceHeader);UINT find2 = Find0001(pSequenceHeader + 4, cbSequenceHeader);//sps大小UINT pps_size = cbSequenceHeader - 4 - find2 - 4;//pps大小UINT avcC_size = 19 + find2 + pps_size; UINT avc1_size = 86 + avcC_size;UINT stsd_size = 16+ avc1_size;UINT stts_size = 24;UINT stss_size = (UINT)VideoKeyFram.Count * 4 + 16;UINT stsc_size = 28;UINT stsz_size = (UINT)VideoSizeAry.Count * 4 + 20;UINT co64_size = (UINT)VideoOffsetAry.Count * 8 + 16;UINT vmhd_size = 20;UINT dinf_size = 36;UINT stbl_size = 8 + stsd_size + stts_size + stss_size + stsc_size + stsz_size + co64_size;UINT mdhd_size = 32+12;UINT hdlr_size = 38;UINT minf_size = 8 + vmhd_size + dinf_size + stbl_size;UINT tkhd_size = 92;UINT mdia_size = 8 + mdhd_size + hdlr_size + minf_size;UINT video_trak_size = 8 + tkhd_size + mdia_size;UINT mvhd_size = 108;//以上为视频box大小UINT audio_stsd_size = 91;UINT audio_stts_size = 24;UINT audio_stsc_size = 28;UINT audio_stsz_size = 20 + (UINT)AudioSizeAry.Count * 4;UINT audio_co64_size = 16 + (UINT)AudioOffsetAry.Count * 8;UINT audio_smhd_size = 16;UINT audio_dinf_size = 36;UINT audio_stbl_size = 8 + audio_stsd_size + audio_stts_size + audio_stsc_size + audio_stsz_size + audio_co64_size;UINT audio_mdhd_size = 44;UINT audio_hdlr_size = 38;UINT audio_minf_size = 8 + audio_smhd_size + audio_dinf_size + audio_stbl_size;UINT audio_mdia_size = 8 + audio_mdhd_size + audio_hdlr_size + audio_minf_size;UINT audio_tkhd_size = 92;UINT audio_trak_size = 8 + audio_tkhd_size + audio_mdia_size;//以上为音频box大小UINT moov_size = 8 + mvhd_size + video_trak_size+ audio_trak_size;Write4(hFile, moov_size);//moov box大小WriteFile(hFile, "moov", 4, NULL, NULL);//moov box标识Write4(hFile, mvhd_size);//mvhd box大小WriteFile(hFile, "mvhd", 4, NULL, NULL);//mvhd box标识Write1(hFile, 0);//版本Write3(hFile, 0);//标志Write4(hFile, (UINT)0);//创建时间Write4(hFile, (UINT)0);//修改时间UINT mvhd_time_scale = 600;Write4(hFile, mvhd_time_scale);//时间刻度UINT mvhd_duration_time = (UINT)((double)CurTime / (double)10000000 * (double)mvhd_time_scale);Write4(hFile, mvhd_duration_time);//时间长度Write4(hFile, 65536);//推荐播放速度Write2(hFile, 256);//音量BYTE mvhd_reserved[10] = { 0,0,0,0,0,0,0,0,0,0 };WriteFile(hFile, mvhd_reserved, 10, NULL, NULL);//保留BYTE matrix[36] = { 0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0 };WriteFile(hFile, matrix, 36, NULL, NULL);//视频变换矩阵BYTE mvhd_PreDefined[24] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };WriteFile(hFile, mvhd_PreDefined, 24, NULL, NULL);//预定义Write4(hFile, 2);//下一个track使用的id号//视频trakWrite4(hFile, video_trak_size);//trak box大小WriteFile(hFile, "trak", 4, NULL, NULL);//trak box标识Write4(hFile, tkhd_size);//tkhd box大小WriteFile(hFile, "tkhd", 4, NULL, NULL);//tkhd box标识Write1(hFile, 0);//版本Write3(hFile, 1);//标志Write4(hFile, (UINT)0);//创建时间Write4(hFile, (UINT)0);//修改时间Write4(hFile, 1);//轨道标识Write4(hFile, 0);//保留Write4(hFile, mvhd_duration_time);//轨道的时间长度BYTE tkhd_reserved[8] = { 0,0,0,0,0,0,0,0 };WriteFile(hFile, tkhd_reserved, 8, NULL, NULL);//保留Write2(hFile, 0);//视频层Write2(hFile, 0);//分组信息Write2(hFile, 0);//音量Write2(hFile, 0);//保留WriteFile(hFile, matrix, 36, NULL, NULL);//视频变换矩阵Write2(hFile, (WORD)biWidth); Write2(hFile, 0);//视频宽度Write2(hFile, (WORD)biHeight); Write2(hFile, 0);//视频高度Write4(hFile, mdia_size);//mdia box大小WriteFile(hFile, "mdia", 4, NULL, NULL);//mdia box标识Write4(hFile, mdhd_size);//mdhd box大小WriteFile(hFile, "mdhd", 4, NULL, NULL);//mdhd box标识Write1(hFile, 1);//版本Write3(hFile, 0);//标志Write8(hFile, (ULONGLONG)0); //创建时间Write8(hFile, (ULONGLONG)0); //修改时间UINT mdhd_time_scale = 1000000;//1微秒Write4(hFile, mdhd_time_scale);//时间刻度分母(分子为1)ULONGLONG mdhd_duration_time =(ULONGLONG)( (double)CurTime / (double)10000000 * (double)mdhd_time_scale);Write8(hFile, mdhd_duration_time);//持续时间Write2(hFile, 0);//语言码Write2(hFile, 0);//预定义Write4(hFile, hdlr_size);//hdlr box大小   WriteFile(hFile, "hdlr", 4, NULL, NULL);//hdlr box标识Write1(hFile, 0);//版本Write3(hFile, 0);//标志Write4(hFile, 0);//预定义WriteFile(hFile, "vide", 4, NULL, NULL);//轨道类型BYTE hdlr_reserved[12] = { 0,0,0,0,0,0,0,0,0,0,0,0 };WriteFile(hFile, hdlr_reserved, 12, NULL, NULL);//保留char Handler_ch[6] = { 'v','i','d','e','o',0 };WriteFile(hFile, Handler_ch, 6, NULL, NULL);//处理类型Write4(hFile, minf_size);//minf box大小WriteFile(hFile, "minf", 4, NULL, NULL);//minf box标识Write4(hFile, vmhd_size);//vmhd box大小WriteFile(hFile, "vmhd", 4, NULL, NULL);//vmhd box标识Write1(hFile, 0);//版本Write3(hFile, 1);//标志Write2(hFile, 0);//视频合成模式。0,不使用合成Write2(hFile, 0); Write2(hFile, 0); Write2(hFile, 0);//合成使用的颜色Write4(hFile, dinf_size);//dinf box大小WriteFile(hFile, "dinf", 4, NULL, NULL);//dinf box标识Write4(hFile, 28);//dref box大小WriteFile(hFile, "dref", 4, NULL, NULL);//dref box标识Write1(hFile, 0);//版本Write3(hFile, 0);//标志Write4(hFile, (UINT)1);//条目数Write4(hFile, 12);//url box大小WriteFile(hFile, "url ", 4, NULL, NULL);//url box标识BYTE url_ch[4] = { 0,0,0,1 };WriteFile(hFile, url_ch, 4, NULL, NULL);//引用索引Write4(hFile, stbl_size);//stbl box大小WriteFile(hFile, "stbl", 4, NULL, NULL);//stbl box标识Write4(hFile, stsd_size);//stsd box大小    WriteFile(hFile, "stsd", 4, NULL, NULL);//stsd box标识Write1(hFile, 0);//版本Write3(hFile, 0);//标志Write4(hFile, (UINT)1);//条目数Write4(hFile, avc1_size);//avc1 box大小     WriteFile(hFile, "avc1", 4, NULL, NULL);//avc1 box标识BYTE avc1_ch[6] = { 0,0,0,0,0,0 };WriteFile(hFile, avc1_ch, 6, NULL, NULL);//保留Write2(hFile, 1);//数据引用索引Write2(hFile, 0);//预定义Write2(hFile, 0);//保留UINT avc1_pre_defined[3] = { 0,0,0 };WriteFile(hFile, avc1_pre_defined, 12, NULL, NULL);//预定义Write2(hFile, (WORD)biWidth);//宽Write2(hFile, (WORD)biHeight);//高Write2(hFile, 72); Write2(hFile, 0);//水平分辨率Write2(hFile, 72); Write2(hFile, 0);//垂直分辨率Write4(hFile, 0);//保留Write2(hFile, 1);//单个样本中的帧数量BYTE compressor_name[32] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };WriteFile(hFile, compressor_name, 32, NULL, NULL);//压缩器名称Write2(hFile, BitCount);//位深度Write2(hFile, 65535);//预定义Write4(hFile, avcC_size);//avcC box大小WriteFile(hFile, "avcC", 4, NULL, NULL);//avcC box标识Write1(hFile, 1);//版本Write1(hFile, (BYTE)Profile);//配置文件Write1(hFile, 0);//兼容文件Write1(hFile, (BYTE)Level);//编码级别Write1(hFile, 0xFF);Write1(hFile, 1);//sps数量Write2(hFile, find2);//sps大小WriteFile(hFile, pSequenceHeader+4, find2, NULL, NULL);//spsWrite1(hFile, 1);//pps数量Write2(hFile, pps_size);//pps大小WriteFile(hFile, pSequenceHeader + 4+find2+4, pps_size, NULL, NULL);//ppsWrite4(hFile, stts_size);//stts box大小WriteFile(hFile, "stts", 4, NULL, NULL);//stts box标识Write1(hFile, 0);//版本Write3(hFile, 0);//标志Write4(hFile, (UINT)1);//条目数Write4(hFile, VideoCount);//样本数量UINT SampleDur = (UINT)((double)CurTime / (double)VideoCount / (double)10000000 * (double)mdhd_time_scale);Write4(hFile, SampleDur);//单个样本的时长Write4(hFile, stss_size);//stss box大小     WriteFile(hFile, "stss", 4, NULL, NULL);//stss box标识Write1(hFile, 0);//版本Write3(hFile, 0);//标志Write4(hFile, (UINT)VideoKeyFram.Count);//条目数for (UINT i = 0; i < (UINT)VideoKeyFram.Count; i++){Write4(hFile, (UINT)VideoKeyFram.GetAt(i));//写关键帧序号}Write4(hFile, stsc_size);//stsc box大小   WriteFile(hFile, "stsc", 4, NULL, NULL);//stsc box标识Write1(hFile, 0);//版本Write3(hFile, 0);//标志Write4(hFile, (UINT)1);//条目数Write4(hFile, 1); Write4(hFile, 1); Write4(hFile, 1);//写条目(范围起始帧序号,每个块中样本的数量,适用的stsd)Write4(hFile, stsz_size);//stsz box大小    WriteFile(hFile, "stsz", 4, NULL, NULL);//stsz box标识Write1(hFile, 0);//版本Write3(hFile, 0);//标志Write4(hFile, 0);//默认样本大小Write4(hFile, (UINT)VideoSizeAry.Count);//条目数for (UINT i = 0; i < (UINT)VideoSizeAry.Count; i++){Write4(hFile, (UINT)VideoSizeAry.GetAt(i));//样本大小}Write4(hFile, co64_size);//co64 box大小WriteFile(hFile, "co64", 4, NULL, NULL);//co64 box标识Write1(hFile, 0);//版本Write3(hFile, 0);//标志Write4(hFile, (UINT)VideoOffsetAry.Count);//条目数for (UINT i = 0; i < (UINT)VideoOffsetAry.Count; i++){Write8(hFile, VideoOffsetAry.GetAt(i));//样本偏移量}//音频trakWrite4(hFile, audio_trak_size);//trak box大小WriteFile(hFile, "trak", 4, NULL, NULL);//trak box标识Write4(hFile, audio_tkhd_size);//tkhd box大小WriteFile(hFile, "tkhd", 4, NULL, NULL);//tkhd box标识Write1(hFile, 0);//版本Write3(hFile, 1);//标志Write4(hFile, 0);//创建时间Write4(hFile, 0);//修改时间Write4(hFile, 2);//轨道标识Write4(hFile, 0);//保留UINT tkhd_duration_time = (UINT)((double)pCFilter->pCAudioPin->CurTime / 10000000 * (double)mvhd_time_scale);Write4(hFile, tkhd_duration_time);//轨道的时间长度BYTE audio_tkhd_reserved[8] = { 0,0,0,0,0,0,0,0 };WriteFile(hFile, audio_tkhd_reserved, 8, NULL, NULL);//保留Write2(hFile, 0);//视频层Write2(hFile, 0);//分组信息Write2(hFile, (WORD)256);//音量Write2(hFile, 0);//保留WriteFile(hFile, matrix, 36, NULL, NULL);//视频变换矩阵Write2(hFile, 0); Write2(hFile, 0);//宽度Write2(hFile, 0); Write2(hFile, 0);//高度Write4(hFile, audio_mdia_size);//mdia box大小WriteFile(hFile, "mdia", 4, NULL, NULL);//mdia box标识Write4(hFile, audio_mdhd_size);//mdhd box大小WriteFile(hFile, "mdhd", 4, NULL, NULL);//mdhd box标识Write1(hFile, 1);//版本Write3(hFile, 0);//标志Write8(hFile, (ULONGLONG)0); //创建时间Write8(hFile, (ULONGLONG)0); //修改时间UINT mdhd_time_scaleA = 1000000;//1微秒Write4(hFile, mdhd_time_scaleA);//时间刻度分母(分子为1)ULONGLONG audio_dur = (ULONGLONG)((double)pCFilter->pCAudioPin->CurTime / 10000000 * (double)mdhd_time_scaleA);Write8(hFile, audio_dur);//持续时间Write2(hFile, 0);//语言码Write2(hFile, 0);//预定义Write4(hFile, audio_hdlr_size);//hdlr box大小   WriteFile(hFile, "hdlr", 4, NULL, NULL);//hdlr box标识Write1(hFile, 0);//版本Write3(hFile, 0);//标志Write4(hFile, 0);//预定义WriteFile(hFile, "soun", 4, NULL, NULL);//轨道类型BYTE hdlr_reservedA[12] = { 0,0,0,0,0,0,0,0,0,0,0,0 };WriteFile(hFile, hdlr_reservedA, 12, NULL, NULL);//保留char Handler_chA[6] = { 's','o','u','n','d',0 };WriteFile(hFile, Handler_chA, 6, NULL, NULL);//处理类型Write4(hFile, audio_minf_size);//minf box大小   WriteFile(hFile, "minf", 4, NULL, NULL);//minf box标识Write4(hFile, audio_smhd_size);//smhd box大小   WriteFile(hFile, "smhd", 4, NULL, NULL);//smhd box标识Write1(hFile, 0);//版本Write3(hFile, 0);//标志Write2(hFile, 0);//立体声平衡Write2(hFile, 0);//保留Write4(hFile, audio_dinf_size);//dinf box大小WriteFile(hFile, "dinf", 4, NULL, NULL);//dinf box标识Write4(hFile, 28);//dref box大小WriteFile(hFile, "dref", 4, NULL, NULL);//dref box标识Write1(hFile, 0);//版本Write3(hFile, 0);//标志Write4(hFile, (UINT)1);//条目数Write4(hFile, (UINT)12);//url box大小WriteFile(hFile, "url ", 4, NULL, NULL);//url box标识BYTE url_chA[4] = { 0,0,0,1 };WriteFile(hFile, url_chA, 4, NULL, NULL);//引用索引Write4(hFile, audio_stbl_size);//stbl box大小WriteFile(hFile, "stbl", 4, NULL, NULL);//stbl box标识Write4(hFile, audio_stsd_size);//stsd box大小=91WriteFile(hFile, "stsd", 4, NULL, NULL);//stsd box标识Write1(hFile, 0);//版本Write3(hFile, 0);//标志Write4(hFile, (UINT)1);//条目数UINT mp4a_size = 75;Write4(hFile, mp4a_size);//mp4a box大小WriteFile(hFile, "mp4a", 4, NULL, NULL);//mp4a box标识BYTE mp4a_reserved[6] = { 0,0,0,0,0,0 };WriteFile(hFile, mp4a_reserved, 6, NULL, NULL);//保留Write2(hFile, (WORD)1);//引用索引Write8(hFile, (ULONGLONG)0);//保留Write2(hFile, pCFilter->pCAudioPin->nChannels);//声道数Write2(hFile, pCFilter->pCAudioPin->wBitsPerSample);//样本位数Write2(hFile, (WORD)0);//预定义Write2(hFile, (WORD)0);//保留Write2(hFile, (WORD)pCFilter->pCAudioPin->SamplesPerSec); Write2(hFile, (WORD)0);//采样率UINT esds_size = 39;Write4(hFile, esds_size);//esds box大小WriteFile(hFile, "esds", 4, NULL, NULL);//esds box标识BYTE esds_by[31] = { 0,0,0,0,3,25,0,0,0,4,17,64,21,0,3,188,0,3,87,248,0,1,234,112,5,2,18,16,6,1,2 };WriteFile(hFile, esds_by, 31, NULL, NULL);//esds内容Write4(hFile, audio_stts_size);//stts box大小=24WriteFile(hFile, "stts", 4, NULL, NULL);//stts box标识Write1(hFile, 0);//版本Write3(hFile, 0);//标志Write4(hFile, (UINT)1);//条目数UINT sample_dur = (UINT)((double)pCFilter->pCAudioPin->CurTime / (double)10000000 / (double)AudioCount * (double)mdhd_time_scaleA);//单个样本的时长Write4(hFile, AudioCount); Write4(hFile, sample_dur);//条目:音频样本数量;单个样本的时长Write4(hFile, audio_stsc_size);//stsc box大小WriteFile(hFile, "stsc", 4, NULL, NULL);//stsc box标识Write1(hFile, 0);//版本Write3(hFile, 0);//标志Write4(hFile, (UINT)1);//条目数Write4(hFile, 1); Write4(hFile, 1); Write4(hFile, 1);//写条目:适用所有块;每个块包含1个样本;使用序号1的stsdWrite4(hFile, audio_stsz_size);//stsz box大小WriteFile(hFile, "stsz", 4, NULL, NULL);//stsz box标识Write1(hFile, 0);//版本Write3(hFile, 0);//标志Write4(hFile, 0);//默认样本大小Write4(hFile, (UINT)AudioSizeAry.Count);//条目数for (UINT i = 0; i < (UINT)AudioSizeAry.Count; i++){UINT size = (UINT)AudioSizeAry.GetAt(i);Write4(hFile, size);//样本大小}Write4(hFile, audio_co64_size);//co64 box大小WriteFile(hFile, "co64", 4, NULL, NULL);//co64 box标识Write1(hFile, 0);//版本Write3(hFile, 0);//标志Write4(hFile, (UINT)AudioOffsetAry.Count);//条目数for (UINT i = 0; i < (UINT)AudioOffsetAry.Count; i++){Write8(hFile, AudioOffsetAry.GetAt(i));//样本偏移量}CloseHandle(hFile);VideoKeyFram.DeleteAll();//视频关键帧序号数组VideoOffsetAry.DeleteAll();//视频样本偏移量数组VideoSizeAry.DeleteAll();//视频样本大小数组AudioOffsetAry.DeleteAll();//音频样本偏移量数组AudioSizeAry.DeleteAll();//音频样本大小数组
}

CAudioPin.cpp

#include "DLL.h"CAudioPin::CAudioPin(CFilter *pFilter, HRESULT *phr, LPCWSTR pPinName) : CBaseInputPin(NAME("Audio"), pFilter, pFilter, phr, pPinName)
{pCFilter = pFilter;WriteCompleted = CreateEvent(NULL, TRUE, FALSE, NULL);//手动重置,初始无信号
}CAudioPin::~CAudioPin()
{}HRESULT CAudioPin::CheckMediaType(const CMediaType *pmt)
{if (pmt->majortype == MEDIATYPE_Audio && pmt->subtype == MEDIASUBTYPE_MPEG_HEAAC && pmt->formattype == FORMAT_WaveFormatEx){return S_OK;}elsereturn S_FALSE;
}HRESULT CAudioPin::SetMediaType(const CMediaType *pmt)
{WAVEFORMATEX* p = (WAVEFORMATEX*)pmt->pbFormat;SamplesPerSec = p->nSamplesPerSec;//采样率nChannels = p->nChannels;//声道数wBitsPerSample = p->wBitsPerSample;//样本位数return CBaseInputPin::SetMediaType(pmt);
}HRESULT CAudioPin::Receive(IMediaSample * pSample)//接收函数
{
Agan:DWORD dw1 = WaitForSingleObject(WriteCompleted, 0);//检测“音频写样本完成”信号DWORD dw2 = WaitForSingleObject(pCFilter->pCVideoPin->hStop, 0);//检测“停止”信号if (dw2 == WAIT_OBJECT_0){return S_FALSE;//如果有“停止”信号,返回S_FALSE以终止流}if (pCFilter->pCVideoPin->END)//如果视频流已结束{pCFilter->pCVideoPin->WriteAudio(pSample);//写音频样本return S_OK;}if (dw1 != WAIT_OBJECT_0)//没有“写样本完成”信号{goto Agan;//重新检测(阻塞)}pCFilter->pCVideoPin->WriteAudio(pSample);//写音频样本if (CurTime < pCFilter->pCVideoPin->CurTime)//如果音频当前时间小{ResetEvent(pCFilter->pCVideoPin->WriteCompleted);//设置“视频写样本完成”无信号SetEvent(WriteCompleted);//设置“音频写样本完成”有信号}else//如果视频当前时间小于或等于音频当前时间{ResetEvent(WriteCompleted);//设置“音频写样本完成”无信号SetEvent(pCFilter->pCVideoPin->WriteCompleted);//设置“视频写样本完成”有信号}return CBaseInputPin::Receive(pSample);
}#define EC_AUDIOSTREAMEND EC_USER+1221//自定义”音频流结束“事件通知STDMETHODIMP CAudioPin::EndOfStream()
{pCFilter->NotifyEvent(EC_AUDIOSTREAMEND, NULL, NULL);//发送自定义“音频流结束”事件通知END = TRUE;return CBaseInputPin::EndOfStream();
}

下载本过滤器DLL

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词