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帧级的内存申请和释放调用

图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申请和释放原理

图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指针为输出图像的指针。

图3 初始化状态

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

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

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

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

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

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

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

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

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

ffmpeg的内部Video Buffer管理和传送机制的更多相关文章

  1. android摄像头(camera)之buffer管理

    一,V4L2驱动申请buffer 视频应用可以通过两种方式从V4L2驱动申请buffer 1. V4L2_MEMORY_USERPTR方式, 顾名思义是用户空间指针的意思,应用层负责分配需要的内存空间 ...

  2. vlc_input buffer管理 & 时钟同步(转)

    vlc_input buffer管理 & 时钟同步 一.背景1.当播放网络视频流时(比如udp视频流),发送方(编码)和接收方(解码)是并行操作的,如果发送太慢(或因为网络原因出现延迟)的话, ...

  3. 大型分布式C++框架《四:netio之buffer管理器 下》

    每周一篇又来了.这次主要介绍netio的buffer管理器. 首先buffer管理是每一个网络层不可回避的问题.怎么高效的使用buffer是很关键的问题.这里主要介绍下我们的netio是怎么处理.说实 ...

  4. with ffmpeg to encode video for live streaming and for recording to files for on-demand playback

    We've been doing some experimentation with ffmpeg to encode video for live streaming and for recordi ...

  5. Android基本功:Handler消息传送机制

    一.什么是UI线程 当程序第一次启动的时候,Android会同时启动一条主线程( Main Thread). 主要负责处理与UI相关的事件. 二.UI线程存在的问题 出于性能优化考虑,Android的 ...

  6. ActiveMQ讯息传送机制以及ACK机制

    http://blog.csdn.net/lulongzhou_llz/article/details/42270113 ActiveMQ消息传送机制以及ACK机制详解 AcitveMQ是作为一种消息 ...

  7. 总结Flink状态管理和容错机制

    本文来自8月11日在北京举行的 Flink Meetup会议,分享来自于施晓罡,目前在阿里大数据团队部从事Blink方面的研发,现在主要负责Blink状态管理和容错相关技术的研发.   本文主要内容如 ...

  8. JVM内存管理及GC机制

    一.概述 Java GC(Garbage Collection,垃圾收集,垃圾回收)机制,是Java与C++/C的主要区别之一,作为Java开发者,一般不需要专门编写内存回收和垃圾清理代码,对内存泄露 ...

  9. Handler消息传送机制

    一.什么是UI线程 当程序第一次启动的时候,Android会同时启动一条主线程( Main Thread). 主要负责处理与UI相关的事件. 二.UI线程存在的问题 出于性能优化考虑,Android的 ...

随机推荐

  1. memcached-repcached

    memcached的复制功能 下载对应的repcached版本:http://sourceforge.jp/projects/sfnet_repcached/,必须版本对应才行 当前只支持到1.2.8 ...

  2. 用windows远程连接linux桌面(使用tightvnc或者tigervnc)

    一.安装tightvnc: tightvnc的安装在安装包中有详细的说明(README文件) 首先你要确保linux已经安装jpeg和zlib库, 2.编译 执行如下两个命令: [root@local ...

  3. 转载一个不错的Scrapy学习博客笔记

    背景: 最近在学习网络爬虫Scrapy,官网是 http://scrapy.org 官方描述:Scrapy is a fast high-level screen scraping and web c ...

  4. trie树--详解

    文章作者:yx_th000 文章来源:Cherish_yimi (http://www.cnblogs.com/cherish_yimi/) 转载请注明,谢谢合作.关键词:trie trie树 数据结 ...

  5. [shell编程]初识sed和gawk

    一.sed编辑器       shell脚本最常见的用途就是处理文本文件,sed和gawk能够极大的简化需要进行的数据处理任务.sed编辑器是流编辑器,跟普通交互式文本编辑器(如vim)不同.流编辑器 ...

  6. Android 一个Activity保存它自己的实例

    一个Activity保存他自己的实例的作用是,在其他Activity中可以方便的调用该Activity里的方法. 我们可以使用一个静态的变量保存当前Activity的实例,并将其标志为private访 ...

  7. Hadoop-eclipse-plugin插件安装

    Hadoop-eclipse-plugin插件安装 学习Hadoop有一段时间了,以前每次的做法都是先在win下用eclipse写好Mapreduce程序,然后打成jar文件,上传到linux下用ha ...

  8. 最长不下降子序列//序列dp

    最长不下降子序列 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 求最长不下降子序列的长度 输入格式 第一行为n,表示n个数第二行n个数 输出格式 最长不下降 ...

  9. 李洪强iOS开发之最全App上架流程

    在上架App之前想要 真机测试的同学 请查看 iOS- 最全的真机测试教程 里面包含怎么让多台电脑同时 上架App和同时真机调试.P12文件的使用详解 准备 开发者账号 完工的项目 上架步骤 一.创建 ...

  10. 分布式内存对象缓存系统Memcached-概述

    全面掌握Memcached 1.       概述 Memcached是danga.com(运营LiveJournal的技术团队)开发的一套分布式内存对象缓存系统,是为了加快网站http://www. ...