视频抓图(有硬编码解码)一获得解码后数据
2015-07-01 14:43
555 查看
一、解决方案
抓图就是保存视频帧,对于有硬编解码的视频,我们需要在编码前,或者解码后,获得视频帧。考虑到准确定位到要抓取的画面的帧,在接收流上做,是一个不错的选择。因为硬编解码的存在,好多事情都变得不那么简单了,比如GetCurrentImageFilter方法肯定不行了,在解码filter后连接一个抓图filter也不能达到预期效果,测试发现这个filter虽然连接上了,但是却工作不了,因为硬编码最后数据放到了显存中,硬解码filter跟最终的EVR(EnhancedVideo Renderer)是经过了特定协商的,才成功把视频帧传下去了。如果中间插入一个filter,硬解码数据就不能成功传过来,所以就工作不了了。那么解决方案是什么了?一个比较好的也是较简单的就是在解码filter上添加一个接口,再解码完成后,保存视频帧,这完全不影响它正常传给EVR。那么我们面对的问题,就主要有以下几个:获得到显存中数据;将帧格式转为rgb格式;将rgb数据生成一个bmp图片。二、获取数据
对于STDMETHODIMP GetPointer(BYTE ** ppBuffer);方法,大家是不是格外亲切熟悉了,是的,一般通过这个方法就能获得sample内存里的数据。但是硬解码后,再用这个方法会发现得不到任何数据,它确实得不到,也不可能得到,因为此时数据没有在内存中,所以我们要自己想办法得到数据,通过看硬解码filter的allocator发现EVR是通过MR_BUFFER_SERVICE获得surface的,注意这个surface是IDirect3DSurface9,然后调用它的LockRect方法,就获得数据了。1.IMFGetService
<strong>HRESULT CDXVA2Sample::QueryInterface(REFIID riid, void **ppv) { CheckPointer(ppv, E_POINTER); if (riid == __uuidof(IMFGetService)) { return GetInterface((IUnknown*)static_cast<IMFGetService*>(this), ppv); } return CMFXSample::QueryInterface(riid, ppv); }</strong>
2.从sample上获得获得service
IMFGetService *pGetService;
hr = pOutSample->QueryInterface(__uuidof(IMFGetService), (void**)&pGetService); //这个pOutSample就是要最后要往下deliver的
3.获得IDirect3DSurface9
hr = pGetService->GetService(MR_BUFFER_SERVICE, __uuidof(IDirect3DSurface9), (void**)&pD3DSurface);
4.现在需要从pD3DSurface中获得数据,用到IDirect3DSurface的LockRect方法。
mfxStatus LockFrame(IDirect3DSurface9 *surface, mfxFrameData *ptr)
{
IDirect3DSurface9 *pSurface = surface;
if (pSurface == 0)
return MFX_ERR_INVALID_HANDLE;
if (ptr == 0)
return MFX_ERR_LOCK_MEMORY;
D3DSURFACE_DESC desc;
HRESULT hr = pSurface->GetDesc(&desc);
if (FAILED(hr))
return MFX_ERR_LOCK_MEMORY;
if (desc.Format != D3DFMT_NV12 &&
desc.Format != D3DFMT_YV12 &&
desc.Format != D3DFMT_YUY2 &&
desc.Format != D3DFMT_R8G8B8 &&
desc.Format != D3DFMT_A8R8G8B8 &&
desc.Format != D3DFMT_P8)
return MFX_ERR_LOCK_MEMORY;
D3DLOCKED_RECT locked;
hr = pSurface->LockRect(&locked, 0, D3DLOCK_NOSYSLOCK);
if (FAILED(hr))
return MFX_ERR_LOCK_MEMORY;
switch ((DWORD)desc.Format)
{
case D3DFMT_NV12:
ptr->Pitch = (mfxU16)locked.Pitch;
ptr->Y = (mfxU8 *)locked.pBits;
ptr->U = (mfxU8 *)locked.pBits + desc.Height * locked.Pitch;
ptr->V = ptr->U + 1;
break;
case D3DFMT_YV12:
ptr->Pitch = (mfxU16)locked.Pitch;
ptr->Y = (mfxU8 *)locked.pBits;
ptr->V = ptr->Y + desc.Height * locked.Pitch;
ptr->U = ptr->V + (desc.Height * locked.Pitch) / 4;
break;
case D3DFMT_YUY2:
ptr->Pitch = (mfxU16)locked.Pitch;
ptr->Y = (mfxU8 *)locked.pBits;
ptr->U = ptr->Y + 1;
ptr->V = ptr->Y + 3;
break;
case D3DFMT_R8G8B8:
ptr->Pitch = (mfxU16)locked.Pitch;
ptr->B = (mfxU8 *)locked.pBits;
ptr->G = ptr->B + 1;
ptr->R = ptr->B + 2;
break;
case D3DFMT_A8R8G8B8:
ptr->Pitch = (mfxU16)locked.Pitch;
ptr->B = (mfxU8 *)locked.pBits;
ptr->G = ptr->B + 1;
ptr->R = ptr->B + 2;
ptr->A = ptr->B + 3;
break;
case D3DFMT_P8:
ptr->Pitch = (mfxU16)locked.Pitch;
ptr->Y = (mfxU8 *)locked.pBits;
ptr->U = 0;
ptr->V = 0;
break;
}
return MFX_ERR_NONE;
}
<pre class="cpp" name="code" style="font-size: 14.039999961853px; font-weight: bold;">//数据就放到ptr中去了,然后对数据进行处理,最后unlock掉
mfxStatus CDecVideoFilter::UnlockFrame(IDirect3DSurface9 *surface, mfxFrameData *ptr){IDirect3DSurface9 *pSurface =surface;if (pSurface == 0)return MFX_ERR_INVALID_HANDLE;pSurface->UnlockRect();if (NULL != ptr){ptr->Pitch = 0;ptr->Y = 0;ptr->U = 0;ptr->V = 0;}return MFX_ERR_NONE;}
三、至此已经获取到数据了,注意对数据进行处理后,要调用unlockframe方法。
相关文章推荐
- 《转》 Openstack Grizzly 指定 compute node 创建 instance
- RTP-RTCP-RTSP协议的区别与联系
- Nginx HTTP:413 Request Entity Too Large解决方法
- memcached分布式缓存
- 面试题17:合并两个排序链表
- hdu1712 ACboy needs your help
- 建议选择专业方向对准晚辈
- javascript使用table排序
- 怎么编写自动化测试用例,如何将自动化测试用例和手工测试用例相辅相成。
- php实现的网络相册图片防盗链完美破解方法
- 实训猜猜看——进度1
- Shortest path in multistage graphs 图的最短路径问题
- CocoaPods安装和使用教程
- 逆波兰法求解数学表达示(C++)
- Linux Debian系统配置LAMP(Apache, MySQL, PHP)网站环境详解
- CTO们接着吼:创业公司几乎全是坑!
- 逆波兰法求解数学表达示(C++) 分类: C/C++ 数据结构与算法 2015-07-01 14:41 128人阅读 评论(1) 收藏
- unity5, assert
- Linux下Rsync+Inotify-tools实现数据实时同步(转)
- 表单设计器介绍以及图例介绍