介绍一下cpu中的yuv转rgb和opengl中的yuv转rgb和直接nv12转rbg方法
YUV/NV12到RGB的转换方案
CPU中的YUV转RGB
FFmpeg方案
- FFmpeg解码默认输出YUV格式
- 使用
sws_getCachedContext
进行格式转换 - 转换目标格式为
AV_PIX_FMT_RGBA
- 适合简单场景,但CPU消耗较大
OpenGL中的YUV转RGB方案
方案一:RGB纹理渲染
继承关系
1
class PlayImage : public QOpenGLWidget, public QOpenGLFunctions_3_3_Core
初始化
1
2
3
4
5void initializeGL() {
// 创建并绑定VAO/VBO/IBO
// 编译连接着色器程序
// 启用顶点属性数组
}图像更新
1
2
3
4void updateImage(const QImage& image) {
// 垂直翻转(OpenGL纹理Y轴相反)
m_texture = new QOpenGLTexture(image.mirrored());
}渲染
1
2
3
4
5
6void paintGL() {
// 绑定着色器程序
// 绑定纹理
// 绑定VAO
glDrawElements(...);
}
方案二:直接YUV渲染
- 数据传递
- 直接使用
AVFrame
传递解码数据 - 使用
BlockingQueuedConnection
确保数据安全
信号槽配置
1
2
3
4
5
6
7// 注册AVFrame用于信号传递
Q_DECLARE_METATYPE(AVFrame)
// 连接信号槽
connect(m_readThread, &ReadThread::repaint,
playImage, &PlayImage::repaint,
Qt::BlockingQueuedConnection);纹理处理
1
2
3
4
5
6
7// 三个纹理对应YUV分量
QOpenGLTexture *m_texY, *m_texU, *m_texV;
// 设置纹理单元
m_program->setUniformValue("tex_y", 0);
m_program->setUniformValue("tex_u", 1);
m_program->setUniformValue("tex_v", 2);渲染实现
1
2
3
4
5
6void paintGL() {
m_texY->bind(0);
m_texU->bind(1);
m_texV->bind(2);
// 执行绘制
}
OpenGL中直接处理NV12
优势
- 避免CPU中的格式转换
- 性能提升约1/3
- 直接在GPU中完成转换
实现要点
- 使用
av_hwframe_map
替代av_hwframe_transfer_data
- 移除
sws_scale
相关代码 - 直接返回硬件帧
格式适配
1 | void initialize() { |
渲染流程
1 | void paintGL() { |
性能对比
CPU转换方案
- 实现简单
- CPU占用高
- 适合简单场景
OpenGL YUV方案
- 中等复杂度
- GPU处理
- 性能较好
OpenGL NV12方案
- 实现较复杂
- 性能最优
- 适合高性能需求
```
评论