Commit d50a5bfd authored by Fiona Glaser's avatar Fiona Glaser

VFR-aware PSNR/SSIM measurement

First step to VFR-aware MB-tree and bit allocation.
parent 506683ae
......@@ -780,19 +780,20 @@ struct x264_t
/* Cumulated stats */
/* per slice info */
int i_frame_count[5];
int64_t i_frame_size[5];
double f_frame_qp[5];
int i_frame_count[3];
int64_t i_frame_size[3];
double f_frame_qp[3];
int i_consecutive_bframes[X264_BFRAME_MAX+1];
/* */
int64_t i_ssd_global[5];
double f_psnr_average[5];
double f_psnr_mean_y[5];
double f_psnr_mean_u[5];
double f_psnr_mean_v[5];
double f_ssim_mean_y[5];
double f_ssd_global[3];
double f_psnr_average[3];
double f_psnr_mean_y[3];
double f_psnr_mean_u[3];
double f_psnr_mean_v[3];
double f_ssim_mean_y[3];
double f_frame_duration[3];
/* */
int64_t i_mb_count[5][19];
int64_t i_mb_count[3][19];
int64_t i_mb_partition[2][17];
int64_t i_mb_count_8x8dct[2];
int64_t i_mb_count_ref[2][2][X264_REF_MAX*2];
......
......@@ -42,6 +42,7 @@ typedef struct x264_frame
int64_t i_dts;
int64_t i_reordered_pts;
int i_duration; /* in SPS time_scale units (i.e 2 * timebase units) used for vfr */
float f_duration; /* in seconds */
int i_cpb_duration;
int i_cpb_delay; /* in SPS time_scale units (i.e 2 * timebase units) */
int i_dpb_output_delay;
......
......@@ -52,16 +52,16 @@ static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current,
******************************* x264 libs **********************************
*
****************************************************************************/
static float x264_psnr( int64_t i_sqe, int64_t i_size )
static double x264_psnr( double sqe, double size )
{
double f_mse = (double)i_sqe / (PIXEL_MAX*PIXEL_MAX * (double)i_size);
if( f_mse <= 0.0000000001 ) /* Max 100dB */
double mse = sqe / (PIXEL_MAX*PIXEL_MAX * size);
if( mse <= 0.0000000001 ) /* Max 100dB */
return 100;
return -10.0 * log10( f_mse );
return -10.0 * log10( mse );
}
static float x264_ssim( float ssim )
static double x264_ssim( double ssim )
{
return -10.0 * log10( 1 - ssim );
}
......@@ -1006,7 +1006,8 @@ x264_t *x264_encoder_open( x264_param_t *param )
CHECKED_MALLOCZERO( h->frames.blank_unused, h->i_thread_frames * 4 * sizeof(x264_frame_t *) );
h->i_ref0 = 0;
h->i_ref1 = 0;
h->i_cpb_delay = h->i_coded_fields = h->i_disp_fields = h->i_prev_duration = 0;
h->i_cpb_delay = h->i_coded_fields = h->i_disp_fields = 0;
h->i_prev_duration = ((uint64_t)h->param.i_fps_den * h->sps->vui.i_time_scale) / ((uint64_t)h->param.i_fps_num * h->sps->vui.i_num_units_in_tick);
h->i_disp_fields_last_frame = -1;
x264_rdo_init();
......@@ -2867,19 +2868,22 @@ static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current,
}
psz_message[0] = '\0';
double dur = h->fenc->f_duration;
h->stat.f_frame_duration[h->sh.i_type] += dur;
if( h->param.analyse.b_psnr )
{
int64_t ssd[3] = {
int64_t ssd[3] =
{
h->stat.frame.i_ssd[0],
h->stat.frame.i_ssd[1],
h->stat.frame.i_ssd[2],
};
h->stat.i_ssd_global[h->sh.i_type] += ssd[0] + ssd[1] + ssd[2];
h->stat.f_psnr_average[h->sh.i_type] += x264_psnr( ssd[0] + ssd[1] + ssd[2], 3 * h->param.i_width * h->param.i_height / 2 );
h->stat.f_psnr_mean_y[h->sh.i_type] += x264_psnr( ssd[0], h->param.i_width * h->param.i_height );
h->stat.f_psnr_mean_u[h->sh.i_type] += x264_psnr( ssd[1], h->param.i_width * h->param.i_height / 4 );
h->stat.f_psnr_mean_v[h->sh.i_type] += x264_psnr( ssd[2], h->param.i_width * h->param.i_height / 4 );
h->stat.f_ssd_global[h->sh.i_type] += dur * (ssd[0] + ssd[1] + ssd[2]);
h->stat.f_psnr_average[h->sh.i_type] += dur * x264_psnr( ssd[0] + ssd[1] + ssd[2], 3 * h->param.i_width * h->param.i_height / 2 );
h->stat.f_psnr_mean_y[h->sh.i_type] += dur * x264_psnr( ssd[0], h->param.i_width * h->param.i_height );
h->stat.f_psnr_mean_u[h->sh.i_type] += dur * x264_psnr( ssd[1], h->param.i_width * h->param.i_height / 4 );
h->stat.f_psnr_mean_v[h->sh.i_type] += dur * x264_psnr( ssd[2], h->param.i_width * h->param.i_height / 4 );
snprintf( psz_message, 80, " PSNR Y:%5.2f U:%5.2f V:%5.2f",
x264_psnr( ssd[0], h->param.i_width * h->param.i_height ),
......@@ -2891,7 +2895,7 @@ static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current,
{
double ssim_y = h->stat.frame.f_ssim
/ (((h->param.i_width-6)>>2) * ((h->param.i_height-6)>>2));
h->stat.f_ssim_mean_y[h->sh.i_type] += ssim_y;
h->stat.f_ssim_mean_y[h->sh.i_type] += ssim_y * dur;
snprintf( psz_message + strlen(psz_message), 80 - strlen(psz_message),
" SSIM Y:%.5f", ssim_y );
}
......@@ -2999,7 +3003,8 @@ void x264_encoder_close ( x264_t *h )
if( h->stat.i_frame_count[i_slice] > 0 )
{
const int i_count = h->stat.i_frame_count[i_slice];
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 )
{
x264_log( h, X264_LOG_INFO,
......@@ -3008,9 +3013,9 @@ void x264_encoder_close ( x264_t *h )
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] / i_count, h->stat.f_psnr_mean_u[i_slice] / i_count, h->stat.f_psnr_mean_v[i_slice] / i_count,
h->stat.f_psnr_average[i_slice] / i_count,
x264_psnr( h->stat.i_ssd_global[i_slice], i_count * i_yuv_size ) );
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
{
......@@ -3113,18 +3118,11 @@ void x264_encoder_close ( x264_t *h )
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];
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];
int64_t i_mb_count = (int64_t)i_count * h->mb.i_mb_count;
float fps = (float) h->param.i_fps_num / h->param.i_fps_den;
float f_bitrate;
/* duration algorithm fails with one frame */
if( !h->param.b_vfr_input || i_count == 1 )
f_bitrate = fps * SUM3(h->stat.i_frame_size) / i_count / 125;
else
{
float duration = (float)(2 * h->frames.i_largest_pts - h->frames.i_second_largest_pts - h->frames.i_first_pts)
* h->param.i_timebase_num / h->param.i_timebase_den;
f_bitrate = SUM3(h->stat.i_frame_size) / duration / 125;
}
float f_bitrate = SUM3(h->stat.i_frame_size) / duration / 125;
if( h->pps->b_transform_8x8_mode )
{
......@@ -3223,18 +3221,18 @@ void x264_encoder_close ( x264_t *h )
if( h->param.analyse.b_ssim )
{
float ssim = SUM3( h->stat.f_ssim_mean_y ) / i_count;
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 ) );
}
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 ) / i_count,
SUM3( h->stat.f_psnr_mean_u ) / i_count,
SUM3( h->stat.f_psnr_mean_v ) / i_count,
SUM3( h->stat.f_psnr_average ) / i_count,
x264_psnr( SUM3( h->stat.i_ssd_global ), i_count * i_yuv_size ),
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
......
......@@ -1253,32 +1253,32 @@ void x264_slicetype_decide( x264_t *h )
int lookahead_size = h->lookahead->next.i_size;
if( h->param.rc.i_rc_method == X264_RC_ABR || h->param.rc.b_stat_write || h->param.rc.i_vbv_buffer_size )
for( int i = 0; i < h->lookahead->next.i_size; i++ )
{
for( int i = 0; i < h->lookahead->next.i_size; i++ )
if( h->param.b_vfr_input )
{
if( h->param.b_vfr_input )
{
if( lookahead_size-- > 1 )
h->lookahead->next.list[i]->i_duration = 2 * (h->lookahead->next.list[i+1]->i_pts - h->lookahead->next.list[i]->i_pts);
else
h->lookahead->next.list[i]->i_duration = h->i_prev_duration;
}
if( lookahead_size-- > 1 )
h->lookahead->next.list[i]->i_duration = 2 * (h->lookahead->next.list[i+1]->i_pts - h->lookahead->next.list[i]->i_pts);
else
h->lookahead->next.list[i]->i_duration = delta_tfi_divisor[h->lookahead->next.list[i]->i_pic_struct];
h->i_prev_duration = h->lookahead->next.list[i]->i_duration;
if( h->lookahead->next.list[i]->i_frame > h->i_disp_fields_last_frame && lookahead_size > 0 )
{
h->lookahead->next.list[i]->i_field_cnt = h->i_disp_fields;
h->i_disp_fields += h->lookahead->next.list[i]->i_duration;
h->i_disp_fields_last_frame = h->lookahead->next.list[i]->i_frame;
}
else if( lookahead_size == 0 )
{
h->lookahead->next.list[i]->i_field_cnt = h->i_disp_fields;
h->lookahead->next.list[i]->i_duration = h->i_prev_duration;
}
}
else
h->lookahead->next.list[i]->i_duration = delta_tfi_divisor[h->lookahead->next.list[i]->i_pic_struct];
h->i_prev_duration = h->lookahead->next.list[i]->i_duration;
h->lookahead->next.list[i]->f_duration = (double)h->lookahead->next.list[i]->i_duration
* h->sps->vui.i_num_units_in_tick
/ h->sps->vui.i_time_scale;
if( h->lookahead->next.list[i]->i_frame > h->i_disp_fields_last_frame && lookahead_size > 0 )
{
h->lookahead->next.list[i]->i_field_cnt = h->i_disp_fields;
h->i_disp_fields += h->lookahead->next.list[i]->i_duration;
h->i_disp_fields_last_frame = h->lookahead->next.list[i]->i_frame;
}
else if( lookahead_size == 0 )
{
h->lookahead->next.list[i]->i_field_cnt = h->i_disp_fields;
h->lookahead->next.list[i]->i_duration = h->i_prev_duration;
}
}
......@@ -1450,20 +1450,17 @@ void x264_slicetype_decide( x264_t *h )
for( int i = 0; i <= bframes; i++ )
{
h->lookahead->next.list[i]->i_coded = i_coded++;
if( h->param.rc.i_rc_method == X264_RC_ABR || h->param.rc.b_stat_write || h->param.rc.i_vbv_buffer_size )
if( i )
{
if( i )
{
x264_calculate_durations( h, h->lookahead->next.list[i], h->lookahead->next.list[i-1], &h->i_cpb_delay, &h->i_coded_fields );
h->lookahead->next.list[0]->f_planned_cpb_duration[i-1] = (double)h->lookahead->next.list[i-1]->i_cpb_duration *
h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale;
}
else
x264_calculate_durations( h, h->lookahead->next.list[i], NULL, &h->i_cpb_delay, &h->i_coded_fields );
h->lookahead->next.list[0]->f_planned_cpb_duration[i] = (double)h->lookahead->next.list[i]->i_cpb_duration *
h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale;
x264_calculate_durations( h, h->lookahead->next.list[i], h->lookahead->next.list[i-1], &h->i_cpb_delay, &h->i_coded_fields );
h->lookahead->next.list[0]->f_planned_cpb_duration[i-1] = (double)h->lookahead->next.list[i-1]->i_cpb_duration *
h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale;
}
else
x264_calculate_durations( h, h->lookahead->next.list[i], NULL, &h->i_cpb_delay, &h->i_coded_fields );
h->lookahead->next.list[0]->f_planned_cpb_duration[i] = (double)h->lookahead->next.list[i]->i_cpb_duration *
h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale;
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment