6.Qt5 FFmpeg本地摄像头采集预览实战
好文章,来自【福优学苑@音视频+流媒体】
6.Qt5+FFmpeg本地摄像头采集预览实战
源码工程:S26_Test2
FFmpeg命令行处理摄像头
ffmpeg -list_devices true -f dshow -i dummy
命令执行后输出的结果如下(注:中文的设备会出现乱码的情况)。
列表显示设备的名称很重要,输入的时候都是使用“-f dshow -i video="{设备名}"”的方式。
获取摄像头数据(保存为本地文件或者发送实时流)
编码为H.264,保存为本地文件
下面这条命令,实现了从摄像头读取数据并编码为H.264,最后保存成mycamera.mkv。
ffmpeg -f dshow -i video="Lenovo EasyCamera" -vcodec libx264 mycamera001.flv
ffplay直接播放摄像头的数据
使用ffplay可以直接播放摄像头的数据,命令如下:
ffplay -f dshow -i video="Lenovo EasyCamera"
如果设备名称正确的话,会直接打开本机的摄像头,
FFmpeg+SDL2.0显示本地摄像头
/***********************
步骤是什么?
回忆:FFmpeg大体架构、流程
1.打开流协议:(本地文件、rtsp、rtmp、摄像头)
2.分析流信息:(video,audio,subtitle,......)
3.封装、解封装:
4.编码、解码:
5.渲染、推流:
---------》数据结构、API:
AVFormatContext:大管家婆
avformat_open_input
avformat_find_stream_info
av_read_packet: AVPacket, AVFrame
avcodec_send_packet
avcodec_receive_frame:AVCodecContext
sws_scale(,,,:::yuv422,420, yuyv, uyvy, yv12,yu12, nv12,nv21)
:SwsContext
***********************/
工程配置文件:.pro
:添加头文件目录、库文件
INCLUDEPATH += $$PWD/../FFmpeg431dev/include
INCLUDEPATH += $$PWD/../SDL2/include
LIBS += $$PWD/../FFmpeg431dev/lib/avcodec.lib \
$$PWD/../FFmpeg431dev/lib/avdevice.lib \
$$PWD/../FFmpeg431dev/lib/avfilter.lib \
$$PWD/../FFmpeg431dev/lib/avformat.lib \
$$PWD/../FFmpeg431dev/lib/avutil.lib \
$$PWD/../FFmpeg431dev/lib/postproc.lib \
$$PWD/../FFmpeg431dev/lib/swresample.lib \
$$PWD/../FFmpeg431dev/lib/swscale.lib
LIBS += $$PWD/../SDL2/lib/x86/SDL2.lib
LIBS += $$PWD/../SDL2/lib/x86/SDL2main.lib
一个坑:
undefined reference to `vtable for’”问题的原因及解决方法
QT中,类要支持信号与槽机制,需要继承自QObject并在头文件开头添加Q_OBJECT宏.
如果使用QtCreator创建类时,没有选择继承自QObject类或其子类,
而在创建后手工修改继承自QObject并手工添加Q_OBJECT宏,
则在编译时有可能会出现”undefined reference to `vtable for’…….”错误.
解决方法: 把新创建的类从项目中移除(注意:不要从磁盘上删除),
然后再添加进来,QtCreator就会重新解析此类,
再编译就不再会出现上述错误.
又一个坑2:
16:58:37: 程序异常结束。
16:58:37: The process was ended forcefully.
原因:运行时缺少dll
又一个坑3:
no documents matching "ui"
无法添加槽函数,导致信号发出后槽函数接收不到信号
原因1:未在类定义中添加Q_OBJECT
原因2:信号或槽指向的对象未实例化
原因3: 多处包含相同的"ui_XXX.h"头文件
查找/添加槽错误
在UI文件中右键转到槽发生错误,弹窗提示如下:
查找或添加槽错误
The class containing "UI::XXX" could mot be found in :\..\.XXX.cpp.Please verify the #include_directives.
可将.pro文件中,SOURCE+=后面的.cpp文件名全部删除,HEADERS+=后面的.h文件名全部删除重新构建后,再次右键项目文件选择“Add Existing Directory”重新加载文件并重新编译工程。
此时再次添加槽函数
弹窗提示如下:
查找/添加槽错误
No documents matching "ui_XXX.h" could be found .Rebuilding the project might help.
此时并不需要重新编译,直接重启Qt Creator即可。
添加头文件:.h
//必须加以下内容,否则编译不能通过,为了兼容C和C99标准 #ifndef INT64_C #define INT64_C #define UINT64_C #endif //引入ffmpeg头文件 #include <iostream> extern "C" { #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libswscale/swscale.h> #include <libavdevice/avdevice.h> #include <libavfilter/avfilter.h> #include <libavutil/imgutils.h> #include <SDL.h> #include <SDL_main.h> }; #undef main #include <QObject> #include <qmutex.h> #include <qstring.h> 本地摄像头的信息 printf("------------av_dump_format-------------------\n"); av_dump_format(pAVFmtCtx, 0, NULL, 0); /* Input #0, dshow, from '(null)': Duration: N/A, bitrate: N/A Stream #0:0: Video: rawvideo (YUY2 / 0x32595559), yuyv422, 640x480, 30 fps, 30 tbr, 10000k tbn */ ///// 1. open local camera ///// 2. find stream info ///// 3. open codec : decoder ///// 4. sws_scale :yuyv422--->yuv420p ///// 5. SDL2.0 ///// 6. demux , decode ///// 7. render
// calculate the bytes of one image
av_frame_alloc
av_image_get_buffer_size
av_image_fill_arrays
问题:为什么第二次Start就无法显示窗口呢?
objFmpg.SetStopped(0);
FFmpeg+Qt显示摄像头
mutex.lock();
sws_scale(pSwsContext2,
(const uint8_t* const )pFrameYUV->data,
pFrameYUV->linesize,0,
videoHeight, pAVPicture.data, pAVPicture.linesize);
//发送获取一帧图像信号
QImage image(pAVPicture.data[0],videoWidth,videoHeight,QImage::Format_RGB888);
emit GetImage(image);
mutex.unlock();
为什么不显示呢?
connect:信号、槽,绑定
为什么窗口可以放大,不能缩小呢?
///作业:请大家自行修改下边这段代码,改造成不用SDL
//一帧一帧读取视频
// int frameFinished=0;
// while (true){
// if (av_read_frame(pFormatCtx, packet) >= 0){
// if(pAVPacket.stream_index == videoStreamIndex){
// qDebug()<<"开始解码"<<QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss");
// decode(pCodecCtx, packet, pFrame, pFrameYUV, img_convert_ctx/*, fp_yu*/);
// /////avcodec_decode_video2(pAVCodecContext, pAVFrame, &frameFinished, &pAVPacket);
// mutex.lock();
// sws_scale(pSwsContext2,(const uint8_t* const *)pFrameYUV->data,pFrameYUV->linesize,0,videoHeight,pAVPicture.data,pAVPicture.linesize);
// //发送获取一帧图像信号
// QImage image(pAVPicture.data[0],videoWidth,videoHeight,QImage::Format_RGB888);
// emit GetImage(image);
// mutex.unlock();
// /// -re : 帧率
// QThread::msleep(33);
// }
// }
// av_free_packet(packet);//释放资源,否则内存会一直上升
// }
***【在线视频教程】***