x264代码剖析(八):encode()函数之x264_encoder_close()函数
encode()函数是x264的主干函数。主要包含x264_encoder_open()函数、x264_encoder_headers()函数、x264_encoder_encode()函数与x264_encoder_close()函数四大部分,当中x264_encoder_encode()函数是其核心部分,详细的H.264视频编码算法均在此模块。
上三篇博文主要分析了x264_encoder_open()函数、x264_encoder_headers()函数与x264_encoder_encode()函数(兴许会继续深入)。本文主要学习x264_encoder_close()函数。
x264_encoder_close()是libx264的一个API函数。该函数用于关闭编码器,同一时候输出一些统计信息。例如以下图所看到的,调用了下面函数:
x264_lookahead_delete():释放Lookahead相关的变量。
x264_ratecontrol_summary():汇总码率控制信息。
x264_ratecontrol_delete():关闭码率控制。
相应的代码例如以下:
/******************************************************************/ /******************************************************************/ /* ======Analysed by RuiDong Fang ======Csdn Blog:http://blog.csdn.net/frd2009041510 ======Date:2016.03.10 */ /******************************************************************/ /******************************************************************/ /************====== x264_encoder_close()函数 ======************/ /* 功能:关闭编码器,同一时候输出一些统计信息。 */ /**************************************************************************** * x264_encoder_close: ****************************************************************************/ void x264_encoder_close ( x264_t *h ) { int64_t i_yuv_size = FRAME_SIZE( h->param.i_width * h->param.i_height ); int64_t i_mb_count_size[2][7] = {{0}}; char buf[200]; int b_print_pcm = h->stat.i_mb_count[SLICE_TYPE_I][I_PCM] || h->stat.i_mb_count[SLICE_TYPE_P][I_PCM] || h->stat.i_mb_count[SLICE_TYPE_B][I_PCM]; x264_lookahead_delete( h ); ////////////////////////释放lookahead相关的变量 #if HAVE_OPENCL x264_opencl_lookahead_delete( h ); x264_opencl_function_t *ocl = h->opencl.ocl; #endif if( h->param.b_sliced_threads ) x264_threadpool_wait_all( h ); if( h->param.i_threads > 1 ) x264_threadpool_delete( h->threadpool ); if( h->param.i_lookahead_threads > 1 ) x264_threadpool_delete( h->lookaheadpool ); if( h->i_thread_frames > 1 ) { for( int i = 0; i < h->i_thread_frames; i++ ) if( h->thread[i]->b_thread_active ) { assert( h->thread[i]->fenc->i_reference_count == 1 ); x264_frame_delete( h->thread[i]->fenc ); } x264_t *thread_prev = h->thread[h->i_thread_phase]; x264_thread_sync_ratecontrol( h, thread_prev, h ); x264_thread_sync_ratecontrol( thread_prev, thread_prev, h ); h->i_frame = thread_prev->i_frame + 1 - h->i_thread_frames; } h->i_frame++; /* Slices used and PSNR */ /* 演示样例 * x264 [info]: frame I:2 Avg QP:20.51 size: 20184 PSNR Mean Y:45.32 U:47.54 V:47.62 Avg:45.94 Global:45.52 * x264 [info]: frame P:33 Avg QP:23.08 size: 3230 PSNR Mean Y:43.23 U:47.06 V:46.87 Avg:44.15 Global:44.00 * x264 [info]: frame B:65 Avg QP:27.87 size: 352 PSNR Mean Y:42.76 U:47.21 V:47.05 Avg:43.79 Global:43.65 */ for( int i = 0; i < 3; i++ ) { static const uint8_t slice_order[] = { SLICE_TYPE_I, SLICE_TYPE_P, SLICE_TYPE_B }; int i_slice = slice_order[i]; if( h->stat.i_frame_count[i_slice] > 0 ) { int i_count = h->stat.i_frame_count[i_slice]; double dur = h->stat.f_frame_duration[i_slice]; if( h->param.analyse.b_psnr ) { //输出统计信息-包括PSNR //注意PSNR都是通过SSD换算过来的,换算方法就是调用x264_psnr()方法 x264_log( h, X264_LOG_INFO, "frame %c:%-5d Avg QP:%5.2f size:%6.0f PSNR Mean Y:%5.2f U:%5.2f V:%5.2f Avg:%5.2f Global:%5.2f\n", slice_type_to_char[i_slice], i_count, h->stat.f_frame_qp[i_slice] / i_count, (double)h->stat.i_frame_size[i_slice] / i_count, h->stat.f_psnr_mean_y[i_slice] / dur, h->stat.f_psnr_mean_u[i_slice] / dur, h->stat.f_psnr_mean_v[i_slice] / dur, h->stat.f_psnr_average[i_slice] / dur, x264_psnr( h->stat.f_ssd_global[i_slice], dur * i_yuv_size ) ); } else { //输出统计信息-不包括PSNR x264_log( h, X264_LOG_INFO, "frame %c:%-5d Avg QP:%5.2f size:%6.0f\n", slice_type_to_char[i_slice], i_count, h->stat.f_frame_qp[i_slice] / i_count, (double)h->stat.i_frame_size[i_slice] / i_count ); } } } /* 演示样例 * x264 [info]: consecutive B-frames: 3.0% 10.0% 63.0% 24.0% * */ if( h->param.i_bframe && h->stat.i_frame_count[SLICE_TYPE_B] ) { //B帧相关信息 char *p = buf; int den = 0; // weight by number of frames (including the I/P-frames) that are in a sequence of N B-frames for( int i = 0; i <= h->param.i_bframe; i++ ) den += (i+1) * h->stat.i_consecutive_bframes[i]; for( int i = 0; i <= h->param.i_bframe; i++ ) p += sprintf( p, " %4.1f%%", 100. * (i+1) * h->stat.i_consecutive_bframes[i] / den ); x264_log( h, X264_LOG_INFO, "consecutive B-frames:%s\n", buf ); } for( int i_type = 0; i_type < 2; i_type++ ) for( int i = 0; i < X264_PARTTYPE_MAX; i++ ) { if( i == D_DIRECT_8x8 ) continue; /* direct is counted as its own type */ i_mb_count_size[i_type][x264_mb_partition_pixel_table[i]] += h->stat.i_mb_partition[i_type][i]; } /* MB types used */ /* 演示样例 * x264 [info]: mb I I16..4: 15.3% 37.5% 47.3% * x264 [info]: mb P I16..4: 0.6% 0.4% 0.2% P16..4: 34.6% 21.2% 12.7% 0.0% 0.0% skip:30.4% * x264 [info]: mb B I16..4: 0.0% 0.0% 0.0% B16..8: 21.2% 4.1% 0.7% direct: 0.8% skip:73.1% L0:28.7% L1:53.0% BI:18.3% */ if( h->stat.i_frame_count[SLICE_TYPE_I] > 0 ) { int64_t *i_mb_count = h->stat.i_mb_count[SLICE_TYPE_I]; double i_count = (double)h->stat.i_frame_count[SLICE_TYPE_I] * h->mb.i_mb_count / 100.0; //Intra宏块信息-存于buf //从左到右3个信息,依次为I16x16,I8x8,I4x4 x264_print_intra( i_mb_count, i_count, b_print_pcm, buf ); x264_log( h, X264_LOG_INFO, "mb I %s\n", buf ); } if( h->stat.i_frame_count[SLICE_TYPE_P] > 0 ) { int64_t *i_mb_count = h->stat.i_mb_count[SLICE_TYPE_P]; double i_count = (double)h->stat.i_frame_count[SLICE_TYPE_P] * h->mb.i_mb_count / 100.0; int64_t *i_mb_size = i_mb_count_size[SLICE_TYPE_P]; x264_print_intra( i_mb_count, i_count, b_print_pcm, buf );//Intra宏块信息-存于buf //Intra宏块信息-放在最前面 //后面加入P宏块信息 //从左到右6个信息,依次为P16x16, P16x8+P8x16, P8x8, P8x4+P4x8, P4x4, PSKIP x264_log( h, X264_LOG_INFO, "mb P %s P16..4: %4.1f%% %4.1f%% %4.1f%% %4.1f%% %4.1f%% skip:%4.1f%%\n", buf, i_mb_size[PIXEL_16x16] / (i_count*4), (i_mb_size[PIXEL_16x8] + i_mb_size[PIXEL_8x16]) / (i_count*4), i_mb_size[PIXEL_8x8] / (i_count*4), (i_mb_size[PIXEL_8x4] + i_mb_size[PIXEL_4x8]) / (i_count*4), i_mb_size[PIXEL_4x4] / (i_count*4), i_mb_count[P_SKIP] / i_count ); } if( h->stat.i_frame_count[SLICE_TYPE_B] > 0 ) { int64_t *i_mb_count = h->stat.i_mb_count[SLICE_TYPE_B]; double i_count = (double)h->stat.i_frame_count[SLICE_TYPE_B] * h->mb.i_mb_count / 100.0; double i_mb_list_count; int64_t *i_mb_size = i_mb_count_size[SLICE_TYPE_B]; int64_t list_count[3] = {0}; /* 0 == L0, 1 == L1, 2 == BI */ x264_print_intra( i_mb_count, i_count, b_print_pcm, buf );//Intra宏块信息 for( int i = 0; i < X264_PARTTYPE_MAX; i++ ) for( int j = 0; j < 2; j++ ) { int l0 = x264_mb_type_list_table[i][0][j]; int l1 = x264_mb_type_list_table[i][1][j]; if( l0 || l1 ) list_count[l1+l0*l1] += h->stat.i_mb_count[SLICE_TYPE_B][i] * 2; } list_count[0] += h->stat.i_mb_partition[SLICE_TYPE_B][D_L0_8x8]; list_count[1] += h->stat.i_mb_partition[SLICE_TYPE_B][D_L1_8x8]; list_count[2] += h->stat.i_mb_partition[SLICE_TYPE_B][D_BI_8x8]; i_mb_count[B_DIRECT] += (h->stat.i_mb_partition[SLICE_TYPE_B][D_DIRECT_8x8]+2)/4; i_mb_list_count = (list_count[0] + list_count[1] + list_count[2]) / 100.0; //Intra宏块信息-放在最前面 //后面加入B宏块信息 //从左到右5个信息。依次为B16x16, B16x8+B8x16, B8x8, BDIRECT, BSKIP // //SKIP和DIRECT差别 //P_SKIP的CBP为0,无像素残差,无运动矢量残 //B_SKIP宏块的模式为B_DIRECT且CBP为0,无像素残差,无运动矢量残 //B_DIRECT的CBP不为0,有像素残差,无运动矢量残 sprintf( buf + strlen(buf), " B16..8: %4.1f%% %4.1f%% %4.1f%% direct:%4.1f%% skip:%4.1f%%", i_mb_size[PIXEL_16x16] / (i_count*4), (i_mb_size[PIXEL_16x8] + i_mb_size[PIXEL_8x16]) / (i_count*4), i_mb_size[PIXEL_8x8] / (i_count*4), i_mb_count[B_DIRECT] / i_count, i_mb_count[B_SKIP] / i_count ); if( i_mb_list_count != 0 ) sprintf( buf + strlen(buf), " L0:%4.1f%% L1:%4.1f%% BI:%4.1f%%", list_count[0] / i_mb_list_count, list_count[1] / i_mb_list_count, list_count[2] / i_mb_list_count ); x264_log( h, X264_LOG_INFO, "mb B %s\n", buf ); } x264_ratecontrol_summary( h ); ////////////////////////汇总码率控制信息 if( h->stat.i_frame_count[SLICE_TYPE_I] + h->stat.i_frame_count[SLICE_TYPE_P] + h->stat.i_frame_count[SLICE_TYPE_B] > 0 ) { #define SUM3(p) (p[SLICE_TYPE_I] + p[SLICE_TYPE_P] + p[SLICE_TYPE_B]) #define SUM3b(p,o) (p[SLICE_TYPE_I][o] + p[SLICE_TYPE_P][o] + p[SLICE_TYPE_B][o]) int64_t i_i8x8 = SUM3b( h->stat.i_mb_count, I_8x8 ); int64_t i_intra = i_i8x8 + SUM3b( h->stat.i_mb_count, I_4x4 ) + SUM3b( h->stat.i_mb_count, I_16x16 ); int64_t i_all_intra = i_intra + SUM3b( h->stat.i_mb_count, I_PCM); int64_t i_skip = SUM3b( h->stat.i_mb_count, P_SKIP ) + SUM3b( h->stat.i_mb_count, B_SKIP ); const int i_count = h->stat.i_frame_count[SLICE_TYPE_I] + h->stat.i_frame_count[SLICE_TYPE_P] + h->stat.i_frame_count[SLICE_TYPE_B]; int64_t i_mb_count = (int64_t)i_count * h->mb.i_mb_count; int64_t i_inter = i_mb_count - i_skip - i_intra; const double duration = h->stat.f_frame_duration[SLICE_TYPE_I] + h->stat.f_frame_duration[SLICE_TYPE_P] + h->stat.f_frame_duration[SLICE_TYPE_B]; float f_bitrate = SUM3(h->stat.i_frame_size) / duration / 125; if( PARAM_INTERLACED )//隔行 { char *fieldstats = buf; fieldstats[0] = 0; if( i_inter ) fieldstats += sprintf( fieldstats, " inter:%.1f%%", h->stat.i_mb_field[1] * 100.0 / i_inter ); if( i_skip ) fieldstats += sprintf( fieldstats, " skip:%.1f%%", h->stat.i_mb_field[2] * 100.0 / i_skip ); x264_log( h, X264_LOG_INFO, "field mbs: intra: %.1f%%%s\n", h->stat.i_mb_field[0] * 100.0 / i_intra, buf ); } if( h->pps->b_transform_8x8_mode )//8x8DCT信息 { buf[0] = 0; if( h->stat.i_mb_count_8x8dct[0] ) sprintf( buf, " inter:%.1f%%", 100. * h->stat.i_mb_count_8x8dct[1] / h->stat.i_mb_count_8x8dct[0] ); x264_log( h, X264_LOG_INFO, "8x8 transform intra:%.1f%%%s\n", 100. * i_i8x8 / i_intra, buf ); } if( (h->param.analyse.i_direct_mv_pred == X264_DIRECT_PRED_AUTO || (h->stat.i_direct_frames[0] && h->stat.i_direct_frames[1])) && h->stat.i_frame_count[SLICE_TYPE_B] ) { x264_log( h, X264_LOG_INFO, "direct mvs spatial:%.1f%% temporal:%.1f%%\n", h->stat.i_direct_frames[1] * 100. / h->stat.i_frame_count[SLICE_TYPE_B], h->stat.i_direct_frames[0] * 100. / h->stat.i_frame_count[SLICE_TYPE_B] ); } buf[0] = 0; int csize = CHROMA444 ? 4 : 1; if( i_mb_count != i_all_intra ) sprintf( buf, " inter: %.1f%% %.1f%% %.1f%%", h->stat.i_mb_cbp[1] * 100.0 / ((i_mb_count - i_all_intra)*4), h->stat.i_mb_cbp[3] * 100.0 / ((i_mb_count - i_all_intra)*csize), h->stat.i_mb_cbp[5] * 100.0 / ((i_mb_count - i_all_intra)*csize) ); /* * 演示样例 * x264 [info]: coded y,uvDC,uvAC intra: 74.1% 83.3% 58.9% inter: 10.4% 6.6% 0.4% */ x264_log( h, X264_LOG_INFO, "coded y,%s,%s intra: %.1f%% %.1f%% %.1f%%%s\n", CHROMA444? "u":"uvDC", CHROMA444?"v":"uvAC", h->stat.i_mb_cbp[0] * 100.0 / (i_all_intra*4), h->stat.i_mb_cbp[2] * 100.0 / (i_all_intra*csize), h->stat.i_mb_cbp[4] * 100.0 / (i_all_intra*csize), buf ); /* * 帧内预測信息 * 从上到下分别为I16x16,I8x8,I4x4 * 从左到右顺序为Vertical, Horizontal, DC, Plane .... * * 演示样例 * * x264 [info]: i16 v,h,dc,p: 21% 25% 7% 48% * x264 [info]: i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 25% 23% 13% 6% 5% 5% 6% 8% 10% * x264 [info]: i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 22% 20% 9% 7% 7% 8% 8% 7% 12% * x264 [info]: i8c dc,h,v,p: 43% 20% 27% 10% * */ int64_t fixed_pred_modes[4][9] = {{0}}; int64_t sum_pred_modes[4] = {0}; for( int i = 0; i <= I_PRED_16x16_DC_128; i++ ) { fixed_pred_modes[0][x264_mb_pred_mode16x16_fix[i]] += h->stat.i_mb_pred_mode[0][i]; sum_pred_modes[0] += h->stat.i_mb_pred_mode[0][i]; } if( sum_pred_modes[0] ) x264_log( h, X264_LOG_INFO, "i16 v,h,dc,p: %2.0f%% %2.0f%% %2.0f%% %2.0f%%\n", fixed_pred_modes[0][0] * 100.0 / sum_pred_modes[0], fixed_pred_modes[0][1] * 100.0 / sum_pred_modes[0], fixed_pred_modes[0][2] * 100.0 / sum_pred_modes[0], fixed_pred_modes[0][3] * 100.0 / sum_pred_modes[0] ); for( int i = 1; i <= 2; i++ ) { for( int j = 0; j <= I_PRED_8x8_DC_128; j++ ) { fixed_pred_modes[i][x264_mb_pred_mode4x4_fix(j)] += h->stat.i_mb_pred_mode[i][j]; sum_pred_modes[i] += h->stat.i_mb_pred_mode[i][j]; } if( sum_pred_modes[i] ) x264_log( h, X264_LOG_INFO, "i%d v,h,dc,ddl,ddr,vr,hd,vl,hu: %2.0f%% %2.0f%% %2.0f%% %2.0f%% %2.0f%% %2.0f%% %2.0f%% %2.0f%% %2.0f%%\n", (3-i)*4, fixed_pred_modes[i][0] * 100.0 / sum_pred_modes[i], fixed_pred_modes[i][1] * 100.0 / sum_pred_modes[i], fixed_pred_modes[i][2] * 100.0 / sum_pred_modes[i], fixed_pred_modes[i][3] * 100.0 / sum_pred_modes[i], fixed_pred_modes[i][4] * 100.0 / sum_pred_modes[i], fixed_pred_modes[i][5] * 100.0 / sum_pred_modes[i], fixed_pred_modes[i][6] * 100.0 / sum_pred_modes[i], fixed_pred_modes[i][7] * 100.0 / sum_pred_modes[i], fixed_pred_modes[i][8] * 100.0 / sum_pred_modes[i] ); } for( int i = 0; i <= I_PRED_CHROMA_DC_128; i++ ) { fixed_pred_modes[3][x264_mb_chroma_pred_mode_fix[i]] += h->stat.i_mb_pred_mode[3][i]; sum_pred_modes[3] += h->stat.i_mb_pred_mode[3][i]; } if( sum_pred_modes[3] && !CHROMA444 ) x264_log( h, X264_LOG_INFO, "i8c dc,h,v,p: %2.0f%% %2.0f%% %2.0f%% %2.0f%%\n", fixed_pred_modes[3][0] * 100.0 / sum_pred_modes[3], fixed_pred_modes[3][1] * 100.0 / sum_pred_modes[3], fixed_pred_modes[3][2] * 100.0 / sum_pred_modes[3], fixed_pred_modes[3][3] * 100.0 / sum_pred_modes[3] ); if( h->param.analyse.i_weighted_pred >= X264_WEIGHTP_SIMPLE && h->stat.i_frame_count[SLICE_TYPE_P] > 0 ) x264_log( h, X264_LOG_INFO, "Weighted P-Frames: Y:%.1f%% UV:%.1f%%\n", h->stat.i_wpred[0] * 100.0 / h->stat.i_frame_count[SLICE_TYPE_P], h->stat.i_wpred[1] * 100.0 / h->stat.i_frame_count[SLICE_TYPE_P] ); /* * 參考帧信息 * 从左到右依次为不同序号的參考帧 * * 演示样例 * * x264 [info]: ref P L0: 62.5% 19.7% 13.8% 4.0% * x264 [info]: ref B L0: 88.8% 9.4% 1.9% * x264 [info]: ref B L1: 92.6% 7.4% * */ for( int i_list = 0; i_list < 2; i_list++ ) for( int i_slice = 0; i_slice < 2; i_slice++ ) { char *p = buf; int64_t i_den = 0; int i_max = 0; for( int i = 0; i < X264_REF_MAX*2; i++ ) if( h->stat.i_mb_count_ref[i_slice][i_list][i] ) { i_den += h->stat.i_mb_count_ref[i_slice][i_list][i]; i_max = i; } if( i_max == 0 ) continue; for( int i = 0; i <= i_max; i++ ) p += sprintf( p, " %4.1f%%", 100. * h->stat.i_mb_count_ref[i_slice][i_list][i] / i_den ); x264_log( h, X264_LOG_INFO, "ref %c L%d:%s\n", "PB"[i_slice], i_list, buf ); } if( h->param.analyse.b_ssim ) { float ssim = SUM3( h->stat.f_ssim_mean_y ) / duration; x264_log( h, X264_LOG_INFO, "SSIM Mean Y:%.7f (%6.3fdb)\n", ssim, x264_ssim( ssim ) ); } /* * 演示样例 * * x264 [info]: PSNR Mean Y:42.967 U:47.163 V:47.000 Avg:43.950 Global:43.796 kb/s:339.67 * */ if( h->param.analyse.b_psnr ) { x264_log( h, X264_LOG_INFO, "PSNR Mean Y:%6.3f U:%6.3f V:%6.3f Avg:%6.3f Global:%6.3f kb/s:%.2f\n", SUM3( h->stat.f_psnr_mean_y ) / duration, SUM3( h->stat.f_psnr_mean_u ) / duration, SUM3( h->stat.f_psnr_mean_v ) / duration, SUM3( h->stat.f_psnr_average ) / duration, x264_psnr( SUM3( h->stat.f_ssd_global ), duration * i_yuv_size ), f_bitrate ); } else x264_log( h, X264_LOG_INFO, "kb/s:%.2f\n", f_bitrate ); } /* rc */ x264_ratecontrol_delete( h ); ////////////////////////关闭码率控制 /* param */ if( h->param.rc.psz_stat_out ) free( h->param.rc.psz_stat_out ); if( h->param.rc.psz_stat_in ) free( h->param.rc.psz_stat_in ); //free...... x264_cqm_delete( h ); x264_free( h->nal_buffer ); x264_free( h->reconfig_h ); x264_analyse_free_costs( h ); if( h->i_thread_frames > 1 ) h = h->thread[h->i_thread_phase]; /* frames */ x264_frame_delete_list( h->frames.unused[0] ); x264_frame_delete_list( h->frames.unused[1] ); x264_frame_delete_list( h->frames.current ); x264_frame_delete_list( h->frames.blank_unused ); h = h->thread[0]; for( int i = 0; i < h->i_thread_frames; i++ ) if( h->thread[i]->b_thread_active ) for( int j = 0; j < h->thread[i]->i_ref[0]; j++ ) if( h->thread[i]->fref[0][j] && h->thread[i]->fref[0][j]->b_duplicate ) x264_frame_delete( h->thread[i]->fref[0][j] ); if( h->param.i_lookahead_threads > 1 ) for( int i = 0; i < h->param.i_lookahead_threads; i++ ) x264_free( h->lookahead_thread[i] ); for( int i = h->param.i_threads - 1; i >= 0; i-- ) { x264_frame_t **frame; if( !h->param.b_sliced_threads || i == 0 ) { for( frame = h->thread[i]->frames.reference; *frame; frame++ ) { assert( (*frame)->i_reference_count > 0 ); (*frame)->i_reference_count--; if( (*frame)->i_reference_count == 0 ) x264_frame_delete( *frame ); } frame = &h->thread[i]->fdec; if( *frame ) { assert( (*frame)->i_reference_count > 0 ); (*frame)->i_reference_count--; if( (*frame)->i_reference_count == 0 ) x264_frame_delete( *frame ); } x264_macroblock_cache_free( h->thread[i] ); } x264_macroblock_thread_free( h->thread[i], 0 ); x264_free( h->thread[i]->out.p_bitstream ); x264_free( h->thread[i]->out.nal ); x264_pthread_mutex_destroy( &h->thread[i]->mutex ); x264_pthread_cond_destroy( &h->thread[i]->cv ); x264_free( h->thread[i] ); } #if HAVE_OPENCL x264_opencl_close_library( ocl ); #endif }
最后给出结果示意图,例如以下图:
至此。x264的主干函数(x264_encoder_open()函数、x264_encoder_headers()函数、x264_encoder_encode()函数与x264_encoder_close()函数)就简单粗暴地呈现出来了。接下来将深入H.264算法继续进行分析。
时间: 2024-10-06 16:53:19