encode_one_frame ()
从这个函数开始才开始真正进入编码阶段,在次之前都是做的一些准备工作,但是这个函数不是核心函数,这个函数的主要功能是通过调用其他的函数对一帧数据进行编码,每调用该函数一次,处理完一帧数据。
刚进入encode_one_frame (),前面几个函数如put_buffer_frame();CalculateFrameNumber(); init_frame ();等都比较简单。
frame_picture (frame_pic)函数是encode_one_frame ()这个函数中的主要函数!完成一帧数据的编码是通过这个函数来实现的。下面来看看这个函数具体做了那些事情。
进入函数,首先为要编码的图像申请空间并进行初始化,比较简单,没什么好说的。看看这个函数code_a_picture(frame);看函数名就知道它是这个函数中的最重要的函数。继续跟踪下去,看看code_a_picture(frame)这个函数的内容。进入这个函数体,
直接看FmoInit()这个函数,这个函数与片组相关,确定宏块到片组的映射关系。主要调用
FmoGenerateMapUnitToSlic eGroupMap(img, pps);
FmoGenerateMBAmap(img, sps);
这两个函数,前面一个函数主要根据slice_group_map_type这个变量决定片到片组的映射关系,既确定那些片属于同一个片组。 FmoGenerateMBAmap()确定宏块到片的映射,既那些宏块属于一个片。
FmoStartPicture ()得到每一个片中的第一个宏块地址。
看看下面这个循环
while (NumberOfCodedMBs < img->total_number_mb) // loop over slices
{
while (!FmoSliceGroupCompletelyC oded (SliceGroup))
{
NumberOfCodedMBs += encode_one_slice (SliceGroup, pic);
FmoSetLastMacroblockInSl ice (img->current_mb_nr);
// Proceed to next slice
img->current_slice_nr++;
stat->bit_slice = 0;
}
}
可以说是编码器的核心地方,外层循环以片为单位循环编码所有片,内层循环以片组为单位循环处理每个片组中的所有片数据。
顺便说一下,若想一个frame中有多个slice,配置文件中设置如下的参数可以实现
##########################################################################################
# Error Resilience / Slices
##########################################################################################
SliceMode
=
0
# Slice mode (0=off 1=fixed #mb in slice 2=fixed #bytes in slice 3=use callback)
SliceArgument
= 50
# Slice argument (Arguments to modes 1 and 2 above)
num_slice_groups_minus1 = 0
# Number of Slice Groups Minus 1, 0 == no FMO, 1 == two slice groups, etc.
slice_group_map_type
= 6
# 0:
Interleave, 1: Dispersed,
2: Foreground with left-over,
# 3:
Box-out,
4: Raster Scan
5: Wipe
# 6:
Explicit, slice_group_id read from SliceGroupConfigFileName
slice_group_change_direction_flag = 0
# 0: box-out clockwise, raster scan or wipe right,
# 1: box-out counter clockwise, reverse raster scan or wipe left
slice_group_change_rate_minus1
= 85
#
SliceGroupConfigFileName
= "sg6conf.cfg"
# Used for slice_group_map_type 0, 2, 6
UseRedundantSlice
= 0
# 0: not used, 1: one redundant slice used for each slice (other modes not supported yet)
SliceMode
=
0
为默认值,既不使用分组,也就是一帧为一个slice。
具体的可以参照相应资料。
下面看看这个函数中的核心函数encode_one_slice();
看名字也知道是对一个slice进行编码 !下面进入这个函数体:
CurrentMbAddr = FmoGetFirstMacroblockInS lice (SliceGroupId); 取得当前片的第一个宏块,init_slice(),为当前要编码的slice申请一个Slice类型结构体,并进行初始化。
len = start_slice ()函数,写slice_header.
while (end_of_slice == FALSE)
{
...............
........................
}
这个循环对每个slice进行编码,用帧或场方式。不管是哪种编码方式,核心函数是encode_one_macroblock ();可以说这才是整个编码器的核心部分!关于这个函数的结构可以参照firsttime 的 encode_one_macroblock()的程序结构——Wisting
(说明:由于本人主要研究的不是jm代码,要是有写的不对的地方,请指教 共同学习,关于其中涉及的各个函数,哪位熟悉的话,如果愿意,可以跟帖补充具体的内容)
从这个函数开始才开始真正进入编码阶段,在次之前都是做的一些准备工作,但是这个函数不是核心函数,这个函数的主要功能是通过调用其他的函数对一帧数据进行编码,每调用该函数一次,处理完一帧数据。
刚进入encode_one_frame (),前面几个函数如put_buffer_frame();CalculateFrameNumber(); init_frame ();等都比较简单。
frame_picture (frame_pic)函数是encode_one_frame ()这个函数中的主要函数!完成一帧数据的编码是通过这个函数来实现的。下面来看看这个函数具体做了那些事情。
进入函数,首先为要编码的图像申请空间并进行初始化,比较简单,没什么好说的。看看这个函数code_a_picture(frame);看函数名就知道它是这个函数中的最重要的函数。继续跟踪下去,看看code_a_picture(frame)这个函数的内容。进入这个函数体,
直接看FmoInit()这个函数,这个函数与片组相关,确定宏块到片组的映射关系。主要调用
FmoGenerateMapUnitToSlic
这两个函数,前面一个函数主要根据slice_group_map_type这个变量决定片到片组的映射关系,既确定那些片属于同一个片组。 FmoGenerateMBAmap()确定宏块到片的映射,既那些宏块属于一个片。
FmoStartPicture ()得到每一个片中的第一个宏块地址。
看看下面这个循环
while (NumberOfCodedMBs < img->total_number_mb)
可以说是编码器的核心地方,外层循环以片为单位循环编码所有片,内层循环以片组为单位循环处理每个片组中的所有片数据。
顺便说一下,若想一个frame中有多个slice,配置文件中设置如下的参数可以实现
##########################################################################################
# Error Resilience / Slices
##########################################################################################
SliceMode
SliceArgument
num_slice_groups_minus1 = 0
slice_group_map_type
slice_group_change_direction_flag = 0
slice_group_change_rate_minus1
SliceGroupConfigFileName
UseRedundantSlice
SliceMode
具体的可以参照相应资料。
下面看看这个函数中的核心函数encode_one_slice();
看名字也知道是对一个slice进行编码 !下面进入这个函数体:
CurrentMbAddr = FmoGetFirstMacroblockInS
len = start_slice ()函数,写slice_header.
while (end_of_slice == FALSE)
{
...............
........................
}
这个循环对每个slice进行编码,用帧或场方式。不管是哪种编码方式,核心函数是encode_one_macroblock ();可以说这才是整个编码器的核心部分!关于这个函数的结构可以参照firsttime 的 encode_one_macroblock()的程序结构——Wisting
(说明:由于本人主要研究的不是jm代码,要是有写的不对的地方,请指教 共同学习,关于其中涉及的各个函数,哪位熟悉的话,如果愿意,可以跟帖补充具体的内容)