在我的代码中,我想在单独的pthread
中连续运行Videocapture
,而主线程将充当套接字服务器
与任何客户沟通(反之亦然)。
当客户端
连接到服务器
时,服务器
会立即发送最新的Videocapture
帧到客户端并关闭连接并再次等待另一个连接。
我目前在 mingw32
环境中使用 OpenCV 2.3.0
。
在 StackOverflow 上查看了一些可能的解决方案后,我尝试遵循它们,但是,我可以将 OpenCV 变量
放置在 本地
或全局
或交换线程
,即将Videocapture
线程保留在主线程
中或第二个线程
中>,当客户端连接时,程序只是静静地卡在 VideoCapture
线程的互斥锁定区域
。
我认为当服务器
线程在连接到客户端后开始锁定互斥体
时就会发生这种情况。
任何推理或可能的解决方案都将受到高度赞赏。另外,我正在使用预构建 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;
}
客户端代码
接收器.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;
}
最佳答案
我认为 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);
现在它按预期工作了。呃!现在,我需要清理代码中的所有困惑内容。
其实我也会更换OpenCV frame
变量有一个简单的 unsigned char
用于共享的缓冲区。
关于c++ - 如何在 C++ 中的单独 posix 线程中运行 OpenCV Videocapture 以实现跨平台?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34469844/