之前已經(jīng)完成了基于opencv的ffmpeg視頻顯示框架。覺得比較好的就是畫中畫禽车。所以先做一個(gè)原型作為入門窍蓝。
設(shè)計(jì)方案
要實(shí)現(xiàn)一種功能啄刹,方法多種多樣,基于我現(xiàn)在的目的是學(xué)習(xí)FFmpeg的應(yīng)用焚辅。所以呢參考了網(wǎng)上的畫中畫實(shí)現(xiàn)方式映屋。
我要做一個(gè)多線程通過線程A完成一幀大屏幀解碼后發(fā)送消息到線程B去做一幀小屏幀解碼,小屏幀解碼后再發(fā)一幀消息同步大屏幀同蜻,然后通過opencv的ROI來合并大屏和小屏幀棚点。
遇到問題
- 如何放大縮小視頻,ffmpeg的sws_getContext雖小視頻后湾蔓,顯示有一部分黑色框瘫析。我暫時(shí)無法用ffmpeg最小視頻,所以就用opencv的resize還是來縮小默责。
- opencv的Copyto函數(shù)無效果贬循。最后網(wǎng)上查到,Copyto的大小需要和img大小一致才能copy成功桃序。
WIN32多線程框架驗(yàn)證
#include <iostream>
#include <windows.h>
using namespace std;
DWORD dwThreadID;
DWORD dwThreadID1;
#define WM_MY_MESSAGE (WM_USER+1)
#define WM_MY_MESSAGE_MERGE (WM_USER+2)
MSG msg;
//線程函數(shù)
DWORD WINAPI Fun(LPVOID lpParameter)
{
char *str = (char*)lpParameter;
int ret = 0;
for (int i = 0; i < 10; i++)
{
cout << "Displaying " << str << endl;
ret = PostThreadMessage(dwThreadID1, WM_MY_MESSAGE, 0, 0);
if (GetMessage(&msg, NULL, 0, 0))
{
if (msg.message == WM_MY_MESSAGE_MERGE)
{
cout << "Merge " <<endl;
}
}
}
return 0;
}
//線程函數(shù)
DWORD WINAPI Fun1(LPVOID lpParameter)
{
char *str = (char*)lpParameter;
for (int i = 0; i < 10; i++)
{
if (GetMessage(&msg, NULL, 0, 0))
{
if (msg.message == WM_MY_MESSAGE)
{
cout << "Displaying " << str << endl;
}
PostThreadMessage(dwThreadID, WM_MY_MESSAGE_MERGE, 0, 0);
}
}
return 0;
}
int main()
{
//使用struct傳遞參數(shù)
char Ptr[] = "123";
char Ptr1[] = "456";
HANDLE hThread1 = CreateThread(NULL, 0, Fun1, Ptr1, 0, &dwThreadID1);
WaitForSingleObject(&dwThreadID, 25);
HANDLE hThread = CreateThread(NULL, 0, Fun, Ptr, 0, &dwThreadID);
//WaitForSingleObject(hThread, INFINITE); // 等待杖虾,直到線程被激發(fā)
CloseHandle(hThread);
CloseHandle(hThread1);
while (1);
return 0;
}
關(guān)鍵合并函數(shù)
此框架驗(yàn)證消息收發(fā)正常,返回把fun和fun1替換成功之前的FFmpeg顯示函數(shù)媒熊,在對(duì)應(yīng)位置添加發(fā)送和接收消息即可奇适。
////轉(zhuǎn)換圖像格式,將解壓出來的YUV420P的圖像轉(zhuǎn)換為BRG24的圖像
if (GetMessage(&msg, NULL, 0, 0))
{
if (msg.message == WM_MY_MESSAGE_MERGE)
{
cv::Mat frameImage(cv::Size(pCodecCtx->width, pCodecCtx->height), CV_8UC3, cv::Scalar(0));
//std::cout << "pCodecCtx->width=" << pCodecCtx->width << std::endl;
//cv::Mat imageROI = frameImage(cv::Rect(0, 0, 480, 360));
frameImage.data = pFrameRGB->data[0];
cv::Mat OutImg;
cv::Mat imageROI;
cv::Mat frameTV(cv::Size(w2, h2), CV_8UC3, cv::Scalar(0));
//std::cout << "w2=" << w2 << std::endl;
frameTV.data = (uchar *)msg.wParam;
if (msg.wParam != NULL)
{
cv::resize(frameTV, OutImg, cv::Size(480, 360), 0, 0, cv::INTER_LINEAR);
cv::Mat imageROI = frameImage(cv::Rect(0, 0, OutImg.cols, OutImg.rows));
OutImg.copyTo(imageROI);
//OutImg.release();
}
if (pFrameRGB->data[0] != NULL)
{
cv::namedWindow("Video", CV_WINDOW_AUTOSIZE);
cv::imshow("Video", frameImage);
cv::waitKey(33);
}
frameImage.release();
imageROI.release();
frameTV.release();
OutImg.release();
}
}