项目实战:Qt+ffmpeg摄像头检测工具

简介: 项目实战:Qt+ffmpeg摄像头检测工具

需求

  打开检测摄像头工具,包括分辨率和帧率。


Demo

  

  

体验下载地址

  CSDN:https://download.csdn.net/download/qq21497936/12815691

  QQ群:1047134658(点击“文件”搜索“ffmpegCameraTool”,群内与博文同步更新)


涉及其他技术

  QCameraInfo打开摄像头偶尔拿不到摄像头;

  QCamera动态切换分辨率会导致崩溃;

  QCamera处理高分辨率存在卡顿问题;

  OpenCV无法拿取摄像头;

  OpenCV设置高分辨率存在帧率跟不上,卡顿问题;

  OpenCV保存高分辨率视频需要修改源码,否则限制mat上限大小为0xFFFF;

  OpenCV保存高分辨率修改源码后存储视频会导致通道混乱,需要手动矫正颜色通道。


相关博客

  《项目实战:Qt+Ffmpeg+OpenCV相机程序(打开摄像头、支持多种摄像头、分辨率调整、翻转、旋转、亮度调整、拍照、录像、回放图片、回放录像)
  《项目实战:Qt+ffmpeg摄像头检测工具
  《项目实战:使用OpenCV库操作摄像头拍照、调节参数和视频录制
  《项目实战:使用OpenCV库的视频播放器(支持播放器操作,如暂停、恢复、停止、时间、进度条拽托等)
  《OpenCV开发专栏
  《OpenCV开发笔记(四):OpenCV图片和视频数据的读取与存储
  《OpenCV开发笔记(五):OpenCV读取与操作摄像头

  FFmpeg开发笔记(一):ffmpeg介绍、windows开发环境搭建(mingw和msvc)


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()));
        }
    }
}
...



相关文章
|
7月前
|
编解码
项目实战——Qt实现FFmpeg音视频转码器(二)
项目实战——Qt实现FFmpeg音视频转码器(二)
141 0
|
7月前
|
编解码 编译器
项目实战——Qt实现FFmpeg音视频转码器(一)
项目实战——Qt实现FFmpeg音视频转码器(一)
210 0
|
7月前
|
编解码 监控 计算机视觉
QT5.14.2 视频分帧:QT与FFmpeg的高效结合
QT5.14.2 视频分帧:QT与FFmpeg的高效结合
410 0
|
2月前
|
缓存 监控 计算机视觉
视频监控笔记(三):opencv结合ffmpeg获取rtsp摄像头相关信息
本文介绍了如何使用OpenCV结合FFmpeg获取RTSP摄像头信息,包括网络架构、视频监控系统组成、以及如何读取和显示网络摄像头视频流。
69 1
|
7月前
|
编解码 算法 vr&ar
深度剖析FFmpeg视频解码后的帧处理到Qt显示 从AVFrame到QImage的转换(二)
深度剖析FFmpeg视频解码后的帧处理到Qt显示 从AVFrame到QImage的转换
263 1
|
7月前
|
存储 编解码 算法
深度剖析FFmpeg视频解码后的帧处理到Qt显示 从AVFrame到QImage的转换(一)
深度剖析FFmpeg视频解码后的帧处理到Qt显示 从AVFrame到QImage的转换
528 1
|
6月前
|
编解码 Linux 计算机视觉
python 调用ffmpeg使用usb摄像头录制视频,输出h264格式,自动获取摄像头的最佳帧率和最大画面尺寸
使用 Python 调用 FFmpeg 进行 USB 摄像头视频录制,需先确保安装 FFmpeg 和 Python 的 `subprocess` 模块。代码示例展示了如何自动获取摄像头的最佳帧率和最大分辨率,然后录制视频。首先通过 FFmpeg 列出摄像头格式获取信息,解析出帧率和分辨率,选择最优值。之后调用 FFmpeg 命令录制视频,设置帧率、分辨率等参数。注意 `/dev/video0` 是 Linux 的摄像头设备路径,Windows 系统需相应调整。代码中未直接实现自动获取最佳参数,通常需要借助其他库如 OpenCV。
|
7月前
qt开发使用camera类获取摄像头信息并拍照保存
qt开发使用camera类获取摄像头信息并拍照保存
233 0
|
7月前
|
编解码 API 数据处理
【摄像头数据处理】摄像头数据处理:使用FFmpeg合并、编码和封装视频流
【摄像头数据处理】摄像头数据处理:使用FFmpeg合并、编码和封装视频流
405 0
|
7月前
|
编解码 Android开发 开发者
QT5.14.2 VS2022环境下FFmpeg与QT的完美邂逅
QT5.14.2 VS2022环境下FFmpeg与QT的完美邂逅
385 0