ffmpeg+opencv

用ffmpeg解码,并且将解码后的视频传入opencv。通过查找相关资料进行快速学习实现了这个需求。现进行简单的记录和分享。

ffmpeg 解码函数:len = avcodec_decode_video2(pInputCodecContext, dst, &nComplete, &InPack);     dst 为 AVFrame *dst,存放了解码后的数据。解码后存入dst的视频是yuv420格式。dst->data[0],dst->data[1],dst->data[2] 中分别存了 yuv的数据。dst->width*dst->height 是原始视频的分辨率。

opencv 结构体 Mat frame, frame=frame.create(dst->height*1.5, dst->width, CV_8UC1);  用frame存储 yuv420 的数据, yuv 需要申请的内存大小为dst->width*dst->height *1.5

memcpy(frame.data,dst->data[0], dst->width*dst->height);  存入 y
memcpy(frame.data+640*480,dst->data[1], dst->width*dst->height/4);   存入 u
memcpy(frame.data+640*480*5/4,dst->data[2], dst->width*dst->height/4);  存入 v

这样解码后的yuv420 数据就存入了opencv中。可添加

cv::cvtColor(frame, rgbImg,CV_YUV2BGR_I420);  //yuv转成rgb
if(frame.empty())break;
imshow("frame",rgbImg);

waitKey(1); 显示解码后的视频


//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------//

 需求:把两路视频合成一路,即一个画面同时显示两路视频,其中一路缩小成小视频叠在大视频上面,和电视机的画中画效果类似。

思路:用h264编码的视频举例,文件中存储的es流是h264,经过解码成yuv,yuv可以转换成rgb格式。把小视频的rgb复制到大视频需要被覆盖的位置上。将重新合成的rgb转换成yuv,利用ffmpeg 或 x264重新编码出新的视频即可。

方法:编解码还是利用ffmpeg 。 ffmpeg 解码两路视频,解码后都是yuv。利用ffmpeg· 的sws_getContext 函数改变小图的大小。之后利用opencv完成两个图片的合成(opencv这种高大上的库被我用成了这样····实在汗颜。其实此处的合并rgb可以自己写算法实现,本质是把小图的rgb复制到大图的对应位置上。)合成好后将rbg转成yuv格式,利用x264重新编码成h264 ,就看到了大视频左上角有个小视频了。

代码思路:

两个线程,各自解码,主视频的线程解码一帧后通知副视频的线程进行解码并转化图片大小,副视频的线程解码完成后通知主线程合成视频并编码。合成视频的时候用opencv很简单,直接把yuv转化成rgb,之后在主视频上设置敏感区,把小视频叠加上就行。

主副线程解码套路一样,ffmpeg的基本使用套路。把yuv转成opencv mat类型的rgb套路也一样,上副视频解码线程的代码进行说明。

全局变量:

  1. cv::Mat littlergb,bigrgb;//大小视频的rgb  
  2. cv::Mat littleframe,bigframe;//大小视频的yuv  

副视频解码线程内的代码:

  1. while(av_read_frame(pInputFormatContext, &InPack) >=0)  
  2.     {  
  3.         len = avcodec_decode_video2(pInputCodecContext, &OutFrame, &nComplete, &InPack);//解码视频  
  4.         if (nComplete>0)  
  5.         {     
  6.             if (GetMessage(&msg, NULL, 0, 0))  
  7.             {  
  8.                 switch(msg.message)  
  9.                 {  
  10.                 case MY_MSG_DECODE:  
  11.                     sws_scale(m_pSwsContext,OutFrame.data,OutFrame.linesize, 0,OutFrame.height,dst->data,dst->linesize);//转换图片大小  
  12.   
  13.                     memcpy(littleframe.data,dst->data[0], 640*480);  //以下将ffmpeg的yuv数据存到opencv的mat类型中。即opencv存储的yuv数据  
  14.                     memcpy(littleframe.data+640*480,dst->data[1], 640*480/4);    
  15.                     memcpy(littleframe.data+640*480*5/4,dst->data[2], 640*480/4);   
  16.                     SetEvent(hEncodeEvent);  
  17.   
  18.                     break;  
  19.                 }  
  20.             }  
  21.   
  22.         }  
  23.         av_free_packet(&InPack);  
  24.     }  

合并图片直接用opencv,代码如下:

  1. cv::cvtColor(littleframe, littlergb,CV_YUV2BGR_I420);   
  2. cv::cvtColor(bigframe, bigrgb,CV_YUV2BGR_I420); //以上yuv转rgb  
  3. Mat roi(bigrgb,Rect(0,0,640,480));//大图上设置敏感区  
  4. littlergb.copyTo(roi);  //把小图拷贝过去  
  5. Mat outframe;  
  6. cv::cvtColor(bigrgb, outframe,CV_BGR2YUV_I420); //rgb到yuv  


这样就获得了合并后的图片的yuv。

之后进行编码即可。编码出来的视频就是画中画了。


  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
敬告:该系列的课程在抓紧录制更新中,敬请大家关注。敬告: 该系列的课程涉及:FFmpeg,WebRTC,SRS,Nginx,Darwin,Live555,OpenCV,等。包括:音视频、流媒体、直播、Android、视频监控28181、等。 我将带领大家一起来学习OpenCV4的图像处理原理和编程知识,并动手操练58案例代码。具体内容包括: 一、小白入门与初体验:禁果尝鲜二、图像基本操作:懵懵懂懂学图像三、图像统计操作:七七八八有收获四、图像卷积:不入虎穴焉得虎子五、磨皮美颜:柳暗花明又一村六、二值图像:阴阳合一法自然七、图像形态学:登高望远天地阔 音视频与流媒体是一门很复杂的技术,涉及的概念、原理、理论非常多,很多初学者不学 基础理论,而是直接做项目,往往会看到c/c++的代码时一头雾水,不知道代码到底是什么意思,这是为什么呢? 因为没有学习音视频和流媒体的基础理论,就比如学习英语,不学习基本单词,而是天天听英语新闻,总也听不懂。所以呢,一定要认真学习基础理论,然后再学习播放器、转码器、非编、流媒体直播、视频监控、等等。 梅老师从事音视频与流媒体行业18年;曾在永新视博、中科大洋、百度、美国Harris广播事业部等公司就职,经验丰富;曾亲手主导广电直播全套项目,精通h.264/h.265/aac,曾亲自参与百度app上的网页播放器等实战产品。目前全身心自主创业,主要聚焦音视频+流媒体行业,精通音视频加密、流媒体在线转码快编等热门产品。     

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值