OpenGL+FFmpeg实现GPU硬解码视频播放

OpenGL渲染流程

1. 着色器准备

需要准备:

  • 顶点着色器代码
  • 片段着色器代码
  • 顶点数组
  • 索引缓冲对象(IBO)数组

2. 缓冲区设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 创建并绑定VAO
GLuint VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);

// 创建并绑定VBO和IBO
GLuint VBO, IBO;
glGenBuffers(1, &VBO);
glGenBuffers(1, &IBO);

// 传入数据
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

3. 着色器编译与链接

1
2
3
4
5
6
7
// 编译着色器
program.addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);
program.addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);

// 链接程序
program.link();
program.bind();

4. 属性指针设置

1
2
3
// 对应着色器中的layout (location = 0)
program.enableAttributeArray(0); // 顶点位置
program.enableAttributeArray(1); // 纹理坐标

5. 矩阵变换

1
2
3
4
5
// 设置MVP矩阵
QMatrix4x4 model, view, projection;
program.setUniformValue("model", model);
program.setUniformValue("view", view);
program.setUniformValue("projection", projection);

FFmpeg硬解码部分

1. 初始化硬解码器

1
2
3
4
5
// 查找硬解码器
const AVCodec *codec = avcodec_find_decoder_by_name("h264_cuvid"); // NVIDIA GPU
if (!codec) {
codec = avcodec_find_decoder_by_name("h264_qsv"); // Intel GPU
}

2. 解码并传输到GPU

1
2
3
4
5
6
7
8
9
// 解码后直接得到GPU纹理
AVFrame *frame = av_frame_alloc();
avcodec_send_packet(codecContext, packet);
avcodec_receive_frame(codecContext, frame);

// 创建OpenGL纹理
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);

渲染循环

1
2
3
4
5
6
7
8
9
10
11
void paintGL() {
// 清空缓冲
glClear(GL_COLOR_BUFFER_BIT);

// 绑定程序和纹理
program.bind();
glBindTexture(GL_TEXTURE_2D, texture);

// 绘制
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
}

图片1
图片1

注意事项

  1. 硬解码支持:

    • 需要确保GPU支持对应格式的硬解码
    • 需要正确安装GPU驱动
  2. 性能优化:

    • 使用PBO(Pixel Buffer Object)进行异步传输
    • 考虑使用多重缓冲
  3. 同步处理:

    • 注意音视频同步
    • 控制帧率