Ubuntu驱动USB采集卡(四)

用到了多线程、信号量、互斥量。给原始数据开辟了10帧缓冲区,循环使用。

主线程初始化变量,然后启动三个子线程,后面什么也不做,线程退出时的清理工作也没有,所以这只是功能测试版本。

  1 #include <iostream>
  2 #include <opencv2/opencv.hpp>
  3 #include <cstdio>
  4 #include <pthread.h>
  5 #include <semaphore.h>
  6 
  7 const int BufBlock = 829440;
  8 const int BufSize = 5;
  9 unsigned char **buf = NULL;
 10 unsigned int wbuf = 0;
 11 unsigned int rbuf = 0;
 12 pthread_mutex_t mutex_buf[BufSize], mutex_show;
 13 sem_t sem_buf;
 14 
 15 cv::Mat yuv(576, 720, CV_8UC3, cv::Scalar(0));
 16 cv::Mat frame(576, 720, CV_8UC3, cv::Scalar(0));
 17 int counter;
 18 char title[10];
 19 
 20 cv::VideoWriter videofile;
 21 
 22 void* capture(void* parameter) {
 23     while (true) {
 24         pthread_mutex_lock(mutex_buf + (wbuf % BufSize));
 25 
 26         unsigned char *data = buf[wbuf % BufSize];
 27         for (int i = 0; i < BufBlock; ++i) {
 28             data[i] = getchar();
 29         }
 30 
 31         pthread_mutex_unlock(mutex_buf + (wbuf % BufSize));
 32 
 33         sem_post(&sem_buf);
 34 
 35         ++wbuf;
 36     }
 37 }
 38 
 39 void* record(void* parameter) {
 40     while (true) {
 41         sem_wait(&sem_buf);
 42 
 43         int cur = 0;
 44         sem_getvalue(&sem_buf, &cur);
 45         std::cout << "Current buffer: " << cur << ", wbuf = " << wbuf << ", rbuf = " << rbuf << std::endl;
 46 
 47         pthread_mutex_lock(mutex_buf + (rbuf % BufSize));
 48 
 49         sprintf(title, "%d", ++counter);
 50         unsigned char *data = buf[rbuf % BufSize];
 51 
 52         int row = 0;
 53         int col = 0;
 54         for (int i = 0; i < BufBlock; i = i + 4) {
 55             yuv.at<cv::Vec3b>(row, col) = cv::Vec3b(data[i + 1], data[i], data[i + 2]);  /// Y1, U1, V1
 56             yuv.at<cv::Vec3b>(row, col + 1) = cv::Vec3b(data[i + 3], data[i], data[i + 2]);  /// Y2, U2=U1, V2=V1
 57 
 58             col = col + 2;
 59             if (col >= 720) {
 60                 col = 0;
 61                 row = row + 1;
 62             }
 63         }
 64 
 65         pthread_mutex_unlock(mutex_buf + (rbuf % BufSize));
 66 
 67         pthread_mutex_lock(&mutex_show);
 68         cv::cvtColor(yuv, frame, CV_YUV2BGR);
 69         cv::putText(frame, title, cv::Point(0, 50), cv::FONT_HERSHEY_SIMPLEX, 1.0, cv::Scalar(255, 255 ,0));
 70         pthread_mutex_unlock(&mutex_show);
 71         videofile << frame;
 72 
 73         ++rbuf;
 74     }
 75 }
 76 
 77 void* show(void* parameter) {
 78     while (true) {
 79         pthread_mutex_lock(&mutex_show);
 80         cv::imshow("frame", frame);
 81         pthread_mutex_unlock(&mutex_show);
 82         cv::waitKey(40);
 83     }
 84 }
 85 
 86 int main(int argc, char **argv) {
 87     buf = new unsigned char * [BufSize];
 88     for (int i = 0; i < BufSize; ++i) {
 89         buf[i] = new unsigned char [BufBlock];
 90     }
 91     sem_init(&sem_buf, 0, 0);
 92     pthread_t captureid, recordid, showid;
 93     counter = 0;
 94 
 95     /// 'D', 'I', 'V', 'X'
 96     /// 'F', 'M', 'P', '4'
 97     videofile = cv::VideoWriter("test.avi", CV_FOURCC('F', 'M', 'P', '4'), 25.0, cv::Size(720, 576));
 98 
 99     int status = pthread_create(&captureid, NULL, capture, NULL);
100     if (status != 0) {
101         std::cerr << "不能创建capture线程: " << strerror(status);
102         return 0;
103     }
104 
105     status = pthread_create(&recordid, NULL, record, NULL);
106     if (status != 0) {
107         std::cerr << "不能创建record线程: " << strerror(status);
108         return 0;
109     }
110 
111     status = pthread_create(&showid, NULL, show, NULL);
112     if (status != 0) {
113         std::cerr << "不能创建show线程: " << strerror(status);
114         return 0;
115     }
116 
117     pthread_join(recordid, (void **)0);
118     pthread_join(captureid, (void **)0);
119     pthread_join(showid, (void **)0);
120 
121     return 0;
122 }

功能基本实现,但是发现画面”破损“很严重。