Qt openGL立方体六个面播放视频

       驾校回来几天了,继续干openGL,之前有一个帖子是立方体六个面不同纹理的。

      这次使用vs+Qt一块写的,Qt里直接配置opencv打不开视频文件,被逼无奈,只能vs里用qt tools,然后在我们设计ui时候,如果vs里直接打开会卡死,直接在文件夹里打开ui,至于qrc源文件,这就多点耐心,卡死了慢慢来就行。

       这次播放是播放个立方体视频,每个面不同视频。其实核心就是opencv+openGL,调用一个时间槽函数,每隔一段时间比如20ms去调用on_timeout()函数,然后函数里用openCV获取视频每一帧,然后转化成Qimage,再调用update()函数,openGL去渲染成为纹理。有个很要命的问题,就是当时显示了d->textureId报错,然后想了挺多方法,最后是把获取的帧的总数减掉一个值(到现在也没太懂,可能是有些帧没办法变成图片,还是帧转化为Qiamge中间有些问题?望懂得小伙伴给我讲讲)。

opencv配置啥的,b站搜一下,很详细,不多说了,画立方体播放不同视频,其实是画立方体每个面不同纹理的进阶版,不懂得可以看我之前写的帖子。

超详细讲解。QT+OpenGL画出不同纹理面立方体(部分面可反色)_硏的博客-CSDN博客

这是axbopenglwidget.cpp

#include "axbopenglwidget.h"
#include 
#include
#include
#include "opencv2/imgproc/types_c.h"
#include "mainwindow.h"
#include 

using namespace cv;
int count = 0;
unsigned int VBO, VAO, EBO;
unsigned int VBO1, VAO1, EBO1;
//VideoCapture capture;
int flag = 0;
int countt = 0;
int count1 = 0;
VideoCapture capture[6];
Mat frame[6], dst, Myvideo;
GLuint myTex;
int totalnumber[6];
float vertices[] = {
    -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
    0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
    0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
    0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
    -0.5f, 0.5f, 0.5f, 0.0f, 1.0f,
    -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,

    -0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
     0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
     0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
     0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
    -0.5f, 0.5f, 0.5f, 0.0f, 0.0f,
    -0.5f, 0.5f, -0.5f, 0.0f, 1.0f,

-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
 0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
 0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
 0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,


-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 1.0f, 0.0f,

 0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
 0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
 0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
 0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
 0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
 0.5f, 0.5f, 0.5f, 1.0f, 0.0f,

-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,
 0.5f, -0.5f, -0.5f, 1.0f, 1.0f,
 0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
 0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f,

    


};

QVector cubePositions = {
QVector3D(0.0f, 0.0f, 0.0f),
/*QVector3D( 2.0f, 5.0f, -15.0f),
QVector3D(-1.5f, -2.2f, -2.5f),
QVector3D(-3.8f, -2.0f, -12.3f),
QVector3D( 2.4f, -0.4f, -3.5f),
QVector3D(-1.7f, 3.0f, -7.5f),
QVector3D( 1.3f, -2.0f, -2.5f),
QVector3D( 1.5f, 2.0f, -2.5f),
QVector3D( 1.5f, 0.2f, -1.5f),
QVector3D(-1.3f, 1.0f, -1.5f)*/
};
float vertices1[] = {

    -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
    0.5f, -0.5f, 0.5f, 1.0f, 0.0f,
    0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
    0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
    -0.5f, 0.5f, 0.5f, 0.0f, 1.0f,
    -0.5f, -0.5f, 0.5f, 0.0f, 0.0f,

    -0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
     0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
     0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
     0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
    -0.5f, 0.5f, 0.5f, 0.0f, 0.0f,
    -0.5f, 0.5f, -0.5f, 0.0f, 1.0f
};


unsigned int indices[] = { // note that we start from 0!
                           0, 1, 3, // first triangle
                           1, 2, 3 // second triangle
};
float ratio = 0.5;
AXBOpenGLWidget::AXBOpenGLWidget(QWidget* parent) : QOpenGLWidget(parent)
{    
    //初始化中将totalnumber,currentnumber,flag都设置为0
    //当currentnumber==totalnumber-15,15是自己试验的一个数,直接写两者等于会报错,flag[i]设置为1,这时候这个视频所有画面播放结束
    
    for (int i = 0; i < 6; i++)
    {
        totalnumber[i] = 0;
        currentnumber[i] = 0;
        flag[i] = 0;
    }
// 调用时间槽函数,on_timeout()中调用opencv获取帧
    setFocusPolicy(Qt::StrongFocus);
    connect(&timer, SIGNAL(timeout()), this, SLOT(on_timeout()));
    timer.start(10);
}
//析构函数,删除VAO VBO
AXBOpenGLWidget::~AXBOpenGLWidget()
{
    makeCurrent();
    glDeleteBuffers(1, &VBO);
    glDeleteVertexArrays(1, &VAO);
    doneCurrent();
}
//帧转化为Qimage,网上找到的,也不知道对不对(opencv还没开始学)
QImage Mat2QImage(cv::Mat& image)
{
    QImage img;

    if (image.channels() == 3) {
        cvtColor(image, image, CV_BGR2RGB);
        img = QImage((const unsigned char*)(image.data), image.cols, image.rows,
            image.cols * image.channels(), QImage::Format_RGB888);
    }
    else if (image.channels() == 1) {
        img = QImage((const unsigned char*)(image.data), image.cols, image.rows,
            image.cols * image.channels(), QImage::Format_ARGB32);
    }
    else {
        img = QImage((const unsigned char*)(image.data), image.cols, image.rows,
            image.cols * image.channels(), QImage::Format_RGB888);
    }

    return img;
}



void AXBOpenGLWidget::initializeGL()
{
    initializeOpenGLFunctions();
    bool success;
    for (int i = 0; i < 6; i++)
    {
        shaderProgram[i].addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/shapes_1.vert");
        shaderProgram[i].addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/shapes_1.frag");
        success = shaderProgram[i].link();
        if (!success)
            qDebug() << "ERR:" << shaderProgram[i].log();
    }
    for (int i = 0; i < 6; i++)
    {
        textureSmall[i]= new QOpenGLTexture(QImage(":/images/wall.jpg").mirrored());
        shaderProgram[i].bind();
        shaderProgram[i].setUniformValue("textureSmall", 0);

    }
//初始化流程,VAO,VBO的创建以及绑定,还有指针告诉其怎么运作
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    QMatrix4x4 projection;
    projection.perspective(45, (float)width() / height(), 0.1, 100);
//给定projection。这一部分直接参考立方体画六个面的纹理,上个帖子就是
    for (int i = 0; i < 6; i++) {
        shaderProgram[i].bind();
        shaderProgram[i].setUniformValue("textureSmall", 0);
        shaderProgram[i].setUniformValue("projection", projection);
    }
    glBindVertexArray(0);

}

void AXBOpenGLWidget::resizeGL(int w, int h)
{
    Q_UNUSED(w);Q_UNUSED(h);
    //glViewport(0, 0, w, h);
}

void AXBOpenGLWidget::paintGL()
{
//interval就是每次绘画时候的范围
    int interval = 0;
    QMatrix4x4 model;
    QMatrix4x4 view;
    unsigned int time = QTime::currentTime().msec();

    view.translate(0.0, 0.0, -3);
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glEnable(GL_DEPTH_TEST);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   //给定view和model。这一部分直接参考立方体画六个面的纹理,上个帖子就是
    model.setToIdentity();
    model.translate(cubePositions[0]);
    model.rotate(45, 1.0f, 1.0f, 1.0f);
    for (int i = 0; i < 6; i++) {
        shaderProgram[i].bind();
        shaderProgram[i].setUniformValue("ratio", ratio);
        shaderProgram[i].setUniformValue("view", view);
        shaderProgram[i].setUniformValue("model", model);
    }

        glBindVertexArray(VAO);
//每次绑定shaderprogram,然后画图,这样子就一次性把六个面渲染完了,然后下次调用paintGL,interval重新回到0,再次画新的帧。缺点是单线程真的很慢
        for (int i = 0; i < 6; i++) {
            shaderProgram[i].bind();
            textureSmall[i]->bind(0);
            glDrawArrays(GL_TRIANGLES, interval,interval+6);
            interval = interval + 6;
        }
 
}
 

 void AXBOpenGLWidget::on_timeout() {
//六个面,每个面都是获取帧,然后一帧一帧播放
     for (int i = 0; i < 6; i++)
     {
         if (flag[i] == 0)
         {
             capture[i] >> frame[i];
             if (currentnumber[i] % 1 == 0)
             {
//这里减去15可以保证视频播放结束不崩
                 if (currentnumber[i] == totalnumber[i] - 15)

                 {
                     flag[i] = 1;
                 }

                 else 
                 {
//frame转化为Qimage,然后分别绑定shaderprogram和着色器程序里的值
                     QImage img = Mat2QImage(frame[i]);
                     shaderProgram[i].bind();
                     shaderProgram[i].setUniformValue("textureSmall", 0);
//opengl纹理是倒过来的,所以用个mirrored,让其方向正过来
                     textureSmall[i] = new QOpenGLTexture(img.mirrored());
                 }
//每次渲染完一幅图片,就++
                 currentnumber[i]++;
             }
//转到paintGL函数喽
             update();
         }
     }
 }


int main(int argc, char* argv[])
{
    QApplication a(argc, argv);

    MainWindow w;
    //读取六个视频,分别放到立方体六个面
    capture[0].open("a.avi");
    capture[1].open("b.avi");
    capture[2].open("c.avi");
    capture[3].open("d.avi");
    capture[4].open("e.avi");
    capture[5].open("yi.avi");
    for (int i = 0; i < 6; i++)
    {
         //打开视频并且获得每个视频总帧数
        if (!capture[i].isOpened())
            std::cout << "could not load video data" << endl;
//新版本中是CAP_PROP_FRAME_COUNT
        totalnumber[i] = capture[i].get(CAP_PROP_FRAME_COUNT);
    }
   //显示窗口,这时候就到了构造函数中调用时间槽函数
    w.show();
    return a.exec();
}

然后这是对应的头文件

#ifndef AXBOPENGLWIDGET_H
#define AXBOPENGLWIDGET_H

#include 
#include 
#include 
#include 
#include 
#include
#include
#include "opencv2/imgproc/types_c.h"

class AXBOpenGLWidget : public QOpenGLWidget, QOpenGLFunctions_3_3_Core
{
    Q_OBJECT
public:
    enum Shape { None, Rect, Circle, Triangle };
    explicit AXBOpenGLWidget(QWidget* parent = nullptr);
    ~AXBOpenGLWidget();
    void drawShape(Shape shape);
    void setWirefame(bool wireframe);
protected:
    virtual void initializeGL();
    virtual void resizeGL(int w, int h);
    virtual void paintGL();
signals:

public slots:
    void on_timeout();
private:
    Shape m_shape;
    QWidget* w1;
    QOpenGLShaderProgram shaderProgram[6];
    QOpenGLTexture* textureSmall[6];
    int currentnumber[6];
    int flag[6];  
    QTimer timer;
};



#endif // AXBOPENGLWIDGET_H
#version 330 core
out vec4 FragColor;
out vec4 Color;
in vec2 TexCord;
uniform sampler2D textureSmall;
void main(){
    Color=texture(textureSmall,TexCord);
}

shapes_1.frag

     #version 330 core
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec2 aTexCord;
out vec2 TexCord;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main(){
    gl_Position = projection*view*model*vec4(aPos.x, aPos.y, aPos.z, 1.0f);
    TexCord=aTexCord;
}

shapes_1.vert

其他mainwindow什么的按原来的就OK,不需要多改

你可能感兴趣的:(音视频,qt,opencv)