6.使用DirecrShow采集摄像头视音频并实时进行H264和AAC编码后封装成MP4

该博客介绍了如何使用DirectShow从摄像头采集视音频,并通过X264和FAAC进行实时H264和AAC编码,最终封装成MP4文件。在采集过程中,为避免帧丢失,采用线程处理方式将帧数据存入数组,同时解决帧率不固定导致的播放问题。最后提到了利用ffmpeg进行封装的建议,并提供了完整工程的下载链接。
摘要由CSDN通过智能技术生成

之前一篇说了采集视频并实时进行H264编码,没有讲音频的实时编码,本篇将讲一个比较完整的例子,从DirectShow采集视音频,然后实时进行视音频的编码,最后封装成MP4。视频编码还使用之前用过的X264编码器,音频使用FAAC,这也比较常用的音频编码器,可直接在官网下载源码,最后将编码后的H264和AAC封装成MP4。

本篇将在前一篇(5.使用DirectShow进行摄像头采集并进行H264实时编码)的基础上进行,只要增加音频采集、编码以及最后的合成封装。不过视频的采集有和之前不一样的地方就是之前的编码工作直接在回调中进行的,本篇换了一种更好的方式,在回调中把每次过来的帧数据都放在一个array中保存起来,然后开启了一个处理线程,一边采集,一边编码处理,这样做比较合理一点,避免在回调中编码时花费大量时间而可能导致帧丢失问题。回调代码如下:

HRESULT STDMETHODCALLTYPE CSampleGrabberCB::BufferCB(double SampleTime, BYTE *pBuffer, long BufferLen)
{
	CString str;
	//str.Format(_T("\n BufferCB--lBufferSize:%ld,lWidth:%d,lHeight:%d"), BufferLen, lWidth, lHeight);
	//OutputDebugString(str);

	//也是开始录制
	if (m_bBeginEncode)
	{
		BYTE * pRgbData = new BYTE[BufferLen];
		memcpy(pRgbData, pBuffer, BufferLen);
		GrabDataInfo sData;
		sData.pData = pRgbData;
		sData.nDataSize = BufferLen;
		sData.dSampleTime = SampleTime;

		//把数据先存到array中
		m_mxMsgLog.Lock();
		m_arrGrabDataArr.Add(sData);
		m_mxMsgLog.Unlock();

		str.Format(_T("\n Video--BufferLen:%ld, SampleTime:%f \n"), BufferLen, SampleTime);
		OutputDebugString(str);

		if (m_bFirst)
		{
			m_bFirst = FALSE;

			CString str;
			str.Format(_T("\n Video--SampleTime:%f \n"), SampleTime);
			OutputDebugString(str);
			//开启线程来处理
			AfxBeginThread(VideoDealFunc, this);
		}
	}

	return 0;
}

m_arrGrabDataArr是一个结构,定义如下:

struct GrabDataInfo
{
	BYTE *pData;
	int nDataSize;
	double dSampleTime;

	GrabDataInfo()
	{
		pData = NULL;
		nDataSize = 0;
		dSampleTime = 0.0;
	};
	
	GrabDataInfo(const GrabDataInfo &other)
	{
		*this = other;
	};
	
	GrabDataInfo& operator = (const GrabDataInfo& other)
	{
		pData = other.pData;
		nDataSize = other.nDataSize;
		dSampleTime = other.dSampleTime;
		return *this;
	};
};
typedef CArray <GrabDataInfo, GrabDataInfo&> ASGrabDataInfoArray;
然后处理的部分全部放到线程中了,代码如下:

UINT VideoDealFunc(LPVOID lpVoid)
{
	CSampleGrabberCB *pManage = (CSampleGrabberCB*)lpVoid;
	if (pManage)
	{
		pManage->VideoDeal();
	}
	return 0;
}
void CSampleGrabberCB::VideoDeal()
{
	//等待音频正式开始的第一个样本时间有了后再比较
	while (!theApp.m_IsBegin)
	{
		Sleep(200);
	}

	double dSampleTime = theApp.m_nSampleTime;

	m_nFrameIndex = 0;
	int csp = X264_CSP_I420;
	int width = lWidt
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值