7.使用directshow采集视音频并进行H264和ACC实时编码再实时用MP4V2封装成MP4

之前博客讲的一些DirectShow的相关应用,可能对很多人来说已经有些旧了,因为更新的MediaFoundation已经替代了DShow的位置。但MediaFoundation只支持win7后的系统,也就是说不支持XP,所以在实际商业应用中,就windows平台而言,dshow依然是实际应用中的主流,ffmpeg、opencv第三方库的采集也都支持dshow,所以现在依然是比较常用的技术。

本篇开始之前,有不少人私信我,问一些工程中存在的问题,本篇打算把这些问题尽可能的解决一下。所以本篇的主题就是对之前的代码进行改进,使得工程更具有实用性,以下是要改进的列表:

1.对编码后的数据进行实时封装;之前进行视音频采集、编码后,都生成了.h264的视频文件和.aac的音频文件,也就是说文件落地了,然后才封装成了MP4,本篇会进行实时封装,不再生成独立的视频和音频文件,自始至终只会有一个MP4文件,这更符合实际应用的场景。

2.对视音频进行同步;之前好多人说同步做的不好,其实针对dshow而言,视音频同步起来还是很简单的,后面会详细讲解。

3.对工程引用的库文件和头文件全部整理到工程目录中来,让大家一次就能编译过;因为之前的工程用到的库和头文件比较散乱,导致大家用起来不方便。

4.对部分代码、结构进行改进,增加一些有用的设置,使得项目尽可能的实用一点;

5.会尽可能地增加注释,以便大家看的更明白。

首先,说一下大致的逻辑:使用Dshow进行视音频采集,采集的过程中将音频和视频都放进同一个队列中去,然后开启一个线程,从队列中一个一个取出来进行实时编码,取到视频就用X264进行编码,取到音频就用faac编码,编码的数据不再落地,而是使用MP4V2写到MP4中,编码和封装的过程中会涉及到视音频同步的问题。下面一一讲解。

本篇的例子程序全部放到线程中做了,防止出现卡顿现象。当然,可能还会有一些问题,真正要实用化可能还需要再继续改进。

DSHOW视音频采集部分跟之前大致相同,但这里要说一下,每个视频采集设备的采集能力是不一样的,比如有的相机采集的源数据只支持YUY2,有的支持YUY2和RGB的,我手上还有相机是支持IJPG的,但大部分相机应该都是支持YUY2或RGB的,所以我在列出视频分辨率的时候,顺便把相机支持的源流类型也列出来了,代码如下:

void CMainDlg::GetVideoResolution()
{
	if (m_pCapture)
	{
		m_arrCamResolutionArr.RemoveAll();
		m_cbxResolutionCtrl.ResetContent();
		IAMStreamConfig *pConfig = NULL;  
		//&MEDIATYPE_Video,如果包括其他媒体类型,第二个参数设置为0
		HRESULT hr = m_pCapture->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, 
			m_pVideoFilter, IID_IAMStreamConfig, (void **)&pConfig);

		int iCount = 0, iSize = 0;
		hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize);
		// Check the size to make sure we pass in the correct structure.
		if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS))
		{
			// Use the video capabilities structure.
			for (int iFormat = 0; iFormat < iCount; iFormat++)
			{
				VIDEO_STREAM_CONFIG_CAPS scc;
				AM_MEDIA_TYPE *pmtConfig = NULL;
				hr = pConfig->GetStreamCaps(iFormat, &pmtConfig, (BYTE*)&scc);
				if (SUCCEEDED(hr))
				{
					//(pmtConfig->subtype == MEDIASUBTYPE_RGB24) &&
					if ((pmtConfig->majortype == MEDIATYPE_Video) &&
						(pmtConfig->formattype == FORMAT_VideoInfo) &&
						(pmtConfig->cbFormat >= sizeof (VIDEOINFOHEADER)) &&
						(pmtConfig->pbFormat != NULL))
					{
						VIDEOINFOHEADER *pVih = (VIDEOINFOHEADER*)pmtConfig->pbFormat;
						// pVih contains the detailed format information.
						LONG lWidth = pVih->bmiHeader.biWidth;
						LONG lHeight = pVih->bmiHeader.biHeight;
						BOOL bFind = FALSE;
						//是否已经存在这个分辨率,不存在就加入array
						for (int n=0; n < m_arrCamResolutionArr.GetSize(); n++)
						{
							CamResolutionInfo sInfo = m_arrCamResolutionArr.GetAt(n);
							if (sInfo.nWidth == lWidth && sInfo.nHeight == lHeight)
							{
								bFind = TRUE;
								break;
							}
						}
						if (!bFind)
						{
							CamResolutionInfo camInfo;
							camInfo.nResolutionIndex = iFormat;
							camInfo.nWidth = lWidth;
							camInfo.nHeight = lHeight;
							m_arrCamResolutionArr.Add(camInfo);

							CString strSubType = _T("");
							if (MEDIASUBTYPE_RGB24 == pmtConfig->subtype)
							{
								strSubType = _T("RGB24");
							}
							else if (MEDIASUBTYPE_RGB555 == pmtConfig->subtype)
							{
								strSubType = _T("RGB555");
							}
							else if (MEDIASUBTYPE_RGB32 == pmtConfig->subtype)
							{
								strSubType = _T("RGB32");
							}
							else if (MEDIASUBTYPE_RGB565 == pmtConfig->subtype)
							{
								strSubType = _T("RGB565");
							}
							else if (MEDIASUBTYPE_RGB8 == pmtConfig->subtype)
							{
								strSubType = _T("RGB8");
							}
							else if (MEDIASUBTYPE_IJPG == pmtConfig->subtype)
							{
								strSubType = _T("IJPG");
							}
							else if (MEDIASUBTYPE_YUY2 == pmtConfig->subtype)
							{
								strSubType = _T("YUY2");
							}
							else if (MEDIASUBTYPE_YUYV == pmtConfig->subtype)
							{
								strSubType = _T("YUYV");
							}
							else if (MEDIASUBTYPE_H264 == pmtConfig->subtype)
							{
								strSubType = _T("H264");
							}
							else if (MEDIASUBTYPE_MJPG == pmtConfig->subtype)
							{
								strSubType = _T("MJPG");
							}
							else if (MEDIASUBTYPE_Y41P == pmtConfig->subtype)
							{
								strSubType = _T("Y41P");
							}
							else
		
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 19
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值