| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 | #ifndef DECODEVEDIO_H#define DECODEVEDIO_H#include <QObject>#include <QQueue>#include <QTimer>#include <QMutex>#include <QWaitCondition>#include <QImage>#include "RingQueue/RingQueue.hpp"extern "C"{#include <libavcodec/avcodec.h>#include <libavformat/avformat.h>// #include <libswscale/swscale.h>// #include <libavutil/imgutils.h>}/** * 使用方式: *      1. 初始化FFmpeg:initFFmpeg() *      2. 开启解码线程:startDecodeVedio() *      3. 获取一帧图像:getOneImage() *      4. 停止解码线程:stopDecodeVedio() *      5. 在初始化完成后,未进入第二步的之前,可以获取视频的宽高信息,也可以设置宽高信息 *       */class DecodeVedio : public QObject{    Q_OBJECTenum class DecodeState{    NONE = 0,    DecodeRun,          /* 解码运行中 */    DecodePause,        /* 暂停解码 */    DecodeSeek,         /* 跳转中 */    DecodeStop,         /* 停止解码,但是并没有退出解码线程 */    DecodeExit          /* 退出解码 */};public:    explicit DecodeVedio(QThread* thread, QObject* parent = nullptr);    ~DecodeVedio();    /* 打开视频,同时初始化解码器) */    void openVedio(const QString& fileName);        /* 开始解码视频,开始前先打开视频文件 */    void startDecodeVedio();    /* 停止解码视频,也是停止线程 */    void stopDecodeVedio();    /* 获取解码状态 */    bool isDecoding() { return m_threadRuning; }    /* 设置当前播放位置,单位ms */    void setCurrentPos(qint64 pos);    /* 获取当前播放位置,单位ms */    qint64 getCurrentPos();    /* 获取视频时长 */    qint64 getDuration();    qint64 getTotalFrame() { return m_totalFrame; }        /* 获取一帧图像 */    QImage* getOneImage();    /* 获取一帧图像,直到有图像为止,可以设置超时时间 */    QImage* getOneImageUntilHave(int timeOut = -1);    /* 获取帧数 */    int getFPS() const { return m_fps; }    /* 设置帧数 */    void setFPS(int fps) { m_fps = fps; }    /* 获取图像宽度 */    QSize getSrcVideoSize() const {return m_srcSize; }    /* 获取解码器名称(编码格式) */    QString getDecoderName() const { return m_decoderName; }    /* 获取硬件解码器名称列表 */    QStringList getHWDecoderList() const { return m_listDecoderName; }    /* 查找硬件解码器 */    static void findHWDecoder(QStringList& listDecoderName);signals:    void signal_oneImage();                         /* 一帧图像信号 */    void signal_playCompleted();                    /* 播放完成信号 */    void signal_startDecode();                      /* 开始解码信号 */private:    /* 查找硬件解码器 */    void findHWDecoder();    /* 初始化硬件解码器 */    void initHWDecoder(const AVCodec* codec);    /* 拷贝数据,从GPU显存拷贝到内存中 */    bool copyDataFromGPU(AVFrame* pFrameHW, AVFrame* pFrameSRC);                    /* 软解码线程 */           void threadDecodeUsingCPU();         /* 硬件解码线程 */    void threadDecodeUsingGPU();    /* 退出线程 */          void exitThread();    /* 暂停解码 */    void pauseDecode();    /* 继续解码 */    void continueDecode();    /* 将AVRational转换为double */    qreal rationalToDouble(AVRational* rational);    /* 释放所有资源 */    void freeAll();private slots:    void do_startDecodeVedio();                     /* 开启解码 */private:    QThread* m_thread = nullptr;                    /* 解码线程 */    /* 线程状态 */    std::atomic_bool m_threadRuning;                /* 解码线程是运行标志 */    std::atomic_bool m_initFFmpeg;                  /* ffmpeg初始化标志 */    std::atomic_bool m_pauseDecode;                 /* 暂停解码 */    std::atomic_bool m_decodeStatus;                /* 解码状态,这里主要是检测是否暂停解码 */    std::atomic_bool m_isSeek;                      /* 是否在跳转中 */    std::atomic_bool m_flushDecoder;                /* 刷新解码器 */    std::atomic<DecodeState> m_decodeState;    /* 视频解码相关变量信息 */    QString m_fileName;                             /* 解码的视频文件名称 */    AVFormatContext *m_pFormatContext = nullptr;    /* 格式上下文,贯穿全局 */    AVCodecContext *m_pCodecContext = nullptr;      /* 解码器上下文 */    AVPacket* m_packet = nullptr;                   /* 存储解码前的数据,一个数据包 */    AVFrame* m_pFrameSRC = nullptr;                 /* 存储解码后的一帧数据原始视频编码 */    AVFrame* m_pFrameHW = nullptr;                  /* 存储解码后的一帧数据,硬件解码 */    struct SwsContext *m_sws_ctx = nullptr;         /* 视频转换上下文 */    uint8_t *m_buffer = nullptr;                    /* 存储解码后的一帧数据,RGB格式 */    int m_videoStream = -1;                         /* 记录视频流是第几个流 */        bool m_supportHWDecoder = false;                /* 是否使用硬件解码 */    AVBufferRef* m_hw_device_ctx = nullptr;         /* 对数据缓冲区的引用 */    QList<int> m_listHWDeviceType;                  /* 保存当前环境支持的硬件解码器 */    QStringList m_listDecoderName;                  /* 硬件解码器列表名称 */    /* 视频相关信息 */    QSize m_srcSize;                                /* 原始视频分辨率大小 */    qint64 m_totalFrame = 0;                        /* 视频总帧数 */    int m_fps = 0;                                  /* 每秒的帧数 */    qint64 m_duration = 0;                          /* 视频时长,单位毫秒 */    qint64 m_startPos = 0;                          /* 开始播放的位置,摄像机视频的位置不是从0开始的,需要在初始化的时候取出这个值 */    std::atomic<qint64> m_pts;                      /* 当前帧显示时间,也就是当前的进度时间 */        qint64 m_targetPos = -1;                        /* 跳转的目标播放位置 */    qint64 m_currentFrame = 0;                      /* 当前已播放的帧数 */    QString m_decoderName;                          /* 解码器名称 */    RingQueue<QImage*> m_queueImage;                /* 环形队列,存储生成的图像 */    };#endif /* DECODEVEDIO_H */
 |