网站安全狗卸载卸载不掉,wordpress 说说 主题,站长之家权重查询,埃及网站后缀一、前言本文主要记录通过 Qt 结合 FFmpeg 实现从摄像头采集视频数据#xff0c;并将采集到的数据保存为 YUV 格式文件的过程。涉及 FFmpeg 设备操作、Qt 多线程编程等核心知识点#xff0c;适合有一定 Qt 和 FFmpeg 基础的开发者学习参考。二、环境准备开发框架#xff1a;…一、前言本文主要记录通过 Qt 结合 FFmpeg 实现从摄像头采集视频数据并将采集到的数据保存为 YUV 格式文件的过程。涉及 FFmpeg 设备操作、Qt 多线程编程等核心知识点适合有一定 Qt 和 FFmpeg 基础的开发者学习参考。二、环境准备开发框架Qt 5/6本文以 Qt 为例核心逻辑不依赖具体版本FFmpeg 库需包含libavdevice、libavformat、libavutil、libavcodec等核心库系统环境本文以 Windows 系统为例使用 dshowDirectShow作为设备输入格式三、核心代码解析3.1 线程类头文件audiothread.h由于视频采集是耗时操作需放在子线程中执行避免阻塞主线程UI 线程。#ifndef AUDIOTHREAD_H #define AUDIOTHREAD_H #include QThread class audioThread : public QThread { Q_OBJECT private: void run(); // 线程执行函数重写QThread的run方法 public: explicit audioThread(QObject *parent nullptr); ~audioThread(); }; #endif // AUDIOTHREAD_H3.2 线程实现文件audiothread.cpp核心逻辑集中在该文件包含 FFmpeg 设备打开、数据采集、文件写入、资源释放等步骤。3.2.1 头文件与宏定义#include audiothread.h #include qdebug.h #include qfile.h // 引入FFmpeg的C语言接口 extern C{ #include libavdevice/avdevice.h #include libavformat/avformat.h #include libavutil/avutil.h #include libavutil/imgutils.h #include libavcodec/avcodec.h } // Windows系统下的设备配置 #ifdef Q_OS_WIN #define FMT_NAME dshow // 设备输入格式dshow #define DEVICE_NAME videoIntegrated Webcam // 摄像头设备名称 #define FILENAME D:/out.yuv // YUV文件保存路径 #endif // 错误信息格式化宏 #define ERROR_BUF(ret) \ char errbuf[1024]; \ av_strerror(ret,errbuf,sizeof(errbuf));3.2.2 构造与析构函数audioThread::audioThread(QObject *parent):QThread{parent} { // 线程结束时自动回收内存 connect(this,audioThread::finished, this,audioThread::deleteLater); } audioThread::~audioThread() { disconnect(); // 断开所有信号槽连接 requestInterruption(); // 请求线程中断 quit(); // 退出事件循环 wait(); // 等待线程结束 qDebug() this 析构内存被回收; }3.2.3 核心采集逻辑run 方法void audioThread::run() { qDebug() this 开始执行------; // 1. 获取输入格式对象dshow AVInputFormat *fmt av_find_input_format(FMT_NAME); if(!fmt){ qDebug() av_find_input_format error FMT_NAME; return; } // 2. 初始化格式上下文操作设备的核心上下文 AVFormatContext *ctx nullptr; AVDictionary *options nullptr; // 设置采集参数分辨率、像素格式、帧率 av_dict_set(options,video_size,1280x720,0); av_dict_set(options,pixel_format,yuyv422,0); av_dict_set(options,framerate,10,0); // 3. 打开摄像头设备 int ret avformat_open_input(ctx,DEVICE_NAME,fmt,options); if(ret 0){ ERROR_BUF(ret); qDebug() avformat_open_input error errbuf; return; } // 4. 打开YUV文件用于写入 QFile file(FILENAME); if(!file.open(QFile::WriteOnly)){ qDebug() file open error FILENAME; avformat_close_input(ctx); // 失败时关闭设备 return; } // 5. 计算一帧视频数据的大小 AVCodecParameters *params ctx-streams[0]-codecpar; AVPixelFormat pixFmt (AVPixelFormat)params-format; int imageSize av_image_get_buffer_size( pixFmt, params-width, params-height, 1); // 6. 循环采集视频数据 AVPacket *pkt av_packet_alloc(); // 分配数据包 while(!isInterruptionRequested()){ // 检查是否需要中断 ret av_read_frame(ctx,pkt); // 读取一帧数据 if(ret 0){ // 读取成功 // 将数据写入YUV文件 file.write((const char*)pkt-data,imageSize); av_packet_unref(pkt); // 释放数据包引用 }else if(ret AVERROR(EAGAIN)){ // 资源临时不可用继续循环 continue; }else{ // 其他错误退出循环 ERROR_BUF(ret); qDebug() av_read_frame error errbuf ret; break; } } // 7. 释放资源 av_packet_free(pkt); // 释放数据包 file.close(); // 关闭文件 avformat_close_input(ctx); // 关闭设备 qDebug() this 正常结束------; }3.3 主窗口逻辑mainwindow 相关3.3.1 头文件mainwindow.h#ifndef MAINWINDOW_H #define MAINWINDOW_H #include QMainWindow #include audiothread.h QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent nullptr); ~MainWindow(); private slots: void on_playBtn_clicked(); // 按钮点击槽函数 private: Ui::MainWindow *ui; audioThread *_audioThread nullptr; // 采集线程指针 }; #endif // MAINWINDOW_H3.3.2 实现文件mainwindow.cpp#include mainwindow.h #include ui_mainwindow.h MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui-setupUi(this); } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_playBtn_clicked() { if(!_audioThread){ // 开始采集 _audioThread new audioThread(this); _audioThread-start(); // 启动线程 // 线程结束后重置指针并恢复按钮文字 connect(_audioThread,audioThread::finished, [this](){ _audioThread nullptr; ui-playBtn-setText(开始录视频); }); ui-playBtn-setText(结束录视频); }else{ // 停止采集 _audioThread-requestInterruption(); // 请求线程中断 _audioThread nullptr; ui-playBtn-setText(开始录视频); } }3.4 程序入口main.cpp#include mainwindow.h #include QApplication extern C{ #include libavdevice/avdevice.h } int main(int argc, char *argv[]) { avdevice_register_all(); // 注册FFmpeg所有设备 QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }四、关键知识点总结4.1 FFmpeg 核心操作流程avdevice_register_all()注册所有 FFmpeg 设备必须在操作设备前调用av_find_input_format()根据格式名称如 dshow获取输入格式对象avformat_open_input()打开设备 / 文件初始化格式上下文av_read_frame()从设备读取一帧视频数据封装在 AVPacket 中avformat_close_input()关闭设备释放格式上下文资源av_image_get_buffer_size()计算指定分辨率、像素格式的单帧视频数据大小。4.2 Qt 多线程注意事项耗时操作如视频采集必须放在QThread::run()方法中避免阻塞 UI线程中断通过requestInterruption()isInterruptionRequested()配合实现优雅停止线程线程结束后通过finished信号关联deleteLater()自动回收线程内存避免内存泄漏主线程与子线程的交互尽量通过信号槽避免直接操作子线程对象。4.3 YUV 文件验证采集完成后可通过 FFmpeg 的 ffplay 工具验证 YUV 文件是否有效ffplay -f rawvideo -pixel_format yuyv422 -video_size 1280x720 -framerate 10 D:/out.yuv五、常见问题与解决avformat_open_input 失败检查设备名称是否正确Windows 下可通过ffmpeg -list_devices true -f dshow -i dummy查看摄像头名称确认 FFmpeg 编译时包含了 dshow 模块检查权限摄像头是否被其他程序占用。采集数据写入文件后无法播放确认像素格式、分辨率、帧率与 ffplay 播放参数一致检查单帧数据大小计算是否正确避免写入数据长度错误。线程退出时崩溃确保退出时释放所有 FFmpeg 资源AVPacket、AVFormatContext 等析构函数中先请求中断再调用 quit () 和 wait ()等待线程完全结束后再释放资源。六、总结本文通过 QtFFmpeg 实现了摄像头视频采集并保存为 YUV 格式文件核心是掌握 FFmpeg 设备操作流程和 Qt 多线程编程规范。YUV 作为原始视频格式是音视频开发的基础理解其采集过程有助于后续学习编码如 H.264/H.265、封装如 MP4等进阶知识点。