一、环境搭建
1.1 编译环境
- os:windows
- 使用qt版本为5.14.2
- 编译器MinGW 64-bit
- IDE: Qt Creator
1.2 外部依赖库
- ffmpeg:5.1.2(64位)
- x264(64位)
1.3 qt配置外部依赖库
并将动态库,添加进系统环境变量
二、软件简介
2.1 系统架构
该系统中,共有3个线程,分别是:
- 主线程:负责各个模块的初始化,以及软件的逻辑处理
- 录像线程:负责不断从摄像头获取原始图片数据,并添加到安全队列中
- 数据保存线程:负责不断从安全队列中获取数据,并转换为合适的像素格式进行播放与保存
2.2 软件界面
- 先点击获取设备,查找可用设备
- 选择相应设备后,点击开始录像
- 最后结束录像
2.3 代码
2.3.1 获取设备
#include "DeviceMsg.h"
#include <QDebug>
DeviceMsg::DeviceMsg()
:m_iFormat(nullptr)
{
avformat_network_init();
avdevice_register_all();
}
QVector<QString> DeviceMsg::getDevice(const QString &deviceName)
{
QVector<QString> v;
AVDeviceInfoList *deviceList = nullptr;
m_iFormat = av_find_input_format(deviceName.toStdString().data());
if (!m_iFormat) {
throw QString("无法找到输入格式"+deviceName);
}
int ret = avdevice_list_input_sources(m_iFormat, nullptr, nullptr, &deviceList);
if (ret < 0) {
throw QString("无法获取设备列表: 错误码 %1").arg(ret);
} else if (deviceList) {
for (int i = 0; i < deviceList->nb_devices; ++i) {
QString s(deviceList->devices[i]->device_description);
v.push_back(s);
}
avdevice_free_list_devices(&deviceList); // 释放资源
} else {
throw QString("设备列表为空");
}
return v;
}
const AVInputFormat *DeviceMsg::getIFormat() const
{
return m_iFormat;
}
2.3.2 打开设备
#include "VideoDecode.h"
#include <QDebug>
VideoDecode::VideoDecode()
:m_outPutFormat(AV_PIX_FMT_YUV420P)
{
}
void VideoDecode::init(const AVInputFormat *iFormat, const QString &deviceName)
{
m_formatCtx = avformat_alloc_context();
m_codecCtx = nullptr;
const AVCodec *m_codec = nullptr;
QString videoDevice = "video="+deviceName;
int ret = avformat_open_input(&m_formatCtx,videoDevice.toUtf8().data(),iFormat,NULL);
if(ret < 0)
{
throw QString("avformat_open_input error");
}
ret = avformat_find_stream_info(m_formatCtx, nullptr);
if(ret < 0)
{
throw QString("avformat_find_stream_info error");
}
m_videoIndex = av_find_best_stream(m_formatCtx, AVMEDIA_TYPE_VIDEO,-1,-1,NULL,0);
if(m_videoIndex == -1)
{
throw QString("找不到视频");
}
m_codec = avcodec_find_decoder(m_formatCtx->streams[m_videoIndex]->codecpar->codec_id);
m_codecCtx = avcodec_alloc_context3(m_codec);
avcodec_parameters_to_context(m_codecCtx,m_formatCtx->streams[m_videoIndex]->codecpar);
//open codec
if(avcodec_open2(m_codecCtx,m_codec,NULL))
{
throw QString("avcodec_open2 error");
}
//packet frame初始化
m_packet = av_packet_alloc();
m_frame = av_frame_alloc();
//宽度、高度、格式设置
m_frame->width = m_codecCtx->width;
m_frame->height = m_codecCtx->height;
m_frame->format = m_codecCtx->pix_fmt;
}
void VideoDecode::convert(AVFrame *dst, AVFrame *src, AVPixelFormat outPutFormat, AVPixelFormat inPutFormat)
{
dst->width = m_codecCtx