ffmpeg的内部Video Buffer管理和传送机制

news/2024/7/20 15:11:32 标签: ffmpeg, 数据结构与算法, 内存管理

ffmpeg的内部Video Buffer管理和传送机制

本文主要介绍ffmpeg解码器内部管理Video Buffer的原理和过程,ffmpeg的Videobuffer为内部管理,其流程大致为:注册处理函数->帧级释放->帧级申请->清空。

1 注册get_buffer()和release_buffer()

FFAPI_InitCodec()

avcodec_alloc_context()

avcodec_alloc_context2()

avcodec_get_context_default2(AVCodecContext *s,…){

……

s->get_buffer = avcodec_default_get_buffer;

s->release_buffer = avcodec_default_release_buffer;

……

}

2帧级的内存申请和释放调用

 

0_1302927911vOO3

图1帧级内存申请和释放的函数调用

2.1 FFAPI函数调用libavcodec相应的codec(WMV3对应的Codec是VC1)函数进行解码,过程中调用内部buffer处理函数。其中buffer管理被统一封装到Mpegvideo接口中(包括的codec有H.261, H.263, H.264, mpeg12, rv10,rv34, svq1和VC1)

FFAPI_Decode()

avcodec_decode_video2()

avctx->codec->decode()//初始化过程中注册codec,wmv3的解码函数是

vc1_decode_frame(){

decode_vc1_header;

MPV_frame_start();                                     //2.2.2

vc1_decode_blocks();

MPV_frame_end();                                     //2.2.3

}

2.2 MPV_frame_start()//通过调用get_buffer()申请当前帧的video buffer。

MPV_frame_start()

//首先调用release_buffer()释放非参考帧的video buffer

for(i=0; i<MAX_PICTURE_COUNT; i++)

if(s->picture[i].data[0] && !s->picture[i].reference)

free_frame_buffer(s, &s->picture[i]); //调用s->avctx->get_buffer(),回调avcodec_default_release_buffer()

 

ff_alloc_picture()

alloc_frame_buffer()

s->avctx->get_buffer()      //回调avcodec_default_get_buffer()

2.3MPV_frame_end()                                          //完成视频加边等操作

 

3帧级的内存申请和释放处理方法

3.1内部buffer数据结构

–   typedef struct InternalBuffer{

–       int last_pic_num;

–       uint8_t *base[4];

–       uint8_t *data[4];

–       int linesize[4];

–       int width, height;

–       enum PixelFormat pix_fmt;

–   }InternalBuffer;

–   typedef struct AVCodecContext {

–          ……

–   int internal_buffer_count; //记录当前内部buffer的个数,get_buffer和release_buffer时均需要对其进行维护。

–   void *internal_buffer;//初始化为数组InternalBuffer [INTERNAL_BUFFER_SIZE]

–   ……

–   } AVCodecContext;

Codec通过维护internal_buffer_count和internal_buffer实现高效的内存管理

3.2参考帧管理相关数据结构

–   typedef  struct Picture{

–       uint8_t *data[4];

–       int linesize[4];

–       uint8_t *base[4];

–       int reference;

–       ……

–   } Picture;

–   typedef  struct MpegEncContext{

–       ……

–       Picture* picture;   //初始化为数组Picture[INTERNAL_BUFFER_SIZE]

–       Picture* last_picture_ptr;      //指向前一帧

–       Picture* next_picture_ptr;;    //双向预测时,指向后一帧

–       Picture* current_picture_ptr;//指向当前帧

–   ……

–   } MpegEncContext; 

3.3申请和释放原理

0_13029279181Joq

图2 内存申请和释放原理

(1)初始化时将internal_buffer全部清零

(2)释放buffer时,将释放的buffer与最后一个有效buffer交换,而不是用av_free()释放内存。

avcodec_default_release_buffer(AVCodecContext *s, AVFrame *pic){

s->internal_buffer_count–;

last = &((InternalBuffer*)s->internal_buffer)[s->internal_buffer_count];

//将last buffer和要释放的buffer交换,使last buffer变成无效buffer,在下次get_buffer时能被申请到。

FFSWAP(InternalBuffer, *buf, *last);

for(i=0; i<4; i++){

pic->data[i]=NULL;

}

}

(3)申请buffer时,检查internal_buffer[internal_buffer_count]的基址是否非空,若非空则直接使用internal_buffer[internal_buffer_count];若空,使用av_malloc()函数进行申请。

这样处理的好处是避免了频繁的调用malloc()和free(),从而提升了效率。

avcodec_default_get_buffer(AVCodecContext *s, AVFrame *pic){

……

buf= &((InternalBuffer*)s->internal_buffer)[s->internal_buffer_count];

get_size_info(size[]);

buf->base[0, 1, 2] = av_malloc(size[0, 1, 2]);

buf->data[0, 1, 2] = buf->base[0, 1, 2] + padding_offset[0, 1, 2];

……

}

(4)决定输出帧是在每帧解码后,根据当前帧的类型和参考信息决定输出帧。

if (s->pict_type == FF_B_TYPE || s->low_delay) {

*pict= *(AVFrame*)s->current_picture_ptr;

} else if (s->last_picture_ptr != NULL) {

*pict= *(AVFrame*)s->last_picture_ptr;

}

3.4举例——假设解码IPBPB的非H.264码流。

(1)初始化后的状态如所示,IBC为ctx->internal_buffer_count,CurPtr为s->current_picture_ptr,LastPtr为s->last_picture_ptr,NextPtr为s->next_picture_ptr。

gpAVPicture指针为输出图像的指针。

 0_1302927929p9BZ

图3 初始化状态

(2)解码第一个I帧,过程中不会不调用release_buffer(),get_buffer()得到picture[0] ,此时不输出任何图像。

 0_1302927934rV3c

图4解码第一个I帧后的状态

(3)解码第一个P帧,过程中不调用release_buffer(),get_buffer()得到picture[1] ,输出picture[0]。

 0_13029279382i4T

图5解码第一个P帧后的状态

(4)解码第一个B帧,过程中不调用release_buffer(),get_buffer()得到picture[2] ,输出picture[2]。

 0_1302927943C7D9

图6解码第一个B帧后的状态

(5)解码第二个P帧,调用release_buffer(&picture[2]),再调用get_buffer(),得到picture[2], 输出picture[1]。

 0_1302928016IUon

图7解码第二个P帧的状态

ref: http://blog.csdn.net/xietao_live_cn/article/details/6327451


http://www.niftyadmin.cn/n/1751706.html

相关文章

php 使用memcached,PHP 使用memcached简单示例分享

1.添加扩展包php_memcache.dll2.在PHP.INI添加extensionphp_memcache.dll3.程序//创建一个mem对象实例$memnew Memcache;if(!$mem->connect("10.18.110.213",11211)){die(连接失败!);}//增加//1.增加一个字串/* if($mem->set(key1,"beijing",MEMCACH…

performSelector延时调用导致的内存泄露

前几天在给游戏做收尾测试时&#xff0c;发现了一个关于内存泄露的问题&#xff0c;一直没找着问题所在&#xff0c;经过反复调试和查找资料今天终于解决了&#xff0c;特此记录下来以免以后再犯&#xff01; 关于objective-c的内存管理&#xff0c;我们都知道一个原则就是“谁…

Java高级部分笔记-------类加载器

2019独角兽企业重金招聘Python工程师标准>>> 1.类加载器的概念及其作用 顾名思义&#xff0c;类加载器&#xff08;class loader&#xff09;用来加载 Java 类到 Java 虚拟机中。一般来说&#xff0c;Java 虚拟机使用 Java 类的方式如下&#xff1a;Java 源程序&…

[转]异步编程与响应式框架

作者&#xff1a;老赵 来源&#xff1a;http://blog.zhaojie.me/2010/09/async-programming-and-reactive-framework.html 前言 异步操作是强大的&#xff0c;它是许多高伸缩性架构的基石。异步操作在许多情况下是必须的&#xff0c;例如在客户端保持用户界面的响应能力&#…

php协程 关键字,php +go关键字实现协程 | 码农网

今天在知乎浏览时忽然发现了一个有趣的东西&#xff0c;php竟然可以实现协程的实现&#xff0c;而且还是通过 go 关键字实现&#xff0c;顿时感觉 php 现在发展的好迅速&#xff0c;竟然把go里的东西都借鉴去。只不过这是在一个叫Swoole的框架中实现的。Swoole4为 PHP 语言提供…

Eclipse:Could not create the view: Plug-in org.eclipse.jdt.ui was unable to load class org.eclipse.

使用Eclipse时&#xff0c;遇到了如下的异常&#xff0c;工作空间&#xff08;workspace&#xff09;打不开&#xff1a;Could not create the view: Plug-in org .eclipse. jdt.ui was unable to load class org .eclipse. jdt.internal.ui.packageview.PackageExplorerPart.*…

centos配置ruby开发环境

2019独角兽企业重金招聘Python工程师标准>>> centos配置ruby开发环境1. 安装ruby 1.1 yum安装&#xff0c;版本旧 #yum install ruby ruby-devel ruby-ri ruby-rdoc ruby-irb ruby-shadow 1.2 删除 #yum remove ruby ruby-devel -y 1.3 源码安装 #wget http://cache…

c odbc连接mysql,请问在C语言中,怎么利用ODBC连接数据库

当前位置:我的异常网 C语言 请问在C语言中&#xff0c;怎么利用ODBC连接数据库请问在C语言中&#xff0c;怎么利用ODBC连接数据库www.myexceptions.net 网友分享于&#xff1a;2013-03-08 浏览&#xff1a;13次请教在C语言中&#xff0c;如何利用ODBC连接数据库&#xff1f;…