在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. HttpURLConnection学习

    转自:http://mobile.51cto.com/abased-448264.htm 最常用的Http请求无非是get和post,get请求可以获取静态页面,也可以把参数放在URL字串后面,传递给 ...

  2. NOI2015 软件包管理器 manager

    显然链剖 然而只询问到根的信息,不用管lca,要好些很多(虽然我没那么写) 对于安装 查询和维护到根路径 对于卸载 查询和维护子树信息 因为链剖本身是用dfs序建的线段树,所以使得查询和修改子树非常方 ...

  3. java hashCode()与equals()的作用

    1.hashcode是用来查找的,如果你学过数据结构就应该知道,在查找和排序这一章有 例如内存中有这样的位置 0  1  2  3  4  5  6  7 而我有个类,这个类有个字段叫ID,我要把这个 ...

  4. [Angular 2] Exposing component properties to the template

    Showing you how you can expose properties on your Controller to access them using #refs inside of yo ...

  5. android string.xml前后加空格的技巧

    方法1: <string name="password">密    码</string>&#160 这个就代表着空格. 方法2:用\u0020代表空 ...

  6. Linux Kernel: buffers和cached的区别

    The page cache caches pages of files to optimize file I/O. The buffer cache caches disk blocks to op ...

  7. ios创建的sqlite数据库文件如何从ios模拟器中导出

    为了验证数据库的结构,有的时候需要使用一些管理工具来直接查看sqlite数据库的内容,在windows下有sqlite3的专用工具下载,而在ios下也可以使用火狐浏览器的插件sqlitemanager ...

  8. Android(java)学习笔记232:Android进程间通讯(IPC)之AIDL

    一.IPC inter process communication  进程间通讯 二.AIDL android  interface  defination  language  安卓接口定义语言 满 ...

  9. 基于bootstrap的轮播广告页,带图片和文字

    <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="utf-8& ...

  10. eclipse[日文版] 的SVN 上传步骤

    可能有些朋友在日企上班,肯定要用到SVN,可是一般就下载和更新,没有用到上传 这里来介绍下上传 1.项目右键 2.点击Share Project 3.点击SVN下一步 4.选择你的上传的服务器地址 5 ...