JM代码分析(一)

article/2025/5/14 13:03:22

JM代码分析(一)

    • 入门视频采集与处理(学会分析YUV数据)
    • 核心编码函数研究
    • 码流控制RC
    • 去块滤波
    • 核心全局变量
    • 运动矢量的写码流
    • 从码流中提取NALU
    • 结构体
    • 00000(IDR)
    • buf2img_basic
    • 宏块模式
    • 编码端写码流
      • 编码器:
      • 解码器:
    • 解码端读取运动矢量信息
    • 解码端读取残差信息
    • 编码端写残差信息
    • JM18中编码一个I宏块的过程
    • CBP
    • JM使用
    • 缩写
    • 问题
    • TIFF文件格式
    • 像素由多少位构成
    • C库函数
    • gdb调试命令

请添加图片描述


入门视频采集与处理(学会分析YUV数据)

核心编码函数研究

如果选择的是帧内模式,则预测值由当前帧已经编码重建的宏块(没有经过去块效应滤波器)给出,最佳的模式值经过熵编码输出到编码流。如果选择的是帧间模式,则预测值由以前编码帧的重建图像给出,选择的参考帧运动向量等信息经过熵编码输出到码流。原始图像的值和帧内或者帧间预测得到的预测值相减得到残差数据,这些残差数据经过变换,量化后得到的残差系数也经过熵编码输出到码流。另外,参加熵编码的残差系数经过反量化和反变换,和预测值相加,得到重建宏块,存储在当前帧的重建图像中。当前帧的重建图像全部完成以后,经过去块效应滤波器的滤波,将作为参考帧存储起来成为以后编码图像的帧间运动估计的参考。

编码一个宏块的步骤:
帧间帧内模式选择,7 种帧间模式包括:16x16 16x8 8x16 8x8 8x4 4x8 4x4, 分别对应模式编号1~7。在进行帧间预测的时候,只有在选择了把一个宏块划分成4 个8x8 的块之后,才能进一步选择8x4,4x8 和4x4的分块。因此,在JM 模型中,把4~7 的四种帧间模式统称为P8x8。根据配置文件中的RDOptimization 的取值,JM 采用两套不同的编码步骤。

码流控制RC

rate control 的总体目标是控制每一帧图像编码输出的比特数,并在总比特数一定的约束条件下使得图像失真最小,并且保证编解码端的缓存区不发生溢出。

去块滤波

去块滤波是在整幅图像编码完后进行,以宏块为单位,以解决DCT变换和量化引起的块效应。

核心全局变量

static const short part_size[8][2] = 
{{4, 4},{4, 4},{4, 2},{2, 4},{2, 2},{2, 1},{1, 2},{1, 1}
};

SKIP模式,16×16,16×8,8×16,P8×8(8x8, 8x4, 4x8, 4x4),以一个4x4大小为基础。

运动矢量的写码流

int main()
{// init encoderinit_encoder(p_Enc->p_Vid, p_Enc->p_Inp);// encode sequenceencode_sequence(p_Enc->p_Vid, p_Enc->p_Inp);
}encode_sequence -> encode_one_frame
encode_sequence  -> encode_one_redundant_frame -> encode_one_frameencode_one_frame(VideoParameters *p_Vid, InputParameters *p_Inp)
{if (p_Inp->PicInterlace == FIELD_CODING)**perform_encode_field**(p_Vid);else**perform_encode_frame**(p_Vid);
}perform_encode_frame -> frame_picture_mp -> frame_picture_mp_b_slice/frame_picture_mp_i_slice/frame_picture_mp_p_slice -> **frame_picture** 
perform_encode_frame -> **frame_picture**perform_encode_frame -> **frame_picture** -> code_a_picture(p_Vid, frame);
perform_encode_field -> field_picture -> code_a_picture(p_Vid, top);/code_a_picture(p_Vid, bottom);code_a_picture(VideoParameters *p_Vid, Picture *pic)
{if( (p_Inp->separate_colour_plane_flag != 0) ){for( pl=0; pl<MAX_PLANE; pl++ ){p_Vid->current_mb_nr = 0;p_Vid->current_slice_nr = 0;p_Vid->SumFrameQP = 0;p_Vid->num_ref_idx_l0_active = 0;p_Vid->num_ref_idx_l1_active = 0;p_Vid->colour_plane_id = (char) pl;code_a_plane(p_Vid, p_Inp);}}else{code_a_plane(p_Vid, p_Inp);}
}code_a_plane
{while (NumberOfCodedMBs < p_Vid->PicSizeInMbs)       // loop over slices{// Encode one SLice Groupwhile (!FmoSliceGroupCompletelyCoded (p_Vid, SliceGroup)){// Encode the current sliceif (!p_Vid->mb_aff_frame_flag)NumberOfCodedMBs += encode_one_slice (p_Vid, SliceGroup, NumberOfCodedMBs);elseNumberOfCodedMBs += encode_one_slice_MBAFF (p_Vid, SliceGroup, NumberOfCodedMBs);FmoSetLastMacroblockInSlice (p_Vid, p_Vid->current_mb_nr);// Proceed to next slicep_Vid->current_slice_nr++;p_Vid->p_Stats->bit_slice = 0;}// Proceed to next SliceGroupSliceGroup++;}
}
encode_one_slice -> init_slice
encode_one_slice_MBAFF -> init_slice
init_slice
{  if ((*currSlice)->symbol_mode == CAVLC){setup_cavlc(*currSlice, (*currSlice)->listXsize);}else{setup_cabac(*currSlice, (*currSlice)->listXsize);}
}

运动矢量是以1/4像素为单位的,所以(4,8),实际代表偏移了(1,2)个像素

从码流中提取NALU

从码流中提取一个NALU的过程:get_ annex_ b_NALU
对于一个原始的 H.264 NALU 单元常由 [Start Code] [NALU Header] [NALU Payload] 三部分组成, 其中 Start Code 用于标示这是一个
NALU 单元的开始, 必须是 “00 00 00 01” 或 “00 00 01”, NALU 头仅一个字节, 其后都是 NALU 单元内容.
打包时去除 “00 00 01” 或 “00 00 00 01” 的开始码, 把其他数据封包的 RTP 包即可.

结构体

struct video_par  //视频参数结构  Image Parameters
{InputParameters          *p_Inp;pic_parameter_set_rbsp_t *active_pps;seq_parameter_set_rbsp_t *active_sps;seq_parameter_set_rbsp_t SeqParSet[MAXSPS];pic_parameter_set_rbsp_t PicParSet[MAXPPS];pic_parameter_set_rbsp_t *pNextPPS;float framerate;int frame_no;int fld_type;                        //!< top or bottom fieldint  key_frame;int  frm_no_in_file;	int pix_x;                   //!< current pixel horizontalint pix_y;                   //!< current pixel vertical//currentPicture指向当前正在活动的图像(frame_pic, top_pic或bottom_pic)Picture       *currentPicture; struct slice  *currentSlice;     //!< pointer to current Slice data structMacroblock    *mb_data;         //!< array containing all MBs of a whole frameint  frameNuminGOP; int num_mb_per_slice;int number_of_slices;GOP_DATA *gop_structure;int p_dec;                      //!< decoded image file handlestruct nalu_t *nalu;
}
 //! Slice
typedef struct slice
{struct video_par    *p_Vid;   // pointer to the original video structureInputParameters     *p_Inp;   // pointer to the input parametersint                 start_mb_nr;int                 max_part_nr;  //!< number of different partitionsint                 num_mb;       //!< number of MBs in the sliceint                 frame_no;MotionVector *****all_mv;         //!< replaces local all_mvMotionVector ******bipred_mv;     //!< Biprediction MVs 
}

00000(IDR)

21392 28 37.638 41.571 43.231 391 0 FRM 3

-------------------------------------------------------------------------------
Frame     Bit/pic    QP   SnrY    SnrU    SnrV    Time(ms) MET(ms) Frm/Fld Ref  
-------------------------------------------------------------------------------
00000(NVB)     320 
00000(IDR)   21392   28  37.638  41.571  43.231       391       0    FRM    3
00002( B )    5280   31  35.548  40.735  42.217      1368     689    FRM    1
00001( B )    2096   32  35.308  41.128  42.611      1281     778    FRM    0
-------------------------------------------------------------------------------
image.c 
encode_ one_frame -> ReportNALNonVLCBits ReportFirstframe

buf2img_basic

将文件中的一帧转换为PIC

void buf2img_basic (imgpel** imgX,            //!< Pointer to image planeunsigned char* buf,       //!< Buffer for file outputint size_x,               //!< horizontal size of pictureint size_y,               //!< vertical size of pictureint o_size_x,             //!< horizontal size of picture outputint o_size_y,             //!< vertical size of picture outputint symbol_size_in_bytes, //!< number of bytes in file used for one pixel  一个像素所需的字节数int dummy                 //!< dummy variable used for allowing function pointer use)
{int i,j;unsigned char* temp_buf = buf;if (symbol_size_in_bytes> sizeof(imgpel))  //sizeof(imgpel) = 2 byte =16bit{error ("Source picture has higher bit depth than imgpel data type. \nPlease recompile with larger data type for imgpel.", 500);}if (( sizeof (imgpel) == symbol_size_in_bytes)){    // imgpel == pixel_in_file -> simple copyif (size_x == o_size_x && size_y == o_size_y)memcpy(&imgX[0][0], temp_buf, size_x * size_y * sizeof(imgpel));else{int iminwidth   = imin(size_x, o_size_x);int iminheight  = imin(size_y, o_size_y);int dst_offset_x  = 0, dst_offset_y = 0;int offset_x = 0, offset_y = 0; // currently not used// determine whether we need to center the copied frame or crop itif ( o_size_x >= size_x ) dst_offset_x = ( o_size_x  - size_x  ) >> 1;if (o_size_y >= size_y) dst_offset_y = ( o_size_y - size_y ) >> 1;// check copied area to avoid copying memory garbage// sourceiminwidth  =  ( (offset_x + iminwidth ) > size_x ) ? (size_x  - offset_x) : iminwidth;iminheight =  ( (offset_y + iminheight) > size_y ) ? (size_y - offset_y) : iminheight;// destinationiminwidth  =  ( (dst_offset_x + iminwidth ) > o_size_x  ) ? (o_size_x  - dst_offset_x) : iminwidth;iminheight =  ( (dst_offset_y + iminheight) > o_size_y )  ? (o_size_y - dst_offset_y) : iminheight;for (i=0; i<iminheight;i++) {memcpy(&imgX[i + dst_offset_y][dst_offset_x], &(temp_buf[(i + offset_y) * size_x + offset_x]), iminwidth * sizeof(imgpel));}}}else{int j_pos;uint16 ui16;if (size_x == o_size_x && size_y == o_size_y){for (j=0; j < o_size_y; j++) //按行{j_pos = j * size_x;  //0*144;1*144;2*144....每行行首for (i=0; i < o_size_x; i++){ui16=0;             //行首+一行的偏移(i + j_pos) * symbol_size_in_bytes表示字节数memcpy(&(ui16), buf + ((i + j_pos) * symbol_size_in_bytes), symbol_size_in_bytes);imgX[j][i]= (imgpel) ui16;}} //@1 为解释此for循环}else{int iminwidth   = imin(size_x, o_size_x);int iminheight  = imin(size_y, o_size_y);int dst_offset_x  = 0, dst_offset_y = 0;int offset_x = 0, offset_y = 0; // currently not used// determine whether we need to center the copied frame or crop itif ( o_size_x >= size_x ) dst_offset_x = ( o_size_x  - size_x  ) >> 1;if (o_size_y >= size_y) dst_offset_y = ( o_size_y - size_y ) >> 1;// check copied area to avoid copying memory garbage// sourceiminwidth  =  ( (offset_x + iminwidth ) > size_x ) ? (size_x  - offset_x) : iminwidth;iminheight =  ( (offset_y + iminheight) > size_y ) ? (size_y - offset_y) : iminheight;// destinationiminwidth  =  ( (dst_offset_x + iminwidth ) > o_size_x  ) ? (o_size_x  - dst_offset_x) : iminwidth;iminheight =  ( (dst_offset_y + iminheight) > o_size_y )  ? (o_size_y - dst_offset_y) : iminheight;for (j = 0; j < iminheight; j++) {memcpy(&imgX[j + dst_offset_y][dst_offset_x], &(temp_buf[(j + offset_y) * size_x + offset_x]), iminwidth * symbol_size_in_bytes);}for (j=0; j < iminheight; j++){        j_pos = (j + offset_y) * size_x + offset_x;for (i=0; i < iminwidth; i++){ui16 = 0;memcpy(&(ui16), buf + ((i + j_pos) * symbol_size_in_bytes), symbol_size_in_bytes);imgX[j + dst_offset_y][i + dst_offset_x]= (imgpel) ui16;}}    }}
}

@1:
这里写图片描述
因此imgX这个二位数组里存放了Y DATA的数据
====================== Y Data ======================
±-------------------------------±-------------------------------+
| 49, 50, 49, 49, 49, 48, 48, 48,| 48, 49, 51, 57, 62, 62, 61, 62,|
| 47, 47, 48, 48, 48, 48, 48, 47,| 47, 48, 48, 47, 48, 50, 50, 50,|
| 45, 45, 45, 44, 45, 45, 46, 45,| 45, 45, 45, 44, 43, 43, 44, 44,|
| 41, 42, 43, 43, 43, 41, 41, 43,| 43, 41, 42, 43, 43, 42, 43, 43,|
| 38, 39, 38, 38, 39, 40, 39, 38,| 39, 39, 39, 40, 39, 38, 39, 38,|
| 39, 39, 39, 38, 39, 41, 40, 40,| 40, 41, 41, 40, 40, 41, 42, 40,|
| 51, 51, 52, 52, 51, 50, 51, 51,| 51, 50, 50, 50, 50, 50, 51, 50,|
| 64, 64, 65, 64, 63, 62, 62, 62,| 62, 62, 62, 61, 61, 61, 60, 60,|
±-------------------------------±-------------------------------+
| 73, 74, 74, 74, 73, 72, 70, 70,| 71, 71, 71, 70, 70, 70, 70, 70,|
| 77, 79, 78, 78, 78, 77, 75, 75,| 76, 75, 75, 75, 75, 75, 75, 74,|
| 79, 79, 79, 79, 78, 77, 76, 76,| 76, 75, 75, 75, 74, 74, 74, 74,|
| 82, 81, 81, 80, 78, 76, 76, 76,| 76, 76, 75, 75, 75, 75, 75, 74,|
| 93, 91, 87, 83, 80, 77, 76, 76,| 76, 76, 75, 74, 75, 76, 76, 76,|
|105,102, 94, 86, 82, 78, 77, 76,| 76, 78, 76, 75, 76, 77, 77, 77,|
|111,108, 99, 89, 82, 80, 77, 77,| 77, 78, 76, 75, 76, 76, 78, 77,|
|117,111,102, 91, 82, 80, 78, 79,| 78, 77, 76, 76, 76, 77, 77, 76,|
±-------------------------------±-------------------------------+:
2、int read_one_frame

int read_one_frame (VideoParameters *p_Vid, VideoDataFile *input_file, int FrameNoInFile, int HeaderSize, FrameFormat *source, FrameFormat *output, imgpel **pImage[3])

pImage[3]存放了Y/U/V的数据
这里写图片描述

宏块模式

static const char mb_mode_table[10]  = 
{0, //16X16 Direct模式,在B帧中有效1, //Inter16X16,在帧间有效2, //Inter16X8,在帧间有效3, //Inter8X16,在帧间有效P8x8,  //帧间有效I16MB, //Intra16X16帧内有效I4MB,  //Intra有效I8MB,  //Intra有效IPCM,  //Intra有效,不要预测,直接对RAW数据编码SI4MB
}; // DO NOT CHANGE ORDER !!!

编码端写码流

编码器:

一直以为写码流在write_one_macroblock()函数中进行,其实不是,这个函数的名字对初学者来说绝对有误导作用。(该函数只是将语法元素写入缓冲区,并未写入文件)
真正的写码流过程如下:
----lencod.c中调用start_sequence()和terminate_sequence()分别打开和关闭文件流(input->outfile).
filehandle.c中的start_sequence()和terminate_sequence()中有几个与写码流相关的重要的操作:

	OpenAnexxbFile(input->outfile);WriteNALU=WriteAnexxbNALU;

于是WriteNALU在编码器中担任了写码流的主要及核心工作。
----在OpenAnexxbFile()中(Anexxb.c中)将文件打开,句柄赋与FILE *f全局变量,f=fopen(Filename,“wb”) 从这句以后文件流一直处于打开状态,便于写码流。
----打开后紧接着调用WriteNALU写头部。
注意:WriteNALU的参数及其中各函数的NALU_t类型变量。
----搜索WriteNALU:
在WriteUnit中有调用,而WriteUnit在WriteOut_Picture中有调用,WriteOut_Picture()在encode_one_frame()中有调用。于是从encode_one_frame开始
,整个写码流流程是:

encode_one_frame---->frame_picture
---->WriteOut_Picture---->WriteUnit
----->WriteNALU(即WriteAnexxbNALU)

整个文件编码完并写码流结束后调用terminate_sequence()关闭文件流。
注意各函数中的NALU_t类型变量,以及WriteNALU中的FILE *f,最终落实写码流的语句是:fwrite(n->buf,1,n->len,f);

解码器:

配置文件中共包含三个文件:
test.264 test_dec_yuv test_rec_yuv分别对应inp->infile(bits),inp->outfile(p_out),inp->reffile(p_ref),括号内为文件所对应的变量 初始化在
init_conf()中进行。
举例:OpenBitstreamFile()中有bits=fopen(fn,“rb”)于是bits便与fn建立起了对应关系,其它两个类同。
read_new_slice()中img->currSlice->currStream保存了从码流中读进来的语法元素(memcpy(currStream->streamBuffer,&nalu->buf[1],nalu->len-1)😉
注意这里的nalu->len,这个分量控制眷读码流的位数,很重要,它在GetAnexxbNALU中求得。
因此解码器中整个码流流向为:
inp->infile->bits->nalu->[CurrStream->streamBuffer]

解码端读取运动矢量信息

readMBMotionVectors

#0  readMBMotionVectors (currSE=0xbfffdde8, dP=0x81cdff0, currMB=0x8148d68, list=0, step_h0=4, step_v0=4, offset=1) at src/macroblock.c:431
#1  0x08093fc1 in read_motion_info_from_NAL_p_slice (currMB=0x8148d68) at src/macroblock.c:1264
#2  0x0809c585 in read_inter_macroblock (currMB=0x8148d68) at src/mb_read.c:1059
#3  0x0809daea in read_one_macroblock_p_slice_cabac (currMB=0x8148d68) at src/mb_read.c:1728
#4  0x0806554f in decode_one_slice (currSlice=0x81c9000) at src/image.c:2534
#5  0x08060e94 in decode_slice (currSlice=0x81c9000, current_header=2) at src/image.c:748
#6  0x0806169d in decode_one_frame (pDecoder=0x810d170) at src/image.c:943
#7  0x08087376 in DecodeOneFrame (ppDecPicList=0xbfffdfe4) at src/ldecod.c:1254
#8  0x08054fd3 in main (argc=1, argv=0xbffff174) at src/decoder_test.c:282

解码端读取残差信息

  • Get coefficients (run/level) of one 8x8 block
  • from the NAL (CABAC Mode)
    readCompCoeff8x8_CABAC

编码端写残差信息

#0  write_significance_map (currMB=0x8233210, eep_dp=0x87c9d04, type=6, coeff=0x87c61a8, coeff_ctr=4, tex_ctx=0x87c6920) at src/cabac.c:1739
#1  0x08058476 in writeRunLevel_CABAC (currMB=0x8233210, se=0xbfffea20, dp=0x87c9cf0) at src/cabac.c:1861
#2  0x080a8559 in write_chroma_coeff (currMB=0x8233210) at src/macroblock.c:3532
#3  0x080a66f8 in write_i_slice_MB_layer (currMB=0x8233210, rdopt=1, coeff_rate=0xbfffeae4, Extraction=0)at src/macroblock.c:2800
#4  0x0812bfd7 in RDCost_for_macroblocks (currMB=0x8233210, lambda=570, mode=10) at src/rdopt.c:1964
#5  0x080f5524 in compute_mode_RD_cost (currMB=0x8233210, enc_mb=0xbfffece8, mode=10, inter_skip=0xbfffec1e)at src/mode_decision.c:460
#6  0x080be518 in encode_one_macroblock_high (currMB=0x8233210) at src/md_high.c:289
#7  0x08149f80 in encode_one_slice (p_Vid=0x81d0020, SliceGroupId=0, TotalCodedMBs=0) at src/slice.c:513
#8  0x0806cad2 in code_a_plane (p_Vid=0x81d0020, p_Inp=0x81e4c88) at src/image.c:223
#9  0x0806ce05 in code_a_picture (p_Vid=0x81d0020, pic=0x8365ab8) at src/image.c:308
#10 0x080709db in frame_picture (p_Vid=0x81d0020, frame=0x8365ab8, imgData=0x81d00ec, rd_pass=0)at src/image.c:1665
#11 0x0806e578 in perform_encode_frame (p_Vid=0x81d0020) at src/image.c:820
#12 0x0806fbe2 in encode_one_frame (p_Vid=0x81d0020, p_Inp=0x81e4c88) at src/image.c:1302
#13 0x0808dfea in encode_sequence (p_Vid=0x81d0020, p_Inp=0x81e4c88) at src/lencod.c:1106
#14 0x0808c0b3 in main (argc=1, argv=0xbffff174) at src/lencod.c:392

JM18中编码一个I宏块的过程

以I16MB为例:

RDCost_for_macroblocks -> 
currSlice->mode_decision_for_I16x16_MB (mode_decision_for_I16x16_MB_RDO) ->
currMB->residual_transform_quant_luma_16x16(residual_transform_quant_luma_16x16)
#0  residual_transform_quant_luma_16x16 (currMB=0x8233210, pl=PLANE_Y) at src/block.c:212
#1  0x08124bd3 in mode_decision_for_I16x16_MB_RDO (currMB=0x8233210, lambda=570) at src/rd_intra_jm.c:490
#2  0x0812bbc1 in RDCost_for_macroblocks (currMB=0x8233210, lambda=570, mode=10) at src/rdopt.c:1875
#3  0x080f544c in compute_mode_RD_cost (currMB=0x8233210, enc_mb=0xbfffece8, mode=10, inter_skip=0xbfffec1e)at src/mode_decision.c:460
#4  0x080be440 in encode_one_macroblock_high (currMB=0x8233210) at src/md_high.c:289
#5  0x08149ea8 in encode_one_slice (p_Vid=0x81d0020, SliceGroupId=0, TotalCodedMBs=0) at src/slice.c:513
#6  0x0806cad2 in code_a_plane (p_Vid=0x81d0020, p_Inp=0x81e4c88) at src/image.c:223
#7  0x0806ce05 in code_a_picture (p_Vid=0x81d0020, pic=0x8365f58) at src/image.c:308
#8  0x08070903 in frame_picture (p_Vid=0x81d0020, frame=0x8365f58, imgData=0x81d00ec, rd_pass=0)at src/image.c:1665
#9  0x0806e578 in perform_encode_frame (p_Vid=0x81d0020) at src/image.c:820
#10 0x0806fbe2 in encode_one_frame (p_Vid=0x81d0020, p_Inp=0x81e4c88) at src/image.c:1302
#11 0x0808df12 in encode_sequence (p_Vid=0x81d0020, p_Inp=0x81e4c88) at src/lencod.c:1105
#12 0x0808bfdb in main (argc=1, argv=0xbffff174) at src/lencod.c:392

write_i_slice_MB_layer
writeIPCMData 写IPCM宏块到码流

CBP

CBP全称为Coded Block Pattern,指亮度和色度分量的各小块的残差的编码方案。H.264解码器中cbp变量(一个uint8_t类型变量)高4位存储了色度CBP,低4位存储了亮度CBP。色度CBP和亮度CBP的含义是不一样的:
亮度CBP数据从最低位开始,每1位对应1个子宏块,该位等于1时表明对应子宏块残差系数被传送。(因此亮度CBP数据通常需要当成二进制数据来看)
色度CBP包含3种取值:
0:代表所有残差都不被传送
1:只传送DC系数
2:传送DC系数以及AC系数
(因此色度CBP数据通常可以当成十进制数据来看)

JM使用

SliceMode             =  0   
# Slice mode (0=off 1=fixed mb in slice, 2=fixed bytes in slice,  3=use callback)

正如注释所说:
值为 0:表示不采用分片。也就是一个片组为一个片,如果不采用片组那么就是一幅图像为一个片。
值为 1:表示将每 SliceArgument 个宏块分为一个片;
值为 2:表示将每 SliceArgument 个字节分为一个片
值为 3:我也不知道是什么意思,猜测可能是根据解码器或者其他什么的反馈信息来确定。这样根据反馈信息可以更好适应不同网络环境下抗错能力。

SliceArgument         = 50   
# Slice argument (Arguments to modes 1 and 2 above)

encoder_ baseline.cfg, encoder_ extended.cfg, encoder_ main.cfg, encoder_ tonemapping.cfg, encoder_yuv422.cfg。它们里面的参数名都一样的,只是值不同。把其他一个文件拷贝成文件名 encoder.cfg。

缩写

ME: Motion Estimation 运动估计
qp/QP: quantization parameter 量化参数
RDOQ: rd optimization 率失真率
PSNR: Peak Signal to Noise Ratio 峰值信噪比 评价图像的客观标准
blk: block 块
idr/IDR: IDR帧
CBP: CodedBlockPattern 当前块的编码模式
POC: picture order count
CPB: coded picture buffer 保存编码图像的队列缓存区
用来反应该宏块编码中残差情况的语法元素。CBP每位都为0,表示没有残差要编码,不为0的位数越多表示要编码的残差越多。 用于表示当前宏块是否存在非零值
http://imeradio.blog.163.com/blog/static/153419404201011224714936/
DPB: decoded picture buffer,解码图片缓存区
在做视频解码时,需要将最近的若干幅参考帧缓存起来,这个缓冲区就叫做DPB。所以最大存储帧数也是最大参考帧数(ref)。DPB一般以宏块数为单位(DpbMbs),计算公式为——
DpbMbs = ref(参考帧数) * PicWidthInMbs(水平宏块数) * FrameHeightInMbs(垂直宏块数)
deblock: 去块滤波
FMO: 指灵活块映射,也即多片组模式。 REF: http://blog.csdn.net/newthinker_wei/article/details/8784754
RDO: Rate–distortion optimization 率失真优化
SSE: MMX/SSE/SSE2指令集对H.264解码器的关键算法进行优化
coef: 变换系数,残差值进行DCT变换之后得到。
SAE: 定义了每种预测的预测误差
PCM/DPCM: 预测编码[1] 中典型的压缩方法有脉冲编码调制(PCM,Pulse Code Modulation)、差分脉冲编码调制(DPCM,Differential Pulse Code Modulation)、自适应差分脉冲编码调制(ADPCM,Adaptive Differential Pulse Code Modulation)等
BS: Boundary Strength 边界强度,去块滤波过程中的。
UVLC: 通用可变长编码 熵编码
CABAC: 基于文本的自适应二进制算术编码 熵编码

问题

1、宏块编码长度
2、宏块编码数据

TIFF文件格式

标签图像文件格式(Tagged Image File Format,简写为TIFF) 是一种主要用来存储包括照片和艺术图在内的图像的文件格式。TIFF 是一个灵活适应性强的文件格式,通过在文件头中包含“标签”它能够在一个文件中处理多幅图像和数据。标签能够标明图像的如图像大小这样的基本几何尺寸或者定义图像数据是如何排列的并且是否使用了各种各样的图像压缩选项。

像素由多少位构成

Q:一幅图像存储容量为64KB,分辨率为256×128
整幅图是用64×1024×8=524288位二进制表示
每一个像素是用524288÷(256×128)=16位表示

C库函数

int access(const char *filenpath, int mode)
FILE * fopen(const char * path,const char * mode);
lseek()便是用来控制该文件的读写位置
int read(int handle, void *buf, int nbyte); nbyte:要读多少个字节,不能大于buffer指向的缓冲区
void *memcpy(void *dest, const void *src, size_t n);

gdb调试命令

bt / info stack 查看栈信息
list 查看源程序
list命令后面还可以更一些参数,来显示更多功能:
行号。
<+> [offset] 当前行号的正偏移量。
<-> [offset] 当前行号的负偏移量。
filename:linenum 文件的中的行行。
函数的代码
filename:function 文件中的函数。
<*address> 程序运行时的语句在内存中的地址。
print p 查看运行时数据

查看二位数组:
一个16*16的二维数组的第一行
p **currSlice->tblk16x16@16

	格式:print [</format>] <expr>例如:(gdb) p /x 3+2*5$19 = 0xdformat的取值范围有如下几种:x 按十六进制格式显示变量。d 按十进制格式显示变量。u 按十六进制格式显示无符号整型。o 按八进制格式显示变量。t 按二进制格式显示变量。a 按十六进制格式显示变量。c 按字符格式显示变量。f 按浮点数格式显示变量。

查看函数返回值

  • finish命令运行至函数结束,此时会打印函数返回值
  • 返回值会存储在eax寄存器中,p $eax

跳出循环:
until NUM 执行到一个比当前行号大的行,或者也可以指定在当前frame(我理解成函数)中的某一行
跳出函数:
finish 执行,直到选定的frame执行结束,然后打印返回值,将其放入历史值中,停止


请添加图片描述


http://chatgpt.dhexx.cn/article/yCgetvVl.shtml

相关文章

代码分析:

爬虫组件分析 目录概述需求&#xff1a; 设计思路实现思路分析1.URL管理 DataTable 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a better result,wait for change,chall…

推荐一款源代码统计分析、开发工作量估算、测试缺陷预测的开发工具 —— 代码统计分析工具(SourceCounter)

目录 一、软件简介 二、主要功能 三、更新日志 四、关键字 一、软件简介 代码统计分析工具 4.0&#xff0c;支持 30多种代码格式。能够统计包括&#xff1a;代码行数、注释、空行、文件大小等数据。另外&#xff0c;还支持对软件开发项目的各个开发阶段的工数、成本、质量…

恶意代码分析——基础技术篇

文章目录 恶意代码分析目的恶意代码分析方法恶意代码种类恶意代码静态分析环境在线反病毒引擎获取哈希值&#xff08;certutil-hanshfile path MD5&#xff09;查找字符串hive string ida火绒剑加壳&查壳文件加壳使用PEiD检测加壳 导入导出函数获取资源信息 常见的DLL程序恶…

Understand(代码分析工具)的安装与使用教程

前言 虽然自己一直都在CSDN上面学习相关知识和查找需要的各种资源&#xff0c;但或许是因为自己实在不知道自己的博客该写什么内容&#xff0c;于是博客的更新速度一慢再慢&#xff0c;进而停更一年左右&#xff0c;在这一点上&#xff0c;我认为自己应该作出批评与反省。 而…

如何看懂源代码--(分析源代码方法)

我们在写程序时&#xff0c;有不少时间都是在看别人的代码。 例如看小组的代码&#xff0c;看小组整合的守则&#xff0c;若一开始没规划怎么看&#xff0c; 就会“看得想哭 ” 不管是参考也好&#xff0c;从开源抓下来研究也好&#xff0c;为了了解箇中含意&#xff0c;在有限…

一文了解全面静态代码分析

在开发具有安全性、可靠性和合规性的软件时&#xff0c;全面静态代码分析是一种有效的方法。在这里&#xff0c;我们将就静态分析而言&#xff0c;讨论全面静态代码分析的不同之处&#xff0c;阐述全面静态代码分析的重要性&#xff0c;以及如何进行全面静态代码分析。 什么是全…

代码分析工具 - SonarQube

1. 常见代码质量分析工具 SonarQube&#xff1a;可以分析27多种不同编程语言中的代码&#xff0c;并帮助您提高性能和检测安全漏洞。它由SonarSource的团队开发&#xff0c;对社区免费开源。SonarQube可以添加到您的CI/CD管道中&#xff0c;或者与您选择的代码库托管平台集成&a…

《编码 - 代码分析》代码结构分析

1 代码结构分析概述 在编写代码时&#xff0c;要求要结构清晰、接口简单。如果代码结构过于复杂&#xff0c;会带来很多问题&#xff1a;代码很难被理解&#xff0c;不方便编写测试用例&#xff0c;容易隐藏错误&#xff0c;出现问题难以定位&#xff0c;修改代码容易产生新的…

利用宏让ERStudio生成代码文件

Embarcadero ERStudio 是一个数据模型工具&#xff0c;用起来很方便。在ERStudio里建完数据模型后&#xff0c;可以利用宏来帮助生成对应的实体类文件以及对应的简单的数据访问类文件。为了实现这一目的&#xff0c;需要自己写脚本&#xff0c;支持的语言为 VB&#xff08;以前…

Erstudio8.0怎么用?Erstudio8.0汉化版详细使用教程

Erstudio8.0使用教程 打开ERstudio,点击新建出现如图对话框&#xff1a; 选择第一个&#xff0c;表示创建一个新的关系型 数据库模型 这里提一点数据库模型分为relational(关系)和dimensional(多维) 两种在这里主要以关系型数据库为主来介绍模型的创建过程。 第二和第三项均是重…

ERStudio如何显示entity的tableName(表名的英文)和defaultColumnName(英文字段名)

转换为物理模型就可以了 物理模型中会优先显示tableName和defaultColumnName 这个mysql选择自己使用的数据库即可&#xff0c; ** 温馨提示&#xff1a;只想单纯看一下英文名而且不会转物理模型的话可以参考我的这个步骤&#xff0c;专业转化物理模型的话&#xff0c;建议另…

【SpringBoot】4. ERStudio初使用

1. 逻辑结构 &#xff08;1&#xff09;创建文件 &#xff08;2&#xff09;建立实体对象entity &#xff08;3&#xff09;编辑实体对象 &#xff08;4&#xff09;添加属性 &#xff08;5&#xff09;图表显示选项 &#xff08;6&#xff09;实体之间建立联系 &#xff08;7…

如何使用ERStudio 生成comment

在ER使用中&#xff0c;在生成sql过程中&#xff0c;如何批量生成字段描述&#xff0c;如何批量添加Owner&#xff0c;请看下文&#xff1a; 1、ER生成字段描述 2、ER生成描述添加Owner 使用的ER版本是8.0&#xff0c;英文版本&#xff0c;在操作过程中&#xff0c;有些配置细节…

使用ERStudio6创建数据表ER图并导出数据表的SQL(DDL)语句

1.创建数据表实体 打开ERStudio软件&#xff0c;其界面如下&#xff1a; 点击File菜单的NEW或则使用快捷键“CtrlN”着按钮 来新建一个ER图文件&#xff0c;按下OK按钮即可打开一个空白的ER图文件 其后缀是.DM1类型的。新建一个ER文件后&#xff0c;ERStudio的工具栏内的许多按…

ER/Studio知识汇总

一、关系 网上找了一下&#xff0c;大部分说得不太清楚&#xff0c;我在这里举上个例子。注意&#xff0c;这里的关系是逻辑上的&#xff0c;并非表结构也要如此。 1. 标识关系identifying relationship 意思&#xff1a;子实体的主键包含父实体的外键&#xff08;可能成为复合…

【NodeJS】20 koa 企业级Cms内容管理系统-XMind功能分析、ERStudio设计数据库ER图

一、 什么是 CMS CMS 是"Content Management System“的缩写&#xff0c;意为"内容管理系统”。 内容管理系统是企业信息化建设和电子政务的新宠&#xff0c;也是一个相对较新的市场。对于内容管理&#xff0c;业界还没有一个统一的定义&#xff0c;不同的机构有不同…

ER-studio显示选项设置

新建erstudio文件&#xff0c;默认不显示entity的datatype&#xff0c;用起来不方便。 设置如下&#xff1a; 当前页面->右键选择 Diagram And object Display Options->Entity->Datatype(勾选即可)。效果如上图

(10)ERStudio

1.外键 https://jingyan.baidu.com/article/f79b7cb37e9d219144023ea6.html 第一个图标&#xff1a;Identifying Relationship。 一对多的关联&#xff0c;主表的主键既是子表的外键也是子表的主键 第二个图标&#xff1a;Non-Identifying, Mandatory Relationship。 一对多的关…

ERStudio逆向工程生成ER模型

首先&#xff0c;打开ERStudio&#xff0c;如下图所示&#xff1a; 然后&#xff0c;点击菜单栏上的“File”——“New”&#xff0c;如下图所示&#xff1a; 弹出如下的对话框&#xff0c;选择第二个单选按钮 接着&#xff0c;点击“Login”按钮&#xff0c;弹出如下的对话框&…

使用ERStudio创建数据表与ER图

下面以一个教育网站的用户数据表来举例说明ERStudio的一些基本操作方法&#xff1a; 1.创建数据表实体 打开ERStudio软件&#xff0c;其界面如下&#xff1a; 点击File菜单的NEW或则使用快捷键“CtrlN”着按钮来新建一个ER图文件&#xff0c;按下OK按钮即可打开一个空白的ER图文…