若该文为原创文章,未经容许不得转载
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/108416332
红瘦子 (红模拟) 的博文大全:开发技术汇合(蕴含 Qt 实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬联合等等)继续更新中…(点击传送门)
Qt 开发专栏:我的项目实战(点击传送门)
Qt 开发专栏:三方库开发技术
需要
关上检测摄像头工具,包含分辨率和帧率。
Demo
体验下载地址
CSDN:https://download.csdn.net/download/qq21497936/12815691
QQ 群:1047134658(点击“文件”搜寻“ffmpegCameraTool”,群内与博文同步更新)
波及其余技术
QCameraInfo 关上摄像头偶然拿不到摄像头;
QCamera 动静切换分辨率会导致解体;
QCamera 解决高分辨率存在卡顿问题;
OpenCV 无奈拿取摄像头;
OpenCV 设置高分辨率存在帧率跟不上,卡顿问题;
OpenCV 保留高分辨率视频须要批改源码,否则限度 mat 下限大小为 0xFFFF;
OpenCV 保留高分辨率批改源码后存储视频会导致通道凌乱,须要手动改正色彩通道。
v1.0.0 性能
- 程序启动关上计算机默认第一个摄像头,最高分辨率最高帧率关上;
- 反对动静切换分辨率和帧率;
- 反对原图显示,等比例显示;
- 多个设施终端测试可用;
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/108416332
外围代码
FfmpegCameraManager.h
#ifndef FFMPEGCAMERAMANAGER_H
#define FFMPEGCAMERAMANAGER_H
/************************************************************\
* 控件名称:FfmpegCameraManager, ffmpeg 治理类(用于摄像头操作)* 控件形容:* 1. 关上摄像头
* 2. 反对动静切换分辨率
* 作者:红模拟 联系方式:QQ21497936
* 博客地址:https://blog.csdn.net/qq21497936
* 日期 版本 形容
* 2018 年 09 年 14 日 v1.0.0 ffmpeg 模块封装空类
* 2020 年 09 年 05 日 v1.1.0 ffmpeg 关上摄像头,反对的动静分辨率切换
\************************************************************/
#include <QObject>
#include <QString>
#include <QDebug>
#include <QTimer>
#include <QThread>
#include <QImage>
#include <QProcess>
#include <QMessageBox>
extern "C" {
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavdevice/avdevice.h"
#include "libavformat/version.h"
#include "libavutil/time.h"
#include "libavutil/mathematics.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "errno.h"
#include "error.h"
}
#define LOG qDebug()<<__FILE__<<__LINE__
class FfmpegCameraManager : public QObject
{
Q_OBJECT
public:
public:
explicit FfmpegCameraManager(QObject *parent = nullptr);
signals:
void signal_captureOneFrame(QImage image);
public:
static QString getAvcodecConfiguration();
public:
bool init();
bool openUsbCamera();
QString getUsbCameraName();
QList<QString> getUsbCameraInfo();
public slots:
void slot_start();
void slot_stop();
void slot_setSizeFps(int index);
protected slots:
void slot_captureOneFrame();
signals:
public slots:
private:
static bool _init;
AVFormatContext *_pAVFormatContext; // 全局上下文
AVInputFormat *_pAVInputFormat;
AVDictionary* _pAVDictionary; // 关上编码器的配置
AVCodecContext *_pAVCodecContextForAudio; // 音频解码器上下文
AVCodecContext *_pAVCodecContextForVideo; // 视频解码器上下文(不带音频)AVCodec * _pAVCodecForAudio; // 音频解码器
AVCodec * _pAVCodecForVideo; // 视频解码器(不带音频)int _streamIndexForAudio; // 音频流序号
int _streamIndexForVideo; // 视频流序号
SwrContext *_pSwrContextForAudio; // 音频转换上下文
bool _running;
bool _first;
bool _opened;
uint8_t *_pOutBuffer;
AVFrame * _pFrame;
AVFrame * _pFrameRGB;
AVPacket *_pAVPacket;
SwsContext *_pSwsContext;
int _videoIndex;
QString _cameraDescription;
QList<QSize> _listSize;
QList<int> _listFps;
QList<QString> _listSizeFpsInfo;
int _currentSuzeFpsIndex;
};
#endif // FfmpegCameraManager_H
FfmpegCameraManager.cpp
...
void FfmpegCameraManager::slot_captureOneFrame()
{if(_first)
{
// 读取一个媒体文件的数据包以获取流信息
if(avformat_find_stream_info(_pAVFormatContext, NULL) < 0)
{LOG << "Couldn't find stream information";}else{LOG << "Success find stream information";}
// 循环查找数据包蕴含的流信息,直到找到视频类型的流
// 便将其记录下来 保留到 videoStream 变量中
_videoIndex = -1;
for(int index = 0; index < _pAVFormatContext->nb_streams; index++)
{if(_pAVFormatContext->streams[index]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
_videoIndex = index;
break;
}
}
if(_videoIndex == -1)
{LOG << "Couldn't find a video stream";}else{LOG << "Success find a video stream";}
_pAVCodecContextForVideo = _pAVFormatContext->streams[_videoIndex]->codec;
_pAVCodecForVideo = avcodec_find_decoder(_pAVCodecContextForVideo->codec_id);
// 软编码
// _pAVCodecForVideo = avcodec_find_encoder(AV_CODEC_ID_H264);
// 硬编码
// _pAVCodecForVideo = avcodec_find_encoder_by_name("nvenc_h264");
if(_pAVCodecForVideo == NULL)
{qDebug() << ("Codec not found.\n");
}else{qDebug() << "Codec found Successfuly!\n";
}
if(avcodec_open2(_pAVCodecContextForVideo, _pAVCodecForVideo, NULL) < 0)// 关上解码器
{LOG << "Failed to open codec";}else{LOG << "Success open codec";}
// 调配一个 AVFrame 并将其字段设置为默认值
if(_pFrame == 0)
{_pFrame = av_frame_alloc();
}
if(_pFrameRGB == 0)
{_pFrameRGB = av_frame_alloc();
}
// 调配和返回一个 SwsContext 你须要它来执行应用 swsscale()的缩放 / 转换操作
_pSwsContext = sws_getContext(_pAVCodecContextForVideo->width,
_pAVCodecContextForVideo->height,
_pAVCodecContextForVideo->pix_fmt,
_pAVCodecContextForVideo->width,
_pAVCodecContextForVideo->height,
AV_PIX_FMT_RGB32,
SWS_BICUBIC,
NULL,
NULL,
NULL);
int numBytes = avpicture_get_size(AV_PIX_FMT_RGB32,
_pAVCodecContextForVideo->width,
_pAVCodecContextForVideo->height);
LOG << "numBytes:" << numBytes;
_pOutBuffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));
avpicture_fill((AVPicture *)_pFrameRGB,
_pOutBuffer,
AV_PIX_FMT_RGB32,
_pAVCodecContextForVideo->width,
_pAVCodecContextForVideo->height);// 依据指定的图像参数和提供的图像数据缓冲区设置图像域
int ySize = _pAVCodecContextForVideo->width * _pAVCodecContextForVideo->height;
LOG;
// 调配一个 packet
if(_pAVPacket == 0)
{
LOG;
_pAVPacket = (AVPacket *)malloc(sizeof(AVPacket));
// 调配 packet 的数据
av_new_packet(_pAVPacket, ySize);
}else{
LOG;
av_free_packet(_pAVPacket);
av_new_packet(_pAVPacket, ySize);
LOG;
}
_first = false;
}
// 解码压缩
if(av_read_frame(_pAVFormatContext, _pAVPacket) < 0)
{
LOG << "解码失败";
return;
}
if(_pAVPacket->stream_index == _videoIndex)
{
int gotPicture;
// 解码一帧视频数据
int ret = avcodec_decode_video2(_pAVCodecContextForVideo, _pFrame, &gotPicture, _pAVPacket);
if(ret < 0)
{LOG << "decode error";}
if(gotPicture)
{
// 缩放图像切片,并将失去的缩放切片放在 pFrameRGB->data 图像中
sws_scale(_pSwsContext,
(uint8_t const * const *)_pFrame->data,
_pFrame->linesize,
0,
_pAVCodecContextForVideo->height,
_pFrameRGB->data,
_pFrameRGB->linesize);
QImage tmpImg((uchar *)_pOutBuffer,
_pAVCodecContextForVideo->width,
_pAVCodecContextForVideo->height,
QImage::Format_RGB32);
QImage image = tmpImg.copy();
LOG << "get a pciture";
emit signal_captureOneFrame(image);
QTimer::singleShot(10, this, SLOT(slot_captureOneFrame()));
}
}
}
...
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/108416332