轩Dawn 2023-10-18 10:45 采纳率: 100%
浏览 6
已结题

我用qt + opengl写了一个读取yuv视频文件并渲染的代码,问题是我渲染横屏的视频没问题,但是我渲染竖屏的视频就会出问题,找不到原因在哪想让各位看看是什么原因。非常感谢

截图如下:

img


```c++
#include "gl_show_widget.h"
#include <QOpenGLTexture>
#include <QOpenGLBuffer>
#include <QMouseEvent>
#include <QTimer>

static const uint32_t VideoWidth = 886;
static const uint32_t VideoHeight = 1920;

#define GL_VERSION_this  "#version 330 core\n"
#define GET_GLSTR(x) GL_VERSION_this#x

const char *vsrc = GET_GLSTR(
    layout (location = 0) in vec2 position; // 顶点坐标
    out vec2 texCoord; // 纹理坐标传递给片段着色器

    void main()
    {
        gl_Position = vec4(position, 0.0, 1.0);
        texCoord = position * 0.5 + 0.5; // 将顶点坐标转换为纹理坐标范围
    }
);

const char *fsrc =GET_GLSTR(
    in vec2 texCoord; // 从顶点着色器传递的纹理坐标

    uniform sampler2D yTexture; // Y分量纹理
    uniform sampler2D uTexture; // U分量纹理
    uniform sampler2D vTexture; // V分量纹理

    out vec4 fragColor; // 最终的颜色输出

    void main()
    {
        float y = texture(yTexture, texCoord).r;
        float u = texture(uTexture, texCoord).r - 0.5;
        float v = texture(vTexture, texCoord).r - 0.5;

        // YUV到RGB转换
        float r = y + 1.13983 * v;
        float g = y - 0.39465 * u - 0.5806 * v;
        float b = y + 2.03211 * u;

        // 输出RGB颜色
        fragColor = vec4(r, g, b, 1.0);
    }
);

GLShowWidget::GLShowWidget(QWidget *parent) : QOpenGLWidget(parent)
{
    qDebug() << "GLShowWidget::GLShowWidget";
    vbo_ = QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
    m_sharder_program_ = new QOpenGLShaderProgram();
    m_textureYUV_ = std::vector<QOpenGLTexture*>(3, nullptr);

    QSurfaceFormat format;
    format.setDepthBufferSize(24);
    format.setStencilBufferSize(8);
    format.setVersion(3, 3);
    format.setProfile(QSurfaceFormat::CoreProfile);
    QSurfaceFormat::setDefaultFormat(format);
    setFormat(format);
}

GLShowWidget::~GLShowWidget()
{
    qDebug("GLShowWidget::~GLShowWidget");
    if (!m_textureYUV_.empty()) {
        for (auto texture : m_textureYUV_) {
            texture->destroy();
            delete texture;
        }
        m_textureYUV_.clear();
    }

    if (m_sharder_program_) {
        m_sharder_program_->release();
        delete m_sharder_program_;
        m_sharder_program_ = nullptr;
    }
    vbo_.destroy();
    vao_.destroy();
}

void GLShowWidget::initializeGL() {
    qDebug() << "GLShowWidget::initializeGL";

    m_file_.setFileName("/Users/chengchao/Desktop/886x1920.yuv");
    if(!m_file_.open(QIODevice::ReadOnly))
    {
        qDebug() << "打开失败!";
        return;
    }

//    {
//        QFile test_file("/Users/chengchao/Desktop/886x1920_first_frame.yuv");
//        test_file.open(QIODevice::ReadWrite);
//        QByteArray buf = m_file_.read(VideoWidth * VideoHeight * 3 / 2);
//        test_file.write(buf);
//        test_file.close();
//    }

    initializeOpenGLFunctions();
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);

    for(int i = 0; i < 3; i++)
    {
        m_textureYUV_[i] = new QOpenGLTexture(QOpenGLTexture::Target2D);
        m_textureYUV_[i]->create();

        if(i == 0)
        {
            m_textureYUV_[i]->setSize(VideoWidth, VideoHeight);
        }
        else
        {
            m_textureYUV_[i]->setSize(VideoWidth / 2, VideoHeight / 2);
        }

        m_textureYUV_[i]->setMinMagFilters(QOpenGLTexture::LinearMipMapNearest, QOpenGLTexture::Linear);
        m_textureYUV_[i]->setFormat(QOpenGLTexture::R8_UNorm);
        m_textureYUV_[i]->setWrapMode(QOpenGLTexture::ClampToEdge);
        m_textureYUV_[i]->allocateStorage();        //存储配置(放大缩小过滤、格式、size)

        qDebug() << "textureId: " << m_textureYUV_[i]->textureId();
    }

    vao_.create();
    vao_.bind();

    vbo_.create();
    vbo_.bind();

    m_sharder_program_->addShaderFromSourceCode(QOpenGLShader::Vertex, vsrc);
    m_sharder_program_->addShaderFromSourceCode(QOpenGLShader::Fragment, fsrc);
    m_sharder_program_->link();
    m_sharder_program_->bind();

    float vertices[] = {
        //顶点坐标
        -1.0f, -1.0f,
        1.0f, -1.0f,
        -1.0f, 1.0f,
        1.0f, 1.0f,
    };

    vbo_.allocate(vertices, sizeof(vertices));
    vbo_.setUsagePattern(QOpenGLBuffer::StaticDraw);

    m_sharder_program_->setAttributeBuffer(0, GL_FLOAT, 0, 2, 2 * sizeof(float));

    m_sharder_program_->enableAttributeArray(0);

    m_sharder_program_->setUniformValue("yTexture", 0);
    m_sharder_program_->setUniformValue("uTexture", 1);
    m_sharder_program_->setUniformValue("vTexture", 2);

    vbo_.release();
    vao_.release();

    //启动定时器
    QTimer *ti = new QTimer(this);
    connect(ti, SIGNAL(timeout()), this, SLOT(update()));
    ti->start(30);
}

void GLShowWidget::paintGL() {
    qDebug() << "GLShowWidget::paintGL";
    glClear(GL_COLOR_BUFFER_BIT);

    glViewport(0, 0, VideoWidth, VideoHeight);

    vao_.bind();
    vbo_.bind();
    if (m_file_.atEnd())
    {
        m_file_.seek(0);
    }

    QByteArray buf = m_file_.read(VideoWidth * VideoHeight);
    m_textureYUV_[0]->setData(QOpenGLTexture::Red,QOpenGLTexture::UInt8,buf.data());
    m_textureYUV_[0]->bind(0);

    buf = m_file_.read(VideoWidth * VideoHeight / 4);
    m_textureYUV_[1]->setData(QOpenGLTexture::Red,QOpenGLTexture::UInt8,buf.data());
    m_textureYUV_[1]->bind(1);

    buf = m_file_.read(VideoWidth * VideoHeight / 4);
    m_textureYUV_[2]->setData(QOpenGLTexture::Red,QOpenGLTexture::UInt8,buf.data());
    m_textureYUV_[2]->bind(2);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    m_textureYUV_[0]->release();
    m_textureYUV_[1]->release();
    m_textureYUV_[2]->release();

    vbo_.release();
    vao_.release();
}

void GLShowWidget::resizeGL(int w, int h) {
    qDebug() << "resizeGL "<<w<<":"<<h;
}


```

  • 写回答

2条回答 默认 最新

  • 轩Dawn 2023-10-18 19:31
    关注

    在 setData之前调佣一下下面的代码:

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录
查看更多回答(1条)

报告相同问题?

问题事件

  • 系统已结题 10月26日
  • 已采纳回答 10月18日
  • 创建了问题 10月18日

悬赏问题

  • ¥100 任意维数的K均值聚类
  • ¥15 stamps做sbas-insar,时序沉降图怎么画
  • ¥15 unity第一人称射击小游戏,有demo,在原脚本的基础上进行修改以达到要求
  • ¥15 买了个传感器,根据商家发的代码和步骤使用但是代码报错了不会改,有没有人可以看看
  • ¥15 关于#Java#的问题,如何解决?
  • ¥15 加热介质是液体,换热器壳侧导热系数和总的导热系数怎么算
  • ¥100 嵌入式系统基于PIC16F882和热敏电阻的数字温度计
  • ¥15 cmd cl 0x000007b
  • ¥20 BAPI_PR_CHANGE how to add account assignment information for service line
  • ¥500 火焰左右视图、视差(基于双目相机)