之前已经完成了基于opencv的ffmpeg视频显示框架。觉得比较好的就是画中画。所以先做一个原型作为入门。
设计方案
要实现一种功能,方法多种多样,基于我现在的目的是学习FFmpeg的应用。所以呢参考了网上的画中画实现方式。
我要做一个多线程通过线程A完成一帧大屏帧解码后发送消息到线程B去做一帧小屏帧解码,小屏帧解码后再发一帧消息同步大屏帧,然后通过opencv的ROI来合并大屏和小屏帧。
遇到问题
- 如何放大缩小视频,ffmpeg的sws_getContext虽小视频后,显示有一部分黑色框。我暂时无法用ffmpeg最小视频,所以就用opencv的resize还是来缩小。
- opencv的Copyto函数无效果。最后网上查到,Copyto的大小需要和img大小一致才能copy成功。
WIN32多线程框架验证
#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;
//线程函数
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;
}
//线程函数
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传递参数
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); // 等待,直到线程被激发
CloseHandle(hThread);
CloseHandle(hThread1);
while (1);
return 0;
}
关键合并函数
此框架验证消息收发正常,返回把fun和fun1替换成功之前的FFmpeg显示函数,在对应位置添加发送和接收消息即可。
////转换图像格式,将解压出来的YUV420P的图像转换为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();
}
}
网友评论