/****************************************************************************
 **
 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
 ** Contact: http://www.qt-project.org/legal
 **
 ** This file is part of the examples of the Qt Toolkit.
 **
 ** $QT_BEGIN_LICENSE:BSD$
 ** You may use this file under the terms of the BSD license as follows:
 **
 ** "Redistribution and use in source and binary forms, with or without
 ** modification, are permitted provided that the following conditions are
 ** met:
 **   * Redistributions of source code must retain the above copyright
 **     notice, this list of conditions and the following disclaimer.
 **   * Redistributions in binary form must reproduce the above copyright
 **     notice, this list of conditions and the following disclaimer in
 **     the documentation and/or other materials provided with the
 **     distribution.
 **   * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
 **     of its contributors may be used to endorse or promote products derived
 **     from this software without specific prior written permission.
 **
 **
 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
 **
 ** $QT_END_LICENSE$
 **
 ****************************************************************************/

#include "qvideowidget.h"
#include <QPainter>
#include <QPaintEngine>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
#include <QCoreApplication>
#include <math.h>
#include <QPainterPath>

#include <QOpenGLPixelTransferOptions>
#include <QFrame>

#include "mainwindow.h"


#include "qvideoshader.h"

#include "qgstreamerplayer.h"


QVideoWidget::QVideoWidget(QWidget* parent, Qt::WindowFlags f):QOpenGLWidget(parent, f),
    m_bCheckFrameUpdateCount(true),
    m_nUpdateFrameCount(0),
    m_transparent(false),
    m_btn(0),
    m_hasButton(NULL),
    m_background(QColor(0, 0, 0))
{
    setMinimumSize(320, 180);

//    m_listRectObject.push_back(QRect(100, 100, 200, 200));

    m_nCountQueue = 5;

    CommonData* pCommonData = MainWindow::GetCommonData();
    int nVideoWidth = pCommonData->GetVideoWidth();
    int nVideoHeight = pCommonData->GetVideoHeight();

    int i=0;
    for(i=0 ; i<m_nCountQueue ; i++)
    {
        uint8_t* pData = new uint8_t[nVideoWidth*nVideoHeight*4];
        m_QueueData.push_back(pData);

    }




    //m_bViewThumbnail = false;


    m_nTextureWidth = nVideoWidth;
    m_nTextureHeight = nVideoHeight;


    m_bTestSaveMode = false;
    m_pidChild = 0;
    m_pData = new uint8_t[m_nTextureWidth*m_nTextureHeight*4];
    m_bChange = false;

    m_pVideoShader = NULL;

    m_bFullScreen = false;


    Init();

    //m_pThreadThumbnail = new QThreadThumbnail;
    //m_pThreadThumbnail->start();
    //QObject::connect(m_pThreadThumbnail, SIGNAL(CreatedThumbnail(QString)), this, SLOT(CreatedThumbnail(QString)));

}

QVideoWidget::~QVideoWidget()
{
    // And now release all OpenGL resources.
    makeCurrent();

    if(m_pVideoShader!=NULL)
    {
        delete m_pVideoShader;
        m_pVideoShader = NULL;
    }

    ResetThumbnailTexture();


    m_VBOVideo.destroy();
    doneCurrent();

    SAFE_ARRAY_DELETE(m_pData);

    int i=0;
    for(i=0 ; i<m_QueueData.size() ; i++)
    {
        uint8_t* pData = m_QueueData[i];
        SAFE_ARRAY_DELETE(pData);
    }
    m_QueueData.clear();
}

void QVideoWidget::SetButton(QPushButton* pButton)
{
    m_btn = pButton;
}

void QVideoWidget::CreatedThumbnail(QString strFilenameThumbnail)
{
    /*
    m_pThumbnail->AddThumbnail(strFilenameThumbnail);

    m_bCapturing = false;
    m_pMenu->SetCapture(m_bCapturing);
    */
}

void QVideoWidget::ReceivedSaveBitmap()
{
    SendSaveBitmap();
}

void QVideoWidget::ReceivedRecord(bool bRecord)
{
    SendRecord(bRecord);
}

void QVideoWidget::ReceivedViewThumbnail(bool bView)
{
    /*
    if(bView==true && m_bViewThumbnail==false)
    {
        m_StartTime = QTime::currentTime();
        m_StartTime.start();

        m_pThumbnail->StartAnimation();
    }
    else if(bView==false && m_bViewThumbnail==true)
    {
        m_StartTime = QTime::currentTime();
        m_StartTime.start();
    }

    m_bViewThumbnail = bView;
    */
}

void QVideoWidget::paintTexturedCube()
{

    if(m_pData!=NULL)
    {
        bool bInit = m_bInitDisplay;
        UpdateTexture();
        if(bInit==false)
        {
            return;
        }
    }

    m_pVideoShader->EnableAttributeArray();

    m_VBOVideo.bind();
    // In the buffer we first have 36 vertices (3 floats for each), then 36 texture
    // coordinates (2 floats for each), then 36 normals (3 floats for each).
    m_pVideoShader->SetAttributeBuffer();




    m_pVideoShader->BindTexture();

    glDrawArrays(GL_TRIANGLES, 0, 6);


    m_pVideoShader->ReleaseTexture();

    m_VBOVideo.release();


    m_pVideoShader->DisableAttributeArray();

}

void QVideoWidget::initializeGL()
{
    int i=0;
    QOpenGLContext * pCurrent = QOpenGLContext::currentContext();

    if(pCurrent!=NULL)
    {
        if(pCurrent->isOpenGLES())
        {

        }
    }

    initializeOpenGLFunctions();

    setUpdateBehavior(QOpenGLWidget::NoPartialUpdate);

    GLuint nFrameBufferObject = defaultFramebufferObject();

    for(i=0 ; i<18 ; i++)
    {
        m_fNormalRect[i] = -1;
    }

    GLfloat afTexCoord[] = {
        0.0f,1.0f, 1.0f,1.0f, 0.0f,0.0f,
                    1.0f,0.0f, 0.0f,0.0f, 1.0f,1.0f
    };

    memcpy(m_fNormalRectTexture, afTexCoord, sizeof(GLfloat)*2*6);

    m_nTmpDisplayType = 0;

    QSize nSize = size();
    m_nTextureWidth = nSize.width();
    m_nTextureHeight = nSize.height();

    int nWidth = m_nTextureWidth;
    int nHeight = m_nTextureHeight;



    m_pVideoShader = new QVideoShader;
    //m_pVideoShader->CreateTexture(nWidth, nHeight, QOpenGLTexture::Target2D, QOpenGLTexture::RGB8_UNorm);
    //m_pVideoShader->CreateTexture(nWidth, nHeight, QOpenGLTexture::Target2D, QOpenGLTexture::RG8_UNorm);
    m_pVideoShader->CreateTexture(nWidth*2, nHeight, QOpenGLTexture::Target2D, QOpenGLTexture::R8_UNorm);








    //m_pThumbnailTexture = new QOpenGLTexture(image);


    char *pSrcVertex =
            "#version 300 es\n"
        "attribute highp vec4 vertex;\n"
        "attribute highp vec4 texCoord;\n"
        "uniform mediump mat4 matrix;\n"
        "varying highp vec4 texc;\n"
        "void main(void)\n"
        "{\n"
        "    gl_Position = matrix * vertex;\n"
        "    texc = texCoord;\n"
        "}\n";


    char *pSrcFragmentCaptureEnvent =
            "#version 300 es\n"
            "in highp vec4 texc;\n"
            "uniform sampler2D tex;\n"
            "out lowp vec4 FragColor;\n"
            "uniform lowp int nImageWidth;\n"
            "uniform lowp int nImageHeight;\n"
            "void main(void)\n"
            "{\n"
            "   int nX=0;\n"
            "   int nY=0;\n"
            "   int nIndex=0;\n"
            "   highp float fX = 0.0;\n"
            "   highp float fY = 0.0;\n"
            "   int nInternalIndex = 0;\n"
            "   highp float fImageWidth = float(nImageWidth);\n"
            "   highp float fImageHeight = float(nImageHeight);\n"
            "   fX = floor(texc.s*(fImageWidth));\n"
            "   fY = floor(texc.t*fImageHeight);\n"
            "   nX = int(fX);\n"
            "   nY = int(fY);\n"
            "   int nStartX = int((int(nX/4)) * 4);\n"
            "   int nIndexY = nStartX + 1 + int(mod(float(nX/2), 2.0)) * 2;\n"
            "   int nIndexU = nStartX+0;\n"
            "   int nIndexV = nStartX+2;\n"
            //"   if(nX<4) { FragColor = vec4(0.0, 0.0, 0.0, 1.0); return; }\n"
            "   fX = float((nX/2)*2+1)/(fImageWidth);\n"
            "   fY = float(nY)/(fImageHeight);\n"
            "   highp vec4 colorY = texture2D(tex, vec2(float(nIndexY)/(fImageWidth)+0.5/fImageWidth,fY+0.5/fImageHeight));\n"
            "   highp vec4 colorU = texture2D(tex, vec2(float(nIndexU)/(fImageWidth)+0.5/fImageWidth,fY+0.5/fImageHeight));\n"
            "   highp vec4 colorV = texture2D(tex, vec2(float(nIndexV)/(fImageWidth)+0.5/fImageWidth,fY+0.5/fImageHeight));\n"
            "   highp float fColorY = colorY.r;\n"
            "   highp float fColorU = colorU.r;\n"
            "   highp float fColorV = colorV.r;\n"
            //"   FragColor = vec4(fColorY, fColorU, fColorV, 1.0); return;\n"


            "   highp float fR = fColorY;\n"
            "   highp float fG = fColorY;\n"
            "   highp float fB = fColorY;\n"

            "   fColorY=1.1643*(fColorY-0.0625);"
            "   fColorU=fColorU-0.5;"
            "   fColorV=fColorV-0.5;"

            "   fR=clamp(fColorY+1.5958*fColorV, 0.0, 1.0);"
            "   fG=clamp(fColorY-0.39173*fColorU-0.81290*fColorV, 0.0, 1.0);"
            "   fB=clamp(fColorY+2.017*fColorU, 0.0, 1.0);"

            "   FragColor = vec4(fR, fG, fB, 1.0);\n"
            "   highp float fTmpColor = colorU\.r;\n"
            //"   FragColor = vec4(fTmpColor, fTmpColor, fTmpColor, 1.0);\n"

            "}\n";

    m_pVideoShader->CreateShader((const char*)pSrcVertex, (const char*)pSrcFragmentCaptureEnvent);
    m_pVideoShader->CreateGeometry();

    if (!m_VBOVideo.isCreated()) {
        //float fRatioWidth = 1572.0f/1920.0f;
        float fRatioWidth = 1.0;
        GLfloat afVertices[] = {
            -1, -fRatioWidth, -1,
            1,-fRatioWidth,-1,

            -1,fRatioWidth,-1,
            1, fRatioWidth,-1,

            -1,fRatioWidth,-1,
            1,-fRatioWidth,-1
        };

        GLfloat afTexCoord[] = {
            0.0f,1.0f, 1.0f,1.0f, 0.0f,0.0f,
                        1.0f,0.0f, 0.0f,0.0f, 1.0f,1.0f
        };

        m_VBOVideo.create();
        m_VBOVideo.bind();

        m_VBOVideo.allocate(6 * 5 * sizeof(GLfloat));
        m_VBOVideo.write(0, afVertices, 6*3*sizeof(GLfloat));
        m_VBOVideo.write(6*3*sizeof(GLfloat), afTexCoord, 6*2*sizeof(GLfloat));

        m_VBOVideo.release();
    }

    /*
    GLfloat afVertices[] = {
        -1,1, -1,      -0.767,1,-1,       -1,-1,-1,
         -0.767, -1,-1,  -1,-1,-1,        -0.767,1,-1
    };



    QImage image("desk_blue.jpg");
    //QImage image("desk_blue.png");
    int nImageWidth = image.width();
    int nImageHeight = image.height();

    QImage image2 = image.convertToFormat(QImage::Format_RGB888);

    int nBytes = image2.byteCount();
    uint8_t* pImageData = (uint8_t*)image2.bits();

    memcpy(m_pData, pImageData, nBytes);
    m_bChange = true;
    */
    UpdateTexture();
}

void QVideoWidget::leaveEvent(QEvent *pEvent)
{


    InitState();
}

void QVideoWidget::mouseDoubleClickEvent(QMouseEvent *)
{
    return;
    m_bFullScreen = !m_bFullScreen;


    QSize sizeParent = ((QFrame*)parent())->size();



    if(m_bFullScreen==true)
    {
        m_rectSmallDisplay = QRect(39, 155, 1103, 621);
        //setGeometry(0, 0, sizeParent.height()*1280.0/1024.0, sizeParent.height());
        setGeometry(0, 0, sizeParent.width(), sizeParent.height());
    }
    else
    {
        setGeometry(m_rectSmallDisplay);
    }


}

void QVideoWidget::mouseMoveEvent(QMouseEvent *pEvent)
{
    int nX = pEvent->x();
    int nY = pEvent->y();

    /*
    if(m_bFullScreen==false)
    {
        m_pThumbnail->CheckRegionSmall(nX, nY);
    }
    else
    {
        m_pThumbnail->CheckRegion(nX, nY);
    }

    */


}

void QVideoWidget::mousePressEvent(QMouseEvent *pEvent)
{
    int nX = pEvent->x();
    int nY = pEvent->y();

    if(m_bFullScreen==false)
    {
        //m_pMenu->CheckRegionSmall(nX, nY);
    }
    else
    {
        //m_pMenu->CheckRegion(nX, nY);
    }



}

void QVideoWidget::paintGL()
{

    bool bChangeTexture = false;

    m_Lock.lock();
    bChangeTexture = m_bChange;
    m_Lock.unlock();

    CommonData* pCommonData = MainWindow::GetCommonData();
    int nVideoWidth = pCommonData->GetVideoWidth();
    int nVideoHeight = pCommonData->GetVideoHeight();

    if(bChangeTexture==false)
    {
        //update();
        //usleep(5*1000);
        return;
        //m_pThumbnail->PaintBuffer();
    }

    //m_MutexPaint.lock();

    QSize nScreenSize = size();

    makeCurrent();
    {

        glViewport(0, 0, nScreenSize.width(), nScreenSize.height()+1);
        QPainter painter;
        //
        painter.begin(this);

        painter.beginNativePainting();

        m_transparent = false;

        glClearColor(m_background.redF(), m_background.greenF(), m_background.blueF(), m_transparent ? 0.0f : 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glDisable(GL_CULL_FACE);
        glDisable(GL_DEPTH_TEST);

        glEnable(GL_BLEND);

        glEnable(GL_TEXTURE_2D);

        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);




        m_pVideoShader->Bind();
        m_pVideoShader->SetUniformValue();

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        paintTexturedCube();
        m_pVideoShader->Release();

        glDisable(GL_CULL_FACE);
        glDisable(GL_BLEND);
        glDisable(GL_TEXTURE_2D);

        glFlush();
        painter.endNativePainting();

        painter.setRenderHint( QPainter::Antialiasing );

        QTime dt = QTime::currentTime();
        int nHour = dt.hour();
        int nMinute = dt.minute();
        int nSec = dt.second();


        QString strTime = QString("%1:%2:%3").arg(QString::number(nHour, 10).rightJustified(2, '0'))
                .arg(QString::number(nMinute, 10).rightJustified(2, '0'))
                .arg(QString::number(nSec, 10).rightJustified(2, '0'));

        //painter.setFont(QFont("Roboto", 32, QFont::Bold));
        //painter.setBrush(QBrush(QColor(255, 255, 255, 255)));
        //painter.drawText(nScreenSize.width()-200, 10, 180, 70, (Qt::AlignVCenter | Qt::AlignLeft), strTime);


        QPainterPath path;

        CommonData* pCommonData = MainWindow::GetCommonData();

        if(pCommonData->GetCropMode()==false)
        {
            path.addText(nScreenSize.width()-250, 50, QFont("Roboto", 36), strTime);
        }
        else
        {
            path.addText(nScreenSize.width()-250, 50, QFont("Roboto", 36), strTime);
        }

        painter.strokePath(path, QPen(Qt::black, 4));
        painter.setPen( Qt::NoPen );
        painter.setBrush( QBrush(QColor(255, 255, 255)) );
        painter.drawPath( path );


        /*
        QPainterPath path;
        QPainterPath rawPath;
        rawPath.addEllipse(QRect(0, 0, 200, 200));

        double const step = 1.0 / double(strTime.length());
        double percent = 0.0;
        for(QChar const& c: strTime)
        {
            double angle = rawPath.angleAtPercent(percent);
            QPointF point = rawPath.pointAtPercent(percent);

            QTransform mat;
            mat.rotate(-angle);
            QPainterPath p2;
            p2.addText(0, 0, font(), c);
            p2 = mat.map(p2);
            path.addPath(p2.translated(point));
            percent += step;
        }
        painter.drawPath(path.translated(100, 100));
        */


        if(m_listRectObject.size()>0)
        {
            int i=0;
            for(i=0 ; i<m_listRectObject.size() ; i++)
            {
                QRect rectObject = m_listRectObject[i];
                QPen pen;
                float fRatioX = (float)nScreenSize.width() / (float)nVideoWidth;
                float fRatioY = (float)nScreenSize.height() / (float)nVideoHeight;

                float fX = (float)rectObject.x() * fRatioX;
                float fY = (float)rectObject.y() * fRatioY;
                float fWidth = (float)rectObject.width() *fRatioX;
                float fHeight = (float)rectObject.height() *fRatioY;

                QRect rectDisplay = QRect(round(fX), round(fY), round(fWidth), round(fHeight));

                pen.setColor(Qt::green);
                pen.setWidth(4);
                painter.setPen(pen);
                painter.drawRect(rectDisplay);

            }
        }

        painter.end();

        usleep(10);

        //update();
    }

    //m_MutexPaint.unlock();



}

/*
void QVideoWidget::createGeometry()
{
    m_vertices.clear();
    m_normals.clear();

    qreal x1 = +0.06f;
    qreal y1 = -0.14f;
    qreal x2 = +0.14f;
    qreal y2 = -0.06f;
    qreal x3 = +0.08f;
    qreal y3 = +0.00f;
    qreal x4 = +0.30f;
    qreal y4 = +0.22f;

    quad(x1, y1, x2, y2, y2, x2, y1, x1);
    quad(x3, y3, x4, y4, y4, x4, y3, x3);

    extrude(x1, y1, x2, y2);
    extrude(x2, y2, y2, x2);
    extrude(y2, x2, y1, x1);
    extrude(y1, x1, x1, y1);
    extrude(x3, y3, x4, y4);
    extrude(x4, y4, y4, x4);
    extrude(y4, x4, y3, x3);

    const qreal Pi = 3.14159f;
    const int NumSectors = 100;

    for (int i = 0; i < NumSectors; ++i) {
        qreal angle1 = (i * 2 * Pi) / NumSectors;
        qreal x5 = 0.30 * sin(angle1);
        qreal y5 = 0.30 * cos(angle1);
        qreal x6 = 0.20 * sin(angle1);
        qreal y6 = 0.20 * cos(angle1);

        qreal angle2 = ((i + 1) * 2 * Pi) / NumSectors;
        qreal x7 = 0.20 * sin(angle2);
        qreal y7 = 0.20 * cos(angle2);
        qreal x8 = 0.30 * sin(angle2);
        qreal y8 = 0.30 * cos(angle2);

        quad(x5, y5, x6, y6, x7, y7, x8, y8);

        extrude(x6, y6, x7, y7);
        extrude(x8, y8, x5, y5);
    }

    for (int i = 0;i < m_vertices.size();i++)
        m_vertices[i] *= 2.0f;
}

void QVideoWidget::quad(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4, qreal y4)
{
    m_vertices << QVector3D(x1, y1, -0.05f);
    m_vertices << QVector3D(x2, y2, -0.05f);
    m_vertices << QVector3D(x4, y4, -0.05f);

    m_vertices << QVector3D(x3, y3, -0.05f);
    m_vertices << QVector3D(x4, y4, -0.05f);
    m_vertices << QVector3D(x2, y2, -0.05f);

    QVector3D n = QVector3D::normal
        (QVector3D(x2 - x1, y2 - y1, 0.0f), QVector3D(x4 - x1, y4 - y1, 0.0f));

    m_normals << n;
    m_normals << n;
    m_normals << n;

    m_normals << n;
    m_normals << n;
    m_normals << n;

    m_vertices << QVector3D(x4, y4, 0.05f);
    m_vertices << QVector3D(x2, y2, 0.05f);
    m_vertices << QVector3D(x1, y1, 0.05f);

    m_vertices << QVector3D(x2, y2, 0.05f);
    m_vertices << QVector3D(x4, y4, 0.05f);
    m_vertices << QVector3D(x3, y3, 0.05f);

    n = QVector3D::normal
        (QVector3D(x2 - x4, y2 - y4, 0.0f), QVector3D(x1 - x4, y1 - y4, 0.0f));

    m_normals << n;
    m_normals << n;
    m_normals << n;

    m_normals << n;
    m_normals << n;
    m_normals << n;
}

void QVideoWidget::extrude(qreal x1, qreal y1, qreal x2, qreal y2)
{
    m_vertices << QVector3D(x1, y1, +0.05f);
    m_vertices << QVector3D(x2, y2, +0.05f);
    m_vertices << QVector3D(x1, y1, -0.05f);

    m_vertices << QVector3D(x2, y2, -0.05f);
    m_vertices << QVector3D(x1, y1, -0.05f);
    m_vertices << QVector3D(x2, y2, +0.05f);

    QVector3D n = QVector3D::normal
        (QVector3D(x2 - x1, y2 - y1, 0.0f), QVector3D(0.0f, 0.0f, -0.1f));

    m_normals << n;
    m_normals << n;
    m_normals << n;

    m_normals << n;
    m_normals << n;
    m_normals << n;
}
*/

void QVideoWidget::setTransparent(bool transparent)
{
    setAttribute(Qt::WA_AlwaysStackOnTop, transparent);
    m_transparent = transparent;
    // Call update() on the top-level window after toggling AlwayStackOnTop to make sure
    // the entire backingstore is updated accordingly.
    window()->update();
}

void QVideoWidget::resizeGL(int w, int h)
{
    QOpenGLWidget::resizeGL(w, h);

    glViewport(0, 0, w, h);
}



void QVideoWidget::UpdateTexture()
{


    if(m_bChange==false)
    {
        return;
    }

    if(m_Lock.tryLock(500)==false)
    {
        return;
    }

    m_bInitDisplay = true;

    QOpenGLPixelTransferOptions uploadOptions;
    uploadOptions.setAlignment(1);
    if(m_pData!=NULL)
    {
        QOpenGLTexture* pTexture = m_pVideoShader->GetTexture();
        pTexture->bind();
        if(m_nIndexCurrent>=0)
        {
            if(m_nIndexCurrent>m_nIndexDisplay)
            {
                m_nIndexDisplay++;

                pTexture->setData(0, QOpenGLTexture::Red, QOpenGLTexture::UInt8, (void*)m_QueueData[m_nIndexDisplay%m_nCountQueue], &uploadOptions);

                pTexture->generateMipMaps();
                pTexture->setMinMagFilters(QOpenGLTexture::LinearMipMapLinear, QOpenGLTexture::LinearMipMapLinear);

                if(m_nIndexCurrent-2>m_nIndexDisplay)
                {
                    m_nIndexDisplay = m_nIndexCurrent-1;
                }
            }

        }


        {
            m_bChange = false;
        }        
        pTexture->release();

        if(m_bCheckFrameUpdateCount==true)
        {
            m_nUpdateFrameCount++;
            if(m_TimerFPS.elapsed()>1000)
            {
                //qDebug() << "FPS: " << m_nUpdateFrameCount;
                m_nUpdateFrameCount = 0;
                m_TimerFPS.restart();
            }

        }
    }

    m_Lock.unlock();
}


QMutex* QVideoWidget::GetMutex()
{
    return &m_Lock;
}


void QVideoWidget::SetTextureData(uint8_t* pData, int nSize)
{
    m_Lock.lock();

    m_StartTime.restart();


    int nQueue = (m_nIndexCurrent+1)%m_nCountQueue;

    uint8_t* pDataQueue = m_QueueData[nQueue];
    memcpy(pDataQueue, pData, nSize);
    m_nIndexCurrent++;


    //YOLOv5 Dataset copy
    CommonData* pCommonData = MainWindow::GetCommonData();
    int nVideoWidth = pCommonData->GetVideoWidth();
    int nVideoHeight = pCommonData->GetVideoHeight();

    if(pCommonData->IsActiveDetect()==true)
    {
        pCommonData->GetThreadCaptureImage()->SetImageDetect(pDataQueue, nVideoWidth, nVideoHeight);
    }




    m_bChange = true;



    m_Lock.unlock();



}


uint8_t* QVideoWidget::GetDataPtr()
{
    return m_pData;
}

int QVideoWidget::GetTextureWidth()
{
    return m_nTextureWidth;
}

int QVideoWidget::GetTextureHeight()
{
    return m_nTextureHeight;
}

void QVideoWidget::SetTextureSize(int nWidth, int nHeight)
{
    return;
    /*
    if(m_nTextureWidth!=nWidth || m_nTextureHeight!=nHeight)
    {
        m_nTextureWidth = nWidth;
        m_nTextureHeight = nHeight;

        if(m_pVideoTexture->isStorageAllocated()==true)
        {
            delete m_pVideoTexture;
            //m_pVideoTexture->destroy();
        }

        m_pVideoTexture->create();
        m_pVideoTexture->setFormat(QOpenGLTexture::R8_UNorm);
        m_pVideoTexture->setSize(nWidth, nHeight*1.5);
        m_pVideoTexture->allocateStorage();
    }
    */
}

void QVideoWidget::SetSmallDisplay(int nX, int nY, int nWidth, int nHeight)
{
    m_rectSmallDisplay = QRect(nX, nY, nWidth, nHeight);
}

void QVideoWidget::ResetThumbnailTexture()
{
    //m_pThumbnail->ResetThumbnailTexture();
}

void QVideoWidget::SaveBitmap(QString strFilename)
{
    //m_bCapturing = true;
    //m_pMenu->SetCapture(m_bCapturing);

    //m_pThreadThumbnail->AddThumbnail(m_pData, 1920, 1080, strFilename);
}

float QVideoWidget::MakeNormalize(int nPos, int nRange)
{
    float fData = 0.0f;

    //fData = (float)(nPos-nRange/2.0)/(float)(nRange/2.0);

    fData = (float)nPos/(float)(nRange/2) - 1.0f;
    return fData;
}

void QVideoWidget::MakeRectNormal(const QRect& rect, QSize rectSize)
{
    float fLeft = MakeNormalize(rect.left(), rectSize.width());
    float fTop = MakeNormalize(rect.top(), rectSize.height()) * -1.0f;
    float fRight = MakeNormalize(rect.right(), rectSize.width());
    float fBottom = MakeNormalize(rect.bottom(), rectSize.height()) * -1.0f;
    //lefttop
    m_fNormalRect[0] = fLeft;
    m_fNormalRect[1] = fBottom;

    //righttop
    m_fNormalRect[3] = fRight;
    m_fNormalRect[4] = fBottom;

    //leftbottom
    m_fNormalRect[6] = fLeft;
    m_fNormalRect[7] = fTop;

    //rightbottom
    m_fNormalRect[9] = fRight;
    m_fNormalRect[10] = fTop;

    //leftbottom
    m_fNormalRect[12] = fLeft;
    m_fNormalRect[13] = fTop;

    //righttop
    m_fNormalRect[15] = fRight;
    m_fNormalRect[16] = fBottom;
}

void QVideoWidget::InitState()
{
    //m_pThumbnail->InitState();
}

void QVideoWidget::DrawRecord()
{
    /*
    QOpenGLTexture* pTexture = NULL;
    m_pShaderThumbnail->Bind();
    m_pShaderThumbnail->SetUniformValue();
    m_pShaderThumbnail->EnableAttributeArray();


    m_VBORecord.bind();
    m_pShaderThumbnail->SetAttributeBuffer();
    m_VBORecord.release();

    if(m_bRecording==false)
    {
        pTexture = m_pButtonRecord->GetTextureNormal();
    }
    else
    {
        pTexture = m_pButtonRecord->GetTextureClicked();
    }

    pTexture->bind();
    glDrawArrays(GL_TRIANGLES, 0, 6);
    pTexture->release();

    m_pShaderThumbnail->DisableAttributeArray();

    m_pShaderThumbnail->Release();
    */
}

void QVideoWidget::DrawCapture()
{
    /*
    QOpenGLTexture* pTexture = NULL;
    m_pShaderThumbnail->Bind();
    m_pShaderThumbnail->SetUniformValue();
    m_pShaderThumbnail->EnableAttributeArray();


    m_VBOCapture.bind();
    m_pShaderThumbnail->SetAttributeBuffer();
    m_VBOCapture.release();

    if(m_bCapturing==false)
    {
        pTexture = m_pButtonCapture->GetTextureNormal();
    }
    else
    {
        pTexture = m_pButtonCapture->GetTextureClicked();
    }

    pTexture->bind();
    glDrawArrays(GL_TRIANGLES, 0, 6);
    pTexture->release();

    m_pShaderThumbnail->DisableAttributeArray();

    m_pShaderThumbnail->Release();
    */


}

void QVideoWidget::SetCapturing()
{
    m_bCapturing = true;
}

uint8_t* QVideoWidget::GetCaptureImage()
{
    uint8_t* pData = m_QueueData[m_nIndexCurrent%m_nCountQueue];
    return pData;
}

void QVideoWidget::Reset()
{
    m_nIndexCurrent = 0;
    m_nIndexDisplay = 0;

    m_bRecording = false;
    m_bCapturing = false;

    m_bFullScreen = false;
}

void QVideoWidget::SetChangeTexture(bool bUpdate)
{
    m_bChange = bUpdate;
    m_nIndexCurrent = 0;
    m_nIndexDisplay = 0;
}

void QVideoWidget::Init()
{
    ClearQueueData();

    CommonData* pCommonData = MainWindow::GetCommonData();
    int nVideoWidth = pCommonData->GetVideoWidth();
    int nVideoHeight = pCommonData->GetVideoHeight();

    m_nIndexCurrent = 0;
    m_nIndexDisplay = 0;

    m_bRecording = false;
    m_bCapturing = false;

    m_bFullScreen = false;

    memset(m_pData, 0, sizeof(uint8_t)*nVideoWidth*nVideoHeight*4);
    //m_bChange = true;

    m_bInitDisplay = false;

    connect(&m_Timer, SIGNAL(timeout()), this, SLOT(Update()));

    m_StartTime.restart();

    m_Timer.start(8);

    m_TimerFPS.restart();
    m_nUpdateFrameCount = 0;


}

void QVideoWidget::Exit()
{
    CommonData* pCommonData = MainWindow::GetCommonData();
    int nVideoWidth = pCommonData->GetVideoWidth();
    int nVideoHeight = pCommonData->GetVideoHeight();

    ClearQueueData();

    m_nIndexCurrent = 0;
    m_nIndexDisplay = 0;

    m_bRecording = false;
    m_bCapturing = false;

    m_bFullScreen = false;

    memset(m_pData, 0, sizeof(uint8_t)*nVideoWidth*nVideoHeight*4);
    m_bChange = true;

    m_bInitDisplay = false;

    disconnect(&m_Timer, SIGNAL(timeout()), this, SLOT(Update()));
    m_Timer.stop();
}

void QVideoWidget::Update()
{
    update();

    QGstreamerPlayer* pPlayer = NULL;

    CommonData* pCommonData = MainWindow::GetCommonData();


    bool bIsStart = false;
    if(bIsStart==false)
    {

        pPlayer = pCommonData->GetThreadRTSP()->GetGstreamerPlayer();

        if(pPlayer==NULL)
        {
            return;
        }

        if(pPlayer->IsPipeStart()==true)
        {
            int nUpdateTextureTime = m_StartTime.elapsed();


            if(nUpdateTextureTime>2100)
            {
                int a=0;
                //pPlayer->Alram();
                //pCommonData->GetThreadRTSP()->Restart();
            }
        }
        else
        {
            m_StartTime.restart();
        }
    }


}


void QVideoWidget::UpdateObjectDisplay(vector<QRect>& listRectDisplay)
{
    m_listRectObject = listRectDisplay;
}



bool QVideoWidget::Lock()
{
    //m_Lock.lock();
    bool bLock = m_Lock.tryLock(100);

    if(bLock==false)
    {
        int a=0;
    }


    return bLock;
}

void QVideoWidget::Unlock()
{
    m_Lock.unlock();
}


void QVideoWidget::ClearQueueData()
{
    CommonData* pCommonData = MainWindow::GetCommonData();
    int nVideoWidth = pCommonData->GetVideoWidth();
    int nVideoHeight = pCommonData->GetVideoHeight();

    int i=0;
    for(i=0 ; i<m_QueueData.size() ; i++)
    {
        uint8_t* pData = m_QueueData[i];
        memset(pData, 0, sizeof(uint8_t)*nVideoWidth*nVideoHeight*4);
    }
}
