Browse Source

V0.3
1、修改了RingQueue.hpp环形队列
2、添加了普通的绘制窗口

Apple 3 weeks ago
parent
commit
672e5f821f

+ 1 - 0
CPlayer/Player/PlayerGLWidget.cpp

@@ -17,6 +17,7 @@ void PlayerGLWidget::updateFrame(Image_YUV420& image)
     yData = image.yData;
     uData = image.uData;
     vData = image.vData;
+    update();
 }
 
 

+ 51 - 0
CPlayer/Player/PlayerWidget.cpp

@@ -0,0 +1,51 @@
+#include "PlayerWidget.h"
+
+#include <QResizeEvent>
+
+
+PlayerWidget::PlayerWidget(QWidget *parent)
+{
+    m_windowSize = QSize(0, 0);
+}
+
+PlayerWidget::~PlayerWidget()
+{
+
+}
+
+/* 刷新一帧 */
+void PlayerWidget::updateFrame(Image_YUV420& image)
+{
+    m_image = image;
+    if(m_windowSize.width() == 0 || m_windowSize.height() == 0)
+    {
+        m_windowSize.setWidth(image.width);
+        m_windowSize.setHeight(image.height);
+    }
+    update();
+}
+
+
+/* 绘画事件 */
+void PlayerWidget::paintEvent(QPaintEvent *event)
+{
+
+    // SPDLOG_TRACE("开始绘制画面...");
+    /* 对图像进行缩放 */
+    if(m_windowSize.width() != m_image.width || m_windowSize.height() != m_image.height)
+    {
+        m_image = m_image.scaled(m_windowSize.width(), m_windowSize.height(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
+    }
+    QPainter painter(this);
+    painter.drawImage(0, 0, *m_image);
+}
+
+/* 重新设置大小事件 */
+void PlayerWidget::resizeEvent(QResizeEvent *event)
+{
+    m_windowSize.setWidth(event->size().width());
+    m_windowSize.setHeight(event->size().height());
+
+    QWidget::resizeEvent(event);
+}
+

+ 20 - 0
CPlayer/Player/PlayerWidget.h

@@ -1,9 +1,29 @@
 #ifndef PLAYERWIDGET_H
 #define PLAYERWIDGET_H
 
+#include <QWidget>
+#include "PlayerGlobalInfo.h"
 
+class PlayerWidget : public QWidget
+{
+    Q_OBJECT
+public:
+    PlayerWidget(QWidget *parent = nullptr);
+    ~PlayerWidget();
 
+    /* 刷新一帧 */
+    void updateFrame(Image_YUV420& image);
 
+protected:
+    /* 绘画事件 */
+    void paintEvent(QPaintEvent *event) override;
+    /* 重新设置大小事件 */
+    void resizeEvent(QResizeEvent *event) override;
 
+private:
+    Image_YUV420 m_image;
+
+    QSize m_windowSize;         /* 窗口大小 */
+};
 
 #endif /* PLAYERWIDGET_H */

+ 34 - 0
CPlayer/PlayerGlobalInfo.cpp

@@ -0,0 +1,34 @@
+#include "PlayerGlobalInfo.h"
+
+
+
+/* 移动构造函数 */
+Image_YUV420::Image_YUV420(Image_YUV420&& other)
+{
+    yData = std::move(other.yData);
+    uData = std::move(other.uData);
+    vData = std::move(other.vData);
+    width = other.width;
+    height = other.height;
+}
+/* 拷贝构造函数 */
+Image_YUV420::Image_YUV420(const Image_YUV420& other)
+{
+    yData = other.yData;
+    uData = other.uData;
+    vData = other.vData;
+    width = other.width;
+    height = other.height;
+}
+
+
+/* 重载= */
+Image_YUV420& Image_YUV420::operator=(const Image_YUV420& other)
+{
+    yData = other.yData;
+    uData = other.uData;
+    vData = other.vData;
+    width = other.width;
+    height = other.height;
+    return *this;
+}

+ 4 - 16
CPlayer/PlayerGlobalInfo.h

@@ -20,23 +20,11 @@ struct Image_YUV420
     Image_YUV420() : width(0), height(0) {}
     ~Image_YUV420() {}
     /* 移动构造函数 */
-    Image_YUV420(Image_YUV420&& other)
-    {
-        yData = std::move(other.yData);
-        uData = std::move(other.uData);
-        vData = std::move(other.vData);
-        width = other.width;
-        height = other.height;
-    }
+    Image_YUV420(Image_YUV420&& other);
     /* 拷贝构造函数 */
-    Image_YUV420(const Image_YUV420& other)
-    {
-        yData = other.yData;
-        uData = other.uData;
-        vData = other.vData;
-        width = other.width;
-        height = other.height;
-    }
+    Image_YUV420(const Image_YUV420& other);
+    /* 重载= */
+    Image_YUV420& operator=(const Image_YUV420& other);
 };
 
 

+ 52 - 1
CPlayer/cameraplayer.cpp

@@ -5,10 +5,17 @@
 
 #include "LHQLogAPI.h"
 
+
 CameraPlayer::CameraPlayer(QObject *parent) : QObject(parent)
 {
     // qDebug() << "主线程ID:" << QThread::currentThreadId();
+
     m_yuvQueue = new RingQueue<Image_YUV420*>(10);
+    m_yuvQueue->setDefaultValue(nullptr);
+
+    m_player = new PlayerGLWidget();
+    /* 连接信号和槽 */
+    connect(&m_frameTimer, &QTimer::timeout, this, &CameraPlayer::do_updateFrame);
 }
 
 CameraPlayer::~CameraPlayer()
@@ -89,7 +96,7 @@ bool CameraPlayer::initCamera(QString cameraIP, int cameraPort, QString cameraUs
  * @return true 
  * @return false 
  */
-bool CameraPlayer::realPlay(int channel, QWidget* playWindow)
+bool CameraPlayer::realPlay(int channel)
 {
     /* 启动预览并设置回调数据流 */
 
@@ -121,6 +128,50 @@ void CameraPlayer::stopRealPlay()
     LH_WRITE_LOG("实时获取数据结束");
 }
 
+/* 开始播放预览 */
+void CameraPlayer::startPlay()
+{
+    if(m_frameRate == 0)
+    {
+        LH_WRITE_ERROR("帧率为0,无法播放");
+        return;
+    }
+    /* 开启定时器 */
+    m_frameTimer.setTimerType(Qt::PreciseTimer);
+    m_frameTimer.setInterval(1000 / m_frameRate);
+    m_frameTimer.start();
+}
+
+/* 设置播放窗口父指针 */
+void CameraPlayer::setPlayerParent(QWidget* playWnd)
+{
+    m_player->setParent(playWnd);
+}
+
+/* 设置播放窗口大小 */
+void CameraPlayer::setPlayWndSize(int width, int height)
+{
+    m_player->resize(width, height);
+}
+
+/* 更新一帧数据 */
+void CameraPlayer::do_updateFrame()
+{
+    /* 获取一帧 */
+    if(m_yuvQueue->isEmpty())
+    {
+        LH_WRITE_LOG("环形队列为空,无法更新一帧数据");
+        return;
+    }
+    /* 以非阻塞的方式先获取一帧数据,获取成功后再出队 */
+    auto one = m_yuvQueue->front_pop_NoBlock();
+    if(one != nullptr)
+    {
+        m_player->updateFrame(*one);
+        delete one;
+    }
+}
+
 
 
 /**

+ 21 - 5
CPlayer/cameraplayer.h

@@ -2,12 +2,13 @@
 #define CAMERAPLAYER_H
 
 #include <QObject>
+#include <QTimer>
 
-#include "HCNetSDK.h"
 #include "PlayM4.h"
+#include "HCNetSDK.h"
 #include "RingQueue.hpp"
 #include "PlayerGlobalInfo.h"
-
+#include "PlayerGLWidget.h"
 
 /**
  * @brief 登录设备返回的设备信息
@@ -22,7 +23,7 @@ struct CameraInfo
 };
 
 
-class CameraPlayer : QObject
+class CameraPlayer : public QObject
 {
     Q_OBJECT
 public:
@@ -32,9 +33,21 @@ public:
     /* 设置摄像机信息 */
     bool initCamera(QString cameraIP, int cameraPort, QString cameraUser, QString cameraPwd);
     /* 设置实时预览 */
-    bool realPlay(int channel, QWidget* playWindow = nullptr);
+    bool realPlay(int channel);
     /* 关闭预览 */
     void stopRealPlay();
+    /* 开始播放预览 */
+    void startPlay();
+    /* 设置播放窗口父指针 */
+    void setPlayerParent(QWidget* playWnd);
+    /* 设置播放窗口大小 */
+    void setPlayWndSize(int width, int height);
+    /* 获取播放窗口指针 */
+    QWidget* getPlayWnd() { return m_player; }
+
+private slots:
+    /* 更新一帧数据 */
+    void do_updateFrame();
 
 private:
     /* 异常回调函数 */
@@ -61,7 +74,10 @@ private:
 
     LONG m_playPort = -1;                               /* 全局的播放库port号 */
     int m_frameRate = 0;                                /* 帧率 */
-    RingQueue<Image_YUV420*>* m_yuvQueue = nullptr;      /* 环形队列,存放YUV数据 */
+    RingQueue<Image_YUV420*>* m_yuvQueue = nullptr;     /* 环形队列,存放YUV数据 */
+
+    QTimer m_frameTimer;                                /* 定时器,用于更新一帧数据 */
+    PlayerGLWidget* m_player = nullptr;                 /* 播放窗口 */
 };
 
 

+ 79 - 6
CPlayer/common/RingQueue/RingQueue.hpp

@@ -39,6 +39,7 @@ class RingQueue
 public:
     RingQueue();
     RingQueue(long size);
+    RingQueue(long size, T defaultValue);
     ~RingQueue();
 
     /* 入队,默认是阻塞入队 */
@@ -56,15 +57,21 @@ public:
     T front();
     /* 非阻塞的方式获取,队列为空返回false */
     bool front_NoBlock(T& t);
+    /* 非阻塞方式获取第一个值,如果对列为空,则会返回设置的默认值 */
+    T front_NoBlock();
 
     /* 获取对立第一个数据,获取完立刻出队
      * 如果队列为空,会阻塞住,直到有数据为止 */
     T&& front_pop();
-    // T&& front_pop_rvalue();
+    /* 非阻塞方式获取第一个值,并出队 */
     bool front_pop_NoBlock(T& t);
+    /* 非阻塞方式获取第一个值,并出队,如果队列为空,会返回设置的默认值 */
+    T&& front_pop_NoBlock();
     
     /* 设置队列大小 */
     void setQueueCapacity(long size);
+    /* 设置默认值,给指针类型使用,如果是非阻塞获取,空的时候可以返回为设置的默认值(如nullptr) */
+    void setDefaultValue(T defaultValue);
     /* 获取队列大小,队列中有效值的大小 */
     long QueueSize();
     /* 获取队列容量 */
@@ -81,10 +88,11 @@ public:
 private:
     bool m_isExit = false;                  /* 是否退出,这个标识位是为了退出阻塞住的函数 */
     std::mutex m_mutex;                     /* 互斥锁 */
+    T m_defaultValue;                       /* 默认值 */
     T* m_queue = nullptr;                   /* 队列 */
-    long m_capacity = 0;     /* 队列容量 */
-    long m_front = 0;        /* 队头 */
-    long m_rear = 0;         /* 队尾 */
+    long m_capacity = 0;                    /* 队列容量 */
+    long m_front = 0;                       /* 队头 */
+    long m_rear = 0;                        /* 队尾 */
     std::condition_variable m_cond_NoFull;      /* 非满条件变量 */
     std::condition_variable m_cond_NoEmpty;     /* 非空条件变量 */
 };
@@ -109,6 +117,20 @@ RingQueue<T>::RingQueue(long capacicy) : m_capacity(capacicy)
     m_queue = new T[m_capacity];
 }
 
+/* 添加默认值 */
+template<typename T>
+RingQueue<T>::RingQueue(long size, T defaultValue)
+{
+    m_front = -1;
+    m_rear = -1;
+    m_queue = new T[m_capacity];
+    for(long i = 0; i < m_capacity; i++)
+    {
+        m_queue[i] = defaultValue;
+    }
+    m_defaultValue = defaultValue;
+}
+
 template<typename T>
 RingQueue<T>::~RingQueue()
 {
@@ -311,12 +333,29 @@ bool RingQueue<T>::front_NoBlock(T& t)
     return true;
 }
 
+
+/* 非阻塞方式获取第一个值,如果对列为空,则会返回设置的默认值 */
+template<typename T>
+T RingQueue<T>::front_NoBlock()
+{
+    T ret;
+    {
+        std::unique_lock<std::mutex> lock(m_mutex);
+        if(isEmpty())
+        {
+            return m_defaultValue;
+        }
+        ret = m_queue[m_front];
+    }
+    return ret;
+}
+
 /* 获取对立第一个数据,获取完立刻出队
  * 如果队列为空,会阻塞住,直到有数据为止 */
 template<typename T>
 T&& RingQueue<T>::front_pop()
 {
-    T ret;
+    T ret = m_defaultValue;
     {
         std::unique_lock<std::mutex> lock(m_mutex);
         m_cond_NoEmpty.wait(lock, [this](){
@@ -338,7 +377,7 @@ T&& RingQueue<T>::front_pop()
     return std::move(ret);
 }
 
-
+/* 非阻塞方式获取第一个值,并出队 */
 template<typename T>
 bool RingQueue<T>::front_pop_NoBlock(T& t)
 {
@@ -360,6 +399,32 @@ bool RingQueue<T>::front_pop_NoBlock(T& t)
     return true;
 }
 
+/* 非阻塞方式获取第一个值,并出队 */
+template<typename T>
+T&& RingQueue<T>::front_pop_NoBlock()
+{
+    T ret = m_defaultValue;
+    {
+        std::unique_lock<std::mutex> lock(m_mutex);
+        m_cond_NoEmpty.wait(lock, [this](){
+            return (!isEmpty() || m_isExit);
+        });
+        if(m_isExit)
+        {
+            return std::move(ret);
+        }
+        ret = std::move(m_queue[m_front]);
+        m_front = (m_front + 1) % m_capacity;
+        if(m_front == m_rear)
+        {
+            m_front = -1;
+            m_rear = -1;
+        }
+    }
+    m_cond_NoFull.notify_all();
+    return std::move(ret);
+}
+
 
 /**
  * @brief 设置队列大小
@@ -384,6 +449,14 @@ void RingQueue<T>::setQueueCapacity(long size)
     m_queue = new T[m_capacity];
 }
 
+
+/* 设置默认值,给指针类型使用,如果是非阻塞获取,空的时候可以返回为设置的默认值(如nullptr) */
+template<typename T>
+void RingQueue<T>::setDefaultValue(T defaultValue)
+{
+    m_defaultValue = defaultValue;
+}
+
 /* 获取队列中有效值的大小 */
 template<typename T>
 long RingQueue<T>::QueueSize()

+ 1 - 1
External

@@ -1 +1 @@
-/home/Apple/Lib/External
+/home/Apple/Libs/External

+ 1 - 1
External_Ex

@@ -1 +1 @@
-/home/Apple/Lib/Library_Ex
+/home/Apple/Libs/Library_Ex

+ 11 - 0
show1/widget.cpp

@@ -14,6 +14,10 @@ widget::widget(QWidget *parent) :
 
     m_cameraPlayer->initCamera("192.1.2.73", 8000, "admin", "LH123456");
     m_cameraPlayer->realPlay(1);
+
+    /* 设置播放窗口 */
+    m_cameraPlayer->setPlayerParent(ui->widget_display);
+    m_cameraPlayer->setPlayWndSize(1280, 720);
 }
 
 widget::~widget()
@@ -21,3 +25,10 @@ widget::~widget()
     delete m_cameraPlayer;
     delete ui;
 }
+
+
+/* 开启预览按钮 */
+void widget::on_pBtn_startRealPlay_clicked()
+{
+    m_cameraPlayer->startPlay();
+}

+ 4 - 0
show1/widget.h

@@ -17,6 +17,10 @@ public:
     explicit widget(QWidget *parent = nullptr);
     ~widget();
 
+private slots:
+    /* 开启预览按钮 */
+    void on_pBtn_startRealPlay_clicked();
+    
 private:
     Ui::widget *ui;
 

+ 57 - 7
show1/widget.ui

@@ -1,21 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
 <ui version="4.0">
- <author/>
- <comment/>
- <exportmacro/>
  <class>widget</class>
- <widget name="widget" class="QWidget">
+ <widget class="QWidget" name="widget">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>400</width>
-    <height>300</height>
+    <width>827</width>
+    <height>559</height>
    </rect>
   </property>
   <property name="windowTitle">
    <string>Form</string>
   </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="spacing">
+    <number>0</number>
+   </property>
+   <property name="leftMargin">
+    <number>0</number>
+   </property>
+   <property name="topMargin">
+    <number>0</number>
+   </property>
+   <property name="rightMargin">
+    <number>0</number>
+   </property>
+   <property name="bottomMargin">
+    <number>0</number>
+   </property>
+   <item>
+    <widget class="QWidget" name="widget_display" native="true"/>
+   </item>
+   <item>
+    <widget class="QWidget" name="widget_control" native="true">
+     <property name="maximumSize">
+      <size>
+       <width>16777215</width>
+       <height>40</height>
+      </size>
+     </property>
+     <layout class="QHBoxLayout" name="horizontalLayout">
+      <item>
+       <widget class="QPushButton" name="pBtn_startRealPlay">
+        <property name="text">
+         <string>开启预览</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <spacer name="horizontalSpacer">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>720</width>
+          <height>19</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
  </widget>
- <pixmapfunction/>
+ <resources/>
  <connections/>
 </ui>