代码运行环境:
ubuntu16.04,QtCreator,Opencv3.4.10
其中一个线程用来获取视频流,一个线程用来显示,其余用于对视频帧的处理。
#include <thread>
#include <mutex>
#include <unistd.h>
#include <sys/time.h>
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
int idxInputImage=0; //image index of input video
int idxShowImage=0; //next frame index to be display
bool bReading=true; //flag of input
typedef std::pair<int,cv::Mat> imagePair;
class pairComp{
public:
bool operator()(const imagePair&n1,const imagePair&n2) const{
if(n1.first==n2.first) return n1.first>n2.first;
return n1.first>n2.first;
}
};
std::mutex mtxQueueInput; //mutex of input queue
std::mutex mtxQueueShow; //mutex of output queue
std::queue<std::pair<int,cv::Mat> > queueInput;
std::priority_queue<imagePair,std::vector<imagePair>,pairComp> queueShow;
double what_time_is_it_now()
{
struct timeval time;
if (gettimeofday(&time,NULL)){
return 0;
}
return (double)time.tv_sec + (double)time.tv_usec * .000001;
}
void videoCapture(const char* videoDir)
{
cpu_set_t mask;
int cpuid = 2;
CPU_ZERO(&mask);
CPU_SET(cpuid, &mask);
if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) < 0){
std::cerr << "set thread affinity failed" <<std::endl;
}
printf("Bind VideoCapture process to CPU %d\n", cpuid);
// std::string videoDir="rtsp://admin:yltx8888@192.168.37.210:554/h264/ch1/main/av_stream";
cv::VideoCapture cap;
cap.open(videoDir);
if(!cap.isOpened()){
printf("the video can't open succ!");
return ;
}
while(true){
usleep(1000);
cv::Mat img;
cap>>img;
if(img.empty()){
std::cerr<<"Fail to read image from rtsp"<<std::endl;
break;
}
mtxQueueInput.lock();
queueInput.push(std::make_pair(idxInputImage++,img));
if(queueInput.size()>=30){
mtxQueueInput.unlock();
std::cout<<"[Warning] input queue size is "<<queueInput.size()<<std::endl;
sleep(1);
}
else {
mtxQueueInput.unlock();
}
if(bReading){
continue;
}
else{
cap.release();
break;
}
}
}
void run_process(int thread_id)
{
cpu_set_t mask;
int cpuid = 0;
//int ret = 0;
if (thread_id == 0){
cpuid = 4;
}
else if (thread_id == 1){
cpuid = 5;
}
else if(thread_id==2){
cpuid=6;
}
else{
cpuid = 0;
}
CPU_ZERO(&mask);
CPU_SET(cpuid, &mask);
if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) < 0){
std::cerr << "set thread affinity failed" << std::endl;
}
printf("Bind run_process(%d) to CPU %d\n", thread_id, cpuid);
while(true){
std::pair<int,cv::Mat>pairIndexImage;
mtxQueueInput.lock();
if(queueInput.empty()){
mtxQueueInput.unlock();
usleep(1000);
if(bReading){
continue;
}else{
break;
}
}
else{
pairIndexImage=queueInput.front();
queueInput.pop();
mtxQueueInput.unlock();
}
cv::resize(pairIndexImage.second,pairIndexImage.second,cv::Size(640,360));
cv::cvtColor(pairIndexImage.second,pairIndexImage.second,cv::COLOR_BGR2GRAY);
cv::Canny(pairIndexImage.second,pairIndexImage.second,30,150,3);
mtxQueueShow.lock();
queueShow.push(pairIndexImage);
mtxQueueShow.unlock();
}
}
void displayImage()
{
cpu_set_t mask;
int cpuid = 3;
CPU_ZERO(&mask);
CPU_SET(cpuid, &mask);
if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) < 0){
std::cerr << "set thread affinity failed" << std::endl;
}
printf("Bind Display process to CPU %d\n", cpuid);
cv::Mat img;
int fps;
double firstTime,lastTime;
firstTime=what_time_is_it_now();
while(true){
mtxQueueShow.lock();
if(queueShow.empty()){
mtxQueueShow.unlock();
usleep(1000);
}
else if(idxShowImage==queueShow.top().first){
cv::Mat img=queueShow.top().second;
std::string a=std::to_string(fps)+"FPS";
cv::putText(img,a,cv::Point(15,15),1,1,cv::Scalar{0,0,255},2);
cv::imshow("Test",img);
idxShowImage++;
queueShow.pop();
mtxQueueShow.unlock();
if(cv::waitKey(1)==27){
cv::destroyAllWindows();
bReading=false;
break;
}
lastTime=what_time_is_it_now();
fps=(int) 1/(lastTime-firstTime);
firstTime=what_time_is_it_now();
}else{
mtxQueueShow.unlock();
}
}
}
int main()
{
const char* rtsp="/home/images/test.avi";
std::array<std::thread,5> threads;
threads={std::thread(videoCapture,rtsp),
std::thread(run_process,0),
std::thread(run_process,1),
std::thread(run_process,2),
std::thread(displayImage)
};
for(int i=0;i<5;i++){
threads[i].join();
}
return 0;
}