本例是用QT编写的视频监控界面。由主窗口的两个按钮可以分别调用观看两个摄像头的视频内容。加主线程共3个线程。两个视频显示窗口用Qtimer 来控制。视频图片显示使用lable控件。此程序主要讲解本地图片多线程传输,暂时不用多次刷新显示连续帧。待USB冲突解决后方可实现。
Client端:
用QT设计界面。其中包括main.cpp, mainWindow_main.cpp, video_thread1.cpp, video_thread2.cpp, video_client.cpp及其对应的*.h文件。
1.mainWindow_main.cpp
此为主窗口的功能实现代码。该主窗口包含两个pushButton, 点击按钮pushBtn_video1则调用video_thread1.cpp, 点击按钮pushBtn_video2则调用video_thread2.cpp.
该mainWindow_main.cpp功能实现很简单,只是实现一个窗口调用。
void mainWindow_main::on_pushBtn_video1_clicked()
{
MainWindow_thread1 *show_video1 = new MainWindow_thread1();
show_video1->show();
}
void mainWindow_main::on_pushBtn_video2_clicked()
{
MainWindow_thread2 *show_video2 = new MainWindow_thread2();
show_video2->show();
}
2. video_thread1.cpp和 video_thread2.cpp
此为点击主界面两个按钮时出现的两个窗口所执行的代码。这两个文件的代码很相似,只用全局变量所标识的线程号thread_Num有所不同。
程序执行伊始,设全局变量temp=0。temp为开启 / 关闭视频的全局标识变量。
update( )。便于随时刷新,它可自动调用paint事件重绘显示屏幕。
1)编写单击开始按钮的槽on_bottonStart1_clicked( )。
{temp=0;//如果是stop按钮的话,就设为1
thread_Num=1;
thread1.video_start(temp, thread_Num);}
线程2同理。只需改动thread_Num为2即可。
2)编写paint事件paintEvent(QPaintEvent *e)
如果不用QT的事件机制来画图的话,图片是不能被正常显示在lable中的。
QPainter paint(this);
QImage image("init_thread1.jpg");//显示传送过来的图片
paint.drawImage(QRect(0,0,640,480),image);
QWidget::paintEvent(e);
3.video_start( int temp, int thread_Num )的实现
(自己定义一个新类video_client,在video_thread1.cpp和 video_thread2.cpp中分别定义一个对象,然后在video_thread1.cpp和 video_thread2.cpp中使用。)
1)先判断temp的值。为1,跳出;为0,向下执行。
2)struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_ANY);//链接本机
//sin.sin_addr.s_addr = inet_addr("192.168.47.23");//指定的服务器端地址(但服务器端不用指明客户端地址)
if(thread_Num == 1)
{sin.sin_port = 8000;}
else
{sin.sin_port = 8001;}
3)sockfd=socket(AF_INET, SOCK_STREAM, 0);// 建立socket
4)::connect(sockfd, (sockaddr *)&sin, sizeof(sin));//请求连接,对应server的accept( )
5)新建init_thread1.jpg和init_thread1.jpg,用于写入接收到的图片数据。
if(thread_Num==1)
{fd_frame = fopen("init_thread1.jpg","wb"); }
else
{fd_frame = fopen("init_thread2.jpg","wb");}
开始数据传输:
1) 接收所传图片的一共需要传送的次数times;
2) 做times次循环;
3) ::memset( buff, 0, 1024 ); 不把暂存数组清零会出错误;
4) 每次接收1024字节len1 = recv(sockfd, buff, 1024, 0);
5) 每次接收后在传输过程中,接收一次,就顺序写入init_thread1.jpg和init_thread1.jpg
len = fwrite(buff, 1024, 1, fd_frame);
6)给server端应答信号:len2 = send(sockfd, buf, 10,0);
7)同理接收最后的小于1024字节的数据(即前面取余所得值)。
关闭写入图片的指针fclose( fd_frame );
关闭socket。即::close( sockfd );