从字面意思来看,configure就是配置的意思,顾名思义,Configure函数就是配置函数了。配置函数的作用是给程序配置(设定)一些初始的值,这些值在很大程度上相当于一个开关.
在用别人写的软件的时候,我们经常在软件的界面的某一个对话框里面输入一个参数,然后软件里的程序就会捕捉到这个对话框里面的参数,这样就把用户设定的参数传到了程序里面。细想一下,在JM8.6编码器中就是这样的,这里的“对话框”实际上是一个配置文件,比如:encoder_baseline.cfg. 那为什么需要这样一个配置文件呢?原因很简单,为了抽象,为了间接. 抽象是为了更好地重用. 间接又可以实现职责的分离,即用户可以通过配置文件来设定自己想用的参数,而不需要去改软件的程序.
先来简要地看一个结构体类型InputParameters, 在编码器的global.h中,是这么定义的:
typedef struct
{
//档次
int ProfileIDC; //!< profile idc
//级别
int LevelIDC; //!< level idc
//编码的帧数
int no_frames; //!< number of frames to be encoded
//第一帧QP
int qp0; //!< QP of first frame
//剩余帧QP
int qpN; //!< QP of remaining frames
//隔n帧编码
int jumpd; //!< number of frames to skip in input sequence (e.g 2 takes frame 0,3,6,9...)
int hadamard; /*!< 0: 'normal' SAD in 1/3 pixel search. 1: use 4x4 Haphazard transform and '
Sum of absolute transform difference' in 1/3 pixel search */
//搜索范围
int search_range; /*!< search range - integer pel search and 16x16 blocks. The search window is
generally around the predicted vector. Max vector is 2xmcrange. For 8x8
and 4x4 block sizes the search range is 1/2 of that for 16x16 blocks. */
//参考帧数
int num_reference_frames; //!< number of reference frames to be used
int P_List0_refs;
int B_List0_refs;
int B_List1_refs;
//图像宽度和高度必须是整MB的
int img_width; //!< image width (must be a multiple of 16 pels)
int img_height; //!< image height (must be a multiple of 16 pels)
//目前只支持4 : 2 : 0
int yuv_format; //!< GH: YUV format (0=4:0:0, 1=4:2:0, 2=4:2:2, 3=4:4:4,currently only 4:2:0 is supported)
//目前只支持8位色深
int color_depth; //!< GH: YUV color depth per component in bit/pel (currently only 8 bit/pel is supported)
int intra_upd; /*!< For error robustness. 0: no special action. 1: One GOB/frame is intra coded
as regular 'update'. 2: One GOB every 2 frames is intra coded etc.
In connection with this intra update, restrictions is put on motion vectors
to prevent errors to propagate from the past */
int blc_size[8][2]; //!< array for different block sizes
int slice_mode; //!< Indicate what algorithm to use for setting slices
int slice_argument; //!< Argument to the specified slice algorithm
//帧间宏块是否可用作帧内预测
int UseConstrainedIntraPred; //!< 0: Inter MB pixels are allowed for intra prediction 1: Not allowed
int infile_header; //!< If input file has a header set this to the length of the header
//输入,输出,重建,跟踪. (4个文件名)
char infile[100]; //!< YUV 4:2:0 input format
char outfile[100]; //!< H.264 compressed output bitstream
char ReconFile[100]; //!< Reconstructed Pictures
char TraceFile[100]; //!< Trace Outputs
int intra_period; //!< Random Access period though intra
// IDR片
int idr_enable; //!< Encode intra slices as IDR
//编码帧的开始位置
int start_frame; //!< Encode sequence starting from Frame start_frame
// B pictures
int successive_Bframe; //!< number of B frames that will be used
int qpB; //!< QP of B frames
int direct_type; //!< Direct Mode type to be used (0: Temporal, 1: Spatial)
int directInferenceFlag; //!< Direct Inference Flag
// SP Pictures
int sp_periodicity; //!< The periodicity of SP-pictures
int qpsp; //!< SP Picture QP for prediction error
int qpsp_pred; //!< SP Picture QP for predicted block
int WeightedPrediction; //!< Weighted prediciton for P frames (0: not used, 1: explicit)
int WeightedBiprediction; //!< Weighted prediciton for B frames (0: not used, 1: explicit, 2: implicit)
int StoredBPictures; //!< Stored (Reference) B pictures replace P pictures (0: not used, 1: used)
//熵编码方式
int symbol_mode; //!< Specifies the mode the symbols are mapped on bits
//输出文件方式(output file mode)即0:Annex B, 1:RTP
int of_mode; //!< Specifies the mode of the output file
//分割方式
int partition_mode; //!< Specifies the mode of data partitioning
//帧间搜索方式
int InterSearch16x16;
int InterSearch16x8;
int InterSearch8x16;
int InterSearch8x8;
int InterSearch8x4;
int InterSearch4x8;
int InterSearch4x4;
char PictureTypeSequence[MAXPICTURETYPESEQUENCELEN];
int FrameRate;
int chroma_qp_index_offset;
#ifdef _FULL_SEARCH_RANGE_
int full_search;
#endif
#ifdef _ADAPT_LAST_GROUP_
int last_frame;
#endif
#ifdef _CHANGE_QP_
int qpN2, qpB2, qp2start;
int qp02;
#endif
int rdopt;
#ifdef _LEAKYBUCKET_
int NumberLeakyBuckets;
char LeakyBucketRateFile[100];
char LeakyBucketParamFile[100];
#endif
int PicInterlace; //!< picture adaptive frame/field
int MbInterlace; //!< macroblock adaptive frame/field
int IntraBottom; //!< Force Intra Bottom at GOP periods.
int LossRateA; //!< assumed loss probablility of partition A (or full slice), in per cent, used for loss-aware R/D optimization
int LossRateB; //!< assumed loss probablility of partition B, in per cent, used for loss-aware R/D
int LossRateC; //!< assumed loss probablility of partition C, in per cent, used for loss-aware R/D
int NoOfDecoders;
int RestrictRef;
int NumFramesInELSubSeq;
int NumFrameIn2ndIGOP;
int RandomIntraMBRefresh; //!< Number of pseudo-random intra-MBs per picture
int LFSendParameters;
int LFDisableIdc;
int LFAlphaC0Offset;
int LFBetaOffset;
int SparePictureOption;
int SPDetectionThreshold;
int SPPercentageThreshold;
// FMO
char SliceGroupConfigFileName[100]; //!< Filename for config info fot type 0, 2, 6
int num_slice_groups_minus1; //!< "FmoNumSliceGroups" in encoder.cfg, same as FmoNumSliceGroups, which should be erased later
int slice_group_map_type;
int *top_left; //!< top_left and bottom_right store values indicating foregrounds
int *bottom_right;
int *slice_group_id; //!< slice_group_id is for slice group type being 6
int *run_length_minus1; //!< run_length_minus1 is for slice group type being 0
int slice_group_change_direction_flag;
int slice_group_change_rate_minus1;
int slice_group_change_cycle;
int redundant_slice_flag; //! whether redundant slices exist, JVT-D101
int pic_order_cnt_type; // POC200301
int context_init_method;
int model_number;
//! Rate Control on JVT standard
int RCEnable;
int bit_rate;
int SeinitialQP;
int basicunit;
int channel_type;
// FastME enable(快速运动估计)
int FMEnable;
} InputParameters;
可以看出, InputParameters结构体类型实际上就是对各种输入参数的一个打包. 在lencod.c中有下面的全局变量定义:
InputParameters inputs, *input = &inputs;
最终配置文件的信息都会导入到input->...里面,那么究竟怎么导入呢?这就要看Configure函数了,在main中, Configure函数是这样被调用的:
Configure (argc, argv);
在典型的正常配置下(可以在VC6.0中配置), argc = 3, argv[0]指向"...lencod.exe", argv[1]指向"-d", argv[2]指向 "encoder_baseline.cfg", 也就是说,有了argc和argv,就有了配置文件的名字. 下面进入Configure函数看看:(说明,只给出程序正常进入的部分,只为示意)
void Configure(int ac, char *av[])
{
char *content, *filename;
//configinput 在configfile.h中定义为:InputParameters configinput;
//下面语句将configinput中的数据项全部置为0
memset (&configinput, 0, sizeof (InputParameters));
configinput.LevelIDC = LEVEL_IDC;
configinput.ProfileIDC = PROFILE_IDC;
filename = av[2]; //获得了正确的"encoder_baseline.cfg"
//content指向了堆内存,堆内存中的内容串是配置文件的内容串,很长
content = GetConfigFileContent (filename);
//下面对content指向的内容串进行分析
//以便让lencod.c中的全局变量input->...从配置文件中获取足够信息
ParseContent (content, strlen(content));
free (content);
PatchInp();//对input->...的合法性进行检验
}
原来, Configure函数就是专门干这个的.