以前学操作系统时学过进程与线程,然从来没有自己亲手编写过多线程的程序。最近在学习时需要用到多线程以减少执行时间,由于一直使用Qt平台,所以看了一下Qt的多线程编码发现难度不大,主要就是重写Thread的run()函数即可。
通过一个例子来说明具体过程:主线程读取视频,检测动静态,发现存在动态视频帧时就将动态视频帧保存。如果不采用多线程就会出现需要等待写完动态视频段才能继续检测剩余的视频。videoProcessor类用来完成写视频文件。
#include<QThread>
#include<QMutex>
#include <QtCore>
#include <io.h>
#include <opencv.hpp>
using namespace cv;
class videoProcessor:public QThread
{
public:
videoProcessor();
videoProcessor(string &filename);
//源文件的文件名
bool setCaptueParams(string &filename);
//设置输出文件参数,如:文件名,编码器,帧率,是否为彩色视频
bool setOutPut(string &filename, int codec = 0, double fps = 0.0, bool isColor = true);
//设置起止帧号
bool setFrameIndex(int startIndex,int endIndex);
//写视频文件
bool writeVideofile();
//获取已经写入的视频帧数
int getWritedFrameNum();
//获取视频帧大小
Size getFrameSize();
//获取帧率
double getFrameRate();
//获取编码器符号代码
int getCodec(char codec[4]);
//设置编码器
int setCodec(char codec[4]);
//是否停止处理
bool isStop();
//启动写视频器
bool startWriter();
bool closeWriter(); //关闭写视频器
void stop(); //停止写线程
~videoProcessor();
protected:
void run();<span style="white-space:pre"> </span>//启动线程
private:
cv::VideoWriter writer; //写视频器
cv::VideoCapture capture; //视频处理结构体
float fps;
bool ColorFlag;
int codecIndex;
int startFrameIndex;
int endFrameIndex;
Mat originFrame; //视频帧
string outputFileName; //设置输出视频的名称
string inputFileName; //设置原始视频的名称
int processedFrames; //已处理的视频帧数
int writedFrames; //已经写入的视频帧数
bool stopFlag; //是否停止处理
QMutex mutex;
};
为了使用Qt的多线程,将需要作为子线程实现的类作为QThread的子类,然后从写run()函数,主线程中通过start()函数启动线程(start()会自动调用run())。看看videoProcessor的run()实现:
void videoProcessor::run()
{
writeVideofile();
}
//写视频,开始帧为startFrameIndex,结束帧为endFrameIndex.成功返回true
bool videoProcessor::writeVideofile()
{
QMutexLocker locker(&mutex);
//起止位置检测
if (startFrameIndex>endFrameIndex)
{
printf("frame index out of range!\n");
stopFlag = true;
return (!stopFlag);
}
//起始位置若小于零,置为0
if (startFrameIndex < 0)
startFrameIndex = 0;
while (!isStop())
{
//为保证准确定位视频帧,对视频文件进行全解码(逐帧读取)
if (processedFrames<startFrameIndex)
{
capture >> originFrame;
if(originFrame.empty())
{
stopFlag = true;
break;
}
processedFrames++;
}
else if (processedFrames<endFrameIndex)
{
capture >> originFrame;
if(originFrame.empty())
{
stopFlag = true;
break;
}
writer.write(originFrame); //写视频
processedFrames++; //处理帧
writedFrames++; //已写入的视频帧数
}
else
{
stopFlag = true;
}
}
return (!stopFlag); //如果stopFlag为假,则说明写入成功呢,否则存在误差
}主线程中启动线程的代码为:
myVideoWriter->setFrameIndex(startFrameNum, endFrameNum);
myVideoWriter->start(); //写视频这样就可以实现多线程编码啦,主线程进行动静态检测,子线程实现写入动态视频。
附:
线程存在多种状态,可以通过thread.isFinshed(),thread.isRunning()等函数来判断。