opengl渲染yuv图像
作者:史正
邮箱:shizheng163@126.com
如有错误还请及时指正
如果有错误的描述给您带来不便还请见谅
如需交流请发送邮件,欢迎联系
- 我的csdn : https://blog.csdn.net/shizheng163
- 我的github : https://github.com/shizheng163
简述
直接渲染Jpeg等编码后的图像(这里使用的是Jpeg图片)是特别慢的(当张图片>40ms), 常用的做法是直接渲染yuv或者rgb的图像。
这里使用的是使用opengl渲染yuv的图像, 当然也可以通过Qt的绘图库来渲染。不过opengl默认的渲染步骤是在gpu上执行的, 而Qt的绘图库是利于cpu进行计算,gpu进行渲染, 占用cpu的资源比较多。
使用opengl渲染yuv图像的时间单帧图像为(0-2]ms
渲染完成后使主线程等待40-渲染时间, 就会呈现出视频的效果。
这一节的完整代码:
这里给出几个ffmpeg将视频分解为jpeg然后再转换为yuv的命令(由于没有找到视频直接分解为yuv图片帧的办法)
ffmpeg -i Suger.mp4 -b 3000k -ss 00:00:10 -t 10 SugerFrames/Frame_%04d.jpeg
ffmpeg -y -s 1920x1080 -i SugerFrames/yuv_0001.jpeg SugerYuvs/yuv_0001.yuv
由于没有找到直接将多张jpeg图片直接转换为多张yuv图像的方法, 这里写了一个shell脚本来处理
for((i=1;i<=480;i++))
do
index=`printf "%04d" $i`
ffmpeg -y -s 1920x1080 -i SugerFrames/yuv_$index.jpeg SugerYuvs/yuv_$index.yuv
done
ffmpeg 查看yuv图像或视频的方法
ffplay.exe -video_size 1920x1080 yuv_0001.yuv
使用QOpenGLWidget进行yuv图片渲染
除了可以选择使用QPainter和标准的OpenGL渲染图形,QOpenGLWidget类提供了在Qt应用程序中显示OpenGL图形的功能。
关于QOpenGLWidget
的介绍可以参考以下文章:
笔者对opengl基本上没什么了解, 渲染部分选自以下博客,感谢博主
另外glviewport
是opengl渲染的图片显示的位置, 坐标原点为左下角。
使用了opengl渲染之后,再使用QPainter渲染(当时只是想使用这个渲染默认的Jpeg图标)就会导致opengl和QPainter渲染的效果无法使用。
解决方法还没有找到, 所以干脆就把默认图片也转成了yuv图像。
.h文件
#ifndef VIDEOGLWIDGET_H
#define VIDEOGLWIDGET_H
#include <QWidget>
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <memory>
#include <mutex>
#include <QOpenGLShaderProgram>
#include <QOpenGLFunctions>
#include <QOpenGLTexture>
#include "fileutil.h"
class VideoGLWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
QOBJECT_H
public:
VideoGLWidget(QWidget * pParent = 0);
virtual ~VideoGLWidget();
void PictureShow(fileutil::PictureFilePtr pPicture);
void DefaultPictureShow();
protected:
void initializeGL();
void resizeGL(int w, int h);
void paintGL();
private:
//绘图是异步动作, 防止绘图过程中,图片被置为NULL,所以需要加锁
std::mutex m_mutexForShowYuvData;
bool m_bIsShowVideoIcon; //是否要显示视频默认图标
fileutil::PictureFilePtr m_pDefaultPict;//默认图片
fileutil::PictureFilePtr m_pYuvPictPtr;//当前需要显示的Yuv数据
//显示Opengl渲染后图像位置
QRect m_drawRect;
//渲染yuv图像变量
GLuint textureUniformY; //y纹理数据位置
GLuint textureUniformU; //u纹理数据位置
GLuint textureUniformV; //v纹理数据位置
GLuint id_y; //y纹理对象ID
GLuint id_u; //u纹理对象ID
GLuint id_v; //v纹理对象ID
QOpenGLTexture* m_pTextureY; //y纹理对象
QOpenGLTexture* m_pTextureU; //u纹理对象
QOpenGLTexture* m_pTextureV; //v纹理对象
QOpenGLShader * m_pVSHader; //顶点着色器程序对象
QOpenGLShader * m_pFSHader; //片段着色器对象
QOpenGLShaderProgram *m_pShaderProgram; //着色器程序容器
};
#endif // VIDEOGLWIDGET_H
PicturePtr结构如下
#include <string>
#include <stdint.h>
#include <memory>
struct FileRawData
{
FileRawData(){
m_pData = NULL;
}
FileRawData(FileRawData && filedata)
{
m_pData = filedata.m_pData;
m_uLen = filedata.m_uLen;
m_filename = filedata.m_filename;
filedata.m_pData = NULL;
filedata.m_uLen = 0;
filedata.m_filename.clear(