Qt视频播放需用FFmpeg解码AVFrame并经sws_scale转RGB后由Qt渲染,关键步骤包括:①avformat_find_stream_info显式探测流参数;②sws_scale做YUV转RGB;③QImage跨线程传递须用QueuedConnection加丢帧;④DLL须与Qt编译器/位数匹配。

Qt 本身不直接解码视频,QMediaPlayer 在 Windows 上依赖 DirectShow,对 RTSP、H.265、自定义帧处理基本无能为力。真正能稳定把一路 rtsp:// 或本地 MP4 显示出来的方案,是让 FFmpeg 负责解码出 AVFrame,Qt 只管把像素画到界面上——中间那层 sws_scale 转换和线程刷新,才是成败关键。
avformat_open_input 打开流后必须调用 avformat_find_stream_info
很多人只调 avformat_open_input 就开始读包,结果 av_read_frame 返回 0 但 pkt.stream_index 对不上,或者 codecpar 里宽高还是 0。这是因为 FFmpeg 不会在打开时自动探测流参数,尤其 RTSP 流或某些 MKV 文件,头信息极简。
-
avformat_find_stream_info必须显式调用,否则AVStream->codecpar中的width/height/format都不可信 - 建议加超时控制:传入
AVDictionary *options,设"probesize"和"analyzeduration"防卡死,比如av_dict_set(&options, "analyzeduration", "2000000", 0) - 返回值为负数(如
-541478725)代表探测失败,不是文件路径错,而是协议或编码器不支持,需检查 FFmpeg 是否启用了对应 demuxer(如rtsp,h265)
YUV to RGB 转换必须用 sws_getContext + sws_scale,不能手写循环
FFmpeg 解出来的 AVFrame 几乎全是 AV_PIX_FMT_YUV420P,而 QImage 只认 QImage::Format_RGB32 或 QImage::Format_RGBA8888。有人试图用三重 for 循环做 YUV 转 RGB,CPU 占用飙到 90% 且画面撕裂——sws_scale 内部做了 SIMD 优化和行对齐处理,自己写根本达不到实时性能。
- 创建
SwsContext时,源格式必须严格匹配frame->format,目标格式用AV_PIX_FMT_RGB24(对应QImage::Format_RGB888)或AV_PIX_FMT_RGBA(对应QImage::Format_RGBA8888) -
sws_scale的srcSlice参数要传frame->data,但dst必须是 malloc 出的连续内存(QImage的bits()不保证可写或对齐),否则崩溃或花屏 - 务必检查
frame->linesize[0]和sws_context创建时的 srcW/srcH 是否一致,缩放过程中若尺寸变更(如窗口 resize),必须重建SwsContext,否则输出错位
QImage 构造和跨线程传递必须用 QueuedConnection + 丢帧策略
解码线程直接 emit 一个含 QImage 的信号给 GUI 线程,在高帧率(如 30fps)下极易导致事件队列积压、UI 卡死甚至内存暴涨。Qt 的 QImage 默认深拷贝,每次传递都在堆上 new 一块新内存。
- 信号声明必须用
void frameReady(const QImage &)(引用),连接方式强制设为Qt::QueuedConnection,避免在解码线程里调用paintEvent - GUI 线程的 slot 里不要保存
QImage成员变量,而是每次用完立即丢弃;可在 slot 开头加判断:if (m_currentFrame.isNull()) { m_currentFrame = image; update(); },实现简易丢帧 - 更稳的做法是在解码线程内用
QMutex+QImage指针双缓冲,GUI 线程只负责交换指针并update(),避免任何拷贝
运行时 DLL 缺失或版本错配会导致 avformat_open_input 直接返回空指针
Qt 程序启动后 avformat_open_input 返回 nullptr,控制台无任何错误提示,十有八九是 FFmpeg 运行时 DLL 没放对位置,或与 Qt 编译器/位数不匹配。
- Windows 下必须把
avcodec-*.dll、avformat-*.dll、avutil-*.dll、swscale-*.dll全部复制到.exe同目录,不能只放bin/子目录 - MSVC2015 编译的 Qt 必须配 MSVC2015 编译的 FFmpeg,MinGW 同理;混用会导致
std::string或异常机制不兼容,程序静默退出 - 用
Dependency Walker或ntldd(MSYS2)检查 exe 依赖,确认所有 DLL 路径解析正确,尤其注意libwinpthread-1.dll(MinGW)或msvcp140.dll(MSVC)是否缺失
最常被忽略的是:AVFrame 的生命周期必须由解码线程完全管理,一旦传给 Qt 线程,就不能再被 av_frame_unref;反过来,QImage 的数据内存也不能被 FFmpeg 复用。这两条边界划不清,早晚出现野指针或双重释放。











