소스 검색

V0.3.7
1、修改了视频解码转换成QImage的格式,改为了RGBA
2、修改了部分其他的解码流程

Apple 6 달 전
부모
커밋
a5b1eec9c7

+ 1 - 1
CMakeLists.txt

@@ -116,7 +116,7 @@ find_package(Qt5 COMPONENTS
 )
 
 include(${CMAKE_SOURCE_DIR}/External/Libraries/Libraries.cmake)
-# include(${CMAKE_SOURCE_DIR}/External_Linux/Library_EX.cmake)
+include(${CMAKE_SOURCE_DIR}/External_Ex/Library_EX.cmake)
 
 
 #=========================================================

+ 1 - 1
External

@@ -1 +1 @@
-/home/Apple/Design/Library/Standard_Library
+/home/Apple/Lib/Standard_Library

+ 1 - 0
External_Ex

@@ -0,0 +1 @@
+/home/Apple/Lib/Library_Ex/

+ 2 - 2
demo/VideoPlayer/CMakeLists.txt

@@ -41,7 +41,7 @@ target_include_directories(${this_exe} PRIVATE
     ${CMAKE_SOURCE_DIR}/External/common/RingQueue
     
     ${CURL_INCLUDE_DIR}
-    # ${FFMPEG2_INCLUDE_DIR}
+    ${FFMPEG_INCLUDE_DIR}
 )
 
 target_link_libraries(${this_exe} PRIVATE
@@ -57,7 +57,7 @@ target_link_libraries(${this_exe} PRIVATE
     fmt::fmt
     spdlog::spdlog
     ${CURL_LIBRARY}
-    # ${FFMPEG2_LIBRARY}
+    ${FFMPEG_LIBRARY}
 )
 
 if(CMAKE_CXX_COMPILER_VERSION LESS 9.0)

+ 19 - 22
demo/VideoPlayer/VideoPlayer/DecodeVedio.cpp

@@ -70,11 +70,12 @@ void DecodeVedio::getHWDecoder()
             strTypes.append(QString(typeName));
         }
     }
-    FMTLOG_INFO_NON("支持的硬件解码器:");
+    FMTLOG_INFO("支持的硬件解码器:");
     for(auto type : strTypes)
     {
         FMTLOG_INFO_NON(" {}",type.toStdString());
     }
+    FMTLOG_INFO_NON("\n");
 }
 
 /* 开始解码视频 */
@@ -365,7 +366,7 @@ void DecodeVedio::initFFmpeg(const QString& fileName)
     }
 
     ret = 0;
-    /* 检查视频容器内部的流信息,将流存储到了pFormatContext->streams中
+    /* 检查视频容器内部的流信息,将所有流存储到了pFormatContext->streams中
      * 这个会补充avformat_open_input()没有获取到的信息 */
     ret = avformat_find_stream_info(m_pFormatContext, nullptr);
     if(ret < 0)
@@ -382,24 +383,15 @@ void DecodeVedio::initFFmpeg(const QString& fileName)
     av_dump_format(m_pFormatContext, 0, m_fileName.toStdString().c_str(), 0);
 
     /************ 找到视频流 ************/
-    int i = 0;
-    AVCodecParameters *pCodecCtxOrig = nullptr;
-    
-    for(i = 0;i < m_pFormatContext->nb_streams; i++)
-    {
-        if(m_pFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
-        {
-            m_videoStream = i;
-            break;
-        }
-    }
-    if(m_videoStream == -1)
+    m_videoStream = av_find_best_stream(m_pFormatContext, AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0);
+    if(m_videoStream < 0)
     {
         SPDLOG_WARN("没有找到视频流");
         return;
     }
     SPDLOG_INFO("找到视频流");
-    
+    /* 获取视频流的编解码信息 */
+    AVCodecParameters *pCodecCtxOrig = nullptr;
     pCodecCtxOrig = m_pFormatContext->streams[m_videoStream]->codecpar;
     SPDLOG_INFO("获取视频流参数成功!");
     /* 使用编码器指向流 */
@@ -411,8 +403,8 @@ void DecodeVedio::initFFmpeg(const QString& fileName)
         SPDLOG_WARN("没有找到解码器");
         return;
     }
-    SPDLOG_TRACE("找到解码器");
-    /* 复制上下文,先分配空间,后面记得释放空间 */
+    SPDLOG_INFO("找到解码器 :{}",pCodec->name);
+    /* 获取视频信息的上下文,先分配空间,后面记得释放空间 */
     m_pCodecCtx = avcodec_alloc_context3(pCodec);
     SPDLOG_TRACE("分配空间成功!");
     /* 将视频流中的编码器参数拷贝下来,这个函数不是线程安全的 */
@@ -422,7 +414,11 @@ void DecodeVedio::initFFmpeg(const QString& fileName)
         return;
     }
     SPDLOG_INFO("复制上下文成功!");
-    if(avcodec_open2(m_pCodecCtx, pCodec, nullptr) < 0)
+
+    /*************** 初始化硬件解码器 ******************/
+
+    /* 打开解码器,(初始化解码器上下文,如果调用了avcodec_alloc_context3,第二个参数可以设置为nullptr) */
+    if(avcodec_open2(m_pCodecCtx, nullptr, nullptr) < 0)
     {
         SPDLOG_ERROR("打开解码器错误");
         return;
@@ -450,7 +446,7 @@ void DecodeVedio::initFFmpeg(const QString& fileName)
     
     int numBytes = 0;
     /* 初始化pFrameRGB */
-    numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, m_pCodecCtx->width, m_pCodecCtx->height, 1);
+    numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGBA, m_pCodecCtx->width, m_pCodecCtx->height, 1);
     m_buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t));
     /* 获取视频相关信息 */
     m_width = m_srcWidth = m_pCodecCtx->width;
@@ -458,13 +454,13 @@ void DecodeVedio::initFFmpeg(const QString& fileName)
     m_frameCount = m_pFormatContext->streams[m_videoStream]->nb_frames;
     
     /* 这个函数的实际作用是将buffer设置给pFrameRGB作为原始数据的内存区域 */
-    av_image_fill_arrays(m_pFrameRGB->data, m_pFrameRGB->linesize, m_buffer, AV_PIX_FMT_RGB24, m_pCodecCtx->width, m_pCodecCtx->height, 1);
+    av_image_fill_arrays(m_pFrameRGB->data, m_pFrameRGB->linesize, m_buffer, AV_PIX_FMT_RGBA, m_pCodecCtx->width, m_pCodecCtx->height, 1);
 
     /********** 创建一个SwsContext结构体,主要为了格式转化的时候使用 ***********/
     
     /* 初始化Sws Context,这是转换规则,转换成RGB */
     m_sws_ctx = sws_getContext( m_pCodecCtx->width, m_pCodecCtx->height, m_pCodecCtx->pix_fmt,    /* 原图像大小和格式 */
-                                m_srcWidth, m_srcHeight, AV_PIX_FMT_RGB24,      /* 目标图像的大小和格式 */
+                                m_srcWidth, m_srcHeight, AV_PIX_FMT_RGBA,      /* 目标图像的大小和格式 */
                                 SWS_BILINEAR,           /* 双线性 */
                                 nullptr, 
                                 nullptr, 
@@ -597,7 +593,8 @@ void DecodeVedio::decodeVedio()
                     // std::chrono::steady_clock::time_point t7 = std::chrono::steady_clock::now();
                     // SPDLOG_TRACE("======================================= 转换RGB耗时:{}",std::chrono::duration_cast<std::chrono::milliseconds>(t7 - t6).count());
                     /* 一帧图像入队 */
-                    auto image = new QImage(m_pFrameRGB->data[0], m_width, m_height, QImage::Format_RGB888);
+                    // auto image = new QImage(m_pFrameRGB->data[0], m_width, m_height, QImage::Format_RGB888);
+                    auto image = new QImage(m_pFrameRGB->data[0], m_width, m_height, QImage::Format_RGBA8888);
                     // SPDLOG_DEBUG("队列中图片个数:{} ",m_queueImage.count());
                     m_mutexQueue.lock();
                     if(m_queueImage.count() >= m_queueMaxNum)

+ 101 - 1
demo/VideoPlayer/VideoPlayer/VideoPlayer.cpp

@@ -5,8 +5,10 @@
 #include <QPainter>
 #include <QResizeEvent>
 #include <QEventLoop>
+#include <QVBoxLayout>
 
 #include "spdlog/spdlog.h"
+#include "FmtLog/fmtlog.h"
 
 
 
@@ -58,6 +60,11 @@ void VideoPlayer::setPlayVedio(const QString& fileName)
     {
         m_decodeVedio->unInitFFmpeg();
     }
+    if(fileName.isEmpty())
+    {
+        SPDLOG_WARN("文件名为空");
+        return;
+    }
     m_fileName = fileName;
     isSetVedioFile = true;
     m_decodeVedio->initFFmpeg(m_fileName);
@@ -155,6 +162,30 @@ void VideoPlayer::stop()
     // isSetVedioFile = false;
 }
 
+/* 后退,单位ms */
+void VideoPlayer::backward(quint64 ms)
+{
+    /* 获取当前位置 */
+    qint64 pos = m_decodeVedio->getCurrentPos();
+    pos = pos - ( ms * 1000 );
+    if(pos < 0)
+    {
+        pos = 0;
+    }
+
+    setCurrentPos(pos);
+}
+
+/* 前进,单位ms */
+void VideoPlayer::forward(quint64 ms)
+{
+    /* 获取当前位置 */
+    qint64 pos = m_decodeVedio->getCurrentPos();
+    pos = pos + ( ms * 1000 );
+
+    setCurrentPos(pos);
+}
+
 /* 获取视频时长 */
 qint64 VideoPlayer::getDuration()
 {
@@ -167,7 +198,7 @@ qint64 VideoPlayer::getCurrentPos()
     return m_decodeVedio->getCurrentPos();
 }
 
-/* 设置当前播放位置 */
+/* 设置当前播放位置,单位us */
 void VideoPlayer::setCurrentPos(quint64 pos)
 {
     /* 先停止播放 */
@@ -231,6 +262,75 @@ void VideoPlayer::setPlayVedioSize(int width,int height)
     SPDLOG_DEBUG("现在位置和大小:{}x{}, {}x{}", this->pos().rx(), this->pos().ry(), this->width(), this->height());
 }
 
+/**
+ * @brief 设置播放窗口,这用于独占一个传入的widget,这里会自动添加一个布局,外面窗口变化,这里也跟随着变化
+ * 
+ * @param widget 
+ */
+void VideoPlayer::setPlayWidget(QWidget* widget)
+{
+    if(widget == nullptr)
+    {
+        SPDLOG_WARN("传入的widget为空");
+        return;
+    }
+    /* 设置布局 */
+    QVBoxLayout* layout = new QVBoxLayout(widget);
+    layout->addWidget(this);
+    layout->setMargin(0);
+    layout->setSpacing(0);
+    widget->setLayout(layout);
+    /* 设置窗口大小 */
+    setPlayVedioSize(widget->width(), widget->height());
+}
+
+/* 列出当前环境支持的硬件解码器 */
+void VideoPlayer::ListHWDecoder()
+{
+    AVHWDeviceType type = AV_HWDEVICE_TYPE_NONE;
+    QStringList strTypes;
+    QList<int> listHWDeviceType;
+    while( (type = av_hwdevice_iterate_types(type)) != AV_HWDEVICE_TYPE_NONE)
+    {
+        listHWDeviceType.append(type);
+        /* 获取硬件解码器的名称 */
+        const char* typeName = av_hwdevice_get_type_name(type);
+        if(typeName)
+        {
+            strTypes.append(QString(typeName));
+        }
+    }
+    FMTLOG_INFO("支持的硬件解码器个数:{} ", listHWDeviceType.size());
+    for(auto type : strTypes)
+    {
+        FMTLOG_INFO_NON(" {}",type.toStdString());
+    }
+    FMTLOG_INFO_NON("\n");
+    
+    // const AVCodec* codec = nullptr;
+    // void* iter = nullptr;
+
+    // while ( (codec = av_codec_iterate(&iter)) != nullptr)
+    // {
+    //     if(codec->type == AVMEDIA_TYPE_VIDEO)
+    //     {
+    //         FMTLOG_INFO("解码器:{}", codec->name);
+    //         const AVCodecHWConfig* config = nullptr;
+    //         int i = 0;
+    //         while( (config = avcodec_get_hw_config(codec, i)) )
+    //         {
+    //             if(config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX)
+    //             {
+    //                 FMTLOG_INFO("解码器:{}, 支持硬件解码器:{}",codec->name, av_hwdevice_get_type_name(config->device_type));
+    //                 i++;
+    //             }
+    //         }
+            
+    //     }
+    
+    // }
+}
+
 /* 设置播放回调函数 */
 // void VideoPlayer::setPlayCallBack(std::function<Play_CallBack> playCallBack,void* context)
 // {

+ 6 - 1
demo/VideoPlayer/VideoPlayer/VideoPlayer.h

@@ -19,11 +19,16 @@ public:
     bool play();                                    /* 播放视频 */
     void pause();                                   /* 暂停播放 */
     void stop();                                    /* 停止播放 */
+    void backward(quint64 ms);                      /* 后退,单位ms */
+    void forward(quint64 ms);                       /* 前进,单位ms */
     bool getPlayStatus() { return m_playStatus; }   /* 获取播放状态 */
     qint64 getDuration();                           /* 获取视频时长 */
     qint64 getCurrentPos();                         /* 获取当前播放位置 */
     void setCurrentPos(quint64 pos);                /* 设置当前播放位置 */
     void setPlayVedioSize(int width,int height);    /* 设置播放视频大小 */
+    void setPlayWidget(QWidget* widget);            /* 设置播放窗口 */
+
+    static void ListHWDecoder();                    /* 列出当前环境支持的硬件解码器 */
 
     // void setPlayCallBack(std::function<Play_CallBack> playCallBack,void* context);  /* 设置播放回调函数 */
 protected:
@@ -41,7 +46,7 @@ private slots:
 private:
     QString m_fileName;
     QTimer m_timerRefreshUI;                        /* 定时器,用于刷新界面 */
-    int m_srcWidth = 0;                             /* 图片原本大小 */
+    int m_srcWidth = 0;                             /* 视频原本大小 */
     int m_srcHeight = 0;
     int m_nowWidth = 0;                             /* 现在大小 */
     int m_nowHeight = 0;

+ 7 - 2
demo/VideoPlayer/main.cpp

@@ -3,9 +3,12 @@
 #include <QApplication>
 #include "Logs/loginit.h"
 #include "spdlog/spdlog.h"
+#include "FmtLog/fmtlog.h"
 
-
-
+extern "C" {
+#include <libavcodec/avcodec.h>
+#include <libavutil/hwcontext.h>
+}
 
 int main(int argc, char *argv[])
 {
@@ -14,6 +17,8 @@ int main(int argc, char *argv[])
 
     SPDLOG_INFO("********** VideoPlayer **********");
 
+
+
     Widget w;
     w.show();
 

+ 53 - 4
demo/VideoPlayer/widget.cpp

@@ -2,10 +2,11 @@
 #include "./ui_widget.h"
 
 #include <QTimer>
+#include <QFileDialog>
 
 #include "spdlog/spdlog.h"
 #include "fmtlog.h"
-#include "VideoPlayer.h"
+
 
 
 Widget::Widget(QWidget *parent)
@@ -14,8 +15,11 @@ Widget::Widget(QWidget *parent)
 {
     ui->setupUi(this);
 
-
+    m_videoPlayer = std::make_shared<VideoPlayer>();
+    m_videoPlayer->setPlayWidget(ui->widget_display);
     SPDLOG_INFO("***** Qt Library *****");
+    
+    // VideoPlayer::ListHWDecoder();
 }
 
 Widget::~Widget()
@@ -28,10 +32,55 @@ Widget::~Widget()
 void Widget::on_pBtn_openVideo_clicked()
 {
     SPDLOG_INFO("点击了“打开视频”按钮");
+    QFileDialog fileDialog(this);
+    fileDialog.setWindowTitle("选择视频文件");
+    fileDialog.setFileMode(QFileDialog::ExistingFiles);
+    fileDialog.setNameFilter("视频文件(*.mp4 *.avi *.flv *.mkv *.rmvb *.rm *.3gp *.wmv *.asf *.mov *.m4v *.dat *.vob *.mpg *.mpeg *.ts *.tp *.trp *.m2ts *.mts *.m2t *.m2p *.ps *.tp *.trp *.webm *.f4v *.swf *.avchd *.h264 *.h265 *.hevc *.vp9 *.vp8 *.vp6 *.vp10 *.rmvb *.rm *.3gp *.wmv *.asf *.mov *.m4v *.dat *.vob *.mpg *.mpeg *.ts *.tp *.trp *.m2ts *.mts *.m2t *.m2p *.ps *.tp *.trp *.webm *.f4v *.swf *.avchd *.h264 *.h265 *.hevc *.vp9 *.vp8 *.vp6 *.vp10)");
+    fileDialog.setDirectory(QApplication::applicationDirPath());
+    if (fileDialog.exec())
+    {
+        QStringList files = fileDialog.selectedFiles();
+        if (files.size() > 0)
+        {
+            ui->lineEdit->setText(files[0]);
+        }
+    }
+
+    m_videoPlayer->setPlayVedio(ui->lineEdit->text());
     
-    std::shared_ptr<VideoPlayer> videoPlayer = std::make_shared<VideoPlayer>();
-    
 }
 
+void Widget::on_pBtn_play_clicked()
+{
+    SPDLOG_INFO("点击了“播放”按钮");
+    m_videoPlayer->play();
+}
+
+void Widget::on_pBtn_pause_clicked()
+{
+    SPDLOG_INFO("点击了“暂停”按钮");
+    m_videoPlayer->pause();
+}
+
+void Widget::on_pBtn_stop_clicked()
+{
+    SPDLOG_INFO("点击了“停止”按钮");
+    m_videoPlayer->stop();
+}
+
+void Widget::on_pBtn_backward_clicked()
+{
+    SPDLOG_INFO("点击了“后退”按钮");
+    m_videoPlayer->backward(10000);
+}
+
+void Widget::on_pBtn_forward_clicked()
+{
+    SPDLOG_INFO("点击了“前进”按钮");
+    m_videoPlayer->forward(10000);
+}
+
+
+
 
 

+ 13 - 0
demo/VideoPlayer/widget.h

@@ -2,6 +2,7 @@
 #define WIDGET_H
 
 #include <QWidget>
+#include "VideoPlayer.h"
 
 QT_BEGIN_NAMESPACE
 namespace Ui { class Widget; }
@@ -19,9 +20,21 @@ private slots:
 
     void on_pBtn_openVideo_clicked();
 
+    void on_pBtn_play_clicked();
 
+    void on_pBtn_pause_clicked();
+
+    void on_pBtn_stop_clicked();
+
+    void on_pBtn_backward_clicked();
+
+    void on_pBtn_forward_clicked();
+
+    
 private:
     Ui::Widget *ui;
 
+    std::shared_ptr<VideoPlayer> m_videoPlayer = nullptr;
+
 };
 #endif // WIDGET_H

+ 70 - 24
demo/VideoPlayer/widget.ui

@@ -6,35 +6,81 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>800</width>
-    <height>600</height>
+    <width>1600</width>
+    <height>900</height>
    </rect>
   </property>
   <property name="windowTitle">
    <string>Widget</string>
   </property>
-  <widget class="QWidget" name="widget_pBtn" native="true">
-   <property name="geometry">
-    <rect>
-     <x>30</x>
-     <y>30</y>
-     <width>681</width>
-     <height>311</height>
-    </rect>
-   </property>
-   <layout class="QGridLayout" name="gridLayout">
-    <item row="0" column="0">
-     <widget class="QPushButton" name="pBtn_openVideo">
-      <property name="text">
-       <string>打开视频</string>
-      </property>
-     </widget>
-    </item>
-    <item row="1" column="0" colspan="2">
-     <widget class="QLineEdit" name="lineEdit"/>
-    </item>
-   </layout>
-  </widget>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QWidget" name="widget_pBtn" native="true">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="minimumSize">
+      <size>
+       <width>1200</width>
+       <height>200</height>
+      </size>
+     </property>
+     <layout class="QGridLayout" name="gridLayout">
+      <item row="3" column="0" colspan="2">
+       <widget class="QLineEdit" name="lineEdit"/>
+      </item>
+      <item row="2" column="1">
+       <widget class="QPushButton" name="pBtn_stop">
+        <property name="text">
+         <string>停止</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="1">
+       <widget class="QPushButton" name="pBtn_pause">
+        <property name="text">
+         <string>暂停</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="0">
+       <widget class="QPushButton" name="pBtn_openVideo">
+        <property name="text">
+         <string>打开视频</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="1">
+       <widget class="QPushButton" name="pBtn_play">
+        <property name="text">
+         <string>播放</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="0">
+       <widget class="QPushButton" name="pBtn_backward">
+        <property name="text">
+         <string>后退</string>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="0">
+       <widget class="QPushButton" name="pBtn_forward">
+        <property name="text">
+         <string>前进</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="widget_display" native="true"/>
+   </item>
+  </layout>
  </widget>
  <resources/>
  <connections/>