Cpper
C/C++高级工程师 Android高级软件工程师 IT集成工程师 音频工程师 熟悉c,c++,java,c#,py,js,asp等多种语言 程序猿
class VideoRenderer : public QObject, public QQuickFramebufferObject::Renderer, public QOpenGLFunctions
{
    Q_OBJECT
public:
    
explicit VideoRenderer(QQuickFramebufferObject* object);
    
~VideoRenderer();

    QOpenGLFramebufferObject
* createFramebufferObject(const QSize& size);
    
void render();
public slots:
    
void updateVideoFrame(AVFrame* frame);
    
void paint();
private:
    std::mutex mux;
    QGLShaderProgram program;
    GLuint yuv[
3= { 0 };
    GLuint textures[
3= { 0 };
    unsigned 
char* datas[3= { 0 };
    QSize videoSize;
    QQuickFramebufferObject
* fbo;
};

VideoRenderer::VideoRenderer(QQuickFramebufferObject
* object):
QObject(
object)
{
    fbo 
= object;
    initializeOpenGLFunctions();

    qDebug() 
<< program.addShaderFromSourceCode(QGLShader::Fragment, tString);
    qDebug() 
<< program.addShaderFromSourceCode(QGLShader::Vertex, vString);

    program.bindAttributeLocation(
"vertexIn", A_VER);
    program.bindAttributeLocation(
"textureIn", T_VER);
    
    qDebug() 
<< "program.link() = " << program.link();
    qDebug() 
<< "program.bind() = " << program.bind();

    
static const GLfloat ver[] = {
        
-1.0f,-1.0f,
        
1.0f,-1.0f,
        
-1.0f1.0f,
        
1.0f,1.0f
    };

    
static const GLfloat tex[] = {
        
0.0f1.0f,
        
1.0f1.0f,
        
0.0f0.0f,
        
1.0f0.0f
    };

    glVertexAttribPointer(A_VER, 
2, GL_FLOAT, 00, ver);
    glEnableVertexAttribArray(A_VER);

    glVertexAttribPointer(T_VER, 
2, GL_FLOAT, 00, tex);
    glEnableVertexAttribArray(T_VER);

    yuv[
0= program.uniformLocation("tex_y");
    yuv[
1= program.uniformLocation("tex_u");
    yuv[
2= program.uniformLocation("tex_v");

    mux.unlock();

    glGenTextures(
3, textures);
}

VideoRenderer::
~VideoRenderer()
{
    
if(datas[0])
    {
        
for(int i = 0; i < 3; i++)
            delete datas[i];
    }
}

void SaveAvFrame(const QString& file,AVFrame* avFrame)
{
    FILE 
*fDump = fopen(file.toLocal8Bit().data(), "ab");

    uint32_t pitchY 
= avFrame->linesize[0];
    uint32_t pitchU 
= avFrame->linesize[1];
    uint32_t pitchV 
= avFrame->linesize[2];

    uint8_t 
*avY = avFrame->data[0];
    uint8_t 
*avU = avFrame->data[1];
    uint8_t 
*avV = avFrame->data[2];

    
for (uint32_t i = 0; i < avFrame->height; i++) {
        fwrite(avY, avFrame
->width, 1, fDump);
        avY 
+= pitchY;
    }

    
for (uint32_t i = 0; i < avFrame->height / 2; i++) {
        fwrite(avU, avFrame
->width / 21, fDump);
        avU 
+= pitchU;
    }

    
for (uint32_t i = 0; i < avFrame->height / 2; i++) {
        fwrite(avV, avFrame
->width / 21, fDump);
        avV 
+= pitchV;
    }

    fclose(fDump);
}

void VideoRenderer::updateVideoFrame(AVFrame* frame)
{
    
if(!frame)
        
return;

    mux.
lock();

    
if (frame->width != videoSize.width() || frame->height != videoSize.height())
    {
        videoSize.setWidth(frame
->width);
        videoSize.setHeight(frame
->height);
        
if (datas[0])
        {
            
for (int i = 0; i < 3; i++)
            {
                delete datas[i];
                datas[i] 
= 0;
            }
        }

        datas[
0= new unsigned char[frame->width*frame->height];        //Y
        datas[1= new unsigned char[frame->width*frame->height / 4];    //U
        datas[2= new unsigned char[frame->width*frame->height / 4];    //V
    }

    
if (!datas[0])
    {
        datas[
0= new unsigned char[frame->width*frame->height];        //Y
        datas[1= new unsigned char[frame->width*frame->height / 4];    //U
        datas[2= new unsigned char[frame->width*frame->height / 4];    //V
    }

    
if (videoSize.width() == frame->linesize[0])
    {
        memcpy(datas[
0], frame->data[0], videoSize.width()*videoSize.height());
        memcpy(datas[
1], frame->data[1], videoSize.width()*videoSize.height() / 4);
        memcpy(datas[
2], frame->data[2], videoSize.width()*videoSize.height() / 4);
    }
    
else
    {
        
for (int i = 0; i < videoSize.height(); i++//
            memcpy(datas[0+ videoSize.width()*i, frame->data[0+ frame->linesize[0* i, videoSize.width());
        
for (int i = 0; i < videoSize.height() / 2; i++//U
            memcpy(datas[1+ videoSize.width() / 2 * i, frame->data[1+ frame->linesize[1* i, videoSize.width());
        
for (int i = 0; i < videoSize.height() / 2; i++//V
            memcpy(datas[2+ videoSize.width() / 2 * i, frame->data[2+ frame->linesize[2* i, videoSize.width());
    }


    mux.unlock();
    av_frame_free(
&frame);

    update();
}

void VideoRenderer::render()
{
    paint();
}

void VideoRenderer::paint()
{
    
if (videoSize.isEmpty())
        
return;

    mux.
lock();

    
//Y
    glBindTexture(GL_TEXTURE_2D, textures[0]);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 
0, GL_RED, videoSize.width(), videoSize.height(), 0, GL_RED, GL_UNSIGNED_BYTE, 0);

    
//U
    glBindTexture(GL_TEXTURE_2D, textures[1]);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 
0, GL_RED, videoSize.width() / 2, videoSize.height() / 20, GL_RED, GL_UNSIGNED_BYTE, 0);

    
//V
    glBindTexture(GL_TEXTURE_2D, textures[2]);

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

    glTexImage2D(GL_TEXTURE_2D, 
0, GL_RED, videoSize.width() / 2, videoSize.height() / 20, GL_RED, GL_UNSIGNED_BYTE, 0);
 

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, textures[
0]); // to y

    glTexSubImage2D(GL_TEXTURE_2D, 
000, videoSize.width(), videoSize.height(), GL_RED, GL_UNSIGNED_BYTE, datas[0]);
    glUniform1i(yuv[
0], 0);

    glActiveTexture(GL_TEXTURE0 
+ 1);
    glBindTexture(GL_TEXTURE_2D, textures[
1]); // 1 to u
    glTexSubImage2D(GL_TEXTURE_2D, 000, videoSize.width() / 2, videoSize.height() / 2, GL_RED, GL_UNSIGNED_BYTE, datas[1]);
    glUniform1i(yuv[
1], 1);


    glActiveTexture(GL_TEXTURE0 
+ 2);
    glBindTexture(GL_TEXTURE_2D, textures[
2]); // 2 to v
    glTexSubImage2D(GL_TEXTURE_2D, 000, videoSize.width() / 2, videoSize.height() / 2, GL_RED, GL_UNSIGNED_BYTE, datas[2]);

    glUniform1i(yuv[
2], 2);

    glDrawArrays(GL_TRIANGLE_STRIP, 
04);
    mux.unlock();

}
 
QOpenGLFramebufferObject
* VideoRenderer::createFramebufferObject(const QSize &size)
{
    QOpenGLFramebufferObjectFormat format;   
//当大小发生变化时,会调用此函数生成对应大小的FBO
    format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
    format.setSamples(
4);
    
return new QOpenGLFramebufferObject(size,format);
}
posted on 2019-08-12 09:25 ccsdu2009 阅读(426) 评论(0)  编辑 收藏 引用 所属分类: QT编程

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理