专门做超市海报的网站,做网站app是什么h行业,网站导航栏模板怎么做,换物网站为什么做不起来目录 1.设计思路 2.Pro文件配置 3.头文件引入 4.界面设计 5.初始化设备函数 6.发起视频链接函数 7.初始化定时器模块函数 8.TCP链接模块函数 9.处理接收的数据线程函数 10.实现功能展示 设计思路 基于TCP协议的视频传输Demo#xff0c;设计要实现的功能主要是TCP传输还有视频设计要实现的功能主要是TCP传输还有视频可参考以下开发思路 1.视频本质都是通过照片组成由于连续的照片数量多了画面就由单纯的静态图片变成动态的视频所以要实现视频传输实现得把摄像头录制到的画面分成帧使用TCP协议发送具体开发细节如下 1.设置QTimer类对象实现定时器功能定期捕获摄像头录制的画面 2.为了实现捕获画面功能需要定义QImageCapture对象并使用QMediaCaptureSession类对象统一管理摄像头和QImageCapture对象 2.TCP协议的链接主要通过三次握手形成可靠的链接。所以我们需要一个QTcpSocket对象来进行链接并对该对象发出的readyRead信号(读取到数据)进行相对应的槽函数绑定 3.由于要同时录制视频还有捕获视频画面发送至其他用户所以要使用线程单独使用线程往往管理不是很方便所以Demo中使用了QThradPool类(线程池)来管理线程并使用QThreadPool::globalInstance()-start()函数将线程放置全局线程池统一管理启动 4.有时候不仅仅满足于视频传输的需求(现实生活中或许只有倒车视频监控等功能不需要实现音频录制)所以该Demo使用了QAudioDevice访问音频设备并录制 Pro文件配置 为了实现基于TCP协议的视频传输Demo我们需要Qt中自带的两个模块分别为multimedia 模块和multimediawidgets模块 1.multimedia模块该模块提供了音频和视频播放、录制以及处理的基本功能。支持多种音频和视频格式能实现流媒体播放等功能 2.multimediawidgets模块该模块提供了一组预构建的多媒体小部件使得开发者可以快速地在应用程序中添加多媒体播放和控制功能 所以开发前Pro文件中应该添加以下字段
QT multimedia multimediawidgets 头文件引入 以下为项目main文件中需要引入的头文件我会把为什么要引入该头文件列在备注中以供参考
头文件备注QDir用于获取操作文件系统目录QFile用于文件操作的类QTimer用于实现定时器功能QCamera用于访问和控制摄像头设备QHostInfo用于获取主机信息QTcpSocket用于实现TCP套接字的类QTcpServer用于实现TCP服务器端的类QMessageBox用于显示消息框向用户显示信息、警告或错误QAudioInput用于音频输入设备的类QThreadPool用于管理线程池QAudioDevice用于访问和控制音频设备QMediaDevices提供对媒体设备信息的访问QCameraDevice用于访问和控制相机设备QImageCapture用于捕获摄像头录制的图片QMediaRecorder用于录制媒体内容QMediaCaptureSession管理媒体捕获会话的类
表1.头文件列表 界面设计 设计思想是为了实现多个用户同时视频的功能但是没实现服务端于是把服务端使用的QTcpServer转到客户端实现写Demo时本人将更多考虑的是提供更强的可扩展性 初始化设备函数 以下函数为初始化设备的函数针对Ui文件中控件名称的不同可以修改对应的指针完成效果
/* 初始化MainWindow界面信息* device当前摄像头* 返回值void
*/
void MainWindow::init_MainWindowInfo()
{session new QMediaCaptureSession(this);session-setVideoOutput(ui-MyvideoPreview); //设置视频输出控件QAudioInput* audioInput new QAudioInput(this);audioInput-setDevice(QMediaDevices::defaultAudioInput()); //获取默认的音频输入设备session-setAudioInput(audioInput); //设置音频输入设备QCameraDevice defaultCameraDevice QMediaDevices::defaultVideoInput();//获取当前摄像头 if(defaultCameraDevice.isNull()){QMessageBox::critical(this,提示,没有发现摄像头);return;}init_CameraDevice(defaultCameraDevice);
}/* 初始化摄像头* device当前摄像头* 返回值void
*/
void MainWindow::init_CameraDevice(const QCameraDevice device)
{QByteArray defaultCameraID device.id();int index0;for(int i0; iQMediaDevices::videoInputs().size(); i){QCameraDevice device QMediaDevices::videoInputs().at(i);if (device.id() defaultCameraID){ui-comboCam_List-addItem(device.description()(默认),QVariant::fromValue(device));indexi;}else{ui-comboCam_List-addItem(device.description(),QVariant::fromValue(device));}}if (ui-comboCam_List-currentIndex() ! index){ui-comboCam_List-setCurrentIndex(index);}camera_Obj new QCamera(this); //初始化摄像头对象camera_Obj-setCameraDevice(device);session-setCamera(camera_Obj); //为session设置摄像头capture_Obj new QImageCapture(this);//创建图像捕获对象session-setImageCapture(capture_Obj);//设置画面捕获对象//捕获到画面时发送画面connect(capture_Obj, QImageCapture::imageCaptured, this, MainWindow::handle_SendingImg);//设置摄像头信息connect(ui-comboCam_List,QComboBox::currentIndexChanged,this, MainWindow::handle_ShowCameraDevice);handle_ShowCameraDevice(ui-comboCam_List-currentIndex());
}/* 初始化摄像头设备信息* device当前摄像头* 返回值void
*/
void MainWindow::init_CameraDeviceInfo(const QCameraDevice device)
{ui-comboCam_VideoRes-clear(); //支持的视频分辨率ui-comboCam_FrameRate-clear(); //支持的帧率范围foreach(QCameraFormat format, device.videoFormats()){QSize sizeformat.resolution();QString strQString::asprintf(%d X %d,size.width(),size.height());ui-comboCam_VideoRes-addItem(str);strQString::asprintf(%.1f ~ %.1f,format.minFrameRate(),format.maxFrameRate());ui-comboCam_FrameRate-addItem(str);}
}/* 显示摄像头信息* index项下标* 返回值void
*/
void MainWindow::handle_ShowCameraDevice(int index)
{QVariant varui-comboCam_List-itemData(index);QCameraDevice device var.valueQCameraDevice();init_CameraDeviceInfo(device); //显示摄像头设备信息camera_Obj-setCameraDevice(device); //重新设置摄像头设备
} 发起视频链接函数
//发起视频链接
void MainWindow::on_Camclose_Btn_2_clicked()
{QString ip ui-lineEdit-text();QString port ui-lineEdit_2-text();if(port.isEmpty() || ip.isEmpty()){QMessageBox::information(nullptr,提示,未输入目标端口或IPv4地址,QMessageBox::Ok);}if(tcpSocket ! nullptr){tcpSocket-deleteLater();}if(video_ThreadObj ! nullptr){video_ThreadObj-handle_CloseThread();}tcpSocket new QTcpSocket(this);qDebug() 发起连接目标地址 ip 目标端口 port.toUShort();//连接成功connect(tcpSocket,QAbstractSocket::connected,this,MainWindow::handle_Connect);//显示接收的图片connect(tcpSocket,QTcpSocket::readyRead,this,MainWindow::hanlde_RelayinThread);tcpSocket-connectToHost(ip,port.toUShort()); //链接服务器video_ThreadObj new VideoThread(ui-show_Img);
}void MainWindow::handle_Connect()
{qDebug() 连接成功;init_TimerModel();
} 初始化定时器模块函数
//初始化定时器
void MainWindow::init_TimerModel()
{timer_Obj new QTimer;timer_Obj-start(100);//定时截取摄像头拍摄的图片connect(timer_Obj,QTimer::timeout,this,MainWindow::handle_InterceptImg);
}//定时截取摄像头图片
void MainWindow::handle_InterceptImg()
{QDir().mkdir(images);QString path QDir::currentPath() /images/image.jpg; //捕获图像的保存路径qDebug() 定时截取摄像头图片 path;capture_Obj-captureToFile(path);
}//发送截取的图片
void MainWindow::handle_SendingImg(int id, const QImage image)
{QDir().mkdir(images);QString path QDir::currentPath() /images/image.jpg; //捕获图像的保存路径if (!image.isNull()) { //截取到图片image.save(path,jpg,30); //保存图像并压缩质量为30QFile file(path);file.open(QIODevice::ReadOnly);tcpSocket-write(file.readAll()); //发送图片tcpSocket-flush(); //确保消息被发送file.close();qDebug() 发送图片;}
} TCP链接模块函数
//初始化Tcp模块
void MainWindow::init_TcpModule()
{tcpSocket new QTcpSocket;tcpServer new QTcpServer(this);connect(tcpServer,QTcpServer::newConnection,this,MainWindow::init_TcpConnection);get_LocalIPv4(); //获取IPv4地址QString port ui-lineEdit_3-text();//监听端口qDebug() 监听端口 port.toUShort();tcpServer-listen(QHostAddress::Any,port.toUShort()); //开始监听
}//初始化Tcp链接
void MainWindow::init_TcpConnection()
{qDebug() 获取到连接;//获取第一个链接的客户端tcpSocket tcpServer-nextPendingConnection();video_ThreadObj new VideoThread(ui-show_Img);//显示接收的图片connect(tcpSocket,QAbstractSocket::readyRead,this,MainWindow::hanlde_RelayinThread);//连接成功connect(tcpSocket,QAbstractSocket::connected,this,MainWindow::handle_Connect);QThreadPool::globalInstance()-start(video_ThreadObj);//启动线程
}//转发至线程处理读取到的数据
void MainWindow::hanlde_RelayinThread()
{qDebug() 处理接收的函数;video_ThreadObj-handle_ShowReceiveImg(tcpSocket-readAll());
}// 获取本机IPV4地址
int MainWindow::get_LocalIPv4()
{QString hostName QHostInfo::localHostName(); //获取主机设备名QHostInfo hostInfo QHostInfo::fromName(hostName);//获取主机信息QListQHostAddress addList hostInfo.addresses();//获取主机地址列表if(addList.isEmpty()){ //未获取到地址return 0;}else{foreach(const QHostAddress item,addList){if(item.protocol() QAbstractSocket::IPv4Protocol){ui-udpIpv4_Box-addItem(item.toString());}}return 1;}return -1;
} 处理接收的数据线程函数
VideoThread::VideoThread(QObject *parent): QRunnable{}, QObject{parent}
{setAutoDelete(true); //设置线程自动析构
}VideoThread::VideoThread(QLabel *widget, QObject *parent): QRunnable{}, QObject{parent}, video_Label{widget}
{ok true; //初始化线程状态setAutoDelete(true); //设置线程自动析构
}void VideoThread::run()
{while(ok);
}//显示接收的图像
void VideoThread::handle_ShowReceiveImg(QByteArray data)
{QPixmap pic QPixmap::fromImage(QImage::fromData(data));video_Label-setPixmap(pic.scaled(video_Label-size(),Qt::KeepAspectRatio,Qt::SmoothTransformation));
}//关闭线程
void VideoThread::handle_CloseThread()
{if(ok){ok false;}
} 实现功能展示 PS由于本机只有一个摄像头就不能开另一边应用的摄像头了后续会把Demo的github地址发布在评论区。该Demo还需要更多的完善才能真正的实现一个视频通话功能后续会更新优化后的Demo