视频解码器和render之间增加一个内容透传的filter,需要处理颜色空间的差异及显卡内存自动对齐问题

本人初学directshow,想做一个简单的transform filter,功能就是把输入数据拷贝到输出数据上,传给下一个filter;

所以主要就是在transform(IMediaSample *pIn, IMediaSample *pOut)中用了Copy(pIn,pOut)函数,这个函数也是在SDK的Contrast例子中找到的,感觉这个函数就是把pIn数据拷贝给了pOut(通过CopyMemory((PVOID) pDestBuffer,(PVOID) pSourceBuffer,lSourceSize); )

但是对得到的filter在graphedit中进行测试发现,如果连接在splitter和解码器之间,那么视频可以正常输出;但如果连接在解码器和render中间,那么输出的视频是一段段条纹,但还是随着时间在变化,说明数据应该传对了,但不知什么原因render时有所差错

恳请各位大侠指教!
 
 
#1楼 得分:20回复于:2010-07-26 15:18:48
video render为了内存对齐会自动调节宽度的,你要取得正在运行的媒体类型,然后一行一行的拷贝过去,output调整宽度多余的地方就不赋值了。
在传第一帧数据的时候取一下output的实际宽度:
C/C++ code
            
            
AM_MEDIA_TYPE * pmt = NULL; HRESULT hr = pOutSample -> GetMediaType( & pmt); if (SUCCEEDED(hr) && pmt) { if (pmt -> formattype == FORMAT_VideoInfo) { VIDEOINFOHEADER * hrIn = (VIDEOINFOHEADER * )pmt -> pbFormat; m_nWidthOutRender = hrIn -> bmiHeader.biWidth; } else if (pmt -> formattype == FORMAT_VideoInfo2) { VIDEOINFOHEADER2 * hrIn = (VIDEOINFOHEADER2 * )pmt -> pbFormat; m_nWidthOutRender = hrIn -> bmiHeader.biWidth; } DeleteMediaType(pmt); }
 
#2楼 得分:0回复于:2010-07-26 16:00:28
感谢楼上解答!
不过因为我对于directshow框架还不是很熟,所以想问下传第一帧数据是在什么地方,或者说上面的代码应该放在哪个函数中?
因为刚才测试了一下,发现放在transform函数中不行,因为pmt->formattype会发生访问冲突;
那请问能放在CheckTransform(const CMediaType *mtIn,const CMediaType *mtOut)中,利用mtOut来获得output的实际宽度吗?
 
  • rageliu用户头像
  • rageliu
  • (天气好了就去长白山看水怪)
  • 等 级:
#3楼 得分:0回复于:2010-07-27 10:07:39
应该是格式改变没处理吧,不过就算是这样,你是直接全块一起copy的,也不应该会花啊
 
#4楼 得分:5回复于:2010-07-27 10:20:00
就在transform函数开头里面写啊,怎么访问冲突了?或者在receive里面处理,不用transform函数。
你还要看一下你的图像subtype是什么类型的,通常有RGB24,YUY2,YV12等,你要对他们的数据结构有一定的了解,才能一行一行的正确拷贝。
C/C++ code
            
            
HRESULT CVideoProcessor::Receive(IMediaSample * pSample) { BYTE * pData = NULL; HRESULT hr = pSample -> GetPointer( & pData); if (FAILED(hr)) { return hr; } AM_MEDIA_TYPE * pmt = NULL; hr = pSample -> GetMediaType( & pmt); if (SUCCEEDED(hr) && pmt) { // 原始尺寸可能有改变,需要通知后面动态重连 // ... DeleteMediaType(pmt); } long lLength = pSample -> GetActualDataLength(); REFERENCE_TIME rtStart = 0 , rtStop = 0 ; hr = pSample -> GetTime( & rtStart, & rtStop); IMediaSample * pOutSample = NULL; hr = m_pOutput -> GetDeliveryBuffer( & pOutSample, NULL, NULL, 0 ); if (FAILED(hr)) { return hr; } BYTE * pOutData = NULL; hr = pOutSample -> GetPointer( & pOutData); if (FAILED(hr)) { pOutSample -> Release(); return hr; } pmt = NULL; hr = pOutSample -> GetMediaType( & pmt); if (SUCCEEDED(hr) && pmt) { if (pmt -> formattype == FORMAT_VideoInfo) { VIDEOINFOHEADER * hrIn = (VIDEOINFOHEADER * )pmt -> pbFormat; m_nWidthOutRender = hrIn -> bmiHeader.biWidth; } else if (pmt -> formattype == FORMAT_VideoInfo2) { VIDEOINFOHEADER2 * hrIn = (VIDEOINFOHEADER2 * )pmt -> pbFormat; m_nWidthOutRender = hrIn -> bmiHeader.biWidth; } DeleteMediaType(pmt); } long lOutLen = Process(pData, pOutData); pOutSample -> SetActualDataLength(lOutLen); pOutSample -> SetTime( & rtStart, & rtStop); pOutSample -> SetSyncPoint(pSample -> IsSyncPoint() == S_OK ? TRUE : FALSE); pOutSample -> SetDiscontinuity(pSample -> IsDiscontinuity() == S_OK ? TRUE : FALSE); pOutSample -> SetPreroll(pSample -> IsPreroll() == S_OK ? TRUE : FALSE); m_pOutput -> Deliver(pOutSample); pOutSample -> Release(); return S_OK; }
 
#5楼 得分:0回复于:2010-07-28 11:21:14
看来是我弄错了,今天又试了试,把上面的代码放到transform函数中已经通过了,并且我查到图像的subtype是NV12这种类型,请问楼上能再给个如何一行行拷贝数据的示例吗?
感激不尽~~
 
#6楼 得分:15回复于:2010-07-28 11:45:31
给你一个YV12的代码,其他的要自己写了:
C/C++ code
            
            
if (nWidth == nWidthRender) { memcpy(pOutData, pData, lOutLen); } else { for ( int i = 0 ; i < nHeight; i ++ ) { memcpy(pOutData, pData, nWidth); pData += nWidth; pOutData += nWidthRender; } for ( int i = 0 ; i < (nHeight >> 1 ) * 2 ; i ++ ) { memcpy(pOutData, pData, nWidth >> 1 ); pData += nWidth >> 1 ; pOutData += nWidthRender >> 1 ; } }
 
#7楼 得分:0回复于:2010-07-28 12:01:42
感谢,下午就试试
 
#8楼 得分:0回复于:2010-07-28 15:08:54
按照上述过程,我在graphedit上播放一段视频,结果已经得到了一副完整的图像,但不知道为什么,结果只停留在这一张图像上,然后不停闪烁,后面的内容都播不出来,求解答!!!
 
#9楼 得分:0回复于:2010-07-28 16:11:04
问题已解决,原来是我重复在transform中取图像的宽度和高度了,实际上只要第一次获得后保存下来就可以了
这样已经获得了可以播放的视频,但颜色略有不对,而且视频中间有一道竖的灰杠,下面继续检查中
 
  • rageliu用户头像
  • rageliu
  • (天气好了就去长白山看水怪)
  • 等 级:
#10楼 得分:0回复于:2010-07-28 18:44:52
而且视频中间有一道竖的灰杠

显然是yuv格式,一样是对齐的问题
 
#11楼 得分:0回复于:2010-07-28 18:49:02
问题终于解决了,最后的问题是因为YV12和NV12格式的差别,实际上的拷贝代码改为这样既可:[code=C/C++][/code]
for(int i = 0; i < m_nHeight; i++)
  {
  CopyMemory((PVOID) pDestBuffer,(PVOID) pSourceBuffer,m_nWidth);
  pSourceBuffer += m_nWidth;
  pDestBuffer += m_nWidthOutRender;
  }

  for(int i = 0; i < m_nHeight/2 ; i++)
  {
  CopyMemory((PVOID) pDestBuffer,(PVOID) pSourceBuffer,m_nWidth );
  pSourceBuffer += m_nWidth ;
  pDestBuffer += m_nWidthOutRender ;
  }
在此感谢tufaqing大侠的热心解答,结贴喽!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值