美文网首页
项目实战:Qt+ffmpeg摄像头检测工具

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

作者: 红模仿_红胖子 | 来源:发表于2020-09-05 11:14 被阅读0次

    原博主博客地址: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

    相关文章

      网友评论

          本文标题:项目实战:Qt+ffmpeg摄像头检测工具

          本文链接:https://www.haomeiwen.com/subject/yygxektx.html