FFMpeg opengl显示解码avframe

FFmpeg解码出来avframe,但显示很容易出现乱码,因为为了计算的方便,ffmpeg解码出来的数据,总视根据系统处理器或者系统来补齐为 64、32、16的倍数。这也是我们显示乱码的问题所在。

问题

比如我显示抖音上的视频的宽为368x640, 解码的帧率avFrame,下面是avframe的一些成员变量:

avFrame->format = 0 // 表示是 yuv420p的数据格式

avFrame->width = 364

avFrame->height= 640

然后取数据的时候,

y= avFrame->data[0]

u= avFrame->data[1]

v= avFrame->data[2]

将yuv给opengl渲染就会乱码。

解决方法

将宽度设置为linesize

直接获得data[0]的数据,在创建显示texture的时候以,avFrame-linesize[0]作为一帧的宽度:

 // 直接按照填补的 宽度来显示,效率最高,若视频宽度不是64/32(根据系统位数)倍数,右边会存在边框。
    int w = avFrame->linesize[0];
    int h = avFrame->height;
    unsigned char * y  = avFrame->data[0];
    unsigned char * u  = avFrame->data[1] ;
    unsigned char * v  = avFrame->data[2];
    glProgram->Draw(w,h,y,u
### RK3588平台上使用FFmpegOpenGL进行多媒体处理或视频渲染的方法 #### 1. 环境准备 在RK3588上进行多媒体处理和视频渲染前,需确保已安装必要的库和支持工具。具体来说,需要配置好FFmpegOpenGL环境。 对于FFmpeg的支持,在特定的操作系统环境下(如Debian),可以通过包管理器来简化这一过程[^3]: ```bash sudo apt-get update && sudo apt-get install ffmpeg libglu1-mesa-dev freeglut3-dev mesa-common-dev ``` 这一步骤能够确保编译环境中具备了基本的FFmpeg功能模块以及OpenGL开发所需的头文件和其他资源。 #### 2. FFmpeg解码并传递给OpenGL纹理 要实现在Picture控件或其他窗口组件内显示FFmpeg解码后的YUV420P格式图像数据至指定区域的功能,通常会涉及到以下几个方面的工作流程[^1]: - **初始化FFmpeg**: 打开输入流、读取元数据、查找解码器等操作。 - **设置OpenGL上下文**: 创建GLContext,并准备好用于绘制的目标Surface。 - **创建着色器程序**: 编写顶点着色器(Vertex Shader) 和 片段着色器(Fragment Shader),以便于后续将像素颜色转换成屏幕上的可见形式。 下面是一个简单的C++代码片段展示如何利用FFmpeg解析帧并将它们作为纹理上传到OpenGL中: ```cpp extern "C" { #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> } // 初始化AVCodecContext *pCodecCtx; void init_decoder(const char* filename){ AVFormatContext *pFormatCtx = nullptr; int videoStream; av_register_all(); if(avformat_open_input(&pFormatCtx, filename, NULL, NULL)!=0) exit(-1); // Couldn't open file if(avformat_find_stream_info(pFormatCtx,NULL)<0) exit(-1); // Couldn't find stream information videoStream=av_find_best_stream(pFormatCtx,AVMEDIA_TYPE_VIDEO,-1,-1,nullptr,0); pCodecCtx=avcodec_alloc_context3(NULL); avcodec_parameters_to_context(pCodecCtx,pFormatCtx->streams[videoStream]->codecpar); const AVCodec *pCodec = avcodec_find_decoder(pCodecCtx->codec_id); if(!pCodec || avcodec_open2(pCodecCtx, pCodec, NULL) < 0) exit(-1); // Unsupported codec or failed to open it. } ``` 此部分负责打开媒体文件并找到其中的第一个可用视频轨道及其对应的解码器实例化对象`pCodecCtx`. 接着定义函数用来获取每一帧的数据并通过OpenGL API将其呈现出来: ```cpp GLuint textureID; // 假定已经生成了一个有效的纹理名称. bool process_frame(AVFrame *frame){ GLuint fbo; glGenFramebuffers(1,&fbo); glBindFramebuffer(GL_FRAMEBUFFER,fbo); glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,textureID,0); // 将 Y,U,V 数据分别绑定为三个不同的纹理单元... // 这里省略了一些细节... GLint oldProgram; glGetIntegerv(GL_CURRENT_PROGRAM,&oldProgram); glUseProgram(shader_program_handle); glUniform1i(glGetUniformLocation(shader_program_handle,"tex_y"),0); glUniform1i(glGetUniformLocation(shader_program_handle,"tex_u"),1); glUniform1i(glGetUniformLocation(shader_program_handle,"tex_v"),2); draw_quad(); // 绘制四边形覆盖整个视口区域 glUseProgram(oldProgram); glBindFramebuffer(GL_FRAMEBUFFER,0); return true; } ``` 这段伪代码展示了如何在一个自定义的FBO (Frame Buffer Object) 中完成对单个视频帧的渲染工作。注意这里假设存在一个预先编写好的片断着色器(`shader_program_handle`) 来执行从YUV空间向RGB色彩模型之间的变换计算。 最后需要注意的是,由于RK3588内部集成了先进的GPU硬件加速特性,因此建议尽可能多地利用这些优势来进行高效的图形运算和视频编解码任务[^2].
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值