#ifndef DECODEVEDIO_H #define DECODEVEDIO_H #include #include #include #include #include #include #include "RingQueue/RingQueue.hpp" // #include "threadcontroller.h" extern "C" { // #include #include // #include // #include } /** * 使用方式: * 1. 初始化FFmpeg:initFFmpeg() * 2. 开启解码线程:startDecodeVedio() * 3. 获取一帧图像:getOneImage() * 4. 停止解码线程:stopDecodeVedio() * 5. 在初始化完成后,未进入第二步的之前,可以获取视频的宽高信息,也可以设置宽高信息 * */ class DecodeVedio : public QObject { Q_OBJECT public: explicit DecodeVedio(QThread* thread, QObject* parent = nullptr); ~DecodeVedio(); /* 获取硬件解码器 */ void getHWDecoder(); // void setFileName(const QString& fileName) { m_fileName = fileName; } /* 初始化函数 */ void initFFmpeg(const QString& fileName); /* 取消ffmpeg初始化函数 */ void unInitFFmpeg(); /* 获取ffmpeg初始化状态 */ bool isInitFFmpeg() { return m_initFFmpeg; } /* 开始解码视频,开始前先设置视频名称 */ void startDecodeVedio(); /* 停止解码视频,也是停止线程 */ void stopDecodeVedio(); /* 设置当前播放位置 */ void setCurrentPos(quint64 pos); /* 获取当前播放位置 */ qint64 getCurrentPos(); /* 获取视频时长 */ qint64 getDuration(); /* 获取解码线程是否运行 */ bool isRunning() { return m_isRunning; } /* 唤醒队列非空条件变量 */ void wakeUpCondQueueNoEmpty(); /* 获取一帧图像 */ QImage* getOneImage(); /* 获取一帧图像,直到有图像为止 */ QImage* getOneImageUntilHave(); /* 获取帧数 */ int getFrameCount(); /* 获取图像宽度 */ int getSrcVideoWidth() const {return m_srcWidth;} /* 获取图像高度 */ int getSrcVideoHeight() const {return m_srcHeight;} /* 设置图像宽度和高度 */ void setVideoSize(int width,int height); signals: void signal_oneImage(); /* 一帧图像信号 */ void signal_playCompleted(); /* 播放完成信号 */ private: void freeFFmpeg(); /* 取消ffmpeg初始化函数 */ void decodeVedio(); /* 解码视频的工作函数,这个就是新线程 */ void decodeUsingCPU(); /* 软解码线程 */ void exitThread(); /* 退出线程 */ void pauseDecode(); /* 暂停解码 */ qreal rationalToDouble(AVRational* rational); /* 将AVRational转换为double */ void freeAll(); /* 释放所有资源 */ private slots: void do_startDecodeVedio(); /* 开启解码 */ private: QThread* m_thread = nullptr; /* 解码线程 */ std::atomic_bool m_isRunning = false; /* 解码线程是否运行 */ QTimer m_startThread; /* 开启线程的定时器 */ std::atomic_bool m_initFFmpeg = false; /* ffmpeg初始化标志 */ std::atomic_bool m_threadStopped = false; /* 停止线程 */ std::atomic_bool m_pauseDecode = false; /* 暂停解码 */ std::atomic_bool m_decodeStatus = false; /* 解码状态,这里主要是检测是否暂停解码 */ std::atomic_bool m_isSeek = false; /* 是否跳转 */ QString m_fileName; /* 解码的视频文件名称 */ AVFormatContext *m_pFormatContext = nullptr; /* 格式上下文,贯穿全局 */ AVCodecContext *m_pCodecCtx = nullptr; /* 解码器上下文 */ AVPacket* m_packet = nullptr; /* 存储解码前的数据,一个数据包 */ AVFrame* m_pFrame = nullptr; /* 存储解码后的一帧数据原始视频编码 */ AVFrame* m_pFrameRGB = nullptr; /* 存储解码后的一帧数据,RGB格式 */ AVFrame* m_pFrameHW = nullptr; /* 存储解码后的一帧数据,硬件解码 */ struct SwsContext *m_sws_ctx = nullptr; /* 视频转换上下文 */ uint8_t *m_buffer = nullptr; /* 存储解码后的一帧数据,RGB格式 */ int m_videoStream = -1; /* 记录视频流是第几个流 */ int m_srcWidth = 0; /* 图片原本宽度 */ int m_srcHeight = 0; /* 图片原本高度 */ int m_width = 0; /* 图像宽度 */ int m_height = 0; /* 图像高度 */ int m_totalFrame = 0; /* 视频总帧数 */ int m_fps; /* 每秒的帧数 */ quint64 m_currentFrame = 0; /* 当前已播放的帧数 */ quint64 m_pts = 0; /* 当前帧显示时间 */ qint64 m_duration = 0; /* 视频时长 */ qint64 m_currentPos = 0; /* 当前播放位置 */ qint64 m_startPos = 0; /* 起始位置,后续操作都需要在这各基础上操作 */ // QImage *m_image = nullptr; int m_queueMaxNum = 10; /* 这里不是环形队列,最大设置为30帧图像 */ QQueue m_queueImage; /* 视频帧队列 */ QMutex m_mutexQueue; /* 队列互斥锁 */ QWaitCondition m_condQueueNoFull; /* 队列不满,可以入队 */ QWaitCondition m_condQueueNoEmpty; /* 队列非空,可以读取 */ QList m_listHWDeviceType; /* 保存当前环境支持的硬件解码器 */ AVBufferRef* m_hw_device_ctx = nullptr; /* 对数据缓冲区的引用 */ RingQueue m_ringQueue; /* 环形队列,存储生成的图像 */ }; #endif /* DECODEVEDIO_H */