利用ffmpeg+opencv實現畫中畫

轉自:http://blog.csdn.net/dzhuang123/article/details/45054497


需求:把兩路視頻合成一路,即一個畫面同時顯示兩路視頻,其中一路縮小成小視頻疊在大視頻上面,和電視機的畫中畫效果類似。

思路:用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套路也一樣,上副視頻解碼線程的代碼進行說明。

全局變量:

[cpp] view plain copy
  1. cv::Mat littlergb,bigrgb;//大小視頻的rgb  
  2. cv::Mat littleframe,bigframe;//大小視頻的yuv  

副視頻解碼線程內的代碼:

[cpp] view plain copy
  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,代碼如下:

[cpp] view plain copy
  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。

之後進行編碼即可。編碼出來的視頻就是畫中畫了。

點擊打開鏈接  (樓主源碼鏈接失效了)

這個代碼,缺了dll和lib還有頭文件,空間不夠傳不上····

發佈了28 篇原創文章 · 獲贊 7 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章