先看lencod.c中的GenerateParameterSets函数,进入其中:
void GenerateParameterSets ()
{
seq_parameter_set_rbsp_t *sps = NULL;
pic_parameter_set_rbsp_t *pps = NULL;
sps = AllocSPS(); // 分配堆空间
pps = AllocPPS(); // 分配堆空间
FillParameterSetStructures (sps, pps);
active_sps = sps; // active_sps和下面的active_pps都是global.h中定义的全局变量
active_pps = pps;
}
进入FillParameterSetStructures函数看看:
void FillParameterSetStructures (seq_parameter_set_rbsp_t *sps,
pic_parameter_set_rbsp_t *pps)
{
unsigned i;
// *************************************************************************
// Sequence Parameter Set
// *************************************************************************
assert (sps != NULL);
assert (pps != NULL);
// Profile and Level should be calculated using the info from the config
// file. Calculation is hidden in IndetifyProfile() and IdentifyLevel()
sps->profile_idc = IdentifyProfile();
sps->level_idc = IdentifyLevel();
// needs to be set according to profile
sps->constrained_set0_flag = 0;
sps->constrained_set1_flag = 0;
sps->constrained_set2_flag = 0;
// Parameter Set ID hardcoded to zero
sps->seq_parameter_set_id = 0;
//! POC stuff:
//! The following values are hard-coded in init_poc(). Apparently,
//! the poc implementation covers only a subset of the poc functionality.
//! Here, the same subset is implemented. Changes in the POC stuff have
//! also to be reflected here
sps->log2_max_frame_num_minus4 = log2_max_frame_num_minus4;
sps->log2_max_pic_order_cnt_lsb_minus4 = log2_max_pic_order_cnt_lsb_minus4;
sps->pic_order_cnt_type = input->pic_order_cnt_type;
sps->num_ref_frames_in_pic_order_cnt_cycle = img->num_ref_frames_in_pic_order_cnt_cycle;
sps->delta_pic_order_always_zero_flag = img->delta_pic_order_always_zero_flag;
sps->offset_for_non_ref_pic = img->offset_for_non_ref_pic;
sps->offset_for_top_to_bottom_field = img->offset_for_top_to_bottom_field;
for (i=0; i<img->num_ref_frames_in_pic_order_cnt_cycle; i++)
{
sps->offset_for_ref_frame[i] = img->offset_for_ref_frame[i];
}
// End of POC stuff
// Number of Reference Frames
sps->num_ref_frames = IdentifyNumRefFrames();
//required_frame_num_update_behaviour_flag hardcoded to zero
sps->gaps_in_frame_num_value_allowed_flag = FALSE; // double check
sps->frame_mbs_only_flag = !(input->PicInterlace || input->MbInterlace);
// Picture size, finally a simple one :-)
sps->pic_width_in_mbs_minus1 = (input->img_width/16) -1;
sps->pic_height_in_map_units_minus1 = ((input->img_height/16)/ (2 - sps->frame_mbs_only_flag)) - 1;
// a couple of flags, simple
sps->mb_adaptive_frame_field_flag = (FRAME_CODING != input->MbInterlace);
sps->direct_8x8_inference_flag = input->directInferenceFlag;
// Sequence VUI not implemented, signalled as not present
sps->vui_parameters_present_flag = FALSE;
{
int PicWidthInMbs, PicHeightInMapUnits, FrameHeightInMbs;
int width, height;
PicWidthInMbs = (sps->pic_width_in_mbs_minus1 +1);
PicHeightInMapUnits = (sps->pic_height_in_map_units_minus1 +1);
FrameHeightInMbs = ( 2 - sps->frame_mbs_only_flag ) * PicHeightInMapUnits;
width = PicWidthInMbs * MB_BLOCK_SIZE;
height = FrameHeightInMbs * MB_BLOCK_SIZE;
Co_located = alloc_colocated (width, height,sps->mb_adaptive_frame_field_flag);
}
// *************************************************************************
// Picture Parameter Set
// *************************************************************************
pps->seq_parameter_set_id = 0;
pps->pic_parameter_set_id = 0;
pps->entropy_coding_mode_flag = (input->symbol_mode==UVLC?0:1);
// JVT-Fxxx (by Stephan Wenger, make this flag unconditional
pps->pic_order_present_flag = img->pic_order_present_flag;
// Begin FMO stuff
pps->num_slice_groups_minus1 = input->num_slice_groups_minus1;
//! Following set the parameter for different slice group types
if (pps->num_slice_groups_minus1 > 0)
switch (input->slice_group_map_type)
{
case 0:
pps->slice_group_map_type = 0;
for(i=0; i<=pps->num_slice_groups_minus1; i++)
{
pps->run_length_minus1[i]=input->run_length_minus1[i];
}
break;
case 1:
pps->slice_group_map_type = 1;
break;
case 2:
// i loops from 0 to num_slice_groups_minus1-1, because no info for background needed
pps->slice_group_map_type = 2;
for(i=0; i<pps->num_slice_groups_minus1; i++)
{
pps->top_left[i] = input->top_left[i];
pps->bottom_right[i] = input->bottom_right[i];
}
break;
case 3:
case 4:
case 5:
pps->slice_group_map_type = input->slice_group_map_type;
pps->slice_group_change_direction_flag = input->slice_group_change_direction_flag;
pps->slice_group_change_rate_minus1 = input->slice_group_change_rate_minus1;
break;
case 6:
pps->slice_group_map_type = 6;
pps->pic_size_in_map_units_minus1 =
((input->img_height/MB_BLOCK_SIZE)/(2-sps->frame_mbs_only_flag))
*(input->img_width/MB_BLOCK_SIZE) -1;
for (i=0;i<=pps->pic_size_in_map_units_minus1; i++)
pps->slice_group_id[i] = input->slice_group_id[i];
break;
default:
printf ("Parset.c: slice_group_map_type invalid, default\n");
assert (0==1);
}
// End FMO stuff
pps->num_ref_idx_l0_active_minus1 = sps->frame_mbs_only_flag ? (sps->num_ref_frames-1) : (2 * sps->num_ref_frames - 1) ; // set defaults
pps->num_ref_idx_l1_active_minus1 = sps->frame_mbs_only_flag ? (sps->num_ref_frames-1) : (2 * sps->num_ref_frames - 1) ; // set defaults
//pps->num_ref_idx_l1_active_minus1 = sps->frame_mbs_only_flag ? 0 : 1 ; // set defaults
pps->weighted_pred_flag = input->WeightedPrediction;
pps->weighted_bipred_idc = input->WeightedBiprediction;
pps->pic_init_qp_minus26 = 0; // hard coded to zero, QP lives in the slice header
pps->pic_init_qs_minus26 = 0;
pps->chroma_qp_index_offset = input->chroma_qp_index_offset; // double check: is this chroma fidelity thing already implemented???
pps->deblocking_filter_control_present_flag = input->LFSendParameters;
pps->constrained_intra_pred_flag = input->UseConstrainedIntraPred;
pps->redundant_pic_cnt_present_flag = 0;
// the picture vui consists currently of the cropping rectangle, which cannot
// used by the current decoder and hence is never sent.
sps->frame_cropping_flag = FALSE;
};
可见,FillParameterSetStructures函数的作用是对sps->...和pps->...进行赋值,其中很多值都是从input->...和img->...中得到的,而后两者中的很多值是从配置文件中得到的. 经过对active_sps和active_pps赋值后,active_sps和active_pps就得到了相应的值(有些是间接从配置文件中获得的)
继续看start_sequence函数:
int start_sequence()
{
int len=0;
NALU_t *nalu;
switch(input->of_mode)
{
case PAR_OF_ANNEXB:
OpenAnnexbFile (input->outfile);
WriteNALU = WriteAnnexbNALU;
break;
case PAR_OF_RTP:
OpenRTPFile (input->outfile);
WriteNALU = WriteRTPNALU;
break;
default:
snprintf(errortext, ET_SIZE, "Output File Mode %d not supported", input->of_mode);
error(errortext,1);
return 1;
}
//! As a sequence header, here we write the both sequence and picture
//! parameter sets. As soon as IDR is implemented, this should go to the
//! IDR part, as both parsets have to be transmitted as part of an IDR.
//! An alterbative may be to consider this function the IDR start function.
nalu = NULL;
nalu = GenerateSeq_parameter_set_NALU ();
len += WriteNALU (nalu);
FreeNALU (nalu);
nalu = NULL;
nalu = GeneratePic_parameter_set_NALU ();
len += WriteNALU (nalu);
FreeNALU (nalu);
// stat->bit_ctr_parametersets = len;
stat->bit_ctr_parametersets_n = len;
return 0;
}
进入GenerateSeq_parameter_set_NALU函数看看:
NALU_t *GenerateSeq_parameter_set_NALU ()
{
NALU_t *n = AllocNALU(64000);
int RBSPlen = 0;
int NALUlen;
byte rbsp[MAXRBSPSIZE];
RBSPlen = GenerateSeq_parameter_set_rbsp (active_sps, rbsp);
NALUlen = RBSPtoNALU (rbsp, n, RBSPlen, NALU_TYPE_SPS, NALU_PRIORITY_HIGHEST, 0, 1);
n->startcodeprefix_len = 4;
return n;
}
由RBSPlen = GenerateSeq_parameter_set_rbsp (active_sps, rbsp);可知,在生成RBSP的过程中,的确用到了active_sps(间接地从配置文件获得了数据). 随后RBSP又转换成了NALU,这样就生成了一个NALU(这样,NALU就间接地从配置文件获得了数据)
于是start_sequence函数中的下面语句就生成了sps对应的NALU和pps对应的NALU:
nalu = GenerateSeq_parameter_set_NALU ();
......
nalu = GeneratePic_parameter_set_NALU ();
于是,调用start_sequence函数中的下面语句后,就把SPS呵呵PPS写进码流了:
len += WriteNALU (nalu);
......
len += WriteNALU (nalu);