美文网首页音视频开发
从 AVFrame 到渲染成纹理我趟过的坑

从 AVFrame 到渲染成纹理我趟过的坑

作者: zhonglaoban | 来源:发表于2023-07-06 19:42 被阅读0次

FFmpeg 解码出来 AVFrame 后,要渲染出来正确的图像,还是有不少问题的,下面来看看几种常见的渲染方式吧(以yuv格式为例)。

使用 AVFrame 的 width,height 直接渲染

在 width 和 lineSize 不一样的情况下,渲染出来的图像会有乱码。

int width - frame->width;
int width = frame->height;
glTexImage2D(texture_y, 0, GL_LUMINANCE, width, height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, frame->data[0]);
glTexImage2D(texture_u, 0, GL_LUMINANCE, width/2, height/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, frame->data[1]);
glTexImage2D(texture_v, 0, GL_LUMINANCE, width/2, height/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, frame->data[2]);

使用 AVFrame 的 lineSize,height 直接渲染

在 width 和 lineSize 不一样的情况下,渲染出来的图像会有绿边。

int width - frame->width;
int width = frame->height;
glTexImage2D(texture_y, 0, GL_LUMINANCE, frame->linesize[0], height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, frame->data[0]);
glTexImage2D(texture_u, 0, GL_LUMINANCE, frame->linesize[1], height/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, frame->data[1]);
glTexImage2D(texture_v, 0, GL_LUMINANCE, frame->linesize[2], height/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, frame->data[2]);

裁剪有效数据后渲染

直接裁剪内存,性能开销比较大。

int w - frame->width;
int h = frame->height;
if(y == nullptr){
  y = new unsigned char[w*h];
}
if(u == nullptr){
  u = new unsigned char[w*h/4];
}
if(v == nullptr){
  v = new unsigned char[w*h/4];
}}
int l1 = frame->linesize[0];
int l2 = frame->linesize[1];
int l3 = frame->linesize[2];
for(int i= 0; i < h ; i++)
{
  memcpy(y + w*i,frame->data[0] + l1* i, sizeof( unsigned char)*w);
}
for(int i= 0 ; i < h/2 ; i++)
{
  memcpy(u + w/2*i,frame->data[1] + l2 * i, sizeof(unsigned char)*w/2);
  memcpy(v + w/2*i,frame->data[2] + l3 * i, sizeof(unsigned char)*w/2);
}
glTexImage2D(texture_y, 0, GL_LUMINANCE, w, h, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, y);
glTexImage2D(texture_u, 0, GL_LUMINANCE, w/2, h/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, u);
glTexImage2D(texture_v, 0, GL_LUMINANCE, w/2, h/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, v);

渲染后再进行裁剪

按 lineSize 去渲染,渲染的时候需要改变纹理坐标。

int width - frame->width;
int width = frame->height;
glTexImage2D(texture_y, 0, GL_LUMINANCE, frame->linesize[0], height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, frame->data[0]);
glTexImage2D(texture_u, 0, GL_LUMINANCE, frame->linesize[1], height/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, frame->data[1]);
glTexImage2D(texture_v, 0, GL_LUMINANCE, frame->linesize[2], height/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, frame->data[2]);
float textureCoords[] = {
        0.0f, 0.0f, // bottom left
        0.0f, 1.0f, // top left
        1.0f, 1.0f, // top right
        1.0f, 0.0f, // bottom right
};
textureCoords[5] = 1.0f * width/frame->linesize[0];
textureCoords[7] = 1.0f * width/frame->linesize[0];
glBindBuffer(GL_ARRAY_BUFFER, textureVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(textureCoords), textureCoords, GL_STATIC_DRAW);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

通过对比上面的四种渲染方式,我们发现第四种不仅最高效,而且没有异常问题,因此值得推荐。

相关文章

  • WKWebView从入门到趟坑

    UIWebView 之痛 开发App的过程中,常常会遇到在App内部加载网页,通常用UIWebView加载。而这个...

  • 转- WKWebView从入门到趟坑

    转载自: http://www.jianshu.com/p/90a90bd13aac WKWebView从入门到趟...

  • WKVebView

    使用WKWebView替换UIWebView WKWebView加载进度条 WKWebView从入门到趟坑 WKW...

  • 使用Dubbo趟过的坑

    最近在做一个项目,这个项目里有两个系统。这是背景! 这两个系统不能互相访问!这是坑爹的需求! 然后我不想使用数据库...

  • WKWebView代替UIWebVIew

    WKWebView从入门到趟坑http://www.jianshu.com/p/90a90bd13aacUIWeb...

  • 还怕装修被坑?毛坯房从0到1真实经历

    从0到1装修,从毛坯房装修成一个温馨小窝,趟过坑,也经历了很多有趣有挑战的事,一个小白的装修心得,分享给大家。 ...

  • Vue 之mounted和created的区别

    从官网上的vue的生命周期图可以看出 created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲...

  • WKWebView 不支持 NSURLProtocol 吗

    WKWebView不支持NSURLProtocol 前段时间总结过《WKWebView从入门到趟坑》,其中提到 N...

  • GridManager 实现搜索

    搜索功能在GridManager中的实现方式很简单。首先需要确认当前的GridManager已经渲染成功, 如何渲...

  • 我和孩子趟过的坑

    孩子过了三岁,完成了早教,接踵而来的就是各种兴趣班。都说艺术教育影响孩子的一生,美育,美术、音乐、舞蹈、口才、各种...

网友评论

    本文标题:从 AVFrame 到渲染成纹理我趟过的坑

    本文链接:https://www.haomeiwen.com/subject/hzfrudtx.html