在H.264之前的标准中,比如H.263,其比特流中的数据是按照一个宏块接一个宏块的方式排列的,一旦发生丢包,很多相邻宏块信息都会丢失,很难进行错误隐藏处理。在H.264中加入了一项新特性:把宏块在比特流中的数据按照一定的映射规则进行排列,而不一定按照原本的光栅扫描顺序排列,这种方称为灵活的宏块重拍FMO(Flexible Macroblock Ordering)。

FMO是基于组的方式将宏块集合起来,把一帧内的宏块划分到不同的条带组(slice group)。当然在最后也需要对条带组按光栅扫描顺序划分条带(slice)。在h.264中,当slice group被设为大于1时才使用FMO。在代码端看来,FMO时,主要是对映射表(数组)的设置,如下第一个表:

对一帧进行FMO:

0 1 2 0 1 2 0 1 2 0 1
1 2 0 1 2 0 1 2 0 1 2
0 1 2 0 1 2 0 1 2 0 1
1 2 0 1 2 0 1 2 0 1 2
0 1 2 0 1 2 0 1 2 0 1
1 2 0 1 2 0 1 2 0 1 2
0 1 2 0 1 2 0 1 2 0 1
1 2 0 1 2 0 1 2 0 1 2
0 1 2 0 1 2 0 1 2 0 1

得到slice group有三个:

0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0        
1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1
2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2
2 2 2 2          

然后再对每个slice group按照光栅扫描顺序进行排序,分割出slice,下面为分割slice group 0(假设slice长度为16)

slice 1 in slice group 0:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

slice 2 in slice group 0:

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

FMO在h.264中有7种(FMO0 ~ FMO6)

FMO0

FMO0,交织映射。交织映射是指不同的slice group交替出现。

如下设置了slice group 0 = 10,slice group 1 = 15,slice group 2 = 18

0 0 0 0 0 0 0 0 0 0 1
1 1 1 1 1 1 1 1 1 1 1
1 1 1 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2 2 0
0 0 0 0 0 0 0 0 0 1 1
1 1 1 1 1 1 1 1 1 1 1
1 1 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2 0 0
0 0 0 0 0 0 0 0 1 1 1

JM code如下:

/*!
************************************************************************
* \brief
* Generate interleaved slice group map type MapUnit map (type 0)
*
* \param img
* Image Parameter to be used for map generation
* \param pps
* Picture Parameter set to be used for map generation
************************************************************************
*/
static void FmoGenerateType0MapUnitMap (ImageParameters * img, pic_parameter_set_rbsp_t * pps )
{
unsigned iGroup, j;
unsigned i = 0;
do
{
for( iGroup = 0;
(iGroup <= pps->num_slice_groups_minus1) && (i < PicSizeInMapUnits);
i += pps->run_length_minus1[iGroup++] + 1)
{
for( j = 0; j <= pps->run_length_minus1[ iGroup ] && i + j < PicSizeInMapUnits; j++ )
MapUnitToSliceGroupMap[i+j] = iGroup;
}
}
while( i < PicSizeInMapUnits );
}

FMO1

FMO1,分散映射。每个宏块相邻的宏块都不在同一组。x方向上的宏块按照slice group序号递增分配,y方向第一个宏块按照0,slice group numbers/2交替分配。

0 1 2 0 1 2 0 1 2 0 1
1 2 0 1 2 0 1 2 0 1 2
0 1 2 0 1 2 0 1 2 0 1
1 2 0 1 2 0 1 2 0 1 2
0 1 2 0 1 2 0 1 2 0 1
1 2 0 1 2 0 1 2 0 1 2
0 1 2 0 1 2 0 1 2 0 1
1 2 0 1 2 0 1 2 0 1 2
0 1 2 0 1 2 0 1 2 0 1

JM code 如下:

/*!
************************************************************************
* \brief
* Generate dispersed slice group map type MapUnit map (type 1)
*
* \param img
* Image Parameter to be used for map generation
* \param pps
* Picture Parameter set to be used for map generation
************************************************************************
*/
static void FmoGenerateType1MapUnitMap (ImageParameters * img, pic_parameter_set_rbsp_t * pps )
{
unsigned i;
for( i = 0; i < PicSizeInMapUnits; i++ )
{
MapUnitToSliceGroupMap[i] = ((i%img->PicWidthInMbs)+(((i/img->PicWidthInMbs)*(pps->num_slice_groups_minus1+1))/2))
%(pps->num_slice_groups_minus1+1);
}
}

FMO2

FMO2,前后景映射。以整个帧作为背景,该模式可以通过(左上角坐标,右下角坐标)的方式指定前景,每个前景都为一个slice group,最先指定的前景可以覆盖后来指定的前景。

假设有

slice group 0(3,4)(8,8)

slice group 1(1,2)(6,6)

2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2 2 2
2 1 1 1 1 1 1 2 2 2 2
2 1 1 1 1 1 1 2 2 2 2
2 1 1 0 0 0 0 0 0 2 2
2 1 1 0 0 0 0 0 0 2 2
2 1 1 0 0 0 0 0 0 2 2
2 2 2 0 0 0 0 0 0 2 2
2 2 2 0 0 0 0 0 0 2 2

JM code如下:

/*!
************************************************************************
* \brief
* Generate foreground with left-over slice group map type MapUnit map (type 2)
*
* \param img
* Image Parameter to be used for map generation
* \param pps
* Picture Parameter set to be used for map generation
************************************************************************
*/
static void FmoGenerateType2MapUnitMap (ImageParameters * img, pic_parameter_set_rbsp_t * pps )
{
int iGroup;
unsigned i, x, y;
unsigned yTopLeft, xTopLeft, yBottomRight, xBottomRight; for( i = 0; i < PicSizeInMapUnits; i++ )
MapUnitToSliceGroupMap[ i ] = pps->num_slice_groups_minus1; for( iGroup = pps->num_slice_groups_minus1 - 1 ; iGroup >= 0; iGroup-- )
{
yTopLeft = pps->top_left[ iGroup ] / img->PicWidthInMbs;
xTopLeft = pps->top_left[ iGroup ] % img->PicWidthInMbs;
yBottomRight = pps->bottom_right[ iGroup ] / img->PicWidthInMbs;
xBottomRight = pps->bottom_right[ iGroup ] % img->PicWidthInMbs;
for( y = yTopLeft; y <= yBottomRight; y++ )
for( x = xTopLeft; x <= xBottomRight; x++ )
MapUnitToSliceGroupMap[ y * img->PicWidthInMbs + x ] = iGroup;
}
}

FMO3

FMO3,环形扫描映射。在JM中,环形扫描映射把一帧分为两个slice group,一个是以一帧为背景,另一个是以环作为的前景(其实环可以扩展到更多的group)。环的起点是帧的中心位置,通过指定环的运动方向(顺时针或逆时针)以及环的长度即可得到前景。

以下为顺时针,环长度为32

1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1
1 1 1 20 21 22 23 24 25 1 1
1 1 1 19 6 7 8 9 26 1 1
1 1 1 18 5 0 1 10 27 1 1
1 1 1 17 4 3 2 11 28 1 1
1 1 1 16 15 14 13 12 29 1 1
1 1 1 1 1 1 1 31 30 1 1
1 1 1 1 1 1 1 1 1 1 1

JM code 如下:

/*!
************************************************************************
* \brief
* Generate box-out slice group map type MapUnit map (type 3)
*
* \param img
* Image Parameter to be used for map generation
* \param pps
* Picture Parameter set to be used for map generation
************************************************************************
*/
static void FmoGenerateType3MapUnitMap (ImageParameters * img, pic_parameter_set_rbsp_t * pps )
{
unsigned i, k;
int leftBound, topBound, rightBound, bottomBound;
int x, y, xDir, yDir;
int mapUnitVacant; unsigned mapUnitsInSliceGroup0 = min((pps->slice_group_change_rate_minus1 + 1) * img->slice_group_change_cycle, PicSizeInMapUnits); for( i = 0; i < PicSizeInMapUnits; i++ )
MapUnitToSliceGroupMap[ i ] = 2; x = ( img->PicWidthInMbs - pps->slice_group_change_direction_flag ) / 2;
y = ( img->PicHeightInMapUnits - pps->slice_group_change_direction_flag ) / 2; leftBound = x;
topBound = y;
rightBound = x;
bottomBound = y; xDir = pps->slice_group_change_direction_flag - 1;
yDir = pps->slice_group_change_direction_flag; for( k = 0; k < PicSizeInMapUnits; k += mapUnitVacant )
{
mapUnitVacant = ( MapUnitToSliceGroupMap[ y * img->PicWidthInMbs + x ] == 2 );
if( mapUnitVacant )
MapUnitToSliceGroupMap[ y * img->PicWidthInMbs + x ] = ( k >= mapUnitsInSliceGroup0 ); if( xDir == -1 && x == leftBound )
{
leftBound = max( leftBound - 1, 0 );
x = leftBound;
xDir = 0;
yDir = 2 * pps->slice_group_change_direction_flag - 1;
}
else
if( xDir == 1 && x == rightBound )
{
rightBound = min( rightBound + 1, (int)img->PicWidthInMbs - 1 );
x = rightBound;
xDir = 0;
yDir = 1 - 2 * pps->slice_group_change_direction_flag;
}
else
if( yDir == -1 && y == topBound )
{
topBound = max( topBound - 1, 0 );
y = topBound;
xDir = 1 - 2 * pps->slice_group_change_direction_flag;
yDir = 0;
}
else
if( yDir == 1 && y == bottomBound )
{
bottomBound = min( bottomBound + 1, (int)img->PicHeightInMapUnits - 1 );
y = bottomBound;
xDir = 2 * pps->slice_group_change_direction_flag - 1;
yDir = 0;
}
else
{
x = x + xDir;
y = y + yDir;
}
} }

FMO4

FMO4,光栅扫描映射。该模式只支持两个slice group,按照光栅扫描顺序来分组,方向有正向与反向之分。

如下为反向FMO4(始于右下角):

1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0

JM code 如下:

/*!
************************************************************************
* \brief
* Generate raster scan slice group map type MapUnit map (type 4)
*
* \param img
* Image Parameter to be used for map generation
* \param pps
* Picture Parameter set to be used for map generation
************************************************************************
*/
static void FmoGenerateType4MapUnitMap (ImageParameters * img, pic_parameter_set_rbsp_t * pps )
{ unsigned mapUnitsInSliceGroup0 = min((pps->slice_group_change_rate_minus1 + 1) * img->slice_group_change_cycle, PicSizeInMapUnits);
unsigned sizeOfUpperLeftGroup = pps->slice_group_change_direction_flag ? ( PicSizeInMapUnits - mapUnitsInSliceGroup0 ) : mapUnitsInSliceGroup0; unsigned i; for( i = 0; i < PicSizeInMapUnits; i++ )
if( i < sizeOfUpperLeftGroup )
MapUnitToSliceGroupMap[ i ] = pps->slice_group_change_direction_flag;
else
MapUnitToSliceGroupMap[ i ] = 1 - pps->slice_group_change_direction_flag; }

FMO5

FMO5,擦式扫描映射。仅支持两个slice group,扫描方式为纵向,也有正反两个方向

如下为正向FMO5(始于左上角):

0 0 0 1 1 1 1 1 1 1 1
0 0 0 1 1 1 1 1 1 1 1
0 0 1 1 1 1 1 1 1 1 1
0 0 1 1 1 1 1 1 1 1 1
0 0 1 1 1 1 1 1 1 1 1
0 0 1 1 1 1 1 1 1 1 1
0 0 1 1 1 1 1 1 1 1 1
0 0 1 1 1 1 1 1 1 1 1
0 0 1 1 1 1 1 1 1 1 1

JM code 如下:

/*!
************************************************************************
* \brief
* Generate wipe slice group map type MapUnit map (type 5)
*
* \param img
* Image Parameter to be used for map generation
* \param pps
* Picture Parameter set to be used for map generation
************************************************************************
*/
static void FmoGenerateType5MapUnitMap (ImageParameters * img, pic_parameter_set_rbsp_t * pps )
{ unsigned mapUnitsInSliceGroup0 = min((pps->slice_group_change_rate_minus1 + 1) * img->slice_group_change_cycle, PicSizeInMapUnits);
unsigned sizeOfUpperLeftGroup = pps->slice_group_change_direction_flag ? ( PicSizeInMapUnits - mapUnitsInSliceGroup0 ) : mapUnitsInSliceGroup0; unsigned i,j, k = 0; for( j = 0; j < img->PicWidthInMbs; j++ )
for( i = 0; i < img->PicHeightInMapUnits; i++ )
if( k++ < sizeOfUpperLeftGroup )
MapUnitToSliceGroupMap[ i * img->PicWidthInMbs + j ] = 1 - pps->slice_group_change_direction_flag;
else
MapUnitToSliceGroupMap[ i * img->PicWidthInMbs + j ] = pps->slice_group_change_direction_flag; }

FMO6

FMO6,显示控制映射。可以在配置文件中自由地指定每个宏块所属的slice group。

0 1 0 2 1 1 0 2 1 1 1
1 2 0 0 0 1 0 2 0 1 0
3 5 4 1 0 0 3 5 4 0 1
0 0 5 5 3 1 0 2 5 0 1
4 1 0 0 1 1 1 1 4 4 2
0 2 2 3 2 3 2 1 5 2 3
0 1 2 0 1 1 2 0 5 5 5
3 2 1 4 1 4 4 0 3 3 2
4 2 3 5 0 0 1 4 1 2 3

顺带一提JM支持一帧中最多为8个slice group

JM code 如下:

/*!
************************************************************************
* \brief
* Generate explicit slice group map type MapUnit map (type 6)
*
* \param img
* Image Parameter to be used for map generation
* \param pps
* Picture Parameter set to be used for map generation
************************************************************************
*/
static void FmoGenerateType6MapUnitMap (ImageParameters * img, pic_parameter_set_rbsp_t * pps )
{
unsigned i;
for (i=0; i<PicSizeInMapUnits; i++)
{
MapUnitToSliceGroupMap[i] = pps->slice_group_id[i];
}
}

h.264 FMO的更多相关文章

  1. h.264语法结构分析

    NAL Unit Stream Network Abstraction Layer,简称NAL. h.264把原始的yuv文件编码成码流文件,生成的码流文件就是NAL单元流(NAL unit Stre ...

  2. H.264视频的RTP荷载格式

    Status of This Memo This document specifies an Internet standards track protocol for the   Internet ...

  3. FFmpeg的H.264解码器源代码简单分析:熵解码(Entropy Decoding)部分

    ===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...

  4. FFmpeg的H.264解码器源代码简单分析:解析器(Parser)部分

    ===================================================== H.264源代码分析文章列表: [编码 - x264] x264源代码简单分析:概述 x26 ...

  5. 6. H.264/AVC编码器原理

    1. H.264/AVC的应用 H.264 不仅具有优异的压缩性能,而且具有良好的网络亲和性,这对实时的视频通信是十分重要的.和 MPEG-4 中的重点是灵活性不同,H.264 着重在压缩的高效率和传 ...

  6. H.264 Profile

    提到High Profile H.264解码许多人并不了解,那么到底什么是High Profile H.264解码?其应用效果又是如何呢?  作为行业标准,H.264编码体系定义了4种不同的Profi ...

  7. (转载)H.264码流的RTP封包说明

    H.264的NALU,RTP封包说明(转自牛人) 2010-06-30 16:28 H.264 RTP payload 格式 H.264 视频 RTP 负载格式 1. 网络抽象层单元类型 (NALU) ...

  8. H.264的优势和主要特点

    H.264,同时也是MPEG-4第十部分,是由ITU-T视频编码专家组(VCEG)和ISO/IEC动态图像专家组(MPEG)联合组成的联合视频组(JVT,Joint Video Team)提出的高度压 ...

  9. Android IOS WebRTC 音视频开发总结(七九)-- WebRTC选择H.264的四大理由

    本文主要介绍WebRTC选择H.264的理由(我们翻译和整理的,译者:weizhenwei,校验:blacker),最早发表在[编风网] 支持原创,转载必须注明出处,欢迎关注我的微信公众号blacke ...

随机推荐

  1. MongoDB C++ 2.4.5 driver 编译安装问题

    安装参考前文,http://blog.csdn.net/sheismylife/article/details/8794589 方法一致.只不过这次在GCC4.8.1上编译. scons instal ...

  2. mysql @变量和变量的区别及怎么判断记录唯一性

    DELIMITER// drop PROCEDURE if EXISTS test.express; create PROCEDURE test.express() BEGIN ) into @a f ...

  3. java mysql驱动

    mysql驱动方式有三种, 1.第一种是先把jar包放在项目的目录下,通过添加jar包,是使用相对地址的,这样把项目复制到其它电脑也可以用 2.第二种方法是导入外部的jar包,是绝对地址,如果项目要复 ...

  4. 2015 南阳ccpc The Battle of Chibi (uestc 1217)

    题意:给定一个序列,找出长度为m的严格递增序列的个数. 思路:用dp[i][j]表示长度为i的序列以下标j结尾的总个数.三层for循环肯定超时,首先离散化,离散化之后就可以用树状数组来优化,快速查找下 ...

  5. codeforces 251A Points on Line(二分or单调队列)

    Description Little Petya likes points a lot. Recently his mom has presented him n points lying on th ...

  6. 转载:C# 中的委托

    原文地址  http://www.tracefact.net/CSharp-Programming/Delegates-and-Events-in-CSharp.aspx 感谢博主分享! 引言 委托和 ...

  7. YII数据库增删查改操作

    初学YII, 整理了一些YII数据库的相关操作,  共同学习,共同进步. 一.查询数据集合 //1.该方法是根据一个条件查询一个集合 $admin=Admin::model()->findAll ...

  8. Android之fragment点击切换和滑动切换结合

    学了一小段时间的Android,主要接触的是UI设计,打交道最多莫过于fragment了吧.在Android3.0引入了fragment的概念后,几乎在所以的Android的应用中都可以看见其身影,已 ...

  9. ios 改变状态栏颜色

    http://stackoverflow.com/questions/17678881/how-to-change-status-bar-text-color-in-ios-7 stackoverfl ...

  10. ANSI escape code

    最近在做iOS上的SSH终端项目,主要是在手机上远程连接Unix系统,并进行一些简单的指令操作,类似于SecureCRT:今天想总结一下这个项目中遇到的新东西----ANSI escape code. ...