#endif
//#define DEBUG_MB_TYPE
-//#define DEBUG_DUMP_FRAME
-//#define DEBUG_BENCHMARK
-
-#ifdef DEBUG_BENCHMARK
-static int64_t i_mtime_encode_frame = 0;
-static int64_t i_mtime_analyse = 0;
-static int64_t i_mtime_encode = 0;
-static int64_t i_mtime_write = 0;
-static int64_t i_mtime_filter = 0;
-#define TIMER_START( d ) \
- { \
- int64_t d##start = x264_mdate();
-
-#define TIMER_STOP( d ) \
- d += x264_mdate() - d##start;\
- }
-#else
-#define TIMER_START( d )
-#define TIMER_STOP( d )
-#endif
#define NALU_OVERHEAD 5 // startcode + NAL type costs 5 bytes per frame
return (float)(-10.0 * log( f_mse ) / log( 10.0 ));
}
-#ifdef DEBUG_DUMP_FRAME
-static void x264_frame_dump( x264_t *h, x264_frame_t *fr, char *name )
+static void x264_frame_dump( x264_t *h )
{
- FILE *f = fopen( name, "r+b" );
+ FILE *f = fopen( h->param.psz_dump_yuv, "r+b" );
int i, y;
if( !f )
return;
-
/* Write the frame in display order */
- fseek( f, fr->i_frame * h->param.i_height * h->param.i_width * 3 / 2, SEEK_SET );
-
- for( i = 0; i < fr->i_plane; i++ )
- {
- for( y = 0; y < h->param.i_height / ( i == 0 ? 1 : 2 ); y++ )
- {
- fwrite( &fr->plane[i][y*fr->i_stride[i]], 1, h->param.i_width / ( i == 0 ? 1 : 2 ), f );
- }
- }
+ fseek( f, h->fdec->i_frame * h->param.i_height * h->param.i_width * 3/2, SEEK_SET );
+ for( i = 0; i < h->fdec->i_plane; i++ )
+ for( y = 0; y < h->param.i_height >> !!i; y++ )
+ fwrite( &h->fdec->plane[i][y*h->fdec->i_stride[i]], 1, h->param.i_width >> !!i, f );
fclose( f );
}
-#endif
/* Fill "default" values */
if( h->param.b_interlaced )
{
- if( h->param.analyse.i_me_method == X264_ME_ESA )
+ if( h->param.analyse.i_me_method >= X264_ME_ESA )
{
x264_log( h, X264_LOG_WARNING, "interlace + me=esa is not implemented\n" );
h->param.analyse.i_me_method = X264_ME_UMH;
h->param.analyse.b_fast_pskip = 0;
h->param.analyse.i_noise_reduction = 0;
h->param.analyse.i_subpel_refine = x264_clip3( h->param.analyse.i_subpel_refine, 1, 6 );
+ h->param.rc.i_aq_mode = 0;
}
if( h->param.rc.i_rc_method == X264_RC_CQP )
{
h->param.i_cqm_preset = X264_CQM_FLAT;
if( h->param.analyse.i_me_method < X264_ME_DIA ||
- h->param.analyse.i_me_method > X264_ME_ESA )
+ h->param.analyse.i_me_method > X264_ME_TESA )
h->param.analyse.i_me_method = X264_ME_HEX;
if( h->param.analyse.i_me_range < 4 )
h->param.analyse.i_me_range = 4;
if( h->param.analyse.i_me_range > 16 && h->param.analyse.i_me_method <= X264_ME_HEX )
h->param.analyse.i_me_range = 16;
+ if( h->param.analyse.i_me_method == X264_ME_TESA &&
+ (h->mb.b_lossless || h->param.analyse.i_subpel_refine <= 1) )
+ h->param.analyse.i_me_method = X264_ME_ESA;
h->param.analyse.i_subpel_refine = x264_clip3( h->param.analyse.i_subpel_refine, 1, 7 );
h->param.analyse.b_bframe_rdo = h->param.analyse.b_bframe_rdo && h->param.analyse.i_subpel_refine >= 6;
h->param.analyse.b_mixed_references = h->param.analyse.b_mixed_references && h->param.i_frame_reference > 1;
if( !h->param.b_cabac )
h->param.analyse.i_trellis = 0;
h->param.analyse.i_trellis = x264_clip3( h->param.analyse.i_trellis, 0, 2 );
+ h->param.rc.i_aq_mode = x264_clip3( h->param.rc.i_aq_mode, 0, 2 );
+ if( h->param.rc.f_aq_strength <= 0 )
+ h->param.rc.i_aq_mode = 0;
+ /* VAQ effectively replaces qcomp, so qcomp is raised towards 1 to compensate. */
+ if( h->param.rc.i_aq_mode == X264_AQ_GLOBAL )
+ h->param.rc.f_qcompress = x264_clip3f(h->param.rc.f_qcompress + h->param.rc.f_aq_strength / 0.7, 0, 1);
h->param.analyse.i_noise_reduction = x264_clip3( h->param.analyse.i_noise_reduction, 0, 1<<16 );
{
static void mbcmp_init( x264_t *h )
{
- memcpy( h->pixf.mbcmp,
- ( h->mb.b_lossless || h->param.analyse.i_subpel_refine <= 1 ) ? h->pixf.sad : h->pixf.satd,
- sizeof(h->pixf.mbcmp) );
+ int satd = !h->mb.b_lossless && h->param.analyse.i_subpel_refine > 1;
+ memcpy( h->pixf.mbcmp, satd ? h->pixf.satd : h->pixf.sad, sizeof(h->pixf.mbcmp) );
+ satd &= h->param.analyse.i_me_method == X264_ME_TESA;
+ memcpy( h->pixf.fpelcmp, satd ? h->pixf.satd : h->pixf.sad, sizeof(h->pixf.fpelcmp) );
+ memcpy( h->pixf.fpelcmp_x3, satd ? h->pixf.satd_x3 : h->pixf.sad_x3, sizeof(h->pixf.fpelcmp_x3) );
+ memcpy( h->pixf.fpelcmp_x4, satd ? h->pixf.satd_x4 : h->pixf.sad_x4, sizeof(h->pixf.fpelcmp_x4) );
}
/****************************************************************************
x264_t *x264_encoder_open ( x264_param_t *param )
{
x264_t *h = x264_malloc( sizeof( x264_t ) );
+ char buf[1000], *p;
int i;
memset( h, 0, sizeof( x264_t ) );
|| h->param.rc.i_rc_method == X264_RC_CRF
|| h->param.b_bframe_adaptive
|| h->param.b_pre_scenecut );
+ h->frames.b_have_lowres |= (h->param.rc.b_stat_read && h->param.rc.i_vbv_buffer_size > 0);
h->frames.i_last_idr = - h->param.i_keyint_max;
h->frames.i_input = 0;
x264_dct_init( h->param.cpu, &h->dctf );
x264_zigzag_init( h->param.cpu, &h->zigzagf, h->param.b_interlaced );
x264_mc_init( h->param.cpu, &h->mc );
- x264_csp_init( h->param.cpu, h->param.i_csp, &h->csp );
x264_quant_init( h, h->param.cpu, &h->quantf );
x264_deblock_init( h->param.cpu, &h->loopf );
x264_dct_init_weights();
mbcmp_init( h );
- x264_log( h, X264_LOG_INFO, "using cpu capabilities: %s%s%s%s%s%s%s%s\n",
- param->cpu&X264_CPU_MMX ? "MMX " : "",
- param->cpu&X264_CPU_MMXEXT ? "MMXEXT " : "",
- param->cpu&X264_CPU_SSE ? "SSE " : "",
- param->cpu&X264_CPU_SSE2 ? "SSE2 " : "",
- param->cpu&X264_CPU_SSSE3 ? "SSSE3 " : "",
- param->cpu&X264_CPU_3DNOW ? "3DNow! " : "",
- param->cpu&X264_CPU_ALTIVEC ? "Altivec " : "",
- param->cpu ? "" : "none!" );
+ p = buf + sprintf( buf, "using cpu capabilities:" );
+ for( i=0; x264_cpu_names[i].flags; i++ )
+ if( (param->cpu & x264_cpu_names[i].flags) == x264_cpu_names[i].flags
+ && (!i || x264_cpu_names[i].flags != x264_cpu_names[i-1].flags) )
+ p += sprintf( p, " %s", x264_cpu_names[i].name );
+ if( !param->cpu )
+ p += sprintf( p, " none!" );
+ x264_log( h, X264_LOG_INFO, "%s\n", buf );
h->out.i_nal = 0;
h->out.i_bitstream = X264_MAX( 1000000, h->param.i_width * h->param.i_height * 4
if( x264_ratecontrol_new( h ) < 0 )
return NULL;
-#ifdef DEBUG_DUMP_FRAME
+ if( h->param.psz_dump_yuv )
{
/* create or truncate the reconstructed video file */
- FILE *f = fopen( "fdec.yuv", "w" );
+ FILE *f = fopen( h->param.psz_dump_yuv, "w" );
if( f )
fclose( f );
else
return NULL;
}
}
-#endif
return h;
}
h->i_ref1 = X264_MIN( h->i_ref1, h->frames.i_max_ref1 );
h->i_ref0 = X264_MIN( h->i_ref0, h->frames.i_max_ref0 );
h->i_ref0 = X264_MIN( h->i_ref0, h->param.i_frame_reference ); // if reconfig() has lowered the limit
- h->i_ref0 = X264_MIN( h->i_ref0, 16 - h->i_ref1 );
+ assert( h->i_ref0 + h->i_ref1 <= 16 );
h->mb.pic.i_fref[0] = h->i_ref0;
h->mb.pic.i_fref[1] = h->i_ref1;
}
int b_deblock = !h->sh.i_disable_deblocking_filter_idc;
int b_end = mb_y == h->sps->i_mb_height;
int min_y = mb_y - (1 << h->sh.b_mbaff);
-#ifndef DEBUG_DUMP_FRAME
- b_deblock &= b_hpel;
-#endif
+ b_deblock &= b_hpel || h->param.psz_dump_yuv;
if( mb_y & h->sh.b_mbaff )
return;
if( min_y < 0 )
if( b_hpel )
{
x264_frame_expand_border( h, h->fdec, min_y, b_end );
- x264_frame_filter( h->param.cpu, h->fdec, h->sh.b_mbaff, min_y, b_end );
+ x264_frame_filter( h, h->fdec, min_y, b_end );
x264_frame_expand_border_filtered( h, h->fdec, min_y, b_end );
}
static void x264_slice_write( x264_t *h )
{
int i_skip;
- int mb_xy;
+ int mb_xy, i_mb_x, i_mb_y;
int i;
/* init stats */
h->mb.i_last_qp = h->sh.i_qp;
h->mb.i_last_dqp = 0;
- for( mb_xy = h->sh.i_first_mb, i_skip = 0; mb_xy < h->sh.i_last_mb; )
+ i_mb_y = h->sh.i_first_mb / h->sps->i_mb_width;
+ i_mb_x = h->sh.i_first_mb % h->sps->i_mb_width;
+ i_skip = 0;
+
+ while( (mb_xy = i_mb_x + i_mb_y * h->sps->i_mb_width) < h->sh.i_last_mb )
{
- const int i_mb_y = mb_xy / h->sps->i_mb_width;
- const int i_mb_x = mb_xy % h->sps->i_mb_width;
int mb_spos = bs_pos(&h->out.bs) + x264_cabac_pos(&h->cabac);
if( i_mb_x == 0 )
* Slice I: choose I_4x4 or I_16x16 mode
* Slice P: choose between using P mode or intra (4x4 or 16x16)
* */
- TIMER_START( i_mtime_analyse );
x264_macroblock_analyse( h );
- TIMER_STOP( i_mtime_analyse );
/* encode this macroblock -> be careful it can change the mb type to P_SKIP if needed */
- TIMER_START( i_mtime_encode );
x264_macroblock_encode( h );
- TIMER_STOP( i_mtime_encode );
- TIMER_START( i_mtime_write );
if( h->param.b_cabac )
{
if( mb_xy > h->sh.i_first_mb && !(h->sh.b_mbaff && (i_mb_y&1)) )
- x264_cabac_encode_terminal( &h->cabac, 0 );
+ x264_cabac_encode_terminal( &h->cabac );
if( IS_SKIP( h->mb.i_type ) )
x264_cabac_mb_skip( h, 1 );
x264_macroblock_write_cavlc( h, &h->out.bs );
}
}
- TIMER_STOP( i_mtime_write );
#if VISUALIZE
if( h->param.b_visualize )
h->stat.frame.i_mb_count_8x8dct[1] += h->mb.b_transform_8x8;
}
- if( h->mb.b_variable_qp )
- x264_ratecontrol_mb(h, bs_pos(&h->out.bs) + x264_cabac_pos(&h->cabac) - mb_spos);
+ x264_ratecontrol_mb( h, bs_pos(&h->out.bs) + x264_cabac_pos(&h->cabac) - mb_spos );
if( h->sh.b_mbaff )
{
- if( (i_mb_y&1) && i_mb_x == h->sps->i_mb_width - 1 )
- mb_xy++;
- else if( i_mb_y&1 )
- mb_xy += 1 - h->sps->i_mb_width;
- else
- mb_xy += h->sps->i_mb_width;
+ i_mb_x += i_mb_y & 1;
+ i_mb_y ^= i_mb_x < h->sps->i_mb_width;
}
else
- mb_xy++;
- }
-
- if( h->param.b_cabac )
- {
- /* end of slice */
- x264_cabac_encode_terminal( &h->cabac, 1 );
- }
- else if( i_skip > 0 )
- {
- bs_write_ue( &h->out.bs, i_skip ); /* last skip run */
+ i_mb_x++;
+ if(i_mb_x == h->sps->i_mb_width)
+ {
+ i_mb_y++;
+ i_mb_x = 0;
+ }
}
if( h->param.b_cabac )
{
- x264_cabac_encode_flush( &h->cabac );
+ x264_cabac_encode_flush( h, &h->cabac );
h->out.bs.p = h->cabac.p;
}
else
{
+ if( i_skip > 0 )
+ bs_write_ue( &h->out.bs, i_skip ); /* last skip run */
/* rbsp_slice_trailing_bits */
bs_rbsp_trailing( &h->out.bs );
}
x264_nal_end( h );
+ x264_fdec_filter_row( h, h->sps->i_mb_height );
+
/* Compute misc bits */
h->stat.frame.i_misc_bits = bs_pos( &h->out.bs )
+ NALU_OVERHEAD * 8
x264_stack_align( x264_slice_write, h );
i_frame_size = h->out.nal[h->out.i_nal-1].i_payload;
- x264_fdec_filter_row( h, h->sps->i_mb_height );
#if VISUALIZE
if( h->param.b_visualize )
*pp_nal = NULL;
/* ------------------- Setup new frame from picture -------------------- */
- TIMER_START( i_mtime_encode_frame );
if( pic_in != NULL )
{
/* 1: Copy the picture to a frame and move it to a buffer */
x264_frame_t *fenc = x264_frame_pop_unused( h );
- x264_frame_copy_picture( h, fenc, pic_in );
+ if( x264_frame_copy_picture( h, fenc, pic_in ) < 0 )
+ return -1;
if( h->param.i_width != 16 * h->sps->i_mb_width ||
h->param.i_height != 16 * h->sps->i_mb_height )
x264_frame_push( h->frames.next, fenc );
if( h->frames.b_have_lowres )
- x264_frame_init_lowres( h->param.cpu, fenc );
+ x264_frame_init_lowres( h, fenc );
if( h->frames.i_input <= h->frames.i_delay + 1 - h->param.i_threads )
{
while( bframes-- )
x264_frame_push( h->frames.current, x264_frame_shift( h->frames.next ) );
}
- TIMER_STOP( i_mtime_encode_frame );
/* ------------------- Get frame to be encoded ------------------------- */
/* 4: get picture to encode */
/* ------------------- Setup frame context ----------------------------- */
/* 5: Init data dependent of frame type */
- TIMER_START( i_mtime_encode_frame );
if( h->fenc->i_type == X264_TYPE_IDR )
{
/* reset ref pictures */
x264_slices_write( h );
/* restore CPU state (before using float again) */
- x264_cpu_restore( h->param.cpu );
+ x264_emms();
if( h->sh.i_type == SLICE_TYPE_P && !h->param.rc.b_stat_read
&& h->param.i_scenecut_threshold >= 0
/* ---------------------- Update encoder state ------------------------- */
/* update rc */
- x264_cpu_restore( h->param.cpu );
+ x264_emms();
x264_ratecontrol_end( h, h->out.i_frame_size * 8 );
/* restore CPU state (before using float again) */
- x264_cpu_restore( h->param.cpu );
-
- x264_noise_reduction_update( h );
+ x264_emms();
- TIMER_STOP( i_mtime_encode_frame );
+ x264_noise_reduction_update( thread_current );
/* ---------------------- Compute/Print statistics --------------------- */
x264_thread_sync_stat( h, h->thread[0] );
/* Slice stat */
h->stat.i_slice_count[h->sh.i_type]++;
h->stat.i_slice_size[h->sh.i_type] += h->out.i_frame_size + NALU_OVERHEAD;
- h->stat.i_slice_qp[h->sh.i_type] += h->fdec->i_qpplus1 - 1;
+ h->stat.f_slice_qp[h->sh.i_type] += h->fdec->f_qp_avg_aq;
for( i = 0; i < X264_MBTYPE_MAX; i++ )
h->stat.i_mb_count[h->sh.i_type][i] += h->stat.frame.i_mb_count[i];
h->fenc->plane[i], h->fenc->i_stride[i],
h->param.i_width >> !!i, h->param.i_height >> !!i );
}
- x264_cpu_restore( h->param.cpu );
+ x264_emms();
h->stat.i_sqe_global[h->sh.i_type] += sqe[0] + sqe[1] + sqe[2];
h->stat.f_psnr_average[h->sh.i_type] += x264_psnr( sqe[0] + sqe[1] + sqe[2], 3 * h->param.i_width * h->param.i_height / 2 );
psz_message[79] = '\0';
x264_log( h, X264_LOG_DEBUG,
- "frame=%4d QP=%i NAL=%d Slice:%c Poc:%-3d I:%-4d P:%-4d SKIP:%-4d size=%d bytes%s\n",
+ "frame=%4d QP=%.2f NAL=%d Slice:%c Poc:%-3d I:%-4d P:%-4d SKIP:%-4d size=%d bytes%s\n",
h->i_frame,
- h->fdec->i_qpplus1 - 1,
+ h->fdec->f_qp_avg_aq,
h->i_nal_ref_idc,
h->sh.i_type == SLICE_TYPE_I ? 'I' : (h->sh.i_type == SLICE_TYPE_P ? 'P' : 'B' ),
h->fdec->i_poc,
}
#endif
-#ifdef DEBUG_DUMP_FRAME
- /* Dump reconstructed frame */
- x264_frame_dump( h, h->fdec, "fdec.yuv" );
-#endif
+ if( h->param.psz_dump_yuv )
+ x264_frame_dump( h );
}
/****************************************************************************
****************************************************************************/
void x264_encoder_close ( x264_t *h )
{
-#ifdef DEBUG_BENCHMARK
- int64_t i_mtime_total = i_mtime_analyse + i_mtime_encode + i_mtime_write + i_mtime_filter + 1;
-#endif
int64_t i_yuv_size = 3 * h->param.i_width * h->param.i_height / 2;
int i;
x264_pthread_join( h->thread[i]->thread_handle, NULL );
}
-#ifdef DEBUG_BENCHMARK
- x264_log( h, X264_LOG_INFO,
- "analyse=%d(%lldms) encode=%d(%lldms) write=%d(%lldms) filter=%d(%lldms)\n",
- (int)(100*i_mtime_analyse/i_mtime_total), i_mtime_analyse/1000,
- (int)(100*i_mtime_encode/i_mtime_total), i_mtime_encode/1000,
- (int)(100*i_mtime_write/i_mtime_total), i_mtime_write/1000,
- (int)(100*i_mtime_filter/i_mtime_total), i_mtime_filter/1000 );
-#endif
-
/* Slices used and PSNR */
for( i=0; i<5; i++ )
{
"slice %s:%-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_name[i_slice],
i_count,
- (double)h->stat.i_slice_qp[i_slice] / i_count,
+ h->stat.f_slice_qp[i_slice] / i_count,
(double)h->stat.i_slice_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,
"slice %s:%-5d Avg QP:%5.2f size:%6.0f\n",
slice_name[i_slice],
i_count,
- (double)h->stat.i_slice_qp[i_slice] / i_count,
+ h->stat.f_slice_qp[i_slice] / i_count,
(double)h->stat.i_slice_size[i_slice] / i_count );
}
}