#ifndef VIDEOWIDGET_H
#define VIDEOWIDGET_H

#include <qopenglpixeltransferoptions.h>
#include <qopenglshaderprogram.h>

#include <QGuiApplication>
#include <QMutex>
#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLTexture>
#include <QQueue>
#include <QScreen>
#include <QThread>
#include <QTimer>
#include <QWidget>
#include <QWindow>

#include "decodestream.h"
#include "ffmpeginclude.h"
#include "pushstream.h"
#include "readstream.h"

#define USE_WINDOW 0  // 1:使用QOpenGLWindow显示, 0：使用QOpenGLWidget显示

#if USE_WINDOW
#include <QOpenGLWindow>
class VideoWidget : public QOpenGLWindow,
                    public QOpenGLFunctions_3_3_Core
#else
#include <QOpenGLWidget>
class VideoWidget : public QOpenGLWidget,
                    public QOpenGLFunctions_3_3_Core
#endif
{
    Q_OBJECT
public:
#if USE_WINDOW
    explicit VideoWidget(UpdateBehavior updateBehavior = NoPartialUpdate,
                         QWindow *parent = nullptr);
#else
    explicit VideoWidget(QWidget *parent = nullptr,
                         Qt::WindowFlags f = Qt::WindowFlags());
#endif
    ~VideoWidget() override;

    bool play(const QString &url);
    bool udpPlay(QString ip, int port);
    void stopPlay();
    void stopUDPPlay();
    bool pushStream(const QString &url);
    void stopPushStream();
    void setPullURL(const QString &url);
    void setPushURL(const QString &url);
    void setVedioSaveFileDirPath(const QString &dirPath);

protected:
    void initializeGL() override;          // 初始化gl
    void resizeGL(int w, int h) override;  // 窗口尺寸变化
    void paintGL() override;               // 刷新显示
    void repaint(AVFrame *frame);          // 设置需要绘制的图像帧
private:
    // YUV420图像数据更新
    void repaintTexYUV420P(AVFrame *frame);
    void initTexYUV420P(int width, int height);
    void freeTexYUV420P();
    // NV12图像数据更新
    void repaintTexNV12(AVFrame *frame);
    void initTexNV12(AVFrame *frame);
    void freeTexNV12();

private:  // opengl
    QOpenGLShaderProgram *m_program = nullptr;
    QOpenGLTexture *m_texY = nullptr;
    QOpenGLTexture *m_texU = nullptr;
    QOpenGLTexture *m_texV = nullptr;
    QOpenGLTexture *m_texUV = nullptr;
    QOpenGLPixelTransferOptions m_options;

    GLuint VBO =
        0;  // 顶点缓冲对象,负责将数据从内存放到缓存，一个VBO可以用于多个VAO
    GLuint VAO =
        0;  // 顶点数组对象,任何随后的顶点属性调用都会储存在这个VAO中，一个VAO可以有多个VBO
    GLuint EBO = 0;  // 元素缓冲对象,它存储 OpenGL 用来决定要绘制哪些顶点的索引
    QSize m_size;
    QSizeF m_zoomSize;
    QPointF m_pos;
    int m_format;  // 像素格式

private:
    bool pullStream(const QString &url);
    bool pullUDPStream(QString ip, int port);
    void receiveErrorMessage(QString message, int type);

private:
    QString m_pullURL;
    QString m_pushURL;
    bool m_playFlag = false;
    bool m_pullFlag = false;
    bool m_pushFlag = false;
    QString m_videoSaveDirPath;

    ReadStream *readStreamer = nullptr;
    QThread readStreamThread;

    DecodeStream *decodeStreamer = nullptr;
    QThread decodeStreamThread;

    SaveStream *saveStreamer = nullptr;
    QThread saveStreamThread;

    PushStream *streamPusher = nullptr;
    QThread pushStreamThread;

    QMutex m_mutex;

signals:
    void startPullSignal();
    void sendErrorMessageSignal(QString message, int type);

public:
    QSizeF getCurImgSize();
};

#endif  // VIDEOWIDGET_H
