Download presentation
Presentation is loading. Please wait.
Published byLynne Boyd Modified over 8 years ago
1
x.264 Code Tracing Group 1 9562241 薛伊倩 9562314 張書瑜 9562134 游智詮 9562138 邱漢坤 9562208 王芳瑜 9562308 張宇蓓 9562336 廖航緯
2
Code segment x264_reduce_fraction select_input select_output x264_param_apply_fastfirstpass x264_param_parse main Encode parse_qpfile Print_status x264_encoder_headers x264_encoder_close x264_encoder_open Parse x264_param_default x264_param_apply_profile Encode_frame x264_dct_init_weights x264_init_vlc_tables x264_rdo_init x264_set_aspect_ratio x264_sps_init x264_pps_init x264_validate_levels x264_cqm_init x264_validate_parameters x264_cqm_parse_file x264_analyse_init_costs x264_lookahead_init x264_macroblock_cache_init x264_ratecontrol_new x264_slurp_file x264_cqm_parse_jmlist x264_ratecontrol_init_reconfigurble parse_zones init_pass2
3
outline Main Encode X264_encoder_headers Parse_qpfile Encode_frame Print_status
4
main() Target Parse command line & encode input file Input Command line Output File Location x264.c Caller none
5
main() 流程圖 Parse command line Start encode int main( int argc, char **argv ){ x264_param_t param; cli_opt_t opt; int ret; … /* Parse command line */ if( Parse( argc, argv, ¶m, &opt ) < 0 ) return -1; … /*start to encode*/ ret = Encode( ¶m, &opt ); return ret; } int main( int argc, char **argv ){ x264_param_t param; cli_opt_t opt; int ret; … /* Parse command line */ if( Parse( argc, argv, ¶m, &opt ) < 0 ) return -1; … /*start to encode*/ ret = Encode( ¶m, &opt ); return ret; }
6
Encode() Target encode Input *param, *opt Output 0 / -1 File Location x264.c Caller main()
7
Encode() static int Encode( x264_param_t *param, cli_opt_t *opt ) { … /* 得到 frame 數 */ opt->b_progress &= param->i_log_level < X264_LOG_DEBUG; i_frame_total = input.get_frame_total( opt->hin ); // 所有的 frame i_frame_total = X264_MAX( i_frame_total - opt->i_seek, 0 ) /*param->i_frame_total 為 user 給的最大編碼 frame# ,若此數 >0 且 i_frame_total=0 或大於此數, i_frame_total 就設為 param->i_frame_total*/ if( ( i_frame_total == 0 || param->i_frame_total i_frame_total > 0 ) i_frame_total = param->i_frame_total; param->i_frame_total = i_frame_total; …… /* 算 i_update_interval, 範圍是 1~10 */ i_update_interval = i_frame_total ? x264_clip3( i_frame_total / 1000, 1, 10 ) : 10; …… /* x264_encoder_open : create a new encoder handler, all parameters from x264_param_t are 各結構體參數、編碼、預測等需要的參數 (h) 初始化 )*/ if( ( h = x264_encoder_open( param ) ) == NULL ) { …} …… if( input.picture_alloc( &pic, param->i_csp, param->i_width, param->i_height ) ) {……} static int Encode( x264_param_t *param, cli_opt_t *opt ) { … /* 得到 frame 數 */ opt->b_progress &= param->i_log_level < X264_LOG_DEBUG; i_frame_total = input.get_frame_total( opt->hin ); // 所有的 frame i_frame_total = X264_MAX( i_frame_total - opt->i_seek, 0 ) /*param->i_frame_total 為 user 給的最大編碼 frame# ,若此數 >0 且 i_frame_total=0 或大於此數, i_frame_total 就設為 param->i_frame_total*/ if( ( i_frame_total == 0 || param->i_frame_total i_frame_total > 0 ) i_frame_total = param->i_frame_total; param->i_frame_total = i_frame_total; …… /* 算 i_update_interval, 範圍是 1~10 */ i_update_interval = i_frame_total ? x264_clip3( i_frame_total / 1000, 1, 10 ) : 10; …… /* x264_encoder_open : create a new encoder handler, all parameters from x264_param_t are 各結構體參數、編碼、預測等需要的參數 (h) 初始化 )*/ if( ( h = x264_encoder_open( param ) ) == NULL ) { …} …… if( input.picture_alloc( &pic, param->i_csp, param->i_width, param->i_height ) ) {……} Get frame # Update interval X264_encoder_open() Create a new pic
8
Encode() if( !param->b_repeat_headers ) { // Write SPS/PPS/SEI x264_nal_t *headers; int i_nal; if( x264_encoder_headers( h, &headers, &i_nal ) < 0 ) { ……} // write header if( (i_file = output.write_headers( opt->hout, headers )) < 0 ) return -1; } if( !param->b_repeat_headers ) { // Write SPS/PPS/SEI x264_nal_t *headers; int i_nal; if( x264_encoder_headers( h, &headers, &i_nal ) < 0 ) { ……} // write header if( (i_file = output.write_headers( opt->hout, headers )) < 0 ) return -1; } b_repeat_headers x264_encoder_headers() F Input.read_frame() T for( i_frame = 0, i_frame_output = 0; b_ctrl_c == 0 && (i_frame < i_frame_total || i_frame_total == 0); ) { //read frame if( input.read_frame( &pic, opt->hin, i_frame + opt->i_seek ) ) break; …… if( opt->qpfile ) parse_qpfile( opt, &pic, i_frame + opt->i_seek ); else { /* Do not force any parameters */ pic.i_type = X264_TYPE_AUTO; pic.i_qpplus1 = 0; } for( i_frame = 0, i_frame_output = 0; b_ctrl_c == 0 && (i_frame < i_frame_total || i_frame_total == 0); ) { //read frame if( input.read_frame( &pic, opt->hin, i_frame + opt->i_seek ) ) break; …… if( opt->qpfile ) parse_qpfile( opt, &pic, i_frame + opt->i_seek ); else { /* Do not force any parameters */ pic.i_type = X264_TYPE_AUTO; pic.i_qpplus1 = 0; } opt->qpfile parse_qpfile() Frametype = AUTO Qpplus1=0 F T For all frames
9
Encode() i_frame_size = Encode_frame( h, opt->hout, &pic, &last_pts ); …… if( opt->b_progress && i_frame_output % i_update_interval == 0 &&i_frame_output ) Print_status( i_start, i_frame_output, i_frame_total, i_file, param, last_pts ); } // end for i_frame_size = Encode_frame( h, opt->hout, &pic, &last_pts ); …… if( opt->b_progress && i_frame_output % i_update_interval == 0 &&i_frame_output ) Print_status( i_start, i_frame_output, i_frame_total, i_file, param, last_pts ); } // end for Encode_frame() Update status? Print_status() T while( !b_ctrl_c && x264_encoder_delayed_frames( h ) ) { i_frame_size = Encode_frame( h, opt->hout, NULL, &last_pts ); …… if( opt->b_progress && i_frame_output % i_update_interval == 0 && i_frame_output ) Print_status( i_start, i_frame_output, i_frame_total, i_file, param, last_pts ); } // end while while( !b_ctrl_c && x264_encoder_delayed_frames( h ) ) { i_frame_size = Encode_frame( h, opt->hout, NULL, &last_pts ); …… if( opt->b_progress && i_frame_output % i_update_interval == 0 && i_frame_output ) Print_status( i_start, i_frame_output, i_frame_total, i_file, param, last_pts ); } // end while x264_encoder_close() Flush all delayed frames i_end = x264_mdate(); input.picture_clean( &pic ); /* Erase progress indicator before printing encoding stats. */ if( opt->b_progress ) fprintf( stderr, " \r" ); x264_encoder_close( h ); //free mem …… input.close_file( opt->hin ); output.close_file( opt->hout, largest_pts, second_largest_pts ); i_end = x264_mdate(); input.picture_clean( &pic ); /* Erase progress indicator before printing encoding stats. */ if( opt->b_progress ) fprintf( stderr, " \r" ); x264_encoder_close( h ); //free mem …… input.close_file( opt->hin ); output.close_file( opt->hout, largest_pts, second_largest_pts ); I B B B P B B B P
10
x264_encoder_headers() Target return the SPS(sequence parameter set) and PPS( picture parameter set ) that will be used for the whole stream Input *h, **pp_nal, *pi_nal : Output framesize File Location encoder.c Caller Encode()
11
x264_encoder_headers() int x264_encoder_headers( x264_t *h, x264_nal_t **pp_nal, int *pi_nal ) { int frame_size = 0; /* init bitstream context */ h->out.i_nal = 0; bs_init( &h->out.bs, h->out.p_bitstream, h->out.i_bitstream ); /* Write SEI, SPS and PPS. */ x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); if( x264_sei_version_write( h, &h->out.bs ) ) return -1; // 把 x264 版本寫到 output if( x264_nal_end( h ) ) return -1; /* generate sequence parameters */ x264_nal_start( h, NAL_SPS, NAL_PRIORITY_HIGHEST ); x264_sps_write( &h->out.bs, h->sps ); // 把 sps 寫到 output if( x264_nal_end( h ) ) return -1; /* generate picture parameters */ x264_nal_start( h, NAL_PPS, NAL_PRIORITY_HIGHEST ); x264_pps_write( &h->out.bs, h->pps ); // 把 pps 寫到 output if( x264_nal_end( h ) ) return -1; frame_size = x264_encoder_encapsulate_nals( h );// 封裝 nal /* now set output*/ *pi_nal = h->out.i_nal; *pp_nal = &h->out.nal[0]; h->out.i_nal = 0; return frame_size; } int x264_encoder_headers( x264_t *h, x264_nal_t **pp_nal, int *pi_nal ) { int frame_size = 0; /* init bitstream context */ h->out.i_nal = 0; bs_init( &h->out.bs, h->out.p_bitstream, h->out.i_bitstream ); /* Write SEI, SPS and PPS. */ x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); if( x264_sei_version_write( h, &h->out.bs ) ) return -1; // 把 x264 版本寫到 output if( x264_nal_end( h ) ) return -1; /* generate sequence parameters */ x264_nal_start( h, NAL_SPS, NAL_PRIORITY_HIGHEST ); x264_sps_write( &h->out.bs, h->sps ); // 把 sps 寫到 output if( x264_nal_end( h ) ) return -1; /* generate picture parameters */ x264_nal_start( h, NAL_PPS, NAL_PRIORITY_HIGHEST ); x264_pps_write( &h->out.bs, h->pps ); // 把 pps 寫到 output if( x264_nal_end( h ) ) return -1; frame_size = x264_encoder_encapsulate_nals( h );// 封裝 nal /* now set output*/ *pi_nal = h->out.i_nal; *pp_nal = &h->out.nal[0]; h->out.i_nal = 0; return frame_size; } initial Write SEIWrite SPSWrite PPS Encapsulate nal Set output
12
parse_qpfile() Target Parse qpfile to set frametype and QP Input *opt, *pic, i_frame Output pic->i-type, pic->i_qpplus1 File Location x264.c Caller Encode()
13
parse_qpfile() format 1 P 20 framenum frametype quantizer Frametype IIDR (key) I-frame PP-frame BReferenced B-frame iNon-IDR (non-key) I-frame bNon-referenced B-frame When only need to set frametype, using -1 as desired quantizer allows x264 to choose the optimal quantizer value
14
parse_qpfile() code static void parse_qpfile( cli_opt_t *opt, x264_picture_t *pic, int i_frame ) { … while( num < i_frame ) { file_pos = ftell( opt->qpfile ); // 記住現在檔案讀寫的位置 ret = fscanf( opt->qpfile, "%d %c %d\n", &num, &type, &qpframe); // ret 是指共讀到幾個變數 if( num > i_frame || ret == EOF) { // 要 qpfile 目前的 frame# 在現在要 encode 的 frame 後面 pic->i_type = X264_TYPE_AUTO; pic->i_qpplus1 = 0; // 設 AUTO fseek( opt->qpfile, file_pos, SEEK_SET ); // 把讀寫位置設為之前記下的位置 file_pos break; } if( num < i_frame && ret == 3 ) continue; pic->i_qpplus1 = qp+1; if ( type == 'I' ) pic->i_type = X264_TYPE_IDR; else if( type == 'i' ) pic->i_type = X264_TYPE_I; … else ret = 0; if( ret != 3 || qp 51 ) { // 格式不對,全部設自動, opt->qpfile = NULL 表示之後不再參考 qpfile …;fclose( opt->qpfile ); opt->qpfile = NULL; pic->i_type = X264_TYPE_AUTO; pic->i_qpplus1 = 0; break; } }} static void parse_qpfile( cli_opt_t *opt, x264_picture_t *pic, int i_frame ) { … while( num < i_frame ) { file_pos = ftell( opt->qpfile ); // 記住現在檔案讀寫的位置 ret = fscanf( opt->qpfile, "%d %c %d\n", &num, &type, &qpframe); // ret 是指共讀到幾個變數 if( num > i_frame || ret == EOF) { // 要 qpfile 目前的 frame# 在現在要 encode 的 frame 後面 pic->i_type = X264_TYPE_AUTO; pic->i_qpplus1 = 0; // 設 AUTO fseek( opt->qpfile, file_pos, SEEK_SET ); // 把讀寫位置設為之前記下的位置 file_pos break; } if( num < i_frame && ret == 3 ) continue; pic->i_qpplus1 = qp+1; if ( type == 'I' ) pic->i_type = X264_TYPE_IDR; else if( type == 'i' ) pic->i_type = X264_TYPE_I; … else ret = 0; if( ret != 3 || qp 51 ) { // 格式不對,全部設自動, opt->qpfile = NULL 表示之後不再參考 qpfile …;fclose( opt->qpfile ); opt->qpfile = NULL; pic->i_type = X264_TYPE_AUTO; pic->i_qpplus1 = 0; break; } }} 根據 qpfile 設定 frametype 和 QP 若是 frametype 格式錯誤,將 ret=0
15
parse_qpfile() 流程圖
16
Encode_frame() Target Encode a frame and write the encoded result to output Input *h, hout, *pic Output i_frame_size File Location x264.c Caller Encode()
17
Encode_frame() static int Encode_frame( x264_t *h, hnd_t hout, x264_picture_t *pic, int64_t *last_pts ) { x264_picture_t pic_out; x264_nal_t *nal; int i_nal; int i_frame_size = 0; // x264_encoder_encode -> encode i_frame_size = x264_encoder_encode( h, &nal, &i_nal, pic, &pic_out ); // frame size error if( i_frame_size < 0 ) { fprintf( stderr, "x264 [error]: x264_encoder_encode failed\n" ); return -1; } // frame size > 0 ---> write frame if( i_frame_size ) { i_frame_size = output.write_frame( hout, nal[0].p_payload, i_frame_size, &pic_out ); *last_pts = pic_out.i_pts; } return i_frame_size;} static int Encode_frame( x264_t *h, hnd_t hout, x264_picture_t *pic, int64_t *last_pts ) { x264_picture_t pic_out; x264_nal_t *nal; int i_nal; int i_frame_size = 0; // x264_encoder_encode -> encode i_frame_size = x264_encoder_encode( h, &nal, &i_nal, pic, &pic_out ); // frame size error if( i_frame_size < 0 ) { fprintf( stderr, "x264 [error]: x264_encoder_encode failed\n" ); return -1; } // frame size > 0 ---> write frame if( i_frame_size ) { i_frame_size = output.write_frame( hout, nal[0].p_payload, i_frame_size, &pic_out ); *last_pts = pic_out.i_pts; } return i_frame_size;} X264_encoder_encode()Output.write_frame
18
Print_status() Target Count fps and bitrate then print them Input i_start ( 開始 encode 的時間 ), i_frame, i_frame_total, i_file, *param, last_pts Output none File Location x264.c Caller Encode()
19
print_status() 流程圖 static void Print_status( int64_t i_start, int i_frame, …… ){ … int64_t i_elapsed = x264_mdate() - i_start; // 目前為止經過的時間 double fps = i_elapsed > 0 ? i_frame * 1000000. / i_elapsed : 0; // 算 frame per second double bitrate = (double) i_file * 8 / ( (double) last_pts * 1000 * param->i_timebase_num / param- >i_timebase_den ); if( i_frame_total ) { int eta = i_elapsed * (i_frame_total - i_frame) / ((int64_t)i_frame * 1000000); sprintf( buf, "x264 [%.1f%] %d/%d frames, %.2f fps, %.2f kb/s, eta %d:%02d:%02d", 100. * i_frame / i_frame_total, i_frame, i_frame_total, fps, bitrate, eta/3600, (eta/60)%60, eta%60 ); } else {sprintf( buf, "x264 %d frames: %.2f fps, %.2f kb/s", i_frame, fps, bitrate ); } fprintf( stderr, "%s \r", buf+5 ); … } static void Print_status( int64_t i_start, int i_frame, …… ){ … int64_t i_elapsed = x264_mdate() - i_start; // 目前為止經過的時間 double fps = i_elapsed > 0 ? i_frame * 1000000. / i_elapsed : 0; // 算 frame per second double bitrate = (double) i_file * 8 / ( (double) last_pts * 1000 * param->i_timebase_num / param- >i_timebase_den ); if( i_frame_total ) { int eta = i_elapsed * (i_frame_total - i_frame) / ((int64_t)i_frame * 1000000); sprintf( buf, "x264 [%.1f%] %d/%d frames, %.2f fps, %.2f kb/s, eta %d:%02d:%02d", 100. * i_frame / i_frame_total, i_frame, i_frame_total, fps, bitrate, eta/3600, (eta/60)%60, eta%60 ); } else {sprintf( buf, "x264 %d frames: %.2f fps, %.2f kb/s", i_frame, fps, bitrate ); } fprintf( stderr, "%s \r", buf+5 ); … } fpsbitrateprint X264 [20.0%] 2/10 frames, 1.12fps, 2.18kb/s, eta 00:02:45 x264 1 frames: 1.21fps, 3.36kb/s
20
Thank you
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.