123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- #ifndef DECODEVEDIO_H
- #define DECODEVEDIO_H
- #include <QObject>
- #include <QQueue>
- #include <QTimer>
- #include <QMutex>
- #include <QWaitCondition>
- #include <QImage>
- #include "RingQueue/RingQueue.hpp"
- // #include "threadcontroller.h"
- 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_OBJECT
- enum 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 */
|