关于ffmpeg:项目实战Qtffmpeg摄像头检测工具

46次阅读

共计 5925 个字符,预计需要花费 15 分钟才能阅读完成。

若该文为原创文章,未经容许不得转载
原博主博客地址: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

正文完
 0