2015-12-26 4 views
2

В моем коде я хочу запускать Videocapture в отдельном pthread непрерывно, в то время как основной поток будет действовать как socket server для связи с любым клиентом (или наоборот).Как запустить OpenCV Videocapture в отдельном потоке posix в C++ для кросс-платформенной?

Когда client подключается к server, то server немедленно отправить последнюю Videocapture кадр клиенту и закрыть соединение и снова ждать другого соединения.

Я в настоящее время использую OpenCV 2.3.0 в mingw32 условиях.

Посмотрев некоторые возможные решения на StackOverflow, я пытался следовать им, но, тем не менее, возможно, я помещаю OpenCV variables либо locally или globally или swapping the threads т.е. сохраняя Videocapture нить в main thread или in the 2nd thread, программа просто висит молча на mutex locked area из поток VideoCapture при подключении клиента.

Я полагаю, что это происходит, когда нить server начинает запирать mutex после подключения к клиенту.

Любое обоснование или Возможное решение будет высоко оценено. Кроме того, я использую prebuilt OpenCV версии 2.3.0, и мне нужен код для кросс-платформы. В любом случае, если он указывает на ошибку, я, очевидно, могу перейти к другой версии.


Серверный код

mynet.h

#ifndef __MYNET__ 
#define __MYNET__ 
#ifdef _WIN32 
#ifndef _WIN32_WINNT 
#define _WIN32_WINNT 0x0501 /* Windows XP. */ 
#endif 
#include <winsock2.h> 
#include <Ws2tcpip.h> 
#else 
/* Assume that any non-Windows platform uses POSIX-style sockets instead. */ 
#include <sys/socket.h> 
#include <arpa/inet.h> 
#include <netdb.h> /* Needed for getaddrinfo() and freeaddrinfo() */ 
#include <unistd.h> /* Needed for close() */ 
#endif 

int sockInit(void) 
{ 
#ifdef _WIN32 
    WSADATA wsa_data; 
    return WSAStartup(MAKEWORD(1,1), &wsa_data); 
#else 
    return 0; 
#endif 
} 

int sockQuit(void) 
{ 
#ifdef _WIN32 
    return WSACleanup(); 
#else 
    return 0; 
#endif 
} 

/* Note: For POSIX, typedef SOCKET as an int. */ 
#ifndef _WIN32 
typedef int SOCKET; 
#else 
typedef unsigned int SOCKET; 
#endif 

int sockClose(SOCKET sock) 
{ 
    int status = 0; 
#ifdef _WIN32 
    status = shutdown(sock, SD_BOTH); 
    if (status == 0) { status = closesocket(sock); } 
#else 
    status = shutdown(sock, SHUT_RDWR); 
    if (status == 0) { status = close(sock); } 
#endif 
    return status; 
} 


#if(defined(_WIN32) || defined(WIN32)) 
#include <windows.h> 
#define mysleep(x) Sleep((x)) 
#else 
#include <unistd.h> 
#define mysleep(x) usleep((x)*1000) 
#endif 

#endif 

netserver.cpp

#define _GLIBCXX_USE_CXX11_ABI 0 
#undef _GLIBCXX_DEBUG 
#include "../mynet.h" 
#include <stdio.h> 
#include <stdlib.h> 
#include <errno.h> 
#include <string.h> 
#include <sys/types.h> 
#include <opencv/cv.h> 
#include <opencv/highgui.h> 
#include <pthread.h> 

using namespace cv; 
Mat frame(120, 160, CV_8UC3);; 
pthread_mutex_t mutex; 
pthread_t thread; 

void *myfunc(void *threadid) 
{ 
    int n; 
    int listenfd = 0,connfd = 0; 
    struct sockaddr_in serv_addr; 
    unsigned char sendBuff[160*120*3]; 
    Mat hereframe; 

    listenfd = socket(AF_INET, SOCK_STREAM, 0); 
    printf("socket retrieve success\n"); 

    memset(&serv_addr, '0', sizeof(serv_addr)); 
    memset(sendBuff, '0', sizeof(sendBuff)); 

    serv_addr.sin_family = AF_INET; 
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); 
    serv_addr.sin_port = htons(5000); 
    bind(listenfd, (struct sockaddr*)&serv_addr,sizeof(serv_addr)); 
    if(listen(listenfd, 10) == -1) 
    { 
     printf("Failed to listen\n"); 
    } 
    else 
    { 
     connfd = accept(listenfd, (struct sockaddr*)NULL,NULL); // accept awaiting request 
     if(connfd<=0) printf("Something went wrong with write()! %s\n", strerror(errno)); 
     else 
     { 
      while(1) 
      { 
       printf("Got client...\n"); 
       pthread_mutex_lock (&mutex); 
       printf("Copying data...\n"); 
       frame.copyTo(hereframe); 
       pthread_mutex_unlock (&mutex); 
       printf("Hereframe size: %dX%d\n", hereframe.rows, hereframe.cols); 
       memcpy(sendBuff, hereframe.data, 120*160*3); 
       printf("Sending data...\n"); 
       n = send(connfd, (char*)sendBuff, 120*160*3,0); 
       if(n<0) printf("Something went wrong with write()! %s\n", strerror(errno)); 
       printf("Closing client after writing %d bytes...\n", n); 
       printf("Closed...\n"); 
       mysleep(40); 
       printf("Restartng data...\n"); 
      } 
      sockClose(connfd); 
     } 
    } 
    sockQuit(); 

    pthread_exit(NULL); 
} 

int main(void) 
{ 
    //cvNamedWindow("Sisplay", CV_WINDOW_AUTOSIZE); 
    sockInit(); 
    pthread_mutex_init(&mutex,NULL); 
    VideoCapture cap; 
    Mat hereframe1; 
    cap.open(0); 
    cap.set(CV_CAP_PROP_FRAME_WIDTH, 160); 
    cap.set(CV_CAP_PROP_FRAME_HEIGHT, 120); 

    if(!cap.isOpened()) printf("Fukced up\n"); 
    int rc; 
    long t; 
    rc = pthread_create(&thread, NULL, myfunc, (void *)t); 
    if (rc) 
    { 
     printf("ERROR; return code from pthread_create() is %d\n", rc); 
     exit(-1); 
    } 

    for(;;) 
    { 
     cap >> hereframe1; 
     //  printf("Video size: %dX%d\n", hereframe1.rows, hereframe1.cols); 

     pthread_mutex_lock(&mutex); 
     hereframe1.copyTo(frame); /* hangs here*/ 
     pthread_mutex_unlock(&mutex); 
     // cvtColor(frame, gray, CV_BGR2GRAY); 

     Scalar tempVal = mean(hereframe1); 
     // printf("Mean = %f\n", tempVal.val[0]); 
     mysleep(30); 
     //if(waitKey(30)=='q') break; 
     // std::swap(prevgray, gray); 
    } 
    char *b; 
    pthread_join(thread,(void**)&b); 
    return 0; 
} 

Клиентский код

receiver.cpp

#define _GLIBCXX_USE_CXX11_ABI 0 
#include "../mynet.h" 
#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <errno.h> 
#include <opencv/cv.h> 
#include <opencv/highgui.h> 

using namespace cv; 

int main(int argc, char *argv[]) 
{ 
    int sockfd = 0,n = 0; 
    unsigned char recvBuff[120*160*3]; 
    struct sockaddr_in serv_addr; 
    sockInit(); 
    memset(recvBuff, '0',sizeof(recvBuff)); 
    if((sockfd = socket(AF_INET, SOCK_STREAM, 0))< 0) 
    { 
     printf("\n Error : Could not create socket \n"); 
     return 1; 
    } 

    serv_addr.sin_family = AF_INET; 
    serv_addr.sin_port = htons(5000); 
    serv_addr.sin_addr.s_addr = inet_addr(argv[1]); 

    if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))<0) 
    { 
     printf("\n Error : Connect Failed \n"); 
     return 1; 
    } 
    printf("Connected to server...\n"); 
    Mat frame(120, 160, CV_8UC3); 
    int csz = 0; 
    cvNamedWindow("Display", CV_WINDOW_AUTOSIZE); 
    printf("OK here 0\n"); 
    for(;;) 
    { 
     csz = 0; 
     while((n = recv(sockfd, (char*)recvBuff, sizeof(recvBuff), 0)) > 0) 
     { 
      printf("OK here 2\n"); 

      printf("Read %d bytes...\n", n); 
      csz += n; 
      if(csz<=120*160*3) 
      { 
       memcpy(frame.data+(csz-n), recvBuff, n); 
      } 
      if(csz>= 120*160*3) break; 
     } 
     printf("OK here 3\n"); 

     printf("Got data of size %d bytes...\n", csz); 
     imshow("Display", frame); 
     if(csz < 120*160*3) 
     { 
      printf("\n Read Error \n"); 
     } 
     if(waitKey(30)=='q') break; 
     // std::swap(prevgray, gray); 
    } 
    sockClose(sockfd); 

    sockQuit(); 
    return 0; 
} 
+0

Что такое VideoCapture 'cap.open (-1);' Я тоже изучаю OpenCV, но вещь '-1' меня озадачивает. Я знаю, что такое« 0, 1, 2 ... », но что означает '-1'? Кроме того, почему кадр установлен в «Матовый кадр (120, 160, CV_8UC3);»? Почему бы не просто «Матовый кадр»? – zipzit

+0

@zipzit: Nevermind, это должно быть 0. Я исправил. Я установил размер 'frame' раньше, потому что после многообмена и изменения переменных во время моей отладки, когда-то это происходило до того, как перед запуском Videocapture клиент подключился. В этом случае серверный поток не может копировать необработанные данные 'frame' с размером' 120x160x3' байт в области блокировки мьютекса без предварительного определения размера. –

+0

Мне интересно, что такое глобальная переменная 'frame' ... Я думал, что вы назвали ее полезной для перечислений и констант .. но не столько для активной переменной. Для этого нужен глобальный оператор области ((:) :)? – zipzit

ответ

2

То, что я считаю, что функции OpenCV 2.3.0 не поточно-. например функции, такие как Mat :: clone(), Mat :: copyTo и т. д. (необходимо уточнить).

Итак, вместо использования этих OpenCV functions в mutex locked regions и OpenCV variables в целом используется в нескольких потоках, я просто использую базовые функции C++ и необработанные буферы.

Использование OpenCV functions в mutex locked regions и OpenCV variables в целом относится к нескольким темам, кажется, не совсем дружелюбны.

Итак, я сделал изменения в потоке сервера как

pthread_mutex_lock (&mutex); 
//printf("Copying data...\n"); 
memcpy(sendBuff, frame.data, 120*160*3); 
//frame.copyTo(hereframe); buggy here removed 
pthread_mutex_unlock (&mutex); 

и теперь его работает, как ожидалось. Uffh! Теперь мне нужно очистить весь беспорядок в моем коде.

Фактически, я также заменю переменную OpenCV frame на простой буфер unsigned char для совместного использования.

+0

Я еще не пробовал OpenCV в многопоточном приложении. Спасибо, что поделились открытием. (Примечание: была ли ссылка для этого «небезобезопасного» поведения, или это был вычет, основанный на множестве сбоев тестирования?) – zipzit

+0

@zipzit: Я не могу сказать это точно. Это просто сомнение. Во-первых, я не эксперт в OpenCV. Кроме того, я просто использую конкретную (старую) версию. –

 Смежные вопросы

  • Нет связанных вопросов^_^