一、前言
用ffmpeg来处理USB摄像头,是前段时间研究视频监控ffmpeg内核的时候搞定的,既然ffmpeg这么牛逼的库可以解析各种音视频,我想处理个本地USB摄像头应该也不是什么难事,果真搜索也是一大堆,当然主要也是因为有个项目的应用需要用到ffmpeg来处理本地USB摄像头,需要拿到每张图片做智能分析,用Qt自带的camera类不大好处理,刚好将ffmpeg的处理流程都搞清楚了,索性直接用ffmpeg来直接处理好了,用上这么强大的解码库,理论上支持各种USB摄像头。本地USB摄像机不需要硬解码,视频流编码类型为 AV_CODEC_ID_RAWVIDEO 像素格式为 AV_PIX_FMT_YUYV422 不经过解码操作直接就可显示。
ffmpeg方案处理流程:
引入avdevice.h头文件,调用avdevice_register_all();注册本地设备处理。调用av_dict_set设置分辨率(video_size)、帧率(framerate)等参数。调用av_find_input_format设置输入格式。调用avformat_open_input打开文件。调用av_find_best_stream找到视频流地址。调用avcodec_find_decoder设置视频解码器。调用av_read_frame循环解码读取帧数据。调用avcodec_send_packet avcodec_receive_frame解码数据。处理完以后调用av_frame_free avcodec_close等释放资源。
二、功能特点
同时支持windows、linux、嵌入式linux上的USB摄像头实时采集。支持多路USB摄像头多线程实时采集。在嵌入式linux设备上,自动查找USB设备文件并加载。可手动设置设备文件名称,手动设置后按照手动设置的设备文件加载。在嵌入式linux设备上支持人脸识别接口,实时绘制人脸框。具有打开、暂停、继续、关闭、截图等常规功能。可设置两路OSD标签,分别设置文本、颜色、字号、位置等。可作为视频监控系统使用。
三、效果图
四、相关站点
国内站点:https://gitee.com/feiyangqingyun/QWidgetDemo国际站点:https://github.com/feiyangqingyun/QWidgetDemo个人主页:https://blog.csdn.net/feiyangqingyun知乎主页:https://www.zhihu.com/people/feiyangqingyun/体验地址:https://blog.csdn.net/feiyangqingyun/article/details/97565652
五、核心代码
void FFmpegThread
::initOption()
{
av_dict_set(&options
, "buffer_size", "8192000", 0);
av_dict_set(&options
, "rtsp_transport", transport
.toUtf8().constData(), 0);
av_dict_set(&options
, "stimeout", "3000000", 0);
av_dict_set(&options
, "max_delay", "1000000", 0);
av_dict_set(&options
, "threads", "auto", 0);
if (isUsbCamera
) {
QString size
= QString("%1x%2").arg(videoWidth
).arg(videoHeight
);
av_dict_set(&options
, "video_size", size
.toUtf8().constData(), 0);
av_dict_set(&options
, "framerate", "25", 0);
}
if (isUsbCamera
) {
callback
= true;
hardware
= "none";
}
#ifndef opengl
callback
= true;
#endif
if (url
.startsWith("rtmp", Qt
::CaseInsensitive
)) {
saveMp4
= false;
}
}
bool FFmpegThread
::initInput()
{
formatCtx
= avformat_alloc_context();
formatCtx
->interrupt_callback
.callback
= AVInterruptCallBackFun
;
formatCtx
->interrupt_callback
.opaque
= this;
tryOpen
= false;
QByteArray urlData
= url
.toUtf8();
AVInputFormat
*ifmt
= NULL;
if (isUsbCamera
) {
#if defined(Q_OS_WIN)
ifmt
= av_find_input_format("dshow");
#elif defined(Q_OS_LINUX)
ifmt
= av_find_input_format("video4linux2");
#elif defined(Q_OS_MAC)
ifmt
= av_find_input_format("avfoundation");
#endif
}
int result
= avformat_open_input(&formatCtx
, urlData
.data(), ifmt
, &options
);
tryOpen
= true;
if (result
< 0) {
qDebug() << TIMEMS
<< "open input error" << url
;
return false;
}
if (options
!= NULL) {
av_dict_free(&options
);
}
result
= avformat_find_stream_info(formatCtx
, NULL);
if (result
< 0) {
qDebug() << TIMEMS
<< "find stream info error";
return false;
}
return true;
}