1.参考图像列表(reference picture list)

一般来说,h.264会把需要编码的图像分为三种类型:I、P、B,其中的B、P类型的图像由于采用了帧间编码的这种编码方式,而帧间编码又是以参考图像为基础进行的,因此需要有个参考图像列表来管理之前生成的参考图像,方便用于对当前图像进行编码。

2.解码图像缓存(decoded picture buffer)

随着图像编码的进行,(解码阶段)会不断有新的图像生成(重建图像),已解码图像会被放到解码图像缓存区中(或直接输出,这个在下面DPB讲)。但是由于内存大小与效率的限制,不可能一直保存参考图像而不丢弃,所以会有个对解码图像缓存这块内存区的管理策略。

参考图像列表

1. 来源

参考图像列表中的参考图像来自于解码图像缓存(DPB)中的已解码参考图像,DPB中可能包含参考以及非参考图像,参考图像列表把DPB中的参考图像整合成列表(数组)的形式,便于后续的排序等操作

2. 结构

组成

如标准8.4.1.2.3的注1所说:

  • 如果当前宏块是场宏块(mb_field),则refIdxL0和refIdxL1指的是一系列的场;
  • 如果当前宏块是帧宏块(!mb_field),则refIdxL0和refIdxL1指的是一系列的帧或者互补场对

但是参考图像列表的排列方式是不可能根据每个宏块的帧场时时刻刻做出改变,参考图像列表当前图像编码前就通过图像的帧场属性确定下来了:

  • 如果当前图像为帧(structure == Frame),参考图像列表中存放的是一系列的帧或者互补场对
  • 如果当前图像为场(structure == Field),参考图像列表中存放的是一系列的场

这就造成了当采用的是mbaff,且当前宏块为mb_field的时候参考图像列表的帧场不匹配,标准中的解决方法是:先得到参考帧RefPicListX[ refIdxLX / 2 ],然后选择该参考帧中对应的场进行编码(8.4.2.1),而JM则采用了一种巧妙的方法:如果当前图像是mbaff,则专门构造另外存放场参考图像列表RefPicListX(X = 2,3,4,5)方便进行提取参考场(JM中的list_offset就是用于决定X的值)。

长度

参考图像列表的最大长度取决于当前宏块是以何种方式进行编码

  • 如果当前宏块为帧宏块(纯帧图像 或 mbaff && !mb_field),默认情况下参考图像列表的长度为16,也可以通过num_ref_idx_l0_active_minus1指定最大长度为(num_ref_idx_l0_active_minus1 + 1)
  • 如果当前宏块为场宏块(场图像 或 mbaff && mb_field),默认情况下参考图像列表长度为32,也可以通过num_ref_idx_l0_active_minus1指定长度为(2 * num_ref_idx_l0_active_minus1 + 2)

——标准7.4.5.2

参考图像列表中的条目数目可能存在大于,或小于等于最大长度的情况:

  • 如果条目数大于最大长度,将删除最大长度之外位置的条目
  • 如果条目数小于最大长度,将把空余的条目设置为“非参考图像”

——标准8.2.4.2

3. 排序

参考图像分为短期参考图像(short-term reference)与长期参考图像(long-term reference),在某一个时间点上,参考图像只能是这两种的其中一种(非短即长)。参考图像列表分为两个部分:短期参考部分,长期参考部分。短期参考部分排在列表前头,长期排在后面。

P帧排序

一般来说,距离当前图像最近的参考图像会被当前图像用作最多的参考,距离越远则参考得越少,短期参考图像列表就是依据这种规律来进行排序的。

短期参考图像的序号由FrameNumWrap进行标记,以GOP为一个周期,GOP的第一帧的FrameNumWrap为0,后面持续递增,到当前帧是FrameNumWrap为最大,因此FrameNumWrap越大代表距离当前图像越近,因此将参考帧以FrameNumWrap降序方式放在refPicList0的起始位置

——标准8.2.4.1

也可以参考h.264的POC计算

长期参考图像的序号由LongTermPicNum进行标记,以升序的方式进行排序,(LongTermPicNum由MMCO分配)

B帧排序

B帧的参考帧排列方式与P帧并不完全相同,B帧的短期参考帧是以POC进行排序,其中有前向参考列表refPicList0与后向参考列表refPicList1

  • 当参考帧的POC小于当前图像的POC时,将参考帧以POC降序方式放在refPicList0的起始位置上。然后剩余的短期参考图像按照POC升序的方式附加到refPicList0
  • 当参考帧的POC大于当前图像的POC时,将参考帧以POC升序方式放在refPicList1的起始位置上。然后剩余的短期参考图像按照POC降序的方式附加到refPicList1

——标准8.2.4.2.3

长期参考图像的序号由LongTermPicNum进行标记,以升序的方式进行排序,分别放进refPicList0与refPicList1中(LongTermPicNum由MMCO分配)

注:一个未配对的场不能用于帧间预测,即表明如果当前为帧,那么其参考帧不可能为一个单一的场

场的处理

无论是P还是B,如果当前图像是场编码时,需要对上述的步骤做进一步处理,即把列表内的帧分为两个场,从与当前场具有相同奇偶性的场(如果存在)开始,对参考场进行排序

  • 如果当前场为Top_field,则列表中为|top|bottom|top|bottom..
  • 如果当前场为Bottom_field,则列表中为|bottom|top|bottom|top..
  • 如果其中某一帧缺少了某个场作为参考场,那么将忽略该缺少的场

——标准8.2.4.2.5

4. 参考图像列表重排序

在某些特殊情况下会需要把已经得到的参考图像列表重新排序,可以参考JM18.6的HierarchicalCoding,下面主要演示重排序过程:

  • 当中的紫灰色格子为重排序操作,对于短期参考图像,重拍序有符号与操作数,对于长期参考图像,直接通过操作数指定图像;
  • 后面还没进行到的列表项会被后移;
  • 划掉的格子为重复的图像,会被消除,如果被消除项后面还有其他项,后面的项会被前移填补前面被消除项的空格;
  • 重排序的初始操作是以当前图像的FrameNumWrap为基础。

——标准8.2.4.3

解码图像缓存

1.参考图像标记过程

在当前图像解码过后、插入DPB之前,会进行标记过程Decoded reference picture marking process,对先前已经解码并存在于DPB中的图像进行标记。该过程会对DPB中已经存在的图像(当然不包括当前图像)重新标记。标记过程有两种情况:

1.当前图像为IDR

如果指定了no_output_of_prior_pics_flag,表示DPB中所有的图像不进行输出,但是需要从DPB中移除

否则,从DPB中移除所有图像并输出到磁盘

2.当前图像不为IDR,且指定了adaptive_ref_pic_buffering_flag

表明需要对当前DPB进行重新标记,其中有6种标记方法,即内存管理控制操作(memory management control operation)

mmco 参数1 参数2 操作描述
0 - - 结束mmco
1 difference_of_pic_nums_minus1 - 求得短期参考图像picNumX后,把picNumX标记为非参考图像
2 - long_term_pic_num 求得长期参考图像LongTermPicNum后,把该长期参考图像标记为非参考图像
3 difference_of_pic_nums_minus1 long_term_pic_num 把短期参考图像picNumX,标记为长期参考图像,并赋值当前图像的LongTermPicNum = long_term_pic_num
4 MaxLongTermFrameIdx - 把LongTermPicNum > MaxLongTermFrameIdx 的长期参考图像都从DPB移除
5 - - 把DPB中所有的参考图像移除
6 - long_term_pic_num 把当前参考图像标记为长期参考图像,并赋值当前图像的LongTermPicNum = long_term_pic_num

其中

  • 短期参考图像序号为picNumX = CurrPicNum − ( difference_of_pic_nums_minus1 + 1 )
  • 长期参考图像序号为LongTermPicNum = long_term_pic_num(也就是说长期参考图像可以从上表3,6项指定)

注:把图像作为参考或者非参考,对于参考场对来说,两个场必须共同作为参考图像或者非参考图像,也就是说当你想为一个场标记的时候,其实标准需要你对整个帧(两场)都进行标记

——标准8.2.5

2.DPB

DPB标记完成后,需要把当前图像插入DPB(如果需要)。

DPB结构

解码图像缓存(DPB)是真正管理与存储图像数据的地方,凡是已经解码的图像,如果需要存储在内存中,都需要通过DPB进行管理,基本操作包括对解码图像的插入与删除。在JM中有个dpb结构体表示解码图像缓存。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

//! Decoded Picture Buffer

typedef struct decoded_picture_buffer

{

  FrameStore  **fs;     //参考图像列表,该指针主要用于管理一帧图像,其中包括一个帧与两个场,其成员frame管理帧,top_field与bottom_field会用于管理场

  FrameStore  **fs_ref;  //短期参考图像列表(当然,在这里是未经排序的)

  FrameStore  **fs_ltref; //长期参考图像列表

  unsigned      size;  //dpb最大容量,能容得下多少帧,最大不超过16

  unsigned      used_size; //dpb实际存了多少帧,以帧为单位,如果只有其中一场,也被看做一帧

  unsigned      ref_frames_in_buffer;//chj fs中用做short-term reference的帧的个数,短期参考帧,遇到下个I(IDR)会清空缓存

  unsigned      ltref_frames_in_buffer; //长期参考帧个数

  int           last_output_poc;  //上一个从dpb输出的poc序号

  int           max_long_term_pic_idx; //最大长期参考帧个数

  int           init_done;//是否已经初始化dpb

  FrameStore   *last_picture;//如果当前帧为场编码,则用于存其中一场,等待下一场编码完成后合并

} DecodedPictureBuffer;

DPB最大长度

当然DPB的大小也是有限制的,标准附件A就对DPB大小做出了限定:MaxDpbSize  = Min( 1024 * MaxDPB / ( PicWidthInMbs * FrameHeightInMbs * 384 ), 16 )

——标准附件A.3.2

DPB管理策略

另外DPB对解码图像的存储有个策略:更倾向于存储对后面编码有用的图像(也就是参考图像)。

虽然说DPB中也可以存储非参考图像,在DPB没满的时候,会无差别地把参考图像与非参考图像一并插入DPB中;

但是一旦DPB满了之后:

如果新重建的图像为参考图像,该参考图像需要插入DPB

  • 如果DPB中没有非参考图像,会按照滑动窗口模式把DPB序号最小的参考图像移除; (1)
  • 如果DPB中存在非参考图像,会把DPB中已经输出到磁盘的非参考图像移除;  (2)

如果新重建的图像为非参考图像

  • 如果DPB中不存在比当前图像POC更小的非参考图像,当前非参考图像会被直接输出到磁盘,而不插入DPB; (3)
  • 如果DPB中存在比当前图像POC更小的非参考图像,会把DPB中POC最小的参考图像移除,插入当前非参考图像;(4)

可以对应下面代码中的四段:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

void store_picture_in_dpb(StorablePicture* p)

{

  ...

    // sliding window, if necessary  (1)

  if ((!img->currentPicture->idr_flag)&&(p->used_for_reference && (!img->adaptive_ref_pic_buffering_flag)))

  {

    sliding_window_memory_management(p);

  }

  // first try to remove unused frames (2)

  if (dpb.used_size==dpb.size)

  {

    remove_unused_frame_from_dpb();

  }

  

  // then output frames until one can be removed

  while (dpb.used_size==dpb.size)

  {

    // non-reference frames may be output directly(3)

    if (!p->used_for_reference)

    {

      get_smallest_poc(&poc, &pos);

      if ((-1==pos) || (p->poc < poc))

      {

        direct_output(p, p_dec);

        return;

      }

    }

    // flush a frame(4)

    output_one_frame_from_dpb();

  }<br>insert_picture_in_dpb(dpb.fs[dpb.used_size],p);

  ...

}

H.264参考帧列表、解码图像缓存相关推荐

  1. h.264参考图像列表、解码图像缓存

    1.参考图像列表(reference picture list) 一般来说,h.264会把需要编码的图像分为三种类型:I.P.B,其中的B.P类型的图像由于采用了帧间编码的这种编码方式,而帧间编码又是 ...

  2. H.264及编解码调试

    H.264及编解码调试 H.264是国际标准化组织(ISO)和国际电信联盟(ITU)在2002年12月共同提出的继MPEG-4之后的新一代数字视频压缩格式,其具有更高的编码效率,并注重对移动和IP网络 ...

  3. 音视频编解码技术(一):MPEG-4/H.264 AVC 编解码标准

    一.H264 概述 H.264,通常也被称之为H.264/AVC(或者H.264/MPEG-4 AVC或MPEG-4/H.264 AVC) 1. H.264视频编解码的意义 H.264的出现就是为了创 ...

  4. H.264视频编解码的FPGA源码分析(一)输入数据分析

    目录 概要 输入数据 宏块 概要 本文的源码基于复旦大学的开源芯片-开源H.265/H.264视频编码器项目,本文的工作主要是在梳理源码的同时学习H.264视频编解码的原理及其硬件实现. 输入数据 C ...

  5. H.264视频编解码的FPGA源码分析(二)帧内预测1

    目录 帧内预测算法原理 基于论文的普通介绍 硬件实现 亮度块与色度块的划分 4×4亮度预测模块 如何产生预测像素与残差像素? 垂直模式`INTRA4x4_V` 水平模式`INTRA4x4_H` 直流模 ...

  6. AIR 3实现iOS下对H.264视频硬件解码

    本帖最后由 nextria 于 2011-10-9 11:27 编辑 在此之前,AIR开发的应用程序在iOS下是不可能实现对H.264视频硬解码的, 也许是以一个多比特率的方式传送. 我知道,是吧? ...

  7. H.264的编解码流程

    H.264是在MPEG-4技术的基础之上建立起来的,其编解码流程主要包括5个部分:帧间和帧内预测(Estimation).变换(Transform)和反变换.量化(Quantization)和反量化. ...

  8. 数据压缩12 | 实验8 | H.264视频编解码

    目录 一.实验准备 1. H.264编码过程 2. 调试和编码(参考JM Reference Software Manual (JVT-AE010)) 3. 编码参数(参考JM Reference S ...

  9. H.264视频编解码的代码移植和优化

    基于DSP系统开发的视频编解码系统,国内几乎都是走的移植,优化的路线,并且移植的代码,都是开源的.毕竟花费大量的人力,物力去开发一套自己的代码,并不见得比一些成熟的开源代码效率更高,健壮性更好.更何况 ...

最新文章

  1. IDEA运行最简单的Java程序Hello World
  2. win7 64位安装redis 及Redis Desktop Manager使用
  3. linux查看新挂上的磁盘
  4. 【转】如何用Maven创建web项目(具体步骤)
  5. 2199元起!荣耀60 SE真机上手图公布:相机模组造型眼熟
  6. 基于Java封装Groovy工具类
  7. csgo手机上看demo_仪表上的车速和手机导航不一样,哪个更准?碰到测速了该看哪个?...
  8. python教程视频哪个好-python视频教程哪家好
  9. JD_Source Code for problem 1379
  10. Wince 设备环境和画笔应用
  11. csss中box-sizing的问题 元素在另一个元素中框框包含的问题
  12. Blackrock的思考与启示
  13. 用外挂只为“吃鸡”成功?为什么不试试正当手段!
  14. KRC歌词文件如何转化为lrc文件,并在Linux虚拟机下观看
  15. Matlab运行.m文件
  16. 经典的10句人生箴言
  17. Jlink v9仿真器PCB原理图自动升级固件
  18. 详解数据结构课程设计———运动会分数统计
  19. java 读写文件乱码_Java 解决读写本地文件中文乱码的问题
  20. FPGA 开发项目参考

热门文章

  1. gitlab安装和基础管理
  2. java 正则表达式 电话_Java-12正则表达式验证电话号码
  3. jq获取兄弟节点_jQuery 获取兄弟元素的几种方法
  4. 字符串内置对象方法与Math内置对象方法的简介
  5. WhatsApp加密功能也成了美国政府“眼中钉”
  6. 重拾职场激情的妙计锦囊
  7. 【毕业设计】基于程序化生成和音频检测的生态仿真与3D内容生成系统----程序化生成地形算法设计
  8. setscale方法的用法_【java】BigDecimal.setScale用法总结
  9. 【Processing】图像处理框架语言(Hello,Processing!
  10. Django安装mysqlclient报错的问题