From fcc3087c6891a04e461d80757e408848113a7246 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Thu, 20 Jan 2011 13:07:54 +0000 Subject: [PATCH 01/81] Add speedcontrol file. --- encoder/speed.c | 257 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 257 insertions(+) create mode 100644 encoder/speed.c diff --git a/encoder/speed.c b/encoder/speed.c new file mode 100644 index 00000000..7b5c400a --- /dev/null +++ b/encoder/speed.c @@ -0,0 +1,257 @@ +#include +#include +#include +#include "common/common.h" +#include "common/cpu.h" + +struct x264_speedcontrol_t +{ + // all times are in usec + int64_t timestamp; // when was speedcontrol last invoked + int64_t cpu_time; // time spent encoding the previous frame + int64_t buffer_size; // assumed application-side buffer of frames to be streamed, + int64_t buffer_fill; // where full = we don't have to hurry + int64_t compensation_period; // how quickly we try to return to the target buffer fullness + float fps, spf; + int preset; // which setting was used in the previous frame + int prev_frame; + float cplx_num; // rolling average of estimated spf for preset #0 + float cplx_den; + float cplx_decay; + float dither; + x264_param_t user_param; + + struct { + int64_t min_buffer, max_buffer; + double avg_preset; + int den; + } stat; +}; + +void x264_speedcontrol_new( x264_t *h ) +{ + x264_speedcontrol_t *sc = h->sc = x264_malloc( sizeof(x264_speedcontrol_t) ); + x264_emms(); + memset( sc, 0, sizeof(x264_speedcontrol_t) ); + + if( h->param.sc.f_speed <= 0 ) + h->param.sc.f_speed = 1; + sc->fps = h->param.i_fps_num / h->param.i_fps_den; + sc->spf = 1e6 / sc->fps; + h->param.sc.i_buffer_size = X264_MAX( 3, h->param.sc.i_buffer_size ); + sc->buffer_size = h->param.sc.i_buffer_size * 1e6 / sc->fps; + sc->buffer_fill = sc->buffer_size * h->param.sc.f_buffer_init; + sc->buffer_fill = x264_clip3( sc->buffer_fill, sc->spf, sc->buffer_size ); + sc->compensation_period = sc->buffer_size/4; + sc->timestamp = x264_mdate(); + sc->preset = -1; + sc->prev_frame = 0; + sc->cplx_num = 3e3; //FIXME estimate initial complexity + sc->cplx_den = .1; + sc->cplx_decay = 1 - 1./h->param.sc.i_buffer_size; + sc->stat.min_buffer = sc->buffer_size; + sc->stat.max_buffer = 0; + sc->user_param = h->param; +} + +void x264_speedcontrol_delete( x264_t *h ) +{ + x264_speedcontrol_t *sc = h->sc; + if( !sc ) + return; + x264_log( h, X264_LOG_INFO, "speedcontrol: avg preset=%.3f buffer min=%.3f max=%.3f\n", + sc->stat.avg_preset / sc->stat.den, + (float)sc->stat.min_buffer / sc->buffer_size, + (float)sc->stat.max_buffer / sc->buffer_size ); +// x264_log( h, X264_LOG_INFO, "speedcontrol: avg cplx=%.5f\n", sc->cplx_num / sc->cplx_den ); + x264_free( sc ); +} + +static int dither( x264_speedcontrol_t *sc, float f ) +{ + int i = f; + if( f < 0 ) + i--; + sc->dither += f - i; + if( sc->dither >= 1. ) + { + sc->dither--; + i++; + } + return i; +} + +typedef struct +{ + float time; // relative encoding time, compared to the other presets + int subme; + int me; + int refs; + int mix; + int trellis; + int partitions; + int chromame; + float psy_rd; + float psy_trellis; +} sc_preset_t; + +#define PRESETS 13 +static const sc_preset_t presets[PRESETS] = +{ +#define I4 X264_ANALYSE_I4x4 +#define I8 X264_ANALYSE_I8x8 +#define P8 X264_ANALYSE_PSUB16x16 +#define B8 X264_ANALYSE_BSUB16x16 +/*0*/ { .time=1.060, .subme=1, .me=X264_ME_DIA, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=0, .psy_rd=0 }, +/*1*/ { .time=1.120, .subme=1, .me=X264_ME_DIA, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=I8|I4, .psy_rd=0 }, +/*2*/ { .time=1.440, .subme=3, .me=X264_ME_HEX, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=I8|I4, .psy_rd=0 }, +/*3*/ { .time=1.620, .subme=5, .me=X264_ME_HEX, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=I8|I4, .psy_rd=1.0 }, +/*4*/ { .time=2.660, .subme=6, .me=X264_ME_HEX, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=I8|I4, .psy_rd=1.0 }, +/*5*/ { .time=3.560, .subme=6, .me=X264_ME_HEX, .refs=1, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4, .psy_rd=1.0 }, +/*6*/ { .time=4.640, .subme=6, .me=X264_ME_HEX, .refs=2, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4, .psy_rd=1.0 }, +/*7*/ { .time=5.190, .subme=7, .me=X264_ME_HEX, .refs=2, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4, .psy_rd=1.0 }, +/*8*/ { .time=6.190, .subme=7, .me=X264_ME_HEX, .refs=2, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 }, +/*9*/ { .time=6.920, .subme=7, .me=X264_ME_HEX, .refs=3, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 }, +/*10*/ { .time=7.070, .subme=8, .me=X264_ME_HEX, .refs=3, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 }, +/*11*/ { .time=8.800, .subme=8, .me=X264_ME_UMH, .refs=3, .mix=1, .chromame=1, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 }, +/*12*/ { .time=18.570, .subme=8, .me=X264_ME_UMH, .refs=3, .mix=1, .chromame=1, .trellis=2, .partitions=I8|I4|P8|B8, .psy_rd=1.0 } +}; + +static void apply_preset( x264_t *h, int preset ) +{ + x264_speedcontrol_t *sc = h->sc; + preset = x264_clip3( preset, 0, PRESETS-1 ); + //if( preset != sc->preset ) + { + const sc_preset_t *s = &presets[preset]; + x264_param_t p = sc->user_param; + + p.i_frame_reference = s->refs; + p.analyse.inter = s->partitions; + p.analyse.i_subpel_refine = s->subme; + p.analyse.i_me_method = s->me; + p.analyse.i_trellis = s->trellis; + p.analyse.b_mixed_references = s->mix; + p.analyse.b_chroma_me = s->chromame; + p.analyse.f_psy_rd = s->psy_rd; + p.analyse.f_psy_trellis = s->psy_trellis; + x264_encoder_reconfig( h, &p ); + sc->preset = preset; + x264_log( h, X264_LOG_DEBUG, "Applying speedcontrol preset %d.\n", preset ); + } +} + +void x264_speedcontrol_frame_end( x264_t *h ) +{ + x264_speedcontrol_t *sc = h->sc; + if( h->param.sc.b_alt_timer ) + sc->cpu_time = x264_mdate() - sc->timestamp; +} + +void x264_speedcontrol_frame( x264_t *h ) +{ + x264_speedcontrol_t *sc = h->sc; + int64_t t, delta_t, delta_buffer; + int delta_f; + + x264_emms(); + + // update buffer state after encoding and outputting the previous frame(s) + t = x264_mdate(); + delta_f = h->i_frame - sc->prev_frame; + delta_t = t - sc->timestamp; + delta_buffer = delta_f * sc->spf / h->param.sc.f_speed - delta_t; + sc->buffer_fill += delta_buffer; + sc->prev_frame = h->i_frame; + sc->timestamp = t; + + // update the time predictor + if( delta_f ) + { + int cpu_time = h->param.sc.b_alt_timer ? sc->cpu_time : delta_t; + float decay = powf( sc->cplx_decay, delta_f ); + sc->cplx_num *= decay; + sc->cplx_den *= decay; + sc->cplx_num += cpu_time / presets[sc->preset].time; + sc->cplx_den += delta_f; + + sc->stat.avg_preset += sc->preset * delta_f; + sc->stat.den += delta_f; + } + sc->stat.min_buffer = X264_MIN( sc->buffer_fill, sc->stat.min_buffer ); + sc->stat.max_buffer = X264_MAX( sc->buffer_fill, sc->stat.max_buffer ); + + if( sc->buffer_fill > sc->buffer_size ) // oops, cpu was idle + { + // not really an error, but we'll warn for debugging purposes + static int64_t idle_t = 0, print_interval = 0; + idle_t += sc->buffer_fill - sc->buffer_size; + if( t - print_interval > 1e6 ) + { + x264_log( h, X264_LOG_WARNING, "speedcontrol idle (%.6f sec)\n", idle_t/1e6 ); + print_interval = t; + idle_t = 0; + } + sc->buffer_fill = sc->buffer_size; + } + else if( sc->buffer_fill < 0 && delta_buffer < 0 ) // oops, we're late + { + // don't clip fullness to 0; we'll hope the real buffer was bigger than + // specified, and maybe we can catch up. if the application had to drop + // frames, then it should override the buffer fullness (FIXME implement this). + x264_log( h, X264_LOG_WARNING, "speedcontrol underflow (%.6f sec)\n", sc->buffer_fill/1e6 ); + } + + { + // pick the preset that should return the buffer to 3/4-full within a time + // specified by compensation_period + float target = sc->spf / h->param.sc.f_speed + * (sc->buffer_fill + sc->compensation_period) + / (sc->buffer_size*3/4 + sc->compensation_period); + float cplx = sc->cplx_num / sc->cplx_den; + float set, t0, t1; + float filled = (float) sc->buffer_fill / sc->buffer_size; + int i; + t0 = presets[0].time * cplx; + for( i=1;; i++ ) + { + t1 = presets[i].time * cplx; + if( t1 >= target || i == PRESETS-1 ) + break; + t0 = t1; + } + // linear interpolation between states + set = i-1 + (target - t0) / (t1 - t0); + // Even if our time estimations in the PRESETS array are off + // this will push us towards our target fullness + set += (20 * (filled-0.75)); + set = x264_clip3f(set,0,PRESETS-1); + apply_preset( h, dither( sc, set ) ); + + // FIXME + if (h->param.i_log_level >= X264_LOG_DEBUG) + { + static float cpu, wall, tgt, den; + float decay = 1-1/100.; + cpu = cpu*decay + sc->cpu_time; + wall = wall*decay + delta_t; + tgt = tgt*decay + target; + den = den*decay + 1; + fprintf( stderr, "speed: %.2f %d[%.5f] (t/c/w: %6.0f/%6.0f/%6.0f = %.4f) fps=%.2f\r", + set, sc->preset, (float)sc->buffer_fill / sc->buffer_size, + tgt/den, cpu/den, wall/den, cpu/wall, 1e6*den/wall ); + } + } + +} + +void x264_speedcontrol_sync( x264_t *h, float f_buffer_fill, int i_buffer_size ) +{ + x264_speedcontrol_t *sc = h->sc; + if( !h->param.sc.i_buffer_size ) + return; + if( i_buffer_size ) + h->param.sc.i_buffer_size = X264_MAX( 3, h->param.sc.i_buffer_size ); + sc->buffer_size = h->param.sc.i_buffer_size * 1e6 / sc->fps; + sc->buffer_fill = sc->buffer_size * f_buffer_fill; +} From aad01e1ddd2a4a2965461808a1f45c6b5a81369e Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Mon, 21 Feb 2011 02:57:27 +0000 Subject: [PATCH 02/81] Merge speedcontrol. --- Makefile | 1 + common/common.c | 15 +++++++++++++++ common/common.h | 2 ++ encoder/encoder.c | 14 ++++++++++++++ encoder/ratecontrol.h | 7 +++++++ x264.c | 10 ++++++++++ x264.h | 14 ++++++++++++++ 7 files changed, 63 insertions(+) diff --git a/Makefile b/Makefile index 560ba901..1ed6da55 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,7 @@ SRCS = common/mc.c common/predict.c common/pixel.c common/macroblock.c \ common/mvpred.c common/bitstream.c \ encoder/analyse.c encoder/me.c encoder/ratecontrol.c \ encoder/set.c encoder/macroblock.c encoder/cabac.c \ + encoder/speed.c \ encoder/cavlc.c encoder/encoder.c encoder/lookahead.c SRCCLI = x264.c input/input.c input/timecode.c input/raw.c input/y4m.c \ diff --git a/common/common.c b/common/common.c index 5c9a72dd..fb46fd31 100644 --- a/common/common.c +++ b/common/common.c @@ -119,6 +119,11 @@ void x264_param_default( x264_param_t *param ) param->rc.i_zones = 0; param->rc.b_mb_tree = 1; + // speedcontrol + param->sc.f_speed = 0; + param->sc.i_buffer_size = 30; + param->sc.f_buffer_init = 0.75; + /* Log */ param->pf_log = x264_log_default; param->p_log_private = NULL; @@ -986,6 +991,14 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value ) p->rc.f_complexity_blur = atof(value); OPT("zones") p->rc.psz_zones = strdup(value); + OPT("speed") + p->sc.f_speed = atof(value); + OPT("speed-bufsize") + p->sc.i_buffer_size = atoi(value); + OPT("speed-init") + p->sc.f_buffer_init = atof(value); + OPT("speed-alt-timer") + p->sc.b_alt_timer = atobool(value); OPT("crop-rect") b_error |= sscanf( value, "%u,%u,%u,%u", &p->crop_rect.i_left, &p->crop_rect.i_top, &p->crop_rect.i_right, &p->crop_rect.i_bottom ) != 4; @@ -1265,6 +1278,8 @@ char *x264_param2string( x264_param_t *p, int b_res ) s += sprintf( s, "bitdepth=%d ", BIT_DEPTH ); } + // FIXME speedcontrol stuff + s += sprintf( s, "cabac=%d", p->b_cabac ); s += sprintf( s, " ref=%d", p->i_frame_reference ); s += sprintf( s, " deblock=%d:%d:%d", p->b_deblocking_filter, diff --git a/common/common.h b/common/common.h index 5763c2ed..3c058ad8 100644 --- a/common/common.h +++ b/common/common.h @@ -424,6 +424,7 @@ typedef struct x264_lookahead_t } x264_lookahead_t; typedef struct x264_ratecontrol_t x264_ratecontrol_t; +typedef struct x264_speedcontrol_t x264_speedcontrol_t; typedef struct x264_left_table_t { @@ -825,6 +826,7 @@ struct x264_t /* rate control encoding only */ x264_ratecontrol_t *rc; + x264_speedcontrol_t *sc; /* stats */ struct diff --git a/encoder/encoder.c b/encoder/encoder.c index 72d716f2..5c056d57 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -894,6 +894,8 @@ static int x264_validate_parameters( x264_t *h, int b_open ) h->param.rc.f_qblur = 0; if( h->param.rc.f_complexity_blur < 0 ) h->param.rc.f_complexity_blur = 0; + if( h->param.sc.i_buffer_size < 0 || h->param.sc.f_speed <= 0 ) + h->param.sc.i_buffer_size = 0; h->param.i_sps_id &= 31; @@ -1186,6 +1188,10 @@ x264_t *x264_encoder_open( x264_param_t *param ) mbcmp_init( h ); chroma_dsp_init( h ); + if( h->param.sc.i_buffer_size ) + x264_speedcontrol_new( h ); + + p = buf + sprintf( buf, "using cpu capabilities:" ); for( int i = 0; x264_cpu_names[i].flags; i++ ) { @@ -3005,6 +3011,10 @@ int x264_encoder_encode( x264_t *h, if( h->fenc->b_keyframe && h->param.b_intra_refresh ) h->i_cpb_delay_pir_offset = h->fenc->i_cpb_delay; + /* Init the speed control */ + if( h->param.sc.i_buffer_size ) + x264_speedcontrol_frame( h ); + /* Init the rate control */ /* FIXME: Include slice header bit cost. */ x264_ratecontrol_start( h, h->fenc->i_qpplus1, overhead*8 ); @@ -3162,6 +3172,9 @@ static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current, x264_noise_reduction_update( h ); + if( h->param.sc.i_buffer_size ) + x264_speedcontrol_frame_end( h ); + /* ---------------------- Compute/Print statistics --------------------- */ x264_thread_sync_stat( h, h->thread[0] ); @@ -3603,6 +3616,7 @@ void x264_encoder_close ( x264_t *h ) /* rc */ x264_ratecontrol_delete( h ); + x264_speedcontrol_delete( h ); /* param */ if( h->param.rc.psz_stat_out ) diff --git a/encoder/ratecontrol.h b/encoder/ratecontrol.h index f5aa9a83..00a424fe 100644 --- a/encoder/ratecontrol.h +++ b/encoder/ratecontrol.h @@ -63,5 +63,12 @@ int x264_weighted_reference_duplicate( x264_t *h, int i_ref, const x264_weight_t void x264_threads_distribute_ratecontrol( x264_t *h ); void x264_threads_merge_ratecontrol( x264_t *h ); void x264_hrd_fullness( x264_t *h ); + +// speedcontrol +void x264_speedcontrol_new( x264_t *h ); +void x264_speedcontrol_delete( x264_t *h ); +void x264_speedcontrol_frame( x264_t *h ); +void x264_speedcontrol_frame_end( x264_t *h ); + #endif diff --git a/x264.c b/x264.c index d735ab4b..5c3385f9 100644 --- a/x264.c +++ b/x264.c @@ -654,6 +654,14 @@ static void help( x264_param_t *defaults, int longhelp ) " K= depending on open-gop setting\n" " QPs are restricted by qpmin/qpmax.\n" ); H1( "\n" ); + + H1( "Speedcontrol:\n" ); + H1( "\n" ); + H1( " --speed Automatically adjust other options to achieve this\n" ); + H1( " fraction of realtime.\n" ); + H1( " --speed-bufsize Averaging period for speed. (in frames) [%d]\n", defaults->sc.i_buffer_size ); + H1( "\n" ); + H1( "Analysis:\n" ); H1( "\n" ); H1( " -A, --partitions Partitions to consider [\"p8x8,b8x8,i8x8,i4x4\"]\n" @@ -955,6 +963,8 @@ static struct option long_options[] = { "cplxblur", required_argument, NULL, 0 }, { "zones", required_argument, NULL, 0 }, { "qpfile", required_argument, NULL, OPT_QPFILE }, + { "speed", required_argument, NULL, 0 }, + { "speed-bufsize", required_argument, NULL, 0 }, { "threads", required_argument, NULL, 0 }, { "sliced-threads", no_argument, NULL, 0 }, { "no-sliced-threads", no_argument, NULL, 0 }, diff --git a/x264.h b/x264.h index 5e88e48e..5df09059 100644 --- a/x264.h +++ b/x264.h @@ -407,6 +407,15 @@ typedef struct x264_param_t /* frame packing arrangement flag */ int i_frame_packing; + /* Speed control parameters */ + struct + { + float f_speed; /* ratio from realtime */ + int i_buffer_size; /* number of frames */ + float f_buffer_init; /* fraction of size */ + int b_alt_timer; /* use a different method of measuring encode time FIXME */ + } sc; + /* Muxing parameters */ int b_aud; /* generate access unit delimiters */ int b_repeat_headers; /* put SPS/PPS before each keyframe */ @@ -836,4 +845,9 @@ void x264_encoder_intra_refresh( x264_t * ); * Returns 0 on success, negative on failure. */ int x264_encoder_invalidate_reference( x264_t *, int64_t pts ); +/* x264_speedcontrol_sync: + * override speedcontrol's internal clock */ +void x264_speedcontrol_sync( x264_t *, float f_buffer_fill, int i_buffer_size ); + + #endif From 772a3b7ee4574622868db85d1b37f61fb5997575 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 9 Nov 2010 17:10:18 +0000 Subject: [PATCH 03/81] Add "Fake HRD". This writes Buffering Period SEI but sets nal_hrd_parameters_present_flag to zero. This allows more flexible T-STD compliant TS muxing and also to workaround bugs in MPEG-2 Systems. The x264_hrd_t struct should be used for PTS and DTS. Fake HRD is not necessary for Blu-Ray. --- encoder/encoder.c | 5 +++-- encoder/set.c | 2 +- x264.h | 5 ++++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/encoder/encoder.c b/encoder/encoder.c index 5c056d57..3e90f681 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -910,8 +910,8 @@ static int x264_validate_parameters( x264_t *h, int b_open ) h->param.i_nal_hrd = X264_NAL_HRD_NONE; } - if( h->param.i_nal_hrd == X264_NAL_HRD_CBR && - (h->param.rc.i_bitrate != h->param.rc.i_vbv_max_bitrate || !h->param.rc.i_vbv_max_bitrate) ) + if( (h->param.i_nal_hrd == X264_NAL_HRD_CBR || h->param.i_nal_hrd == X264_NAL_HRD_FAKE_CBR) && + (h->param.rc.i_bitrate != h->param.rc.i_vbv_max_bitrate || !h->param.rc.i_vbv_max_bitrate) ) { x264_log( h, X264_LOG_WARNING, "CBR HRD requires constant bitrate\n" ); h->param.i_nal_hrd = X264_NAL_HRD_VBR; @@ -3083,6 +3083,7 @@ static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current, } x264_emms(); + /* generate buffering period sei and insert it into place */ if( h->i_thread_frames > 1 && h->fenc->b_keyframe && h->sps->vui.b_nal_hrd_parameters_present ) { diff --git a/encoder/set.c b/encoder/set.c index 876176af..8c556b26 100644 --- a/encoder/set.c +++ b/encoder/set.c @@ -244,7 +244,7 @@ void x264_sps_init( x264_sps_t *sps, int i_id, x264_param_t *param ) } sps->vui.b_vcl_hrd_parameters_present = 0; // we don't support VCL HRD - sps->vui.b_nal_hrd_parameters_present = !!param->i_nal_hrd; + sps->vui.b_nal_hrd_parameters_present = param->i_nal_hrd == X264_NAL_HRD_VBR || param->i_nal_hrd == X264_NAL_HRD_CBR; sps->vui.b_pic_struct_present = param->b_pic_struct; // NOTE: HRD related parts of the SPS are initialised in x264_ratecontrol_init_reconfigurable diff --git a/x264.h b/x264.h index 5df09059..2201dfc7 100644 --- a/x264.h +++ b/x264.h @@ -175,7 +175,8 @@ static const char * const x264_fullrange_names[] = { "off", "on", 0 }; static const char * const x264_colorprim_names[] = { "", "bt709", "undef", "", "bt470m", "bt470bg", "smpte170m", "smpte240m", "film", 0 }; static const char * const x264_transfer_names[] = { "", "bt709", "undef", "", "bt470m", "bt470bg", "smpte170m", "smpte240m", "linear", "log100", "log316", 0 }; static const char * const x264_colmatrix_names[] = { "GBR", "bt709", "undef", "", "fcc", "bt470bg", "smpte170m", "smpte240m", "YCgCo", 0 }; -static const char * const x264_nal_hrd_names[] = { "none", "vbr", "cbr", 0 }; +static const char * const x264_nal_hrd_names[] = { "none", "vbr", "cbr", "fakevbr", "fakecbr", 0 }; +static const char * const x264_open_gop_names[] = { "none", "normal", "bluray", 0 }; /* Colorspace type */ #define X264_CSP_MASK 0x00ff /* */ @@ -221,6 +222,8 @@ static const char * const x264_nal_hrd_names[] = { "none", "vbr", "cbr", 0 }; #define X264_NAL_HRD_NONE 0 #define X264_NAL_HRD_VBR 1 #define X264_NAL_HRD_CBR 2 +#define X264_NAL_HRD_FAKE_VBR 3 +#define X264_NAL_HRD_FAKE_CBR 4 /* Zones: override ratecontrol or other options for specific sections of the video. * See x264_encoder_reconfig() for which options can be changed. From 394c8b957f359c0705978787f6cc5534da294556 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Sun, 27 Feb 2011 00:07:24 +0000 Subject: [PATCH 04/81] Use a better API for speedcontrol on Linux. --- common/osdep.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/common/osdep.c b/common/osdep.c index 75936151..b957965e 100644 --- a/common/osdep.c +++ b/common/osdep.c @@ -43,10 +43,15 @@ extern int ptw32_processInitialized; int64_t x264_mdate( void ) { -#if SYS_WINDOWS +<<<<<<< HEAD +#ifdef __MINGW32__ struct timeb tb; ftime( &tb ); return ((int64_t)tb.time * 1000 + (int64_t)tb.millitm) * 1000; +#elif __LINUX__ + struct timespec ts_current; + clock_gettime( CLOCK_MONOTONIC, &ts_current ); + return (int64_t)ts_current.tv_sec * 1000000 + (int64_t)ts_current.tv_usec; #else struct timeval tv_date; gettimeofday( &tv_date, NULL ); From 86cca25d55359873f53d85af30d1d2220bde8404 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Thu, 3 Mar 2011 10:20:42 +0000 Subject: [PATCH 05/81] Pass through user data. --- common/frame.c | 1 + common/frame.h | 3 +++ encoder/encoder.c | 2 +- x264.h | 3 +++ 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/common/frame.c b/common/frame.c index 04e8afaa..5e4a1767 100644 --- a/common/frame.c +++ b/common/frame.c @@ -353,6 +353,7 @@ int x264_frame_copy_picture( x264_t *h, x264_frame_t *dst, x264_picture_t *src ) dst->param = src->param; dst->i_pic_struct = src->i_pic_struct; dst->extra_sei = src->extra_sei; + dst->passthrough_opaque = src->passthrough_opaque; uint8_t *pix[3]; int stride[3]; diff --git a/common/frame.h b/common/frame.h index 0ee68cb2..0d0a5320 100644 --- a/common/frame.h +++ b/common/frame.h @@ -162,6 +162,9 @@ typedef struct x264_frame /* user sei */ x264_sei_t extra_sei; + + /* user data */ + void *passthrough_opaque; } x264_frame_t; /* synchronized frame list */ diff --git a/encoder/encoder.c b/encoder/encoder.c index 3e90f681..f31c14bb 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -3109,7 +3109,7 @@ static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current, /* Set output picture properties */ pic_out->i_type = h->fenc->i_type; - + pic_out->passthrough_opaque = h->fenc->passthrough_opaque; pic_out->b_keyframe = h->fenc->b_keyframe; pic_out->i_pic_struct = h->fenc->i_pic_struct; diff --git a/x264.h b/x264.h index 2201dfc7..ab99d246 100644 --- a/x264.h +++ b/x264.h @@ -739,6 +739,9 @@ typedef struct /* private user data. libx264 doesn't touch this, not even copy it from input to output frames. */ void *opaque; + /* private user data, libx264 doesn't touch this, + copied from input to output frames. */ + void *passthrough_opaque; } x264_picture_t; /* x264_picture_init: From ebeed246a2faac32bfcc5c44d1e605c3f3d96784 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Mon, 7 Mar 2011 10:47:22 +0000 Subject: [PATCH 06/81] Turn off warning temporarily. --- encoder/ratecontrol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index 4853432e..4606427c 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -554,7 +554,7 @@ void x264_ratecontrol_init_reconfigurable( x264_t *h, int b_init ) } else if( h->param.i_nal_hrd && !b_init ) { - x264_log( h, X264_LOG_WARNING, "VBV parameters cannot be changed when NAL HRD is in use\n" ); + //x264_log( h, X264_LOG_WARNING, "VBV parameters cannot be changed when NAL HRD is in use\n" ); return; } h->sps->vui.hrd.i_bit_rate_unscaled = vbv_max_bitrate; From 36070c51257719f6df9f97ff9f69d0fc2db11e1f Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Mon, 7 Mar 2011 14:24:29 +0000 Subject: [PATCH 07/81] Export profile and actual vbv values. --- encoder/encoder.c | 2 ++ encoder/ratecontrol.c | 4 ++-- x264.h | 4 ++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/encoder/encoder.c b/encoder/encoder.c index f31c14bb..ff9eed10 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -1097,6 +1097,8 @@ x264_t *x264_encoder_open( x264_param_t *param ) } x264_sps_init( h->sps, h->param.i_sps_id, &h->param ); + h->param.i_profile = h->sps->i_profile_idc; + x264_pps_init( h->pps, h->param.i_sps_id, &h->param, h->sps ); x264_set_aspect_ratio( h, &h->param, 1 ); diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index 4606427c..75d75356 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -549,8 +549,8 @@ void x264_ratecontrol_init_reconfigurable( x264_t *h, int b_init ) #undef MAX_DURATION - vbv_buffer_size = h->sps->vui.hrd.i_cpb_size_unscaled; - vbv_max_bitrate = h->sps->vui.hrd.i_bit_rate_unscaled; + vbv_buffer_size = h->param.rc.i_vbv_buffer_size_actual = h->sps->vui.hrd.i_cpb_size_unscaled; + vbv_max_bitrate = h->param.rc.i_vbv_max_bitrate_actual = h->sps->vui.hrd.i_bit_rate_unscaled; } else if( h->param.i_nal_hrd && !b_init ) { diff --git a/x264.h b/x264.h index ab99d246..a831a3a8 100644 --- a/x264.h +++ b/x264.h @@ -253,6 +253,7 @@ typedef struct x264_param_t int i_csp; /* CSP of encoded bitstream */ int i_level_idc; int i_frame_total; /* number of frames to encode if known, else 0 */ + int i_profile; /* Output Only */ /* NAL HRD * Uses Buffering and Picture Timing SEIs to signal HRD @@ -377,6 +378,9 @@ typedef struct x264_param_t float f_ip_factor; float f_pb_factor; + int i_vbv_max_bitrate_actual; /* Output only when HRD enabled */ + int i_vbv_buffer_size_actual; /* Output only when HRD enabled */ + int i_aq_mode; /* psy adaptive QP. (X264_AQ_*) */ float f_aq_strength; int b_mb_tree; /* Macroblock-tree ratecontrol. */ From 4ce2a2e89e90d21c73b35aeaed3a3581ade0070e Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 8 Mar 2011 14:45:04 +0000 Subject: [PATCH 08/81] Start counting when the first frame is encoded, not when x264_encoder_open is called. --- encoder/speed.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/encoder/speed.c b/encoder/speed.c index 7b5c400a..09917a30 100644 --- a/encoder/speed.c +++ b/encoder/speed.c @@ -21,7 +21,10 @@ struct x264_speedcontrol_t float dither; x264_param_t user_param; - struct { + int first; + + struct + { int64_t min_buffer, max_buffer; double avg_preset; int den; @@ -52,6 +55,7 @@ void x264_speedcontrol_new( x264_t *h ) sc->stat.min_buffer = sc->buffer_size; sc->stat.max_buffer = 0; sc->user_param = h->param; + sc->first = 1; } void x264_speedcontrol_delete( x264_t *h ) @@ -157,7 +161,14 @@ void x264_speedcontrol_frame( x264_t *h ) x264_emms(); // update buffer state after encoding and outputting the previous frame(s) - t = x264_mdate(); + if( sc->first ) + { + t = sc->timestamp; + sc->first = 0; + } + else + t = x264_mdate(); + delta_f = h->i_frame - sc->prev_frame; delta_t = t - sc->timestamp; delta_buffer = delta_f * sc->spf / h->param.sc.f_speed - delta_t; From 14234b9ce3541180f2d55cb1ca2f4e8006830510 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 8 Mar 2011 14:57:03 +0000 Subject: [PATCH 09/81] Fix 10L --- encoder/speed.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encoder/speed.c b/encoder/speed.c index 09917a30..cd73fb90 100644 --- a/encoder/speed.c +++ b/encoder/speed.c @@ -163,7 +163,7 @@ void x264_speedcontrol_frame( x264_t *h ) // update buffer state after encoding and outputting the previous frame(s) if( sc->first ) { - t = sc->timestamp; + t = sc->timestamp = x264_mdate(); sc->first = 0; } else From 3b628bbbd1972ad1e16b62cd2e02d635359cef7f Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 8 Mar 2011 17:50:52 +0000 Subject: [PATCH 10/81] Fix Linux timing function and build. --- common/osdep.c | 4 ++-- configure | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/osdep.c b/common/osdep.c index b957965e..816b03f2 100644 --- a/common/osdep.c +++ b/common/osdep.c @@ -48,10 +48,10 @@ int64_t x264_mdate( void ) struct timeb tb; ftime( &tb ); return ((int64_t)tb.time * 1000 + (int64_t)tb.millitm) * 1000; -#elif __LINUX__ +#elif SYS_LINUX struct timespec ts_current; clock_gettime( CLOCK_MONOTONIC, &ts_current ); - return (int64_t)ts_current.tv_sec * 1000000 + (int64_t)ts_current.tv_usec; + return (int64_t)ts_current.tv_sec * 1000000 + (int64_t)ts_current.tv_nsec / 1000; #else struct timeval tv_date; gettimeofday( &tv_date, NULL ); diff --git a/configure b/configure index de6afd9c..ad35db18 100755 --- a/configure +++ b/configure @@ -444,7 +444,7 @@ case $host_os in *linux*) SYS="LINUX" define HAVE_MALLOC_H - LDFLAGS="$LDFLAGS -lm" + LDFLAGS="$LDFLAGS -lm -lrt" ;; gnu*) SYS="HURD" From 0a39eda08344d96471fae931c9d06e82d5e8367e Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Wed, 9 Mar 2011 11:55:39 +0000 Subject: [PATCH 11/81] Change defaults and use x264_log --- common/common.c | 2 +- encoder/speed.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/common.c b/common/common.c index fb46fd31..37bc249f 100644 --- a/common/common.c +++ b/common/common.c @@ -121,7 +121,7 @@ void x264_param_default( x264_param_t *param ) // speedcontrol param->sc.f_speed = 0; - param->sc.i_buffer_size = 30; + param->sc.i_buffer_size = 12; param->sc.f_buffer_init = 0.75; /* Log */ diff --git a/encoder/speed.c b/encoder/speed.c index cd73fb90..7d4a1d36 100644 --- a/encoder/speed.c +++ b/encoder/speed.c @@ -248,7 +248,7 @@ void x264_speedcontrol_frame( x264_t *h ) wall = wall*decay + delta_t; tgt = tgt*decay + target; den = den*decay + 1; - fprintf( stderr, "speed: %.2f %d[%.5f] (t/c/w: %6.0f/%6.0f/%6.0f = %.4f) fps=%.2f\r", + x264_log( h, X264_LOG_DEBUG, "speed: %.2f %d[%.5f] (t/c/w: %6.0f/%6.0f/%6.0f = %.4f) fps=%.2f\r", set, sc->preset, (float)sc->buffer_fill / sc->buffer_size, tgt/den, cpu/den, wall/den, cpu/wall, 1e6*den/wall ); } From e8de85d5ba52c72f675d2368ab9b70e991d6e0c0 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Thu, 10 Mar 2011 15:57:02 +0000 Subject: [PATCH 12/81] Fix merge problem. --- encoder/ratecontrol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index 75d75356..731872ec 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -1714,7 +1714,7 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) *filler = update_vbv( h, bits ); rc->filler_bits_sum += *filler * 8; - if( h->sps->vui.b_nal_hrd_parameters_present ) + if( h->param.i_nal_hrd ) { if( h->fenc->i_frame == 0 ) { From e39fe19793161ed2e4e8cbfda161e6abf568821b Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Thu, 12 May 2011 16:47:54 +0100 Subject: [PATCH 13/81] Fix Fake CBR --- encoder/encoder.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/encoder/encoder.c b/encoder/encoder.c index ff9eed10..2a008ef8 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -902,7 +902,7 @@ static int x264_validate_parameters( x264_t *h, int b_open ) if( PARAM_INTERLACED ) h->param.b_pic_struct = 1; - h->param.i_nal_hrd = x264_clip3( h->param.i_nal_hrd, X264_NAL_HRD_NONE, X264_NAL_HRD_CBR ); + h->param.i_nal_hrd = x264_clip3( h->param.i_nal_hrd, X264_NAL_HRD_NONE, X264_NAL_HRD_FAKE_CBR ); if( h->param.i_nal_hrd && !h->param.rc.i_vbv_buffer_size ) { @@ -914,7 +914,7 @@ static int x264_validate_parameters( x264_t *h, int b_open ) (h->param.rc.i_bitrate != h->param.rc.i_vbv_max_bitrate || !h->param.rc.i_vbv_max_bitrate) ) { x264_log( h, X264_LOG_WARNING, "CBR HRD requires constant bitrate\n" ); - h->param.i_nal_hrd = X264_NAL_HRD_VBR; + h->param.i_nal_hrd = h->param.i_nal_hrd == X264_NAL_HRD_CBR ? X264_NAL_HRD_VBR : X264_NAL_HRD_FAKE_CBR; } /* ensure the booleans are 0 or 1 so they can be used in math */ From d15a8881200b410dd24b6d45860b2a75ba7797ed Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 19 Jul 2011 13:15:56 +0100 Subject: [PATCH 14/81] Add new speedcontrol timings. --- encoder/speed.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/encoder/speed.c b/encoder/speed.c index 7d4a1d36..47eeb64b 100644 --- a/encoder/speed.c +++ b/encoder/speed.c @@ -106,19 +106,19 @@ static const sc_preset_t presets[PRESETS] = #define I8 X264_ANALYSE_I8x8 #define P8 X264_ANALYSE_PSUB16x16 #define B8 X264_ANALYSE_BSUB16x16 -/*0*/ { .time=1.060, .subme=1, .me=X264_ME_DIA, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=0, .psy_rd=0 }, -/*1*/ { .time=1.120, .subme=1, .me=X264_ME_DIA, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=I8|I4, .psy_rd=0 }, -/*2*/ { .time=1.440, .subme=3, .me=X264_ME_HEX, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=I8|I4, .psy_rd=0 }, -/*3*/ { .time=1.620, .subme=5, .me=X264_ME_HEX, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=I8|I4, .psy_rd=1.0 }, -/*4*/ { .time=2.660, .subme=6, .me=X264_ME_HEX, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=I8|I4, .psy_rd=1.0 }, -/*5*/ { .time=3.560, .subme=6, .me=X264_ME_HEX, .refs=1, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4, .psy_rd=1.0 }, -/*6*/ { .time=4.640, .subme=6, .me=X264_ME_HEX, .refs=2, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4, .psy_rd=1.0 }, -/*7*/ { .time=5.190, .subme=7, .me=X264_ME_HEX, .refs=2, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4, .psy_rd=1.0 }, -/*8*/ { .time=6.190, .subme=7, .me=X264_ME_HEX, .refs=2, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 }, -/*9*/ { .time=6.920, .subme=7, .me=X264_ME_HEX, .refs=3, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 }, -/*10*/ { .time=7.070, .subme=8, .me=X264_ME_HEX, .refs=3, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 }, -/*11*/ { .time=8.800, .subme=8, .me=X264_ME_UMH, .refs=3, .mix=1, .chromame=1, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 }, -/*12*/ { .time=18.570, .subme=8, .me=X264_ME_UMH, .refs=3, .mix=1, .chromame=1, .trellis=2, .partitions=I8|I4|P8|B8, .psy_rd=1.0 } +/*0*/ { .time=1.000, .subme=1, .me=X264_ME_DIA, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=0, .psy_rd=0 }, +/*1*/ { .time=1.009, .subme=1, .me=X264_ME_DIA, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=I8|I4, .psy_rd=0 }, +/*2*/ { .time=1.843, .subme=3, .me=X264_ME_HEX, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=I8|I4, .psy_rd=0 }, +/*3*/ { .time=1.984, .subme=5, .me=X264_ME_HEX, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=I8|I4, .psy_rd=1.0 }, +/*4*/ { .time=2.289, .subme=6, .me=X264_ME_HEX, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=I8|I4, .psy_rd=1.0 }, +/*5*/ { .time=3.113, .subme=6, .me=X264_ME_HEX, .refs=1, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4, .psy_rd=1.0 }, +/*6*/ { .time=3.400, .subme=6, .me=X264_ME_HEX, .refs=2, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4, .psy_rd=1.0 }, +/*7*/ { .time=3.755, .subme=7, .me=X264_ME_HEX, .refs=2, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4, .psy_rd=1.0 }, +/*8*/ { .time=4.592, .subme=7, .me=X264_ME_HEX, .refs=2, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 }, +/*9*/ { .time=4.730, .subme=7, .me=X264_ME_HEX, .refs=3, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 }, +/*10*/ { .time=5.453, .subme=8, .me=X264_ME_HEX, .refs=3, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 }, +/*11*/ { .time=8.277, .subme=8, .me=X264_ME_UMH, .refs=3, .mix=1, .chromame=1, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 }, +/*12*/ { .time=8.410, .subme=8, .me=X264_ME_UMH, .refs=4, .mix=1, .chromame=1, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 } }; static void apply_preset( x264_t *h, int preset ) From 40d893f2f96622e04dbe9ec69d08e1102a002272 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Wed, 27 Jul 2011 16:27:41 +0100 Subject: [PATCH 15/81] Make speedcontrol idle an informational log message. --- encoder/speed.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encoder/speed.c b/encoder/speed.c index 47eeb64b..93343a40 100644 --- a/encoder/speed.c +++ b/encoder/speed.c @@ -199,7 +199,7 @@ void x264_speedcontrol_frame( x264_t *h ) idle_t += sc->buffer_fill - sc->buffer_size; if( t - print_interval > 1e6 ) { - x264_log( h, X264_LOG_WARNING, "speedcontrol idle (%.6f sec)\n", idle_t/1e6 ); + x264_log( h, X264_LOG_INFO, "speedcontrol idle (%.6f sec)\n", idle_t/1e6 ); print_interval = t; idle_t = 0; } From c015eeda7fce4c0eecf09d7eb673e54d064c5b7a Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Fri, 29 Jul 2011 17:41:25 +0100 Subject: [PATCH 16/81] Only use 10 speedcontrol presets for now. --- encoder/speed.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encoder/speed.c b/encoder/speed.c index 93343a40..7bf370ef 100644 --- a/encoder/speed.c +++ b/encoder/speed.c @@ -99,7 +99,7 @@ typedef struct float psy_trellis; } sc_preset_t; -#define PRESETS 13 +#define PRESETS 10 static const sc_preset_t presets[PRESETS] = { #define I4 X264_ANALYSE_I4x4 From 17e72e71e20802b2fd047fa1f14e548613b802ec Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Fri, 29 Jul 2011 17:56:06 +0100 Subject: [PATCH 17/81] Pre-place keyframes to fix long stalls when PB... becomes IP... and a new path has to be calculated. THIS BREAKS OPEN-GOP BLU-RAY and doesn't fix b-adapt=2. --- encoder/slicetype.c | 112 +++++++++++++++++++++++++++++--------------- 1 file changed, 74 insertions(+), 38 deletions(-) diff --git a/encoder/slicetype.c b/encoder/slicetype.c index 7ea493b0..4085c3f1 100644 --- a/encoder/slicetype.c +++ b/encoder/slicetype.c @@ -1309,7 +1309,7 @@ void x264_slicetype_analyse( x264_t *h, int keyframe ) if( !h->lookahead->last_nonb ) return; frames[0] = h->lookahead->last_nonb; - for( framecnt = 0; framecnt < i_max_search && h->lookahead->next.list[framecnt]->i_type == X264_TYPE_AUTO; framecnt++ ) + for( framecnt = 0; framecnt < i_max_search; framecnt++ ) frames[framecnt+1] = h->lookahead->next.list[framecnt]; x264_lowres_context_init( h, &a ); @@ -1341,7 +1341,7 @@ void x264_slicetype_analyse( x264_t *h, int keyframe ) int num_bframes = 0; int num_analysed_frames = num_frames; int reset_start; - if( h->param.i_scenecut_threshold && scenecut( h, &a, frames, 0, 1, 1, orig_num_frames, i_max_search ) ) + if( h->param.i_scenecut_threshold && !IS_INTRA( frames[1]->i_type ) && scenecut( h, &a, frames, 0, 1, 1, orig_num_frames, i_max_search ) ) { frames[1]->i_type = X264_TYPE_I; return; @@ -1365,12 +1365,25 @@ void x264_slicetype_analyse( x264_t *h, int keyframe ) for( int j = 1; j < num_frames; j++ ) frames[j]->i_type = best_paths[best_path_index][j-1] == 'B' ? X264_TYPE_B : X264_TYPE_P; } - frames[num_frames]->i_type = X264_TYPE_P; + if( !frames[num_frames]->b_keyframe ) + frames[num_frames]->i_type = X264_TYPE_P; } else if( h->param.i_bframe_adaptive == X264_B_ADAPT_FAST ) { for( int i = 0; i <= num_frames-2; ) { + if( frames[i+1]->b_keyframe ) + { + i++; + continue; + } + + if( frames[i+2]->b_keyframe ) + { + frames[i+1]->i_type = X264_TYPE_B; + i += 2; + continue; + } cost2p1 = x264_slicetype_frame_cost( h, &a, frames, i+0, i+2, i+2, 1 ); if( frames[i+2]->i_intra_mbs[2] > i_mb_count / 2 ) { @@ -1399,16 +1412,20 @@ void x264_slicetype_analyse( x264_t *h, int keyframe ) int j; for( j = i+2; j <= X264_MIN( i+h->param.i_bframe, num_frames-1 ); j++ ) { + if( frames[j]->b_keyframe ) + break; int pthresh = X264_MAX(INTER_THRESH - P_SENS_BIAS * (j-i-1), INTER_THRESH/10); int pcost = x264_slicetype_frame_cost( h, &a, frames, i+0, j+1, j+1, 1 ); if( pcost > pthresh*i_mb_count || frames[j+1]->i_intra_mbs[j-i+1] > i_mb_count/3 ) break; frames[j]->i_type = X264_TYPE_B; } - frames[j]->i_type = X264_TYPE_P; + if( !frames[j]->b_keyframe ) + frames[j]->i_type = X264_TYPE_P; i = j; } - frames[num_frames]->i_type = X264_TYPE_P; + if( !frames[num_frames]->b_keyframe ) + frames[num_frames]->i_type = X264_TYPE_P; num_bframes = 0; while( num_bframes < num_frames && frames[num_bframes+1]->i_type == X264_TYPE_B ) num_bframes++; @@ -1417,8 +1434,12 @@ void x264_slicetype_analyse( x264_t *h, int keyframe ) { num_bframes = X264_MIN(num_frames-1, h->param.i_bframe); for( int j = 1; j < num_frames; j++ ) - frames[j]->i_type = (j%(num_bframes+1)) ? X264_TYPE_B : X264_TYPE_P; - frames[num_frames]->i_type = X264_TYPE_P; + { + if( !frames[j]->b_keyframe ) + frames[j]->i_type = (j%(num_bframes+1)) ? X264_TYPE_B : X264_TYPE_P; + } + if( !frames[num_frames]->b_keyframe ) + frames[num_frames]->i_type = X264_TYPE_P; } /* Check scenecut on the first minigop. */ @@ -1435,7 +1456,10 @@ void x264_slicetype_analyse( x264_t *h, int keyframe ) else { for( int j = 1; j <= num_frames; j++ ) - frames[j]->i_type = X264_TYPE_P; + { + if( !frames[j]->b_keyframe ) + frames[j]->i_type = X264_TYPE_P; + } reset_start = !keyframe + 1; num_bframes = 0; } @@ -1445,6 +1469,7 @@ void x264_slicetype_analyse( x264_t *h, int keyframe ) if( h->param.rc.b_mb_tree ) x264_macroblock_tree( h, &a, frames, X264_MIN(num_frames, h->param.i_keyint_max), keyframe ); +#if 0 /* Enforce keyframe limit. */ if( !h->param.b_intra_refresh ) for( int i = keyint_limit+1; i <= num_frames; i += h->param.i_keyint_max ) @@ -1455,13 +1480,17 @@ void x264_slicetype_analyse( x264_t *h, int keyframe ) while( IS_X264_TYPE_B( frames[i-1]->i_type ) ) i--; } +#endif if( vbv_lookahead ) x264_vbv_lookahead( h, &a, frames, num_frames, keyframe ); - /* Restore frametypes for all frames that haven't actually been decided yet. */ + /* Restore non-keyint frametypes for all frames that haven't actually been decided yet. */ for( int j = reset_start; j <= num_frames; j++ ) - frames[j]->i_type = X264_TYPE_AUTO; + { + if( !frames[j]->b_keyframe ) + frames[j]->i_type = X264_TYPE_AUTO; + } } void x264_slicetype_decide( x264_t *h ) @@ -1512,32 +1541,10 @@ void x264_slicetype_decide( x264_t *h ) h->lookahead->next.list[i]->i_type = x264_ratecontrol_slice_type( h, h->lookahead->next.list[i]->i_frame ); } - else if( (h->param.i_bframe && h->param.i_bframe_adaptive) - || h->param.i_scenecut_threshold - || h->param.rc.b_mb_tree - || (h->param.rc.i_vbv_buffer_size && h->param.rc.i_lookahead) ) - x264_slicetype_analyse( h, 0 ); - for( bframes = 0, brefs = 0;; bframes++ ) + for( int i = 0; i < h->lookahead->next.i_size; i++ ) { - frm = h->lookahead->next.list[bframes]; - if( frm->i_type == X264_TYPE_BREF && h->param.i_bframe_pyramid < X264_B_PYRAMID_NORMAL && - brefs == h->param.i_bframe_pyramid ) - { - frm->i_type = X264_TYPE_B; - x264_log( h, X264_LOG_WARNING, "B-ref at frame %d incompatible with B-pyramid %s \n", - frm->i_frame, x264_b_pyramid_names[h->param.i_bframe_pyramid] ); - } - /* pyramid with multiple B-refs needs a big enough dpb that the preceding P-frame stays available. - smaller dpb could be supported by smart enough use of mmco, but it's easier just to forbid it. */ - else if( frm->i_type == X264_TYPE_BREF && h->param.i_bframe_pyramid == X264_B_PYRAMID_NORMAL && - brefs && h->param.i_frame_reference <= (brefs+3) ) - { - frm->i_type = X264_TYPE_B; - x264_log( h, X264_LOG_WARNING, "B-ref at frame %d incompatible with B-pyramid %s and %d reference frames\n", - frm->i_frame, x264_b_pyramid_names[h->param.i_bframe_pyramid], h->param.i_frame_reference ); - } - + frm = h->lookahead->next.list[i]; if( frm->i_type == X264_TYPE_KEYFRAME ) frm->i_type = h->param.b_open_gop ? X264_TYPE_I : X264_TYPE_IDR; @@ -1552,13 +1559,12 @@ void x264_slicetype_decide( x264_t *h ) if( warn ) x264_log( h, X264_LOG_WARNING, "specified frame type (%d) at %d is not compatible with keyframe interval\n", frm->i_type, frm->i_frame ); } + if( frm->i_type == X264_TYPE_I && frm->i_frame - h->lookahead->i_last_keyframe >= h->param.i_keyint_min ) { if( h->param.b_open_gop ) { h->lookahead->i_last_keyframe = frm->i_frame; // Use display order - if( h->param.b_bluray_compat ) - h->lookahead->i_last_keyframe -= bframes; // Use bluray order frm->b_keyframe = 1; } else @@ -1569,6 +1575,37 @@ void x264_slicetype_decide( x264_t *h ) /* Close GOP */ h->lookahead->i_last_keyframe = frm->i_frame; frm->b_keyframe = 1; + } + } + + if( !h->param.rc.b_stat_read && ((h->param.i_bframe && h->param.i_bframe_adaptive) + || h->param.i_scenecut_threshold + || h->param.rc.b_mb_tree + || (h->param.rc.i_vbv_buffer_size && h->param.rc.i_lookahead)) ) + x264_slicetype_analyse( h, 0, 0 ); + + for( bframes = 0, brefs = 0;; bframes++ ) + { + frm = h->lookahead->next.list[bframes]; + if( frm->i_type == X264_TYPE_BREF && h->param.i_bframe_pyramid < X264_B_PYRAMID_NORMAL && + brefs == h->param.i_bframe_pyramid ) + { + frm->i_type = X264_TYPE_B; + x264_log( h, X264_LOG_WARNING, "B-ref at frame %d incompatible with B-pyramid %s \n", + frm->i_frame, x264_b_pyramid_names[h->param.i_bframe_pyramid] ); + } + /* pyramid with multiple B-refs needs a big enough dpb that the preceding P-frame stays available. + smaller dpb could be supported by smart enough use of mmco, but it's easier just to forbid it. */ + else if( frm->i_type == X264_TYPE_BREF && h->param.i_bframe_pyramid == X264_B_PYRAMID_NORMAL && + brefs && h->param.i_frame_reference <= (brefs+3) ) + { + frm->i_type = X264_TYPE_B; + x264_log( h, X264_LOG_WARNING, "B-ref at frame %d incompatible with B-pyramid %s and %d reference frames\n", + frm->i_frame, x264_b_pyramid_names[h->param.i_bframe_pyramid], h->param.i_frame_reference ); + } + + if( frm->i_type == X264_TYPE_IDR ) + { if( bframes > 0 ) { bframes--; @@ -1576,8 +1613,7 @@ void x264_slicetype_decide( x264_t *h ) } } - if( bframes == h->param.i_bframe || - !h->lookahead->next.list[bframes+1] ) + if( bframes == h->param.i_bframe || !h->lookahead->next.list[bframes+1] ) { if( IS_X264_TYPE_B( frm->i_type ) ) x264_log( h, X264_LOG_WARNING, "specified frame type is not compatible with max B-frames\n" ); From 344404387e5e5fce0b9b0b7de02e3e040ce8fb73 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Fri, 29 Jul 2011 18:21:51 +0100 Subject: [PATCH 18/81] Fix typo in previous patch. --- encoder/slicetype.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encoder/slicetype.c b/encoder/slicetype.c index 4085c3f1..a064a988 100644 --- a/encoder/slicetype.c +++ b/encoder/slicetype.c @@ -1582,7 +1582,7 @@ void x264_slicetype_decide( x264_t *h ) || h->param.i_scenecut_threshold || h->param.rc.b_mb_tree || (h->param.rc.i_vbv_buffer_size && h->param.rc.i_lookahead)) ) - x264_slicetype_analyse( h, 0, 0 ); + x264_slicetype_analyse( h, 0 ); for( bframes = 0, brefs = 0;; bframes++ ) { From 71145581c1197ff8b970ba7ff17968e57dd6951e Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Wed, 24 Aug 2011 19:29:36 +0100 Subject: [PATCH 19/81] Use a 27MHz clock for HRD timing output. There was accumulation of error when using doubles. --- encoder/ratecontrol.c | 30 ++++++------------------------ x264.h | 7 ++----- 2 files changed, 8 insertions(+), 29 deletions(-) diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index 731872ec..5b7ff504 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -155,9 +155,8 @@ struct x264_ratecontrol_t /* hrd stuff */ int initial_cpb_removal_delay; - int initial_cpb_removal_delay_offset; - double nrt_first_access_unit; /* nominal removal time */ - double previous_cpb_final_arrival_time; + int64_t nrt_first_access_unit; /* nominal removal time */ + int64_t previous_cpb_final_arrival_time; uint64_t hrd_multiply_denom; }; @@ -1719,37 +1718,22 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) if( h->fenc->i_frame == 0 ) { // access unit initialises the HRD - h->fenc->hrd_timing.cpb_initial_arrival_time = 0; rc->initial_cpb_removal_delay = h->initial_cpb_removal_delay; - rc->initial_cpb_removal_delay_offset = h->initial_cpb_removal_delay_offset; - h->fenc->hrd_timing.cpb_removal_time = rc->nrt_first_access_unit = (double)rc->initial_cpb_removal_delay / 90000; + h->fenc->hrd_timing.cpb_removal_time = rc->nrt_first_access_unit = (int64_t)rc->initial_cpb_removal_delay * 300; } else { - h->fenc->hrd_timing.cpb_removal_time = rc->nrt_first_access_unit + (double)(h->fenc->i_cpb_delay - h->i_cpb_delay_pir_offset) * - h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale; + h->fenc->hrd_timing.cpb_removal_time = rc->nrt_first_access_unit + (int64_t)(h->fenc->i_cpb_delay - h->i_cpb_delay_pir_offset) * + 27000000LL * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale; - double cpb_earliest_arrival_time = h->fenc->hrd_timing.cpb_removal_time - (double)rc->initial_cpb_removal_delay / 90000; if( h->fenc->b_keyframe ) { rc->nrt_first_access_unit = h->fenc->hrd_timing.cpb_removal_time; rc->initial_cpb_removal_delay = h->initial_cpb_removal_delay; - rc->initial_cpb_removal_delay_offset = h->initial_cpb_removal_delay_offset; } - else - cpb_earliest_arrival_time -= (double)rc->initial_cpb_removal_delay_offset / 90000; - - if( h->sps->vui.hrd.b_cbr_hrd ) - h->fenc->hrd_timing.cpb_initial_arrival_time = rc->previous_cpb_final_arrival_time; - else - h->fenc->hrd_timing.cpb_initial_arrival_time = X264_MAX( rc->previous_cpb_final_arrival_time, cpb_earliest_arrival_time ); } - int filler_bits = *filler ? X264_MAX( (FILLER_OVERHEAD - h->param.b_annexb), *filler )*8 : 0; - // Equation C-6 - h->fenc->hrd_timing.cpb_final_arrival_time = rc->previous_cpb_final_arrival_time = h->fenc->hrd_timing.cpb_initial_arrival_time + - (double)(bits + filler_bits) / h->sps->vui.hrd.i_bit_rate_unscaled; - h->fenc->hrd_timing.dpb_output_time = (double)h->fenc->i_dpb_output_delay * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale + + h->fenc->hrd_timing.dpb_output_time = (int64_t)h->fenc->i_dpb_output_delay * 27000000LL * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale + h->fenc->hrd_timing.cpb_removal_time; } @@ -2512,8 +2496,6 @@ void x264_thread_sync_ratecontrol( x264_t *cur, x264_t *prev, x264_t *next ) COPY(wanted_bits_window); COPY(bframe_bits); COPY(initial_cpb_removal_delay); - COPY(initial_cpb_removal_delay_offset); - COPY(nrt_first_access_unit); COPY(previous_cpb_final_arrival_time); #undef COPY } diff --git a/x264.h b/x264.h index a831a3a8..4c7ffb5d 100644 --- a/x264.h +++ b/x264.h @@ -647,11 +647,8 @@ enum pic_struct_e typedef struct { - double cpb_initial_arrival_time; - double cpb_final_arrival_time; - double cpb_removal_time; - - double dpb_output_time; + int64_t cpb_removal_time; + int64_t dpb_output_time; } x264_hrd_t; /* Arbitrary user SEI: From c39d0861dd9b4497051b38eb311445b9413675f6 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Wed, 24 Aug 2011 20:00:28 +0100 Subject: [PATCH 20/81] Fix issues with HRD timings. --- encoder/ratecontrol.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index 5b7ff504..88ad9b56 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -154,7 +154,6 @@ struct x264_ratecontrol_t x264_zone_t *prev_zone; /* hrd stuff */ - int initial_cpb_removal_delay; int64_t nrt_first_access_unit; /* nominal removal time */ int64_t previous_cpb_final_arrival_time; uint64_t hrd_multiply_denom; @@ -1718,8 +1717,7 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) if( h->fenc->i_frame == 0 ) { // access unit initialises the HRD - rc->initial_cpb_removal_delay = h->initial_cpb_removal_delay; - h->fenc->hrd_timing.cpb_removal_time = rc->nrt_first_access_unit = (int64_t)rc->initial_cpb_removal_delay * 300; + h->fenc->hrd_timing.cpb_removal_time = rc->nrt_first_access_unit = (int64_t)h->initial_cpb_removal_delay * 300; } else { @@ -1727,10 +1725,7 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) 27000000LL * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale; if( h->fenc->b_keyframe ) - { - rc->nrt_first_access_unit = h->fenc->hrd_timing.cpb_removal_time; - rc->initial_cpb_removal_delay = h->initial_cpb_removal_delay; - } + rc->nrt_first_access_unit = h->fenc->hrd_timing.cpb_removal_time; } h->fenc->hrd_timing.dpb_output_time = (int64_t)h->fenc->i_dpb_output_delay * 27000000LL * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale + @@ -2495,8 +2490,8 @@ void x264_thread_sync_ratecontrol( x264_t *cur, x264_t *prev, x264_t *next ) COPY(filler_bits_sum); COPY(wanted_bits_window); COPY(bframe_bits); - COPY(initial_cpb_removal_delay); COPY(previous_cpb_final_arrival_time); + COPY(nrt_first_access_unit); #undef COPY } //FIXME row_preds[] (not strictly necessary, but would improve prediction) From 543137f4c240f562c2bbaf3df75e83875dae1f94 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Mon, 29 Aug 2011 17:58:28 +0100 Subject: [PATCH 21/81] Get rid of hardcoded parameters in speedcontrol. This allows SAR changes. --- encoder/speed.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/encoder/speed.c b/encoder/speed.c index 7bf370ef..a449ddd2 100644 --- a/encoder/speed.c +++ b/encoder/speed.c @@ -19,7 +19,6 @@ struct x264_speedcontrol_t float cplx_den; float cplx_decay; float dither; - x264_param_t user_param; int first; @@ -54,7 +53,6 @@ void x264_speedcontrol_new( x264_t *h ) sc->cplx_decay = 1 - 1./h->param.sc.i_buffer_size; sc->stat.min_buffer = sc->buffer_size; sc->stat.max_buffer = 0; - sc->user_param = h->param; sc->first = 1; } @@ -128,7 +126,7 @@ static void apply_preset( x264_t *h, int preset ) //if( preset != sc->preset ) { const sc_preset_t *s = &presets[preset]; - x264_param_t p = sc->user_param; + x264_param_t p = h->param; p.i_frame_reference = s->refs; p.analyse.inter = s->partitions; From 37a647c00e28353b4c185ab1da9c22092dc021f6 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Sat, 22 Oct 2011 17:46:59 +0100 Subject: [PATCH 22/81] Fix bad merge. --- common/osdep.c | 1 - 1 file changed, 1 deletion(-) diff --git a/common/osdep.c b/common/osdep.c index 816b03f2..c94e80cf 100644 --- a/common/osdep.c +++ b/common/osdep.c @@ -43,7 +43,6 @@ extern int ptw32_processInitialized; int64_t x264_mdate( void ) { -<<<<<<< HEAD #ifdef __MINGW32__ struct timeb tb; ftime( &tb ); From 2c33d283ea71aad69f71f8f87506fe5c863debaa Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 25 Oct 2011 17:44:47 +0100 Subject: [PATCH 23/81] Fix error with rebasing. Fix bad rebase #2 --- encoder/encoder.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/encoder/encoder.c b/encoder/encoder.c index 2a008ef8..253f073b 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -2929,7 +2929,7 @@ int x264_encoder_encode( x264_t *h, } /* when frame threading is used, buffering period sei is written in x264_encoder_frame_end */ - if( h->i_thread_frames == 1 && h->sps->vui.b_nal_hrd_parameters_present ) + if( h->i_thread_frames == 1 && h->param.i_nal_hrd ) { x264_hrd_fullness( h ); x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); @@ -3087,7 +3087,7 @@ static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current, x264_emms(); /* generate buffering period sei and insert it into place */ - if( h->i_thread_frames > 1 && h->fenc->b_keyframe && h->sps->vui.b_nal_hrd_parameters_present ) + if( h->i_thread_frames > 1 && h->fenc->b_keyframe && h->param.i_nal_hrd ) { x264_hrd_fullness( h ); x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); From 3ffaa2b87ec1c2b86e5ed88755d610549d586c8e Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Sat, 3 Dec 2011 16:01:43 +0000 Subject: [PATCH 24/81] Output the arrival time of the AU into the CPB. --- encoder/ratecontrol.c | 9 +++++++++ x264.h | 1 + 2 files changed, 10 insertions(+) diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index 88ad9b56..da5704e3 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -154,6 +154,8 @@ struct x264_ratecontrol_t x264_zone_t *prev_zone; /* hrd stuff */ + int initial_cpb_removal_delay; + int initial_cpb_removal_delay_offset; int64_t nrt_first_access_unit; /* nominal removal time */ int64_t previous_cpb_final_arrival_time; uint64_t hrd_multiply_denom; @@ -1717,6 +1719,7 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) if( h->fenc->i_frame == 0 ) { // access unit initialises the HRD + h->fenc->hrd_timing.cpb_initial_arrival_time = 0; h->fenc->hrd_timing.cpb_removal_time = rc->nrt_first_access_unit = (int64_t)h->initial_cpb_removal_delay * 300; } else @@ -1724,8 +1727,12 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) h->fenc->hrd_timing.cpb_removal_time = rc->nrt_first_access_unit + (int64_t)(h->fenc->i_cpb_delay - h->i_cpb_delay_pir_offset) * 27000000LL * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale; + h->fenc->hrd_timing.cpb_initial_arrival_time = h->fenc->hrd_timing.cpb_removal_time - rc->initial_cpb_removal_delay * 300; + if( h->fenc->b_keyframe ) rc->nrt_first_access_unit = h->fenc->hrd_timing.cpb_removal_time; + else + h->fenc->hrd_timing.cpb_initial_arrival_time -= rc->initial_cpb_removal_delay_offset * 300; } h->fenc->hrd_timing.dpb_output_time = (int64_t)h->fenc->i_dpb_output_delay * 27000000LL * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale + @@ -2490,6 +2497,8 @@ void x264_thread_sync_ratecontrol( x264_t *cur, x264_t *prev, x264_t *next ) COPY(filler_bits_sum); COPY(wanted_bits_window); COPY(bframe_bits); + COPY(initial_cpb_removal_delay); + COPY(initial_cpb_removal_delay_offset); COPY(previous_cpb_final_arrival_time); COPY(nrt_first_access_unit); #undef COPY diff --git a/x264.h b/x264.h index 4c7ffb5d..780bd566 100644 --- a/x264.h +++ b/x264.h @@ -647,6 +647,7 @@ enum pic_struct_e typedef struct { + int64_t cpb_initial_arrival_time; int64_t cpb_removal_time; int64_t dpb_output_time; } x264_hrd_t; From ccf4f20da4a4ebcbe5e5d26275860c12c6a40d74 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Mon, 5 Dec 2011 19:24:44 +0000 Subject: [PATCH 25/81] Set CBR HRD flags correctly. --- encoder/ratecontrol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index da5704e3..22ca4609 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -516,7 +516,7 @@ void x264_ratecontrol_init_reconfigurable( x264_t *h, int b_init ) if( h->param.i_nal_hrd && b_init ) { h->sps->vui.hrd.i_cpb_cnt = 1; - h->sps->vui.hrd.b_cbr_hrd = h->param.i_nal_hrd == X264_NAL_HRD_CBR; + h->sps->vui.hrd.b_cbr_hrd = h->param.i_nal_hrd == X264_NAL_HRD_CBR || h->param.i_nal_hrd == X264_NAL_HRD_FAKE_CBR; h->sps->vui.hrd.i_time_offset_length = 0; #define BR_SHIFT 6 From c444d2b67adc7ead59993902970a48fb858571de Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Mon, 5 Dec 2011 23:35:50 +0000 Subject: [PATCH 26/81] Make single frame vbv code, correct the actual buffer size. Also get rid of some now useless (and hacky) outputs in the API. --- encoder/ratecontrol.c | 54 +++++++++++++++++++++++-------------------- x264.h | 3 --- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index 22ca4609..8f8a9bfb 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -522,43 +522,41 @@ void x264_ratecontrol_init_reconfigurable( x264_t *h, int b_init ) #define BR_SHIFT 6 #define CPB_SHIFT 4 - int bitrate = 1000*h->param.rc.i_vbv_max_bitrate; - int bufsize = 1000*h->param.rc.i_vbv_buffer_size; - - // normalize HRD size and rate to the value / scale notation - h->sps->vui.hrd.i_bit_rate_scale = x264_clip3( x264_ctz( bitrate ) - BR_SHIFT, 0, 15 ); - h->sps->vui.hrd.i_bit_rate_value = bitrate >> ( h->sps->vui.hrd.i_bit_rate_scale + BR_SHIFT ); - h->sps->vui.hrd.i_bit_rate_unscaled = h->sps->vui.hrd.i_bit_rate_value << ( h->sps->vui.hrd.i_bit_rate_scale + BR_SHIFT ); - h->sps->vui.hrd.i_cpb_size_scale = x264_clip3( x264_ctz( bufsize ) - CPB_SHIFT, 0, 15 ); - h->sps->vui.hrd.i_cpb_size_value = bufsize >> ( h->sps->vui.hrd.i_cpb_size_scale + CPB_SHIFT ); - h->sps->vui.hrd.i_cpb_size_unscaled = h->sps->vui.hrd.i_cpb_size_value << ( h->sps->vui.hrd.i_cpb_size_scale + CPB_SHIFT ); + if( h->param.i_nal_hrd == X264_NAL_HRD_VBR || h->param.i_nal_hrd == X264_NAL_HRD_VBR ) + { + // normalize HRD size and rate to the value / scale notation + h->sps->vui.hrd.i_bit_rate_scale = x264_clip3( x264_ctz( vbv_max_bitrate ) - BR_SHIFT, 0, 15 ); + h->sps->vui.hrd.i_bit_rate_value = vbv_max_bitrate >> ( h->sps->vui.hrd.i_bit_rate_scale + BR_SHIFT ); + h->sps->vui.hrd.i_bit_rate_unscaled = h->sps->vui.hrd.i_bit_rate_value << ( h->sps->vui.hrd.i_bit_rate_scale + BR_SHIFT ); + h->sps->vui.hrd.i_cpb_size_scale = x264_clip3( x264_ctz( vbv_buffer_size ) - CPB_SHIFT, 0, 15 ); + h->sps->vui.hrd.i_cpb_size_value = vbv_buffer_size >> ( h->sps->vui.hrd.i_cpb_size_scale + CPB_SHIFT ); + h->sps->vui.hrd.i_cpb_size_unscaled = h->sps->vui.hrd.i_cpb_size_value << ( h->sps->vui.hrd.i_cpb_size_scale + CPB_SHIFT ); - #undef CPB_SHIFT - #undef BR_SHIFT + #undef CPB_SHIFT + #undef BR_SHIFT - // arbitrary - #define MAX_DURATION 0.5 + // arbitrary + #define MAX_DURATION 0.5 - int max_cpb_output_delay = X264_MIN( h->param.i_keyint_max * MAX_DURATION * h->sps->vui.i_time_scale / h->sps->vui.i_num_units_in_tick, INT_MAX ); - int max_dpb_output_delay = h->sps->vui.i_max_dec_frame_buffering * MAX_DURATION * h->sps->vui.i_time_scale / h->sps->vui.i_num_units_in_tick; - int max_delay = (int)(90000.0 * (double)h->sps->vui.hrd.i_cpb_size_unscaled / h->sps->vui.hrd.i_bit_rate_unscaled + 0.5); + int max_cpb_output_delay = X264_MIN( h->param.i_keyint_max * MAX_DURATION * h->sps->vui.i_time_scale / h->sps->vui.i_num_units_in_tick, INT_MAX ); + int max_dpb_output_delay = h->sps->vui.i_max_dec_frame_buffering * MAX_DURATION * h->sps->vui.i_time_scale / h->sps->vui.i_num_units_in_tick; + int max_delay = (int)(90000.0 * (double)h->sps->vui.hrd.i_cpb_size_unscaled / h->sps->vui.hrd.i_bit_rate_unscaled + 0.5); - h->sps->vui.hrd.i_initial_cpb_removal_delay_length = 2 + x264_clip3( 32 - x264_clz( max_delay ), 4, 22 ); - h->sps->vui.hrd.i_cpb_removal_delay_length = x264_clip3( 32 - x264_clz( max_cpb_output_delay ), 4, 31 ); - h->sps->vui.hrd.i_dpb_output_delay_length = x264_clip3( 32 - x264_clz( max_dpb_output_delay ), 4, 31 ); + h->sps->vui.hrd.i_initial_cpb_removal_delay_length = 2 + x264_clip3( 32 - x264_clz( max_delay ), 4, 22 ); + h->sps->vui.hrd.i_cpb_removal_delay_length = x264_clip3( 32 - x264_clz( max_cpb_output_delay ), 4, 31 ); + h->sps->vui.hrd.i_dpb_output_delay_length = x264_clip3( 32 - x264_clz( max_dpb_output_delay ), 4, 31 ); - #undef MAX_DURATION + #undef MAX_DURATION - vbv_buffer_size = h->param.rc.i_vbv_buffer_size_actual = h->sps->vui.hrd.i_cpb_size_unscaled; - vbv_max_bitrate = h->param.rc.i_vbv_max_bitrate_actual = h->sps->vui.hrd.i_bit_rate_unscaled; + vbv_buffer_size = h->sps->vui.hrd.i_cpb_size_unscaled; + vbv_max_bitrate = h->sps->vui.hrd.i_bit_rate_unscaled; + } } else if( h->param.i_nal_hrd && !b_init ) { //x264_log( h, X264_LOG_WARNING, "VBV parameters cannot be changed when NAL HRD is in use\n" ); return; } - h->sps->vui.hrd.i_bit_rate_unscaled = vbv_max_bitrate; - h->sps->vui.hrd.i_cpb_size_unscaled = vbv_buffer_size; if( rc->b_vbv_min_rate ) rc->bitrate = h->param.rc.i_bitrate * 1000.; @@ -566,6 +564,12 @@ void x264_ratecontrol_init_reconfigurable( x264_t *h, int b_init ) rc->vbv_max_rate = vbv_max_bitrate; rc->buffer_size = vbv_buffer_size; rc->single_frame_vbv = rc->buffer_rate * 1.1 > rc->buffer_size; + if( rc->single_frame_vbv && h->param.i_nal_hrd > X264_NAL_HRD_CBR ) + rc->buffer_size = rc->buffer_rate; + + h->sps->vui.hrd.i_bit_rate_unscaled = rc->vbv_max_rate; + h->sps->vui.hrd.i_cpb_size_unscaled = rc->buffer_size; + rc->cbr_decay = 1.0 - rc->buffer_rate / rc->buffer_size * 0.5 * X264_MAX(0, 1.5 - rc->buffer_rate * rc->fps / rc->bitrate); if( h->param.rc.i_rc_method == X264_RC_CRF && h->param.rc.f_rf_constant_max ) diff --git a/x264.h b/x264.h index 780bd566..d8048af3 100644 --- a/x264.h +++ b/x264.h @@ -378,9 +378,6 @@ typedef struct x264_param_t float f_ip_factor; float f_pb_factor; - int i_vbv_max_bitrate_actual; /* Output only when HRD enabled */ - int i_vbv_buffer_size_actual; /* Output only when HRD enabled */ - int i_aq_mode; /* psy adaptive QP. (X264_AQ_*) */ float f_aq_strength; int b_mb_tree; /* Macroblock-tree ratecontrol. */ From 36dc854cbeb773aa8d24f5a725db38c6de8d305c Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 6 Dec 2011 00:26:13 +0000 Subject: [PATCH 27/81] Merge git://git.videolan.org/x264 --- Makefile | 22 ++- common/common.h | 2 + common/deblock.c | 24 +-- common/frame.c | 2 +- common/frame.h | 2 +- common/mc.c | 14 +- common/rectangle.c | 2 +- common/set.c | 11 ++ common/x86/x86inc.asm | 365 +++++++++++++++++++++++------------------ configure | 8 +- encoder/cabac.c | 7 +- encoder/encoder.c | 3 +- encoder/ratecontrol.c | 2 +- encoder/rdo.c | 101 ++++++------ encoder/slicetype.c | 2 +- filters/video/resize.c | 64 +++----- input/avs.c | 32 +++- input/ffms.c | 16 +- input/input.h | 5 +- input/lavf.c | 21 ++- input/timecode.c | 3 +- tools/checkasm.c | 31 ++-- x264.c | 43 ++++- x264.h | 8 +- x264cli.h | 7 + 25 files changed, 479 insertions(+), 318 deletions(-) diff --git a/Makefile b/Makefile index 1ed6da55..9fcd7f78 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,8 @@ SRCCLI = x264.c input/input.c input/timecode.c input/raw.c input/y4m.c \ SRCSO = +OBJCHK = tools/checkasm.o + CONFIG := $(shell cat config.h) # GPL-only files @@ -89,7 +91,7 @@ ASFLAGS += -Icommon/x86/ SRCS += common/x86/mc-c.c common/x86/predict-c.c OBJASM = $(ASMSRC:%.asm=%.o) $(OBJASM): common/x86/x86inc.asm common/x86/x86util.asm -checkasm: tools/checkasm-a.o +OBJCHK += tools/checkasm-a.o endif endif @@ -136,7 +138,7 @@ OBJCLI = $(SRCCLI:%.c=%.o) OBJSO = $(SRCSO:%.c=%.o) DEP = depend -.PHONY: all default fprofiled clean distclean install uninstall dox test testclean lib-static lib-shared cli install-lib-dev install-lib-static install-lib-shared install-cli +.PHONY: all default fprofiled clean distclean install uninstall lib-static lib-shared cli install-lib-dev install-lib-static install-lib-shared install-cli default: $(DEP) @@ -145,17 +147,26 @@ lib-static: $(LIBX264) lib-shared: $(SONAME) $(LIBX264): .depend $(OBJS) $(OBJASM) + rm -f $(LIBX264) $(AR)$@ $(OBJS) $(OBJASM) $(if $(RANLIB), $(RANLIB) $@) $(SONAME): .depend $(OBJS) $(OBJASM) $(OBJSO) $(LD)$@ $(OBJS) $(OBJASM) $(OBJSO) $(SOFLAGS) $(LDFLAGS) +ifneq ($(EXE),) +.PHONY: x264 checkasm +x264: x264$(EXE) +checkasm: checkasm$(EXE) +endif + x264$(EXE): .depend $(OBJCLI) $(CLI_LIBX264) $(LD)$@ $(OBJCLI) $(CLI_LIBX264) $(LDFLAGSCLI) $(LDFLAGS) -checkasm: tools/checkasm.o $(LIBX264) - $(LD)$@ $+ $(LDFLAGS) +checkasm$(EXE): .depend $(OBJCHK) $(LIBX264) + $(LD)$@ $(OBJCHK) $(LIBX264) $(LDFLAGS) + +$(OBJS) $(OBJASM) $(OBJSO) $(OBJCLI) $(OBJCHK): .depend %.o: %.asm $(AS) $(ASFLAGS) -o $@ $< @@ -205,12 +216,11 @@ endif clean: rm -f $(OBJS) $(OBJASM) $(OBJCLI) $(OBJSO) $(SONAME) *.a *.lib *.exp *.pdb x264 x264.exe .depend TAGS - rm -f checkasm checkasm.exe tools/checkasm.o tools/checkasm-a.o + rm -f checkasm checkasm.exe $(OBJCHK) rm -f $(SRC2:%.c=%.gcda) $(SRC2:%.c=%.gcno) *.dyn pgopti.dpi pgopti.dpi.lock distclean: clean rm -f config.mak x264_config.h config.h config.log x264.pc x264.def - rm -rf test/ install-cli: cli install -d $(DESTDIR)$(bindir) diff --git a/common/common.h b/common/common.h index 3c058ad8..595ed6fa 100644 --- a/common/common.h +++ b/common/common.h @@ -499,6 +499,8 @@ struct x264_t udctcoef (*quant8_mf[4])[64]; /* [4][52][64] */ udctcoef (*quant4_bias[4])[16]; /* [4][52][16] */ udctcoef (*quant8_bias[4])[64]; /* [4][52][64] */ + udctcoef (*quant4_bias0[4])[16]; /* [4][52][16] */ + udctcoef (*quant8_bias0[4])[64]; /* [4][52][64] */ udctcoef (*nr_offset_emergency)[4][64]; /* mv/ref cost arrays. */ diff --git a/common/deblock.c b/common/deblock.c index 2ae5f75c..d52d53c3 100644 --- a/common/deblock.c +++ b/common/deblock.c @@ -165,13 +165,11 @@ static ALWAYS_INLINE void deblock_chroma_c( pixel *pix, int height, int xstride, } static void deblock_h_chroma_mbaff_c( pixel *pix, int stride, int alpha, int beta, int8_t *tc0 ) { - for( int i = 0; i < 4; i++, pix += stride ) - deblock_edge_chroma_c( pix, 2, alpha, beta, tc0[i] ); + deblock_chroma_c( pix, 1, 2, stride, alpha, beta, tc0 ); } static void deblock_h_chroma_422_mbaff_c( pixel *pix, int stride, int alpha, int beta, int8_t *tc0 ) { - for( int i = 0; i < 8; i++, pix += stride ) - deblock_edge_chroma_c( pix, 2, alpha, beta, tc0[i>>1] ); + deblock_chroma_c( pix, 2, 2, stride, alpha, beta, tc0 ); } static void deblock_v_chroma_c( pixel *pix, int stride, int alpha, int beta, int8_t *tc0 ) { @@ -265,13 +263,11 @@ static ALWAYS_INLINE void deblock_chroma_intra_c( pixel *pix, int width, int hei } static void deblock_h_chroma_intra_mbaff_c( pixel *pix, int stride, int alpha, int beta ) { - for( int i = 0; i < 4; i++, pix += stride ) - deblock_edge_chroma_intra_c( pix, 2, alpha, beta ); + deblock_chroma_intra_c( pix, 2, 4, 2, stride, alpha, beta ); } static void deblock_h_chroma_422_intra_mbaff_c( pixel *pix, int stride, int alpha, int beta ) { - for( int i = 0; i < 8; i++, pix += stride ) - deblock_edge_chroma_intra_c( pix, 2, alpha, beta ); + deblock_chroma_intra_c( pix, 2, 8, 2, stride, alpha, beta ); } static void deblock_v_chroma_intra_c( pixel *pix, int stride, int alpha, int beta ) { @@ -474,13 +470,15 @@ void x264_frame_deblock_row( x264_t *h, int mb_y ) { deblock_edge_intra( h, pixy, 2*stridey, bs[0][0], luma_qp[0], a, b, 0, luma_intra_deblock ); deblock_edge_intra( h, pixuv, 2*strideuv, bs[0][0], chroma_qp[0], a, b, c, chroma_intra_deblock ); - deblock_edge_intra( h, pixuv + uvdiff, 2*strideuv, bs[0][0], chroma_qp[0], a, b, c, chroma_intra_deblock ); + if( chroma444 ) + deblock_edge_intra( h, pixuv + uvdiff, 2*strideuv, bs[0][0], chroma_qp[0], a, b, c, chroma_intra_deblock ); } else { deblock_edge( h, pixy, 2*stridey, bs[0][0], luma_qp[0], a, b, 0, luma_deblock ); deblock_edge( h, pixuv, 2*strideuv, bs[0][0], chroma_qp[0], a, b, c, chroma_deblock ); - deblock_edge( h, pixuv + uvdiff, 2*strideuv, bs[0][0], chroma_qp[0], a, b, c, chroma_deblock ); + if( chroma444 ) + deblock_edge( h, pixuv + uvdiff, 2*strideuv, bs[0][0], chroma_qp[0], a, b, c, chroma_deblock ); } int offy = MB_INTERLACED ? 4 : 0; @@ -492,13 +490,15 @@ void x264_frame_deblock_row( x264_t *h, int mb_y ) { deblock_edge_intra( h, pixy + (stridey<param = src->param; dst->i_pic_struct = src->i_pic_struct; dst->extra_sei = src->extra_sei; - dst->passthrough_opaque = src->passthrough_opaque; + dst->opaque = src->opaque; uint8_t *pix[3]; int stride[3]; diff --git a/common/frame.h b/common/frame.h index 0d0a5320..37878f5f 100644 --- a/common/frame.h +++ b/common/frame.h @@ -164,7 +164,7 @@ typedef struct x264_frame x264_sei_t extra_sei; /* user data */ - void *passthrough_opaque; + void *opaque; } x264_frame_t; /* synchronized frame list */ diff --git a/common/mc.c b/common/mc.c index 6f772afa..314c6f96 100644 --- a/common/mc.c +++ b/common/mc.c @@ -304,9 +304,9 @@ void x264_plane_copy_interleave_c( pixel *dst, int i_dst, } } -void x264_plane_copy_deinterleave_c( pixel *dstu, int i_dstu, - pixel *dstv, int i_dstv, - pixel *src, int i_src, int w, int h ) +static void x264_plane_copy_deinterleave_c( pixel *dstu, int i_dstu, + pixel *dstv, int i_dstv, + pixel *src, int i_src, int w, int h ) { for( int y=0; ypps->scaling_list[i], h->pps->scaling_list[j], size*sizeof(uint8_t) ) ) break; if( j < i ) + { h->quant4_bias[i] = h->quant4_bias[j]; + h->quant4_bias0[i] = h->quant4_bias0[j]; + } else + { CHECKED_MALLOC( h->quant4_bias[i], (QP_MAX+1)*size*sizeof(udctcoef) ); + CHECKED_MALLOC( h->quant4_bias0[i], (QP_MAX+1)*size*sizeof(udctcoef) ); + } } for( int q = 0; q < 6; q++ ) @@ -163,6 +169,7 @@ int x264_cqm_init( x264_t *h ) } // round to nearest, unless that would cause the deadzone to be negative h->quant4_bias[i_list][q][i] = X264_MIN( DIV(deadzone[i_list]<<10, j), (1<<15)/j ); + h->quant4_bias0[i_list][q][i] = (1<<15)/j; if( j > 0xffff && q > max_qp_err && (i_list == CQM_4IY || i_list == CQM_4PY) ) max_qp_err = q; if( j > 0xffff && q > max_chroma_qp_err && (i_list == CQM_4IC || i_list == CQM_4PC) ) @@ -182,6 +189,7 @@ int x264_cqm_init( x264_t *h ) continue; } h->quant8_bias[i_list][q][i] = X264_MIN( DIV(deadzone[i_list]<<10, j), (1<<15)/j ); + h->quant8_bias0[i_list][q][i] = (1<<15)/j; if( j > 0xffff && q > max_qp_err && (i_list == CQM_8IY || i_list == CQM_8PY) ) max_qp_err = q; if( j > 0xffff && q > max_chroma_qp_err && (i_list == CQM_8IC || i_list == CQM_8PC) ) @@ -272,7 +280,10 @@ int x264_cqm_init( x264_t *h ) if( h->quant##n##_bias[i] == h->quant##n##_bias[j] )\ break;\ if( j == i )\ + {\ x264_free( h->quant##n##_bias[i] );\ + x264_free( h->quant##n##_bias0[i] );\ + }\ } void x264_cqm_delete( x264_t *h ) diff --git a/common/x86/x86inc.asm b/common/x86/x86inc.asm index 1bb64a9d..6d8db874 100644 --- a/common/x86/x86inc.asm +++ b/common/x86/x86inc.asm @@ -784,16 +784,38 @@ INIT_XMM %endrep %undef i +%macro CHECK_AVX_INSTR_EMU 3-* + %xdefine %%opcode %1 + %xdefine %%dst %2 + %rep %0-2 + %ifidn %%dst, %3 + %error non-avx emulation of ``%%opcode'' is not supported + %endif + %rotate 1 + %endrep +%endmacro + ;%1 == instruction ;%2 == 1 if float, 0 if int -;%3 == 0 if 3-operand (xmm, xmm, xmm), 1 if 4-operand (xmm, xmm, xmm, imm) +;%3 == 1 if 4-operand (xmm, xmm, xmm, imm), 0 if 3-operand (xmm, xmm, xmm) ;%4 == number of operands given ;%5+: operands %macro RUN_AVX_INSTR 6-7+ - %if sizeof%5==32 - v%1 %5, %6, %7 + %ifid %5 + %define %%sizeofreg sizeof%5 + %elifid %6 + %define %%sizeofreg sizeof%6 + %else + %define %%sizeofreg mmsize + %endif + %if %%sizeofreg==32 + %if %4>=3 + v%1 %5, %6, %7 + %else + v%1 %5, %6 + %endif %else - %if sizeof%5==8 + %if %%sizeofreg==8 %define %%regmov movq %elif %2 %define %%regmov movaps @@ -803,16 +825,17 @@ INIT_XMM %if %4>=3+%3 %ifnidn %5, %6 - %if avx_enabled && sizeof%5==16 + %if avx_enabled && %%sizeofreg==16 v%1 %5, %6, %7 %else + CHECK_AVX_INSTR_EMU {%1 %5, %6, %7}, %5, %7 %%regmov %5, %6 %1 %5, %7 %endif %else %1 %5, %7 %endif - %elif %3 + %elif %4>=3 %1 %5, %6, %7 %else %1 %5, %6 @@ -820,15 +843,37 @@ INIT_XMM %endif %endmacro +; 3arg AVX ops with a memory arg can only have it in src2, +; whereas SSE emulation of 3arg prefers to have it in src1 (i.e. the mov). +; So, if the op is symmetric and the wrong one is memory, swap them. +%macro RUN_AVX_INSTR1 8 + %assign %%swap 0 + %if avx_enabled + %ifnid %6 + %assign %%swap 1 + %endif + %elifnidn %5, %6 + %ifnid %7 + %assign %%swap 1 + %endif + %endif + %if %%swap && %3 == 0 && %8 == 1 + RUN_AVX_INSTR %1, %2, %3, %4, %5, %7, %6 + %else + RUN_AVX_INSTR %1, %2, %3, %4, %5, %6, %7 + %endif +%endmacro + ;%1 == instruction ;%2 == 1 if float, 0 if int -;%3 == 0 if 3-operand (xmm, xmm, xmm), 1 if 4-operand (xmm, xmm, xmm, imm) -%macro AVX_INSTR 3 - %macro %1 2-8 fnord, fnord, fnord, %1, %2, %3 +;%3 == 1 if 4-operand (xmm, xmm, xmm, imm), 0 if 3-operand (xmm, xmm, xmm) +;%4 == 1 if symmetric (i.e. doesn't matter which src arg is which), 0 if not +%macro AVX_INSTR 4 + %macro %1 2-9 fnord, fnord, fnord, %1, %2, %3, %4 %ifidn %3, fnord RUN_AVX_INSTR %6, %7, %8, 2, %1, %2 %elifidn %4, fnord - RUN_AVX_INSTR %6, %7, %8, 3, %1, %2, %3 + RUN_AVX_INSTR1 %6, %7, %8, 3, %1, %2, %3, %9 %elifidn %5, fnord RUN_AVX_INSTR %6, %7, %8, 4, %1, %2, %3, %4 %else @@ -837,158 +882,158 @@ INIT_XMM %endmacro %endmacro -AVX_INSTR addpd, 1, 0 -AVX_INSTR addps, 1, 0 -AVX_INSTR addsd, 1, 0 -AVX_INSTR addss, 1, 0 -AVX_INSTR addsubpd, 1, 0 -AVX_INSTR addsubps, 1, 0 -AVX_INSTR andpd, 1, 0 -AVX_INSTR andps, 1, 0 -AVX_INSTR andnpd, 1, 0 -AVX_INSTR andnps, 1, 0 -AVX_INSTR blendpd, 1, 0 -AVX_INSTR blendps, 1, 0 -AVX_INSTR blendvpd, 1, 0 -AVX_INSTR blendvps, 1, 0 -AVX_INSTR cmppd, 1, 0 -AVX_INSTR cmpps, 1, 0 -AVX_INSTR cmpsd, 1, 0 -AVX_INSTR cmpss, 1, 0 -AVX_INSTR divpd, 1, 0 -AVX_INSTR divps, 1, 0 -AVX_INSTR divsd, 1, 0 -AVX_INSTR divss, 1, 0 -AVX_INSTR dppd, 1, 0 -AVX_INSTR dpps, 1, 0 -AVX_INSTR haddpd, 1, 0 -AVX_INSTR haddps, 1, 0 -AVX_INSTR hsubpd, 1, 0 -AVX_INSTR hsubps, 1, 0 -AVX_INSTR maxpd, 1, 0 -AVX_INSTR maxps, 1, 0 -AVX_INSTR maxsd, 1, 0 -AVX_INSTR maxss, 1, 0 -AVX_INSTR minpd, 1, 0 -AVX_INSTR minps, 1, 0 -AVX_INSTR minsd, 1, 0 -AVX_INSTR minss, 1, 0 -AVX_INSTR movsd, 1, 0 -AVX_INSTR movss, 1, 0 -AVX_INSTR mpsadbw, 0, 1 -AVX_INSTR mulpd, 1, 0 -AVX_INSTR mulps, 1, 0 -AVX_INSTR mulsd, 1, 0 -AVX_INSTR mulss, 1, 0 -AVX_INSTR orpd, 1, 0 -AVX_INSTR orps, 1, 0 -AVX_INSTR packsswb, 0, 0 -AVX_INSTR packssdw, 0, 0 -AVX_INSTR packuswb, 0, 0 -AVX_INSTR packusdw, 0, 0 -AVX_INSTR paddb, 0, 0 -AVX_INSTR paddw, 0, 0 -AVX_INSTR paddd, 0, 0 -AVX_INSTR paddq, 0, 0 -AVX_INSTR paddsb, 0, 0 -AVX_INSTR paddsw, 0, 0 -AVX_INSTR paddusb, 0, 0 -AVX_INSTR paddusw, 0, 0 -AVX_INSTR palignr, 0, 1 -AVX_INSTR pand, 0, 0 -AVX_INSTR pandn, 0, 0 -AVX_INSTR pavgb, 0, 0 -AVX_INSTR pavgw, 0, 0 -AVX_INSTR pblendvb, 0, 0 -AVX_INSTR pblendw, 0, 1 -AVX_INSTR pcmpestri, 0, 0 -AVX_INSTR pcmpestrm, 0, 0 -AVX_INSTR pcmpistri, 0, 0 -AVX_INSTR pcmpistrm, 0, 0 -AVX_INSTR pcmpeqb, 0, 0 -AVX_INSTR pcmpeqw, 0, 0 -AVX_INSTR pcmpeqd, 0, 0 -AVX_INSTR pcmpeqq, 0, 0 -AVX_INSTR pcmpgtb, 0, 0 -AVX_INSTR pcmpgtw, 0, 0 -AVX_INSTR pcmpgtd, 0, 0 -AVX_INSTR pcmpgtq, 0, 0 -AVX_INSTR phaddw, 0, 0 -AVX_INSTR phaddd, 0, 0 -AVX_INSTR phaddsw, 0, 0 -AVX_INSTR phsubw, 0, 0 -AVX_INSTR phsubd, 0, 0 -AVX_INSTR phsubsw, 0, 0 -AVX_INSTR pmaddwd, 0, 0 -AVX_INSTR pmaddubsw, 0, 0 -AVX_INSTR pmaxsb, 0, 0 -AVX_INSTR pmaxsw, 0, 0 -AVX_INSTR pmaxsd, 0, 0 -AVX_INSTR pmaxub, 0, 0 -AVX_INSTR pmaxuw, 0, 0 -AVX_INSTR pmaxud, 0, 0 -AVX_INSTR pminsb, 0, 0 -AVX_INSTR pminsw, 0, 0 -AVX_INSTR pminsd, 0, 0 -AVX_INSTR pminub, 0, 0 -AVX_INSTR pminuw, 0, 0 -AVX_INSTR pminud, 0, 0 -AVX_INSTR pmulhuw, 0, 0 -AVX_INSTR pmulhrsw, 0, 0 -AVX_INSTR pmulhw, 0, 0 -AVX_INSTR pmullw, 0, 0 -AVX_INSTR pmulld, 0, 0 -AVX_INSTR pmuludq, 0, 0 -AVX_INSTR pmuldq, 0, 0 -AVX_INSTR por, 0, 0 -AVX_INSTR psadbw, 0, 0 -AVX_INSTR pshufb, 0, 0 -AVX_INSTR psignb, 0, 0 -AVX_INSTR psignw, 0, 0 -AVX_INSTR psignd, 0, 0 -AVX_INSTR psllw, 0, 0 -AVX_INSTR pslld, 0, 0 -AVX_INSTR psllq, 0, 0 -AVX_INSTR pslldq, 0, 0 -AVX_INSTR psraw, 0, 0 -AVX_INSTR psrad, 0, 0 -AVX_INSTR psrlw, 0, 0 -AVX_INSTR psrld, 0, 0 -AVX_INSTR psrlq, 0, 0 -AVX_INSTR psrldq, 0, 0 -AVX_INSTR psubb, 0, 0 -AVX_INSTR psubw, 0, 0 -AVX_INSTR psubd, 0, 0 -AVX_INSTR psubq, 0, 0 -AVX_INSTR psubsb, 0, 0 -AVX_INSTR psubsw, 0, 0 -AVX_INSTR psubusb, 0, 0 -AVX_INSTR psubusw, 0, 0 -AVX_INSTR punpckhbw, 0, 0 -AVX_INSTR punpckhwd, 0, 0 -AVX_INSTR punpckhdq, 0, 0 -AVX_INSTR punpckhqdq, 0, 0 -AVX_INSTR punpcklbw, 0, 0 -AVX_INSTR punpcklwd, 0, 0 -AVX_INSTR punpckldq, 0, 0 -AVX_INSTR punpcklqdq, 0, 0 -AVX_INSTR pxor, 0, 0 -AVX_INSTR shufps, 0, 1 -AVX_INSTR subpd, 1, 0 -AVX_INSTR subps, 1, 0 -AVX_INSTR subsd, 1, 0 -AVX_INSTR subss, 1, 0 -AVX_INSTR unpckhpd, 1, 0 -AVX_INSTR unpckhps, 1, 0 -AVX_INSTR unpcklpd, 1, 0 -AVX_INSTR unpcklps, 1, 0 -AVX_INSTR xorpd, 1, 0 -AVX_INSTR xorps, 1, 0 +AVX_INSTR addpd, 1, 0, 1 +AVX_INSTR addps, 1, 0, 1 +AVX_INSTR addsd, 1, 0, 1 +AVX_INSTR addss, 1, 0, 1 +AVX_INSTR addsubpd, 1, 0, 0 +AVX_INSTR addsubps, 1, 0, 0 +AVX_INSTR andpd, 1, 0, 1 +AVX_INSTR andps, 1, 0, 1 +AVX_INSTR andnpd, 1, 0, 0 +AVX_INSTR andnps, 1, 0, 0 +AVX_INSTR blendpd, 1, 0, 0 +AVX_INSTR blendps, 1, 0, 0 +AVX_INSTR blendvpd, 1, 0, 0 +AVX_INSTR blendvps, 1, 0, 0 +AVX_INSTR cmppd, 1, 0, 0 +AVX_INSTR cmpps, 1, 0, 0 +AVX_INSTR cmpsd, 1, 0, 0 +AVX_INSTR cmpss, 1, 0, 0 +AVX_INSTR divpd, 1, 0, 0 +AVX_INSTR divps, 1, 0, 0 +AVX_INSTR divsd, 1, 0, 0 +AVX_INSTR divss, 1, 0, 0 +AVX_INSTR dppd, 1, 1, 0 +AVX_INSTR dpps, 1, 1, 0 +AVX_INSTR haddpd, 1, 0, 0 +AVX_INSTR haddps, 1, 0, 0 +AVX_INSTR hsubpd, 1, 0, 0 +AVX_INSTR hsubps, 1, 0, 0 +AVX_INSTR maxpd, 1, 0, 1 +AVX_INSTR maxps, 1, 0, 1 +AVX_INSTR maxsd, 1, 0, 1 +AVX_INSTR maxss, 1, 0, 1 +AVX_INSTR minpd, 1, 0, 1 +AVX_INSTR minps, 1, 0, 1 +AVX_INSTR minsd, 1, 0, 1 +AVX_INSTR minss, 1, 0, 1 +AVX_INSTR movsd, 1, 0, 0 +AVX_INSTR movss, 1, 0, 0 +AVX_INSTR mpsadbw, 0, 1, 0 +AVX_INSTR mulpd, 1, 0, 1 +AVX_INSTR mulps, 1, 0, 1 +AVX_INSTR mulsd, 1, 0, 1 +AVX_INSTR mulss, 1, 0, 1 +AVX_INSTR orpd, 1, 0, 1 +AVX_INSTR orps, 1, 0, 1 +AVX_INSTR packsswb, 0, 0, 0 +AVX_INSTR packssdw, 0, 0, 0 +AVX_INSTR packuswb, 0, 0, 0 +AVX_INSTR packusdw, 0, 0, 0 +AVX_INSTR paddb, 0, 0, 1 +AVX_INSTR paddw, 0, 0, 1 +AVX_INSTR paddd, 0, 0, 1 +AVX_INSTR paddq, 0, 0, 1 +AVX_INSTR paddsb, 0, 0, 1 +AVX_INSTR paddsw, 0, 0, 1 +AVX_INSTR paddusb, 0, 0, 1 +AVX_INSTR paddusw, 0, 0, 1 +AVX_INSTR palignr, 0, 1, 0 +AVX_INSTR pand, 0, 0, 1 +AVX_INSTR pandn, 0, 0, 0 +AVX_INSTR pavgb, 0, 0, 1 +AVX_INSTR pavgw, 0, 0, 1 +AVX_INSTR pblendvb, 0, 0, 0 +AVX_INSTR pblendw, 0, 1, 0 +AVX_INSTR pcmpestri, 0, 0, 0 +AVX_INSTR pcmpestrm, 0, 0, 0 +AVX_INSTR pcmpistri, 0, 0, 0 +AVX_INSTR pcmpistrm, 0, 0, 0 +AVX_INSTR pcmpeqb, 0, 0, 1 +AVX_INSTR pcmpeqw, 0, 0, 1 +AVX_INSTR pcmpeqd, 0, 0, 1 +AVX_INSTR pcmpeqq, 0, 0, 1 +AVX_INSTR pcmpgtb, 0, 0, 0 +AVX_INSTR pcmpgtw, 0, 0, 0 +AVX_INSTR pcmpgtd, 0, 0, 0 +AVX_INSTR pcmpgtq, 0, 0, 0 +AVX_INSTR phaddw, 0, 0, 0 +AVX_INSTR phaddd, 0, 0, 0 +AVX_INSTR phaddsw, 0, 0, 0 +AVX_INSTR phsubw, 0, 0, 0 +AVX_INSTR phsubd, 0, 0, 0 +AVX_INSTR phsubsw, 0, 0, 0 +AVX_INSTR pmaddwd, 0, 0, 1 +AVX_INSTR pmaddubsw, 0, 0, 0 +AVX_INSTR pmaxsb, 0, 0, 1 +AVX_INSTR pmaxsw, 0, 0, 1 +AVX_INSTR pmaxsd, 0, 0, 1 +AVX_INSTR pmaxub, 0, 0, 1 +AVX_INSTR pmaxuw, 0, 0, 1 +AVX_INSTR pmaxud, 0, 0, 1 +AVX_INSTR pminsb, 0, 0, 1 +AVX_INSTR pminsw, 0, 0, 1 +AVX_INSTR pminsd, 0, 0, 1 +AVX_INSTR pminub, 0, 0, 1 +AVX_INSTR pminuw, 0, 0, 1 +AVX_INSTR pminud, 0, 0, 1 +AVX_INSTR pmulhuw, 0, 0, 1 +AVX_INSTR pmulhrsw, 0, 0, 1 +AVX_INSTR pmulhw, 0, 0, 1 +AVX_INSTR pmullw, 0, 0, 1 +AVX_INSTR pmulld, 0, 0, 1 +AVX_INSTR pmuludq, 0, 0, 1 +AVX_INSTR pmuldq, 0, 0, 1 +AVX_INSTR por, 0, 0, 1 +AVX_INSTR psadbw, 0, 0, 1 +AVX_INSTR pshufb, 0, 0, 0 +AVX_INSTR psignb, 0, 0, 0 +AVX_INSTR psignw, 0, 0, 0 +AVX_INSTR psignd, 0, 0, 0 +AVX_INSTR psllw, 0, 0, 0 +AVX_INSTR pslld, 0, 0, 0 +AVX_INSTR psllq, 0, 0, 0 +AVX_INSTR pslldq, 0, 0, 0 +AVX_INSTR psraw, 0, 0, 0 +AVX_INSTR psrad, 0, 0, 0 +AVX_INSTR psrlw, 0, 0, 0 +AVX_INSTR psrld, 0, 0, 0 +AVX_INSTR psrlq, 0, 0, 0 +AVX_INSTR psrldq, 0, 0, 0 +AVX_INSTR psubb, 0, 0, 0 +AVX_INSTR psubw, 0, 0, 0 +AVX_INSTR psubd, 0, 0, 0 +AVX_INSTR psubq, 0, 0, 0 +AVX_INSTR psubsb, 0, 0, 0 +AVX_INSTR psubsw, 0, 0, 0 +AVX_INSTR psubusb, 0, 0, 0 +AVX_INSTR psubusw, 0, 0, 0 +AVX_INSTR punpckhbw, 0, 0, 0 +AVX_INSTR punpckhwd, 0, 0, 0 +AVX_INSTR punpckhdq, 0, 0, 0 +AVX_INSTR punpckhqdq, 0, 0, 0 +AVX_INSTR punpcklbw, 0, 0, 0 +AVX_INSTR punpcklwd, 0, 0, 0 +AVX_INSTR punpckldq, 0, 0, 0 +AVX_INSTR punpcklqdq, 0, 0, 0 +AVX_INSTR pxor, 0, 0, 1 +AVX_INSTR shufps, 1, 1, 0 +AVX_INSTR subpd, 1, 0, 0 +AVX_INSTR subps, 1, 0, 0 +AVX_INSTR subsd, 1, 0, 0 +AVX_INSTR subss, 1, 0, 0 +AVX_INSTR unpckhpd, 1, 0, 0 +AVX_INSTR unpckhps, 1, 0, 0 +AVX_INSTR unpcklpd, 1, 0, 0 +AVX_INSTR unpcklps, 1, 0, 0 +AVX_INSTR xorpd, 1, 0, 1 +AVX_INSTR xorps, 1, 0, 1 ; 3DNow instructions, for sharing code between AVX, SSE and 3DN -AVX_INSTR pfadd, 1, 0 -AVX_INSTR pfsub, 1, 0 -AVX_INSTR pfmul, 1, 0 +AVX_INSTR pfadd, 1, 0, 1 +AVX_INSTR pfsub, 1, 0, 0 +AVX_INSTR pfmul, 1, 0, 1 ; base-4 constants for shuffles %assign i 0 diff --git a/configure b/configure index ad35db18..14fc6df5 100755 --- a/configure +++ b/configure @@ -588,7 +588,7 @@ case $host_cpu in s390|s390x) ARCH="S390" ;; - parisc|parisc64) + hppa*|parisc*) ARCH="PARISC" ;; ia64) @@ -626,12 +626,12 @@ if [ $compiler != ICL ]; then fi fi -if [ $shared = yes -a \( $ARCH = "X86_64" -o $ARCH = "PPC" -o $ARCH = "ALPHA" -o $ARCH = "ARM" -o $ARCH = "IA64" \) ] ; then +if [ $shared = yes -a \( $ARCH = "X86_64" -o $ARCH = "PPC" -o $ARCH = "ALPHA" -o $ARCH = "ARM" -o $ARCH = "IA64" -o $ARCH = "PARISC" -o $ARCH = "MIPS" \) ] ; then pic="yes" fi if [ $asm = auto -a \( $ARCH = X86 -o $ARCH = X86_64 \) ] ; then - if ! as_check "vfmaddps xmm0, xmm0, xmm0, xmm0" ; then + if ! as_check "vpperm xmm0, xmm0, xmm0, xmm0" ; then VER=`($AS --version || echo no assembler) 2>/dev/null | head -n 1` echo "Found $VER" echo "Minimum version is yasm-1.0.0" @@ -795,7 +795,7 @@ if [ "$lavf" = "auto" ] ; then fi if [ "$ffms" = "auto" ] ; then - ffms_major="2"; ffms_minor="14"; ffms_micro="0"; ffms_bump="0" + ffms_major="2"; ffms_minor="16"; ffms_micro="2"; ffms_bump="0" ffms="no" if ${cross_prefix}pkg-config --exists ffms2 2>/dev/null; then diff --git a/encoder/cabac.c b/encoder/cabac.c index f3080fea..bd4ae832 100644 --- a/encoder/cabac.c +++ b/encoder/cabac.c @@ -167,7 +167,12 @@ static void x264_cabac_qp_delta( x264_t *h, x264_cabac_t *cb ) if( i_dqp != 0 ) { - int val = i_dqp <= 0 ? (-2*i_dqp) : (2*i_dqp - 1); + /* Faster than (i_dqp <= 0 ? (-2*i_dqp) : (2*i_dqp-1)). + * If you so much as sneeze on these lines, gcc will compile this suboptimally. */ + i_dqp *= 2; + int val = 1 - i_dqp; + if( val < 0 ) val = i_dqp; + val--; /* dqp is interpreted modulo (QP_MAX_SPEC+1) */ if( val >= QP_MAX_SPEC && val != QP_MAX_SPEC+1 ) val = 2*QP_MAX_SPEC+1 - val; diff --git a/encoder/encoder.c b/encoder/encoder.c index 253f073b..9c6db74f 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -3111,7 +3111,6 @@ static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current, /* Set output picture properties */ pic_out->i_type = h->fenc->i_type; - pic_out->passthrough_opaque = h->fenc->passthrough_opaque; pic_out->b_keyframe = h->fenc->b_keyframe; pic_out->i_pic_struct = h->fenc->i_pic_struct; @@ -3121,6 +3120,8 @@ static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current, if( pic_out->i_pts < pic_out->i_dts ) x264_log( h, X264_LOG_WARNING, "invalid DTS: PTS is less than DTS\n" ); + pic_out->opaque = h->fenc->opaque; + pic_out->img.i_csp = h->fdec->i_csp; #if HIGH_BIT_DEPTH pic_out->img.i_csp |= X264_CSP_HIGH_DEPTH; diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index 8f8a9bfb..c9a94db5 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -2375,7 +2375,7 @@ static float rate_estimate_qscale( x264_t *h ) } } -void x264_threads_normalize_predictors( x264_t *h ) +static void x264_threads_normalize_predictors( x264_t *h ) { double totalsize = 0; for( int i = 0; i < h->param.i_threads; i++ ) diff --git a/encoder/rdo.c b/encoder/rdo.c index f02c50ba..28461d64 100644 --- a/encoder/rdo.c +++ b/encoder/rdo.c @@ -431,15 +431,17 @@ typedef struct // comparable to the input. so unquant is the direct inverse of quant, // and uses the dct scaling factors, not the idct ones. +#define SIGN(x,y) ((x^(y >> 31))-(y >> 31)) + static ALWAYS_INLINE int quant_trellis_cabac( x264_t *h, dctcoef *dct, - const udctcoef *quant_mf, const int *unquant_mf, + udctcoef *quant_mf, udctcoef *quant_bias, const int *unquant_mf, const uint16_t *coef_weight, const uint8_t *zigzag, int ctx_block_cat, int i_lambda2, int b_ac, int b_chroma, int dc, int i_coefs, int idx ) { - udctcoef abs_coefs[64]; - int8_t signs[64]; + ALIGNED_ARRAY_16( dctcoef, coefs, [64] ); + ALIGNED_ARRAY_16( dctcoef, quant_coefs, [64] ); trellis_node_t nodes[2][8]; trellis_node_t *nodes_cur = nodes[0]; trellis_node_t *nodes_prev = nodes[1]; @@ -448,9 +450,6 @@ int quant_trellis_cabac( x264_t *h, dctcoef *dct, uint8_t *cabac_state_sig = &h->cabac.state[ significant_coeff_flag_offset[b_interlaced][ctx_block_cat] ]; uint8_t *cabac_state_last = &h->cabac.state[ last_coeff_flag_offset[b_interlaced][ctx_block_cat] ]; const uint8_t *levelgt1_ctx = b_chroma && dc ? coeff_abs_levelgt1_ctx_chroma_dc : coeff_abs_levelgt1_ctx; - const int f = 1 << 15; // no deadzone - int i_last_nnz; - int i; // (# of coefs) * (# of ctx) * (# of levels tried) = 1024 // we don't need to keep all of those: (# of coefs) * (# of ctx) would be enough, @@ -462,30 +461,36 @@ int quant_trellis_cabac( x264_t *h, dctcoef *dct, } level_tree[64*8*2]; int i_levels_used = 1; - /* init coefs */ - for( i = i_coefs-1; i >= b_ac; i-- ) - if( (unsigned)(dct[zigzag[i]] * (dc?quant_mf[0]>>1:quant_mf[zigzag[i]]) + f-1) >= 2*f ) - break; - - if( i < b_ac ) + if( i_coefs == 64 ) { - /* We only need to zero an empty 4x4 block. 8x8 can be - implicitly emptied via zero nnz, as can dc. */ - if( i_coefs == 16 && !dc ) - memset( dct, 0, 16 * sizeof(dctcoef) ); - return 0; + h->mc.memcpy_aligned( coefs, dct, sizeof(dctcoef)*64 ); + if( !h->quantf.quant_8x8( dct, quant_mf, quant_bias ) ) + return 0; + h->zigzagf.scan_8x8( quant_coefs, dct ); } - - i_last_nnz = i; - idx &= i_coefs == 64 ? 3 : 15; - - for( ; i >= b_ac; i-- ) + else if( i_coefs == 16 ) + { + memcpy( coefs, dct, sizeof(dctcoef)*16 ); + if( !h->quantf.quant_4x4( dct, quant_mf, quant_bias ) ) + return 0; + h->zigzagf.scan_4x4( quant_coefs, dct ); + } + else { - int coef = dct[zigzag[i]]; - abs_coefs[i] = abs(coef); - signs[i] = coef>>31 | 1; + memcpy( coefs, dct, sizeof(dctcoef)*i_coefs ); + int nz = h->quantf.quant_2x2_dc( &dct[0], quant_mf[0] >> 1, quant_bias[0] << 1 ); + if( i_coefs == 8 ) + nz |= h->quantf.quant_2x2_dc( &dct[4], quant_mf[0] >> 1, quant_bias[0] << 1 ); + if( !nz ) + return 0; + for( int i = 0; i < i_coefs; i++ ) + quant_coefs[i] = dct[zigzag[i]]; } + int i_last_nnz = h->quantf.coeff_last[ctx_block_cat]( quant_coefs+b_ac )+b_ac; + + idx &= i_coefs == 64 ? 3 : 15; + /* init trellis */ for( int j = 1; j < 8; j++ ) nodes_cur[j].score = TRELLIS_SCORE_MAX; @@ -504,15 +509,11 @@ int quant_trellis_cabac( x264_t *h, dctcoef *dct, memcpy( nodes_cur[0].cabac_state, &h->cabac.state[ coeff_abs_level_m1_offset[ctx_block_cat] ], 10 ); + int i; for( i = i_last_nnz; i >= b_ac; i-- ) { - int i_coef = abs_coefs[i]; - int q = ( f + i_coef * (dc?quant_mf[0]>>1:quant_mf[zigzag[i]]) ) >> 16; - int cost_sig[2], cost_last[2]; - trellis_node_t n; - // skip 0s: this doesn't affect the output, but saves some unnecessary computation. - if( q == 0 ) + if( !quant_coefs[i] ) { // no need to calculate ssd of 0s: it's the same in all nodes. // no need to modify level_tree for ctx=0: it starts with an infinite loop of 0s. @@ -537,6 +538,12 @@ int quant_trellis_cabac( x264_t *h, dctcoef *dct, continue; } + int sign_coef = coefs[zigzag[i]]; + int i_coef = abs( sign_coef ); + int q = abs( quant_coefs[i] ); + int cost_sig[2], cost_last[2]; + trellis_node_t n; + XCHG( trellis_node_t*, nodes_cur, nodes_prev ); for( int j = 0; j < 8; j++ ) @@ -572,8 +579,8 @@ int quant_trellis_cabac( x264_t *h, dctcoef *dct, if( h->mb.i_psy_trellis && i && !dc && !b_chroma ) { int orig_coef = (i_coefs == 64) ? h->mb.pic.fenc_dct8[idx][zigzag[i]] : h->mb.pic.fenc_dct4[idx][zigzag[i]]; - int predicted_coef = orig_coef - i_coef * signs[i]; - int psy_value = h->mb.i_psy_trellis * abs(predicted_coef + unquant_abs_level * signs[i]); + int predicted_coef = orig_coef - sign_coef; + int psy_value = h->mb.i_psy_trellis * abs(predicted_coef + SIGN(unquant_abs_level, sign_coef)); int psy_weight = (i_coefs == 64) ? x264_dct8_weight_tab[zigzag[i]] : x264_dct4_weight_tab[zigzag[i]]; ssd = (int64_t)d*d * coef_weight[i] - psy_weight * psy_value; } @@ -620,7 +627,7 @@ int quant_trellis_cabac( x264_t *h, dctcoef *dct, /* Optimize rounding for DC coefficients in DC-only luma 4x4/8x8 blocks. */ else { - d = i_coef * signs[0] - ((unquant_abs_level * signs[0] + 8)&~15); + d = sign_coef - ((SIGN(unquant_abs_level, sign_coef) + 8)&~15); n.score += (int64_t)d*d * coef_weight[i]; } @@ -642,19 +649,19 @@ int quant_trellis_cabac( x264_t *h, dctcoef *dct, if( bnode == &nodes_cur[0] ) { + /* We only need to zero an empty 4x4 block. 8x8 can be + implicitly emptied via zero nnz, as can dc. */ if( i_coefs == 16 && !dc ) memset( dct, 0, 16 * sizeof(dctcoef) ); return 0; } int level = bnode->level_idx; - for( i = b_ac; level; i++ ) + for( i = b_ac; i <= i_last_nnz; i++ ) { - dct[zigzag[i]] = level_tree[level].abs_level * signs[i]; + dct[zigzag[i]] = SIGN(level_tree[level].abs_level, coefs[zigzag[i]]); level = level_tree[level].next; } - for( ; i < i_coefs; i++ ) - dct[zigzag[i]] = 0; return 1; } @@ -839,10 +846,8 @@ int quant_trellis_cavlc( x264_t *h, dctcoef *dct, if( coef_mask ) { - for( i = b_ac, j = start; i <= i_last_nnz; i++, j += step ) + for( i = b_ac, j = start; i < i_coefs; i++, j += step ) dct[zigzag[j]] = coefs[i]; - for( ; j <= end; j += step ) - dct[zigzag[j]] = 0; return 1; } @@ -862,7 +867,8 @@ int x264_quant_luma_dc_trellis( x264_t *h, dctcoef *dct, int i_quant_cat, int i_ { if( h->param.b_cabac ) return quant_trellis_cabac( h, dct, - h->quant4_mf[i_quant_cat][i_qp], h->unquant4_mf[i_quant_cat][i_qp], NULL, x264_zigzag_scan4[MB_INTERLACED], + h->quant4_mf[i_quant_cat][i_qp], h->quant4_bias0[i_quant_cat][i_qp], + h->unquant4_mf[i_quant_cat][i_qp], NULL, x264_zigzag_scan4[MB_INTERLACED], ctx_block_cat, h->mb.i_trellis_lambda2[0][b_intra], 0, 0, 1, 16, idx ); return quant_trellis_cavlc( h, dct, @@ -892,7 +898,8 @@ int x264_quant_chroma_dc_trellis( x264_t *h, dctcoef *dct, int i_qp, int b_intra if( h->param.b_cabac ) return quant_trellis_cabac( h, dct, - h->quant4_mf[quant_cat][i_qp], h->unquant4_mf[quant_cat][i_qp], NULL, zigzag, + h->quant4_mf[quant_cat][i_qp], h->quant4_bias0[quant_cat][i_qp], + h->unquant4_mf[quant_cat][i_qp], NULL, zigzag, DCT_CHROMA_DC, h->mb.i_trellis_lambda2[1][b_intra], 0, 1, 1, num_coefs, idx ); return quant_trellis_cavlc( h, dct, @@ -907,8 +914,8 @@ int x264_quant_4x4_trellis( x264_t *h, dctcoef *dct, int i_quant_cat, int b_ac = ctx_ac[ctx_block_cat]; if( h->param.b_cabac ) return quant_trellis_cabac( h, dct, - h->quant4_mf[i_quant_cat][i_qp], h->unquant4_mf[i_quant_cat][i_qp], - x264_dct4_weight2_zigzag[MB_INTERLACED], + h->quant4_mf[i_quant_cat][i_qp], h->quant4_bias0[i_quant_cat][i_qp], + h->unquant4_mf[i_quant_cat][i_qp], x264_dct4_weight2_zigzag[MB_INTERLACED], x264_zigzag_scan4[MB_INTERLACED], ctx_block_cat, h->mb.i_trellis_lambda2[b_chroma][b_intra], b_ac, b_chroma, 0, 16, idx ); @@ -925,8 +932,8 @@ int x264_quant_8x8_trellis( x264_t *h, dctcoef *dct, int i_quant_cat, if( h->param.b_cabac ) { return quant_trellis_cabac( h, dct, - h->quant8_mf[i_quant_cat][i_qp], h->unquant8_mf[i_quant_cat][i_qp], - x264_dct8_weight2_zigzag[MB_INTERLACED], + h->quant8_mf[i_quant_cat][i_qp], h->quant8_bias0[i_quant_cat][i_qp], + h->unquant8_mf[i_quant_cat][i_qp], x264_dct8_weight2_zigzag[MB_INTERLACED], x264_zigzag_scan8[MB_INTERLACED], ctx_block_cat, h->mb.i_trellis_lambda2[b_chroma][b_intra], 0, b_chroma, 0, 64, idx ); } diff --git a/encoder/slicetype.c b/encoder/slicetype.c index a064a988..f46697ba 100644 --- a/encoder/slicetype.c +++ b/encoder/slicetype.c @@ -283,7 +283,7 @@ static NOINLINE unsigned int x264_weight_cost_chroma444( x264_t *h, x264_frame_t return cost; } -void x264_weights_analyse( x264_t *h, x264_frame_t *fenc, x264_frame_t *ref, int b_lookahead ) +static void x264_weights_analyse( x264_t *h, x264_frame_t *fenc, x264_frame_t *ref, int b_lookahead ) { int i_delta_index = fenc->i_frame - ref->i_frame - 1; /* epsilon is chosen to require at least a numerator of 127 (with denominator = 128) */ diff --git a/filters/video/resize.c b/filters/video/resize.c index 87687268..fac9f5ed 100644 --- a/filters/video/resize.c +++ b/filters/video/resize.c @@ -32,9 +32,10 @@ cli_vid_filter_t resize_filter; static int full_check( video_info_t *info, x264_param_t *param ) { int required = 0; - required |= info->csp != param->i_csp; - required |= info->width != param->i_width; - required |= info->height != param->i_height; + required |= info->csp != param->i_csp; + required |= info->width != param->i_width; + required |= info->height != param->i_height; + required |= info->fullrange != param->vui.b_fullrange; return required; } @@ -49,6 +50,7 @@ typedef struct int width; int height; int pix_fmt; + int range; } frame_prop_t; typedef struct @@ -59,6 +61,7 @@ typedef struct cli_pic_t buffer; int buffer_allocated; int dst_csp; + int input_range; struct SwsContext *ctx; uint32_t ctx_flags; /* state of swapping chroma planes pre and post resize */ @@ -343,27 +346,6 @@ static int handle_opts( const char **optlist, char **opts, video_info_t *info, r return 0; } -static int handle_jpeg( int *format ) -{ - switch( *format ) - { - case PIX_FMT_YUVJ420P: - *format = PIX_FMT_YUV420P; - return 1; - case PIX_FMT_YUVJ422P: - *format = PIX_FMT_YUV422P; - return 1; - case PIX_FMT_YUVJ444P: - *format = PIX_FMT_YUV444P; - return 1; - case PIX_FMT_YUVJ440P: - *format = PIX_FMT_YUV440P; - return 1; - default: - return 0; - } -} - static int x264_init_sws_context( resizer_hnd_t *h ) { if( !h->ctx ) @@ -373,27 +355,22 @@ static int x264_init_sws_context( resizer_hnd_t *h ) return -1; /* set flags that will not change */ - int dst_format = h->dst.pix_fmt; - int dst_range = handle_jpeg( &dst_format ); av_set_int( h->ctx, "sws_flags", h->ctx_flags ); av_set_int( h->ctx, "dstw", h->dst.width ); av_set_int( h->ctx, "dsth", h->dst.height ); - av_set_int( h->ctx, "dst_format", dst_format ); - av_set_int( h->ctx, "dst_range", dst_range ); /* FIXME: use the correct full range value */ + av_set_int( h->ctx, "dst_format", h->dst.pix_fmt ); + av_set_int( h->ctx, "dst_range", h->dst.range ); } - int src_format = h->scale.pix_fmt; - int src_range = handle_jpeg( &src_format ); av_set_int( h->ctx, "srcw", h->scale.width ); av_set_int( h->ctx, "srch", h->scale.height ); - av_set_int( h->ctx, "src_format", src_format ); - av_set_int( h->ctx, "src_range", src_range ); /* FIXME: use the correct full range value */ + av_set_int( h->ctx, "src_format", h->scale.pix_fmt ); + av_set_int( h->ctx, "src_range", h->scale.range ); - /* FIXME: use the correct full range values - * FIXME: use the correct matrix coefficients (only YUV -> RGB conversions are supported) */ + /* FIXME: use the correct matrix coefficients (only YUV -> RGB conversions are supported) */ sws_setColorspaceDetails( h->ctx, - sws_getCoefficients( SWS_CS_DEFAULT ), src_range, - sws_getCoefficients( SWS_CS_DEFAULT ), av_get_int( h->ctx, "dst_range", NULL ), + sws_getCoefficients( SWS_CS_DEFAULT ), h->scale.range, + sws_getCoefficients( SWS_CS_DEFAULT ), h->dst.range, 0, 1<<16, 1<<16 ); return sws_init_context( h->ctx, NULL, NULL ) < 0; @@ -401,7 +378,7 @@ static int x264_init_sws_context( resizer_hnd_t *h ) static int check_resizer( resizer_hnd_t *h, cli_pic_t *in ) { - frame_prop_t input_prop = { in->img.width, in->img.height, convert_csp_to_pix_fmt( in->img.csp ) }; + frame_prop_t input_prop = { in->img.width, in->img.height, convert_csp_to_pix_fmt( in->img.csp ), h->input_range }; if( !memcmp( &input_prop, &h->scale, sizeof(frame_prop_t) ) ) return 0; /* also warn if the resizer was initialized after the first frame */ @@ -440,6 +417,7 @@ static int init( hnd_t *handle, cli_vid_filter_t *filter, video_info_t *info, x2 h->dst_csp = info->csp; h->dst.width = info->width; h->dst.height = info->height; + h->dst.range = info->fullrange; // maintain input range if( !strcmp( opt_string, "normcsp" ) ) { /* only in normalization scenarios is the input capable of changing properties */ @@ -459,6 +437,7 @@ static int init( hnd_t *handle, cli_vid_filter_t *filter, video_info_t *info, x2 h->dst_csp = param->i_csp; h->dst.width = param->i_width; h->dst.height = param->i_height; + h->dst.range = param->vui.b_fullrange; // change to libx264's range } h->ctx_flags = convert_method_to_flag( x264_otos( x264_get_option( optlist[5], opts ), "" ) ); x264_free_string_array( opts ); @@ -467,6 +446,7 @@ static int init( hnd_t *handle, cli_vid_filter_t *filter, video_info_t *info, x2 h->ctx_flags |= SWS_FULL_CHR_H_INT | SWS_FULL_CHR_H_INP | SWS_ACCURATE_RND; h->dst.pix_fmt = convert_csp_to_pix_fmt( h->dst_csp ); h->scale = h->dst; + h->input_range = info->fullrange; /* swap chroma planes if YV12/YV16/YV24 is involved, as libswscale works with I420/I422/I444 */ int src_csp = info->csp & (X264_CSP_MASK | X264_CSP_OTHER); @@ -500,6 +480,9 @@ static int init( hnd_t *handle, cli_vid_filter_t *filter, video_info_t *info, x2 if( h->dst.pix_fmt != src_pix_fmt ) x264_cli_log( NAME, X264_LOG_WARNING, "converting from %s to %s\n", av_get_pix_fmt_name( src_pix_fmt ), av_get_pix_fmt_name( h->dst.pix_fmt ) ); + else if( h->dst.range != h->input_range ) + x264_cli_log( NAME, X264_LOG_WARNING, "converting range from %s to %s\n", + h->input_range ? "PC" : "TV", h->dst.range ? "PC" : "TV" ); h->dst_csp |= info->csp & X264_CSP_VFLIP; // preserve vflip /* if the input is not variable, initialize the context */ @@ -511,9 +494,10 @@ static int init( hnd_t *handle, cli_vid_filter_t *filter, video_info_t *info, x2 } /* finished initing, overwrite values */ - info->csp = h->dst_csp; - info->width = h->dst.width; - info->height = h->dst.height; + info->csp = h->dst_csp; + info->width = h->dst.width; + info->height = h->dst.height; + info->fullrange = h->dst.range; h->prev_filter = *filter; h->prev_hnd = *handle; diff --git a/input/avs.c b/input/avs.c index 0169746d..5fc3006b 100644 --- a/input/avs.c +++ b/input/avs.c @@ -235,14 +235,40 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c "input clip height not divisible by 4 (%dx%d)\n", vi->width, vi->height ) FAIL_IF_ERROR( (opt->output_csp == X264_CSP_I420 || info->interlaced) && (vi->height&1), "input clip height not divisible by 2 (%dx%d)\n", vi->width, vi->height ) - const char *arg_name[2] = { NULL, "interlaced" }; - AVS_Value arg_arr[2] = { res, avs_new_value_bool( info->interlaced ) }; char conv_func[14] = { "ConvertTo" }; strcat( conv_func, csp ); - AVS_Value res2 = h->func.avs_invoke( h->env, conv_func, avs_new_value_array( arg_arr, 2 ), arg_name ); + char matrix[7] = ""; + int arg_count = 2; + /* if doing a rgb <-> yuv conversion then range is handled via 'matrix'. though it's only supported in 2.56+ */ + if( avs_version >= 2.56f && ((opt->output_csp == X264_CSP_RGB && avs_is_yuv( vi )) || (opt->output_csp != X264_CSP_RGB && avs_is_rgb( vi ))) ) + { + // if converting from yuv, then we specify the matrix for the input, otherwise use the output's. + int use_pc_matrix = avs_is_yuv( vi ) ? opt->input_range == RANGE_PC : opt->output_range == RANGE_PC; + strcpy( matrix, use_pc_matrix ? "PC." : "Rec" ); + strcat( matrix, "601" ); /* FIXME: use correct coefficients */ + arg_count++; + // notification that the input range has changed to the desired one + opt->input_range = opt->output_range; + } + const char *arg_name[] = { NULL, "interlaced", "matrix" }; + AVS_Value arg_arr[] = { res, avs_new_value_bool( info->interlaced ), avs_new_value_string( matrix ) }; + AVS_Value res2 = h->func.avs_invoke( h->env, conv_func, avs_new_value_array( arg_arr, arg_count ), arg_name ); FAIL_IF_ERROR( avs_is_error( res2 ), "couldn't convert input clip to %s\n", csp ) res = update_clip( h, &vi, res2, res ); } + /* if swscale is not available, change the range if necessary. This only applies to YUV-based CSPs however */ + if( avs_is_yuv( vi ) && opt->output_range != RANGE_AUTO && ((opt->input_range == RANGE_PC) != opt->output_range) ) + { + const char *levels = opt->output_range ? "TV->PC" : "PC->TV"; + x264_cli_log( "avs", X264_LOG_WARNING, "performing %s conversion\n", levels ); + AVS_Value arg_arr[] = { res, avs_new_value_string( levels ) }; + const char *arg_name[] = { NULL, "levels" }; + AVS_Value res2 = h->func.avs_invoke( h->env, "ColorYUV", avs_new_value_array( arg_arr, 2 ), arg_name ); + FAIL_IF_ERROR( avs_is_error( res2 ), "couldn't convert range: %s\n", avs_as_error( res2 ) ) + res = update_clip( h, &vi, res2, res ); + // notification that the input range has changed to the desired one + opt->input_range = opt->output_range; + } #endif h->func.avs_release_value( res ); diff --git a/input/ffms.c b/input/ffms.c index ebfdb686..626b783d 100644 --- a/input/ffms.c +++ b/input/ffms.c @@ -65,6 +65,18 @@ static int FFMS_CC update_progress( int64_t current, int64_t total, void *privat return 0; } +/* handle the deprecated jpeg pixel formats */ +static int handle_jpeg( int csp, int *fullrange ) +{ + switch( csp ) + { + case PIX_FMT_YUVJ420P: *fullrange = 1; return PIX_FMT_YUV420P; + case PIX_FMT_YUVJ422P: *fullrange = 1; return PIX_FMT_YUV422P; + case PIX_FMT_YUVJ444P: *fullrange = 1; return PIX_FMT_YUV444P; + default: return csp; + } +} + static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, cli_input_opt_t *opt ) { ffms_hnd_t *h = calloc( 1, sizeof(ffms_hnd_t) ); @@ -119,11 +131,13 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c const FFMS_Frame *frame = FFMS_GetFrame( h->video_source, 0, &e ); FAIL_IF_ERROR( !frame, "could not read frame 0\n" ) + info->fullrange = 0; info->width = frame->EncodedWidth; info->height = frame->EncodedHeight; - info->csp = frame->EncodedPixelFormat | X264_CSP_OTHER; + info->csp = handle_jpeg( frame->EncodedPixelFormat, &info->fullrange ) | X264_CSP_OTHER; info->interlaced = frame->InterlacedFrame; info->tff = frame->TopFieldFirst; + info->fullrange |= frame->ColorRange == FFMS_CR_JPEG; /* ffms timestamps are in milliseconds. ffms also uses int64_ts for timebase, * so we need to reduce large timebases to prevent overflow */ diff --git a/input/input.h b/input/input.h index bd7e4218..ecd1f380 100644 --- a/input/input.h +++ b/input/input.h @@ -42,6 +42,8 @@ typedef struct int seek; int progress; int output_csp; /* convert to this csp, if applicable */ + int output_range; /* user desired output range */ + int input_range; /* user override input range */ } cli_input_opt_t; /* properties of the source given by the demuxer */ @@ -50,6 +52,8 @@ typedef struct int csp; /* colorspace of the input */ uint32_t fps_num; uint32_t fps_den; + int fullrange; /* has 2^bit_depth-1 instead of 219*2^(bit_depth-8) ranges (YUV only) */ + int width; int height; int interlaced; int num_frames; @@ -60,7 +64,6 @@ typedef struct uint32_t timebase_num; uint32_t timebase_den; int vfr; - int width; } video_info_t; /* image data type used by x264cli */ diff --git a/input/lavf.c b/input/lavf.c index 1073ee5a..4b35422a 100644 --- a/input/lavf.c +++ b/input/lavf.c @@ -46,6 +46,18 @@ typedef struct av_init_packet( pkt );\ } +/* handle the deprecated jpeg pixel formats */ +static int handle_jpeg( int csp, int *fullrange ) +{ + switch( csp ) + { + case PIX_FMT_YUVJ420P: *fullrange = 1; return PIX_FMT_YUV420P; + case PIX_FMT_YUVJ422P: *fullrange = 1; return PIX_FMT_YUV422P; + case PIX_FMT_YUVJ444P: *fullrange = 1; return PIX_FMT_YUV444P; + default: return csp; + } +} + static int read_frame_internal( cli_pic_t *p_pic, lavf_hnd_t *h, int i_frame, video_info_t *info ) { if( h->first_pic && !info ) @@ -101,14 +113,16 @@ static int read_frame_internal( cli_pic_t *p_pic, lavf_hnd_t *h, int i_frame, vi memcpy( p_pic->img.stride, frame.linesize, sizeof(p_pic->img.stride) ); memcpy( p_pic->img.plane, frame.data, sizeof(p_pic->img.plane) ); - p_pic->img.height = c->height; - p_pic->img.csp = c->pix_fmt | X264_CSP_OTHER; + int is_fullrange = 0; p_pic->img.width = c->width; + p_pic->img.height = c->height; + p_pic->img.csp = handle_jpeg( c->pix_fmt, &is_fullrange ) | X264_CSP_OTHER; if( info ) { + info->fullrange = is_fullrange; info->interlaced = frame.interlaced_frame; - info->tff = frame.top_field_first; + info->tff = frame.top_field_first; } if( h->vfr_input ) @@ -186,6 +200,7 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c info->num_frames = h->lavf->streams[i]->nb_frames; info->sar_height = c->sample_aspect_ratio.den; info->sar_width = c->sample_aspect_ratio.num; + info->fullrange |= c->color_range == AVCOL_RANGE_JPEG; /* avisynth stores rgb data vertically flipped. */ if( !strcasecmp( get_filename_extension( psz_filename ), "avs" ) && diff --git a/input/timecode.c b/input/timecode.c index cfec6c90..143304e5 100644 --- a/input/timecode.c +++ b/input/timecode.c @@ -368,8 +368,6 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c timecode_input.picture_alloc = h->input.picture_alloc; timecode_input.picture_clean = h->input.picture_clean; - *p_handle = h; - tcfile_in = fopen( psz_filename, "rb" ); FAIL_IF_ERROR( !tcfile_in, "can't open `%s'\n", psz_filename ) else if( !x264_is_regular_file( tcfile_in ) ) @@ -392,6 +390,7 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c info->timebase_den = h->timebase_den; info->vfr = 1; + *p_handle = h; return 0; } diff --git a/tools/checkasm.c b/tools/checkasm.c index 0c587efb..1958a7de 100644 --- a/tools/checkasm.c +++ b/tools/checkasm.c @@ -55,7 +55,7 @@ int quiet = 0; #define BENCH_RUNS 100 // tradeoff between accuracy and speed #define BENCH_ALIGNS 16 // number of stack+heap data alignments (another accuracy vs speed tradeoff) #define MAX_FUNCS 1000 // just has to be big enough to hold all the existing functions -#define MAX_CPUS 10 // number of different combinations of cpu flags +#define MAX_CPUS 30 // number of different combinations of cpu flags typedef struct { @@ -168,11 +168,10 @@ static void print_bench(void) b->cpu&X264_CPU_XOP ? "xop" : b->cpu&X264_CPU_AVX ? "avx" : b->cpu&X264_CPU_SSE4 ? "sse4" : - b->cpu&X264_CPU_SHUFFLE_IS_FAST ? "fastshuffle" : b->cpu&X264_CPU_SSSE3 ? "ssse3" : b->cpu&X264_CPU_SSE3 ? "sse3" : /* print sse2slow only if there's also a sse2fast version of the same func */ - b->cpu&X264_CPU_SSE2_IS_SLOW && jcpu&X264_CPU_SSE2_IS_SLOW && jcpu&X264_CPU_SSE2 ? "sse2" : b->cpu&X264_CPU_MMX ? "mmx" : b->cpu&X264_CPU_ALTIVEC ? "altivec" : @@ -180,6 +179,7 @@ static void print_bench(void) b->cpu&X264_CPU_ARMV6 ? "armv6" : "c", b->cpu&X264_CPU_CACHELINE_32 ? "_c32" : b->cpu&X264_CPU_CACHELINE_64 ? "_c64" : + b->cpu&X264_CPU_SHUFFLE_IS_FAST && !(b->cpu&X264_CPU_SSE4) ? "_fastshuffle" : b->cpu&X264_CPU_SSE_MISALIGN ? "_misalign" : b->cpu&X264_CPU_LZCNT ? "_lzcnt" : b->cpu&X264_CPU_FAST_NEON_MRC ? "_fast_mrc" : @@ -516,8 +516,10 @@ static int check_pixel( int cpu_ref, int cpu_new ) set_func_name( #name ); \ used_asm = 1; \ ALIGNED_ARRAY_64( uint16_t, bitcosts,[17] ); \ - ALIGNED_ARRAY_16( uint16_t, satds_c,[16] ) = {0}; \ - ALIGNED_ARRAY_16( uint16_t, satds_a,[16] ) = {0}; \ + ALIGNED_ARRAY_16( uint16_t, satds_c,[16] ); \ + ALIGNED_ARRAY_16( uint16_t, satds_a,[16] ); \ + memset( satds_c, 0, 16 * sizeof(*satds_c) ); \ + memset( satds_a, 0, 16 * sizeof(*satds_a) ); \ for( int i=0; i<17; i++ ) \ bitcosts[i] = 9*(i!=8); \ for( int i=0; i<32; i++ ) \ @@ -649,7 +651,8 @@ static int check_pixel( int cpu_ref, int cpu_new ) { ALIGNED_16( uint16_t sums[72] ); ALIGNED_16( int dc[4] ); - int16_t mvs_a[32], mvs_c[32]; + ALIGNED_16( int16_t mvs_a[32] ); + ALIGNED_16( int16_t mvs_c[32] ); int mvn_a, mvn_c; int thresh = rand() & 0x3fff; set_func_name( "esa_ads" ); @@ -2293,6 +2296,9 @@ static int add_flags( int *cpu_ref, int *cpu_new, int flags, const char *name ) { *cpu_ref = *cpu_new; *cpu_new |= flags; +#if BROKEN_STACK_ALIGNMENT + *cpu_new |= X264_CPU_STACK_MOD4; +#endif if( *cpu_new & X264_CPU_SSE2_IS_FAST ) *cpu_new &= ~X264_CPU_SSE2_IS_SLOW; if( !quiet ) @@ -2327,6 +2333,7 @@ static int check_all_flags( void ) ret |= add_flags( &cpu0, &cpu1, X264_CPU_SSE | X264_CPU_SSE2 | X264_CPU_SSE2_IS_SLOW, "SSE2Slow" ); ret |= add_flags( &cpu0, &cpu1, X264_CPU_SSE2_IS_FAST, "SSE2Fast" ); ret |= add_flags( &cpu0, &cpu1, X264_CPU_CACHELINE_64, "SSE2Fast Cache64" ); + cpu1 &= ~X264_CPU_CACHELINE_64; ret |= add_flags( &cpu0, &cpu1, X264_CPU_SHUFFLE_IS_FAST, "SSE2 FastShuffle" ); cpu1 &= ~X264_CPU_SHUFFLE_IS_FAST; ret |= add_flags( &cpu0, &cpu1, X264_CPU_SLOW_CTZ, "SSE2 SlowCTZ" ); @@ -2336,23 +2343,24 @@ static int check_all_flags( void ) } if( x264_cpu_detect() & X264_CPU_SSE_MISALIGN ) { - cpu1 &= ~X264_CPU_CACHELINE_64; ret |= add_flags( &cpu0, &cpu1, X264_CPU_SSE_MISALIGN, "SSE_Misalign" ); cpu1 &= ~X264_CPU_SSE_MISALIGN; } if( x264_cpu_detect() & X264_CPU_LZCNT ) { - cpu1 &= ~X264_CPU_CACHELINE_64; ret |= add_flags( &cpu0, &cpu1, X264_CPU_LZCNT, "SSE_LZCNT" ); cpu1 &= ~X264_CPU_LZCNT; } if( x264_cpu_detect() & X264_CPU_SSE3 ) + { ret |= add_flags( &cpu0, &cpu1, X264_CPU_SSE3 | X264_CPU_CACHELINE_64, "SSE3" ); + cpu1 &= ~X264_CPU_CACHELINE_64; + } if( x264_cpu_detect() & X264_CPU_SSSE3 ) { - cpu1 &= ~X264_CPU_CACHELINE_64; ret |= add_flags( &cpu0, &cpu1, X264_CPU_SSSE3, "SSSE3" ); ret |= add_flags( &cpu0, &cpu1, X264_CPU_CACHELINE_64, "SSSE3 Cache64" ); + cpu1 &= ~X264_CPU_CACHELINE_64; ret |= add_flags( &cpu0, &cpu1, X264_CPU_SHUFFLE_IS_FAST, "SSSE3 FastShuffle" ); cpu1 &= ~X264_CPU_SHUFFLE_IS_FAST; ret |= add_flags( &cpu0, &cpu1, X264_CPU_SLOW_CTZ, "SSSE3 SlowCTZ" ); @@ -2361,10 +2369,7 @@ static int check_all_flags( void ) cpu1 &= ~X264_CPU_SLOW_ATOM; } if( x264_cpu_detect() & X264_CPU_SSE4 ) - { - cpu1 &= ~X264_CPU_CACHELINE_64; - ret |= add_flags( &cpu0, &cpu1, X264_CPU_SSE4, "SSE4" ); - } + ret |= add_flags( &cpu0, &cpu1, X264_CPU_SSE4 | X264_CPU_SHUFFLE_IS_FAST, "SSE4" ); if( x264_cpu_detect() & X264_CPU_AVX ) ret |= add_flags( &cpu0, &cpu1, X264_CPU_AVX, "AVX" ); if( x264_cpu_detect() & X264_CPU_XOP ) diff --git a/x264.c b/x264.c index 5c3385f9..6f891498 100644 --- a/x264.c +++ b/x264.c @@ -53,6 +53,7 @@ #endif #if HAVE_SWSCALE +#undef DECLARE_ALIGNED #include #endif @@ -135,6 +136,8 @@ static const char * const output_csp_names[] = 0 }; +static const char * const range_names[] = { "auto", "tv", "pc", 0 }; + typedef struct { int mod; @@ -742,9 +745,8 @@ static void help( x264_param_t *defaults, int longhelp ) H2( " --videoformat Specify video format [\"%s\"]\n" " - component, pal, ntsc, secam, mac, undef\n", strtable_lookup( x264_vidformat_names, defaults->vui.i_vidformat ) ); - H2( " --fullrange Specify full range samples setting [\"%s\"]\n" - " - off, on\n", - strtable_lookup( x264_fullrange_names, defaults->vui.b_fullrange ) ); + H2( " --range Specify color range [\"%s\"]\n" + " - %s\n", range_names[0], stringify_names( buf, range_names ) ); H2( " --colorprim Specify color primaries [\"%s\"]\n" " - undef, bt709, bt470m, bt470bg\n" " smpte170m, smpte240m, film\n", @@ -780,6 +782,8 @@ static void help( x264_param_t *defaults, int longhelp ) H1( " --output-csp Specify output colorspace [\"%s\"]\n" " - %s\n", output_csp_names[0], stringify_names( buf, output_csp_names ) ); H1( " --input-depth Specify input bit depth for raw input\n" ); + H1( " --input-range Specify input color range [\"%s\"]\n" + " - %s\n", range_names[0], stringify_names( buf, range_names ) ); H1( " --input-res Specify input resolution (width x height)\n" ); H1( " --index Filename for input index file\n" ); H0( " --sar width:height Specify Sample Aspect Ratio\n" ); @@ -861,7 +865,9 @@ typedef enum OPT_INPUT_CSP, OPT_INPUT_DEPTH, OPT_DTS_COMPRESSION, - OPT_OUTPUT_CSP + OPT_OUTPUT_CSP, + OPT_INPUT_RANGE, + OPT_RANGE } OptionsOPT; static char short_options[] = "8A:B:b:f:hI:i:m:o:p:q:r:t:Vvw"; @@ -1000,7 +1006,7 @@ static struct option long_options[] = { "cqm8p", required_argument, NULL, 0 }, { "overscan", required_argument, NULL, 0 }, { "videoformat", required_argument, NULL, 0 }, - { "fullrange", required_argument, NULL, 0 }, + { "range", required_argument, NULL, OPT_RANGE }, { "colorprim", required_argument, NULL, 0 }, { "transfer", required_argument, NULL, 0 }, { "colormatrix", required_argument, NULL, 0 }, @@ -1023,6 +1029,7 @@ static struct option long_options[] = { "input-depth", required_argument, NULL, OPT_INPUT_DEPTH }, { "dts-compress", no_argument, NULL, OPT_DTS_COMPRESSION }, { "output-csp", required_argument, NULL, OPT_OUTPUT_CSP }, + { "input-range", required_argument, NULL, OPT_INPUT_RANGE }, {0, 0, 0, 0} }; @@ -1186,6 +1193,9 @@ static int init_vid_filters( char *sequence, hnd_t *handle, video_info_t *info, else if( output_csp == X264_CSP_RGB && (csp < X264_CSP_BGR || csp > X264_CSP_RGB) ) param->i_csp = X264_CSP_RGB; param->i_csp |= info->csp & X264_CSP_HIGH_DEPTH; + /* if the output range is not forced, assign it to the input one now */ + if( param->vui.b_fullrange == RANGE_AUTO ) + param->vui.b_fullrange = info->fullrange; if( x264_init_vid_filter( "resize", handle, &filter, info, param, NULL ) ) return -1; @@ -1247,6 +1257,7 @@ static int parse( int argc, char **argv, x264_param_t *param, cli_opt_t *opt ) memset( &input_opt, 0, sizeof(cli_input_opt_t) ); memset( &output_opt, 0, sizeof(cli_output_opt_t) ); input_opt.bit_depth = 8; + input_opt.input_range = input_opt.output_range = param->vui.b_fullrange = RANGE_AUTO; int output_csp = defaults.i_csp; opt->b_progress = 1; @@ -1412,6 +1423,14 @@ static int parse( int argc, char **argv, x264_param_t *param, cli_opt_t *opt ) #endif param->i_csp = output_csp = output_csp_fix[output_csp]; break; + case OPT_INPUT_RANGE: + FAIL_IF_ERROR( parse_enum_value( optarg, range_names, &input_opt.input_range ), "Unknown input range `%s'\n", optarg ) + input_opt.input_range += RANGE_AUTO; + break; + case OPT_RANGE: + FAIL_IF_ERROR( parse_enum_value( optarg, range_names, ¶m->vui.b_fullrange ), "Unknown range `%s'\n", optarg ); + input_opt.output_range = param->vui.b_fullrange += RANGE_AUTO; + break; default: generic_option: { @@ -1462,10 +1481,11 @@ static int parse( int argc, char **argv, x264_param_t *param, cli_opt_t *opt ) video_info_t info = {0}; char demuxername[5]; - /* set info flags to param flags to be overwritten by demuxer as necessary. */ + /* set info flags to be overwritten by demuxer as necessary. */ info.csp = param->i_csp; info.fps_num = param->i_fps_num; info.fps_den = param->i_fps_den; + info.fullrange = input_opt.input_range == RANGE_PC; info.interlaced = param->b_interlaced; info.sar_width = param->vui.i_sar_width; info.sar_height = param->vui.i_sar_height; @@ -1550,6 +1570,8 @@ static int parse( int argc, char **argv, x264_param_t *param, cli_opt_t *opt ) info.interlaced = param->b_interlaced; info.tff = param->b_tff; } + if( input_opt.input_range != RANGE_AUTO ) + info.fullrange = input_opt.input_range; if( init_vid_filters( vid_filters, &opt->hin, &info, param, output_csp ) ) return -1; @@ -1581,6 +1603,15 @@ static int parse( int argc, char **argv, x264_param_t *param, cli_opt_t *opt ) x264_cli_log( "x264", X264_LOG_WARNING, "input appears to be interlaced, but not compiled with interlaced support\n" ); #endif } + /* if the user never specified the output range and the input is now rgb, default it to pc */ + int csp = param->i_csp & X264_CSP_MASK; + if( csp >= X264_CSP_BGR && csp <= X264_CSP_RGB ) + { + if( input_opt.output_range == RANGE_AUTO ) + param->vui.b_fullrange = RANGE_PC; + /* otherwise fail if they specified tv */ + FAIL_IF_ERROR( !param->vui.b_fullrange, "RGB must be PC range" ) + } /* Automatically reduce reference frame count to match the user's target level * if the user didn't explicitly set a reference frame count. */ diff --git a/x264.h b/x264.h index d8048af3..b7aae80d 100644 --- a/x264.h +++ b/x264.h @@ -41,7 +41,7 @@ #include "x264_config.h" -#define X264_BUILD 119 +#define X264_BUILD 120 /* x264_t: * opaque handler for encoder */ @@ -735,12 +735,8 @@ typedef struct x264_hrd_t hrd_timing; /* In: arbitrary user SEI (e.g subtitles, AFDs) */ x264_sei_t extra_sei; - /* private user data. libx264 doesn't touch this, - not even copy it from input to output frames. */ + /* private user data. copied from input to output frames. */ void *opaque; - /* private user data, libx264 doesn't touch this, - copied from input to output frames. */ - void *passthrough_opaque; } x264_picture_t; /* x264_picture_init: diff --git a/x264cli.h b/x264cli.h index 29e961cd..cc44a1aa 100644 --- a/x264cli.h +++ b/x264cli.h @@ -72,4 +72,11 @@ if( cond )\ #define FAIL_IF_ERR( cond, name, ... ) RETURN_IF_ERR( cond, name, -1, __VA_ARGS__ ) +typedef enum +{ + RANGE_AUTO = -1, + RANGE_TV, + RANGE_PC +} range_enum; + #endif From 97bb99fcfa1a6ae8e77d2167d85a69182464727d Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 13 Dec 2011 21:14:40 +0000 Subject: [PATCH 28/81] Add missing lines in hrd output. --- encoder/ratecontrol.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index c9a94db5..391f5c6b 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -1724,6 +1724,8 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) { // access unit initialises the HRD h->fenc->hrd_timing.cpb_initial_arrival_time = 0; + rc->initial_cpb_removal_delay = h->initial_cpb_removal_delay; + rc->initial_cpb_removal_delay_offset = h->initial_cpb_removal_delay_offset; h->fenc->hrd_timing.cpb_removal_time = rc->nrt_first_access_unit = (int64_t)h->initial_cpb_removal_delay * 300; } else @@ -1734,7 +1736,11 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) h->fenc->hrd_timing.cpb_initial_arrival_time = h->fenc->hrd_timing.cpb_removal_time - rc->initial_cpb_removal_delay * 300; if( h->fenc->b_keyframe ) + { rc->nrt_first_access_unit = h->fenc->hrd_timing.cpb_removal_time; + rc->initial_cpb_removal_delay = h->initial_cpb_removal_delay; + rc->initial_cpb_removal_delay_offset = h->initial_cpb_removal_delay_offset; + } else h->fenc->hrd_timing.cpb_initial_arrival_time -= rc->initial_cpb_removal_delay_offset * 300; } From 6787ff946d789bfbe61ccee4a87b81657438ece4 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Thu, 15 Dec 2011 22:37:12 +0000 Subject: [PATCH 29/81] Including cpb removal delay offset in the initial arrival time is wrong. --- encoder/ratecontrol.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index 391f5c6b..0eb842e3 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -1741,8 +1741,6 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) rc->initial_cpb_removal_delay = h->initial_cpb_removal_delay; rc->initial_cpb_removal_delay_offset = h->initial_cpb_removal_delay_offset; } - else - h->fenc->hrd_timing.cpb_initial_arrival_time -= rc->initial_cpb_removal_delay_offset * 300; } h->fenc->hrd_timing.dpb_output_time = (int64_t)h->fenc->i_dpb_output_delay * 27000000LL * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale + From f3cfa4f2b109673b4fa156ee368038fb1559cf92 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Mon, 19 Dec 2011 15:36:32 +0000 Subject: [PATCH 30/81] Make HRD timings work acceptable for single frame vbv --- encoder/ratecontrol.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index 0eb842e3..d6a414ab 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -1741,6 +1741,11 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) rc->initial_cpb_removal_delay = h->initial_cpb_removal_delay; rc->initial_cpb_removal_delay_offset = h->initial_cpb_removal_delay_offset; } + + /* It's safe to do this when using single frame vbv */ + if( rc->single_frame_vbv ) + h->fenc->hrd_timing.cpb_initial_arrival_time -= rc->initial_cpb_removal_delay_offset * 300; + } h->fenc->hrd_timing.dpb_output_time = (int64_t)h->fenc->i_dpb_output_delay * 27000000LL * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale + From d244441ace098686ed427eef2f5fe126bec30a6b Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 20 Dec 2011 14:41:32 +0000 Subject: [PATCH 31/81] Make HRD output timings more accurate --- encoder/ratecontrol.c | 48 ++++++++++++++++++++++++++++++++----------- x264.h | 1 + 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index d6a414ab..1c035c33 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -157,7 +157,11 @@ struct x264_ratecontrol_t int initial_cpb_removal_delay; int initial_cpb_removal_delay_offset; int64_t nrt_first_access_unit; /* nominal removal time */ - int64_t previous_cpb_final_arrival_time; + + /* Integer and fractional part of the cpb arrival time */ + int64_t previous_cpb_final_arrival_time_int; + int64_t previous_cpb_final_arrival_time_frac; + uint64_t hrd_multiply_denom; }; @@ -638,11 +642,11 @@ int x264_ratecontrol_new( x264_t *h ) if( h->param.i_nal_hrd ) { uint64_t denom = (uint64_t)h->sps->vui.hrd.i_bit_rate_unscaled * h->sps->vui.i_time_scale; - uint64_t num = 180000; + uint64_t num = 54000000; x264_reduce_fraction64( &num, &denom ); - rc->hrd_multiply_denom = 180000 / num; + rc->hrd_multiply_denom = 54000000 / num; - double bits_required = log2( 180000 / rc->hrd_multiply_denom ) + double bits_required = log2( 54000000 / rc->hrd_multiply_denom ) + log2( h->sps->vui.i_time_scale ) + log2( h->sps->vui.hrd.i_cpb_size_unscaled ); if( bits_required >= 63 ) @@ -1720,6 +1724,9 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) if( h->param.i_nal_hrd ) { + uint64_t denom = (uint64_t)h->sps->vui.hrd.i_bit_rate_unscaled * h->sps->vui.i_time_scale / rc->hrd_multiply_denom; + uint64_t multiply_factor = 54000000 / rc->hrd_multiply_denom; + if( h->fenc->i_frame == 0 ) { // access unit initialises the HRD @@ -1733,7 +1740,7 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) h->fenc->hrd_timing.cpb_removal_time = rc->nrt_first_access_unit + (int64_t)(h->fenc->i_cpb_delay - h->i_cpb_delay_pir_offset) * 27000000LL * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale; - h->fenc->hrd_timing.cpb_initial_arrival_time = h->fenc->hrd_timing.cpb_removal_time - rc->initial_cpb_removal_delay * 300; + int64_t cpb_earliest_arrival_time = h->fenc->hrd_timing.cpb_removal_time - rc->initial_cpb_removal_delay * 300; if( h->fenc->b_keyframe ) { @@ -1741,13 +1748,29 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) rc->initial_cpb_removal_delay = h->initial_cpb_removal_delay; rc->initial_cpb_removal_delay_offset = h->initial_cpb_removal_delay_offset; } + else + cpb_earliest_arrival_time -= rc->initial_cpb_removal_delay_offset * 300; - /* It's safe to do this when using single frame vbv */ - if( rc->single_frame_vbv ) - h->fenc->hrd_timing.cpb_initial_arrival_time -= rc->initial_cpb_removal_delay_offset * 300; + /* Compare the arrival times using the 27MHz clock which should be acceptable */ + int64_t previous_cpb_arrival_time = rc->previous_cpb_final_arrival_time_int + (multiply_factor * rc->previous_cpb_final_arrival_time_frac + denom) + / (2*denom); + if( h->sps->vui.hrd.b_cbr_hrd ) + h->fenc->hrd_timing.cpb_initial_arrival_time = previous_cpb_arrival_time; + else + h->fenc->hrd_timing.cpb_initial_arrival_time = X264_MAX( previous_cpb_arrival_time, cpb_earliest_arrival_time ); } + int filler_bits = *filler ? X264_MAX( (FILLER_OVERHEAD - h->param.b_annexb), *filler )*8 : 0; + uint64_t frame_size = (bits + filler_bits) * h->sps->vui.i_time_scale; + uint64_t integer = (multiply_factor * frame_size) / (2*denom); + + rc->previous_cpb_final_arrival_time_int = h->fenc->hrd_timing.cpb_initial_arrival_time + integer; + rc->previous_cpb_final_arrival_time_frac = frame_size - ((integer * (2*denom)) / multiply_factor); + + h->fenc->hrd_timing.cpb_final_arrival_time = rc->previous_cpb_final_arrival_time_int + (multiply_factor * rc->previous_cpb_final_arrival_time_frac + denom) + / (2*denom); + h->fenc->hrd_timing.dpb_output_time = (int64_t)h->fenc->i_dpb_output_delay * 27000000LL * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale + h->fenc->hrd_timing.cpb_removal_time; } @@ -1943,7 +1966,7 @@ void x264_hrd_fullness( x264_t *h ) uint64_t denom = (uint64_t)h->sps->vui.hrd.i_bit_rate_unscaled * h->sps->vui.i_time_scale / rct->hrd_multiply_denom; uint64_t cpb_state = rct->buffer_fill_final; uint64_t cpb_size = (uint64_t)h->sps->vui.hrd.i_cpb_size_unscaled * h->sps->vui.i_time_scale; - uint64_t multiply_factor = 180000 / rct->hrd_multiply_denom; + uint64_t multiply_factor = 54000000 / rct->hrd_multiply_denom; if( rct->buffer_fill_final < 0 || rct->buffer_fill_final > cpb_size ) { @@ -1951,8 +1974,8 @@ void x264_hrd_fullness( x264_t *h ) rct->buffer_fill_final < 0 ? "underflow" : "overflow", (float)rct->buffer_fill_final/denom, (float)cpb_size/denom ); } - h->initial_cpb_removal_delay = (multiply_factor * cpb_state + denom) / (2*denom); - h->initial_cpb_removal_delay_offset = (multiply_factor * cpb_size + denom) / (2*denom) - h->initial_cpb_removal_delay; + h->initial_cpb_removal_delay = (multiply_factor * cpb_state + denom) / (600*denom); + h->initial_cpb_removal_delay_offset = (multiply_factor * cpb_size + denom) / (600*denom) - h->initial_cpb_removal_delay; } // provisionally update VBV according to the planned size of all frames currently in progress @@ -2512,7 +2535,8 @@ void x264_thread_sync_ratecontrol( x264_t *cur, x264_t *prev, x264_t *next ) COPY(bframe_bits); COPY(initial_cpb_removal_delay); COPY(initial_cpb_removal_delay_offset); - COPY(previous_cpb_final_arrival_time); + COPY(previous_cpb_final_arrival_time_int); + COPY(previous_cpb_final_arrival_time_frac); COPY(nrt_first_access_unit); #undef COPY } diff --git a/x264.h b/x264.h index b7aae80d..cbc08538 100644 --- a/x264.h +++ b/x264.h @@ -645,6 +645,7 @@ enum pic_struct_e typedef struct { int64_t cpb_initial_arrival_time; + int64_t cpb_final_arrival_time; int64_t cpb_removal_time; int64_t dpb_output_time; } x264_hrd_t; From 5ef09c79cd718bfb346d7993341cdfc77a81240f Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Fri, 23 Dec 2011 19:52:38 +0000 Subject: [PATCH 32/81] Have a safe cpb initial arrival time field so that single frame vbv can be given a slightly better arrival time. --- encoder/ratecontrol.c | 5 ++++- x264.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index 1c035c33..d3f6ecbb 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -1730,7 +1730,7 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) if( h->fenc->i_frame == 0 ) { // access unit initialises the HRD - h->fenc->hrd_timing.cpb_initial_arrival_time = 0; + h->fenc->hrd_timing.cpb_initial_arrival_time = h->fenc->hrd_timing.safe_cpb_initial_arrival_time = 0; rc->initial_cpb_removal_delay = h->initial_cpb_removal_delay; rc->initial_cpb_removal_delay_offset = h->initial_cpb_removal_delay_offset; h->fenc->hrd_timing.cpb_removal_time = rc->nrt_first_access_unit = (int64_t)h->initial_cpb_removal_delay * 300; @@ -1759,6 +1759,9 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) h->fenc->hrd_timing.cpb_initial_arrival_time = previous_cpb_arrival_time; else h->fenc->hrd_timing.cpb_initial_arrival_time = X264_MAX( previous_cpb_arrival_time, cpb_earliest_arrival_time ); + + /* With single frame vbv it's safe to allow the frame to arrive as early as possible */ + h->fenc->hrd_timing.safe_cpb_initial_arrival_time = rc->single_frame_vbv ? cpb_earliest_arrival_time : h->fenc->hrd_timing.cpb_initial_arrival_time; } int filler_bits = *filler ? X264_MAX( (FILLER_OVERHEAD - h->param.b_annexb), *filler )*8 : 0; diff --git a/x264.h b/x264.h index cbc08538..04d39e35 100644 --- a/x264.h +++ b/x264.h @@ -645,6 +645,7 @@ enum pic_struct_e typedef struct { int64_t cpb_initial_arrival_time; + int64_t safe_cpb_initial_arrival_time; int64_t cpb_final_arrival_time; int64_t cpb_removal_time; int64_t dpb_output_time; From 284ff3f6b3d5e07e2dd7d14fc857674914990b6f Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Thu, 20 Jan 2011 13:07:54 +0000 Subject: [PATCH 33/81] Add speedcontrol file. --- encoder/speed.c | 257 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 257 insertions(+) create mode 100644 encoder/speed.c diff --git a/encoder/speed.c b/encoder/speed.c new file mode 100644 index 00000000..7b5c400a --- /dev/null +++ b/encoder/speed.c @@ -0,0 +1,257 @@ +#include +#include +#include +#include "common/common.h" +#include "common/cpu.h" + +struct x264_speedcontrol_t +{ + // all times are in usec + int64_t timestamp; // when was speedcontrol last invoked + int64_t cpu_time; // time spent encoding the previous frame + int64_t buffer_size; // assumed application-side buffer of frames to be streamed, + int64_t buffer_fill; // where full = we don't have to hurry + int64_t compensation_period; // how quickly we try to return to the target buffer fullness + float fps, spf; + int preset; // which setting was used in the previous frame + int prev_frame; + float cplx_num; // rolling average of estimated spf for preset #0 + float cplx_den; + float cplx_decay; + float dither; + x264_param_t user_param; + + struct { + int64_t min_buffer, max_buffer; + double avg_preset; + int den; + } stat; +}; + +void x264_speedcontrol_new( x264_t *h ) +{ + x264_speedcontrol_t *sc = h->sc = x264_malloc( sizeof(x264_speedcontrol_t) ); + x264_emms(); + memset( sc, 0, sizeof(x264_speedcontrol_t) ); + + if( h->param.sc.f_speed <= 0 ) + h->param.sc.f_speed = 1; + sc->fps = h->param.i_fps_num / h->param.i_fps_den; + sc->spf = 1e6 / sc->fps; + h->param.sc.i_buffer_size = X264_MAX( 3, h->param.sc.i_buffer_size ); + sc->buffer_size = h->param.sc.i_buffer_size * 1e6 / sc->fps; + sc->buffer_fill = sc->buffer_size * h->param.sc.f_buffer_init; + sc->buffer_fill = x264_clip3( sc->buffer_fill, sc->spf, sc->buffer_size ); + sc->compensation_period = sc->buffer_size/4; + sc->timestamp = x264_mdate(); + sc->preset = -1; + sc->prev_frame = 0; + sc->cplx_num = 3e3; //FIXME estimate initial complexity + sc->cplx_den = .1; + sc->cplx_decay = 1 - 1./h->param.sc.i_buffer_size; + sc->stat.min_buffer = sc->buffer_size; + sc->stat.max_buffer = 0; + sc->user_param = h->param; +} + +void x264_speedcontrol_delete( x264_t *h ) +{ + x264_speedcontrol_t *sc = h->sc; + if( !sc ) + return; + x264_log( h, X264_LOG_INFO, "speedcontrol: avg preset=%.3f buffer min=%.3f max=%.3f\n", + sc->stat.avg_preset / sc->stat.den, + (float)sc->stat.min_buffer / sc->buffer_size, + (float)sc->stat.max_buffer / sc->buffer_size ); +// x264_log( h, X264_LOG_INFO, "speedcontrol: avg cplx=%.5f\n", sc->cplx_num / sc->cplx_den ); + x264_free( sc ); +} + +static int dither( x264_speedcontrol_t *sc, float f ) +{ + int i = f; + if( f < 0 ) + i--; + sc->dither += f - i; + if( sc->dither >= 1. ) + { + sc->dither--; + i++; + } + return i; +} + +typedef struct +{ + float time; // relative encoding time, compared to the other presets + int subme; + int me; + int refs; + int mix; + int trellis; + int partitions; + int chromame; + float psy_rd; + float psy_trellis; +} sc_preset_t; + +#define PRESETS 13 +static const sc_preset_t presets[PRESETS] = +{ +#define I4 X264_ANALYSE_I4x4 +#define I8 X264_ANALYSE_I8x8 +#define P8 X264_ANALYSE_PSUB16x16 +#define B8 X264_ANALYSE_BSUB16x16 +/*0*/ { .time=1.060, .subme=1, .me=X264_ME_DIA, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=0, .psy_rd=0 }, +/*1*/ { .time=1.120, .subme=1, .me=X264_ME_DIA, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=I8|I4, .psy_rd=0 }, +/*2*/ { .time=1.440, .subme=3, .me=X264_ME_HEX, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=I8|I4, .psy_rd=0 }, +/*3*/ { .time=1.620, .subme=5, .me=X264_ME_HEX, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=I8|I4, .psy_rd=1.0 }, +/*4*/ { .time=2.660, .subme=6, .me=X264_ME_HEX, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=I8|I4, .psy_rd=1.0 }, +/*5*/ { .time=3.560, .subme=6, .me=X264_ME_HEX, .refs=1, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4, .psy_rd=1.0 }, +/*6*/ { .time=4.640, .subme=6, .me=X264_ME_HEX, .refs=2, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4, .psy_rd=1.0 }, +/*7*/ { .time=5.190, .subme=7, .me=X264_ME_HEX, .refs=2, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4, .psy_rd=1.0 }, +/*8*/ { .time=6.190, .subme=7, .me=X264_ME_HEX, .refs=2, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 }, +/*9*/ { .time=6.920, .subme=7, .me=X264_ME_HEX, .refs=3, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 }, +/*10*/ { .time=7.070, .subme=8, .me=X264_ME_HEX, .refs=3, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 }, +/*11*/ { .time=8.800, .subme=8, .me=X264_ME_UMH, .refs=3, .mix=1, .chromame=1, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 }, +/*12*/ { .time=18.570, .subme=8, .me=X264_ME_UMH, .refs=3, .mix=1, .chromame=1, .trellis=2, .partitions=I8|I4|P8|B8, .psy_rd=1.0 } +}; + +static void apply_preset( x264_t *h, int preset ) +{ + x264_speedcontrol_t *sc = h->sc; + preset = x264_clip3( preset, 0, PRESETS-1 ); + //if( preset != sc->preset ) + { + const sc_preset_t *s = &presets[preset]; + x264_param_t p = sc->user_param; + + p.i_frame_reference = s->refs; + p.analyse.inter = s->partitions; + p.analyse.i_subpel_refine = s->subme; + p.analyse.i_me_method = s->me; + p.analyse.i_trellis = s->trellis; + p.analyse.b_mixed_references = s->mix; + p.analyse.b_chroma_me = s->chromame; + p.analyse.f_psy_rd = s->psy_rd; + p.analyse.f_psy_trellis = s->psy_trellis; + x264_encoder_reconfig( h, &p ); + sc->preset = preset; + x264_log( h, X264_LOG_DEBUG, "Applying speedcontrol preset %d.\n", preset ); + } +} + +void x264_speedcontrol_frame_end( x264_t *h ) +{ + x264_speedcontrol_t *sc = h->sc; + if( h->param.sc.b_alt_timer ) + sc->cpu_time = x264_mdate() - sc->timestamp; +} + +void x264_speedcontrol_frame( x264_t *h ) +{ + x264_speedcontrol_t *sc = h->sc; + int64_t t, delta_t, delta_buffer; + int delta_f; + + x264_emms(); + + // update buffer state after encoding and outputting the previous frame(s) + t = x264_mdate(); + delta_f = h->i_frame - sc->prev_frame; + delta_t = t - sc->timestamp; + delta_buffer = delta_f * sc->spf / h->param.sc.f_speed - delta_t; + sc->buffer_fill += delta_buffer; + sc->prev_frame = h->i_frame; + sc->timestamp = t; + + // update the time predictor + if( delta_f ) + { + int cpu_time = h->param.sc.b_alt_timer ? sc->cpu_time : delta_t; + float decay = powf( sc->cplx_decay, delta_f ); + sc->cplx_num *= decay; + sc->cplx_den *= decay; + sc->cplx_num += cpu_time / presets[sc->preset].time; + sc->cplx_den += delta_f; + + sc->stat.avg_preset += sc->preset * delta_f; + sc->stat.den += delta_f; + } + sc->stat.min_buffer = X264_MIN( sc->buffer_fill, sc->stat.min_buffer ); + sc->stat.max_buffer = X264_MAX( sc->buffer_fill, sc->stat.max_buffer ); + + if( sc->buffer_fill > sc->buffer_size ) // oops, cpu was idle + { + // not really an error, but we'll warn for debugging purposes + static int64_t idle_t = 0, print_interval = 0; + idle_t += sc->buffer_fill - sc->buffer_size; + if( t - print_interval > 1e6 ) + { + x264_log( h, X264_LOG_WARNING, "speedcontrol idle (%.6f sec)\n", idle_t/1e6 ); + print_interval = t; + idle_t = 0; + } + sc->buffer_fill = sc->buffer_size; + } + else if( sc->buffer_fill < 0 && delta_buffer < 0 ) // oops, we're late + { + // don't clip fullness to 0; we'll hope the real buffer was bigger than + // specified, and maybe we can catch up. if the application had to drop + // frames, then it should override the buffer fullness (FIXME implement this). + x264_log( h, X264_LOG_WARNING, "speedcontrol underflow (%.6f sec)\n", sc->buffer_fill/1e6 ); + } + + { + // pick the preset that should return the buffer to 3/4-full within a time + // specified by compensation_period + float target = sc->spf / h->param.sc.f_speed + * (sc->buffer_fill + sc->compensation_period) + / (sc->buffer_size*3/4 + sc->compensation_period); + float cplx = sc->cplx_num / sc->cplx_den; + float set, t0, t1; + float filled = (float) sc->buffer_fill / sc->buffer_size; + int i; + t0 = presets[0].time * cplx; + for( i=1;; i++ ) + { + t1 = presets[i].time * cplx; + if( t1 >= target || i == PRESETS-1 ) + break; + t0 = t1; + } + // linear interpolation between states + set = i-1 + (target - t0) / (t1 - t0); + // Even if our time estimations in the PRESETS array are off + // this will push us towards our target fullness + set += (20 * (filled-0.75)); + set = x264_clip3f(set,0,PRESETS-1); + apply_preset( h, dither( sc, set ) ); + + // FIXME + if (h->param.i_log_level >= X264_LOG_DEBUG) + { + static float cpu, wall, tgt, den; + float decay = 1-1/100.; + cpu = cpu*decay + sc->cpu_time; + wall = wall*decay + delta_t; + tgt = tgt*decay + target; + den = den*decay + 1; + fprintf( stderr, "speed: %.2f %d[%.5f] (t/c/w: %6.0f/%6.0f/%6.0f = %.4f) fps=%.2f\r", + set, sc->preset, (float)sc->buffer_fill / sc->buffer_size, + tgt/den, cpu/den, wall/den, cpu/wall, 1e6*den/wall ); + } + } + +} + +void x264_speedcontrol_sync( x264_t *h, float f_buffer_fill, int i_buffer_size ) +{ + x264_speedcontrol_t *sc = h->sc; + if( !h->param.sc.i_buffer_size ) + return; + if( i_buffer_size ) + h->param.sc.i_buffer_size = X264_MAX( 3, h->param.sc.i_buffer_size ); + sc->buffer_size = h->param.sc.i_buffer_size * 1e6 / sc->fps; + sc->buffer_fill = sc->buffer_size * f_buffer_fill; +} From 8deeec818d640c331f1df96e5f879f958826cac9 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Mon, 21 Feb 2011 02:57:27 +0000 Subject: [PATCH 34/81] Merge speedcontrol. --- Makefile | 1 + common/common.c | 15 +++++++++++++++ common/common.h | 2 ++ encoder/encoder.c | 14 ++++++++++++++ encoder/ratecontrol.h | 7 +++++++ x264.c | 10 ++++++++++ x264.h | 14 ++++++++++++++ 7 files changed, 63 insertions(+) diff --git a/Makefile b/Makefile index 51c40e36..5e6d74b1 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,7 @@ SRCS = common/mc.c common/predict.c common/pixel.c common/macroblock.c \ common/mvpred.c common/bitstream.c \ encoder/analyse.c encoder/me.c encoder/ratecontrol.c \ encoder/set.c encoder/macroblock.c encoder/cabac.c \ + encoder/speed.c \ encoder/cavlc.c encoder/encoder.c encoder/lookahead.c SRCCLI = x264.c input/input.c input/timecode.c input/raw.c input/y4m.c \ diff --git a/common/common.c b/common/common.c index 5c9a72dd..fb46fd31 100644 --- a/common/common.c +++ b/common/common.c @@ -119,6 +119,11 @@ void x264_param_default( x264_param_t *param ) param->rc.i_zones = 0; param->rc.b_mb_tree = 1; + // speedcontrol + param->sc.f_speed = 0; + param->sc.i_buffer_size = 30; + param->sc.f_buffer_init = 0.75; + /* Log */ param->pf_log = x264_log_default; param->p_log_private = NULL; @@ -986,6 +991,14 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value ) p->rc.f_complexity_blur = atof(value); OPT("zones") p->rc.psz_zones = strdup(value); + OPT("speed") + p->sc.f_speed = atof(value); + OPT("speed-bufsize") + p->sc.i_buffer_size = atoi(value); + OPT("speed-init") + p->sc.f_buffer_init = atof(value); + OPT("speed-alt-timer") + p->sc.b_alt_timer = atobool(value); OPT("crop-rect") b_error |= sscanf( value, "%u,%u,%u,%u", &p->crop_rect.i_left, &p->crop_rect.i_top, &p->crop_rect.i_right, &p->crop_rect.i_bottom ) != 4; @@ -1265,6 +1278,8 @@ char *x264_param2string( x264_param_t *p, int b_res ) s += sprintf( s, "bitdepth=%d ", BIT_DEPTH ); } + // FIXME speedcontrol stuff + s += sprintf( s, "cabac=%d", p->b_cabac ); s += sprintf( s, " ref=%d", p->i_frame_reference ); s += sprintf( s, " deblock=%d:%d:%d", p->b_deblocking_filter, diff --git a/common/common.h b/common/common.h index b6cec651..a78da341 100644 --- a/common/common.h +++ b/common/common.h @@ -424,6 +424,7 @@ typedef struct x264_lookahead_t } x264_lookahead_t; typedef struct x264_ratecontrol_t x264_ratecontrol_t; +typedef struct x264_speedcontrol_t x264_speedcontrol_t; typedef struct x264_left_table_t { @@ -827,6 +828,7 @@ struct x264_t /* rate control encoding only */ x264_ratecontrol_t *rc; + x264_speedcontrol_t *sc; /* stats */ struct diff --git a/encoder/encoder.c b/encoder/encoder.c index 7d0b5574..2b81f4db 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -898,6 +898,8 @@ static int x264_validate_parameters( x264_t *h, int b_open ) h->param.rc.f_qblur = 0; if( h->param.rc.f_complexity_blur < 0 ) h->param.rc.f_complexity_blur = 0; + if( h->param.sc.i_buffer_size < 0 || h->param.sc.f_speed <= 0 ) + h->param.sc.i_buffer_size = 0; h->param.i_sps_id &= 31; @@ -1189,6 +1191,10 @@ x264_t *x264_encoder_open( x264_param_t *param ) mbcmp_init( h ); chroma_dsp_init( h ); + if( h->param.sc.i_buffer_size ) + x264_speedcontrol_new( h ); + + p = buf + sprintf( buf, "using cpu capabilities:" ); for( int i = 0; x264_cpu_names[i].flags; i++ ) { @@ -3008,6 +3014,10 @@ int x264_encoder_encode( x264_t *h, if( h->fenc->b_keyframe && h->param.b_intra_refresh ) h->i_cpb_delay_pir_offset = h->fenc->i_cpb_delay; + /* Init the speed control */ + if( h->param.sc.i_buffer_size ) + x264_speedcontrol_frame( h ); + /* Init the rate control */ /* FIXME: Include slice header bit cost. */ x264_ratecontrol_start( h, h->fenc->i_qpplus1, overhead*8 ); @@ -3167,6 +3177,9 @@ static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current, x264_noise_reduction_update( h ); + if( h->param.sc.i_buffer_size ) + x264_speedcontrol_frame_end( h ); + /* ---------------------- Compute/Print statistics --------------------- */ x264_thread_sync_stat( h, h->thread[0] ); @@ -3608,6 +3621,7 @@ void x264_encoder_close ( x264_t *h ) /* rc */ x264_ratecontrol_delete( h ); + x264_speedcontrol_delete( h ); /* param */ if( h->param.rc.psz_stat_out ) diff --git a/encoder/ratecontrol.h b/encoder/ratecontrol.h index f5aa9a83..00a424fe 100644 --- a/encoder/ratecontrol.h +++ b/encoder/ratecontrol.h @@ -63,5 +63,12 @@ int x264_weighted_reference_duplicate( x264_t *h, int i_ref, const x264_weight_t void x264_threads_distribute_ratecontrol( x264_t *h ); void x264_threads_merge_ratecontrol( x264_t *h ); void x264_hrd_fullness( x264_t *h ); + +// speedcontrol +void x264_speedcontrol_new( x264_t *h ); +void x264_speedcontrol_delete( x264_t *h ); +void x264_speedcontrol_frame( x264_t *h ); +void x264_speedcontrol_frame_end( x264_t *h ); + #endif diff --git a/x264.c b/x264.c index 35b1f10f..0af53b75 100644 --- a/x264.c +++ b/x264.c @@ -660,6 +660,14 @@ static void help( x264_param_t *defaults, int longhelp ) " K= depending on open-gop setting\n" " QPs are restricted by qpmin/qpmax.\n" ); H1( "\n" ); + + H1( "Speedcontrol:\n" ); + H1( "\n" ); + H1( " --speed Automatically adjust other options to achieve this\n" ); + H1( " fraction of realtime.\n" ); + H1( " --speed-bufsize Averaging period for speed. (in frames) [%d]\n", defaults->sc.i_buffer_size ); + H1( "\n" ); + H1( "Analysis:\n" ); H1( "\n" ); H1( " -A, --partitions Partitions to consider [\"p8x8,b8x8,i8x8,i4x4\"]\n" @@ -964,6 +972,8 @@ static struct option long_options[] = { "cplxblur", required_argument, NULL, 0 }, { "zones", required_argument, NULL, 0 }, { "qpfile", required_argument, NULL, OPT_QPFILE }, + { "speed", required_argument, NULL, 0 }, + { "speed-bufsize", required_argument, NULL, 0 }, { "threads", required_argument, NULL, 0 }, { "sliced-threads", no_argument, NULL, 0 }, { "no-sliced-threads", no_argument, NULL, 0 }, diff --git a/x264.h b/x264.h index c95c1f2e..9dbe88f9 100644 --- a/x264.h +++ b/x264.h @@ -407,6 +407,15 @@ typedef struct x264_param_t /* frame packing arrangement flag */ int i_frame_packing; + /* Speed control parameters */ + struct + { + float f_speed; /* ratio from realtime */ + int i_buffer_size; /* number of frames */ + float f_buffer_init; /* fraction of size */ + int b_alt_timer; /* use a different method of measuring encode time FIXME */ + } sc; + /* Muxing parameters */ int b_aud; /* generate access unit delimiters */ int b_repeat_headers; /* put SPS/PPS before each keyframe */ @@ -835,4 +844,9 @@ void x264_encoder_intra_refresh( x264_t * ); * Returns 0 on success, negative on failure. */ int x264_encoder_invalidate_reference( x264_t *, int64_t pts ); +/* x264_speedcontrol_sync: + * override speedcontrol's internal clock */ +void x264_speedcontrol_sync( x264_t *, float f_buffer_fill, int i_buffer_size ); + + #endif From 91d8a8136c4bf8191653a0e1b55713d150d186e2 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 9 Nov 2010 17:10:18 +0000 Subject: [PATCH 35/81] Add "Fake HRD". This writes Buffering Period SEI but sets nal_hrd_parameters_present_flag to zero. This allows more flexible T-STD compliant TS muxing and also to workaround bugs in MPEG-2 Systems. The x264_hrd_t struct should be used for PTS and DTS. Fake HRD is not necessary for Blu-Ray. --- encoder/encoder.c | 5 +++-- encoder/set.c | 2 +- x264.h | 5 ++++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/encoder/encoder.c b/encoder/encoder.c index 2b81f4db..681a4354 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -914,8 +914,8 @@ static int x264_validate_parameters( x264_t *h, int b_open ) h->param.i_nal_hrd = X264_NAL_HRD_NONE; } - if( h->param.i_nal_hrd == X264_NAL_HRD_CBR && - (h->param.rc.i_bitrate != h->param.rc.i_vbv_max_bitrate || !h->param.rc.i_vbv_max_bitrate) ) + if( (h->param.i_nal_hrd == X264_NAL_HRD_CBR || h->param.i_nal_hrd == X264_NAL_HRD_FAKE_CBR) && + (h->param.rc.i_bitrate != h->param.rc.i_vbv_max_bitrate || !h->param.rc.i_vbv_max_bitrate) ) { x264_log( h, X264_LOG_WARNING, "CBR HRD requires constant bitrate\n" ); h->param.i_nal_hrd = X264_NAL_HRD_VBR; @@ -3086,6 +3086,7 @@ static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current, } x264_emms(); + /* generate buffering period sei and insert it into place */ if( h->i_thread_frames > 1 && h->fenc->b_keyframe && h->sps->vui.b_nal_hrd_parameters_present ) { diff --git a/encoder/set.c b/encoder/set.c index 876176af..8c556b26 100644 --- a/encoder/set.c +++ b/encoder/set.c @@ -244,7 +244,7 @@ void x264_sps_init( x264_sps_t *sps, int i_id, x264_param_t *param ) } sps->vui.b_vcl_hrd_parameters_present = 0; // we don't support VCL HRD - sps->vui.b_nal_hrd_parameters_present = !!param->i_nal_hrd; + sps->vui.b_nal_hrd_parameters_present = param->i_nal_hrd == X264_NAL_HRD_VBR || param->i_nal_hrd == X264_NAL_HRD_CBR; sps->vui.b_pic_struct_present = param->b_pic_struct; // NOTE: HRD related parts of the SPS are initialised in x264_ratecontrol_init_reconfigurable diff --git a/x264.h b/x264.h index 9dbe88f9..1bc1765e 100644 --- a/x264.h +++ b/x264.h @@ -175,7 +175,8 @@ static const char * const x264_fullrange_names[] = { "off", "on", 0 }; static const char * const x264_colorprim_names[] = { "", "bt709", "undef", "", "bt470m", "bt470bg", "smpte170m", "smpte240m", "film", 0 }; static const char * const x264_transfer_names[] = { "", "bt709", "undef", "", "bt470m", "bt470bg", "smpte170m", "smpte240m", "linear", "log100", "log316", 0 }; static const char * const x264_colmatrix_names[] = { "GBR", "bt709", "undef", "", "fcc", "bt470bg", "smpte170m", "smpte240m", "YCgCo", 0 }; -static const char * const x264_nal_hrd_names[] = { "none", "vbr", "cbr", 0 }; +static const char * const x264_nal_hrd_names[] = { "none", "vbr", "cbr", "fakevbr", "fakecbr", 0 }; +static const char * const x264_open_gop_names[] = { "none", "normal", "bluray", 0 }; /* Colorspace type */ #define X264_CSP_MASK 0x00ff /* */ @@ -221,6 +222,8 @@ static const char * const x264_nal_hrd_names[] = { "none", "vbr", "cbr", 0 }; #define X264_NAL_HRD_NONE 0 #define X264_NAL_HRD_VBR 1 #define X264_NAL_HRD_CBR 2 +#define X264_NAL_HRD_FAKE_VBR 3 +#define X264_NAL_HRD_FAKE_CBR 4 /* Zones: override ratecontrol or other options for specific sections of the video. * See x264_encoder_reconfig() for which options can be changed. From ab79ff2a95c217af8a3541d121e6e58ce269c445 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Sun, 27 Feb 2011 00:07:24 +0000 Subject: [PATCH 36/81] Use a better API for speedcontrol on Linux. --- common/osdep.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/common/osdep.c b/common/osdep.c index 75936151..b957965e 100644 --- a/common/osdep.c +++ b/common/osdep.c @@ -43,10 +43,15 @@ extern int ptw32_processInitialized; int64_t x264_mdate( void ) { -#if SYS_WINDOWS +<<<<<<< HEAD +#ifdef __MINGW32__ struct timeb tb; ftime( &tb ); return ((int64_t)tb.time * 1000 + (int64_t)tb.millitm) * 1000; +#elif __LINUX__ + struct timespec ts_current; + clock_gettime( CLOCK_MONOTONIC, &ts_current ); + return (int64_t)ts_current.tv_sec * 1000000 + (int64_t)ts_current.tv_usec; #else struct timeval tv_date; gettimeofday( &tv_date, NULL ); From 2dfa98f70bdf5e3af055054bf084a2a3dab43fec Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Mon, 7 Mar 2011 10:47:22 +0000 Subject: [PATCH 37/81] Turn off warning temporarily. --- encoder/ratecontrol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index aad66cd3..1553ccbf 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -554,7 +554,7 @@ void x264_ratecontrol_init_reconfigurable( x264_t *h, int b_init ) } else if( h->param.i_nal_hrd && !b_init ) { - x264_log( h, X264_LOG_WARNING, "VBV parameters cannot be changed when NAL HRD is in use\n" ); + //x264_log( h, X264_LOG_WARNING, "VBV parameters cannot be changed when NAL HRD is in use\n" ); return; } h->sps->vui.hrd.i_bit_rate_unscaled = vbv_max_bitrate; From b65fd9fa17ed468364ebb0a612e461cde44e869d Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Mon, 7 Mar 2011 14:24:29 +0000 Subject: [PATCH 38/81] Export profile and actual vbv values. --- encoder/encoder.c | 2 ++ encoder/ratecontrol.c | 4 ++-- x264.h | 4 ++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/encoder/encoder.c b/encoder/encoder.c index 681a4354..bb5f383e 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -1101,6 +1101,8 @@ x264_t *x264_encoder_open( x264_param_t *param ) } x264_sps_init( h->sps, h->param.i_sps_id, &h->param ); + h->param.i_profile = h->sps->i_profile_idc; + x264_pps_init( h->pps, h->param.i_sps_id, &h->param, h->sps ); x264_set_aspect_ratio( h, &h->param, 1 ); diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index 1553ccbf..be4ba608 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -549,8 +549,8 @@ void x264_ratecontrol_init_reconfigurable( x264_t *h, int b_init ) #undef MAX_DURATION - vbv_buffer_size = h->sps->vui.hrd.i_cpb_size_unscaled; - vbv_max_bitrate = h->sps->vui.hrd.i_bit_rate_unscaled; + vbv_buffer_size = h->param.rc.i_vbv_buffer_size_actual = h->sps->vui.hrd.i_cpb_size_unscaled; + vbv_max_bitrate = h->param.rc.i_vbv_max_bitrate_actual = h->sps->vui.hrd.i_bit_rate_unscaled; } else if( h->param.i_nal_hrd && !b_init ) { diff --git a/x264.h b/x264.h index 1bc1765e..5cedbfb9 100644 --- a/x264.h +++ b/x264.h @@ -253,6 +253,7 @@ typedef struct x264_param_t int i_csp; /* CSP of encoded bitstream */ int i_level_idc; int i_frame_total; /* number of frames to encode if known, else 0 */ + int i_profile; /* Output Only */ /* NAL HRD * Uses Buffering and Picture Timing SEIs to signal HRD @@ -377,6 +378,9 @@ typedef struct x264_param_t float f_ip_factor; float f_pb_factor; + int i_vbv_max_bitrate_actual; /* Output only when HRD enabled */ + int i_vbv_buffer_size_actual; /* Output only when HRD enabled */ + int i_aq_mode; /* psy adaptive QP. (X264_AQ_*) */ float f_aq_strength; int b_mb_tree; /* Macroblock-tree ratecontrol. */ From 5dff104a142e90337195130d0b8d34e0171f4e58 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 8 Mar 2011 14:45:04 +0000 Subject: [PATCH 39/81] Start counting when the first frame is encoded, not when x264_encoder_open is called. --- encoder/speed.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/encoder/speed.c b/encoder/speed.c index 7b5c400a..09917a30 100644 --- a/encoder/speed.c +++ b/encoder/speed.c @@ -21,7 +21,10 @@ struct x264_speedcontrol_t float dither; x264_param_t user_param; - struct { + int first; + + struct + { int64_t min_buffer, max_buffer; double avg_preset; int den; @@ -52,6 +55,7 @@ void x264_speedcontrol_new( x264_t *h ) sc->stat.min_buffer = sc->buffer_size; sc->stat.max_buffer = 0; sc->user_param = h->param; + sc->first = 1; } void x264_speedcontrol_delete( x264_t *h ) @@ -157,7 +161,14 @@ void x264_speedcontrol_frame( x264_t *h ) x264_emms(); // update buffer state after encoding and outputting the previous frame(s) - t = x264_mdate(); + if( sc->first ) + { + t = sc->timestamp; + sc->first = 0; + } + else + t = x264_mdate(); + delta_f = h->i_frame - sc->prev_frame; delta_t = t - sc->timestamp; delta_buffer = delta_f * sc->spf / h->param.sc.f_speed - delta_t; From e9e81348b862f47c249ef3394c7bee2a08ebc6bf Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 8 Mar 2011 14:57:03 +0000 Subject: [PATCH 40/81] Fix 10L --- encoder/speed.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encoder/speed.c b/encoder/speed.c index 09917a30..cd73fb90 100644 --- a/encoder/speed.c +++ b/encoder/speed.c @@ -163,7 +163,7 @@ void x264_speedcontrol_frame( x264_t *h ) // update buffer state after encoding and outputting the previous frame(s) if( sc->first ) { - t = sc->timestamp; + t = sc->timestamp = x264_mdate(); sc->first = 0; } else From 37db7a3dcf74948cb5823ef0ec7c875c7727dad8 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 8 Mar 2011 17:50:52 +0000 Subject: [PATCH 41/81] Fix Linux timing function and build. --- common/osdep.c | 4 ++-- configure | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/osdep.c b/common/osdep.c index b957965e..816b03f2 100644 --- a/common/osdep.c +++ b/common/osdep.c @@ -48,10 +48,10 @@ int64_t x264_mdate( void ) struct timeb tb; ftime( &tb ); return ((int64_t)tb.time * 1000 + (int64_t)tb.millitm) * 1000; -#elif __LINUX__ +#elif SYS_LINUX struct timespec ts_current; clock_gettime( CLOCK_MONOTONIC, &ts_current ); - return (int64_t)ts_current.tv_sec * 1000000 + (int64_t)ts_current.tv_usec; + return (int64_t)ts_current.tv_sec * 1000000 + (int64_t)ts_current.tv_nsec / 1000; #else struct timeval tv_date; gettimeofday( &tv_date, NULL ); diff --git a/configure b/configure index 5c58f5aa..ac263878 100755 --- a/configure +++ b/configure @@ -448,7 +448,7 @@ case $host_os in *linux*) SYS="LINUX" define HAVE_MALLOC_H - LDFLAGS="$LDFLAGS -lm" + LDFLAGS="$LDFLAGS -lm -lrt" ;; gnu*) SYS="HURD" From 9a4f969d4bf88a9a1d426353adce89b0b1aa1c25 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Wed, 9 Mar 2011 11:55:39 +0000 Subject: [PATCH 42/81] Change defaults and use x264_log --- common/common.c | 2 +- encoder/speed.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/common.c b/common/common.c index fb46fd31..37bc249f 100644 --- a/common/common.c +++ b/common/common.c @@ -121,7 +121,7 @@ void x264_param_default( x264_param_t *param ) // speedcontrol param->sc.f_speed = 0; - param->sc.i_buffer_size = 30; + param->sc.i_buffer_size = 12; param->sc.f_buffer_init = 0.75; /* Log */ diff --git a/encoder/speed.c b/encoder/speed.c index cd73fb90..7d4a1d36 100644 --- a/encoder/speed.c +++ b/encoder/speed.c @@ -248,7 +248,7 @@ void x264_speedcontrol_frame( x264_t *h ) wall = wall*decay + delta_t; tgt = tgt*decay + target; den = den*decay + 1; - fprintf( stderr, "speed: %.2f %d[%.5f] (t/c/w: %6.0f/%6.0f/%6.0f = %.4f) fps=%.2f\r", + x264_log( h, X264_LOG_DEBUG, "speed: %.2f %d[%.5f] (t/c/w: %6.0f/%6.0f/%6.0f = %.4f) fps=%.2f\r", set, sc->preset, (float)sc->buffer_fill / sc->buffer_size, tgt/den, cpu/den, wall/den, cpu/wall, 1e6*den/wall ); } From e7e953e99dcbcc8fea66152e59d114213e70d19b Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Thu, 10 Mar 2011 15:57:02 +0000 Subject: [PATCH 43/81] Fix merge problem. --- encoder/ratecontrol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index be4ba608..ce27f160 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -1714,7 +1714,7 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) *filler = update_vbv( h, bits ); rc->filler_bits_sum += *filler * 8; - if( h->sps->vui.b_nal_hrd_parameters_present ) + if( h->param.i_nal_hrd ) { if( h->fenc->i_frame == 0 ) { From 7258c34be49cd670ec5015ff89a06f57751c94be Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Thu, 12 May 2011 16:47:54 +0100 Subject: [PATCH 44/81] Fix Fake CBR --- encoder/encoder.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/encoder/encoder.c b/encoder/encoder.c index bb5f383e..350185ad 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -906,7 +906,7 @@ static int x264_validate_parameters( x264_t *h, int b_open ) if( PARAM_INTERLACED ) h->param.b_pic_struct = 1; - h->param.i_nal_hrd = x264_clip3( h->param.i_nal_hrd, X264_NAL_HRD_NONE, X264_NAL_HRD_CBR ); + h->param.i_nal_hrd = x264_clip3( h->param.i_nal_hrd, X264_NAL_HRD_NONE, X264_NAL_HRD_FAKE_CBR ); if( h->param.i_nal_hrd && !h->param.rc.i_vbv_buffer_size ) { @@ -918,7 +918,7 @@ static int x264_validate_parameters( x264_t *h, int b_open ) (h->param.rc.i_bitrate != h->param.rc.i_vbv_max_bitrate || !h->param.rc.i_vbv_max_bitrate) ) { x264_log( h, X264_LOG_WARNING, "CBR HRD requires constant bitrate\n" ); - h->param.i_nal_hrd = X264_NAL_HRD_VBR; + h->param.i_nal_hrd = h->param.i_nal_hrd == X264_NAL_HRD_CBR ? X264_NAL_HRD_VBR : X264_NAL_HRD_FAKE_CBR; } /* ensure the booleans are 0 or 1 so they can be used in math */ From d48697e5a7dc4a69d2b6651dcee8b974dad1d704 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 19 Jul 2011 13:15:56 +0100 Subject: [PATCH 45/81] Add new speedcontrol timings. --- encoder/speed.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/encoder/speed.c b/encoder/speed.c index 7d4a1d36..47eeb64b 100644 --- a/encoder/speed.c +++ b/encoder/speed.c @@ -106,19 +106,19 @@ static const sc_preset_t presets[PRESETS] = #define I8 X264_ANALYSE_I8x8 #define P8 X264_ANALYSE_PSUB16x16 #define B8 X264_ANALYSE_BSUB16x16 -/*0*/ { .time=1.060, .subme=1, .me=X264_ME_DIA, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=0, .psy_rd=0 }, -/*1*/ { .time=1.120, .subme=1, .me=X264_ME_DIA, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=I8|I4, .psy_rd=0 }, -/*2*/ { .time=1.440, .subme=3, .me=X264_ME_HEX, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=I8|I4, .psy_rd=0 }, -/*3*/ { .time=1.620, .subme=5, .me=X264_ME_HEX, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=I8|I4, .psy_rd=1.0 }, -/*4*/ { .time=2.660, .subme=6, .me=X264_ME_HEX, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=I8|I4, .psy_rd=1.0 }, -/*5*/ { .time=3.560, .subme=6, .me=X264_ME_HEX, .refs=1, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4, .psy_rd=1.0 }, -/*6*/ { .time=4.640, .subme=6, .me=X264_ME_HEX, .refs=2, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4, .psy_rd=1.0 }, -/*7*/ { .time=5.190, .subme=7, .me=X264_ME_HEX, .refs=2, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4, .psy_rd=1.0 }, -/*8*/ { .time=6.190, .subme=7, .me=X264_ME_HEX, .refs=2, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 }, -/*9*/ { .time=6.920, .subme=7, .me=X264_ME_HEX, .refs=3, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 }, -/*10*/ { .time=7.070, .subme=8, .me=X264_ME_HEX, .refs=3, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 }, -/*11*/ { .time=8.800, .subme=8, .me=X264_ME_UMH, .refs=3, .mix=1, .chromame=1, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 }, -/*12*/ { .time=18.570, .subme=8, .me=X264_ME_UMH, .refs=3, .mix=1, .chromame=1, .trellis=2, .partitions=I8|I4|P8|B8, .psy_rd=1.0 } +/*0*/ { .time=1.000, .subme=1, .me=X264_ME_DIA, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=0, .psy_rd=0 }, +/*1*/ { .time=1.009, .subme=1, .me=X264_ME_DIA, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=I8|I4, .psy_rd=0 }, +/*2*/ { .time=1.843, .subme=3, .me=X264_ME_HEX, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=I8|I4, .psy_rd=0 }, +/*3*/ { .time=1.984, .subme=5, .me=X264_ME_HEX, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=I8|I4, .psy_rd=1.0 }, +/*4*/ { .time=2.289, .subme=6, .me=X264_ME_HEX, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=I8|I4, .psy_rd=1.0 }, +/*5*/ { .time=3.113, .subme=6, .me=X264_ME_HEX, .refs=1, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4, .psy_rd=1.0 }, +/*6*/ { .time=3.400, .subme=6, .me=X264_ME_HEX, .refs=2, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4, .psy_rd=1.0 }, +/*7*/ { .time=3.755, .subme=7, .me=X264_ME_HEX, .refs=2, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4, .psy_rd=1.0 }, +/*8*/ { .time=4.592, .subme=7, .me=X264_ME_HEX, .refs=2, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 }, +/*9*/ { .time=4.730, .subme=7, .me=X264_ME_HEX, .refs=3, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 }, +/*10*/ { .time=5.453, .subme=8, .me=X264_ME_HEX, .refs=3, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 }, +/*11*/ { .time=8.277, .subme=8, .me=X264_ME_UMH, .refs=3, .mix=1, .chromame=1, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 }, +/*12*/ { .time=8.410, .subme=8, .me=X264_ME_UMH, .refs=4, .mix=1, .chromame=1, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 } }; static void apply_preset( x264_t *h, int preset ) From 198c8876e321deea8fe54872ec8933a6ca9f0773 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Wed, 27 Jul 2011 16:27:41 +0100 Subject: [PATCH 46/81] Make speedcontrol idle an informational log message. --- encoder/speed.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encoder/speed.c b/encoder/speed.c index 47eeb64b..93343a40 100644 --- a/encoder/speed.c +++ b/encoder/speed.c @@ -199,7 +199,7 @@ void x264_speedcontrol_frame( x264_t *h ) idle_t += sc->buffer_fill - sc->buffer_size; if( t - print_interval > 1e6 ) { - x264_log( h, X264_LOG_WARNING, "speedcontrol idle (%.6f sec)\n", idle_t/1e6 ); + x264_log( h, X264_LOG_INFO, "speedcontrol idle (%.6f sec)\n", idle_t/1e6 ); print_interval = t; idle_t = 0; } From 67c00ed76d34834696f996020f773b96559e8eae Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Fri, 29 Jul 2011 17:41:25 +0100 Subject: [PATCH 47/81] Only use 10 speedcontrol presets for now. --- encoder/speed.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encoder/speed.c b/encoder/speed.c index 93343a40..7bf370ef 100644 --- a/encoder/speed.c +++ b/encoder/speed.c @@ -99,7 +99,7 @@ typedef struct float psy_trellis; } sc_preset_t; -#define PRESETS 13 +#define PRESETS 10 static const sc_preset_t presets[PRESETS] = { #define I4 X264_ANALYSE_I4x4 From 168a2afbf68551cb34ce1a2c53490dfeb12cbb69 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Fri, 29 Jul 2011 17:56:06 +0100 Subject: [PATCH 48/81] Pre-place keyframes to fix long stalls when PB... becomes IP... and a new path has to be calculated. THIS BREAKS OPEN-GOP BLU-RAY and doesn't fix b-adapt=2. --- encoder/slicetype.c | 112 +++++++++++++++++++++++++++++--------------- 1 file changed, 74 insertions(+), 38 deletions(-) diff --git a/encoder/slicetype.c b/encoder/slicetype.c index e6fa93a3..4a5d5508 100644 --- a/encoder/slicetype.c +++ b/encoder/slicetype.c @@ -1309,7 +1309,7 @@ void x264_slicetype_analyse( x264_t *h, int keyframe ) if( !h->lookahead->last_nonb ) return; frames[0] = h->lookahead->last_nonb; - for( framecnt = 0; framecnt < i_max_search && h->lookahead->next.list[framecnt]->i_type == X264_TYPE_AUTO; framecnt++ ) + for( framecnt = 0; framecnt < i_max_search; framecnt++ ) frames[framecnt+1] = h->lookahead->next.list[framecnt]; x264_lowres_context_init( h, &a ); @@ -1341,7 +1341,7 @@ void x264_slicetype_analyse( x264_t *h, int keyframe ) int num_bframes = 0; int num_analysed_frames = num_frames; int reset_start; - if( h->param.i_scenecut_threshold && scenecut( h, &a, frames, 0, 1, 1, orig_num_frames, i_max_search ) ) + if( h->param.i_scenecut_threshold && !IS_INTRA( frames[1]->i_type ) && scenecut( h, &a, frames, 0, 1, 1, orig_num_frames, i_max_search ) ) { frames[1]->i_type = X264_TYPE_I; return; @@ -1365,12 +1365,25 @@ void x264_slicetype_analyse( x264_t *h, int keyframe ) for( int j = 1; j < num_frames; j++ ) frames[j]->i_type = best_paths[best_path_index][j-1] == 'B' ? X264_TYPE_B : X264_TYPE_P; } - frames[num_frames]->i_type = X264_TYPE_P; + if( !frames[num_frames]->b_keyframe ) + frames[num_frames]->i_type = X264_TYPE_P; } else if( h->param.i_bframe_adaptive == X264_B_ADAPT_FAST ) { for( int i = 0; i <= num_frames-2; ) { + if( frames[i+1]->b_keyframe ) + { + i++; + continue; + } + + if( frames[i+2]->b_keyframe ) + { + frames[i+1]->i_type = X264_TYPE_B; + i += 2; + continue; + } cost2p1 = x264_slicetype_frame_cost( h, &a, frames, i+0, i+2, i+2, 1 ); if( frames[i+2]->i_intra_mbs[2] > i_mb_count / 2 ) { @@ -1399,16 +1412,20 @@ void x264_slicetype_analyse( x264_t *h, int keyframe ) int j; for( j = i+2; j <= X264_MIN( i+h->param.i_bframe, num_frames-1 ); j++ ) { + if( frames[j]->b_keyframe ) + break; int pthresh = X264_MAX(INTER_THRESH - P_SENS_BIAS * (j-i-1), INTER_THRESH/10); int pcost = x264_slicetype_frame_cost( h, &a, frames, i+0, j+1, j+1, 1 ); if( pcost > pthresh*i_mb_count || frames[j+1]->i_intra_mbs[j-i+1] > i_mb_count/3 ) break; frames[j]->i_type = X264_TYPE_B; } - frames[j]->i_type = X264_TYPE_P; + if( !frames[j]->b_keyframe ) + frames[j]->i_type = X264_TYPE_P; i = j; } - frames[num_frames]->i_type = X264_TYPE_P; + if( !frames[num_frames]->b_keyframe ) + frames[num_frames]->i_type = X264_TYPE_P; num_bframes = 0; while( num_bframes < num_frames && frames[num_bframes+1]->i_type == X264_TYPE_B ) num_bframes++; @@ -1417,8 +1434,12 @@ void x264_slicetype_analyse( x264_t *h, int keyframe ) { num_bframes = X264_MIN(num_frames-1, h->param.i_bframe); for( int j = 1; j < num_frames; j++ ) - frames[j]->i_type = (j%(num_bframes+1)) ? X264_TYPE_B : X264_TYPE_P; - frames[num_frames]->i_type = X264_TYPE_P; + { + if( !frames[j]->b_keyframe ) + frames[j]->i_type = (j%(num_bframes+1)) ? X264_TYPE_B : X264_TYPE_P; + } + if( !frames[num_frames]->b_keyframe ) + frames[num_frames]->i_type = X264_TYPE_P; } /* Check scenecut on the first minigop. */ @@ -1435,7 +1456,10 @@ void x264_slicetype_analyse( x264_t *h, int keyframe ) else { for( int j = 1; j <= num_frames; j++ ) - frames[j]->i_type = X264_TYPE_P; + { + if( !frames[j]->b_keyframe ) + frames[j]->i_type = X264_TYPE_P; + } reset_start = !keyframe + 1; num_bframes = 0; } @@ -1445,6 +1469,7 @@ void x264_slicetype_analyse( x264_t *h, int keyframe ) if( h->param.rc.b_mb_tree ) x264_macroblock_tree( h, &a, frames, X264_MIN(num_frames, h->param.i_keyint_max), keyframe ); +#if 0 /* Enforce keyframe limit. */ if( !h->param.b_intra_refresh ) for( int i = keyint_limit+1; i <= num_frames; i += h->param.i_keyint_max ) @@ -1455,13 +1480,17 @@ void x264_slicetype_analyse( x264_t *h, int keyframe ) while( IS_X264_TYPE_B( frames[i-1]->i_type ) ) i--; } +#endif if( vbv_lookahead ) x264_vbv_lookahead( h, &a, frames, num_frames, keyframe ); - /* Restore frametypes for all frames that haven't actually been decided yet. */ + /* Restore non-keyint frametypes for all frames that haven't actually been decided yet. */ for( int j = reset_start; j <= num_frames; j++ ) - frames[j]->i_type = X264_TYPE_AUTO; + { + if( !frames[j]->b_keyframe ) + frames[j]->i_type = X264_TYPE_AUTO; + } } void x264_slicetype_decide( x264_t *h ) @@ -1512,32 +1541,10 @@ void x264_slicetype_decide( x264_t *h ) h->lookahead->next.list[i]->i_type = x264_ratecontrol_slice_type( h, h->lookahead->next.list[i]->i_frame ); } - else if( (h->param.i_bframe && h->param.i_bframe_adaptive) - || h->param.i_scenecut_threshold - || h->param.rc.b_mb_tree - || (h->param.rc.i_vbv_buffer_size && h->param.rc.i_lookahead) ) - x264_slicetype_analyse( h, 0 ); - for( bframes = 0, brefs = 0;; bframes++ ) + for( int i = 0; i < h->lookahead->next.i_size; i++ ) { - frm = h->lookahead->next.list[bframes]; - if( frm->i_type == X264_TYPE_BREF && h->param.i_bframe_pyramid < X264_B_PYRAMID_NORMAL && - brefs == h->param.i_bframe_pyramid ) - { - frm->i_type = X264_TYPE_B; - x264_log( h, X264_LOG_WARNING, "B-ref at frame %d incompatible with B-pyramid %s \n", - frm->i_frame, x264_b_pyramid_names[h->param.i_bframe_pyramid] ); - } - /* pyramid with multiple B-refs needs a big enough dpb that the preceding P-frame stays available. - smaller dpb could be supported by smart enough use of mmco, but it's easier just to forbid it. */ - else if( frm->i_type == X264_TYPE_BREF && h->param.i_bframe_pyramid == X264_B_PYRAMID_NORMAL && - brefs && h->param.i_frame_reference <= (brefs+3) ) - { - frm->i_type = X264_TYPE_B; - x264_log( h, X264_LOG_WARNING, "B-ref at frame %d incompatible with B-pyramid %s and %d reference frames\n", - frm->i_frame, x264_b_pyramid_names[h->param.i_bframe_pyramid], h->param.i_frame_reference ); - } - + frm = h->lookahead->next.list[i]; if( frm->i_type == X264_TYPE_KEYFRAME ) frm->i_type = h->param.b_open_gop ? X264_TYPE_I : X264_TYPE_IDR; @@ -1552,13 +1559,12 @@ void x264_slicetype_decide( x264_t *h ) if( warn ) x264_log( h, X264_LOG_WARNING, "specified frame type (%d) at %d is not compatible with keyframe interval\n", frm->i_type, frm->i_frame ); } + if( frm->i_type == X264_TYPE_I && frm->i_frame - h->lookahead->i_last_keyframe >= h->param.i_keyint_min ) { if( h->param.b_open_gop ) { h->lookahead->i_last_keyframe = frm->i_frame; // Use display order - if( h->param.b_bluray_compat ) - h->lookahead->i_last_keyframe -= bframes; // Use bluray order frm->b_keyframe = 1; } else @@ -1569,6 +1575,37 @@ void x264_slicetype_decide( x264_t *h ) /* Close GOP */ h->lookahead->i_last_keyframe = frm->i_frame; frm->b_keyframe = 1; + } + } + + if( !h->param.rc.b_stat_read && ((h->param.i_bframe && h->param.i_bframe_adaptive) + || h->param.i_scenecut_threshold + || h->param.rc.b_mb_tree + || (h->param.rc.i_vbv_buffer_size && h->param.rc.i_lookahead)) ) + x264_slicetype_analyse( h, 0, 0 ); + + for( bframes = 0, brefs = 0;; bframes++ ) + { + frm = h->lookahead->next.list[bframes]; + if( frm->i_type == X264_TYPE_BREF && h->param.i_bframe_pyramid < X264_B_PYRAMID_NORMAL && + brefs == h->param.i_bframe_pyramid ) + { + frm->i_type = X264_TYPE_B; + x264_log( h, X264_LOG_WARNING, "B-ref at frame %d incompatible with B-pyramid %s \n", + frm->i_frame, x264_b_pyramid_names[h->param.i_bframe_pyramid] ); + } + /* pyramid with multiple B-refs needs a big enough dpb that the preceding P-frame stays available. + smaller dpb could be supported by smart enough use of mmco, but it's easier just to forbid it. */ + else if( frm->i_type == X264_TYPE_BREF && h->param.i_bframe_pyramid == X264_B_PYRAMID_NORMAL && + brefs && h->param.i_frame_reference <= (brefs+3) ) + { + frm->i_type = X264_TYPE_B; + x264_log( h, X264_LOG_WARNING, "B-ref at frame %d incompatible with B-pyramid %s and %d reference frames\n", + frm->i_frame, x264_b_pyramid_names[h->param.i_bframe_pyramid], h->param.i_frame_reference ); + } + + if( frm->i_type == X264_TYPE_IDR ) + { if( bframes > 0 ) { bframes--; @@ -1576,8 +1613,7 @@ void x264_slicetype_decide( x264_t *h ) } } - if( bframes == h->param.i_bframe || - !h->lookahead->next.list[bframes+1] ) + if( bframes == h->param.i_bframe || !h->lookahead->next.list[bframes+1] ) { if( IS_X264_TYPE_B( frm->i_type ) ) x264_log( h, X264_LOG_WARNING, "specified frame type is not compatible with max B-frames\n" ); From 1bd59847e654cfc845082eb07b1d3fea9bc451b0 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Fri, 29 Jul 2011 18:21:51 +0100 Subject: [PATCH 49/81] Fix typo in previous patch. --- encoder/slicetype.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encoder/slicetype.c b/encoder/slicetype.c index 4a5d5508..f46697ba 100644 --- a/encoder/slicetype.c +++ b/encoder/slicetype.c @@ -1582,7 +1582,7 @@ void x264_slicetype_decide( x264_t *h ) || h->param.i_scenecut_threshold || h->param.rc.b_mb_tree || (h->param.rc.i_vbv_buffer_size && h->param.rc.i_lookahead)) ) - x264_slicetype_analyse( h, 0, 0 ); + x264_slicetype_analyse( h, 0 ); for( bframes = 0, brefs = 0;; bframes++ ) { From 683fd7bde88514f9a4279dbeb59c3a0d0de6d014 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Wed, 24 Aug 2011 19:29:36 +0100 Subject: [PATCH 50/81] Use a 27MHz clock for HRD timing output. There was accumulation of error when using doubles. --- encoder/ratecontrol.c | 30 ++++++------------------------ x264.h | 7 ++----- 2 files changed, 8 insertions(+), 29 deletions(-) diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index ce27f160..d79af200 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -155,9 +155,8 @@ struct x264_ratecontrol_t /* hrd stuff */ int initial_cpb_removal_delay; - int initial_cpb_removal_delay_offset; - double nrt_first_access_unit; /* nominal removal time */ - double previous_cpb_final_arrival_time; + int64_t nrt_first_access_unit; /* nominal removal time */ + int64_t previous_cpb_final_arrival_time; uint64_t hrd_multiply_denom; }; @@ -1719,37 +1718,22 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) if( h->fenc->i_frame == 0 ) { // access unit initialises the HRD - h->fenc->hrd_timing.cpb_initial_arrival_time = 0; rc->initial_cpb_removal_delay = h->initial_cpb_removal_delay; - rc->initial_cpb_removal_delay_offset = h->initial_cpb_removal_delay_offset; - h->fenc->hrd_timing.cpb_removal_time = rc->nrt_first_access_unit = (double)rc->initial_cpb_removal_delay / 90000; + h->fenc->hrd_timing.cpb_removal_time = rc->nrt_first_access_unit = (int64_t)rc->initial_cpb_removal_delay * 300; } else { - h->fenc->hrd_timing.cpb_removal_time = rc->nrt_first_access_unit + (double)(h->fenc->i_cpb_delay - h->i_cpb_delay_pir_offset) * - h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale; + h->fenc->hrd_timing.cpb_removal_time = rc->nrt_first_access_unit + (int64_t)(h->fenc->i_cpb_delay - h->i_cpb_delay_pir_offset) * + 27000000LL * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale; - double cpb_earliest_arrival_time = h->fenc->hrd_timing.cpb_removal_time - (double)rc->initial_cpb_removal_delay / 90000; if( h->fenc->b_keyframe ) { rc->nrt_first_access_unit = h->fenc->hrd_timing.cpb_removal_time; rc->initial_cpb_removal_delay = h->initial_cpb_removal_delay; - rc->initial_cpb_removal_delay_offset = h->initial_cpb_removal_delay_offset; } - else - cpb_earliest_arrival_time -= (double)rc->initial_cpb_removal_delay_offset / 90000; - - if( h->sps->vui.hrd.b_cbr_hrd ) - h->fenc->hrd_timing.cpb_initial_arrival_time = rc->previous_cpb_final_arrival_time; - else - h->fenc->hrd_timing.cpb_initial_arrival_time = X264_MAX( rc->previous_cpb_final_arrival_time, cpb_earliest_arrival_time ); } - int filler_bits = *filler ? X264_MAX( (FILLER_OVERHEAD - h->param.b_annexb), *filler )*8 : 0; - // Equation C-6 - h->fenc->hrd_timing.cpb_final_arrival_time = rc->previous_cpb_final_arrival_time = h->fenc->hrd_timing.cpb_initial_arrival_time + - (double)(bits + filler_bits) / h->sps->vui.hrd.i_bit_rate_unscaled; - h->fenc->hrd_timing.dpb_output_time = (double)h->fenc->i_dpb_output_delay * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale + + h->fenc->hrd_timing.dpb_output_time = (int64_t)h->fenc->i_dpb_output_delay * 27000000LL * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale + h->fenc->hrd_timing.cpb_removal_time; } @@ -2512,8 +2496,6 @@ void x264_thread_sync_ratecontrol( x264_t *cur, x264_t *prev, x264_t *next ) COPY(wanted_bits_window); COPY(bframe_bits); COPY(initial_cpb_removal_delay); - COPY(initial_cpb_removal_delay_offset); - COPY(nrt_first_access_unit); COPY(previous_cpb_final_arrival_time); #undef COPY } diff --git a/x264.h b/x264.h index 5cedbfb9..0e251bc8 100644 --- a/x264.h +++ b/x264.h @@ -647,11 +647,8 @@ enum pic_struct_e typedef struct { - double cpb_initial_arrival_time; - double cpb_final_arrival_time; - double cpb_removal_time; - - double dpb_output_time; + int64_t cpb_removal_time; + int64_t dpb_output_time; } x264_hrd_t; /* Arbitrary user SEI: From 7c063d41ea97bd98bffe8725dbc4c9c5685f1531 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Wed, 24 Aug 2011 20:00:28 +0100 Subject: [PATCH 51/81] Fix issues with HRD timings. --- encoder/ratecontrol.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index d79af200..1be1059f 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -154,7 +154,6 @@ struct x264_ratecontrol_t x264_zone_t *prev_zone; /* hrd stuff */ - int initial_cpb_removal_delay; int64_t nrt_first_access_unit; /* nominal removal time */ int64_t previous_cpb_final_arrival_time; uint64_t hrd_multiply_denom; @@ -1718,8 +1717,7 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) if( h->fenc->i_frame == 0 ) { // access unit initialises the HRD - rc->initial_cpb_removal_delay = h->initial_cpb_removal_delay; - h->fenc->hrd_timing.cpb_removal_time = rc->nrt_first_access_unit = (int64_t)rc->initial_cpb_removal_delay * 300; + h->fenc->hrd_timing.cpb_removal_time = rc->nrt_first_access_unit = (int64_t)h->initial_cpb_removal_delay * 300; } else { @@ -1727,10 +1725,7 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) 27000000LL * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale; if( h->fenc->b_keyframe ) - { - rc->nrt_first_access_unit = h->fenc->hrd_timing.cpb_removal_time; - rc->initial_cpb_removal_delay = h->initial_cpb_removal_delay; - } + rc->nrt_first_access_unit = h->fenc->hrd_timing.cpb_removal_time; } h->fenc->hrd_timing.dpb_output_time = (int64_t)h->fenc->i_dpb_output_delay * 27000000LL * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale + @@ -2495,8 +2490,8 @@ void x264_thread_sync_ratecontrol( x264_t *cur, x264_t *prev, x264_t *next ) COPY(filler_bits_sum); COPY(wanted_bits_window); COPY(bframe_bits); - COPY(initial_cpb_removal_delay); COPY(previous_cpb_final_arrival_time); + COPY(nrt_first_access_unit); #undef COPY } //FIXME row_preds[] (not strictly necessary, but would improve prediction) From e6bb06f5672e0d35b1d6c4eab26cb015b6717d9c Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Mon, 29 Aug 2011 17:58:28 +0100 Subject: [PATCH 52/81] Get rid of hardcoded parameters in speedcontrol. This allows SAR changes. --- encoder/speed.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/encoder/speed.c b/encoder/speed.c index 7bf370ef..a449ddd2 100644 --- a/encoder/speed.c +++ b/encoder/speed.c @@ -19,7 +19,6 @@ struct x264_speedcontrol_t float cplx_den; float cplx_decay; float dither; - x264_param_t user_param; int first; @@ -54,7 +53,6 @@ void x264_speedcontrol_new( x264_t *h ) sc->cplx_decay = 1 - 1./h->param.sc.i_buffer_size; sc->stat.min_buffer = sc->buffer_size; sc->stat.max_buffer = 0; - sc->user_param = h->param; sc->first = 1; } @@ -128,7 +126,7 @@ static void apply_preset( x264_t *h, int preset ) //if( preset != sc->preset ) { const sc_preset_t *s = &presets[preset]; - x264_param_t p = sc->user_param; + x264_param_t p = h->param; p.i_frame_reference = s->refs; p.analyse.inter = s->partitions; From c425bb7f36c05fcd9f4f11f87336a22c2c528ced Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Sat, 22 Oct 2011 17:46:59 +0100 Subject: [PATCH 53/81] Fix bad merge. --- common/osdep.c | 1 - 1 file changed, 1 deletion(-) diff --git a/common/osdep.c b/common/osdep.c index 816b03f2..c94e80cf 100644 --- a/common/osdep.c +++ b/common/osdep.c @@ -43,7 +43,6 @@ extern int ptw32_processInitialized; int64_t x264_mdate( void ) { -<<<<<<< HEAD #ifdef __MINGW32__ struct timeb tb; ftime( &tb ); From 30ead414da7721a63389e23ac7e27d8bb126b006 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 25 Oct 2011 17:44:47 +0100 Subject: [PATCH 54/81] Fix error with rebasing. Fix bad rebase #2 --- encoder/encoder.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/encoder/encoder.c b/encoder/encoder.c index 350185ad..d8cfd87b 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -2932,7 +2932,7 @@ int x264_encoder_encode( x264_t *h, } /* when frame threading is used, buffering period sei is written in x264_encoder_frame_end */ - if( h->i_thread_frames == 1 && h->sps->vui.b_nal_hrd_parameters_present ) + if( h->i_thread_frames == 1 && h->param.i_nal_hrd ) { x264_hrd_fullness( h ); x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); @@ -3090,7 +3090,7 @@ static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current, x264_emms(); /* generate buffering period sei and insert it into place */ - if( h->i_thread_frames > 1 && h->fenc->b_keyframe && h->sps->vui.b_nal_hrd_parameters_present ) + if( h->i_thread_frames > 1 && h->fenc->b_keyframe && h->param.i_nal_hrd ) { x264_hrd_fullness( h ); x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); From 35a640b2eb8bb561af5c39f86e4475b1a1b1d444 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Sat, 3 Dec 2011 16:01:43 +0000 Subject: [PATCH 55/81] Output the arrival time of the AU into the CPB. --- encoder/ratecontrol.c | 9 +++++++++ x264.h | 1 + 2 files changed, 10 insertions(+) diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index 1be1059f..a46d7217 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -154,6 +154,8 @@ struct x264_ratecontrol_t x264_zone_t *prev_zone; /* hrd stuff */ + int initial_cpb_removal_delay; + int initial_cpb_removal_delay_offset; int64_t nrt_first_access_unit; /* nominal removal time */ int64_t previous_cpb_final_arrival_time; uint64_t hrd_multiply_denom; @@ -1717,6 +1719,7 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) if( h->fenc->i_frame == 0 ) { // access unit initialises the HRD + h->fenc->hrd_timing.cpb_initial_arrival_time = 0; h->fenc->hrd_timing.cpb_removal_time = rc->nrt_first_access_unit = (int64_t)h->initial_cpb_removal_delay * 300; } else @@ -1724,8 +1727,12 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) h->fenc->hrd_timing.cpb_removal_time = rc->nrt_first_access_unit + (int64_t)(h->fenc->i_cpb_delay - h->i_cpb_delay_pir_offset) * 27000000LL * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale; + h->fenc->hrd_timing.cpb_initial_arrival_time = h->fenc->hrd_timing.cpb_removal_time - rc->initial_cpb_removal_delay * 300; + if( h->fenc->b_keyframe ) rc->nrt_first_access_unit = h->fenc->hrd_timing.cpb_removal_time; + else + h->fenc->hrd_timing.cpb_initial_arrival_time -= rc->initial_cpb_removal_delay_offset * 300; } h->fenc->hrd_timing.dpb_output_time = (int64_t)h->fenc->i_dpb_output_delay * 27000000LL * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale + @@ -2490,6 +2497,8 @@ void x264_thread_sync_ratecontrol( x264_t *cur, x264_t *prev, x264_t *next ) COPY(filler_bits_sum); COPY(wanted_bits_window); COPY(bframe_bits); + COPY(initial_cpb_removal_delay); + COPY(initial_cpb_removal_delay_offset); COPY(previous_cpb_final_arrival_time); COPY(nrt_first_access_unit); #undef COPY diff --git a/x264.h b/x264.h index 0e251bc8..1051862a 100644 --- a/x264.h +++ b/x264.h @@ -647,6 +647,7 @@ enum pic_struct_e typedef struct { + int64_t cpb_initial_arrival_time; int64_t cpb_removal_time; int64_t dpb_output_time; } x264_hrd_t; From d7684b1cb5a230130acd6aa1f70fc4097bbf945b Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Mon, 5 Dec 2011 19:24:44 +0000 Subject: [PATCH 56/81] Set CBR HRD flags correctly. --- encoder/ratecontrol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index a46d7217..259ca79c 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -516,7 +516,7 @@ void x264_ratecontrol_init_reconfigurable( x264_t *h, int b_init ) if( h->param.i_nal_hrd && b_init ) { h->sps->vui.hrd.i_cpb_cnt = 1; - h->sps->vui.hrd.b_cbr_hrd = h->param.i_nal_hrd == X264_NAL_HRD_CBR; + h->sps->vui.hrd.b_cbr_hrd = h->param.i_nal_hrd == X264_NAL_HRD_CBR || h->param.i_nal_hrd == X264_NAL_HRD_FAKE_CBR; h->sps->vui.hrd.i_time_offset_length = 0; #define BR_SHIFT 6 From 785204711f17434be996824425dfadf6fc56573c Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Mon, 5 Dec 2011 23:35:50 +0000 Subject: [PATCH 57/81] Make single frame vbv code, correct the actual buffer size. Also get rid of some now useless (and hacky) outputs in the API. --- encoder/ratecontrol.c | 54 +++++++++++++++++++++++-------------------- x264.h | 3 --- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index 259ca79c..c9a94db5 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -522,43 +522,41 @@ void x264_ratecontrol_init_reconfigurable( x264_t *h, int b_init ) #define BR_SHIFT 6 #define CPB_SHIFT 4 - int bitrate = 1000*h->param.rc.i_vbv_max_bitrate; - int bufsize = 1000*h->param.rc.i_vbv_buffer_size; - - // normalize HRD size and rate to the value / scale notation - h->sps->vui.hrd.i_bit_rate_scale = x264_clip3( x264_ctz( bitrate ) - BR_SHIFT, 0, 15 ); - h->sps->vui.hrd.i_bit_rate_value = bitrate >> ( h->sps->vui.hrd.i_bit_rate_scale + BR_SHIFT ); - h->sps->vui.hrd.i_bit_rate_unscaled = h->sps->vui.hrd.i_bit_rate_value << ( h->sps->vui.hrd.i_bit_rate_scale + BR_SHIFT ); - h->sps->vui.hrd.i_cpb_size_scale = x264_clip3( x264_ctz( bufsize ) - CPB_SHIFT, 0, 15 ); - h->sps->vui.hrd.i_cpb_size_value = bufsize >> ( h->sps->vui.hrd.i_cpb_size_scale + CPB_SHIFT ); - h->sps->vui.hrd.i_cpb_size_unscaled = h->sps->vui.hrd.i_cpb_size_value << ( h->sps->vui.hrd.i_cpb_size_scale + CPB_SHIFT ); + if( h->param.i_nal_hrd == X264_NAL_HRD_VBR || h->param.i_nal_hrd == X264_NAL_HRD_VBR ) + { + // normalize HRD size and rate to the value / scale notation + h->sps->vui.hrd.i_bit_rate_scale = x264_clip3( x264_ctz( vbv_max_bitrate ) - BR_SHIFT, 0, 15 ); + h->sps->vui.hrd.i_bit_rate_value = vbv_max_bitrate >> ( h->sps->vui.hrd.i_bit_rate_scale + BR_SHIFT ); + h->sps->vui.hrd.i_bit_rate_unscaled = h->sps->vui.hrd.i_bit_rate_value << ( h->sps->vui.hrd.i_bit_rate_scale + BR_SHIFT ); + h->sps->vui.hrd.i_cpb_size_scale = x264_clip3( x264_ctz( vbv_buffer_size ) - CPB_SHIFT, 0, 15 ); + h->sps->vui.hrd.i_cpb_size_value = vbv_buffer_size >> ( h->sps->vui.hrd.i_cpb_size_scale + CPB_SHIFT ); + h->sps->vui.hrd.i_cpb_size_unscaled = h->sps->vui.hrd.i_cpb_size_value << ( h->sps->vui.hrd.i_cpb_size_scale + CPB_SHIFT ); - #undef CPB_SHIFT - #undef BR_SHIFT + #undef CPB_SHIFT + #undef BR_SHIFT - // arbitrary - #define MAX_DURATION 0.5 + // arbitrary + #define MAX_DURATION 0.5 - int max_cpb_output_delay = X264_MIN( h->param.i_keyint_max * MAX_DURATION * h->sps->vui.i_time_scale / h->sps->vui.i_num_units_in_tick, INT_MAX ); - int max_dpb_output_delay = h->sps->vui.i_max_dec_frame_buffering * MAX_DURATION * h->sps->vui.i_time_scale / h->sps->vui.i_num_units_in_tick; - int max_delay = (int)(90000.0 * (double)h->sps->vui.hrd.i_cpb_size_unscaled / h->sps->vui.hrd.i_bit_rate_unscaled + 0.5); + int max_cpb_output_delay = X264_MIN( h->param.i_keyint_max * MAX_DURATION * h->sps->vui.i_time_scale / h->sps->vui.i_num_units_in_tick, INT_MAX ); + int max_dpb_output_delay = h->sps->vui.i_max_dec_frame_buffering * MAX_DURATION * h->sps->vui.i_time_scale / h->sps->vui.i_num_units_in_tick; + int max_delay = (int)(90000.0 * (double)h->sps->vui.hrd.i_cpb_size_unscaled / h->sps->vui.hrd.i_bit_rate_unscaled + 0.5); - h->sps->vui.hrd.i_initial_cpb_removal_delay_length = 2 + x264_clip3( 32 - x264_clz( max_delay ), 4, 22 ); - h->sps->vui.hrd.i_cpb_removal_delay_length = x264_clip3( 32 - x264_clz( max_cpb_output_delay ), 4, 31 ); - h->sps->vui.hrd.i_dpb_output_delay_length = x264_clip3( 32 - x264_clz( max_dpb_output_delay ), 4, 31 ); + h->sps->vui.hrd.i_initial_cpb_removal_delay_length = 2 + x264_clip3( 32 - x264_clz( max_delay ), 4, 22 ); + h->sps->vui.hrd.i_cpb_removal_delay_length = x264_clip3( 32 - x264_clz( max_cpb_output_delay ), 4, 31 ); + h->sps->vui.hrd.i_dpb_output_delay_length = x264_clip3( 32 - x264_clz( max_dpb_output_delay ), 4, 31 ); - #undef MAX_DURATION + #undef MAX_DURATION - vbv_buffer_size = h->param.rc.i_vbv_buffer_size_actual = h->sps->vui.hrd.i_cpb_size_unscaled; - vbv_max_bitrate = h->param.rc.i_vbv_max_bitrate_actual = h->sps->vui.hrd.i_bit_rate_unscaled; + vbv_buffer_size = h->sps->vui.hrd.i_cpb_size_unscaled; + vbv_max_bitrate = h->sps->vui.hrd.i_bit_rate_unscaled; + } } else if( h->param.i_nal_hrd && !b_init ) { //x264_log( h, X264_LOG_WARNING, "VBV parameters cannot be changed when NAL HRD is in use\n" ); return; } - h->sps->vui.hrd.i_bit_rate_unscaled = vbv_max_bitrate; - h->sps->vui.hrd.i_cpb_size_unscaled = vbv_buffer_size; if( rc->b_vbv_min_rate ) rc->bitrate = h->param.rc.i_bitrate * 1000.; @@ -566,6 +564,12 @@ void x264_ratecontrol_init_reconfigurable( x264_t *h, int b_init ) rc->vbv_max_rate = vbv_max_bitrate; rc->buffer_size = vbv_buffer_size; rc->single_frame_vbv = rc->buffer_rate * 1.1 > rc->buffer_size; + if( rc->single_frame_vbv && h->param.i_nal_hrd > X264_NAL_HRD_CBR ) + rc->buffer_size = rc->buffer_rate; + + h->sps->vui.hrd.i_bit_rate_unscaled = rc->vbv_max_rate; + h->sps->vui.hrd.i_cpb_size_unscaled = rc->buffer_size; + rc->cbr_decay = 1.0 - rc->buffer_rate / rc->buffer_size * 0.5 * X264_MAX(0, 1.5 - rc->buffer_rate * rc->fps / rc->bitrate); if( h->param.rc.i_rc_method == X264_RC_CRF && h->param.rc.f_rf_constant_max ) diff --git a/x264.h b/x264.h index 1051862a..b7aae80d 100644 --- a/x264.h +++ b/x264.h @@ -378,9 +378,6 @@ typedef struct x264_param_t float f_ip_factor; float f_pb_factor; - int i_vbv_max_bitrate_actual; /* Output only when HRD enabled */ - int i_vbv_buffer_size_actual; /* Output only when HRD enabled */ - int i_aq_mode; /* psy adaptive QP. (X264_AQ_*) */ float f_aq_strength; int b_mb_tree; /* Macroblock-tree ratecontrol. */ From 753f8c4d2649d0342f99592706c7d2fd406ca804 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 13 Dec 2011 21:14:40 +0000 Subject: [PATCH 58/81] Add missing lines in hrd output. --- encoder/ratecontrol.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index c9a94db5..391f5c6b 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -1724,6 +1724,8 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) { // access unit initialises the HRD h->fenc->hrd_timing.cpb_initial_arrival_time = 0; + rc->initial_cpb_removal_delay = h->initial_cpb_removal_delay; + rc->initial_cpb_removal_delay_offset = h->initial_cpb_removal_delay_offset; h->fenc->hrd_timing.cpb_removal_time = rc->nrt_first_access_unit = (int64_t)h->initial_cpb_removal_delay * 300; } else @@ -1734,7 +1736,11 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) h->fenc->hrd_timing.cpb_initial_arrival_time = h->fenc->hrd_timing.cpb_removal_time - rc->initial_cpb_removal_delay * 300; if( h->fenc->b_keyframe ) + { rc->nrt_first_access_unit = h->fenc->hrd_timing.cpb_removal_time; + rc->initial_cpb_removal_delay = h->initial_cpb_removal_delay; + rc->initial_cpb_removal_delay_offset = h->initial_cpb_removal_delay_offset; + } else h->fenc->hrd_timing.cpb_initial_arrival_time -= rc->initial_cpb_removal_delay_offset * 300; } From 6f8745eab17cb392a955b9d42cc7b75449083293 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Thu, 15 Dec 2011 22:37:12 +0000 Subject: [PATCH 59/81] Including cpb removal delay offset in the initial arrival time is wrong. --- encoder/ratecontrol.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index 391f5c6b..0eb842e3 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -1741,8 +1741,6 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) rc->initial_cpb_removal_delay = h->initial_cpb_removal_delay; rc->initial_cpb_removal_delay_offset = h->initial_cpb_removal_delay_offset; } - else - h->fenc->hrd_timing.cpb_initial_arrival_time -= rc->initial_cpb_removal_delay_offset * 300; } h->fenc->hrd_timing.dpb_output_time = (int64_t)h->fenc->i_dpb_output_delay * 27000000LL * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale + From 724f2e60e037ce246b41a165e668cef0cda3ff88 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Mon, 19 Dec 2011 15:36:32 +0000 Subject: [PATCH 60/81] Make HRD timings work acceptable for single frame vbv --- encoder/ratecontrol.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index 0eb842e3..d6a414ab 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -1741,6 +1741,11 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) rc->initial_cpb_removal_delay = h->initial_cpb_removal_delay; rc->initial_cpb_removal_delay_offset = h->initial_cpb_removal_delay_offset; } + + /* It's safe to do this when using single frame vbv */ + if( rc->single_frame_vbv ) + h->fenc->hrd_timing.cpb_initial_arrival_time -= rc->initial_cpb_removal_delay_offset * 300; + } h->fenc->hrd_timing.dpb_output_time = (int64_t)h->fenc->i_dpb_output_delay * 27000000LL * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale + From 06191ad54ce54a88a744b31671f2a448ac9567f9 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 20 Dec 2011 14:41:32 +0000 Subject: [PATCH 61/81] Make HRD output timings more accurate --- encoder/ratecontrol.c | 48 ++++++++++++++++++++++++++++++++----------- x264.h | 1 + 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index d6a414ab..1c035c33 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -157,7 +157,11 @@ struct x264_ratecontrol_t int initial_cpb_removal_delay; int initial_cpb_removal_delay_offset; int64_t nrt_first_access_unit; /* nominal removal time */ - int64_t previous_cpb_final_arrival_time; + + /* Integer and fractional part of the cpb arrival time */ + int64_t previous_cpb_final_arrival_time_int; + int64_t previous_cpb_final_arrival_time_frac; + uint64_t hrd_multiply_denom; }; @@ -638,11 +642,11 @@ int x264_ratecontrol_new( x264_t *h ) if( h->param.i_nal_hrd ) { uint64_t denom = (uint64_t)h->sps->vui.hrd.i_bit_rate_unscaled * h->sps->vui.i_time_scale; - uint64_t num = 180000; + uint64_t num = 54000000; x264_reduce_fraction64( &num, &denom ); - rc->hrd_multiply_denom = 180000 / num; + rc->hrd_multiply_denom = 54000000 / num; - double bits_required = log2( 180000 / rc->hrd_multiply_denom ) + double bits_required = log2( 54000000 / rc->hrd_multiply_denom ) + log2( h->sps->vui.i_time_scale ) + log2( h->sps->vui.hrd.i_cpb_size_unscaled ); if( bits_required >= 63 ) @@ -1720,6 +1724,9 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) if( h->param.i_nal_hrd ) { + uint64_t denom = (uint64_t)h->sps->vui.hrd.i_bit_rate_unscaled * h->sps->vui.i_time_scale / rc->hrd_multiply_denom; + uint64_t multiply_factor = 54000000 / rc->hrd_multiply_denom; + if( h->fenc->i_frame == 0 ) { // access unit initialises the HRD @@ -1733,7 +1740,7 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) h->fenc->hrd_timing.cpb_removal_time = rc->nrt_first_access_unit + (int64_t)(h->fenc->i_cpb_delay - h->i_cpb_delay_pir_offset) * 27000000LL * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale; - h->fenc->hrd_timing.cpb_initial_arrival_time = h->fenc->hrd_timing.cpb_removal_time - rc->initial_cpb_removal_delay * 300; + int64_t cpb_earliest_arrival_time = h->fenc->hrd_timing.cpb_removal_time - rc->initial_cpb_removal_delay * 300; if( h->fenc->b_keyframe ) { @@ -1741,13 +1748,29 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) rc->initial_cpb_removal_delay = h->initial_cpb_removal_delay; rc->initial_cpb_removal_delay_offset = h->initial_cpb_removal_delay_offset; } + else + cpb_earliest_arrival_time -= rc->initial_cpb_removal_delay_offset * 300; - /* It's safe to do this when using single frame vbv */ - if( rc->single_frame_vbv ) - h->fenc->hrd_timing.cpb_initial_arrival_time -= rc->initial_cpb_removal_delay_offset * 300; + /* Compare the arrival times using the 27MHz clock which should be acceptable */ + int64_t previous_cpb_arrival_time = rc->previous_cpb_final_arrival_time_int + (multiply_factor * rc->previous_cpb_final_arrival_time_frac + denom) + / (2*denom); + if( h->sps->vui.hrd.b_cbr_hrd ) + h->fenc->hrd_timing.cpb_initial_arrival_time = previous_cpb_arrival_time; + else + h->fenc->hrd_timing.cpb_initial_arrival_time = X264_MAX( previous_cpb_arrival_time, cpb_earliest_arrival_time ); } + int filler_bits = *filler ? X264_MAX( (FILLER_OVERHEAD - h->param.b_annexb), *filler )*8 : 0; + uint64_t frame_size = (bits + filler_bits) * h->sps->vui.i_time_scale; + uint64_t integer = (multiply_factor * frame_size) / (2*denom); + + rc->previous_cpb_final_arrival_time_int = h->fenc->hrd_timing.cpb_initial_arrival_time + integer; + rc->previous_cpb_final_arrival_time_frac = frame_size - ((integer * (2*denom)) / multiply_factor); + + h->fenc->hrd_timing.cpb_final_arrival_time = rc->previous_cpb_final_arrival_time_int + (multiply_factor * rc->previous_cpb_final_arrival_time_frac + denom) + / (2*denom); + h->fenc->hrd_timing.dpb_output_time = (int64_t)h->fenc->i_dpb_output_delay * 27000000LL * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale + h->fenc->hrd_timing.cpb_removal_time; } @@ -1943,7 +1966,7 @@ void x264_hrd_fullness( x264_t *h ) uint64_t denom = (uint64_t)h->sps->vui.hrd.i_bit_rate_unscaled * h->sps->vui.i_time_scale / rct->hrd_multiply_denom; uint64_t cpb_state = rct->buffer_fill_final; uint64_t cpb_size = (uint64_t)h->sps->vui.hrd.i_cpb_size_unscaled * h->sps->vui.i_time_scale; - uint64_t multiply_factor = 180000 / rct->hrd_multiply_denom; + uint64_t multiply_factor = 54000000 / rct->hrd_multiply_denom; if( rct->buffer_fill_final < 0 || rct->buffer_fill_final > cpb_size ) { @@ -1951,8 +1974,8 @@ void x264_hrd_fullness( x264_t *h ) rct->buffer_fill_final < 0 ? "underflow" : "overflow", (float)rct->buffer_fill_final/denom, (float)cpb_size/denom ); } - h->initial_cpb_removal_delay = (multiply_factor * cpb_state + denom) / (2*denom); - h->initial_cpb_removal_delay_offset = (multiply_factor * cpb_size + denom) / (2*denom) - h->initial_cpb_removal_delay; + h->initial_cpb_removal_delay = (multiply_factor * cpb_state + denom) / (600*denom); + h->initial_cpb_removal_delay_offset = (multiply_factor * cpb_size + denom) / (600*denom) - h->initial_cpb_removal_delay; } // provisionally update VBV according to the planned size of all frames currently in progress @@ -2512,7 +2535,8 @@ void x264_thread_sync_ratecontrol( x264_t *cur, x264_t *prev, x264_t *next ) COPY(bframe_bits); COPY(initial_cpb_removal_delay); COPY(initial_cpb_removal_delay_offset); - COPY(previous_cpb_final_arrival_time); + COPY(previous_cpb_final_arrival_time_int); + COPY(previous_cpb_final_arrival_time_frac); COPY(nrt_first_access_unit); #undef COPY } diff --git a/x264.h b/x264.h index b7aae80d..cbc08538 100644 --- a/x264.h +++ b/x264.h @@ -645,6 +645,7 @@ enum pic_struct_e typedef struct { int64_t cpb_initial_arrival_time; + int64_t cpb_final_arrival_time; int64_t cpb_removal_time; int64_t dpb_output_time; } x264_hrd_t; From 3d0a3ce0381469f2654380a2887ed8f5b42baba7 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Fri, 23 Dec 2011 19:52:38 +0000 Subject: [PATCH 62/81] Have a safe cpb initial arrival time field so that single frame vbv can be given a slightly better arrival time. --- encoder/ratecontrol.c | 5 ++++- x264.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index 1c035c33..d3f6ecbb 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -1730,7 +1730,7 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) if( h->fenc->i_frame == 0 ) { // access unit initialises the HRD - h->fenc->hrd_timing.cpb_initial_arrival_time = 0; + h->fenc->hrd_timing.cpb_initial_arrival_time = h->fenc->hrd_timing.safe_cpb_initial_arrival_time = 0; rc->initial_cpb_removal_delay = h->initial_cpb_removal_delay; rc->initial_cpb_removal_delay_offset = h->initial_cpb_removal_delay_offset; h->fenc->hrd_timing.cpb_removal_time = rc->nrt_first_access_unit = (int64_t)h->initial_cpb_removal_delay * 300; @@ -1759,6 +1759,9 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) h->fenc->hrd_timing.cpb_initial_arrival_time = previous_cpb_arrival_time; else h->fenc->hrd_timing.cpb_initial_arrival_time = X264_MAX( previous_cpb_arrival_time, cpb_earliest_arrival_time ); + + /* With single frame vbv it's safe to allow the frame to arrive as early as possible */ + h->fenc->hrd_timing.safe_cpb_initial_arrival_time = rc->single_frame_vbv ? cpb_earliest_arrival_time : h->fenc->hrd_timing.cpb_initial_arrival_time; } int filler_bits = *filler ? X264_MAX( (FILLER_OVERHEAD - h->param.b_annexb), *filler )*8 : 0; diff --git a/x264.h b/x264.h index cbc08538..04d39e35 100644 --- a/x264.h +++ b/x264.h @@ -645,6 +645,7 @@ enum pic_struct_e typedef struct { int64_t cpb_initial_arrival_time; + int64_t safe_cpb_initial_arrival_time; int64_t cpb_final_arrival_time; int64_t cpb_removal_time; int64_t dpb_output_time; From da0c2ad9e0f40efb82842359973c6a5f7958ab1d Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 24 Jan 2012 22:09:16 +0000 Subject: [PATCH 63/81] Disable BFF signalling using POC. Fixes playback on a set top box. --- encoder/encoder.c | 2 +- encoder/set.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/encoder/encoder.c b/encoder/encoder.c index c7c3eb75..4e581662 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -2040,7 +2040,7 @@ static inline void x264_slice_init( x264_t *h, int i_nal_type, int i_global_qp ) if( h->sps->i_poc_type == 0 ) { h->sh.i_poc = h->fdec->i_poc; - if( PARAM_INTERLACED ) + if( PARAM_INTERLACED && h->pps->b_pic_order ) { h->sh.i_delta_poc_bottom = h->param.b_tff ? 1 : -1; h->sh.i_poc += h->sh.i_delta_poc_bottom == -1; diff --git a/encoder/set.c b/encoder/set.c index 8c556b26..14c8b7b2 100644 --- a/encoder/set.c +++ b/encoder/set.c @@ -421,7 +421,7 @@ void x264_pps_init( x264_pps_t *pps, int i_id, x264_param_t *param, x264_sps_t * pps->i_sps_id = sps->i_id; pps->b_cabac = param->b_cabac; - pps->b_pic_order = param->b_interlaced; + pps->b_pic_order = param->b_interlaced && !param->b_tff; pps->i_num_slice_groups = 1; pps->i_num_ref_idx_l0_default_active = param->i_frame_reference; From 49226f92fe9973de011ea382e6a67b9473bd0029 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Sat, 11 Feb 2012 18:09:28 +0000 Subject: [PATCH 64/81] Fix hrd timings with intra-refresh --- encoder/encoder.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/encoder/encoder.c b/encoder/encoder.c index c3773ff5..47f0db8a 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -3018,9 +3018,6 @@ int x264_encoder_encode( x264_t *h, overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD - (h->param.b_annexb && h->out.i_nal-1); } - if( h->fenc->b_keyframe && h->param.b_intra_refresh ) - h->i_cpb_delay_pir_offset = h->fenc->i_cpb_delay; - /* Init the speed control */ if( h->param.sc.i_buffer_size ) x264_speedcontrol_frame( h ); @@ -3176,6 +3173,9 @@ static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current, filler -= total_size; } + if( h->fenc->b_keyframe && h->param.b_intra_refresh ) + h->i_cpb_delay_pir_offset = h->fenc->i_cpb_delay; + /* End bitstream, set output */ *pi_nal = h->out.i_nal; *pp_nal = h->out.nal; From 60b8f8a80fda7ca4a807b6d91e4058dfbee87a76 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Thu, 23 Feb 2012 23:52:00 +0000 Subject: [PATCH 65/81] Export the earliest arrival time correctly. --- encoder/ratecontrol.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index 4fd0edac..d6508d0d 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -1740,15 +1740,16 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) h->fenc->hrd_timing.cpb_removal_time = rc->nrt_first_access_unit + (int64_t)(h->fenc->i_cpb_delay - h->i_cpb_delay_pir_offset) * 27000000LL * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale; - int64_t cpb_earliest_arrival_time = h->fenc->hrd_timing.cpb_removal_time - rc->initial_cpb_removal_delay * 300; - if( h->fenc->b_keyframe ) { rc->nrt_first_access_unit = h->fenc->hrd_timing.cpb_removal_time; rc->initial_cpb_removal_delay = h->initial_cpb_removal_delay; rc->initial_cpb_removal_delay_offset = h->initial_cpb_removal_delay_offset; } - else + + int64_t cpb_earliest_arrival_time = h->fenc->hrd_timing.cpb_removal_time - rc->initial_cpb_removal_delay * 300; + + if( !h->fenc->b_keyframe ) cpb_earliest_arrival_time -= rc->initial_cpb_removal_delay_offset * 300; /* Compare the arrival times using the 27MHz clock which should be acceptable */ From c525ca3a2eff58712a698763a9f52c305d0629ee Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Sat, 25 Feb 2012 23:47:21 +0000 Subject: [PATCH 66/81] Fix typo (didn't affect OBE-RT) --- encoder/ratecontrol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index d6508d0d..c083f332 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -526,7 +526,7 @@ void x264_ratecontrol_init_reconfigurable( x264_t *h, int b_init ) #define BR_SHIFT 6 #define CPB_SHIFT 4 - if( h->param.i_nal_hrd == X264_NAL_HRD_VBR || h->param.i_nal_hrd == X264_NAL_HRD_VBR ) + if( h->param.i_nal_hrd == X264_NAL_HRD_VBR || h->param.i_nal_hrd == X264_NAL_HRD_CBR ) { // normalize HRD size and rate to the value / scale notation h->sps->vui.hrd.i_bit_rate_scale = x264_clip3( x264_ctz( vbv_max_bitrate ) - BR_SHIFT, 0, 15 ); From 85059494bb32de9bd516bdfdb0ba457b00aedae6 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Fri, 9 Mar 2012 22:05:13 +0000 Subject: [PATCH 67/81] Revert "Sliced-threads: do hpel and deblock after returning" This reverts commit c522ad1fed167d0e985e4f9dcdee042473cf74db. --- common/common.h | 7 -- common/deblock.c | 4 +- common/frame.c | 43 ++++-------- common/frame.h | 5 +- common/macroblock.c | 19 +----- encoder/encoder.c | 156 ++++++++++++-------------------------------- 6 files changed, 58 insertions(+), 176 deletions(-) diff --git a/common/common.h b/common/common.h index 366bf204..c0277d8d 100644 --- a/common/common.h +++ b/common/common.h @@ -471,13 +471,9 @@ struct x264_t x264_t *thread[X264_THREAD_MAX+1]; int b_thread_active; int i_thread_phase; /* which thread to use for the next frame */ - int i_thread_idx; /* which thread this is */ int i_threadslice_start; /* first row in this thread slice */ int i_threadslice_end; /* row after the end of this thread slice */ - int i_threadslice_pass; /* which pass of encoding we are on */ x264_threadpool_t *threadpool; - x264_pthread_mutex_t mutex; - x264_pthread_cond_t cv; /* bitstream output */ struct @@ -828,9 +824,6 @@ struct x264_t /* extra data required for mbaff in mv prediction */ int16_t topright_mv[2][3][2]; int8_t topright_ref[2][3]; - - /* current mb deblock strength */ - uint8_t (*deblock_strength)[8][4]; } cache; /* */ diff --git a/common/deblock.c b/common/deblock.c index d76682a2..58cf3c41 100644 --- a/common/deblock.c +++ b/common/deblock.c @@ -395,7 +395,7 @@ void x264_frame_deblock_row( x264_t *h, int mb_y ) int mb_xy = h->mb.i_mb_xy; int transform_8x8 = h->mb.mb_transform_size[h->mb.i_mb_xy]; int intra_cur = IS_INTRA( h->mb.type[mb_xy] ); - uint8_t (*bs)[8][4] = h->deblock_strength[mb_y&1][h->param.b_sliced_threads?mb_xy:mb_x]; + uint8_t (*bs)[8][4] = h->deblock_strength[mb_y&1][mb_x]; pixel *pixy = h->fdec->plane[0] + 16*mb_y*stridey + 16*mb_x; pixel *pixuv = h->fdec->plane[1] + chroma_height*mb_y*strideuv + 16*mb_x; @@ -592,7 +592,7 @@ void x264_macroblock_deblock( x264_t *h ) if( (h->mb.i_partition == D_16x16 && !h->mb.i_cbp_luma && !intra_cur) || qp <= qp_thresh ) return; - uint8_t (*bs)[8][4] = h->mb.cache.deblock_strength; + uint8_t (*bs)[8][4] = h->deblock_strength[h->mb.i_mb_y&1][h->mb.i_mb_x]; if( intra_cur ) { memset( &bs[0][1], 3, 3*4*sizeof(uint8_t) ); diff --git a/common/frame.c b/common/frame.c index 86c7e730..d9bb257c 100644 --- a/common/frame.c +++ b/common/frame.c @@ -480,12 +480,9 @@ static void ALWAYS_INLINE plane_expand_border( pixel *pix, int i_stride, int i_w #undef PPIXEL } -void x264_frame_expand_border( x264_t *h, x264_frame_t *frame, int mb_y ) +void x264_frame_expand_border( x264_t *h, x264_frame_t *frame, int mb_y, int b_end ) { - int pad_top = mb_y == 0; - int pad_bot = mb_y == h->mb.i_mb_height - (1 << SLICE_MBAFF); - int b_start = mb_y == h->i_threadslice_start; - int b_end = mb_y == h->i_threadslice_end - (1 << SLICE_MBAFF); + int b_start = !mb_y; if( mb_y & SLICE_MBAFF ) return; for( int i = 0; i < frame->i_plane; i++ ) @@ -494,31 +491,30 @@ void x264_frame_expand_border( x264_t *h, x264_frame_t *frame, int mb_y ) int v_shift = i && CHROMA_V_SHIFT; int stride = frame->i_stride[i]; int width = 16*h->mb.i_mb_width; - int height = (pad_bot ? 16*(h->mb.i_mb_height - mb_y) >> SLICE_MBAFF : 16) >> v_shift; + int height = (b_end ? 16*(h->mb.i_mb_height - mb_y) >> SLICE_MBAFF : 16) >> v_shift; int padh = PADH; int padv = PADV >> v_shift; // buffer: 2 chroma, 3 luma (rounded to 4) because deblocking goes beyond the top of the mb if( b_end && !b_start ) height += 4 >> (v_shift + SLICE_MBAFF); pixel *pix; - int starty = 16*mb_y - 4*!b_start; if( SLICE_MBAFF ) { // border samples for each field are extended separately - pix = frame->plane_fld[i] + (starty*stride >> v_shift); - plane_expand_border( pix, stride*2, width, height, padh, padv, pad_top, pad_bot, h_shift ); - plane_expand_border( pix+stride, stride*2, width, height, padh, padv, pad_top, pad_bot, h_shift ); + pix = frame->plane_fld[i] + X264_MAX(0, (16*mb_y-4)*stride >> v_shift); + plane_expand_border( pix, stride*2, width, height, padh, padv, b_start, b_end, h_shift ); + plane_expand_border( pix+stride, stride*2, width, height, padh, padv, b_start, b_end, h_shift ); - height = (pad_bot ? 16*(h->mb.i_mb_height - mb_y) : 32) >> v_shift; + height = (b_end ? 16*(h->mb.i_mb_height - mb_y) : 32) >> v_shift; if( b_end && !b_start ) height += 4 >> v_shift; - pix = frame->plane[i] + (starty*stride >> v_shift); - plane_expand_border( pix, stride, width, height, padh, padv, pad_top, pad_bot, h_shift ); + pix = frame->plane[i] + X264_MAX(0, (16*mb_y-4)*stride >> v_shift); + plane_expand_border( pix, stride, width, height, padh, padv, b_start, b_end, h_shift ); } else { - pix = frame->plane[i] + (starty*stride >> v_shift); - plane_expand_border( pix, stride, width, height, padh, padv, pad_top, pad_bot, h_shift ); + pix = frame->plane[i] + X264_MAX(0, (16*mb_y-4)*stride >> v_shift); + plane_expand_border( pix, stride, width, height, padh, padv, b_start, b_end, h_shift ); } } } @@ -623,23 +619,6 @@ void x264_frame_cond_wait( x264_frame_t *frame, int i_lines_completed ) x264_pthread_mutex_unlock( &frame->mutex ); } -void x264_threadslice_cond_broadcast( x264_t *h, int pass ) -{ - x264_pthread_mutex_lock( &h->mutex ); - h->i_threadslice_pass = pass; - if( pass > 0 ) - x264_pthread_cond_broadcast( &h->cv ); - x264_pthread_mutex_unlock( &h->mutex ); -} - -void x264_threadslice_cond_wait( x264_t *h, int pass ) -{ - x264_pthread_mutex_lock( &h->mutex ); - while( h->i_threadslice_pass < pass ) - x264_pthread_cond_wait( &h->cv, &h->mutex ); - x264_pthread_mutex_unlock( &h->mutex ); -} - /* list operators */ void x264_frame_push( x264_frame_t **list, x264_frame_t *frame ) diff --git a/common/frame.h b/common/frame.h index 55bccacc..8861726b 100644 --- a/common/frame.h +++ b/common/frame.h @@ -207,7 +207,7 @@ void x264_frame_delete( x264_frame_t *frame ); int x264_frame_copy_picture( x264_t *h, x264_frame_t *dst, x264_picture_t *src ); -void x264_frame_expand_border( x264_t *h, x264_frame_t *frame, int mb_y ); +void x264_frame_expand_border( x264_t *h, x264_frame_t *frame, int mb_y, int b_end ); void x264_frame_expand_border_filtered( x264_t *h, x264_frame_t *frame, int mb_y, int b_end ); void x264_frame_expand_border_lowres( x264_frame_t *frame ); void x264_frame_expand_border_chroma( x264_t *h, x264_frame_t *frame, int plane ); @@ -225,9 +225,6 @@ void x264_deblock_init( int cpu, x264_deblock_function_t *pf, int b_mba void x264_frame_cond_broadcast( x264_frame_t *frame, int i_lines_completed ); void x264_frame_cond_wait( x264_frame_t *frame, int i_lines_completed ); -void x264_threadslice_cond_broadcast( x264_t *h, int pass ); -void x264_threadslice_cond_wait( x264_t *h, int pass ); - void x264_frame_push( x264_frame_t **list, x264_frame_t *frame ); x264_frame_t *x264_frame_pop( x264_frame_t **list ); void x264_frame_unshift( x264_frame_t **list, x264_frame_t *frame ); diff --git a/common/macroblock.c b/common/macroblock.c index 11c3e75e..9d478d29 100644 --- a/common/macroblock.c +++ b/common/macroblock.c @@ -368,17 +368,7 @@ int x264_macroblock_thread_allocate( x264_t *h, int b_lookahead ) } for( int i = 0; i <= PARAM_INTERLACED; i++ ) { - if( h->param.b_sliced_threads ) - { - /* Only allocate the first one, and allocate it for the whole frame, because we - * won't be deblocking until after the frame is fully encoded. */ - if( h == h->thread[0] && !i ) - CHECKED_MALLOC( h->deblock_strength[0], sizeof(**h->deblock_strength) * h->mb.i_mb_count ); - else - h->deblock_strength[i] = h->thread[0]->deblock_strength[0]; - } - else - CHECKED_MALLOC( h->deblock_strength[i], sizeof(**h->deblock_strength) * h->mb.i_mb_width ); + CHECKED_MALLOC( h->deblock_strength[i], sizeof(**h->deblock_strength) * h->mb.i_mb_width ); h->deblock_strength[1] = h->deblock_strength[i]; } } @@ -411,8 +401,7 @@ void x264_macroblock_thread_free( x264_t *h, int b_lookahead ) if( !b_lookahead ) { for( int i = 0; i <= PARAM_INTERLACED; i++ ) - if( !h->param.b_sliced_threads || (h == h->thread[0] && !i) ) - x264_free( h->deblock_strength[i] ); + x264_free( h->deblock_strength[i] ); for( int i = 0; i < (PARAM_INTERLACED ? 5 : 2); i++ ) for( int j = 0; j < (CHROMA444 ? 3 : 2); j++ ) x264_free( h->intra_border_backup[i][j] - 16 ); @@ -869,8 +858,6 @@ static void ALWAYS_INLINE x264_macroblock_cache_load( x264_t *h, int mb_x, int m const x264_left_table_t *left_index_table = h->mb.left_index_table; - h->mb.cache.deblock_strength = h->deblock_strength[mb_y&1][h->param.b_sliced_threads?h->mb.i_mb_xy:mb_x]; - /* load cache */ if( h->mb.i_neighbour & MB_TOP ) { @@ -1445,7 +1432,7 @@ static void x264_macroblock_deblock_strength_mbaff( x264_t *h, uint8_t (*bs)[8][ void x264_macroblock_deblock_strength( x264_t *h ) { - uint8_t (*bs)[8][4] = h->mb.cache.deblock_strength; + uint8_t (*bs)[8][4] = h->deblock_strength[h->mb.i_mb_y&1][h->mb.i_mb_x]; if( IS_INTRA( h->mb.i_type ) ) { memset( bs[0][1], 3, 3*4*sizeof(uint8_t) ); diff --git a/encoder/encoder.c b/encoder/encoder.c index f00455c4..2d7e9278 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -68,28 +68,12 @@ static double x264_ssim( double ssim ) return -10.0 * log10( inv_ssim ); } -static int x264_threadpool_wait_all( x264_t *h ) -{ - for( int i = 0; i < h->param.i_threads; i++ ) - if( h->thread[i]->b_thread_active ) - { - h->thread[i]->b_thread_active = 0; - if( (intptr_t)x264_threadpool_wait( h->threadpool, h->thread[i] ) < 0 ) - return -1; - } - return 0; -} - static void x264_frame_dump( x264_t *h ) { FILE *f = fopen( h->param.psz_dump_yuv, "r+b" ); if( !f ) return; - /* Wait for the threads to finish deblocking */ - if( h->param.b_sliced_threads ) - x264_threadpool_wait_all( h ); - /* Write the frame in display order */ int frame_size = FRAME_SIZE( h->param.i_height * h->param.i_width * sizeof(pixel) ); fseek( f, (uint64_t)h->fdec->i_frame * frame_size, SEEK_SET ); @@ -939,6 +923,9 @@ static int x264_validate_parameters( x264_t *h, int b_open ) h->param.i_nal_hrd = h->param.i_nal_hrd == X264_NAL_HRD_CBR ? X264_NAL_HRD_VBR : X264_NAL_HRD_FAKE_CBR; } + if( h->param.psz_dump_yuv ) + h->param.b_full_recon = 1; + /* ensure the booleans are 0 or 1 so they can be used in math */ #define BOOLIFY(x) h->param.x = !!h->param.x BOOLIFY( b_cabac ); @@ -1279,18 +1266,8 @@ x264_t *x264_encoder_open( x264_param_t *param ) goto fail; h->thread[0] = h; - for( int i = 0; i < h->param.i_threads + !!h->param.i_sync_lookahead; i++ ) - { - if( i ) - CHECKED_MALLOC( h->thread[i], sizeof(x264_t) ); - if( i < h->param.i_threads ) - { - if( x264_pthread_mutex_init( &h->thread[i]->mutex, NULL ) ) - goto fail; - if( x264_pthread_cond_init( &h->thread[i]->cv, NULL ) ) - goto fail; - } - } + for( int i = 1; i < h->param.i_threads + !!h->param.i_sync_lookahead; i++ ) + CHECKED_MALLOC( h->thread[i], sizeof(x264_t) ); for( int i = 0; i < h->param.i_threads; i++ ) { @@ -1385,11 +1362,6 @@ x264_t *x264_encoder_open( x264_param_t *param ) ****************************************************************************/ int x264_encoder_reconfig( x264_t *h, x264_param_t *param ) { - /* If the previous frame isn't done encoding, reconfiguring is probably dangerous. */ - if( h->param.b_sliced_threads ) - if( x264_threadpool_wait_all( h ) < 0 ) - return -1; - int rc_reconfig = 0; h = h->thread[h->thread[0]->i_thread_phase]; x264_set_aspect_ratio( h, param, 0 ); @@ -1866,7 +1838,7 @@ static inline void x264_reference_build_list( x264_t *h, int i_poc ) h->mb.pic.i_fref[1] = h->i_ref[1]; } -static void x264_fdec_filter_row( x264_t *h, int mb_y, int pass ) +static void x264_fdec_filter_row( x264_t *h, int mb_y, int b_inloop ) { /* mb_y is the mb to be encoded next, not the mb to be filtered here */ int b_hpel = h->fdec->b_kept_as_ref; @@ -1879,30 +1851,11 @@ static void x264_fdec_filter_row( x264_t *h, int mb_y, int pass ) * above each MB, as bS=4 doesn't happen for the top of interlaced mbpairs. */ int minpix_y = min_y*16 - 4 * !b_start; int maxpix_y = mb_y*16 - 4 * !b_end; - b_deblock &= b_hpel || h->param.b_full_recon || h->param.psz_dump_yuv; - if( h->param.b_sliced_threads ) + b_deblock &= b_hpel || h->param.b_full_recon; + if( h->param.b_sliced_threads && b_start && min_y && !b_inloop ) { - switch( pass ) - { - /* During encode: only do deblock if asked for */ - default: - case 0: - b_deblock &= h->param.b_full_recon; - b_hpel = 0; - break; - /* During post-encode pass: do deblock if not done yet, do hpel for all - * rows except those between slices. */ - case 1: - b_deblock &= !h->param.b_full_recon; - b_hpel &= !(b_start && min_y > 0); - b_measure_quality = 0; - break; - /* Final pass: do the rows between slices in sequence. */ - case 2: - b_deblock = 0; - b_measure_quality = 0; - break; - } + b_deblock = 0; /* We already deblocked on the inloop pass. */ + b_measure_quality = 0; /* We already measured quality on the inloop pass. */ } if( mb_y & SLICE_MBAFF ) return; @@ -1916,19 +1869,17 @@ static void x264_fdec_filter_row( x264_t *h, int mb_y, int pass ) /* FIXME: Prediction requires different borders for interlaced/progressive mc, * but the actual image data is equivalent. For now, maintain this * consistency by copying deblocked pixels between planes. */ - if( PARAM_INTERLACED && (!h->param.b_sliced_threads || pass == 1) ) + if( PARAM_INTERLACED ) for( int p = 0; p < h->fdec->i_plane; p++ ) for( int i = minpix_y>>(CHROMA_V_SHIFT && p); i < maxpix_y>>(CHROMA_V_SHIFT && p); i++ ) memcpy( h->fdec->plane_fld[p] + i*h->fdec->i_stride[p], h->fdec->plane[p] + i*h->fdec->i_stride[p], h->mb.i_mb_width*16*sizeof(pixel) ); - if( h->fdec->b_kept_as_ref && (!h->param.b_sliced_threads || pass == 1) ) - x264_frame_expand_border( h, h->fdec, min_y ); if( b_hpel ) { int end = mb_y == h->mb.i_mb_height; - /* Can't do hpel until the previous slice is done encoding. */ + x264_frame_expand_border( h, h->fdec, min_y, end ); if( h->param.analyse.i_subpel_refine ) { x264_frame_filter( h, h->fdec, min_y, end ); @@ -1936,7 +1887,7 @@ static void x264_fdec_filter_row( x264_t *h, int mb_y, int pass ) } } - if( SLICE_MBAFF && pass == 0 ) + if( SLICE_MBAFF ) for( int i = 0; i < 3; i++ ) { XCHG( pixel *, h->intra_border_backup[0][i], h->intra_border_backup[3][i] ); @@ -2205,7 +2156,7 @@ static int x264_slice_write( x264_t *h ) int orig_last_mb = h->sh.i_last_mb; uint8_t *last_emu_check; x264_bs_bak_t bs_bak[2]; - b_deblock &= b_hpel || h->param.b_full_recon || h->param.psz_dump_yuv; + b_deblock &= b_hpel || h->param.b_full_recon; bs_realign( &h->out.bs ); /* Slice */ @@ -2257,7 +2208,7 @@ static int x264_slice_write( x264_t *h ) if( !(i_mb_y & SLICE_MBAFF) && h->param.rc.i_vbv_buffer_size ) x264_bitstream_backup( h, &bs_bak[1], i_skip, 1 ); if( !h->mb.b_reencode_mb ) - x264_fdec_filter_row( h, i_mb_y, 0 ); + x264_fdec_filter_row( h, i_mb_y, 1 ); } if( !(i_mb_y & SLICE_MBAFF) && back_up_bitstream ) @@ -2504,23 +2455,7 @@ static int x264_slice_write( x264_t *h ) + (h->out.i_nal*NALU_OVERHEAD * 8) - h->stat.frame.i_tex_bits - h->stat.frame.i_mv_bits; - x264_fdec_filter_row( h, h->i_threadslice_end, 0 ); - - if( h->param.b_sliced_threads ) - { - /* Tell the main thread we're done. */ - x264_threadslice_cond_broadcast( h, 1 ); - /* Do hpel now */ - for( int mb_y = h->i_threadslice_start; mb_y <= h->i_threadslice_end; mb_y++ ) - x264_fdec_filter_row( h, mb_y, 1 ); - x264_threadslice_cond_broadcast( h, 2 ); - /* Do the first row of hpel, now that the previous slice is done */ - if( h->i_thread_idx > 0 ) - { - x264_threadslice_cond_wait( h->thread[h->i_thread_idx-1], 2 ); - x264_fdec_filter_row( h, h->i_threadslice_start + (1 << SLICE_MBAFF), 2 ); - } - } + x264_fdec_filter_row( h, h->i_threadslice_end, 1 ); } return 0; @@ -2561,7 +2496,7 @@ static void *x264_slices_write( x264_t *h ) #if HAVE_VISUALIZE if( h->param.b_visualize ) if( x264_visualize_init( h ) ) - goto fail; + return (void *)-1; #endif /* init stats */ @@ -2594,7 +2529,7 @@ static void *x264_slices_write( x264_t *h ) } h->sh.i_last_mb = X264_MIN( h->sh.i_last_mb, last_thread_mb ); if( x264_stack_align( x264_slice_write, h ) ) - goto fail; + return (void *)-1; h->sh.i_first_mb = h->sh.i_last_mb + 1; // if i_first_mb is not the last mb in a row then go to the next mb in MBAFF order if( SLICE_MBAFF && h->sh.i_first_mb % h->mb.i_mb_width ) @@ -2610,12 +2545,6 @@ static void *x264_slices_write( x264_t *h ) #endif return (void *)0; - -fail: - /* Tell other threads we're done, so they wouldn't wait for it */ - if( h->param.b_sliced_threads ) - x264_threadslice_cond_broadcast( h, 2 ); - return (void *)-1; } static int x264_threaded_slices_write( x264_t *h ) @@ -2640,19 +2569,26 @@ static int x264_threaded_slices_write( x264_t *h ) x264_threads_distribute_ratecontrol( h ); - /* setup */ + /* dispatch */ for( int i = 0; i < h->param.i_threads; i++ ) { - h->thread[i]->i_thread_idx = i; + x264_threadpool_run( h->threadpool, (void*)x264_slices_write, h->thread[i] ); h->thread[i]->b_thread_active = 1; - x264_threadslice_cond_broadcast( h->thread[i], 0 ); } - /* dispatch */ - for( int i = 0; i < h->param.i_threads; i++ ) - x264_threadpool_run( h->threadpool, (void*)x264_slices_write, h->thread[i] ); - /* wait */ for( int i = 0; i < h->param.i_threads; i++ ) - x264_threadslice_cond_wait( h->thread[i], 1 ); + { + h->thread[i]->b_thread_active = 0; + if( (intptr_t)x264_threadpool_wait( h->threadpool, h->thread[i] ) ) + return -1; + } + + /* Go back and fix up the hpel on the borders between slices. */ + for( int i = 1; i < h->param.i_threads; i++ ) + { + x264_fdec_filter_row( h->thread[i], h->thread[i]->i_threadslice_start + 1, 0 ); + if( SLICE_MBAFF ) + x264_fdec_filter_row( h->thread[i], h->thread[i]->i_threadslice_start + 2, 0 ); + } x264_threads_merge_ratecontrol( h ); @@ -2749,6 +2685,11 @@ int x264_encoder_encode( x264_t *h, x264_cpu_mask_misalign_sse(); #endif + // ok to call this before encoding any frames, since the initial values of fdec have b_kept_as_ref=0 + if( x264_reference_update( h ) ) + return -1; + h->fdec->i_lines_completed = -1; + /* no data out */ *pi_nal = 0; *pp_nal = NULL; @@ -2844,12 +2785,6 @@ int x264_encoder_encode( x264_t *h, /* ------------------- Get frame to be encoded ------------------------- */ /* 4: get picture to encode */ h->fenc = x264_frame_shift( h->frames.current ); - - /* If applicable, wait for previous frame reconstruction to finish */ - if( h->param.b_sliced_threads ) - if( x264_threadpool_wait_all( h ) < 0 ) - return -1; - if( h->i_frame == h->i_thread_frames - 1 ) h->i_reordered_pts_delay = h->fenc->i_reordered_pts; if( h->fenc->param ) @@ -2859,11 +2794,6 @@ int x264_encoder_encode( x264_t *h, h->fenc->param->param_free( h->fenc->param ); } - // ok to call this before encoding any frames, since the initial values of fdec have b_kept_as_ref=0 - if( x264_reference_update( h ) ) - return -1; - h->fdec->i_lines_completed = -1; - if( !IS_X264_TYPE_I( h->fenc->i_type ) ) { int valid_refs_left = 0; @@ -3196,7 +3126,7 @@ static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current, { char psz_message[80]; - if( !h->param.b_sliced_threads && h->b_thread_active ) + if( h->b_thread_active ) { h->b_thread_active = 0; if( (intptr_t)x264_threadpool_wait( h->threadpool, h ) ) @@ -3466,8 +3396,6 @@ void x264_encoder_close ( x264_t *h ) x264_lookahead_delete( h ); - if( h->param.b_sliced_threads ) - x264_threadpool_wait_all( h ); if( h->param.i_threads > 1 ) x264_threadpool_delete( h->threadpool ); if( h->i_thread_frames > 1 ) @@ -3763,7 +3691,7 @@ void x264_encoder_close ( x264_t *h ) x264_free( h->nal_buffer ); x264_analyse_free_costs( h ); - if( h->i_thread_frames > 1 ) + if( h->i_thread_frames > 1) h = h->thread[h->i_thread_phase]; /* frames */ @@ -3805,9 +3733,7 @@ void x264_encoder_close ( x264_t *h ) } 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]->out.nal); x264_free( h->thread[i] ); } } From 6180eed8311d7c1750daf6af8098d959c08eea5c Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Thu, 15 Mar 2012 10:05:59 +0000 Subject: [PATCH 68/81] Revert "Fix clobbering of mutex/cvs" This reverts commit 5c85e0a2b7992fcaab09418e3fcefc613cffc743. --- encoder/encoder.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/encoder/encoder.c b/encoder/encoder.c index d4641d58..50edaf16 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -1266,8 +1266,18 @@ x264_t *x264_encoder_open( x264_param_t *param ) goto fail; h->thread[0] = h; - for( int i = 1; i < h->param.i_threads + !!h->param.i_sync_lookahead; i++ ) - CHECKED_MALLOC( h->thread[i], sizeof(x264_t) ); + for( int i = 0; i < h->param.i_threads + !!h->param.i_sync_lookahead; i++ ) + { + if( i ) + CHECKED_MALLOC( h->thread[i], sizeof(x264_t) ); + if( i < h->param.i_threads ) + { + if( x264_pthread_mutex_init( &h->thread[i]->mutex, NULL ) ) + goto fail; + if( x264_pthread_cond_init( &h->thread[i]->cv, NULL ) ) + goto fail; + } + } for( int i = 0; i < h->param.i_threads; i++ ) { @@ -1276,11 +1286,6 @@ x264_t *x264_encoder_open( x264_param_t *param ) if( i > 0 ) *h->thread[i] = *h; - if( x264_pthread_mutex_init( &h->thread[i]->mutex, NULL ) ) - goto fail; - if( x264_pthread_cond_init( &h->thread[i]->cv, NULL ) ) - goto fail; - if( allocate_threadlocal_data ) { h->thread[i]->fdec = x264_frame_pop_unused( h, 1 ); From 475c62d96496a75f186b10e815824e6f9f56e549 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Mon, 19 Mar 2012 16:27:00 +0000 Subject: [PATCH 69/81] Fix build temporarily. --- encoder/encoder.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/encoder/encoder.c b/encoder/encoder.c index 50edaf16..2d7e9278 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -1266,18 +1266,8 @@ x264_t *x264_encoder_open( x264_param_t *param ) goto fail; h->thread[0] = h; - for( int i = 0; i < h->param.i_threads + !!h->param.i_sync_lookahead; i++ ) - { - if( i ) - CHECKED_MALLOC( h->thread[i], sizeof(x264_t) ); - if( i < h->param.i_threads ) - { - if( x264_pthread_mutex_init( &h->thread[i]->mutex, NULL ) ) - goto fail; - if( x264_pthread_cond_init( &h->thread[i]->cv, NULL ) ) - goto fail; - } - } + for( int i = 1; i < h->param.i_threads + !!h->param.i_sync_lookahead; i++ ) + CHECKED_MALLOC( h->thread[i], sizeof(x264_t) ); for( int i = 0; i < h->param.i_threads; i++ ) { From 788efde84d04fb04a3d458acb371994606e4faed Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 27 Mar 2012 16:55:05 +0100 Subject: [PATCH 70/81] Fix intra-refresh + hrd. --- common/common.h | 1 + encoder/encoder.c | 7 ++++--- encoder/slicetype.c | 3 ++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/common/common.h b/common/common.h index fab453e3..a3149c02 100644 --- a/common/common.h +++ b/common/common.h @@ -513,6 +513,7 @@ struct x264_t int64_t i_cpb_delay_lookahead; int64_t i_cpb_delay_pir_offset; + int64_t i_cpb_delay_pir_offset_next; int b_queued_intra_refresh; int64_t i_last_idr_pts; diff --git a/encoder/encoder.c b/encoder/encoder.c index 2539b3fc..58689c96 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -2735,6 +2735,7 @@ int x264_encoder_encode( x264_t *h, if( h->param.cpu&X264_CPU_SSE_MISALIGN ) x264_cpu_mask_misalign_sse(); #endif + h->i_cpb_delay_pir_offset = h->i_cpb_delay_pir_offset_next; /* no data out */ *pi_nal = 0; @@ -3124,9 +3125,6 @@ int x264_encoder_encode( x264_t *h, overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD - (h->param.b_annexb && h->out.i_nal-1); } - if( h->fenc->b_keyframe && h->param.b_intra_refresh ) - h->i_cpb_delay_pir_offset = h->fenc->i_cpb_delay; - /* Init the rate control */ /* FIXME: Include slice header bit cost. */ x264_ratecontrol_start( h, h->fenc->i_qpplus1, overhead*8 ); @@ -3252,6 +3250,9 @@ static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current, if( x264_ratecontrol_end( h, frame_size * 8, &filler ) < 0 ) return -1; + if( h->fenc->b_keyframe && h->param.b_intra_refresh ) + h->i_cpb_delay_pir_offset_next = h->fenc->i_cpb_delay; + pic_out->hrd_timing = h->fenc->hrd_timing; while( filler > 0 ) diff --git a/encoder/slicetype.c b/encoder/slicetype.c index e77ba1d0..9bd862de 100644 --- a/encoder/slicetype.c +++ b/encoder/slicetype.c @@ -1067,7 +1067,8 @@ static void x264_calculate_durations( x264_t *h, x264_frame_t *cur_frame, x264_f prev_frame->i_cpb_duration += cur_frame->i_dpb_output_delay; } - if( cur_frame->b_keyframe ) + // don't reset cpb delay for IDR frames when using intra-refresh + if( cur_frame->b_keyframe && !h->param.b_intra_refresh ) *i_cpb_delay = 0; *i_cpb_delay += cur_frame->i_duration; From 48de3178ced2ca1d884ba8b2b401bb07c6654221 Mon Sep 17 00:00:00 2001 From: Jason Garrett-Glaser Date: Fri, 24 Feb 2012 13:34:39 -0800 Subject: [PATCH 71/81] Sliced-threads: do hpel and deblock after returning Lowers encoding latency around 14% in sliced threads mode with preset superfast. Additionally, even if there is no waiting time between frames, this improves parallelism, because hpel+deblock are done during the (singlethreaded) lookahead. For ease of debugging, dump-yuv forces all of the threads to wait and finish instead of setting b_full_recon. --- common/common.h | 7 ++ common/deblock.c | 4 +- common/frame.c | 43 ++++++++---- common/frame.h | 5 +- common/macroblock.c | 19 +++++- encoder/encoder.c | 156 ++++++++++++++++++++++++++++++++------------ 6 files changed, 176 insertions(+), 58 deletions(-) diff --git a/common/common.h b/common/common.h index c0277d8d..366bf204 100644 --- a/common/common.h +++ b/common/common.h @@ -471,9 +471,13 @@ struct x264_t x264_t *thread[X264_THREAD_MAX+1]; int b_thread_active; int i_thread_phase; /* which thread to use for the next frame */ + int i_thread_idx; /* which thread this is */ int i_threadslice_start; /* first row in this thread slice */ int i_threadslice_end; /* row after the end of this thread slice */ + int i_threadslice_pass; /* which pass of encoding we are on */ x264_threadpool_t *threadpool; + x264_pthread_mutex_t mutex; + x264_pthread_cond_t cv; /* bitstream output */ struct @@ -824,6 +828,9 @@ struct x264_t /* extra data required for mbaff in mv prediction */ int16_t topright_mv[2][3][2]; int8_t topright_ref[2][3]; + + /* current mb deblock strength */ + uint8_t (*deblock_strength)[8][4]; } cache; /* */ diff --git a/common/deblock.c b/common/deblock.c index 58cf3c41..d76682a2 100644 --- a/common/deblock.c +++ b/common/deblock.c @@ -395,7 +395,7 @@ void x264_frame_deblock_row( x264_t *h, int mb_y ) int mb_xy = h->mb.i_mb_xy; int transform_8x8 = h->mb.mb_transform_size[h->mb.i_mb_xy]; int intra_cur = IS_INTRA( h->mb.type[mb_xy] ); - uint8_t (*bs)[8][4] = h->deblock_strength[mb_y&1][mb_x]; + uint8_t (*bs)[8][4] = h->deblock_strength[mb_y&1][h->param.b_sliced_threads?mb_xy:mb_x]; pixel *pixy = h->fdec->plane[0] + 16*mb_y*stridey + 16*mb_x; pixel *pixuv = h->fdec->plane[1] + chroma_height*mb_y*strideuv + 16*mb_x; @@ -592,7 +592,7 @@ void x264_macroblock_deblock( x264_t *h ) if( (h->mb.i_partition == D_16x16 && !h->mb.i_cbp_luma && !intra_cur) || qp <= qp_thresh ) return; - uint8_t (*bs)[8][4] = h->deblock_strength[h->mb.i_mb_y&1][h->mb.i_mb_x]; + uint8_t (*bs)[8][4] = h->mb.cache.deblock_strength; if( intra_cur ) { memset( &bs[0][1], 3, 3*4*sizeof(uint8_t) ); diff --git a/common/frame.c b/common/frame.c index d9bb257c..86c7e730 100644 --- a/common/frame.c +++ b/common/frame.c @@ -480,9 +480,12 @@ static void ALWAYS_INLINE plane_expand_border( pixel *pix, int i_stride, int i_w #undef PPIXEL } -void x264_frame_expand_border( x264_t *h, x264_frame_t *frame, int mb_y, int b_end ) +void x264_frame_expand_border( x264_t *h, x264_frame_t *frame, int mb_y ) { - int b_start = !mb_y; + int pad_top = mb_y == 0; + int pad_bot = mb_y == h->mb.i_mb_height - (1 << SLICE_MBAFF); + int b_start = mb_y == h->i_threadslice_start; + int b_end = mb_y == h->i_threadslice_end - (1 << SLICE_MBAFF); if( mb_y & SLICE_MBAFF ) return; for( int i = 0; i < frame->i_plane; i++ ) @@ -491,30 +494,31 @@ void x264_frame_expand_border( x264_t *h, x264_frame_t *frame, int mb_y, int b_e int v_shift = i && CHROMA_V_SHIFT; int stride = frame->i_stride[i]; int width = 16*h->mb.i_mb_width; - int height = (b_end ? 16*(h->mb.i_mb_height - mb_y) >> SLICE_MBAFF : 16) >> v_shift; + int height = (pad_bot ? 16*(h->mb.i_mb_height - mb_y) >> SLICE_MBAFF : 16) >> v_shift; int padh = PADH; int padv = PADV >> v_shift; // buffer: 2 chroma, 3 luma (rounded to 4) because deblocking goes beyond the top of the mb if( b_end && !b_start ) height += 4 >> (v_shift + SLICE_MBAFF); pixel *pix; + int starty = 16*mb_y - 4*!b_start; if( SLICE_MBAFF ) { // border samples for each field are extended separately - pix = frame->plane_fld[i] + X264_MAX(0, (16*mb_y-4)*stride >> v_shift); - plane_expand_border( pix, stride*2, width, height, padh, padv, b_start, b_end, h_shift ); - plane_expand_border( pix+stride, stride*2, width, height, padh, padv, b_start, b_end, h_shift ); + pix = frame->plane_fld[i] + (starty*stride >> v_shift); + plane_expand_border( pix, stride*2, width, height, padh, padv, pad_top, pad_bot, h_shift ); + plane_expand_border( pix+stride, stride*2, width, height, padh, padv, pad_top, pad_bot, h_shift ); - height = (b_end ? 16*(h->mb.i_mb_height - mb_y) : 32) >> v_shift; + height = (pad_bot ? 16*(h->mb.i_mb_height - mb_y) : 32) >> v_shift; if( b_end && !b_start ) height += 4 >> v_shift; - pix = frame->plane[i] + X264_MAX(0, (16*mb_y-4)*stride >> v_shift); - plane_expand_border( pix, stride, width, height, padh, padv, b_start, b_end, h_shift ); + pix = frame->plane[i] + (starty*stride >> v_shift); + plane_expand_border( pix, stride, width, height, padh, padv, pad_top, pad_bot, h_shift ); } else { - pix = frame->plane[i] + X264_MAX(0, (16*mb_y-4)*stride >> v_shift); - plane_expand_border( pix, stride, width, height, padh, padv, b_start, b_end, h_shift ); + pix = frame->plane[i] + (starty*stride >> v_shift); + plane_expand_border( pix, stride, width, height, padh, padv, pad_top, pad_bot, h_shift ); } } } @@ -619,6 +623,23 @@ void x264_frame_cond_wait( x264_frame_t *frame, int i_lines_completed ) x264_pthread_mutex_unlock( &frame->mutex ); } +void x264_threadslice_cond_broadcast( x264_t *h, int pass ) +{ + x264_pthread_mutex_lock( &h->mutex ); + h->i_threadslice_pass = pass; + if( pass > 0 ) + x264_pthread_cond_broadcast( &h->cv ); + x264_pthread_mutex_unlock( &h->mutex ); +} + +void x264_threadslice_cond_wait( x264_t *h, int pass ) +{ + x264_pthread_mutex_lock( &h->mutex ); + while( h->i_threadslice_pass < pass ) + x264_pthread_cond_wait( &h->cv, &h->mutex ); + x264_pthread_mutex_unlock( &h->mutex ); +} + /* list operators */ void x264_frame_push( x264_frame_t **list, x264_frame_t *frame ) diff --git a/common/frame.h b/common/frame.h index 8861726b..55bccacc 100644 --- a/common/frame.h +++ b/common/frame.h @@ -207,7 +207,7 @@ void x264_frame_delete( x264_frame_t *frame ); int x264_frame_copy_picture( x264_t *h, x264_frame_t *dst, x264_picture_t *src ); -void x264_frame_expand_border( x264_t *h, x264_frame_t *frame, int mb_y, int b_end ); +void x264_frame_expand_border( x264_t *h, x264_frame_t *frame, int mb_y ); void x264_frame_expand_border_filtered( x264_t *h, x264_frame_t *frame, int mb_y, int b_end ); void x264_frame_expand_border_lowres( x264_frame_t *frame ); void x264_frame_expand_border_chroma( x264_t *h, x264_frame_t *frame, int plane ); @@ -225,6 +225,9 @@ void x264_deblock_init( int cpu, x264_deblock_function_t *pf, int b_mba void x264_frame_cond_broadcast( x264_frame_t *frame, int i_lines_completed ); void x264_frame_cond_wait( x264_frame_t *frame, int i_lines_completed ); +void x264_threadslice_cond_broadcast( x264_t *h, int pass ); +void x264_threadslice_cond_wait( x264_t *h, int pass ); + void x264_frame_push( x264_frame_t **list, x264_frame_t *frame ); x264_frame_t *x264_frame_pop( x264_frame_t **list ); void x264_frame_unshift( x264_frame_t **list, x264_frame_t *frame ); diff --git a/common/macroblock.c b/common/macroblock.c index 9d478d29..11c3e75e 100644 --- a/common/macroblock.c +++ b/common/macroblock.c @@ -368,7 +368,17 @@ int x264_macroblock_thread_allocate( x264_t *h, int b_lookahead ) } for( int i = 0; i <= PARAM_INTERLACED; i++ ) { - CHECKED_MALLOC( h->deblock_strength[i], sizeof(**h->deblock_strength) * h->mb.i_mb_width ); + if( h->param.b_sliced_threads ) + { + /* Only allocate the first one, and allocate it for the whole frame, because we + * won't be deblocking until after the frame is fully encoded. */ + if( h == h->thread[0] && !i ) + CHECKED_MALLOC( h->deblock_strength[0], sizeof(**h->deblock_strength) * h->mb.i_mb_count ); + else + h->deblock_strength[i] = h->thread[0]->deblock_strength[0]; + } + else + CHECKED_MALLOC( h->deblock_strength[i], sizeof(**h->deblock_strength) * h->mb.i_mb_width ); h->deblock_strength[1] = h->deblock_strength[i]; } } @@ -401,7 +411,8 @@ void x264_macroblock_thread_free( x264_t *h, int b_lookahead ) if( !b_lookahead ) { for( int i = 0; i <= PARAM_INTERLACED; i++ ) - x264_free( h->deblock_strength[i] ); + if( !h->param.b_sliced_threads || (h == h->thread[0] && !i) ) + x264_free( h->deblock_strength[i] ); for( int i = 0; i < (PARAM_INTERLACED ? 5 : 2); i++ ) for( int j = 0; j < (CHROMA444 ? 3 : 2); j++ ) x264_free( h->intra_border_backup[i][j] - 16 ); @@ -858,6 +869,8 @@ static void ALWAYS_INLINE x264_macroblock_cache_load( x264_t *h, int mb_x, int m const x264_left_table_t *left_index_table = h->mb.left_index_table; + h->mb.cache.deblock_strength = h->deblock_strength[mb_y&1][h->param.b_sliced_threads?h->mb.i_mb_xy:mb_x]; + /* load cache */ if( h->mb.i_neighbour & MB_TOP ) { @@ -1432,7 +1445,7 @@ static void x264_macroblock_deblock_strength_mbaff( x264_t *h, uint8_t (*bs)[8][ void x264_macroblock_deblock_strength( x264_t *h ) { - uint8_t (*bs)[8][4] = h->deblock_strength[h->mb.i_mb_y&1][h->mb.i_mb_x]; + uint8_t (*bs)[8][4] = h->mb.cache.deblock_strength; if( IS_INTRA( h->mb.i_type ) ) { memset( bs[0][1], 3, 3*4*sizeof(uint8_t) ); diff --git a/encoder/encoder.c b/encoder/encoder.c index 2d7e9278..f00455c4 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -68,12 +68,28 @@ static double x264_ssim( double ssim ) return -10.0 * log10( inv_ssim ); } +static int x264_threadpool_wait_all( x264_t *h ) +{ + for( int i = 0; i < h->param.i_threads; i++ ) + if( h->thread[i]->b_thread_active ) + { + h->thread[i]->b_thread_active = 0; + if( (intptr_t)x264_threadpool_wait( h->threadpool, h->thread[i] ) < 0 ) + return -1; + } + return 0; +} + static void x264_frame_dump( x264_t *h ) { FILE *f = fopen( h->param.psz_dump_yuv, "r+b" ); if( !f ) return; + /* Wait for the threads to finish deblocking */ + if( h->param.b_sliced_threads ) + x264_threadpool_wait_all( h ); + /* Write the frame in display order */ int frame_size = FRAME_SIZE( h->param.i_height * h->param.i_width * sizeof(pixel) ); fseek( f, (uint64_t)h->fdec->i_frame * frame_size, SEEK_SET ); @@ -923,9 +939,6 @@ static int x264_validate_parameters( x264_t *h, int b_open ) h->param.i_nal_hrd = h->param.i_nal_hrd == X264_NAL_HRD_CBR ? X264_NAL_HRD_VBR : X264_NAL_HRD_FAKE_CBR; } - if( h->param.psz_dump_yuv ) - h->param.b_full_recon = 1; - /* ensure the booleans are 0 or 1 so they can be used in math */ #define BOOLIFY(x) h->param.x = !!h->param.x BOOLIFY( b_cabac ); @@ -1266,8 +1279,18 @@ x264_t *x264_encoder_open( x264_param_t *param ) goto fail; h->thread[0] = h; - for( int i = 1; i < h->param.i_threads + !!h->param.i_sync_lookahead; i++ ) - CHECKED_MALLOC( h->thread[i], sizeof(x264_t) ); + for( int i = 0; i < h->param.i_threads + !!h->param.i_sync_lookahead; i++ ) + { + if( i ) + CHECKED_MALLOC( h->thread[i], sizeof(x264_t) ); + if( i < h->param.i_threads ) + { + if( x264_pthread_mutex_init( &h->thread[i]->mutex, NULL ) ) + goto fail; + if( x264_pthread_cond_init( &h->thread[i]->cv, NULL ) ) + goto fail; + } + } for( int i = 0; i < h->param.i_threads; i++ ) { @@ -1362,6 +1385,11 @@ x264_t *x264_encoder_open( x264_param_t *param ) ****************************************************************************/ int x264_encoder_reconfig( x264_t *h, x264_param_t *param ) { + /* If the previous frame isn't done encoding, reconfiguring is probably dangerous. */ + if( h->param.b_sliced_threads ) + if( x264_threadpool_wait_all( h ) < 0 ) + return -1; + int rc_reconfig = 0; h = h->thread[h->thread[0]->i_thread_phase]; x264_set_aspect_ratio( h, param, 0 ); @@ -1838,7 +1866,7 @@ static inline void x264_reference_build_list( x264_t *h, int i_poc ) h->mb.pic.i_fref[1] = h->i_ref[1]; } -static void x264_fdec_filter_row( x264_t *h, int mb_y, int b_inloop ) +static void x264_fdec_filter_row( x264_t *h, int mb_y, int pass ) { /* mb_y is the mb to be encoded next, not the mb to be filtered here */ int b_hpel = h->fdec->b_kept_as_ref; @@ -1851,11 +1879,30 @@ static void x264_fdec_filter_row( x264_t *h, int mb_y, int b_inloop ) * above each MB, as bS=4 doesn't happen for the top of interlaced mbpairs. */ int minpix_y = min_y*16 - 4 * !b_start; int maxpix_y = mb_y*16 - 4 * !b_end; - b_deblock &= b_hpel || h->param.b_full_recon; - if( h->param.b_sliced_threads && b_start && min_y && !b_inloop ) + b_deblock &= b_hpel || h->param.b_full_recon || h->param.psz_dump_yuv; + if( h->param.b_sliced_threads ) { - b_deblock = 0; /* We already deblocked on the inloop pass. */ - b_measure_quality = 0; /* We already measured quality on the inloop pass. */ + switch( pass ) + { + /* During encode: only do deblock if asked for */ + default: + case 0: + b_deblock &= h->param.b_full_recon; + b_hpel = 0; + break; + /* During post-encode pass: do deblock if not done yet, do hpel for all + * rows except those between slices. */ + case 1: + b_deblock &= !h->param.b_full_recon; + b_hpel &= !(b_start && min_y > 0); + b_measure_quality = 0; + break; + /* Final pass: do the rows between slices in sequence. */ + case 2: + b_deblock = 0; + b_measure_quality = 0; + break; + } } if( mb_y & SLICE_MBAFF ) return; @@ -1869,17 +1916,19 @@ static void x264_fdec_filter_row( x264_t *h, int mb_y, int b_inloop ) /* FIXME: Prediction requires different borders for interlaced/progressive mc, * but the actual image data is equivalent. For now, maintain this * consistency by copying deblocked pixels between planes. */ - if( PARAM_INTERLACED ) + if( PARAM_INTERLACED && (!h->param.b_sliced_threads || pass == 1) ) for( int p = 0; p < h->fdec->i_plane; p++ ) for( int i = minpix_y>>(CHROMA_V_SHIFT && p); i < maxpix_y>>(CHROMA_V_SHIFT && p); i++ ) memcpy( h->fdec->plane_fld[p] + i*h->fdec->i_stride[p], h->fdec->plane[p] + i*h->fdec->i_stride[p], h->mb.i_mb_width*16*sizeof(pixel) ); + if( h->fdec->b_kept_as_ref && (!h->param.b_sliced_threads || pass == 1) ) + x264_frame_expand_border( h, h->fdec, min_y ); if( b_hpel ) { int end = mb_y == h->mb.i_mb_height; - x264_frame_expand_border( h, h->fdec, min_y, end ); + /* Can't do hpel until the previous slice is done encoding. */ if( h->param.analyse.i_subpel_refine ) { x264_frame_filter( h, h->fdec, min_y, end ); @@ -1887,7 +1936,7 @@ static void x264_fdec_filter_row( x264_t *h, int mb_y, int b_inloop ) } } - if( SLICE_MBAFF ) + if( SLICE_MBAFF && pass == 0 ) for( int i = 0; i < 3; i++ ) { XCHG( pixel *, h->intra_border_backup[0][i], h->intra_border_backup[3][i] ); @@ -2156,7 +2205,7 @@ static int x264_slice_write( x264_t *h ) int orig_last_mb = h->sh.i_last_mb; uint8_t *last_emu_check; x264_bs_bak_t bs_bak[2]; - b_deblock &= b_hpel || h->param.b_full_recon; + b_deblock &= b_hpel || h->param.b_full_recon || h->param.psz_dump_yuv; bs_realign( &h->out.bs ); /* Slice */ @@ -2208,7 +2257,7 @@ static int x264_slice_write( x264_t *h ) if( !(i_mb_y & SLICE_MBAFF) && h->param.rc.i_vbv_buffer_size ) x264_bitstream_backup( h, &bs_bak[1], i_skip, 1 ); if( !h->mb.b_reencode_mb ) - x264_fdec_filter_row( h, i_mb_y, 1 ); + x264_fdec_filter_row( h, i_mb_y, 0 ); } if( !(i_mb_y & SLICE_MBAFF) && back_up_bitstream ) @@ -2455,7 +2504,23 @@ static int x264_slice_write( x264_t *h ) + (h->out.i_nal*NALU_OVERHEAD * 8) - h->stat.frame.i_tex_bits - h->stat.frame.i_mv_bits; - x264_fdec_filter_row( h, h->i_threadslice_end, 1 ); + x264_fdec_filter_row( h, h->i_threadslice_end, 0 ); + + if( h->param.b_sliced_threads ) + { + /* Tell the main thread we're done. */ + x264_threadslice_cond_broadcast( h, 1 ); + /* Do hpel now */ + for( int mb_y = h->i_threadslice_start; mb_y <= h->i_threadslice_end; mb_y++ ) + x264_fdec_filter_row( h, mb_y, 1 ); + x264_threadslice_cond_broadcast( h, 2 ); + /* Do the first row of hpel, now that the previous slice is done */ + if( h->i_thread_idx > 0 ) + { + x264_threadslice_cond_wait( h->thread[h->i_thread_idx-1], 2 ); + x264_fdec_filter_row( h, h->i_threadslice_start + (1 << SLICE_MBAFF), 2 ); + } + } } return 0; @@ -2496,7 +2561,7 @@ static void *x264_slices_write( x264_t *h ) #if HAVE_VISUALIZE if( h->param.b_visualize ) if( x264_visualize_init( h ) ) - return (void *)-1; + goto fail; #endif /* init stats */ @@ -2529,7 +2594,7 @@ static void *x264_slices_write( x264_t *h ) } h->sh.i_last_mb = X264_MIN( h->sh.i_last_mb, last_thread_mb ); if( x264_stack_align( x264_slice_write, h ) ) - return (void *)-1; + goto fail; h->sh.i_first_mb = h->sh.i_last_mb + 1; // if i_first_mb is not the last mb in a row then go to the next mb in MBAFF order if( SLICE_MBAFF && h->sh.i_first_mb % h->mb.i_mb_width ) @@ -2545,6 +2610,12 @@ static void *x264_slices_write( x264_t *h ) #endif return (void *)0; + +fail: + /* Tell other threads we're done, so they wouldn't wait for it */ + if( h->param.b_sliced_threads ) + x264_threadslice_cond_broadcast( h, 2 ); + return (void *)-1; } static int x264_threaded_slices_write( x264_t *h ) @@ -2569,26 +2640,19 @@ static int x264_threaded_slices_write( x264_t *h ) x264_threads_distribute_ratecontrol( h ); - /* dispatch */ + /* setup */ for( int i = 0; i < h->param.i_threads; i++ ) { - x264_threadpool_run( h->threadpool, (void*)x264_slices_write, h->thread[i] ); + h->thread[i]->i_thread_idx = i; h->thread[i]->b_thread_active = 1; + x264_threadslice_cond_broadcast( h->thread[i], 0 ); } + /* dispatch */ for( int i = 0; i < h->param.i_threads; i++ ) - { - h->thread[i]->b_thread_active = 0; - if( (intptr_t)x264_threadpool_wait( h->threadpool, h->thread[i] ) ) - return -1; - } - - /* Go back and fix up the hpel on the borders between slices. */ - for( int i = 1; i < h->param.i_threads; i++ ) - { - x264_fdec_filter_row( h->thread[i], h->thread[i]->i_threadslice_start + 1, 0 ); - if( SLICE_MBAFF ) - x264_fdec_filter_row( h->thread[i], h->thread[i]->i_threadslice_start + 2, 0 ); - } + x264_threadpool_run( h->threadpool, (void*)x264_slices_write, h->thread[i] ); + /* wait */ + for( int i = 0; i < h->param.i_threads; i++ ) + x264_threadslice_cond_wait( h->thread[i], 1 ); x264_threads_merge_ratecontrol( h ); @@ -2685,11 +2749,6 @@ int x264_encoder_encode( x264_t *h, x264_cpu_mask_misalign_sse(); #endif - // ok to call this before encoding any frames, since the initial values of fdec have b_kept_as_ref=0 - if( x264_reference_update( h ) ) - return -1; - h->fdec->i_lines_completed = -1; - /* no data out */ *pi_nal = 0; *pp_nal = NULL; @@ -2785,6 +2844,12 @@ int x264_encoder_encode( x264_t *h, /* ------------------- Get frame to be encoded ------------------------- */ /* 4: get picture to encode */ h->fenc = x264_frame_shift( h->frames.current ); + + /* If applicable, wait for previous frame reconstruction to finish */ + if( h->param.b_sliced_threads ) + if( x264_threadpool_wait_all( h ) < 0 ) + return -1; + if( h->i_frame == h->i_thread_frames - 1 ) h->i_reordered_pts_delay = h->fenc->i_reordered_pts; if( h->fenc->param ) @@ -2794,6 +2859,11 @@ int x264_encoder_encode( x264_t *h, h->fenc->param->param_free( h->fenc->param ); } + // ok to call this before encoding any frames, since the initial values of fdec have b_kept_as_ref=0 + if( x264_reference_update( h ) ) + return -1; + h->fdec->i_lines_completed = -1; + if( !IS_X264_TYPE_I( h->fenc->i_type ) ) { int valid_refs_left = 0; @@ -3126,7 +3196,7 @@ static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current, { char psz_message[80]; - if( h->b_thread_active ) + if( !h->param.b_sliced_threads && h->b_thread_active ) { h->b_thread_active = 0; if( (intptr_t)x264_threadpool_wait( h->threadpool, h ) ) @@ -3396,6 +3466,8 @@ void x264_encoder_close ( x264_t *h ) x264_lookahead_delete( h ); + if( h->param.b_sliced_threads ) + x264_threadpool_wait_all( h ); if( h->param.i_threads > 1 ) x264_threadpool_delete( h->threadpool ); if( h->i_thread_frames > 1 ) @@ -3691,7 +3763,7 @@ void x264_encoder_close ( x264_t *h ) x264_free( h->nal_buffer ); x264_analyse_free_costs( h ); - if( h->i_thread_frames > 1) + if( h->i_thread_frames > 1 ) h = h->thread[h->i_thread_phase]; /* frames */ @@ -3733,7 +3805,9 @@ void x264_encoder_close ( x264_t *h ) } x264_macroblock_thread_free( h->thread[i], 0 ); x264_free( h->thread[i]->out.p_bitstream ); - x264_free( h->thread[i]->out.nal); + 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] ); } } From 575c11ad1b42d0470975ef91f9eac24b9732e6b0 Mon Sep 17 00:00:00 2001 From: Anton Mitrofanov Date: Sun, 11 Mar 2012 23:08:18 -0700 Subject: [PATCH 72/81] Fix clobbering of mutex/cvs Regression in r2183. Bizarrely seemed to work on many platforms, but crashed on win64 and may have been slower. Only affected sliced threads during encoding, but could cause crashes on x264 encoder close even without sliced threads. --- encoder/encoder.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/encoder/encoder.c b/encoder/encoder.c index f00455c4..3a5701ee 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -1279,18 +1279,8 @@ x264_t *x264_encoder_open( x264_param_t *param ) goto fail; h->thread[0] = h; - for( int i = 0; i < h->param.i_threads + !!h->param.i_sync_lookahead; i++ ) - { - if( i ) - CHECKED_MALLOC( h->thread[i], sizeof(x264_t) ); - if( i < h->param.i_threads ) - { - if( x264_pthread_mutex_init( &h->thread[i]->mutex, NULL ) ) - goto fail; - if( x264_pthread_cond_init( &h->thread[i]->cv, NULL ) ) - goto fail; - } - } + for( int i = 1; i < h->param.i_threads + !!h->param.i_sync_lookahead; i++ ) + CHECKED_MALLOC( h->thread[i], sizeof(x264_t) ); for( int i = 0; i < h->param.i_threads; i++ ) { @@ -1299,6 +1289,11 @@ x264_t *x264_encoder_open( x264_param_t *param ) if( i > 0 ) *h->thread[i] = *h; + if( x264_pthread_mutex_init( &h->thread[i]->mutex, NULL ) ) + goto fail; + if( x264_pthread_cond_init( &h->thread[i]->cv, NULL ) ) + goto fail; + if( allocate_threadlocal_data ) { h->thread[i]->fdec = x264_frame_pop_unused( h, 1 ); From 21fed518c115579178ca448abcde76e1f9e6209f Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Tue, 27 Mar 2012 17:44:27 +0100 Subject: [PATCH 73/81] Move the pir_offset code back to its original place. --- encoder/encoder.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/encoder/encoder.c b/encoder/encoder.c index 2f6718c9..16653f25 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -3137,6 +3137,9 @@ int x264_encoder_encode( x264_t *h, if( h->param.sc.i_buffer_size ) x264_speedcontrol_frame( h ); + if( h->fenc->b_keyframe && h->param.b_intra_refresh ) + h->i_cpb_delay_pir_offset_next = h->fenc->i_cpb_delay; + /* Init the rate control */ /* FIXME: Include slice header bit cost. */ x264_ratecontrol_start( h, h->fenc->i_qpplus1, overhead*8 ); @@ -3262,9 +3265,6 @@ static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current, if( x264_ratecontrol_end( h, frame_size * 8, &filler ) < 0 ) return -1; - if( h->fenc->b_keyframe && h->param.b_intra_refresh ) - h->i_cpb_delay_pir_offset_next = h->fenc->i_cpb_delay; - pic_out->hrd_timing = h->fenc->hrd_timing; while( filler > 0 ) From 87c617d9ddb590394df8396e7524c9e013f44300 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Fri, 30 Mar 2012 16:10:18 +0100 Subject: [PATCH 74/81] Turn down verbosity of speedcontrol --- encoder/speed.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encoder/speed.c b/encoder/speed.c index a449ddd2..5a4b3703 100644 --- a/encoder/speed.c +++ b/encoder/speed.c @@ -197,7 +197,7 @@ void x264_speedcontrol_frame( x264_t *h ) idle_t += sc->buffer_fill - sc->buffer_size; if( t - print_interval > 1e6 ) { - x264_log( h, X264_LOG_INFO, "speedcontrol idle (%.6f sec)\n", idle_t/1e6 ); + x264_log( h, X264_LOG_DEBUG, "speedcontrol idle (%.6f sec)\n", idle_t/1e6 ); print_interval = t; idle_t = 0; } From 40b8756bfa024b9357b9f6fcca31cd429c20daa2 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Fri, 30 Mar 2012 16:50:13 +0100 Subject: [PATCH 75/81] Add ability to signal to x264 when speedcontrol buffering is complete --- common/common.h | 1 + encoder/encoder.c | 2 ++ encoder/speed.c | 19 +++++++++++-------- x264.h | 5 +++-- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/common/common.h b/common/common.h index 9e938fe4..cf338c23 100644 --- a/common/common.h +++ b/common/common.h @@ -81,6 +81,7 @@ do {\ #define NALU_OVERHEAD 5 // startcode + NAL type costs 5 bytes per frame #define FILLER_OVERHEAD (NALU_OVERHEAD+1) +#define SC_PRESETS 13 /**************************************************************************** * Includes ****************************************************************************/ diff --git a/encoder/encoder.c b/encoder/encoder.c index 16653f25..8b4a03a8 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -939,6 +939,8 @@ static int x264_validate_parameters( x264_t *h, int b_open ) h->param.i_nal_hrd = h->param.i_nal_hrd == X264_NAL_HRD_CBR ? X264_NAL_HRD_VBR : X264_NAL_HRD_FAKE_CBR; } + h->param.sc.max_preset = x264_clip3( h->param.sc.max_preset, 1, SC_PRESETS ); + /* ensure the booleans are 0 or 1 so they can be used in math */ #define BOOLIFY(x) h->param.x = !!h->param.x BOOLIFY( b_cabac ); diff --git a/encoder/speed.c b/encoder/speed.c index 5a4b3703..faade8e6 100644 --- a/encoder/speed.c +++ b/encoder/speed.c @@ -21,6 +21,7 @@ struct x264_speedcontrol_t float dither; int first; + int buffer_complete; struct { @@ -54,6 +55,7 @@ void x264_speedcontrol_new( x264_t *h ) sc->stat.min_buffer = sc->buffer_size; sc->stat.max_buffer = 0; sc->first = 1; + sc->buffer_complete = 0; } void x264_speedcontrol_delete( x264_t *h ) @@ -97,8 +99,7 @@ typedef struct float psy_trellis; } sc_preset_t; -#define PRESETS 10 -static const sc_preset_t presets[PRESETS] = +static const sc_preset_t presets[SC_PRESETS] = { #define I4 X264_ANALYSE_I4x4 #define I8 X264_ANALYSE_I8x8 @@ -122,7 +123,7 @@ static const sc_preset_t presets[PRESETS] = static void apply_preset( x264_t *h, int preset ) { x264_speedcontrol_t *sc = h->sc; - preset = x264_clip3( preset, 0, PRESETS-1 ); + preset = x264_clip3( preset, 0, h->param.sc.max_preset-1 ); //if( preset != sc->preset ) { const sc_preset_t *s = &presets[preset]; @@ -170,7 +171,8 @@ void x264_speedcontrol_frame( x264_t *h ) delta_f = h->i_frame - sc->prev_frame; delta_t = t - sc->timestamp; delta_buffer = delta_f * sc->spf / h->param.sc.f_speed - delta_t; - sc->buffer_fill += delta_buffer; + if( !sc->buffer_complete ) + sc->buffer_fill += delta_buffer; sc->prev_frame = h->i_frame; sc->timestamp = t; @@ -225,16 +227,16 @@ void x264_speedcontrol_frame( x264_t *h ) for( i=1;; i++ ) { t1 = presets[i].time * cplx; - if( t1 >= target || i == PRESETS-1 ) + if( t1 >= target || i == h->param.sc.max_preset-1 ) break; t0 = t1; } // linear interpolation between states set = i-1 + (target - t0) / (t1 - t0); - // Even if our time estimations in the PRESETS array are off + // Even if our time estimations in the SC_PRESETS array are off // this will push us towards our target fullness set += (20 * (filled-0.75)); - set = x264_clip3f(set,0,PRESETS-1); + set = x264_clip3f( set, 0 , h->param.sc.max_preset-1 ); apply_preset( h, dither( sc, set ) ); // FIXME @@ -254,7 +256,7 @@ void x264_speedcontrol_frame( x264_t *h ) } -void x264_speedcontrol_sync( x264_t *h, float f_buffer_fill, int i_buffer_size ) +void x264_speedcontrol_sync( x264_t *h, float f_buffer_fill, int i_buffer_size, int buffer_complete ) { x264_speedcontrol_t *sc = h->sc; if( !h->param.sc.i_buffer_size ) @@ -263,4 +265,5 @@ void x264_speedcontrol_sync( x264_t *h, float f_buffer_fill, int i_buffer_size ) h->param.sc.i_buffer_size = X264_MAX( 3, h->param.sc.i_buffer_size ); sc->buffer_size = h->param.sc.i_buffer_size * 1e6 / sc->fps; sc->buffer_fill = sc->buffer_size * f_buffer_fill; + sc->buffer_complete = !!buffer_complete; } diff --git a/x264.h b/x264.h index 2af0bdd3..1db27039 100644 --- a/x264.h +++ b/x264.h @@ -423,7 +423,8 @@ typedef struct x264_param_t float f_speed; /* ratio from realtime */ int i_buffer_size; /* number of frames */ float f_buffer_init; /* fraction of size */ - int b_alt_timer; /* use a different method of measuring encode time FIXME */ + int b_alt_timer; /* use a different method of measuring encode time */ + int max_preset; /* maximum speedcontrol preset to use */ } sc; /* Muxing parameters */ @@ -866,7 +867,7 @@ int x264_encoder_invalidate_reference( x264_t *, int64_t pts ); /* x264_speedcontrol_sync: * override speedcontrol's internal clock */ -void x264_speedcontrol_sync( x264_t *, float f_buffer_fill, int i_buffer_size ); +void x264_speedcontrol_sync( x264_t *, float f_buffer_fill, int i_buffer_size, int buffer_complete ); #endif From 6e14252fe4214763433f198631c5f63b8f871c61 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Fri, 30 Mar 2012 17:48:30 +0100 Subject: [PATCH 76/81] Set the default number of presets to be used to the maximum --- common/common.c | 1 + x264.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/common/common.c b/common/common.c index f53af5c3..c5fcaa50 100644 --- a/common/common.c +++ b/common/common.c @@ -123,6 +123,7 @@ void x264_param_default( x264_param_t *param ) param->sc.f_speed = 0; param->sc.i_buffer_size = 12; param->sc.f_buffer_init = 0.75; + param->sc.max_preset = SC_PRESETS; /* Log */ param->pf_log = x264_log_default; diff --git a/x264.h b/x264.h index 1db27039..21c8c648 100644 --- a/x264.h +++ b/x264.h @@ -424,7 +424,7 @@ typedef struct x264_param_t int i_buffer_size; /* number of frames */ float f_buffer_init; /* fraction of size */ int b_alt_timer; /* use a different method of measuring encode time */ - int max_preset; /* maximum speedcontrol preset to use */ + int max_preset; /* maximum number of speedcontrol presets to use */ } sc; /* Muxing parameters */ From 0f8a002924c128479f695493ecdf97f88f72a3db Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Fri, 1 Mar 2013 21:07:37 +0000 Subject: [PATCH 77/81] Revert "Pre-place keyframes to fix long stalls when PB... becomes IP... and a new path" This reverts commit 168a2afbf68551cb34ce1a2c53490dfeb12cbb69. Conflicts: encoder/slicetype.c --- encoder/slicetype.c | 112 +++++++++++++++----------------------------- 1 file changed, 38 insertions(+), 74 deletions(-) diff --git a/encoder/slicetype.c b/encoder/slicetype.c index b933c9e0..9bd862de 100644 --- a/encoder/slicetype.c +++ b/encoder/slicetype.c @@ -1313,7 +1313,7 @@ void x264_slicetype_analyse( x264_t *h, int keyframe ) if( !h->lookahead->last_nonb ) return; frames[0] = h->lookahead->last_nonb; - for( framecnt = 0; framecnt < i_max_search; framecnt++ ) + for( framecnt = 0; framecnt < i_max_search && h->lookahead->next.list[framecnt]->i_type == X264_TYPE_AUTO; framecnt++ ) frames[framecnt+1] = h->lookahead->next.list[framecnt]; x264_lowres_context_init( h, &a ); @@ -1345,7 +1345,7 @@ void x264_slicetype_analyse( x264_t *h, int keyframe ) int num_bframes = 0; int num_analysed_frames = num_frames; int reset_start; - if( h->param.i_scenecut_threshold && !IS_INTRA( frames[1]->i_type ) && scenecut( h, &a, frames, 0, 1, 1, orig_num_frames, i_max_search ) ) + if( h->param.i_scenecut_threshold && scenecut( h, &a, frames, 0, 1, 1, orig_num_frames, i_max_search ) ) { frames[1]->i_type = X264_TYPE_I; return; @@ -1369,25 +1369,12 @@ void x264_slicetype_analyse( x264_t *h, int keyframe ) for( int j = 1; j < num_frames; j++ ) frames[j]->i_type = best_paths[best_path_index][j-1] == 'B' ? X264_TYPE_B : X264_TYPE_P; } - if( !frames[num_frames]->b_keyframe ) - frames[num_frames]->i_type = X264_TYPE_P; + frames[num_frames]->i_type = X264_TYPE_P; } else if( h->param.i_bframe_adaptive == X264_B_ADAPT_FAST ) { for( int i = 0; i <= num_frames-2; ) { - if( frames[i+1]->b_keyframe ) - { - i++; - continue; - } - - if( frames[i+2]->b_keyframe ) - { - frames[i+1]->i_type = X264_TYPE_B; - i += 2; - continue; - } cost2p1 = x264_slicetype_frame_cost( h, &a, frames, i+0, i+2, i+2, 1 ); if( frames[i+2]->i_intra_mbs[2] > i_mb_count / 2 ) { @@ -1416,20 +1403,16 @@ void x264_slicetype_analyse( x264_t *h, int keyframe ) int j; for( j = i+2; j <= X264_MIN( i+h->param.i_bframe, num_frames-1 ); j++ ) { - if( frames[j]->b_keyframe ) - break; int pthresh = X264_MAX(INTER_THRESH - P_SENS_BIAS * (j-i-1), INTER_THRESH/10); int pcost = x264_slicetype_frame_cost( h, &a, frames, i+0, j+1, j+1, 1 ); if( pcost > pthresh*i_mb_count || frames[j+1]->i_intra_mbs[j-i+1] > i_mb_count/3 ) break; frames[j]->i_type = X264_TYPE_B; } - if( !frames[j]->b_keyframe ) - frames[j]->i_type = X264_TYPE_P; + frames[j]->i_type = X264_TYPE_P; i = j; } - if( !frames[num_frames]->b_keyframe ) - frames[num_frames]->i_type = X264_TYPE_P; + frames[num_frames]->i_type = X264_TYPE_P; num_bframes = 0; while( num_bframes < num_frames && frames[num_bframes+1]->i_type == X264_TYPE_B ) num_bframes++; @@ -1438,12 +1421,8 @@ void x264_slicetype_analyse( x264_t *h, int keyframe ) { num_bframes = X264_MIN(num_frames-1, h->param.i_bframe); for( int j = 1; j < num_frames; j++ ) - { - if( !frames[j]->b_keyframe ) - frames[j]->i_type = (j%(num_bframes+1)) ? X264_TYPE_B : X264_TYPE_P; - } - if( !frames[num_frames]->b_keyframe ) - frames[num_frames]->i_type = X264_TYPE_P; + frames[j]->i_type = (j%(num_bframes+1)) ? X264_TYPE_B : X264_TYPE_P; + frames[num_frames]->i_type = X264_TYPE_P; } /* Check scenecut on the first minigop. */ @@ -1460,10 +1439,7 @@ void x264_slicetype_analyse( x264_t *h, int keyframe ) else { for( int j = 1; j <= num_frames; j++ ) - { - if( !frames[j]->b_keyframe ) - frames[j]->i_type = X264_TYPE_P; - } + frames[j]->i_type = X264_TYPE_P; reset_start = !keyframe + 1; num_bframes = 0; } @@ -1473,7 +1449,6 @@ void x264_slicetype_analyse( x264_t *h, int keyframe ) if( h->param.rc.b_mb_tree ) x264_macroblock_tree( h, &a, frames, X264_MIN(num_frames, h->param.i_keyint_max), keyframe ); -#if 0 /* Enforce keyframe limit. */ if( !h->param.b_intra_refresh ) for( int i = keyint_limit+1; i <= num_frames; i += h->param.i_keyint_max ) @@ -1484,17 +1459,13 @@ void x264_slicetype_analyse( x264_t *h, int keyframe ) while( IS_X264_TYPE_B( frames[i-1]->i_type ) ) i--; } -#endif if( vbv_lookahead ) x264_vbv_lookahead( h, &a, frames, num_frames, keyframe ); - /* Restore non-keyint frametypes for all frames that haven't actually been decided yet. */ + /* Restore frametypes for all frames that haven't actually been decided yet. */ for( int j = reset_start; j <= num_frames; j++ ) - { - if( !frames[j]->b_keyframe ) - frames[j]->i_type = X264_TYPE_AUTO; - } + frames[j]->i_type = X264_TYPE_AUTO; } void x264_slicetype_decide( x264_t *h ) @@ -1545,10 +1516,32 @@ void x264_slicetype_decide( x264_t *h ) h->lookahead->next.list[i]->i_type = x264_ratecontrol_slice_type( h, h->lookahead->next.list[i]->i_frame ); } + else if( (h->param.i_bframe && h->param.i_bframe_adaptive) + || h->param.i_scenecut_threshold + || h->param.rc.b_mb_tree + || (h->param.rc.i_vbv_buffer_size && h->param.rc.i_lookahead) ) + x264_slicetype_analyse( h, 0 ); - for( int i = 0; i < h->lookahead->next.i_size; i++ ) + for( bframes = 0, brefs = 0;; bframes++ ) { - frm = h->lookahead->next.list[i]; + frm = h->lookahead->next.list[bframes]; + if( frm->i_type == X264_TYPE_BREF && h->param.i_bframe_pyramid < X264_B_PYRAMID_NORMAL && + brefs == h->param.i_bframe_pyramid ) + { + frm->i_type = X264_TYPE_B; + x264_log( h, X264_LOG_WARNING, "B-ref at frame %d incompatible with B-pyramid %s \n", + frm->i_frame, x264_b_pyramid_names[h->param.i_bframe_pyramid] ); + } + /* pyramid with multiple B-refs needs a big enough dpb that the preceding P-frame stays available. + smaller dpb could be supported by smart enough use of mmco, but it's easier just to forbid it. */ + else if( frm->i_type == X264_TYPE_BREF && h->param.i_bframe_pyramid == X264_B_PYRAMID_NORMAL && + brefs && h->param.i_frame_reference <= (brefs+3) ) + { + frm->i_type = X264_TYPE_B; + x264_log( h, X264_LOG_WARNING, "B-ref at frame %d incompatible with B-pyramid %s and %d reference frames\n", + frm->i_frame, x264_b_pyramid_names[h->param.i_bframe_pyramid], h->param.i_frame_reference ); + } + if( frm->i_type == X264_TYPE_KEYFRAME ) frm->i_type = h->param.b_open_gop ? X264_TYPE_I : X264_TYPE_IDR; @@ -1563,12 +1556,13 @@ void x264_slicetype_decide( x264_t *h ) if( warn ) x264_log( h, X264_LOG_WARNING, "specified frame type (%d) at %d is not compatible with keyframe interval\n", frm->i_type, frm->i_frame ); } - if( frm->i_type == X264_TYPE_I && frm->i_frame - h->lookahead->i_last_keyframe >= h->param.i_keyint_min ) { if( h->param.b_open_gop ) { h->lookahead->i_last_keyframe = frm->i_frame; // Use display order + if( h->param.b_bluray_compat ) + h->lookahead->i_last_keyframe -= bframes; // Use bluray order frm->b_keyframe = 1; } else @@ -1579,37 +1573,6 @@ void x264_slicetype_decide( x264_t *h ) /* Close GOP */ h->lookahead->i_last_keyframe = frm->i_frame; frm->b_keyframe = 1; - } - } - - if( !h->param.rc.b_stat_read && ((h->param.i_bframe && h->param.i_bframe_adaptive) - || h->param.i_scenecut_threshold - || h->param.rc.b_mb_tree - || (h->param.rc.i_vbv_buffer_size && h->param.rc.i_lookahead)) ) - x264_slicetype_analyse( h, 0 ); - - for( bframes = 0, brefs = 0;; bframes++ ) - { - frm = h->lookahead->next.list[bframes]; - if( frm->i_type == X264_TYPE_BREF && h->param.i_bframe_pyramid < X264_B_PYRAMID_NORMAL && - brefs == h->param.i_bframe_pyramid ) - { - frm->i_type = X264_TYPE_B; - x264_log( h, X264_LOG_WARNING, "B-ref at frame %d incompatible with B-pyramid %s \n", - frm->i_frame, x264_b_pyramid_names[h->param.i_bframe_pyramid] ); - } - /* pyramid with multiple B-refs needs a big enough dpb that the preceding P-frame stays available. - smaller dpb could be supported by smart enough use of mmco, but it's easier just to forbid it. */ - else if( frm->i_type == X264_TYPE_BREF && h->param.i_bframe_pyramid == X264_B_PYRAMID_NORMAL && - brefs && h->param.i_frame_reference <= (brefs+3) ) - { - frm->i_type = X264_TYPE_B; - x264_log( h, X264_LOG_WARNING, "B-ref at frame %d incompatible with B-pyramid %s and %d reference frames\n", - frm->i_frame, x264_b_pyramid_names[h->param.i_bframe_pyramid], h->param.i_frame_reference ); - } - - if( frm->i_type == X264_TYPE_IDR ) - { if( bframes > 0 ) { bframes--; @@ -1617,7 +1580,8 @@ void x264_slicetype_decide( x264_t *h ) } } - if( bframes == h->param.i_bframe || !h->lookahead->next.list[bframes+1] ) + if( bframes == h->param.i_bframe || + !h->lookahead->next.list[bframes+1] ) { if( IS_X264_TYPE_B( frm->i_type ) ) x264_log( h, X264_LOG_WARNING, "specified frame type is not compatible with max B-frames\n" ); From e2eec40a62d8eb2c3fdf168f3ff68eef82faab0b Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Fri, 1 Mar 2013 21:34:47 +0000 Subject: [PATCH 78/81] Merge x264 git --- Makefile | 4 +- common/arm/asm.S | 2 +- common/arm/cpu-a.S | 2 +- common/arm/dct-a.S | 2 +- common/arm/dct.h | 2 +- common/arm/deblock-a.S | 2 +- common/arm/mc-a.S | 399 ++++++---- common/arm/mc-c.c | 4 +- common/arm/mc.h | 2 +- common/arm/pixel-a.S | 18 +- common/arm/pixel.h | 2 +- common/arm/predict-a.S | 2 +- common/arm/predict-c.c | 2 +- common/arm/predict.h | 2 +- common/arm/quant-a.S | 53 +- common/arm/quant.h | 3 +- common/bitstream.c | 2 +- common/bitstream.h | 2 +- common/cabac.c | 2 +- common/cabac.h | 2 +- common/common.c | 29 +- common/common.h | 54 +- common/cpu.c | 114 +-- common/cpu.h | 3 +- common/dct.c | 44 +- common/dct.h | 2 +- common/deblock.c | 46 +- common/display-x11.c | 6 +- common/display.h | 2 +- common/frame.c | 23 +- common/frame.h | 8 +- common/macroblock.c | 6 +- common/macroblock.h | 18 +- common/mc.c | 2 +- common/mc.h | 2 +- common/mvpred.c | 2 +- common/osdep.c | 17 +- common/osdep.h | 17 +- common/pixel.c | 78 +- common/pixel.h | 4 +- common/ppc/dct.c | 2 +- common/ppc/dct.h | 2 +- common/ppc/deblock.c | 2 +- common/ppc/mc.c | 2 +- common/ppc/mc.h | 2 +- common/ppc/pixel.c | 2 +- common/ppc/pixel.h | 2 +- common/ppc/ppccommon.h | 2 +- common/ppc/predict.c | 2 +- common/ppc/predict.h | 2 +- common/ppc/quant.c | 2 +- common/ppc/quant.h | 2 +- common/predict.c | 2 +- common/predict.h | 2 +- common/quant.c | 23 +- common/quant.h | 7 +- common/rectangle.c | 2 +- common/rectangle.h | 2 +- common/set.c | 4 +- common/set.h | 3 +- common/sparc/pixel.asm | 2 +- common/sparc/pixel.h | 2 +- common/threadpool.c | 9 +- common/threadpool.h | 2 +- common/visualize.c | 2 +- common/visualize.h | 2 +- common/vlc.c | 2 +- common/win32thread.c | 10 +- common/win32thread.h | 3 +- common/x86/bitstream-a.asm | 2 +- common/x86/cabac-a.asm | 70 +- common/x86/const-a.asm | 2 +- common/x86/cpu-a.asm | 52 +- common/x86/dct-32.asm | 2 +- common/x86/dct-64.asm | 2 +- common/x86/dct-a.asm | 8 +- common/x86/dct.h | 2 +- common/x86/deblock-a.asm | 83 +- common/x86/mc-a.asm | 54 +- common/x86/mc-a2.asm | 167 ++-- common/x86/mc-c.c | 170 ++-- common/x86/mc.h | 2 +- common/x86/pixel-32.asm | 2 +- common/x86/pixel-a.asm | 501 +++++++++--- common/x86/pixel.h | 14 +- common/x86/predict-a.asm | 52 +- common/x86/predict-c.c | 32 +- common/x86/predict.h | 10 +- common/x86/quant-a.asm | 113 ++- common/x86/quant.h | 6 +- common/x86/sad-a.asm | 2 +- common/x86/sad16-a.asm | 2 +- common/x86/trellis-64.asm | 2 +- common/x86/util.h | 154 +++- common/x86/x86inc.asm | 637 +++++++++++---- common/x86/x86util.asm | 40 +- config.guess | 299 ++++--- config.sub | 242 ++++-- configure | 94 ++- doc/regression_test.txt | 2 +- encoder/analyse.c | 88 ++- encoder/analyse.h | 4 +- encoder/cabac.c | 23 +- encoder/cavlc.c | 35 +- encoder/encoder.c | 164 +++- encoder/lookahead.c | 15 +- encoder/macroblock.c | 377 +++++---- encoder/macroblock.h | 6 +- encoder/me.c | 297 ++++--- encoder/me.h | 2 +- encoder/ratecontrol.c | 233 +++++- encoder/ratecontrol.h | 2 +- encoder/rdo.c | 3 +- encoder/set.c | 49 +- encoder/set.h | 2 +- encoder/slicetype.c | 258 +++++-- extras/avxsynth_c.h | 727 ++++++++++++++++++ .../windowsPorts/basicDataTypeConversions.h | 85 ++ extras/windowsPorts/windows2linux.h | 77 ++ filters/filters.c | 2 +- filters/filters.h | 2 +- filters/video/cache.c | 2 +- filters/video/crop.c | 2 +- filters/video/depth.c | 33 +- filters/video/fix_vfr_pts.c | 2 +- filters/video/internal.c | 2 +- filters/video/internal.h | 2 +- filters/video/resize.c | 2 +- filters/video/select_every.c | 2 +- filters/video/source.c | 2 +- filters/video/video.c | 2 +- filters/video/video.h | 2 +- input/avs.c | 53 +- input/ffms.c | 2 +- input/input.c | 2 +- input/input.h | 2 +- input/lavf.c | 33 +- input/raw.c | 2 +- input/thread.c | 2 +- input/timecode.c | 2 +- input/y4m.c | 58 +- output/flv.c | 2 +- output/flv_bytestream.c | 2 +- output/flv_bytestream.h | 2 +- output/matroska.c | 2 +- output/matroska_ebml.c | 2 +- output/matroska_ebml.h | 2 +- output/mp4.c | 6 +- output/output.h | 2 +- output/raw.c | 2 +- tools/checkasm-a.asm | 4 +- tools/checkasm.c | 150 ++-- x264.c | 13 +- x264.h | 172 +++-- x264cli.h | 2 +- x264dll.c | 2 +- x264res.rc | 4 +- 157 files changed, 5040 insertions(+), 1898 deletions(-) mode change 100755 => 100644 configure create mode 100644 extras/avxsynth_c.h create mode 100644 extras/windowsPorts/basicDataTypeConversions.h create mode 100644 extras/windowsPorts/windows2linux.h diff --git a/Makefile b/Makefile index 547ee120..e8fa9389 100644 --- a/Makefile +++ b/Makefile @@ -187,10 +187,10 @@ $(OBJS) $(OBJASM) $(OBJSO) $(OBJCLI) $(OBJCHK): .depend -@ $(if $(STRIP), $(STRIP) -x $@) # delete local/anonymous symbols, so they don't show up in oprofile %.dll.o: %.rc x264.h - $(RC)$@ -DDLL $< + $(RC) $(RCFLAGS)$@ -DDLL $< %.o: %.rc x264.h - $(RC)$@ $< + $(RC) $(RCFLAGS)$@ $< .depend: config.mak @rm -f .depend diff --git a/common/arm/asm.S b/common/arm/asm.S index 310c9813..053328a0 100644 --- a/common/arm/asm.S +++ b/common/arm/asm.S @@ -1,7 +1,7 @@ /***************************************************************************** * asm.S: arm utility macros ***************************************************************************** - * Copyright (C) 2008-2012 x264 project + * Copyright (C) 2008-2013 x264 project * * Authors: Mans Rullgard * David Conrad diff --git a/common/arm/cpu-a.S b/common/arm/cpu-a.S index a4595530..7a392908 100644 --- a/common/arm/cpu-a.S +++ b/common/arm/cpu-a.S @@ -1,7 +1,7 @@ /***************************************************************************** * cpu-a.S: arm cpu detection ***************************************************************************** - * Copyright (C) 2009-2012 x264 project + * Copyright (C) 2009-2013 x264 project * * Authors: David Conrad * diff --git a/common/arm/dct-a.S b/common/arm/dct-a.S index 86cc2ed3..1b188e91 100644 --- a/common/arm/dct-a.S +++ b/common/arm/dct-a.S @@ -1,7 +1,7 @@ /**************************************************************************** * dct-a.S: arm transform and zigzag ***************************************************************************** - * Copyright (C) 2009-2012 x264 project + * Copyright (C) 2009-2013 x264 project * * Authors: David Conrad * diff --git a/common/arm/dct.h b/common/arm/dct.h index 912e32b8..4defc32a 100644 --- a/common/arm/dct.h +++ b/common/arm/dct.h @@ -1,7 +1,7 @@ /***************************************************************************** * dct.h: arm transform and zigzag ***************************************************************************** - * Copyright (C) 2009-2012 x264 project + * Copyright (C) 2009-2013 x264 project * * Authors: David Conrad * diff --git a/common/arm/deblock-a.S b/common/arm/deblock-a.S index 9c505f69..f0e7f4d0 100644 --- a/common/arm/deblock-a.S +++ b/common/arm/deblock-a.S @@ -1,7 +1,7 @@ /***************************************************************************** * deblock.S: arm deblocking ***************************************************************************** - * Copyright (C) 2009-2012 x264 project + * Copyright (C) 2009-2013 x264 project * * Authors: Mans Rullgard * diff --git a/common/arm/mc-a.S b/common/arm/mc-a.S index 507bbba1..8a37e957 100644 --- a/common/arm/mc-a.S +++ b/common/arm/mc-a.S @@ -1,10 +1,11 @@ /***************************************************************************** * mc.S: arm motion compensation ***************************************************************************** - * Copyright (C) 2009-2012 x264 project + * Copyright (C) 2009-2013 x264 project * * Authors: David Conrad * Mans Rullgard + * Stefan Groenroos * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -813,54 +814,57 @@ copy_w16_aligned_loop: // void x264_mc_chroma_neon( uint8_t *dst, intptr_t i_dst_stride, // uint8_t *src, intptr_t i_src_stride, // int dx, int dy, int i_width, int i_height ); + function x264_mc_chroma_neon - push {r4-r6, lr} - ldrd r4, [sp, #16] - ldr r6, [sp, #24] + push {r4-r8, lr} + vpush {d8-d11} + ldrd r4, [sp, #56] + ldrd r6, [sp, #64] - asr lr, r5, #3 - mul lr, r3, lr - add r2, r2, r4, asr #3 - cmp r6, #4 - add r2, r2, lr + asr lr, r6, #3 + mul lr, r4, lr + add r3, r3, r5, asr #2 + cmp r7, #4 - and r4, r4, #7 and r5, r5, #7 - pld [r2] - pld [r2, r3] + and r6, r6, #7 + + add r3, r3, lr + bic r3, r3, #0x1 + + pld [r3] + pld [r3, r4] bgt mc_chroma_w8 beq mc_chroma_w4 -// calculate cA cB cC cD -.macro CHROMA_MC_START r0 r1 - muls lr, r4, r5 - rsb r6, lr, r5, lsl #3 - rsb ip, lr, r4, lsl #3 - sub r4, lr, r4, lsl #3 - sub r4, r4, r5, lsl #3 - add r4, r4, #64 +.macro CHROMA_MC_START r00, r01, r10, r11 + muls lr, r5, r6 + rsb r7, lr, r6, lsl #3 + rsb ip, lr, r5, lsl #3 + sub r5, lr, r5, lsl #3 + sub r5, r5, r6, lsl #3 + add r5, r5, #64 beq 2f + vld2.8 {\r00-\r01}, [r3], r4 - add r5, r2, r3 + vdup.8 d0, r5 + vdup.8 d1, ip - vdup.8 d0, r4 - lsl r3, r3, #1 - vdup.8 d1, ip - vld1.64 {\r0}, [r2], r3 - vdup.8 d2, r6 - vld1.64 {\r1}, [r5], r3 - vdup.8 d3, lr - ldr r4, [sp, #28] - - vext.8 d5, d4, d5, #1 - vext.8 d7, d6, d7, #1 + vdup.8 d2, r7 + vld2.8 {\r10-\r11}, [r3], r4 + vdup.8 d3, lr + ldr r5, [sp, #72] .endm .macro CHROMA_MC width, align mc_chroma_w\width: - CHROMA_MC_START d4, d6 + CHROMA_MC_START d4, d5, d8, d9 + vext.8 d6, d4, d6, #1 + vext.8 d7, d5, d7, #1 + vext.8 d10, d8, d10, #1 + vext.8 d11, d9, d11, #1 // since the element size varies, there's a different index for the 2nd store .if \width == 4 .set st2, 1 @@ -868,187 +872,292 @@ mc_chroma_w\width: .set st2, 2 .endif - vtrn.32 d4, d5 - vtrn.32 d6, d7 + vtrn.32 d4, d6 + vtrn.32 d5, d7 + vtrn.32 d8, d10 + vtrn.32 d9, d11 - vtrn.32 d0, d1 - vtrn.32 d2, d3 + vtrn.32 d0, d1 + vtrn.32 d2, d3 1: // height loop, interpolate xy - pld [r5] + vmull.u8 q8, d4, d0 - vmlal.u8 q8, d6, d2 - vld1.64 {d4}, [r2], r3 - vext.8 d5, d4, d5, #1 - vtrn.32 d4, d5 - vmull.u8 q9, d6, d0 - vmlal.u8 q9, d4, d2 - vld1.64 {d6}, [r5], r3 + vmlal.u8 q8, d8, d2 + vmull.u8 q9, d5, d0 + vmlal.u8 q9, d9, d2 + + vld2.8 {d4-d5}, [r3], r4 + + vext.8 d6, d4, d6, #1 + vext.8 d7, d5, d7, #1 + vadd.i16 d16, d16, d17 vadd.i16 d17, d18, d19 + + vtrn.32 d4, d6 + vtrn.32 d5, d7 + + vmull.u8 q10, d8, d0 + vmlal.u8 q10, d4, d2 + vmull.u8 q11, d9, d0 + vmlal.u8 q11, d5, d2 + + vld2.8 {d8-d9}, [r3], r4 + vrshrn.u16 d16, q8, #6 - subs r4, r4, #2 - pld [r2] - vext.8 d7, d6, d7, #1 - vtrn.32 d6, d7 - vst1.\align {d16[0]}, [r0,:\align], r1 - vst1.\align {d16[st2]}, [r0,:\align], r1 + + vext.8 d10, d8, d10, #1 + vext.8 d11, d9, d11, #1 + + vadd.i16 d18, d20, d21 + vadd.i16 d19, d22, d23 + + vtrn.32 d8, d10 + vtrn.32 d9, d11 + + vrshrn.u16 d18, q9, #6 + + subs r5, r5, #2 + + pld [r3] + pld [r3, r4] + + vst1.\align {d16[0]}, [r0,:\align], r2 + vst1.\align {d16[st2]}, [r1,:\align], r2 + vst1.\align {d18[0]}, [r0,:\align], r2 + vst1.\align {d18[st2]}, [r1,:\align], r2 bgt 1b - pop {r4-r6, pc} + vpop {d8-d11} + pop {r4-r8, pc} 2: // dx or dy are 0 - tst r6, r6 - add ip, ip, r6 - vdup.8 d0, r4 + tst r7, r7 + add ip, ip, r7 + vdup.8 d0, r5 + ldr r5, [sp, #72] vdup.8 d1, ip - vtrn.32 d0, d1 - ldr r4, [sp, #28] beq 4f - vext.32 d1, d0, d1, #1 - add r5, r2, r3 - lsl r3, r3, #1 - vld1.32 {d4[0]}, [r2], r3 - vld1.32 {d4[1]}, [r5], r3 + vld1.64 {d4}, [r3], r4 + vld1.64 {d6}, [r3], r4 3: // vertical interpolation loop - pld [r5] + vmull.u8 q8, d4, d0 - vld1.32 {d4[0]}, [r2], r3 - vmull.u8 q9, d4, d1 - vld1.32 {d4[1]}, [r5], r3 - vadd.i16 d16, d16, d17 - vadd.i16 d17, d18, d19 - vrshrn.u16 d16, q8, #6 - subs r4, r4, #2 - pld [r2] - vst1.\align {d16[0]}, [r0,:\align], r1 - vst1.\align {d16[st2]}, [r0,:\align], r1 + vmlal.u8 q8, d6, d1 + vmull.u8 q9, d6, d0 + vld1.64 {d4}, [r3], r4 + vmlal.u8 q9, d4, d1 + vld1.64 {d6}, [r3], r4 + + vrshrn.u16 d16, q8, #6 // uvuvuvuv + vrshrn.u16 d17, q9, #6 // uvuvuvuv + subs r5, r5, #2 + vuzp.8 d16, d17 // d16=uuuu|uuuu, d17=vvvv|vvvv + + pld [r3] + pld [r3, r4] + + vst1.\align {d16[0]}, [r0,:\align], r2 + vst1.\align {d16[st2]}, [r0,:\align], r2 + vst1.\align {d17[0]}, [r1,:\align], r2 + vst1.\align {d17[st2]}, [r1,:\align], r2 bgt 3b - pop {r4-r6, pc} + vpop {d8-d11} + pop {r4-r8, pc} 4: // dy is 0 - vld1.64 {d4}, [r2], r3 - vld1.64 {d6}, [r2], r3 - vext.8 d5, d4, d5, #1 - vext.8 d7, d6, d7, #1 - vtrn.32 d4, d5 - vtrn.32 d6, d7 + + vld1.64 {d4-d5}, [r3], r4 + vld1.64 {d6-d7}, [r3], r4 + + vext.8 d5, d4, d5, #2 + vext.8 d7, d6, d7, #2 5: // horizontal interpolation loop + vmull.u8 q8, d4, d0 + vmlal.u8 q8, d5, d1 vmull.u8 q9, d6, d0 - subs r4, r4, #2 - vld1.64 {d4}, [r2], r3 - vext.8 d5, d4, d5, #1 - vtrn.32 d4, d5 - vadd.i16 d16, d16, d17 - vadd.i16 d17, d18, d19 - pld [r2] + vmlal.u8 q9, d7, d1 + + subs r5, r5, #2 + vld1.64 {d4-d5}, [r3], r4 + vld1.64 {d6-d7}, [r3], r4 + vext.8 d5, d4, d5, #2 vrshrn.u16 d16, q8, #6 - vld1.64 {d6}, [r2], r3 - vext.8 d7, d6, d7, #1 - vtrn.32 d6, d7 - pld [r2] - vst1.\align {d16[0]}, [r0,:\align], r1 - vst1.\align {d16[st2]}, [r0,:\align], r1 + vrshrn.u16 d17, q9, #6 + vext.8 d7, d6, d7, #2 + vuzp.8 d16, d17 + + pld [r3] + pld [r3, r4] + + vst1.\align {d16[0]}, [r0,:\align], r2 + vst1.\align {d16[st2]}, [r0,:\align], r2 + vst1.\align {d17[0]}, [r1,:\align], r2 + vst1.\align {d17[st2]}, [r1,:\align], r2 bgt 5b - pop {r4-r6, pc} + vpop {d8-d11} + pop {r4-r8, pc} .endm - CHROMA_MC 2, 16 - CHROMA_MC 4, 32 + CHROMA_MC 2, 16 + CHROMA_MC 4, 32 -// the optimial timing for width 8 is different enough that it's not -// readable to put it in the same macro as width 2/4 mc_chroma_w8: - CHROMA_MC_START d4-d5, d6-d7 + CHROMA_MC_START d4, d7, d8, d11 + vext.8 d5, d4, d5, #1 + vext.8 d9, d8, d9, #1 + vext.8 d7, d6, d7, #1 + vext.8 d11, d10, d11, #1 1: // height loop, interpolate xy - pld [r5] vmull.u8 q8, d4, d0 vmlal.u8 q8, d5, d1 - vld1.64 {d4, d5}, [r2], r3 - vmlal.u8 q8, d6, d2 - vext.8 d5, d4, d5, #1 - vmlal.u8 q8, d7, d3 + vmlal.u8 q8, d8, d2 + vmlal.u8 q8, d9, d3 + vmull.u8 q9, d6, d0 - subs r4, r4, #2 vmlal.u8 q9, d7, d1 - vmlal.u8 q9, d4, d2 - vmlal.u8 q9, d5, d3 + vmlal.u8 q9, d10, d2 + vmlal.u8 q9, d11, d3 + + vld2.8 {d4-d7}, [r3], r4 + + vext.8 d5, d4, d5, #1 + vext.8 d7, d6, d7, #1 + + vmull.u8 q10, d8, d0 + vmlal.u8 q10, d9, d1 + vmlal.u8 q10, d4, d2 + vmlal.u8 q10, d5, d3 + + vmull.u8 q11, d10, d0 + vmlal.u8 q11, d11, d1 + vmlal.u8 q11, d6, d2 + vmlal.u8 q11, d7, d3 + + subs r5, r5, #2 + vld2.8 {d8-d11}, [r3], r4 + vrshrn.u16 d16, q8, #6 - vld1.64 {d6, d7}, [r5], r3 - pld [r2] vrshrn.u16 d17, q9, #6 - vext.8 d7, d6, d7, #1 - vst1.64 {d16}, [r0,:64], r1 - vst1.64 {d17}, [r0,:64], r1 + vrshrn.u16 d18, q10, #6 + vext.8 d9, d8, d9, #1 + vrshrn.u16 d19, q11, #6 + vext.8 d11, d10, d11, #1 + + pld [r3] + pld [r3, r4] + + vst1.64 {d16}, [r0,:64], r2 + vst1.64 {d17}, [r1,:64], r2 + vst1.64 {d18}, [r0,:64], r2 + vst1.64 {d19}, [r1,:64], r2 + bgt 1b - pop {r4-r6, pc} + vpop {d8-d11} + pop {r4-r8, pc} 2: // dx or dy are 0 - tst r6, r6 - add ip, ip, r6 - vdup.8 d0, r4 + tst r7, r7 + add ip, ip, r7 + vdup.8 d0, r5 + ldr r5, [sp, #72] vdup.8 d1, ip - ldr r4, [sp, #28] beq 4f - add r5, r2, r3 - lsl r3, r3, #1 - vld1.64 {d4}, [r2], r3 - vld1.64 {d6}, [r5], r3 + vld2.8 {d4-d5}, [r3], r4 + vld2.8 {d6-d7}, [r3], r4 3: // vertical interpolation loop - pld [r5] - vmull.u8 q8, d4, d0 + vmull.u8 q8, d4, d0 //U vmlal.u8 q8, d6, d1 - vld1.64 {d4}, [r2], r3 - vmull.u8 q9, d6, d0 - vmlal.u8 q9, d4, d1 - vld1.64 {d6}, [r5], r3 + vmull.u8 q9, d5, d0 //V + vmlal.u8 q9, d7, d1 + + vld2.8 {d4-d5}, [r3], r4 + + vmull.u8 q10, d6, d0 + vmlal.u8 q10, d4, d1 + vmull.u8 q11, d7, d0 + vmlal.u8 q11, d5, d1 + + vld2.8 {d6-d7}, [r3], r4 + vrshrn.u16 d16, q8, #6 vrshrn.u16 d17, q9, #6 - subs r4, r4, #2 - pld [r2] - vst1.64 {d16}, [r0,:64], r1 - vst1.64 {d17}, [r0,:64], r1 + vrshrn.u16 d18, q10, #6 + vrshrn.u16 d19, q11, #6 + subs r5, r5, #2 + + pld [r3] + pld [r3, r4] + + vst1.64 {d16}, [r0,:64], r2 + vst1.64 {d17}, [r1,:64], r2 + vst1.64 {d18}, [r0,:64], r2 + vst1.64 {d19}, [r1,:64], r2 + bgt 3b - pop {r4-r6, pc} + vpop {d8-d11} + pop {r4-r8, pc} 4: // dy is 0 - vld1.64 {d4, d5}, [r2], r3 - vld1.64 {d6, d7}, [r2], r3 + + vld2.8 {d4-d7}, [r3], r4 + vld2.8 {d8-d11}, [r3], r4 vext.8 d5, d4, d5, #1 vext.8 d7, d6, d7, #1 + vext.8 d9, d8, d9, #1 + vext.8 d11, d10, d11, #1 5: // horizontal interpolation loop - pld [r2] - subs r4, r4, #2 - vmull.u8 q8, d4, d0 + subs r5, r5, #2 + vmull.u8 q8, d4, d0 //U vmlal.u8 q8, d5, d1 - vld1.64 {d4, d5}, [r2], r3 - vmull.u8 q9, d6, d0 + vmull.u8 q9, d6, d0 //V vmlal.u8 q9, d7, d1 - pld [r2] + + vld2.8 {d4-d7}, [r3], r4 + + vmull.u8 q10, d8, d0 + vmlal.u8 q10, d9, d1 + vmull.u8 q11, d10, d0 + vmlal.u8 q11, d11, d1 + + vld2.8 {d8-d11}, [r3], r4 + vext.8 d5, d4, d5, #1 vrshrn.u16 d16, q8, #6 - vrshrn.u16 d17, q9, #6 - vld1.64 {d6, d7}, [r2], r3 vext.8 d7, d6, d7, #1 - vst1.64 {d16}, [r0,:64], r1 - vst1.64 {d17}, [r0,:64], r1 + vrshrn.u16 d17, q9, #6 + vext.8 d9, d8, d9, #1 + vrshrn.u16 d18, q10, #6 + vext.8 d11, d10, d11, #1 + vrshrn.u16 d19, q11, #6 + + pld [r3] + pld [r3, r4] + + vst1.64 {d16}, [r0,:64], r2 + vst1.64 {d17}, [r1,:64], r2 + vst1.64 {d18}, [r0,:64], r2 + vst1.64 {d19}, [r1,:64], r2 bgt 5b - pop {r4-r6, pc} + vpop {d8-d11} + pop {r4-r8, pc} + .endfunc diff --git a/common/arm/mc-c.c b/common/arm/mc-c.c index 1148ae76..2168120f 100644 --- a/common/arm/mc-c.c +++ b/common/arm/mc-c.c @@ -1,7 +1,7 @@ /***************************************************************************** * mc-c.c: arm motion compensation ***************************************************************************** - * Copyright (C) 2009-2012 x264 project + * Copyright (C) 2009-2013 x264 project * * Authors: David Conrad * @@ -238,7 +238,7 @@ void x264_mc_init_arm( int cpu, x264_mc_functions_t *pf ) pf->offsetsub = x264_mc_offsetsub_wtab_neon; pf->weight_cache = x264_weight_cache_neon; -// pf->mc_chroma = x264_mc_chroma_neon; + pf->mc_chroma = x264_mc_chroma_neon; pf->mc_luma = mc_luma_neon; pf->get_ref = get_ref_neon; pf->hpel_filter = hpel_filter_neon; diff --git a/common/arm/mc.h b/common/arm/mc.h index b988bc1b..8823a53d 100644 --- a/common/arm/mc.h +++ b/common/arm/mc.h @@ -1,7 +1,7 @@ /***************************************************************************** * mc.h: arm motion compensation ***************************************************************************** - * Copyright (C) 2009-2012 x264 project + * Copyright (C) 2009-2013 x264 project * * Authors: David Conrad * diff --git a/common/arm/pixel-a.S b/common/arm/pixel-a.S index 8bce3b68..7294ad0e 100644 --- a/common/arm/pixel-a.S +++ b/common/arm/pixel-a.S @@ -1,7 +1,7 @@ /***************************************************************************** * pixel.S: arm pixel metrics ***************************************************************************** - * Copyright (C) 2009-2012 x264 project + * Copyright (C) 2009-2013 x264 project * * Authors: David Conrad * @@ -68,45 +68,45 @@ SAD4_ARMV6 8 .macro SAD_START_4 align:vararg - vld1.32 {d1[]}, [r2 \align], r3 + vld1.32 {d1[]}, [r2\align], r3 vld1.32 {d0[]}, [r0,:32], r1 vabdl.u8 q8, d0, d1 .endm .macro SAD_4 align:vararg - vld1.32 {d1[]}, [r2 \align], r3 + vld1.32 {d1[]}, [r2\align], r3 vld1.32 {d0[]}, [r0,:32], r1 vabal.u8 q8, d0, d1 .endm .macro SAD_START_8 align:vararg - vld1.64 {d1}, [r2 \align], r3 + vld1.64 {d1}, [r2\align], r3 vld1.64 {d0}, [r0,:64], r1 vabdl.u8 q8, d0, d1 .endm .macro SAD_8 align:vararg - vld1.64 {d1}, [r2 \align], r3 + vld1.64 {d1}, [r2\align], r3 vld1.64 {d0}, [r0,:64], r1 vabal.u8 q8, d0, d1 .endm .macro SAD_START_16 align:vararg - vld1.64 {d2-d3}, [r2 \align], r3 + vld1.64 {d2-d3}, [r2\align], r3 vld1.64 {d0-d1}, [r0,:128], r1 vabdl.u8 q8, d0, d2 - vld1.64 {d6-d7}, [r2 \align], r3 + vld1.64 {d6-d7}, [r2\align], r3 vabdl.u8 q9, d1, d3 vld1.64 {d4-d5}, [r0,:128], r1 .endm .macro SAD_16 align:vararg vabal.u8 q8, d4, d6 - vld1.64 {d2-d3}, [r2 \align], r3 + vld1.64 {d2-d3}, [r2\align], r3 vabal.u8 q9, d5, d7 vld1.64 {d0-d1}, [r0,:128], r1 vabal.u8 q8, d0, d2 - vld1.64 {d6-d7}, [r2 \align], r3 + vld1.64 {d6-d7}, [r2\align], r3 vabal.u8 q9, d1, d3 vld1.64 {d4-d5}, [r0,:128], r1 .endm diff --git a/common/arm/pixel.h b/common/arm/pixel.h index ba390112..7d042473 100644 --- a/common/arm/pixel.h +++ b/common/arm/pixel.h @@ -1,7 +1,7 @@ /***************************************************************************** * pixel.h: arm pixel metrics ***************************************************************************** - * Copyright (C) 2009-2012 x264 project + * Copyright (C) 2009-2013 x264 project * * Authors: David Conrad * diff --git a/common/arm/predict-a.S b/common/arm/predict-a.S index af65bd7b..6d652f2c 100644 --- a/common/arm/predict-a.S +++ b/common/arm/predict-a.S @@ -1,7 +1,7 @@ /***************************************************************************** * predict.S: arm intra prediction ***************************************************************************** - * Copyright (C) 2009-2012 x264 project + * Copyright (C) 2009-2013 x264 project * * Authors: David Conrad * Mans Rullgard diff --git a/common/arm/predict-c.c b/common/arm/predict-c.c index 95d08158..07a46fac 100644 --- a/common/arm/predict-c.c +++ b/common/arm/predict-c.c @@ -1,7 +1,7 @@ /***************************************************************************** * predict.c: arm intra prediction ***************************************************************************** - * Copyright (C) 2009-2012 x264 project + * Copyright (C) 2009-2013 x264 project * * Authors: David Conrad * diff --git a/common/arm/predict.h b/common/arm/predict.h index c6425f6f..e6e13fa1 100644 --- a/common/arm/predict.h +++ b/common/arm/predict.h @@ -1,7 +1,7 @@ /***************************************************************************** * predict.h: arm intra prediction ***************************************************************************** - * Copyright (C) 2009-2012 x264 project + * Copyright (C) 2009-2013 x264 project * * Authors: David Conrad * diff --git a/common/arm/quant-a.S b/common/arm/quant-a.S index e851562c..a265fc7f 100644 --- a/common/arm/quant-a.S +++ b/common/arm/quant-a.S @@ -1,7 +1,7 @@ /**************************************************************************** * quant.S: arm quantization and level-run ***************************************************************************** - * Copyright (C) 2009-2012 x264 project + * Copyright (C) 2009-2013 x264 project * * Authors: David Conrad * @@ -35,7 +35,7 @@ pmovmskb_byte: .text -.macro QUANT_TWO bias0 bias1 mf0 mf1 mf2 mf3 load_mf=no +.macro QUANT_TWO bias0 bias1 mf0 mf1 mf2 mf3 mask load_mf=no vadd.u16 q8, q8, \bias0 vadd.u16 q9, q9, \bias1 .ifc \load_mf, yes @@ -55,7 +55,7 @@ pmovmskb_byte: veor q9, q9, q15 vsub.s16 q8, q8, q14 vsub.s16 q9, q9, q15 - vorr \bias0, q8, q9 + vorr \mask, q8, q9 vst1.64 {d16-d19}, [r0,:128]! .endm @@ -89,7 +89,7 @@ function x264_quant_4x4_dc_neon vabs.s16 q9, q15 vdup.16 q0, r2 vdup.16 q2, r1 - QUANT_TWO q0, q0, d4, d5, d4, d5 + QUANT_TWO q0, q0, d4, d5, d4, d5, q0 vorr d0, d0, d1 QUANT_END d0 .endfunc @@ -101,11 +101,50 @@ function x264_quant_4x4_neon vabs.s16 q9, q15 vld1.64 {d0-d3}, [r2,:128] vld1.64 {d4-d7}, [r1,:128] - QUANT_TWO q0, q1, d4, d5, d6, d7 + QUANT_TWO q0, q1, d4, d5, d6, d7, q0 vorr d0, d0, d1 QUANT_END d0 .endfunc +// quant_4x4x4( int16_t dct[4][16], uint16_t mf[16], uint16_t bias[16] ) +function x264_quant_4x4x4_neon + vld1.64 {d28-d31}, [r0,:128] + vabs.s16 q8, q14 + vabs.s16 q9, q15 + vld1.64 {d0-d3}, [r2,:128] + vld1.64 {d4-d7}, [r1,:128] + QUANT_TWO q0, q1, d4, d5, d6, d7, q4 + vld1.64 {d28-d31}, [r0,:128] + vabs.s16 q8, q14 + vabs.s16 q9, q15 + QUANT_TWO q0, q1, d4, d5, d6, d7, q5 + vld1.64 {d28-d31}, [r0,:128] + vabs.s16 q8, q14 + vabs.s16 q9, q15 + QUANT_TWO q0, q1, d4, d5, d6, d7, q6 + vld1.64 {d28-d31}, [r0,:128] + vabs.s16 q8, q14 + vabs.s16 q9, q15 + QUANT_TWO q0, q1, d4, d5, d6, d7, q7 + vorr d8, d8, d9 + vorr d10, d10, d11 + vorr d12, d12, d13 + vorr d14, d14, d15 + vmov r0, r1, d8 + vmov r2, r3, d10 + orrs r0, r1 + movne r0, #1 + orrs r2, r3 + orrne r0, #2 + vmov r1, r2, d12 + vmov r3, ip, d14 + orrs r1, r2 + orrne r0, #4 + orrs r3, ip + orrne r0, #8 + bx lr +.endfunc + // quant_8x8( int16_t dct[64], uint16_t mf[64], uint16_t bias[64] ) function x264_quant_8x8_neon vld1.64 {d28-d31}, [r0,:128] @@ -113,13 +152,13 @@ function x264_quant_8x8_neon vabs.s16 q9, q15 vld1.64 {d0-d3}, [r2,:128]! vld1.64 {d4-d7}, [r1,:128]! - QUANT_TWO q0, q1, d4, d5, d6, d7 + QUANT_TWO q0, q1, d4, d5, d6, d7, q0 .rept 3 vld1.64 {d28-d31}, [r0,:128] vabs.s16 q8, q14 vabs.s16 q9, q15 vld1.64 {d2-d5}, [r2,:128]! - QUANT_TWO q1, q2, d4, d5, d6, d7, yes + QUANT_TWO q1, q2, d4, d5, d6, d7, q1, yes vorr q0, q0, q1 .endr vorr d0, d0, d1 diff --git a/common/arm/quant.h b/common/arm/quant.h index 05a708e2..bf29f251 100644 --- a/common/arm/quant.h +++ b/common/arm/quant.h @@ -1,7 +1,7 @@ /***************************************************************************** * quant.h: arm quantization and level-run ***************************************************************************** - * Copyright (C) 2005-2012 x264 project + * Copyright (C) 2005-2013 x264 project * * Authors: David Conrad * @@ -31,6 +31,7 @@ int x264_quant_2x2_dc_armv6( int16_t dct[4], int mf, int bias ); int x264_quant_2x2_dc_neon( int16_t dct[4], int mf, int bias ); int x264_quant_4x4_dc_neon( int16_t dct[16], int mf, int bias ); int x264_quant_4x4_neon( int16_t dct[16], uint16_t mf[16], uint16_t bias[16] ); +int x264_quant_4x4x4_neon( int16_t dct[4][16], uint16_t mf[16], uint16_t bias[16] ); int x264_quant_8x8_neon( int16_t dct[64], uint16_t mf[64], uint16_t bias[64] ); void x264_dequant_4x4_dc_neon( int16_t dct[16], int dequant_mf[6][16], int i_qp ); diff --git a/common/bitstream.c b/common/bitstream.c index 52ba95fd..ae8d840c 100644 --- a/common/bitstream.c +++ b/common/bitstream.c @@ -1,7 +1,7 @@ /***************************************************************************** * bitstream.c: bitstream writing ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Laurent Aimar * Jason Garrett-Glaser diff --git a/common/bitstream.h b/common/bitstream.h index 3beb1ea9..a269e941 100644 --- a/common/bitstream.h +++ b/common/bitstream.h @@ -1,7 +1,7 @@ /***************************************************************************** * bitstream.h: bitstream writing ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Loren Merritt * Jason Garrett-Glaser diff --git a/common/cabac.c b/common/cabac.c index b6d4b739..04d1add9 100644 --- a/common/cabac.c +++ b/common/cabac.c @@ -1,7 +1,7 @@ /***************************************************************************** * cabac.c: arithmetic coder ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Laurent Aimar * Loren Merritt diff --git a/common/cabac.h b/common/cabac.h index d638ff11..ccf4d4e8 100644 --- a/common/cabac.h +++ b/common/cabac.h @@ -1,7 +1,7 @@ /***************************************************************************** * cabac.h: arithmetic coder ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Loren Merritt * Laurent Aimar diff --git a/common/common.c b/common/common.c index c5fcaa50..64d02620 100644 --- a/common/common.c +++ b/common/common.c @@ -1,7 +1,7 @@ /***************************************************************************** * common.c: misc common functions ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Loren Merritt * Laurent Aimar @@ -50,6 +50,7 @@ void x264_param_default( x264_param_t *param ) /* CPU autodetect */ param->cpu = x264_cpu_detect(); param->i_threads = X264_THREADS_AUTO; + param->i_lookahead_threads = X264_THREADS_AUTO; param->b_deterministic = 1; param->i_sync_lookahead = X264_SYNC_LOOKAHEAD_AUTO; @@ -568,6 +569,8 @@ static double x264_atof( const char *str, int *b_error ) } #define atobool(str) ( name_was_bool = 1, x264_atobool( str, &b_error ) ) +#undef atoi +#undef atof #define atoi(str) x264_atoi( str, &b_error ) #define atof(str) x264_atof( str, &b_error ) @@ -625,10 +628,8 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value ) b_error = 1; } free( buf ); - if( p->cpu & X264_CPU_SSSE3 ) + if( (p->cpu&X264_CPU_SSSE3) && !(p->cpu&X264_CPU_SSE2_IS_SLOW) ) p->cpu |= X264_CPU_SSE2_IS_FAST; - if( p->cpu & X264_CPU_SSE4 ) - p->cpu |= X264_CPU_SHUFFLE_IS_FAST; } } OPT("threads") @@ -638,6 +639,13 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value ) else p->i_threads = atoi(value); } + OPT("lookahead-threads") + { + if( !strcmp(value, "auto") ) + p->i_lookahead_threads = X264_THREADS_AUTO; + else + p->i_lookahead_threads = atoi(value); + } OPT("sliced-threads") p->b_sliced_threads = atobool(value); OPT("sync-lookahead") @@ -691,8 +699,16 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value ) else { float fps = atof(value); - p->i_fps_num = (int)(fps * 1000 + .5); - p->i_fps_den = 1000; + if( fps > 0 && fps <= INT_MAX/1000 ) + { + p->i_fps_num = (int)(fps * 1000 + .5); + p->i_fps_den = 1000; + } + else + { + p->i_fps_num = atoi(value); + p->i_fps_den = 1; + } } } OPT2("ref", "frameref") @@ -1301,6 +1317,7 @@ char *x264_param2string( x264_param_t *p, int b_res ) s += sprintf( s, " fast_pskip=%d", p->analyse.b_fast_pskip ); s += sprintf( s, " chroma_qp_offset=%d", p->analyse.i_chroma_qp_offset ); s += sprintf( s, " threads=%d", p->i_threads ); + s += sprintf( s, " lookahead_threads=%d", p->i_lookahead_threads ); s += sprintf( s, " sliced_threads=%d", p->b_sliced_threads ); if( p->i_slice_count ) s += sprintf( s, " slices=%d", p->i_slice_count ); diff --git a/common/common.h b/common/common.h index cf338c23..eb0575f5 100644 --- a/common/common.h +++ b/common/common.h @@ -1,7 +1,7 @@ /***************************************************************************** * common.h: misc common functions ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Laurent Aimar * Loren Merritt @@ -56,6 +56,7 @@ do {\ #define X264_BFRAME_MAX 16 #define X264_REF_MAX 16 #define X264_THREAD_MAX 128 +#define X264_LOOKAHEAD_THREAD_MAX 16 #define X264_PCM_COST (FRAME_SIZE(256*BIT_DEPTH)+16) #define X264_LOOKAHEAD_MAX 250 #define QP_BD_OFFSET (6*(BIT_DEPTH-8)) @@ -291,17 +292,6 @@ static ALWAYS_INLINE uint16_t x264_cabac_mvd_sum( uint8_t *mvdleft, uint8_t *mvd return amvd0 + (amvd1<<8); } -static void ALWAYS_INLINE x264_predictor_roundclip( int16_t (*dst)[2], int16_t (*mvc)[2], int i_mvc, int mv_x_min, int mv_x_max, int mv_y_min, int mv_y_max ) -{ - for( int i = 0; i < i_mvc; i++ ) - { - int mx = (mvc[i][0] + 2) >> 2; - int my = (mvc[i][1] + 2) >> 2; - dst[i][0] = x264_clip3( mx, mv_x_min, mv_x_max ); - dst[i][1] = x264_clip3( my, mv_y_min, mv_y_max ); - } -} - extern const uint8_t x264_exp2_lut[64]; extern const float x264_log2_lut[128]; extern const float x264_log2_lz_lut[32]; @@ -386,6 +376,7 @@ typedef struct } ref_pic_list_order[2][X264_REF_MAX]; /* P-frame weighting */ + int b_weighted_pred; x264_weight_t weight[X264_REF_MAX*2][3]; int i_mmco_remove_from_end; @@ -470,6 +461,7 @@ struct x264_t x264_param_t param; x264_t *thread[X264_THREAD_MAX+1]; + x264_t *lookahead_thread[X264_LOOKAHEAD_THREAD_MAX]; int b_thread_active; int i_thread_phase; /* which thread to use for the next frame */ int i_thread_idx; /* which thread this is */ @@ -477,6 +469,7 @@ struct x264_t int i_threadslice_end; /* row after the end of this thread slice */ int i_threadslice_pass; /* which pass of encoding we are on */ x264_threadpool_t *threadpool; + x264_threadpool_t *lookaheadpool; x264_pthread_mutex_t mutex; x264_pthread_cond_t cv; @@ -669,8 +662,7 @@ struct x264_t int mv_miny_spel_row[3]; int mv_maxy_spel_row[3]; /* Fullpel MV range for motion search */ - int mv_min_fpel[2]; - int mv_max_fpel[2]; + ALIGNED_8( int16_t mv_limit_fpel[2][2] ); /* min_x, min_y, max_x, max_y */ int mv_miny_fpel_row[3]; int mv_maxy_fpel_row[3]; @@ -917,6 +909,7 @@ struct x264_t /* Buffers that are allocated per-thread even in sliced threads. */ void *scratch_buffer; /* for any temporary storage that doesn't want repeated malloc */ + void *scratch_buffer2; /* if the first one's already in use */ pixel *intra_border_backup[5][3]; /* bottom pixels of the previous mb row, used for intra prediction after the framebuffer has been deblocked */ /* Deblock strength values are stored for each 4x4 partition. In MBAFF * there are four extra values that need to be stored, located in [4][i]. */ @@ -950,6 +943,39 @@ struct x264_t // included at the end because it needs x264_t #include "macroblock.h" +static int ALWAYS_INLINE x264_predictor_roundclip( int16_t (*dst)[2], int16_t (*mvc)[2], int i_mvc, int16_t mv_limit[2][2], uint32_t pmv ) +{ + int cnt = 0; + for( int i = 0; i < i_mvc; i++ ) + { + int mx = (mvc[i][0] + 2) >> 2; + int my = (mvc[i][1] + 2) >> 2; + uint32_t mv = pack16to32_mask(mx, my); + if( !mv || mv == pmv ) continue; + dst[cnt][0] = x264_clip3( mx, mv_limit[0][0], mv_limit[1][0] ); + dst[cnt][1] = x264_clip3( my, mv_limit[0][1], mv_limit[1][1] ); + cnt++; + } + return cnt; +} + +static int ALWAYS_INLINE x264_predictor_clip( int16_t (*dst)[2], int16_t (*mvc)[2], int i_mvc, int16_t mv_limit[2][2], uint32_t pmv ) +{ + int cnt = 0; + int qpel_limit[4] = {mv_limit[0][0] << 2, mv_limit[0][1] << 2, mv_limit[1][0] << 2, mv_limit[1][1] << 2}; + for( int i = 0; i < i_mvc; i++ ) + { + uint32_t mv = M32( mvc[i] ); + int mx = mvc[i][0]; + int my = mvc[i][1]; + if( !mv || mv == pmv ) continue; + dst[cnt][0] = x264_clip3( mx, qpel_limit[0], qpel_limit[2] ); + dst[cnt][1] = x264_clip3( my, qpel_limit[1], qpel_limit[3] ); + cnt++; + } + return cnt; +} + #if ARCH_X86 || ARCH_X86_64 #include "x86/util.h" #endif diff --git a/common/cpu.c b/common/cpu.c index fa57407b..42a1b0ee 100644 --- a/common/cpu.c +++ b/common/cpu.c @@ -1,7 +1,7 @@ /***************************************************************************** * cpu.c: cpu detection ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Loren Merritt * Laurent Aimar @@ -47,18 +47,19 @@ const x264_cpu_name_t x264_cpu_names[] = { - {"Altivec", X264_CPU_ALTIVEC}, -// {"MMX", X264_CPU_MMX}, // we don't support asm on mmx1 cpus anymore - {"MMX2", X264_CPU_MMX|X264_CPU_MMX2}, - {"MMXEXT", X264_CPU_MMX|X264_CPU_MMX2}, -// {"SSE", X264_CPU_MMX|X264_CPU_MMX2|X264_CPU_SSE}, // there are no sse1 functions in x264 -#define SSE2 X264_CPU_MMX|X264_CPU_MMX2|X264_CPU_SSE|X264_CPU_SSE2 +#if HAVE_MMX +// {"MMX", X264_CPU_MMX}, // we don't support asm on mmx1 cpus anymore +// {"CMOV", X264_CPU_CMOV}, // we require this unconditionally, so don't print it +#define MMX2 X264_CPU_MMX|X264_CPU_MMX2|X264_CPU_CMOV + {"MMX2", MMX2}, + {"MMXEXT", MMX2}, + {"SSE", MMX2|X264_CPU_SSE}, +#define SSE2 MMX2|X264_CPU_SSE|X264_CPU_SSE2 {"SSE2Slow", SSE2|X264_CPU_SSE2_IS_SLOW}, {"SSE2", SSE2}, {"SSE2Fast", SSE2|X264_CPU_SSE2_IS_FAST}, {"SSE3", SSE2|X264_CPU_SSE3}, {"SSSE3", SSE2|X264_CPU_SSE3|X264_CPU_SSSE3}, - {"FastShuffle", SSE2|X264_CPU_SHUFFLE_IS_FAST}, {"SSE4.1", SSE2|X264_CPU_SSE3|X264_CPU_SSSE3|X264_CPU_SSE4}, {"SSE4", SSE2|X264_CPU_SSE3|X264_CPU_SSSE3|X264_CPU_SSE4}, {"SSE4.2", SSE2|X264_CPU_SSE3|X264_CPU_SSSE3|X264_CPU_SSE4|X264_CPU_SSE42}, @@ -70,19 +71,26 @@ const x264_cpu_name_t x264_cpu_names[] = {"FMA3", AVX|X264_CPU_FMA3}, #undef AVX #undef SSE2 +#undef MMX2 {"Cache32", X264_CPU_CACHELINE_32}, {"Cache64", X264_CPU_CACHELINE_64}, {"SSEMisalign", X264_CPU_SSE_MISALIGN}, {"LZCNT", X264_CPU_LZCNT}, {"BMI1", X264_CPU_BMI1}, {"BMI2", X264_CPU_BMI1|X264_CPU_BMI2}, - {"TBM", X264_CPU_TBM}, - {"Slow_mod4_stack", X264_CPU_STACK_MOD4}, - {"ARMv6", X264_CPU_ARMV6}, - {"NEON", X264_CPU_NEON}, - {"Fast_NEON_MRC", X264_CPU_FAST_NEON_MRC}, {"SlowCTZ", X264_CPU_SLOW_CTZ}, {"SlowAtom", X264_CPU_SLOW_ATOM}, + {"SlowPshufb", X264_CPU_SLOW_PSHUFB}, + {"SlowPalignr", X264_CPU_SLOW_PALIGNR}, + {"SlowShuffle", X264_CPU_SLOW_SHUFFLE}, + {"UnalignedStack", X264_CPU_STACK_MOD4}, +#elif ARCH_PPC + {"Altivec", X264_CPU_ALTIVEC}, +#elif ARCH_ARM + {"ARMv6", X264_CPU_ARMV6}, + {"NEON", X264_CPU_NEON}, + {"FastNeonMRC", X264_CPU_FAST_NEON_MRC}, +#endif {"", 0}, }; @@ -131,9 +139,13 @@ uint32_t x264_cpu_detect( void ) if( edx&0x00800000 ) cpu |= X264_CPU_MMX; else - return 0; + return cpu; if( edx&0x02000000 ) cpu |= X264_CPU_MMX2|X264_CPU_SSE; + if( edx&0x00008000 ) + cpu |= X264_CPU_CMOV; + else + return cpu; if( edx&0x04000000 ) cpu |= X264_CPU_SSE2; if( ecx&0x00000001 ) @@ -170,46 +182,50 @@ uint32_t x264_cpu_detect( void ) if( cpu & X264_CPU_SSSE3 ) cpu |= X264_CPU_SSE2_IS_FAST; - if( cpu & X264_CPU_SSE4 ) - cpu |= X264_CPU_SHUFFLE_IS_FAST; x264_cpu_cpuid( 0x80000000, &eax, &ebx, &ecx, &edx ); max_extended_cap = eax; - if( !strcmp((char*)vendor, "AuthenticAMD") && max_extended_cap >= 0x80000001 ) + if( max_extended_cap >= 0x80000001 ) { - cpu |= X264_CPU_SLOW_CTZ; x264_cpu_cpuid( 0x80000001, &eax, &ebx, &ecx, &edx ); - if( edx&0x00400000 ) - cpu |= X264_CPU_MMX2; - if( cpu & X264_CPU_SSE2 ) + + if( ecx&0x00000020 ) + cpu |= X264_CPU_LZCNT; /* Supported by Intel chips starting with Haswell */ + if( ecx&0x00000040 ) /* SSE4a, AMD only */ { - if( ecx&0x00000040 ) /* SSE4a */ + int family = ((eax>>8)&0xf) + ((eax>>20)&0xff); + cpu |= X264_CPU_SSE2_IS_FAST; /* Phenom and later CPUs have fast SSE units */ + if( family == 0x14 ) { - cpu |= X264_CPU_SSE2_IS_FAST; - cpu |= X264_CPU_LZCNT; - cpu |= X264_CPU_SHUFFLE_IS_FAST; - cpu &= ~X264_CPU_SLOW_CTZ; + cpu &= ~X264_CPU_SSE2_IS_FAST; /* SSSE3 doesn't imply fast SSE anymore... */ + cpu |= X264_CPU_SSE2_IS_SLOW; /* Bobcat has 64-bit SIMD units */ + cpu |= X264_CPU_SLOW_PALIGNR; /* palignr is insanely slow on Bobcat */ } - else - cpu |= X264_CPU_SSE2_IS_SLOW; + } - if( ecx&0x00000080 ) /* Misalign SSE */ - { - cpu |= X264_CPU_SSE_MISALIGN; - x264_cpu_mask_misalign_sse(); - } + if( ecx&0x00000080 ) /* Misalign SSE */ + { + cpu |= X264_CPU_SSE_MISALIGN; + x264_cpu_mask_misalign_sse(); + } - if( cpu & X264_CPU_AVX ) - { - if( ecx&0x00000800 ) /* XOP */ - cpu |= X264_CPU_XOP; - if( ecx&0x00010000 ) /* FMA4 */ - cpu |= X264_CPU_FMA4; - } + if( cpu & X264_CPU_AVX ) + { + if( ecx&0x00000800 ) /* XOP */ + cpu |= X264_CPU_XOP; + if( ecx&0x00010000 ) /* FMA4 */ + cpu |= X264_CPU_FMA4; + } - if( ecx&0x00200000 ) - cpu |= X264_CPU_TBM; + if( !strcmp((char*)vendor, "AuthenticAMD") ) + { + if( edx&0x00400000 ) + cpu |= X264_CPU_MMX2; + if( !(cpu&X264_CPU_LZCNT) ) + cpu |= X264_CPU_SLOW_CTZ; + if( (cpu&X264_CPU_SSE2) && !(cpu&X264_CPU_SSE2_IS_FAST) ) + cpu |= X264_CPU_SSE2_IS_SLOW; /* AMD CPUs come in two types: terrible at SSE and great at it */ } } @@ -233,11 +249,12 @@ uint32_t x264_cpu_detect( void ) { cpu |= X264_CPU_SLOW_ATOM; cpu |= X264_CPU_SLOW_CTZ; + cpu |= X264_CPU_SLOW_PSHUFB; } - /* Some Penryns and Nehalems are pointlessly crippled (SSE4 disabled), so - * detect them here. */ - else if( model >= 23 ) - cpu |= X264_CPU_SHUFFLE_IS_FAST; + /* Conroe has a slow shuffle unit. Check the model number to make sure not + * to include crippled low-end Penryns and Nehalems that don't have SSE4. */ + else if( (cpu&X264_CPU_SSSE3) && !(cpu&X264_CPU_SSE4) && model < 23 ) + cpu |= X264_CPU_SLOW_SHUFFLE; } } @@ -376,7 +393,10 @@ uint32_t x264_cpu_detect( void ) // Note that there is potential for a race condition if another program or // x264 instance disables or reinits the counters while x264 is using them, // which may result in incorrect detection and the counters stuck enabled. + // right now Apple does not seem to support performance counters for this test +#ifndef __MACH__ flags |= x264_cpu_fast_neon_mrc_test() ? X264_CPU_FAST_NEON_MRC : 0; +#endif // TODO: write dual issue test? currently it's A8 (dual issue) vs. A9 (fast mrc) #endif return flags; @@ -399,7 +419,7 @@ int x264_cpu_num_processors( void ) #elif SYS_WINDOWS return x264_pthread_num_processors_np(); -#elif SYS_CYGWIN +#elif SYS_CYGWIN || SYS_SunOS return sysconf( _SC_NPROCESSORS_ONLN ); #elif SYS_LINUX diff --git a/common/cpu.h b/common/cpu.h index c92f93ea..7f76e435 100644 --- a/common/cpu.h +++ b/common/cpu.h @@ -1,7 +1,7 @@ /***************************************************************************** * cpu.h: cpu detection ***************************************************************************** - * Copyright (C) 2004-2012 x264 project + * Copyright (C) 2004-2013 x264 project * * Authors: Loren Merritt * @@ -46,6 +46,7 @@ void x264_cpu_sfence( void ); #endif #define x264_sfence x264_cpu_sfence void x264_cpu_mask_misalign_sse( void ); +void x264_safe_intel_cpu_indicator_init( void ); /* kluge: * gcc can't give variables any greater alignment than the stack frame has. diff --git a/common/dct.c b/common/dct.c index 8c3a0364..479e03d0 100644 --- a/common/dct.c +++ b/common/dct.c @@ -1,7 +1,7 @@ /***************************************************************************** * dct.c: transform and zigzag ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Loren Merritt * Laurent Aimar @@ -640,23 +640,32 @@ void x264_dct_init( int cpu, x264_dct_function_t *dctf ) dctf->add8x8_idct8 = x264_add8x8_idct8_sse2; dctf->add16x16_idct8= x264_add16x16_idct8_sse2; - dctf->sub8x8_dct = x264_sub8x8_dct_sse2; - dctf->sub16x16_dct = x264_sub16x16_dct_sse2; - dctf->add8x8_idct = x264_add8x8_idct_sse2; - dctf->add16x16_idct = x264_add16x16_idct_sse2; - dctf->add16x16_idct_dc = x264_add16x16_idct_dc_sse2; + if( !(cpu&X264_CPU_SSE2_IS_SLOW) ) + { + dctf->sub8x8_dct = x264_sub8x8_dct_sse2; + dctf->sub16x16_dct = x264_sub16x16_dct_sse2; + dctf->add8x8_idct = x264_add8x8_idct_sse2; + dctf->add16x16_idct = x264_add16x16_idct_sse2; + dctf->add16x16_idct_dc = x264_add16x16_idct_dc_sse2; + } } - if( (cpu&X264_CPU_SSSE3) && !(cpu&X264_CPU_SLOW_ATOM) ) + if( (cpu&X264_CPU_SSSE3) && !(cpu&X264_CPU_SSE2_IS_SLOW) ) { - dctf->sub4x4_dct = x264_sub4x4_dct_ssse3; - dctf->sub8x8_dct = x264_sub8x8_dct_ssse3; - dctf->sub16x16_dct = x264_sub16x16_dct_ssse3; - dctf->sub8x8_dct8 = x264_sub8x8_dct8_ssse3; - dctf->sub16x16_dct8 = x264_sub16x16_dct8_ssse3; dctf->sub8x16_dct_dc = x264_sub8x16_dct_dc_ssse3; - dctf->add8x8_idct_dc = x264_add8x8_idct_dc_ssse3; - dctf->add16x16_idct_dc = x264_add16x16_idct_dc_ssse3; + if( !(cpu&X264_CPU_SLOW_ATOM) ) + { + dctf->sub4x4_dct = x264_sub4x4_dct_ssse3; + dctf->sub8x8_dct = x264_sub8x8_dct_ssse3; + dctf->sub16x16_dct = x264_sub16x16_dct_ssse3; + dctf->sub8x8_dct8 = x264_sub8x8_dct8_ssse3; + dctf->sub16x16_dct8 = x264_sub16x16_dct8_ssse3; + if( !(cpu&X264_CPU_SLOW_PSHUFB) ) + { + dctf->add8x8_idct_dc = x264_add8x8_idct_dc_ssse3; + dctf->add16x16_idct_dc = x264_add16x16_idct_dc_ssse3; + } + } } if( cpu&X264_CPU_SSE4 ) @@ -951,7 +960,7 @@ void x264_zigzag_init( int cpu, x264_zigzag_function_t *pf_progressive, x264_zig pf_interlaced->sub_4x4ac = x264_zigzag_sub_4x4ac_field_ssse3; pf_progressive->sub_4x4ac= x264_zigzag_sub_4x4ac_frame_ssse3; pf_progressive->scan_8x8 = x264_zigzag_scan_8x8_frame_ssse3; - if( cpu&X264_CPU_SHUFFLE_IS_FAST ) + if( !(cpu&X264_CPU_SLOW_SHUFFLE) ) pf_progressive->scan_4x4 = x264_zigzag_scan_4x4_frame_ssse3; } if( cpu&X264_CPU_AVX ) @@ -962,8 +971,7 @@ void x264_zigzag_init( int cpu, x264_zigzag_function_t *pf_progressive, x264_zig pf_interlaced->sub_4x4ac = x264_zigzag_sub_4x4ac_field_avx; pf_progressive->sub_4x4ac= x264_zigzag_sub_4x4ac_frame_avx; #endif - if( cpu&X264_CPU_SHUFFLE_IS_FAST ) - pf_progressive->scan_4x4 = x264_zigzag_scan_4x4_frame_avx; + pf_progressive->scan_4x4 = x264_zigzag_scan_4x4_frame_avx; } if( cpu&X264_CPU_XOP ) { @@ -1005,7 +1013,7 @@ void x264_zigzag_init( int cpu, x264_zigzag_function_t *pf_progressive, x264_zig pf_interlaced->interleave_8x8_cavlc = pf_progressive->interleave_8x8_cavlc = x264_zigzag_interleave_8x8_cavlc_mmx; } - if( cpu&X264_CPU_SHUFFLE_IS_FAST ) + if( (cpu&X264_CPU_SSE2) && !(cpu&(X264_CPU_SLOW_SHUFFLE|X264_CPU_SSE2_IS_SLOW)) ) { pf_interlaced->interleave_8x8_cavlc = pf_progressive->interleave_8x8_cavlc = x264_zigzag_interleave_8x8_cavlc_sse2; diff --git a/common/dct.h b/common/dct.h index a8fa18ea..ce10eb21 100644 --- a/common/dct.h +++ b/common/dct.h @@ -1,7 +1,7 @@ /***************************************************************************** * dct.h: transform and zigzag ***************************************************************************** - * Copyright (C) 2004-2012 x264 project + * Copyright (C) 2004-2013 x264 project * * Authors: Loren Merritt * diff --git a/common/deblock.c b/common/deblock.c index 8ce902bf..18ed14fa 100644 --- a/common/deblock.c +++ b/common/deblock.c @@ -1,7 +1,7 @@ /***************************************************************************** * deblock.c: deblocking ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Laurent Aimar * Loren Merritt @@ -393,7 +393,7 @@ void x264_frame_deblock_row( x264_t *h, int mb_y ) x264_macroblock_cache_load_neighbours_deblock( h, mb_x, mb_y ); int mb_xy = h->mb.i_mb_xy; - int transform_8x8 = h->mb.mb_transform_size[h->mb.i_mb_xy]; + int transform_8x8 = h->mb.mb_transform_size[mb_xy]; int intra_cur = IS_INTRA( h->mb.type[mb_xy] ); uint8_t (*bs)[8][4] = h->deblock_strength[mb_y&1][h->param.b_sliced_threads?mb_xy:mb_x]; @@ -501,8 +501,19 @@ void x264_frame_deblock_row( x264_t *h, int mb_y ) int qp_left = (qp + qpl + 1) >> 1; int qpc_left = (qpc + h->chroma_qp_table[qpl] + 1) >> 1; int intra_left = IS_INTRA( h->mb.type[h->mb.i_mb_xy-1] ); + int intra_deblock = intra_cur || intra_left; - if( intra_cur || intra_left ) + /* Any MB that was coded, or that analysis decided to skip, has quality commensurate with its QP. + * But if deblocking affects neighboring MBs that were force-skipped, blur might accumulate there. + * So reset their effective QP to max, to indicate that lack of guarantee. */ + if( h->fdec->mb_info && M32( bs[0][0] ) ) + { +#define RESET_EFFECTIVE_QP(xy) h->fdec->effective_qp[xy] |= 0xff * !!(h->fdec->mb_info[xy] & X264_MBINFO_CONSTANT); + RESET_EFFECTIVE_QP(mb_xy); + RESET_EFFECTIVE_QP(h->mb.i_mb_left_xy[0]); + } + + if( intra_deblock ) FILTER( _intra, 0, 0, qp_left, qpc_left ); else FILTER( , 0, 0, qp_left, qpc_left ); @@ -547,15 +558,22 @@ void x264_frame_deblock_row( x264_t *h, int mb_y ) int qp_top = (qp + qpt + 1) >> 1; int qpc_top = (qpc + h->chroma_qp_table[qpt] + 1) >> 1; int intra_top = IS_INTRA( h->mb.type[h->mb.i_mb_top_xy] ); + int intra_deblock = intra_cur || intra_top; - if( (!b_interlaced || (!MB_INTERLACED && !h->mb.field[h->mb.i_mb_top_xy])) - && (intra_cur || intra_top) ) + /* This edge has been modified, reset effective qp to max. */ + if( h->fdec->mb_info && M32( bs[1][0] ) ) + { + RESET_EFFECTIVE_QP(mb_xy); + RESET_EFFECTIVE_QP(h->mb.i_mb_top_xy); + } + + if( (!b_interlaced || (!MB_INTERLACED && !h->mb.field[h->mb.i_mb_top_xy])) && intra_deblock ) { FILTER( _intra, 1, 0, qp_top, qpc_top ); } else { - if( intra_cur || intra_top ) + if( intra_deblock ) M32( bs[1][0] ) = 0x03030303; FILTER( , 1, 0, qp_top, qpc_top ); } @@ -761,13 +779,13 @@ void x264_deblock_init( int cpu, x264_deblock_function_t *pf, int b_mbaff ) pf->deblock_h_chroma_422 = x264_deblock_h_chroma_422_sse2; pf->deblock_h_chroma_422_intra = x264_deblock_h_chroma_422_intra_sse2; pf->deblock_chroma_420_mbaff = x264_deblock_h_chroma_mbaff_sse2; + pf->deblock_luma[1] = x264_deblock_v_luma_sse2; + pf->deblock_luma[0] = x264_deblock_h_luma_sse2; + pf->deblock_luma_intra[1] = x264_deblock_v_luma_intra_sse2; + pf->deblock_luma_intra[0] = x264_deblock_h_luma_intra_sse2; if( !(cpu&X264_CPU_STACK_MOD4) ) { - pf->deblock_luma[1] = x264_deblock_v_luma_sse2; - pf->deblock_luma[0] = x264_deblock_h_luma_sse2; pf->deblock_chroma[1] = x264_deblock_v_chroma_sse2; - pf->deblock_luma_intra[1] = x264_deblock_v_luma_intra_sse2; - pf->deblock_luma_intra[0] = x264_deblock_h_luma_intra_sse2; pf->deblock_chroma_intra[1] = x264_deblock_v_chroma_intra_sse2; pf->deblock_h_chroma_420_intra = x264_deblock_h_chroma_intra_sse2; #if HIGH_BIT_DEPTH @@ -783,13 +801,13 @@ void x264_deblock_init( int cpu, x264_deblock_function_t *pf, int b_mbaff ) pf->deblock_h_chroma_420 = x264_deblock_h_chroma_avx; pf->deblock_h_chroma_422 = x264_deblock_h_chroma_422_avx; pf->deblock_h_chroma_422_intra = x264_deblock_h_chroma_422_intra_avx; + pf->deblock_luma[1] = x264_deblock_v_luma_avx; + pf->deblock_luma[0] = x264_deblock_h_luma_avx; + pf->deblock_luma_intra[1] = x264_deblock_v_luma_intra_avx; + pf->deblock_luma_intra[0] = x264_deblock_h_luma_intra_avx; if( !(cpu&X264_CPU_STACK_MOD4) ) { - pf->deblock_luma[1] = x264_deblock_v_luma_avx; - pf->deblock_luma[0] = x264_deblock_h_luma_avx; pf->deblock_chroma[1] = x264_deblock_v_chroma_avx; - pf->deblock_luma_intra[1] = x264_deblock_v_luma_intra_avx; - pf->deblock_luma_intra[0] = x264_deblock_h_luma_intra_avx; pf->deblock_chroma_intra[1] = x264_deblock_v_chroma_intra_avx; pf->deblock_h_chroma_420_intra = x264_deblock_h_chroma_intra_avx; #if HIGH_BIT_DEPTH diff --git a/common/display-x11.c b/common/display-x11.c index b1792653..17c02a6f 100644 --- a/common/display-x11.c +++ b/common/display-x11.c @@ -1,7 +1,7 @@ /***************************************************************************** * display-x11.c: x11 interface ***************************************************************************** - * Copyright (C) 2005-2012 x264 project + * Copyright (C) 2005-2013 x264 project * * Authors: Tuukka Toivonen * @@ -49,7 +49,7 @@ static inline void disp_chkerror( int cond, char *e ) abort(); } -static void disp_init_display() +static void disp_init_display( void ) { Visual *visual; int dpy_class; @@ -130,7 +130,7 @@ static void disp_init_window( int num, int width, int height, const unsigned cha XFree( shint ); } -void disp_sync() +void disp_sync( void ) { XSync( disp_display, 1 ); } diff --git a/common/display.h b/common/display.h index 77dca6a1..afae456b 100644 --- a/common/display.h +++ b/common/display.h @@ -1,7 +1,7 @@ /***************************************************************************** * display.h: x11 visualization interface ***************************************************************************** - * Copyright (C) 2005-2012 x264 project + * Copyright (C) 2005-2013 x264 project * * Authors: Tuukka Toivonen * diff --git a/common/frame.c b/common/frame.c index e31919e6..552a6aeb 100644 --- a/common/frame.c +++ b/common/frame.c @@ -1,7 +1,7 @@ /***************************************************************************** * frame.c: frame handling ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Laurent Aimar * Loren Merritt @@ -73,7 +73,11 @@ static x264_frame_t *x264_frame_new( x264_t *h, int b_fdec ) int i_stride, i_width, i_lines, luma_plane_count; int i_padv = PADV << PARAM_INTERLACED; int align = h->param.cpu&X264_CPU_CACHELINE_64 ? 64 : h->param.cpu&X264_CPU_CACHELINE_32 ? 32 : 16; - int disalign = h->param.cpu&X264_CPU_ALTIVEC ? 1<<9 : 1<<10; +#if ARCH_PPC + int disalign = 1<<9; +#else + int disalign = 1<<10; +#endif CHECKED_MALLOCZERO( frame, sizeof(x264_frame_t) ); @@ -210,6 +214,8 @@ static x264_frame_t *x264_frame_new( x264_t *h, int b_fdec ) } if( PARAM_INTERLACED ) CHECKED_MALLOC( frame->field, i_mb_count * sizeof(uint8_t) ); + if( h->param.analyse.b_mb_info ) + CHECKED_MALLOC( frame->effective_qp, i_mb_count * sizeof(uint8_t) ); } else /* fenc frame */ { @@ -289,6 +295,7 @@ void x264_frame_delete( x264_frame_t *frame ) x264_free( frame->f_row_qp ); x264_free( frame->f_row_qscale ); x264_free( frame->field ); + x264_free( frame->effective_qp ); x264_free( frame->mb_type ); x264_free( frame->mb_partition ); x264_free( frame->mv[0] ); @@ -297,6 +304,16 @@ void x264_frame_delete( x264_frame_t *frame ) x264_free( frame->mv16x16-1 ); x264_free( frame->ref[0] ); x264_free( frame->ref[1] ); + if( frame->param && frame->param->param_free ) + frame->param->param_free( frame->param ); + if( frame->mb_info_free ) + frame->mb_info_free( frame->mb_info ); + if( frame->extra_sei.sei_free ) + { + for( int i = 0; i < frame->extra_sei.num_payloads; i++ ) + frame->extra_sei.sei_free( frame->extra_sei.payloads[i].payload ); + frame->extra_sei.sei_free( frame->extra_sei.payloads ); + } x264_pthread_mutex_destroy( &frame->mutex ); x264_pthread_cond_destroy( &frame->cv ); } @@ -354,6 +371,8 @@ int x264_frame_copy_picture( x264_t *h, x264_frame_t *dst, x264_picture_t *src ) dst->i_pic_struct = src->i_pic_struct; dst->extra_sei = src->extra_sei; dst->opaque = src->opaque; + dst->mb_info = h->param.analyse.b_mb_info ? src->prop.mb_info : NULL; + dst->mb_info_free = h->param.analyse.b_mb_info ? src->prop.mb_info_free : NULL; uint8_t *pix[3]; int stride[3]; diff --git a/common/frame.h b/common/frame.h index 55bccacc..447a6ac4 100644 --- a/common/frame.h +++ b/common/frame.h @@ -1,7 +1,7 @@ /***************************************************************************** * frame.h: frame handling ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Laurent Aimar * Loren Merritt @@ -61,6 +61,7 @@ typedef struct x264_frame uint8_t i_bframes; /* number of bframes following this nonb in coded order */ float f_qp_avg_rc; /* QPs as decided by ratecontrol */ float f_qp_avg_aq; /* QPs as decided by AQ in addition to ratecontrol */ + float f_crf_avg; /* Average effective CRF for this frame */ int i_poc_l0ref0; /* poc of first refframe in L0, used to check if direct temporal is possible */ /* YUV buffer */ @@ -97,6 +98,7 @@ typedef struct x264_frame int16_t (*mv16x16)[2]; int16_t (*lowres_mvs[2][X264_BFRAME_MAX+1])[2]; uint8_t *field; + uint8_t *effective_qp; /* Stored as (lists_used << LOWRES_COST_SHIFT) + (cost). * Doesn't need special addressing for intra cost because @@ -165,6 +167,10 @@ typedef struct x264_frame /* user data */ void *opaque; + + /* user frame properties */ + uint8_t *mb_info; + void (*mb_info_free)( void* ); } x264_frame_t; /* synchronized frame list */ diff --git a/common/macroblock.c b/common/macroblock.c index 11c3e75e..71073222 100644 --- a/common/macroblock.c +++ b/common/macroblock.c @@ -1,7 +1,7 @@ /***************************************************************************** * macroblock.c: macroblock common functions ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Jason Garrett-Glaser * Laurent Aimar @@ -401,6 +401,9 @@ int x264_macroblock_thread_allocate( x264_t *h, int b_lookahead ) else h->scratch_buffer = NULL; + int buf_lookahead_threads = (h->mb.i_mb_height + (4 + 32) * h->param.i_lookahead_threads) * sizeof(int) * 2; + CHECKED_MALLOC( h->scratch_buffer2, buf_lookahead_threads ); + return 0; fail: return -1; @@ -418,6 +421,7 @@ void x264_macroblock_thread_free( x264_t *h, int b_lookahead ) x264_free( h->intra_border_backup[i][j] - 16 ); } x264_free( h->scratch_buffer ); + x264_free( h->scratch_buffer2 ); } void x264_macroblock_slice_init( x264_t *h ) diff --git a/common/macroblock.h b/common/macroblock.h index 43b2a9c2..b149a603 100644 --- a/common/macroblock.h +++ b/common/macroblock.h @@ -1,7 +1,7 @@ /***************************************************************************** * macroblock.h: macroblock common functions ***************************************************************************** - * Copyright (C) 2005-2012 x264 project + * Copyright (C) 2005-2013 x264 project * * Authors: Loren Merritt * Laurent Aimar @@ -420,23 +420,23 @@ static ALWAYS_INLINE int x264_mb_predict_non_zero_code( x264_t *h, int idx ) i_ret = ( i_ret + 1 ) >> 1; return i_ret & 0x7f; } + +/* intra and skip are disallowed, p8x8 is conditional. */ +static const uint8_t x264_transform_allowed[X264_MBTYPE_MAX] = +{ + 0,0,0,0,1,2,0,1,1,1,1,1,1,1,1,1,1,1,0 +}; + /* x264_mb_transform_8x8_allowed: * check whether any partition is smaller than 8x8 (or at least * might be, according to just partition type.) * doesn't check for cbp */ static ALWAYS_INLINE int x264_mb_transform_8x8_allowed( x264_t *h ) { - // intra and skip are disallowed - // large partitions are allowed - // direct and 8x8 are conditional - static const uint8_t partition_tab[X264_MBTYPE_MAX] = { - 0,0,0,0,1,2,0,1,1,1,1,1,1,1,1,1,1,1,0, - }; - if( !h->pps->b_transform_8x8_mode ) return 0; if( h->mb.i_type != P_8x8 ) - return partition_tab[h->mb.i_type]; + return x264_transform_allowed[h->mb.i_type]; return M32( h->mb.i_sub_partition ) == D_L0_8x8*0x01010101; } diff --git a/common/mc.c b/common/mc.c index 86f7e35a..a44c2afa 100644 --- a/common/mc.c +++ b/common/mc.c @@ -1,7 +1,7 @@ /***************************************************************************** * mc.c: motion compensation ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Laurent Aimar * Loren Merritt diff --git a/common/mc.h b/common/mc.h index 8d0f7727..018e2fac 100644 --- a/common/mc.h +++ b/common/mc.h @@ -1,7 +1,7 @@ /***************************************************************************** * mc.h: motion compensation ***************************************************************************** - * Copyright (C) 2004-2012 x264 project + * Copyright (C) 2004-2013 x264 project * * Authors: Loren Merritt * diff --git a/common/mvpred.c b/common/mvpred.c index eb38d68e..088c40a6 100644 --- a/common/mvpred.c +++ b/common/mvpred.c @@ -1,7 +1,7 @@ /***************************************************************************** * mvpred.c: motion vector prediction ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Loren Merritt * Jason Garrett-Glaser diff --git a/common/osdep.c b/common/osdep.c index 27beb3d4..542ee79e 100644 --- a/common/osdep.c +++ b/common/osdep.c @@ -1,7 +1,7 @@ /***************************************************************************** * osdep.c: platform-specific code ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Steven Walters * Laurent Aimar @@ -94,6 +94,7 @@ int x264_threading_init( void ) } #endif +#if HAVE_MMX #ifdef __INTEL_COMPILER /* Agner's patch to Intel's CPU dispatcher from pages 131-132 of * http://agner.org/optimize/optimizing_cpp.pdf (2011-01-30) @@ -102,7 +103,7 @@ int x264_threading_init( void ) // Global variable indicating cpu int __intel_cpu_indicator = 0; // CPU dispatcher function -void __intel_cpu_indicator_init( void ) +void x264_intel_cpu_indicator_init( void ) { unsigned int cpu = x264_cpu_detect(); if( cpu&X264_CPU_AVX ) @@ -124,4 +125,16 @@ void __intel_cpu_indicator_init( void ) else __intel_cpu_indicator = 1; } + +/* __intel_cpu_indicator_init appears to have a non-standard calling convention that + * assumes certain registers aren't preserved, so we'll route it through a function + * that backs up all the registers. */ +void __intel_cpu_indicator_init( void ) +{ + x264_safe_intel_cpu_indicator_init(); +} +#else +void x264_intel_cpu_indicator_init( void ) +{} +#endif #endif diff --git a/common/osdep.h b/common/osdep.h index f7cad575..1e17c6a1 100644 --- a/common/osdep.h +++ b/common/osdep.h @@ -1,7 +1,7 @@ /***************************************************************************** * osdep.h: platform-specific code ***************************************************************************** - * Copyright (C) 2007-2012 x264 project + * Copyright (C) 2007-2013 x264 project * * Authors: Loren Merritt * Laurent Aimar @@ -108,8 +108,10 @@ ALIGNED_16( type name sub1 __VA_ARGS__ ) #endif -#define ALIGNED_ARRAY_32( ... ) ALIGNED_ARRAY_EMU( 31, __VA_ARGS__ ) -#define ALIGNED_ARRAY_64( ... ) ALIGNED_ARRAY_EMU( 63, __VA_ARGS__ ) +#define EXPAND(x) x + +#define ALIGNED_ARRAY_32( ... ) EXPAND( ALIGNED_ARRAY_EMU( 31, __VA_ARGS__ ) ) +#define ALIGNED_ARRAY_64( ... ) EXPAND( ALIGNED_ARRAY_EMU( 63, __VA_ARGS__ ) ) #define UNINIT(x) x=x @@ -147,7 +149,7 @@ static inline int x264_pthread_create( x264_pthread_t *t, void *a, void *(*f)(vo return 0; } #define x264_pthread_join(t,s) { long tmp; \ - wait_for_thread(t,(s)?(long*)(*(s)):&tmp); } + wait_for_thread(t,(s)?(long*)(s):&tmp); } #elif HAVE_POSIXTHREAD #include @@ -252,6 +254,13 @@ static ALWAYS_INLINE uint16_t endian_fix16( uint16_t x ) } #endif +/* For values with 4 bits or less. */ +static int ALWAYS_INLINE x264_ctz_4bit( uint32_t x ) +{ + static uint8_t lut[16] = {4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0}; + return lut[x]; +} + #if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 3) #define x264_clz(x) __builtin_clz(x) #define x264_ctz(x) __builtin_ctz(x) diff --git a/common/pixel.c b/common/pixel.c index 9f52c79c..4588a697 100644 --- a/common/pixel.c +++ b/common/pixel.c @@ -1,7 +1,7 @@ /***************************************************************************** * pixel.c: pixel metrics ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Loren Merritt * Laurent Aimar @@ -370,7 +370,6 @@ static int x264_pixel_sa8d_16x16( pixel *pix1, intptr_t i_pix1, pixel *pix2, int return (sum+2)>>2; } - static NOINLINE uint64_t pixel_hadamard_ac( pixel *pix, intptr_t stride ) { sum2_t tmp[32]; @@ -501,6 +500,7 @@ SATD_X_DECL7( _mmx2 ) #if !HIGH_BIT_DEPTH SATD_X_DECL6( _sse2 ) SATD_X_DECL7( _ssse3 ) +SATD_X_DECL6( _ssse3_atom ) SATD_X_DECL7( _sse4 ) SATD_X_DECL7( _avx ) SATD_X_DECL7( _xop ) @@ -528,6 +528,7 @@ void x264_intra_##mbcmp##_x3_8x8##cpu( pixel *fenc, pixel edge[36], int res[3] ) INTRA_MBCMP_8x8( sad,, _c ) INTRA_MBCMP_8x8(sa8d,, _c ) #if HIGH_BIT_DEPTH && HAVE_MMX +#define x264_predict_8x8_v_sse2 x264_predict_8x8_v_sse INTRA_MBCMP_8x8( sad, _mmx2, _c ) INTRA_MBCMP_8x8(sa8d, _sse2, _sse2 ) #endif @@ -554,6 +555,9 @@ INTRA_MBCMP(satd, 16x16, v, h, dc, ,, _c ) #if HAVE_MMX #if HIGH_BIT_DEPTH +#define x264_predict_8x8c_v_sse2 x264_predict_8x8c_v_sse +#define x264_predict_8x16c_v_sse2 x264_predict_8x16c_v_sse +#define x264_predict_16x16_v_sse2 x264_predict_16x16_v_sse INTRA_MBCMP( sad, 4x4, v, h, dc, , _mmx2, _c ) INTRA_MBCMP( sad, 8x8, dc, h, v, c, _mmx2, _c ) INTRA_MBCMP( sad, 16x16, v, h, dc, , _mmx2, _mmx2 ) @@ -703,6 +707,15 @@ int x264_field_vsad( x264_t *h, int mb_x, int mb_y ) return (score_field < score_frame); } +static int pixel_asd8( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2, int height ) +{ + int sum = 0; + for( int y = 0; y < height; y++, pix1 += stride1, pix2 += stride2 ) + for( int x = 0; x < 8; x++ ) + sum += pix1[x] - pix2[x]; + return abs( sum ); +} + /**************************************************************************** * successive elimination ****************************************************************************/ @@ -814,6 +827,7 @@ void x264_pixel_init( int cpu, x264_pixel_function_t *pixf ) pixf->ssim_4x4x2_core = ssim_4x4x2_core; pixf->ssim_end4 = ssim_end4; pixf->vsad = pixel_vsad; + pixf->asd8 = pixel_asd8; pixf->intra_sad_x3_4x4 = x264_intra_sad_x3_4x4; pixf->intra_satd_x3_4x4 = x264_intra_satd_x3_4x4; @@ -860,11 +874,14 @@ void x264_pixel_init( int cpu, x264_pixel_function_t *pixf ) { INIT4_NAME( sad_aligned, sad, _sse2_aligned ); INIT5( ssd, _sse2 ); + INIT6( satd, _sse2 ); + pixf->satd[PIXEL_4x16] = x264_pixel_satd_4x16_sse2; pixf->sa8d[PIXEL_16x16] = x264_pixel_sa8d_16x16_sse2; pixf->sa8d[PIXEL_8x8] = x264_pixel_sa8d_8x8_sse2; #if ARCH_X86_64 pixf->intra_sa8d_x3_8x8 = x264_intra_sa8d_x3_8x8_sse2; + pixf->sa8d_satd[PIXEL_16x16] = x264_pixel_sa8d_satd_16x16_sse2; #endif pixf->intra_sad_x3_4x4 = x264_intra_sad_x3_4x4_sse2; pixf->ssd_nv12_core = x264_pixel_ssd_nv12_core_sse2; @@ -888,6 +905,7 @@ void x264_pixel_init( int cpu, x264_pixel_function_t *pixf ) INIT4( hadamard_ac, _sse2 ); } pixf->vsad = x264_pixel_vsad_sse2; + pixf->asd8 = x264_pixel_asd8_sse2; pixf->intra_sad_x3_8x8 = x264_intra_sad_x3_8x8_sse2; pixf->intra_sad_x3_8x8c = x264_intra_sad_x3_8x8c_sse2; pixf->intra_sad_x3_16x16 = x264_intra_sad_x3_16x16_sse2; @@ -909,15 +927,21 @@ void x264_pixel_init( int cpu, x264_pixel_function_t *pixf ) INIT7( sad_x3, _ssse3 ); INIT7( sad_x4, _ssse3 ); INIT_ADS( _ssse3 ); + INIT6( satd, _ssse3 ); + pixf->satd[PIXEL_4x16] = x264_pixel_satd_4x16_ssse3; if( !(cpu&X264_CPU_STACK_MOD4) ) { INIT4( hadamard_ac, _ssse3 ); } pixf->vsad = x264_pixel_vsad_ssse3; + pixf->asd8 = x264_pixel_asd8_ssse3; pixf->intra_sad_x3_4x4 = x264_intra_sad_x3_4x4_ssse3; pixf->sa8d[PIXEL_16x16]= x264_pixel_sa8d_16x16_ssse3; pixf->sa8d[PIXEL_8x8] = x264_pixel_sa8d_8x8_ssse3; +#if ARCH_X86_64 + pixf->sa8d_satd[PIXEL_16x16] = x264_pixel_sa8d_satd_16x16_ssse3; +#endif pixf->intra_sad_x3_4x4 = x264_intra_sad_x3_4x4_ssse3; pixf->intra_sad_x3_8x8 = x264_intra_sad_x3_8x8_ssse3; pixf->intra_sad_x3_8x8c = x264_intra_sad_x3_8x8c_ssse3; @@ -925,16 +949,23 @@ void x264_pixel_init( int cpu, x264_pixel_function_t *pixf ) } if( cpu&X264_CPU_SSE4 ) { + INIT6( satd, _sse4 ); + pixf->satd[PIXEL_4x16] = x264_pixel_satd_4x16_sse4; if( !(cpu&X264_CPU_STACK_MOD4) ) { INIT4( hadamard_ac, _sse4 ); } pixf->sa8d[PIXEL_16x16]= x264_pixel_sa8d_16x16_sse4; pixf->sa8d[PIXEL_8x8] = x264_pixel_sa8d_8x8_sse4; +#if ARCH_X86_64 + pixf->sa8d_satd[PIXEL_16x16] = x264_pixel_sa8d_satd_16x16_sse4; +#endif } if( cpu&X264_CPU_AVX ) { INIT_ADS( _avx ); + INIT6( satd, _avx ); + pixf->satd[PIXEL_4x16] = x264_pixel_satd_4x16_avx; if( !(cpu&X264_CPU_STACK_MOD4) ) { INIT4( hadamard_ac, _avx ); @@ -947,10 +978,14 @@ void x264_pixel_init( int cpu, x264_pixel_function_t *pixf ) pixf->ssd_nv12_core = x264_pixel_ssd_nv12_core_avx; pixf->ssim_4x4x2_core = x264_pixel_ssim_4x4x2_core_avx; pixf->ssim_end4 = x264_pixel_ssim_end4_avx; +#if ARCH_X86_64 + pixf->sa8d_satd[PIXEL_16x16] = x264_pixel_sa8d_satd_16x16_avx; +#endif } if( cpu&X264_CPU_XOP ) { pixf->vsad = x264_pixel_vsad_xop; + pixf->asd8 = x264_pixel_asd8_xop; } #endif // HAVE_MMX #else // !HIGH_BIT_DEPTH @@ -990,14 +1025,14 @@ void x264_pixel_init( int cpu, x264_pixel_function_t *pixf ) INIT4( sad_x3, _cache32_mmx2 ); INIT4( sad_x4, _cache32_mmx2 ); } - else if( cpu&X264_CPU_CACHELINE_64 ) + else if( cpu&X264_CPU_CACHELINE_64 && !(cpu&X264_CPU_SLOW_ATOM) ) { INIT5( sad, _cache64_mmx2 ); INIT4( sad_x3, _cache64_mmx2 ); INIT4( sad_x4, _cache64_mmx2 ); } #else - if( cpu&X264_CPU_CACHELINE_64 ) + if( cpu&X264_CPU_CACHELINE_64 && !(cpu&X264_CPU_SLOW_ATOM) ) { pixf->sad[PIXEL_8x16] = x264_pixel_sad_8x16_cache64_mmx2; pixf->sad[PIXEL_8x8] = x264_pixel_sad_8x8_cache64_mmx2; @@ -1031,10 +1066,12 @@ void x264_pixel_init( int cpu, x264_pixel_function_t *pixf ) pixf->sa8d[PIXEL_8x8] = x264_pixel_sa8d_8x8_sse2; #if ARCH_X86_64 pixf->intra_sa8d_x3_8x8 = x264_intra_sa8d_x3_8x8_sse2; + pixf->sa8d_satd[PIXEL_16x16] = x264_pixel_sa8d_satd_16x16_sse2; #endif pixf->var2[PIXEL_8x8] = x264_pixel_var2_8x8_sse2; pixf->var2[PIXEL_8x16] = x264_pixel_var2_8x16_sse2; pixf->vsad = x264_pixel_vsad_sse2; + pixf->asd8 = x264_pixel_asd8_sse2; } if( (cpu&X264_CPU_SSE2) && !(cpu&X264_CPU_SSE2_IS_SLOW) ) @@ -1110,7 +1147,20 @@ void x264_pixel_init( int cpu, x264_pixel_function_t *pixf ) #endif } INIT_ADS( _ssse3 ); - if( !(cpu&X264_CPU_SLOW_ATOM) ) + if( cpu&X264_CPU_SLOW_ATOM ) + { + pixf->sa8d[PIXEL_16x16]= x264_pixel_sa8d_16x16_ssse3_atom; + pixf->sa8d[PIXEL_8x8] = x264_pixel_sa8d_8x8_ssse3_atom; + INIT6( satd, _ssse3_atom ); + pixf->satd[PIXEL_4x16] = x264_pixel_satd_4x16_ssse3_atom; + INIT6( satd_x3, _ssse3_atom ); + INIT6( satd_x4, _ssse3_atom ); + INIT4( hadamard_ac, _ssse3_atom ); +#if ARCH_X86_64 + pixf->sa8d_satd[PIXEL_16x16] = x264_pixel_sa8d_satd_16x16_ssse3_atom; +#endif + } + else { INIT8( ssd, _ssse3 ); pixf->sa8d[PIXEL_16x16]= x264_pixel_sa8d_16x16_ssse3; @@ -1118,21 +1168,26 @@ void x264_pixel_init( int cpu, x264_pixel_function_t *pixf ) INIT8( satd, _ssse3 ); INIT7( satd_x3, _ssse3 ); INIT7( satd_x4, _ssse3 ); +#if ARCH_X86_64 + pixf->sa8d_satd[PIXEL_16x16] = x264_pixel_sa8d_satd_16x16_ssse3; +#endif } pixf->intra_satd_x3_16x16 = x264_intra_satd_x3_16x16_ssse3; - pixf->intra_sad_x3_16x16 = x264_intra_sad_x3_16x16_ssse3; + if( !(cpu&X264_CPU_SLOW_PSHUFB) ) + pixf->intra_sad_x3_16x16 = x264_intra_sad_x3_16x16_ssse3; pixf->intra_satd_x3_8x16c = x264_intra_satd_x3_8x16c_ssse3; pixf->intra_satd_x3_8x8c = x264_intra_satd_x3_8x8c_ssse3; pixf->intra_sad_x3_8x8c = x264_intra_sad_x3_8x8c_ssse3; pixf->var2[PIXEL_8x8] = x264_pixel_var2_8x8_ssse3; pixf->var2[PIXEL_8x16] = x264_pixel_var2_8x16_ssse3; + pixf->asd8 = x264_pixel_asd8_ssse3; if( cpu&X264_CPU_CACHELINE_64 ) { INIT2( sad, _cache64_ssse3 ); INIT2( sad_x3, _cache64_ssse3 ); INIT2( sad_x4, _cache64_ssse3 ); } - if( cpu&X264_CPU_SLOW_ATOM || !(cpu&X264_CPU_SHUFFLE_IS_FAST) ) + if( (cpu&X264_CPU_SLOW_ATOM) || (cpu&X264_CPU_SLOW_SHUFFLE) ) { INIT5( ssd, _sse2 ); /* on conroe, sse2 is faster for width8/16 */ } @@ -1156,6 +1211,9 @@ void x264_pixel_init( int cpu, x264_pixel_function_t *pixf ) pixf->sa8d[PIXEL_16x16]= x264_pixel_sa8d_16x16_sse4; pixf->sa8d[PIXEL_8x8] = x264_pixel_sa8d_8x8_sse4; pixf->intra_satd_x3_8x16c = x264_intra_satd_x3_8x16c_sse4; +#if ARCH_X86_64 + pixf->sa8d_satd[PIXEL_16x16] = x264_pixel_sa8d_satd_16x16_sse4; +#endif } if( cpu&X264_CPU_AVX ) @@ -1184,6 +1242,9 @@ void x264_pixel_init( int cpu, x264_pixel_function_t *pixf ) pixf->var[PIXEL_8x8] = x264_pixel_var_8x8_avx; pixf->ssim_4x4x2_core = x264_pixel_ssim_4x4x2_core_avx; pixf->ssim_end4 = x264_pixel_ssim_end4_avx; +#if ARCH_X86_64 + pixf->sa8d_satd[PIXEL_16x16] = x264_pixel_sa8d_satd_16x16_avx; +#endif } if( cpu&X264_CPU_XOP ) @@ -1205,6 +1266,9 @@ void x264_pixel_init( int cpu, x264_pixel_function_t *pixf ) pixf->var[PIXEL_8x8] = x264_pixel_var_8x8_xop; pixf->var2[PIXEL_8x8] = x264_pixel_var2_8x8_xop; pixf->var2[PIXEL_8x16] = x264_pixel_var2_8x16_xop; +#if ARCH_X86_64 + pixf->sa8d_satd[PIXEL_16x16] = x264_pixel_sa8d_satd_16x16_xop; +#endif } #endif //HAVE_MMX diff --git a/common/pixel.h b/common/pixel.h index 1375b90d..6da14f6b 100644 --- a/common/pixel.h +++ b/common/pixel.h @@ -1,7 +1,7 @@ /***************************************************************************** * pixel.c: pixel metrics ***************************************************************************** - * Copyright (C) 2004-2012 x264 project + * Copyright (C) 2004-2013 x264 project * * Authors: Loren Merritt * Jason Garrett-Glaser @@ -89,6 +89,8 @@ typedef struct x264_pixel_cmp_x4_t fpelcmp_x4[7]; x264_pixel_cmp_t sad_aligned[8]; /* Aligned SAD for mbcmp */ int (*vsad)( pixel *, intptr_t, int ); + int (*asd8)( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2, int height ); + uint64_t (*sa8d_satd[1])( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2 ); uint64_t (*var[4])( pixel *pix, intptr_t stride ); int (*var2[4])( pixel *pix1, intptr_t stride1, diff --git a/common/ppc/dct.c b/common/ppc/dct.c index 37a077d6..8420ad21 100644 --- a/common/ppc/dct.c +++ b/common/ppc/dct.c @@ -1,7 +1,7 @@ /***************************************************************************** * dct.c: ppc transform and zigzag ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Guillaume Poirier * Eric Petit diff --git a/common/ppc/dct.h b/common/ppc/dct.h index f7684bea..3ac841a9 100644 --- a/common/ppc/dct.h +++ b/common/ppc/dct.h @@ -1,7 +1,7 @@ /***************************************************************************** * dct.h: ppc transform and zigzag ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Eric Petit * Guillaume Poirier diff --git a/common/ppc/deblock.c b/common/ppc/deblock.c index dea872ba..bddd2e41 100644 --- a/common/ppc/deblock.c +++ b/common/ppc/deblock.c @@ -1,7 +1,7 @@ /***************************************************************************** * deblock.c: ppc deblocking ***************************************************************************** - * Copyright (C) 2007-2012 x264 project + * Copyright (C) 2007-2013 x264 project * * Authors: Guillaume Poirier * diff --git a/common/ppc/mc.c b/common/ppc/mc.c index 2e720f47..437c7d06 100644 --- a/common/ppc/mc.c +++ b/common/ppc/mc.c @@ -1,7 +1,7 @@ /***************************************************************************** * mc.c: ppc motion compensation ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Eric Petit * Guillaume Poirier diff --git a/common/ppc/mc.h b/common/ppc/mc.h index fafe56bc..a996ae7b 100644 --- a/common/ppc/mc.h +++ b/common/ppc/mc.h @@ -1,7 +1,7 @@ /***************************************************************************** * mc.h: ppc motion compensation ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Eric Petit * diff --git a/common/ppc/pixel.c b/common/ppc/pixel.c index 585bc197..4d322843 100644 --- a/common/ppc/pixel.c +++ b/common/ppc/pixel.c @@ -1,7 +1,7 @@ /***************************************************************************** * pixel.c: ppc pixel metrics ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Eric Petit * Guillaume Poirier diff --git a/common/ppc/pixel.h b/common/ppc/pixel.h index 87a43c18..62e8cfc4 100644 --- a/common/ppc/pixel.h +++ b/common/ppc/pixel.h @@ -1,7 +1,7 @@ /***************************************************************************** * pixel.h: ppc pixel metrics ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Eric Petit * diff --git a/common/ppc/ppccommon.h b/common/ppc/ppccommon.h index 52af6c50..f88d3608 100644 --- a/common/ppc/ppccommon.h +++ b/common/ppc/ppccommon.h @@ -1,7 +1,7 @@ /***************************************************************************** * ppccommon.h: ppc utility macros ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Eric Petit * diff --git a/common/ppc/predict.c b/common/ppc/predict.c index 4a1904c8..69fe2224 100644 --- a/common/ppc/predict.c +++ b/common/ppc/predict.c @@ -1,7 +1,7 @@ /***************************************************************************** * predict.c: ppc intra prediction ***************************************************************************** - * Copyright (C) 2007-2012 x264 project + * Copyright (C) 2007-2013 x264 project * * Authors: Guillaume Poirier * diff --git a/common/ppc/predict.h b/common/ppc/predict.h index ccc230ea..9082ca55 100644 --- a/common/ppc/predict.h +++ b/common/ppc/predict.h @@ -1,7 +1,7 @@ /***************************************************************************** * predict.h: ppc intra prediction ***************************************************************************** - * Copyright (C) 2007-2012 x264 project + * Copyright (C) 2007-2013 x264 project * * Authors: Guillaume Poirier * diff --git a/common/ppc/quant.c b/common/ppc/quant.c index 9fa0ee94..f11938af 100644 --- a/common/ppc/quant.c +++ b/common/ppc/quant.c @@ -1,7 +1,7 @@ /***************************************************************************** * quant.c: ppc quantization ***************************************************************************** - * Copyright (C) 2007-2012 x264 project + * Copyright (C) 2007-2013 x264 project * * Authors: Guillaume Poirier * diff --git a/common/ppc/quant.h b/common/ppc/quant.h index 59c29f9a..1f789c35 100644 --- a/common/ppc/quant.h +++ b/common/ppc/quant.h @@ -1,7 +1,7 @@ /***************************************************************************** * quant.c: ppc quantization ***************************************************************************** - * Copyright (C) 2007-2012 x264 project + * Copyright (C) 2007-2013 x264 project * * Authors: Guillaume Poirier * diff --git a/common/predict.c b/common/predict.c index 06996966..94f5d1cc 100644 --- a/common/predict.c +++ b/common/predict.c @@ -1,7 +1,7 @@ /***************************************************************************** * predict.c: intra prediction ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Laurent Aimar * Loren Merritt diff --git a/common/predict.h b/common/predict.h index 33b95366..957c3aba 100644 --- a/common/predict.h +++ b/common/predict.h @@ -1,7 +1,7 @@ /***************************************************************************** * predict.h: intra prediction ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Loren Merritt * Laurent Aimar diff --git a/common/quant.c b/common/quant.c index 17a6e1c6..4a17fc76 100644 --- a/common/quant.c +++ b/common/quant.c @@ -1,7 +1,7 @@ /***************************************************************************** * quant.c: quantization and level-run ***************************************************************************** - * Copyright (C) 2005-2012 x264 project + * Copyright (C) 2005-2013 x264 project * * Authors: Loren Merritt * Jason Garrett-Glaser @@ -63,6 +63,19 @@ static int quant_4x4( dctcoef dct[16], udctcoef mf[16], udctcoef bias[16] ) return !!nz; } +static int quant_4x4x4( dctcoef dct[4][16], udctcoef mf[16], udctcoef bias[16] ) +{ + int nza = 0; + for( int j = 0; j < 4; j++ ) + { + int nz = 0; + for( int i = 0; i < 16; i++ ) + QUANT_ONE( dct[j][i], mf[i], bias[i] ); + nza |= (!!nz)<quant_8x8 = quant_8x8; pf->quant_4x4 = quant_4x4; + pf->quant_4x4x4 = quant_4x4x4; pf->quant_4x4_dc = quant_4x4_dc; pf->quant_2x2_dc = quant_2x2_dc; @@ -464,6 +478,7 @@ void x264_quant_init( x264_t *h, int cpu, x264_quant_function_t *pf ) if( cpu&X264_CPU_SSE2 ) { pf->quant_4x4 = x264_quant_4x4_sse2; + pf->quant_4x4x4 = x264_quant_4x4x4_sse2; pf->quant_8x8 = x264_quant_8x8_sse2; pf->quant_2x2_dc = x264_quant_2x2_dc_sse2; pf->quant_4x4_dc = x264_quant_4x4_dc_sse2; @@ -501,6 +516,7 @@ void x264_quant_init( x264_t *h, int cpu, x264_quant_function_t *pf ) if( cpu&X264_CPU_SSSE3 ) { pf->quant_4x4 = x264_quant_4x4_ssse3; + pf->quant_4x4x4 = x264_quant_4x4x4_ssse3; pf->quant_8x8 = x264_quant_8x8_ssse3; pf->quant_2x2_dc = x264_quant_2x2_dc_ssse3; pf->quant_4x4_dc = x264_quant_4x4_dc_ssse3; @@ -520,6 +536,7 @@ void x264_quant_init( x264_t *h, int cpu, x264_quant_function_t *pf ) pf->quant_2x2_dc = x264_quant_2x2_dc_sse4; pf->quant_4x4_dc = x264_quant_4x4_dc_sse4; pf->quant_4x4 = x264_quant_4x4_sse4; + pf->quant_4x4x4 = x264_quant_4x4x4_sse4; pf->quant_8x8 = x264_quant_8x8_sse4; } if( cpu&X264_CPU_AVX ) @@ -543,6 +560,7 @@ void x264_quant_init( x264_t *h, int cpu, x264_quant_function_t *pf ) { #if ARCH_X86 pf->quant_4x4 = x264_quant_4x4_mmx; + pf->quant_4x4x4 = x264_quant_4x4x4_mmx; pf->quant_8x8 = x264_quant_8x8_mmx; pf->dequant_4x4 = x264_dequant_4x4_mmx; pf->dequant_4x4_dc = x264_dequant_4x4dc_mmx2; @@ -592,6 +610,7 @@ void x264_quant_init( x264_t *h, int cpu, x264_quant_function_t *pf ) { pf->quant_4x4_dc = x264_quant_4x4_dc_sse2; pf->quant_4x4 = x264_quant_4x4_sse2; + pf->quant_4x4x4 = x264_quant_4x4x4_sse2; pf->quant_8x8 = x264_quant_8x8_sse2; pf->dequant_4x4 = x264_dequant_4x4_sse2; pf->dequant_4x4_dc = x264_dequant_4x4dc_sse2; @@ -631,6 +650,7 @@ void x264_quant_init( x264_t *h, int cpu, x264_quant_function_t *pf ) pf->quant_2x2_dc = x264_quant_2x2_dc_ssse3; pf->quant_4x4_dc = x264_quant_4x4_dc_ssse3; pf->quant_4x4 = x264_quant_4x4_ssse3; + pf->quant_4x4x4 = x264_quant_4x4x4_ssse3; pf->quant_8x8 = x264_quant_8x8_ssse3; pf->optimize_chroma_2x2_dc = x264_optimize_chroma_2x2_dc_ssse3; pf->denoise_dct = x264_denoise_dct_ssse3; @@ -696,6 +716,7 @@ void x264_quant_init( x264_t *h, int cpu, x264_quant_function_t *pf ) pf->quant_2x2_dc = x264_quant_2x2_dc_neon; pf->quant_4x4 = x264_quant_4x4_neon; pf->quant_4x4_dc = x264_quant_4x4_dc_neon; + pf->quant_4x4x4 = x264_quant_4x4x4_neon; pf->quant_8x8 = x264_quant_8x8_neon; pf->dequant_4x4 = x264_dequant_4x4_neon; pf->dequant_4x4_dc = x264_dequant_4x4_dc_neon; diff --git a/common/quant.h b/common/quant.h index 290705cf..bed93e42 100644 --- a/common/quant.h +++ b/common/quant.h @@ -1,7 +1,7 @@ /***************************************************************************** * quant.h: quantization and level-run ***************************************************************************** - * Copyright (C) 2005-2012 x264 project + * Copyright (C) 2005-2013 x264 project * * Authors: Loren Merritt * Jason Garrett-Glaser @@ -29,8 +29,9 @@ typedef struct { - int (*quant_8x8)( dctcoef dct[64], udctcoef mf[64], udctcoef bias[64] ); - int (*quant_4x4)( dctcoef dct[16], udctcoef mf[16], udctcoef bias[16] ); + int (*quant_8x8) ( dctcoef dct[64], udctcoef mf[64], udctcoef bias[64] ); + int (*quant_4x4) ( dctcoef dct[16], udctcoef mf[16], udctcoef bias[16] ); + int (*quant_4x4x4)( dctcoef dct[4][16], udctcoef mf[16], udctcoef bias[16] ); int (*quant_4x4_dc)( dctcoef dct[16], int mf, int bias ); int (*quant_2x2_dc)( dctcoef dct[4], int mf, int bias ); diff --git a/common/rectangle.c b/common/rectangle.c index ff584c3c..5b657f25 100644 --- a/common/rectangle.c +++ b/common/rectangle.c @@ -1,7 +1,7 @@ /***************************************************************************** * rectangle.c: rectangle filling ***************************************************************************** - * Copyright (C) 2010-2012 x264 project + * Copyright (C) 2010-2013 x264 project * * Authors: Jason Garrett-Glaser * diff --git a/common/rectangle.h b/common/rectangle.h index 21dd7c99..6e718be2 100644 --- a/common/rectangle.h +++ b/common/rectangle.h @@ -1,7 +1,7 @@ /***************************************************************************** * rectangle.h: rectangle filling ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Jason Garrett-Glaser * Loren Merritt diff --git a/common/set.c b/common/set.c index 56da025f..4c721255 100644 --- a/common/set.c +++ b/common/set.c @@ -1,7 +1,7 @@ /***************************************************************************** * set.c: quantization init ***************************************************************************** - * Copyright (C) 2005-2012 x264 project + * Copyright (C) 2005-2013 x264 project * * Authors: Loren Merritt * @@ -241,7 +241,7 @@ int x264_cqm_init( x264_t *h ) if( !h->mb.b_lossless ) { - while( h->chroma_qp_table[h->param.rc.i_qp_min] <= max_chroma_qp_err ) + while( h->chroma_qp_table[SPEC_QP(h->param.rc.i_qp_min)] <= max_chroma_qp_err ) h->param.rc.i_qp_min++; if( min_qp_err <= h->param.rc.i_qp_max ) h->param.rc.i_qp_max = min_qp_err-1; diff --git a/common/set.h b/common/set.h index d68e8bf8..b41ad5c8 100644 --- a/common/set.h +++ b/common/set.h @@ -1,7 +1,7 @@ /***************************************************************************** * set.h: quantization init ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Loren Merritt * Laurent Aimar @@ -31,7 +31,6 @@ enum profile_e { PROFILE_BASELINE = 66, PROFILE_MAIN = 77, - PROFILE_EXTENDED = 88, PROFILE_HIGH = 100, PROFILE_HIGH10 = 110, PROFILE_HIGH422 = 122, diff --git a/common/sparc/pixel.asm b/common/sparc/pixel.asm index b3e4a36d..ba21273c 100644 --- a/common/sparc/pixel.asm +++ b/common/sparc/pixel.asm @@ -1,7 +1,7 @@ /***************************************************************************** * pixel.asm: sparc pixel metrics ***************************************************************************** - * Copyright (C) 2005-2012 x264 project + * Copyright (C) 2005-2013 x264 project * * Authors: Phil Jensen * diff --git a/common/sparc/pixel.h b/common/sparc/pixel.h index 0c762d4a..600b05d5 100644 --- a/common/sparc/pixel.h +++ b/common/sparc/pixel.h @@ -1,7 +1,7 @@ /***************************************************************************** * pixel.h: sparc pixel metrics ***************************************************************************** - * Copyright (C) 2005-2012 x264 project + * Copyright (C) 2005-2013 x264 project * * Authors: Phil Jensen * diff --git a/common/threadpool.c b/common/threadpool.c index f7a95fcc..303349a4 100644 --- a/common/threadpool.c +++ b/common/threadpool.c @@ -1,7 +1,7 @@ /***************************************************************************** * threadpool.c: thread pooling ***************************************************************************** - * Copyright (C) 2010-2012 x264 project + * Copyright (C) 2010-2013 x264 project * * Authors: Steven Walters * @@ -47,7 +47,7 @@ struct x264_threadpool_t x264_sync_frame_list_t done; /* list of jobs that have finished processing */ }; -static void x264_threadpool_thread( x264_threadpool_t *pool ) +static void *x264_threadpool_thread( x264_threadpool_t *pool ) { if( pool->init_func ) pool->init_func( pool->init_arg ); @@ -66,9 +66,10 @@ static void x264_threadpool_thread( x264_threadpool_t *pool ) x264_pthread_mutex_unlock( &pool->run.mutex ); if( !job ) continue; - job->ret = job->func( job->arg ); /* execute the function */ + job->ret = (void*)x264_stack_align( job->func, job->arg ); /* execute the function */ x264_sync_frame_list_push( &pool->done, (void*)job ); } + return NULL; } int x264_threadpool_init( x264_threadpool_t **p_pool, int threads, @@ -83,7 +84,7 @@ int x264_threadpool_init( x264_threadpool_t **p_pool, int threads, pool->init_func = init_func; pool->init_arg = init_arg; - pool->threads = X264_MIN( threads, X264_THREAD_MAX ); + pool->threads = threads; CHECKED_MALLOC( pool->thread_handle, pool->threads * sizeof(x264_pthread_t) ); diff --git a/common/threadpool.h b/common/threadpool.h index 92a77e83..2941458b 100644 --- a/common/threadpool.h +++ b/common/threadpool.h @@ -1,7 +1,7 @@ /***************************************************************************** * threadpool.h: thread pooling ***************************************************************************** - * Copyright (C) 2010-2012 x264 project + * Copyright (C) 2010-2013 x264 project * * Authors: Steven Walters * diff --git a/common/visualize.c b/common/visualize.c index 8f9e571f..9e80afbf 100644 --- a/common/visualize.c +++ b/common/visualize.c @@ -1,7 +1,7 @@ /***************************************************************************** * visualize.c: visualization ***************************************************************************** - * Copyright (C) 2005-2012 x264 project + * Copyright (C) 2005-2013 x264 project * * Authors: Tuukka Toivonen * diff --git a/common/visualize.h b/common/visualize.h index d07e2d65..8655adf0 100644 --- a/common/visualize.h +++ b/common/visualize.h @@ -1,7 +1,7 @@ /***************************************************************************** * visualize.h: visualization ***************************************************************************** - * Copyright (C) 2005-2012 x264 project + * Copyright (C) 2005-2013 x264 project * * Authors: Tuukka Toivonen * diff --git a/common/vlc.c b/common/vlc.c index 8af36de1..f2425ec9 100644 --- a/common/vlc.c +++ b/common/vlc.c @@ -1,7 +1,7 @@ /***************************************************************************** * vlc.c : vlc tables ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Laurent Aimar * Jason Garrett-Glaser diff --git a/common/win32thread.c b/common/win32thread.c index a81cd6cf..4be914f1 100644 --- a/common/win32thread.c +++ b/common/win32thread.c @@ -1,7 +1,7 @@ /***************************************************************************** * win32thread.c: windows threading ***************************************************************************** - * Copyright (C) 2010-2012 x264 project + * Copyright (C) 2010-2013 x264 project * * Authors: Steven Walters * Pegasys Inc. @@ -62,7 +62,7 @@ static x264_win32thread_control_t thread_control; static unsigned __stdcall x264_win32thread_worker( void *arg ) { x264_pthread_t *h = arg; - h->ret = h->func( h->arg ); + *h->p_ret = h->func( h->arg ); return 0; } @@ -71,6 +71,8 @@ int x264_pthread_create( x264_pthread_t *thread, const x264_pthread_attr_t *attr { thread->func = start_routine; thread->arg = arg; + thread->p_ret = &thread->ret; + thread->ret = NULL; thread->handle = (void*)_beginthreadex( NULL, 0, x264_win32thread_worker, thread, 0, NULL ); return !thread->handle; } @@ -81,7 +83,7 @@ int x264_pthread_join( x264_pthread_t thread, void **value_ptr ) if( ret != WAIT_OBJECT_0 ) return -1; if( value_ptr ) - *value_ptr = thread.ret; + *value_ptr = *thread.p_ret; CloseHandle( thread.handle ); return 0; } @@ -277,7 +279,7 @@ void x264_win32_threading_destroy( void ) memset( &thread_control, 0, sizeof(x264_win32thread_control_t) ); } -int x264_pthread_num_processors_np() +int x264_pthread_num_processors_np( void ) { DWORD_PTR system_cpus, process_cpus = 0; int cpus = 0; diff --git a/common/win32thread.h b/common/win32thread.h index d6370a77..844b18ab 100644 --- a/common/win32thread.h +++ b/common/win32thread.h @@ -1,7 +1,7 @@ /***************************************************************************** * win32thread.h: windows threading ***************************************************************************** - * Copyright (C) 2010-2012 x264 project + * Copyright (C) 2010-2013 x264 project * * Authors: Steven Walters * @@ -36,6 +36,7 @@ typedef struct void *handle; void *(*func)( void* arg ); void *arg; + void **p_ret; void *ret; } x264_pthread_t; #define x264_pthread_attr_t int diff --git a/common/x86/bitstream-a.asm b/common/x86/bitstream-a.asm index c2aaf792..16061f22 100644 --- a/common/x86/bitstream-a.asm +++ b/common/x86/bitstream-a.asm @@ -1,7 +1,7 @@ ;***************************************************************************** ;* bitstream-a.asm: x86 bitstream functions ;***************************************************************************** -;* Copyright (C) 2010-2012 x264 project +;* Copyright (C) 2010-2013 x264 project ;* ;* Authors: Jason Garrett-Glaser ;* Henrik Gramner diff --git a/common/x86/cabac-a.asm b/common/x86/cabac-a.asm index d57bd956..d95d1254 100644 --- a/common/x86/cabac-a.asm +++ b/common/x86/cabac-a.asm @@ -1,7 +1,7 @@ ;***************************************************************************** ;* cabac-a.asm: x86 cabac ;***************************************************************************** -;* Copyright (C) 2008-2012 x264 project +;* Copyright (C) 2008-2013 x264 project ;* ;* Authors: Loren Merritt ;* Jason Garrett-Glaser @@ -35,7 +35,7 @@ cextern cabac_renorm_shift ; t3 must be ecx, since it's used for shift. %if WIN64 - DECLARE_REG_TMP 3,1,2,0,6,5,4,2 + DECLARE_REG_TMP 3,1,2,0,5,6,4,4 %define pointer resq %elif ARCH_X86_64 DECLARE_REG_TMP 0,1,2,3,4,5,6,6 @@ -58,24 +58,24 @@ struc cb .state: resb 1024 endstruc -%macro LOAD_GLOBAL 4 +%macro LOAD_GLOBAL 3-5 0 ; dst, base, off1, off2, tmp %ifdef PIC - ; this would be faster if the arrays were declared in asm, so that I didn't have to duplicate the lea - lea r7, [%2] - %ifnidn %3, 0 - add r7, %3 + %ifidn %4, 0 + movzx %1, byte [%2+%3+r7-$$] + %else + lea %5, [r7+%4] + movzx %1, byte [%2+%3+%5-$$] %endif - movzx %1, byte [r7+%4] %else movzx %1, byte [%2+%3+%4] %endif %endmacro -cglobal cabac_encode_decision_asm, 0,7 - movifnidn t0, r0mp +cglobal cabac_encode_decision_asm, 1,7 movifnidn t1d, r1m - mov t5d, [t0+cb.range] - movzx t6d, byte [t0+cb.state+t1] + mov t5d, [r0+cb.range] + movzx t6d, byte [r0+cb.state+t1] + movifnidn t0, r0 ; WIN64 mov t4d, ~1 mov t3d, t5d and t4d, t6d @@ -84,8 +84,11 @@ cglobal cabac_encode_decision_asm, 0,7 %if WIN64 PUSH r7 %endif - LOAD_GLOBAL t5d, cabac_range_lps-4, t5, t4*2 - LOAD_GLOBAL t4d, cabac_transition, t2, t6*2 +%ifdef PIC + lea r7, [$$] +%endif + LOAD_GLOBAL t5d, cabac_range_lps-4, t5, t4*2, t4 + LOAD_GLOBAL t4d, cabac_transition, t2, t6*2, t4 and t6d, 1 sub t3d, t5d cmp t6d, t2d @@ -97,7 +100,7 @@ cglobal cabac_encode_decision_asm, 0,7 ;cabac_encode_renorm mov t4d, t3d shr t3d, 3 - LOAD_GLOBAL t3d, cabac_renorm_shift, 0, t3 + LOAD_GLOBAL t3d, cabac_renorm_shift, t3 %if WIN64 POP r7 %endif @@ -111,15 +114,14 @@ cglobal cabac_encode_decision_asm, 0,7 mov [t0+cb.queue], t3d RET -cglobal cabac_encode_bypass_asm, 0,3 - movifnidn t0, r0mp - movifnidn t3d, r1m - mov t7d, [t0+cb.low] - and t3d, [t0+cb.range] - lea t7d, [t7*2+t3] - mov t3d, [t0+cb.queue] +cglobal cabac_encode_bypass_asm, 2,3 + mov t7d, [r0+cb.low] + and r1d, [r0+cb.range] + lea t7d, [t7*2+r1] + movifnidn t0, r0 ; WIN64 + mov t3d, [r0+cb.queue] inc t3d -%if UNIX64 ; .putbyte compiles to nothing but a jmp +%if ARCH_X86_64 ; .putbyte compiles to nothing but a jmp jge cabac_putbyte %else jge .putbyte @@ -127,28 +129,30 @@ cglobal cabac_encode_bypass_asm, 0,3 mov [t0+cb.low], t7d mov [t0+cb.queue], t3d RET +%if ARCH_X86_64 == 0 .putbyte: PROLOGUE 0,7 movifnidn t6d, t7d jmp cabac_putbyte +%endif -cglobal cabac_encode_terminal_asm, 0,3 - movifnidn t0, r0mp - sub dword [t0+cb.range], 2 +cglobal cabac_encode_terminal_asm, 1,3 + sub dword [r0+cb.range], 2 ; shortcut: the renormalization shift in terminal ; can only be 0 or 1 and is zero over 99% of the time. - test dword [t0+cb.range], 0x100 + test dword [r0+cb.range], 0x100 je .renorm - REP_RET + RET .renorm: - shl dword [t0+cb.low], 1 - shl dword [t0+cb.range], 1 - inc dword [t0+cb.queue] + shl dword [r0+cb.low], 1 + shl dword [r0+cb.range], 1 + inc dword [r0+cb.queue] jge .putbyte - REP_RET + RET .putbyte: PROLOGUE 0,7 - mov t3d, [t0+cb.queue] + movifnidn t0, r0 ; WIN64 + mov t3d, [r0+cb.queue] mov t6d, [t0+cb.low] cabac_putbyte: diff --git a/common/x86/const-a.asm b/common/x86/const-a.asm index ce9ef40c..dceb525a 100644 --- a/common/x86/const-a.asm +++ b/common/x86/const-a.asm @@ -1,7 +1,7 @@ ;***************************************************************************** ;* const-a.asm: x86 global constants ;***************************************************************************** -;* Copyright (C) 2010-2012 x264 project +;* Copyright (C) 2010-2013 x264 project ;* ;* Authors: Loren Merritt ;* Jason Garrett-Glaser diff --git a/common/x86/cpu-a.asm b/common/x86/cpu-a.asm index 0712447f..6e26b965 100644 --- a/common/x86/cpu-a.asm +++ b/common/x86/cpu-a.asm @@ -1,7 +1,7 @@ ;***************************************************************************** ;* cpu-a.asm: x86 cpu utilities ;***************************************************************************** -;* Copyright (C) 2003-2012 x264 project +;* Copyright (C) 2003-2013 x264 project ;* ;* Authors: Laurent Aimar ;* Loren Merritt @@ -139,3 +139,53 @@ cglobal cpu_mask_misalign_sse ldmxcsr [rsp] add rsp, 4 ret + +cextern intel_cpu_indicator_init + +;----------------------------------------------------------------------------- +; void safe_intel_cpu_indicator_init( void ); +;----------------------------------------------------------------------------- +cglobal safe_intel_cpu_indicator_init + push r0 + push r1 + push r2 + push r3 + push r4 + push r5 + push r6 +%if ARCH_X86_64 + push r7 + push r8 + push r9 + push r10 + push r11 + push r12 + push r13 + push r14 +%endif + push rbp + mov rbp, rsp +%if WIN64 + sub rsp, 32 ; shadow space +%endif + and rsp, ~15 + call intel_cpu_indicator_init + leave +%if ARCH_X86_64 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + pop r9 + pop r8 + pop r7 +%endif + pop r6 + pop r5 + pop r4 + pop r3 + pop r2 + pop r1 + pop r0 + ret diff --git a/common/x86/dct-32.asm b/common/x86/dct-32.asm index 07c47ab2..70c7fb57 100644 --- a/common/x86/dct-32.asm +++ b/common/x86/dct-32.asm @@ -1,7 +1,7 @@ ;***************************************************************************** ;* dct-32.asm: x86_32 transform and zigzag ;***************************************************************************** -;* Copyright (C) 2003-2012 x264 project +;* Copyright (C) 2003-2013 x264 project ;* ;* Authors: Loren Merritt ;* Holger Lubitz diff --git a/common/x86/dct-64.asm b/common/x86/dct-64.asm index 8f402229..350066d9 100644 --- a/common/x86/dct-64.asm +++ b/common/x86/dct-64.asm @@ -1,7 +1,7 @@ ;***************************************************************************** ;* dct-64.asm: x86_64 transform and zigzag ;***************************************************************************** -;* Copyright (C) 2003-2012 x264 project +;* Copyright (C) 2003-2013 x264 project ;* ;* Authors: Loren Merritt ;* Holger Lubitz diff --git a/common/x86/dct-a.asm b/common/x86/dct-a.asm index 1928604c..db2ae0e7 100644 --- a/common/x86/dct-a.asm +++ b/common/x86/dct-a.asm @@ -1,7 +1,7 @@ ;***************************************************************************** ;* dct-a.asm: x86 transform and zigzag ;***************************************************************************** -;* Copyright (C) 2003-2012 x264 project +;* Copyright (C) 2003-2013 x264 project ;* ;* Authors: Holger Lubitz ;* Loren Merritt @@ -555,7 +555,7 @@ cglobal add16x16_idct_dc, 2,3,8 add r0, 4*FDEC_STRIDEB dec r2 jg .loop - REP_RET + RET %endmacro ; ADD_IDCT_DC INIT_XMM sse2 @@ -664,7 +664,7 @@ cglobal add16x16_idct_dc, 2,3 add r0, FDEC_STRIDE*4 dec r2 jg .loop - REP_RET + RET INIT_XMM sse2 cglobal add16x16_idct_dc, 2,2,8 @@ -1274,7 +1274,7 @@ cglobal zigzag_scan_8x8_field, 2,3,8 mova m1, [r1+ 4*SIZEOF_DCTCOEF] ; 07 06 05 04 mova m2, [r1+ 8*SIZEOF_DCTCOEF] ; 11 10 09 08 pshuf%1 m3, m0, q3333 ; 03 03 03 03 - movd r2, m2 ; 09 08 + movd r2d, m2 ; 09 08 pshuf%1 m2, m2, q0321 ; 08 11 10 09 punpckl%2 m3, m1 ; 05 03 04 03 pinsr%1 m0, r2d, 3 ; 08 02 01 00 diff --git a/common/x86/dct.h b/common/x86/dct.h index d48b3976..5156212f 100644 --- a/common/x86/dct.h +++ b/common/x86/dct.h @@ -1,7 +1,7 @@ /***************************************************************************** * dct.h: x86 transform and zigzag ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Loren Merritt * Laurent Aimar diff --git a/common/x86/deblock-a.asm b/common/x86/deblock-a.asm index d03a9de9..0cc003f6 100644 --- a/common/x86/deblock-a.asm +++ b/common/x86/deblock-a.asm @@ -1,7 +1,7 @@ ;***************************************************************************** ;* deblock-a.asm: x86 deblocking ;***************************************************************************** -;* Copyright (C) 2005-2012 x264 project +;* Copyright (C) 2005-2013 x264 project ;* ;* Authors: Loren Merritt ;* Jason Garrett-Glaser @@ -171,7 +171,7 @@ cglobal deblock_v_luma, 5,5,8 %define bm [rsp+mmsize*4] SUB rsp, pad add r1, r1 - LOAD_AB m4, m5, r2, r3 + LOAD_AB m4, m5, r2d, r3d mov r3, 32/mmsize mov r2, r0 sub r0, r1 @@ -227,7 +227,7 @@ cglobal deblock_h_luma, 5,6,8 %define bm [rsp+mmsize*6] SUB rsp, pad add r1, r1 - LOAD_AB m4, m5, r2, r3 + LOAD_AB m4, m5, r2d, r3d mov r3, r1 mova am, m4 add r3, r1 @@ -355,7 +355,7 @@ cglobal deblock_v_luma, 5,5,15 %define mask1 m10 %define mask2 m11 add r1, r1 - LOAD_AB m12, m13, r2, r3 + LOAD_AB m12, m13, r2d, r3d mov r2, r0 sub r0, r1 sub r0, r1 @@ -378,11 +378,11 @@ cglobal deblock_v_luma, 5,5,15 add r4, 2 dec r3 jg .loop - REP_RET + RET cglobal deblock_h_luma, 5,7,15 add r1, r1 - LOAD_AB m12, m13, r2, r3 + LOAD_AB m12, m13, r2d, r3d mov r2, r1 add r2, r1 add r2, r1 @@ -416,7 +416,7 @@ cglobal deblock_h_luma, 5,7,15 lea r5, [r5+r1*8] dec r6 jg .loop - REP_RET + RET %endmacro INIT_XMM sse2 @@ -650,7 +650,7 @@ cglobal deblock_v_luma_intra, 4,7,16 add r4, mmsize dec r6 jg .loop - REP_RET + RET ;----------------------------------------------------------------------------- ; void deblock_h_luma_intra( uint16_t *pix, intptr_t stride, int alpha, int beta ) @@ -1205,20 +1205,18 @@ DEBLOCK_LUMA ;----------------------------------------------------------------------------- ; void deblock_v8_luma( uint8_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ) ;----------------------------------------------------------------------------- -cglobal deblock_%1_luma, 5,5 +cglobal deblock_%1_luma, 5,5,8,2*%2 lea r4, [r1*3] dec r2 ; alpha-1 neg r4 dec r3 ; beta-1 add r4, r0 ; pix-3*stride - %assign pad 2*%2+12-(stack_offset&15) - SUB esp, pad mova m0, [r4+r1] ; p1 mova m1, [r4+2*r1] ; p0 mova m2, [r0] ; q0 mova m3, [r0+r1] ; q1 - LOAD_MASK r2, r3 + LOAD_MASK r2d, r3d mov r3, r4mp movd m4, [r3] ; tc0 @@ -1251,22 +1249,19 @@ cglobal deblock_%1_luma, 5,5 DEBLOCK_P0_Q0 mova [r4+2*r1], m1 mova [r0], m2 - ADD esp, pad RET ;----------------------------------------------------------------------------- ; void deblock_h_luma( uint8_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ) ;----------------------------------------------------------------------------- INIT_MMX cpuname -cglobal deblock_h_luma, 0,5 +cglobal deblock_h_luma, 0,5,8,0x60+HAVE_ALIGNED_STACK*12 mov r0, r0mp mov r3, r1m lea r4, [r3*3] sub r0, 4 lea r1, [r0+r4] - %assign pad 0x78-(stack_offset&15) - SUB esp, pad -%define pix_tmp esp+12 + %define pix_tmp esp+12*HAVE_ALIGNED_STACK ; transpose 6x16 -> tmp space TRANSPOSE6x8_MEM PASS8ROWS(r0, r1, r3, r4), pix_tmp @@ -1308,7 +1303,6 @@ cglobal deblock_h_luma, 0,5 movq m3, [pix_tmp+0x48] TRANSPOSE8x4B_STORE PASS8ROWS(r0, r1, r3, r4) - ADD esp, pad RET %endmacro ; DEBLOCK_LUMA @@ -1435,11 +1429,15 @@ DEBLOCK_LUMA v, 16 %define t5 m11 %define mask0 m12 %define mask1p m13 +%if WIN64 + %define mask1q [rsp] +%else %define mask1q [rsp-24] +%endif %define mpb_0 m14 %define mpb_1 m15 %else - %define spill(x) [esp+16*x+((stack_offset+4)&15)] + %define spill(x) [esp+16*x] %define p2 [r4+r1] %define q2 [r0+2*r1] %define t4 spill(0) @@ -1454,10 +1452,7 @@ DEBLOCK_LUMA v, 16 ;----------------------------------------------------------------------------- ; void deblock_v_luma_intra( uint8_t *pix, intptr_t stride, int alpha, int beta ) ;----------------------------------------------------------------------------- -cglobal deblock_%1_luma_intra, 4,6,16 -%if ARCH_X86_64 == 0 - sub esp, 0x60 -%endif +cglobal deblock_%1_luma_intra, 4,6,16,0-(1-ARCH_X86_64)*0x50-WIN64*0x10 lea r4, [r1*4] lea r5, [r1*3] ; 3*stride dec r2d ; alpha-1 @@ -1506,10 +1501,7 @@ cglobal deblock_%1_luma_intra, 4,6,16 LUMA_INTRA_SWAP_PQ LUMA_INTRA_P012 [r0], [r0+r1], [r0+2*r1], [r0+r5] .end: -%if ARCH_X86_64 == 0 - add esp, 0x60 -%endif - RET + REP_RET INIT_MMX cpuname %if ARCH_X86_64 @@ -1545,12 +1537,10 @@ cglobal deblock_h_luma_intra, 4,9 add rsp, 0x88 RET %else -cglobal deblock_h_luma_intra, 2,4 +cglobal deblock_h_luma_intra, 2,4,8,0x80 lea r3, [r1*3] sub r0, 4 lea r2, [r0+r3] -%assign pad 0x8c-(stack_offset&15) - SUB rsp, pad %define pix_tmp rsp ; transpose 8x16 -> tmp space @@ -1581,7 +1571,6 @@ cglobal deblock_h_luma_intra, 2,4 lea r0, [r0+r1*8] lea r2, [r2+r1*8] TRANSPOSE8x8_MEM PASS8ROWS(pix_tmp+8, pix_tmp+0x38, 0x10, 0x30), PASS8ROWS(r0, r2, r1, r3) - ADD rsp, pad RET %endif ; ARCH_X86_64 %endmacro ; DEBLOCK_LUMA_INTRA @@ -1675,7 +1664,7 @@ DEBLOCK_LUMA_INTRA v8 %macro DEBLOCK_CHROMA 0 cglobal deblock_inter_body - LOAD_AB m4, m5, r2, r3 + LOAD_AB m4, m5, r2d, r3d LOAD_MASK m0, m1, m2, m3, m4, m5, m7, m6, m4 pxor m4, m4 LOAD_TC m6, r4 @@ -1702,7 +1691,7 @@ cglobal deblock_v_chroma, 5,7,8 add r4, mmsize/8 dec r6 jg .loop - REP_RET + RET ;----------------------------------------------------------------------------- ; void deblock_h_chroma( uint16_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ) @@ -1721,11 +1710,11 @@ cglobal deblock_h_chroma, 5,7,8 add r4, mmsize/8 dec r5 jg .loop - REP_RET + RET cglobal deblock_intra_body - LOAD_AB m4, m5, r2, r3 + LOAD_AB m4, m5, r2d, r3d LOAD_MASK m0, m1, m2, m3, m4, m5, m7, m6, m4 CHROMA_DEBLOCK_P0_Q0_INTRA m1, m2, m0, m3, m7, m5, m6 ret @@ -1736,7 +1725,7 @@ cglobal deblock_intra_body cglobal deblock_v_chroma_intra, 4,6,8 add r1, r1 mov r5, 32/mmsize - movd m5, r3 + movd m5, r3d mov r4, r0 sub r0, r1 sub r0, r1 @@ -1749,7 +1738,7 @@ cglobal deblock_v_chroma_intra, 4,6,8 add r4, mmsize dec r5 jg .loop - REP_RET + RET ;----------------------------------------------------------------------------- ; void deblock_h_chroma_intra( uint16_t *pix, intptr_t stride, int alpha, int beta ) @@ -1767,7 +1756,7 @@ cglobal deblock_h_chroma_intra, 4,6,8 lea r0, [r0+r1*(mmsize/4)] dec r4 jg .loop - REP_RET + RET ;----------------------------------------------------------------------------- ; void deblock_h_chroma_intra_mbaff( uint16_t *pix, intptr_t stride, int alpha, int beta ) @@ -1781,7 +1770,7 @@ cglobal deblock_h_chroma_intra_mbaff, 4,6,8 lea r5, [r1*3] %endif CHROMA_H_LOAD r5 - LOAD_AB m4, m5, r2, r3 + LOAD_AB m4, m5, r2d, r3d LOAD_MASK m0, m1, m2, m3, m4, m5, m7, m6, m4 CHROMA_DEBLOCK_P0_Q0_INTRA m1, m2, m0, m3, m7, m5, m6 CHROMA_H_STORE r5 @@ -1790,7 +1779,7 @@ cglobal deblock_h_chroma_intra_mbaff, 4,6,8 dec r4 jg .loop %endif - REP_RET + RET ;----------------------------------------------------------------------------- ; void deblock_h_chroma_mbaff( uint16_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ) @@ -1803,7 +1792,7 @@ cglobal deblock_h_chroma_mbaff, 5,7,8 .loop: %endif CHROMA_H_LOAD r6 - LOAD_AB m4, m5, r2, r3 + LOAD_AB m4, m5, r2d, r3d LOAD_MASK m0, m1, m2, m3, m4, m5, m7, m6, m4 movd m6, [r4] punpcklbw m6, m6 @@ -1818,7 +1807,7 @@ cglobal deblock_h_chroma_mbaff, 5,7,8 dec r5 jg .loop %endif - REP_RET + RET ;----------------------------------------------------------------------------- ; void deblock_h_chroma_422_intra( uint16_t *pix, intptr_t stride, int alpha, int beta ) @@ -1836,7 +1825,7 @@ cglobal deblock_h_chroma_422_intra, 4,6,8 lea r0, [r0+r1*(mmsize/4)] dec r4 jg .loop - REP_RET + RET ;----------------------------------------------------------------------------- ; void deblock_h_chroma_422( uint16_t *pix, intptr_t stride, int alpha, int beta, int8_t *tc0 ) @@ -1847,7 +1836,7 @@ cglobal deblock_h_chroma_422, 5,7,8 lea r6, [r1*3] .loop: CHROMA_H_LOAD r6 - LOAD_AB m4, m5, r2m, r3 + LOAD_AB m4, m5, r2m, r3d LOAD_MASK m0, m1, m2, m3, m4, m5, m7, m6, m4 pxor m4, m4 movd m6, [r4-1] @@ -1867,7 +1856,7 @@ cglobal deblock_h_chroma_422, 5,7,8 %endif dec r5 jg .loop - REP_RET + RET %endmacro ; DEBLOCK_CHROMA %if ARCH_X86_64 == 0 @@ -2035,7 +2024,7 @@ cglobal deblock_h_chroma_422, 5,8,8 add r4, mmsize/8 dec cntr jg .loop - REP_RET + RET %endmacro INIT_MMX mmx2 @@ -2116,7 +2105,7 @@ cglobal deblock_h_chroma_422_intra, 4,7,8 lea t5, [t5+r1*(mmsize/2)] dec r6d jg .loop - REP_RET + RET %endmacro ; DEBLOCK_CHROMA_INTRA INIT_XMM sse2 diff --git a/common/x86/mc-a.asm b/common/x86/mc-a.asm index fc2be473..ce7f7860 100644 --- a/common/x86/mc-a.asm +++ b/common/x86/mc-a.asm @@ -1,7 +1,7 @@ ;***************************************************************************** ;* mc-a.asm: x86 motion compensation ;***************************************************************************** -;* Copyright (C) 2003-2012 x264 project +;* Copyright (C) 2003-2013 x264 project ;* ;* Authors: Loren Merritt ;* Jason Garrett-Glaser @@ -87,7 +87,7 @@ cextern pd_32 lea t0, [t0+t1*2*SIZEOF_PIXEL] sub eax, 2 jg .height_loop - REP_RET + RET %endmacro %if HIGH_BIT_DEPTH @@ -415,7 +415,7 @@ cglobal mc_weight_w%1, 6,6,8 lea r2, [r2+r3*2] sub r5d, 2 jg .loop - REP_RET + RET %endmacro INIT_MMX mmx2 @@ -495,7 +495,7 @@ cglobal mc_offset%2_w%1, 6,6 lea r2, [r2+r3*2] sub r5d, 2 jg .loop - REP_RET + RET %endmacro %macro OFFSETPN 1 @@ -672,7 +672,7 @@ cglobal pixel_avg2_w%1, 6,7,4 lea r0, [r0+r1*4] sub r5d, 2 jg .height_loop - REP_RET + RET %endmacro %macro AVG2_W_TWO 3 @@ -707,7 +707,7 @@ cglobal pixel_avg2_w%1, 6,7,8 lea r0, [r0+r1*4] sub r5d, 2 jg .height_loop - REP_RET + RET %endmacro INIT_MMX mmx2 @@ -745,7 +745,7 @@ cglobal pixel_avg2_w10_mmx2, 6,7 lea r0, [r0+r1*2*2] sub r5d, 2 jg .height_loop - REP_RET + RET cglobal pixel_avg2_w16_mmx2, 6,7 sub r4, r2 @@ -779,7 +779,7 @@ cglobal pixel_avg2_w16_mmx2, 6,7 lea r0, [r0+r1*2*2] sub r5d, 2 jg .height_loop - REP_RET + RET cglobal pixel_avg2_w18_mmx2, 6,7 sub r4, r2 @@ -803,7 +803,7 @@ cglobal pixel_avg2_w18_mmx2, 6,7 lea r0, [r0+r1*2] dec r5d jg .height_loop - REP_RET + RET INIT_XMM cglobal pixel_avg2_w18_sse2, 6,7,6 @@ -825,7 +825,7 @@ cglobal pixel_avg2_w18_sse2, 6,7,6 lea r0, [r0+r1*2] dec r5d jg .height_loop - REP_RET + RET %endif ; HIGH_BIT_DEPTH %if HIGH_BIT_DEPTH == 0 @@ -849,7 +849,7 @@ cglobal pixel_avg2_w%1_mmx2, 6,7 lea r0, [r0+r1*2] sub r5d, 2 jg .height_loop - REP_RET + RET %endmacro INIT_MMX @@ -877,7 +877,7 @@ cglobal pixel_avg2_w%1_mmx2, 6,7 lea r0, [r0+r1*2] sub r5d, 2 jg .height_loop - REP_RET + RET %endmacro AVG2_W16 12, movd @@ -909,7 +909,7 @@ cglobal pixel_avg2_w20_mmx2, 6,7 lea r0, [r0+r1*2] sub r5d, 2 jg .height_loop - REP_RET + RET cglobal pixel_avg2_w16_sse2, 6,7 sub r4, r2 @@ -927,7 +927,7 @@ cglobal pixel_avg2_w16_sse2, 6,7 lea r0, [r0+r1*2] sub r5d, 2 jg .height_loop - REP_RET + RET %macro AVG2_W20 1 cglobal pixel_avg2_w20_%1, 6,7 @@ -959,7 +959,7 @@ cglobal pixel_avg2_w20_%1, 6,7 lea r0, [r0+r1*2] sub r5d, 2 jg .height_loop - REP_RET + RET %endmacro AVG2_W20 sse2 @@ -1022,7 +1022,7 @@ pixel_avg2_w%1_cache_mmx2: add r0, r1 dec r5d jg .height_loop - REP_RET + RET %endmacro %macro AVG_CACHELINE_CHECK 3 ; width, cacheline, instruction set @@ -1226,17 +1226,17 @@ cglobal mc_copy_w%1, 5,7,8*(%%w/2) lea r0, [r0+r1*4] sub r4d, 4 jg .height_loop - REP_RET + RET %endif %endmacro INIT_MMX mmx MC_COPY 8 MC_COPY 16 -INIT_XMM sse2 +INIT_XMM sse MC_COPY 8 MC_COPY 16 -INIT_XMM aligned, sse2 +INIT_XMM aligned, sse MC_COPY 16 @@ -1506,7 +1506,7 @@ ALIGN 4 add r1, r2 dec r5d jg .loop2 - REP_RET + RET %if mmsize==8 .width4: @@ -1514,7 +1514,11 @@ ALIGN 4 mov t0, r0 mov t1, r1 mov t2, r3 +%if WIN64 + %define multy0 r4m +%else %define multy0 [rsp-8] +%endif mova multy0, m5 %else mov r3m, r3 @@ -1626,11 +1630,11 @@ ALIGN 4 dec r5d jg .loop4 %if mmsize!=8 - REP_RET + RET %else sub dword r7m, 4 jg .width8 - REP_RET + RET .width8: %if ARCH_X86_64 lea r3, [t2+8*SIZEOF_PIXEL] @@ -1766,7 +1770,7 @@ ALIGN 4 add r1, r2 dec r5d jg .loop1d_w4 - REP_RET + RET .mc1d_w8: sub r2, 4*SIZEOF_PIXEL sub r4, 8*SIZEOF_PIXEL @@ -1848,7 +1852,7 @@ cglobal mc_chroma lea r1, [r1+r2*2] sub r5d, 2 jg .loop4 - REP_RET + RET .width8: movu m0, [r3] @@ -1909,7 +1913,7 @@ cglobal mc_chroma lea r1, [r1+r2*2] sub r5d, 2 jg .loop8 - REP_RET + RET %endmacro %if HIGH_BIT_DEPTH diff --git a/common/x86/mc-a2.asm b/common/x86/mc-a2.asm index 01979411..ba23c94f 100644 --- a/common/x86/mc-a2.asm +++ b/common/x86/mc-a2.asm @@ -1,7 +1,7 @@ ;***************************************************************************** ;* mc-a2.asm: x86 motion compensation ;***************************************************************************** -;* Copyright (C) 2005-2012 x264 project +;* Copyright (C) 2005-2013 x264 project ;* ;* Authors: Loren Merritt ;* Jason Garrett-Glaser @@ -210,7 +210,7 @@ cglobal hpel_filter_v, 5,6,11 mova [r0+r4+mmsize], m4 add r4, 2*mmsize jl .loop - REP_RET + RET ;----------------------------------------------------------------------------- ; void hpel_filter_c( uint16_t *dst, int16_t *buf, intptr_t width ); @@ -259,7 +259,7 @@ cglobal hpel_filter_c, 3,3,10 mova [r0+r2], m1 add r2, mmsize jl .loop - REP_RET + RET ;----------------------------------------------------------------------------- ; void hpel_filter_h( uint16_t *dst, uint16_t *src, intptr_t width ); @@ -302,7 +302,7 @@ cglobal hpel_filter_h, 3,4,8 mova [r0+r2+mmsize], m4 add r2, mmsize*2 jl .loop - REP_RET + RET %endmacro ; HPEL_FILTER INIT_MMX mmx2 @@ -365,7 +365,7 @@ cglobal hpel_filter_v, 5,6,%1 add r5, mmsize add r4, mmsize jl .loop - REP_RET + RET %endmacro ;----------------------------------------------------------------------------- @@ -396,7 +396,7 @@ cglobal hpel_filter_c_mmx2, 3,3 movntq [r0+r2], m1 add r2, 8 jl .loop - REP_RET + RET ;----------------------------------------------------------------------------- ; void hpel_filter_h( uint8_t *dst, uint8_t *src, intptr_t width ); @@ -440,7 +440,7 @@ cglobal hpel_filter_h_mmx2, 3,3 movntq [r0+r2], m1 add r2, 8 jl .loop - REP_RET + RET INIT_XMM @@ -510,7 +510,7 @@ cglobal hpel_filter_c, 3,3,9 movntps [r0+r2], m4 add r2, 16 jl .loop - REP_RET + RET %endmacro ;----------------------------------------------------------------------------- @@ -559,7 +559,7 @@ cglobal hpel_filter_h_sse2, 3,3,8 movntps [r0+r2], m1 add r2, 16 jl .loop - REP_RET + RET ;----------------------------------------------------------------------------- ; void hpel_filter_h( uint8_t *dst, uint8_t *src, intptr_t width ); @@ -600,7 +600,7 @@ cglobal hpel_filter_h, 3,3 movntps [r0+r2], m3 add r2, 16 jl .loop - REP_RET + RET %endmacro INIT_MMX mmx2 @@ -1026,7 +1026,7 @@ cglobal store_interleave_chroma, 5,5 lea r0, [r0+r1*2] sub r4d, 2 jg .loop - REP_RET + RET %endmacro ; PLANE_INTERLEAVE %macro DEINTERLEAVE_START 0 @@ -1068,7 +1068,7 @@ cglobal plane_copy_deinterleave, 6,7 add r4, r5 dec dword r7m jg .loopy - REP_RET + RET ;----------------------------------------------------------------------------- ; void load_deinterleave_chroma_fenc( pixel *dst, pixel *src, intptr_t i_src, int height ) @@ -1083,7 +1083,7 @@ cglobal load_deinterleave_chroma_fenc, 4,4 lea r1, [r1+r2*2] sub r3d, 2 jg .loop - REP_RET + RET ;----------------------------------------------------------------------------- ; void load_deinterleave_chroma_fdec( pixel *dst, pixel *src, intptr_t i_src, int height ) @@ -1098,7 +1098,7 @@ cglobal load_deinterleave_chroma_fdec, 4,4 lea r1, [r1+r2*2] sub r3d, 2 jg .loop - REP_RET + RET %endmacro ; PLANE_DEINTERLEAVE %if HIGH_BIT_DEPTH @@ -1131,65 +1131,45 @@ PLANE_DEINTERLEAVE ;----------------------------------------------------------------------------- ; void *memcpy_aligned( void *dst, const void *src, size_t n ); ;----------------------------------------------------------------------------- -INIT_MMX -cglobal memcpy_aligned_mmx, 3,3 - test r2d, 16 - jz .copy32start - movq mm0, [r1 + r2 - 16] - movq mm1, [r1 + r2 - 8] - movq [r0 + r2 - 16], mm0 - movq [r0 + r2 - 8], mm1 - sub r2d, 16 -.copy32start - test r2d, r2d - jz .ret -.copy32: - movq mm0, [r1 + r2 - 32] - movq mm1, [r1 + r2 - 24] - movq mm2, [r1 + r2 - 16] - movq mm3, [r1 + r2 - 8] - movq [r0 + r2 - 32], mm0 - movq [r0 + r2 - 24], mm1 - movq [r0 + r2 - 16], mm2 - movq [r0 + r2 - 8], mm3 - sub r2d, 32 - jg .copy32 -.ret - REP_RET - -;----------------------------------------------------------------------------- -; void *memcpy_aligned( void *dst, const void *src, size_t n ); -;----------------------------------------------------------------------------- -cglobal memcpy_aligned_sse2, 3,3 +%macro MEMCPY 0 +cglobal memcpy_aligned, 3,3 +%if mmsize == 16 test r2d, 16 - jz .copy32 - movdqa xmm0, [r1 + r2 - 16] - movdqa [r0 + r2 - 16], xmm0 + jz .copy2 + mova m0, [r1+r2-16] + mova [r0+r2-16], m0 sub r2d, 16 -.copy32: - test r2d, 32 - jz .copy64start - movdqa xmm0, [r1 + r2 - 32] - movdqa [r0 + r2 - 32], xmm0 - movdqa xmm1, [r1 + r2 - 16] - movdqa [r0 + r2 - 16], xmm1 - sub r2d, 32 -.copy64start +.copy2: +%endif + test r2d, 2*mmsize + jz .copy4start + mova m0, [r1+r2-1*mmsize] + mova m1, [r1+r2-2*mmsize] + mova [r0+r2-1*mmsize], m0 + mova [r0+r2-2*mmsize], m1 + sub r2d, 2*mmsize +.copy4start: test r2d, r2d jz .ret -.copy64: - movdqa xmm0, [r1 + r2 - 64] - movdqa [r0 + r2 - 64], xmm0 - movdqa xmm1, [r1 + r2 - 48] - movdqa [r0 + r2 - 48], xmm1 - movdqa xmm2, [r1 + r2 - 32] - movdqa [r0 + r2 - 32], xmm2 - movdqa xmm3, [r1 + r2 - 16] - movdqa [r0 + r2 - 16], xmm3 - sub r2d, 64 - jg .copy64 +.copy4: + mova m0, [r1+r2-1*mmsize] + mova m1, [r1+r2-2*mmsize] + mova m2, [r1+r2-3*mmsize] + mova m3, [r1+r2-4*mmsize] + mova [r0+r2-1*mmsize], m0 + mova [r0+r2-2*mmsize], m1 + mova [r0+r2-3*mmsize], m2 + mova [r0+r2-4*mmsize], m3 + sub r2d, 4*mmsize + jg .copy4 .ret: REP_RET +%endmacro + +INIT_MMX mmx +MEMCPY +INIT_XMM sse +MEMCPY ;----------------------------------------------------------------------------- ; void *memzero_aligned( void *dst, size_t n ); @@ -1198,7 +1178,11 @@ cglobal memcpy_aligned_sse2, 3,3 cglobal memzero_aligned, 2,2 add r0, r1 neg r1 +%if mmsize == 8 pxor m0, m0 +%else + xorps m0, m0 +%endif .loop: %assign i 0 %rep 8 @@ -1207,12 +1191,12 @@ cglobal memzero_aligned, 2,2 %endrep add r1, mmsize*8 jl .loop - REP_RET + RET %endmacro INIT_MMX mmx MEMZERO -INIT_XMM sse2 +INIT_XMM sse MEMZERO @@ -1239,7 +1223,7 @@ cglobal integral_init4h_sse4, 3,4 movdqa [r3+r2*2+16], m1 add r2, 16 jl .loop - REP_RET + RET %macro INTEGRAL_INIT8H 0 cglobal integral_init8h, 3,4 @@ -1263,7 +1247,7 @@ cglobal integral_init8h, 3,4 movdqa [r3+r2*2+16], m1 add r2, 16 jl .loop - REP_RET + RET %endmacro INIT_XMM sse4 @@ -1290,7 +1274,7 @@ cglobal integral_init8v, 3,3 mova [r0+r1+mmsize], m1 add r1, 2*mmsize jl .loop - REP_RET + RET %endmacro INIT_MMX mmx @@ -1321,7 +1305,7 @@ cglobal integral_init4v_mmx, 3,5 mova [r1+r2-8], m3 sub r2, 8 jge .loop - REP_RET + RET INIT_XMM cglobal integral_init4v_sse2, 3,5 @@ -1347,7 +1331,7 @@ cglobal integral_init4v_sse2, 3,5 mova [r1+r2], m3 add r2, 16 jl .loop - REP_RET + RET cglobal integral_init4v_ssse3, 3,5 shl r2, 1 @@ -1372,7 +1356,7 @@ cglobal integral_init4v_ssse3, 3,5 mova [r1+r2], m3 add r2, 16 jl .loop - REP_RET + RET %macro FILT8x4 7 mova %3, [r0+%7] @@ -1702,7 +1686,7 @@ cglobal mbtree_propagate_cost, 7,7,7 %if cpuflag(fma4) cvtdq2ps xmm0, xmm0 cvtdq2ps xmm1, xmm1 - vfmaddps xmm0, xmm0, xmm6, xmm1 + fmaddps xmm0, xmm0, xmm6, xmm1 cvtdq2ps xmm1, xmm2 psubd xmm2, xmm3 cvtdq2ps xmm2, xmm2 @@ -1710,7 +1694,7 @@ cglobal mbtree_propagate_cost, 7,7,7 mulps xmm1, xmm3 mulps xmm0, xmm2 addps xmm2, xmm3, xmm3 - vfnmaddps xmm3, xmm1, xmm3, xmm2 + fnmaddps xmm3, xmm1, xmm3, xmm2 mulps xmm0, xmm3 %else cvtdq2ps xmm0, xmm0 @@ -1732,7 +1716,7 @@ cglobal mbtree_propagate_cost, 7,7,7 movdqa [r0+r6*2], xmm0 add r6, 8 jl .loop - REP_RET + RET %endmacro INIT_XMM sse2 @@ -1742,14 +1726,18 @@ INIT_XMM fma4 MBTREE %macro INT16_TO_FLOAT 1 +%if cpuflag(avx2) + vpmovzxwd ymm%1, xmm%1 +%else vpunpckhwd xmm4, xmm%1, xmm7 vpunpcklwd xmm%1, xmm7 vinsertf128 ymm%1, ymm%1, xmm4, 1 +%endif vcvtdq2ps ymm%1, ymm%1 %endmacro ; FIXME: align loads/stores to 16 bytes -INIT_YMM avx +%macro MBTREE_AVX 0 cglobal mbtree_propagate_cost, 7,7,8 add r6d, r6d lea r0, [r0+r6*2] @@ -1761,7 +1749,9 @@ cglobal mbtree_propagate_cost, 7,7,8 vmovdqa xmm5, [pw_3fff] vbroadcastss ymm6, [r5] vmulps ymm6, ymm6, [pf_inv256] +%if notcpuflag(avx2) vpxor xmm7, xmm7 +%endif .loop: vmovdqu xmm0, [r2+r6] ; intra vmovdqu xmm1, [r4+r6] ; invq @@ -1771,6 +1761,17 @@ cglobal mbtree_propagate_cost, 7,7,8 INT16_TO_FLOAT 1 INT16_TO_FLOAT 2 INT16_TO_FLOAT 3 +%if cpuflag(fma3) + vmulps ymm1, ymm1, ymm0 + vsubps ymm4, ymm0, ymm3 + fmaddps ymm1, ymm1, ymm6, ymm2 + vrcpps ymm3, ymm0 + vmulps ymm2, ymm0, ymm3 + vmulps ymm1, ymm1, ymm4 + vaddps ymm4, ymm3, ymm3 + fnmaddps ymm4, ymm2, ymm3, ymm4 + vmulps ymm1, ymm1, ymm4 +%else vmulps ymm1, ymm1, ymm0 vsubps ymm4, ymm0, ymm3 vmulps ymm1, ymm1, ymm6 ; intra*invq*fps_factor>>8 @@ -1782,9 +1783,15 @@ cglobal mbtree_propagate_cost, 7,7,8 vaddps ymm3, ymm3, ymm3 ; 2 * (1/intra 1st approx) vsubps ymm3, ymm3, ymm2 ; 2nd approximation for 1/intra vmulps ymm1, ymm1, ymm3 ; / intra +%endif vcvtps2dq ymm1, ymm1 vmovdqu [r0+r6*2], ymm1 add r6, 16 jl .loop - vzeroupper RET +%endmacro + +INIT_YMM avx +MBTREE_AVX +INIT_YMM avx2,fma3 +MBTREE_AVX diff --git a/common/x86/mc-c.c b/common/x86/mc-c.c index dbb118b8..44efa66d 100644 --- a/common/x86/mc-c.c +++ b/common/x86/mc-c.c @@ -1,7 +1,7 @@ /***************************************************************************** * mc-c.c: x86 motion compensation ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Laurent Aimar * Loren Merritt @@ -75,12 +75,12 @@ MC_WEIGHT( 20, ssse3 ) #undef MC_OFFSET #undef MC_WEIGHT -void x264_mc_copy_w4_mmx ( pixel *, intptr_t, pixel *, intptr_t, int ); -void x264_mc_copy_w8_mmx ( pixel *, intptr_t, pixel *, intptr_t, int ); -void x264_mc_copy_w8_sse2 ( pixel *, intptr_t, pixel *, intptr_t, int ); -void x264_mc_copy_w16_mmx ( pixel *, intptr_t, pixel *, intptr_t, int ); -void x264_mc_copy_w16_sse2( pixel *, intptr_t, pixel *, intptr_t, int ); -void x264_mc_copy_w16_aligned_sse2( pixel *, intptr_t, pixel *, intptr_t, int ); +void x264_mc_copy_w4_mmx ( pixel *, intptr_t, pixel *, intptr_t, int ); +void x264_mc_copy_w8_mmx ( pixel *, intptr_t, pixel *, intptr_t, int ); +void x264_mc_copy_w8_sse ( pixel *, intptr_t, pixel *, intptr_t, int ); +void x264_mc_copy_w16_mmx( pixel *, intptr_t, pixel *, intptr_t, int ); +void x264_mc_copy_w16_sse( pixel *, intptr_t, pixel *, intptr_t, int ); +void x264_mc_copy_w16_aligned_sse( pixel *, intptr_t, pixel *, intptr_t, int ); void x264_prefetch_fenc_420_mmx2( pixel *, intptr_t, pixel *, intptr_t, int ); void x264_prefetch_fenc_422_mmx2( pixel *, intptr_t, pixel *, intptr_t, int ); void x264_prefetch_ref_mmx2( pixel *, intptr_t, int ); @@ -121,10 +121,10 @@ void x264_load_deinterleave_chroma_fdec_mmx ( pixel *dst, pixel *src, intptr_t i void x264_load_deinterleave_chroma_fdec_sse2( pixel *dst, pixel *src, intptr_t i_src, int height ); void x264_load_deinterleave_chroma_fdec_ssse3( uint8_t *dst, uint8_t *src, intptr_t i_src, int height ); void x264_load_deinterleave_chroma_fdec_avx( uint16_t *dst, uint16_t *src, intptr_t i_src, int height ); -void *x264_memcpy_aligned_mmx ( void *dst, const void *src, size_t n ); -void *x264_memcpy_aligned_sse2( void *dst, const void *src, size_t n ); -void x264_memzero_aligned_mmx ( void *dst, size_t n ); -void x264_memzero_aligned_sse2( void *dst, size_t n ); +void *x264_memcpy_aligned_mmx( void *dst, const void *src, size_t n ); +void *x264_memcpy_aligned_sse( void *dst, const void *src, size_t n ); +void x264_memzero_aligned_mmx( void *dst, size_t n ); +void x264_memzero_aligned_sse( void *dst, size_t n ); void x264_integral_init4h_sse4( uint16_t *sum, uint8_t *pix, intptr_t stride ); void x264_integral_init8h_sse4( uint16_t *sum, uint8_t *pix, intptr_t stride ); void x264_integral_init8h_avx ( uint16_t *sum, uint8_t *pix, intptr_t stride ); @@ -139,6 +139,8 @@ void x264_mbtree_propagate_cost_avx ( int *dst, uint16_t *propagate_in, uint16_t uint16_t *inter_costs, uint16_t *inv_qscales, float *fps_factor, int len ); void x264_mbtree_propagate_cost_fma4( int *dst, uint16_t *propagate_in, uint16_t *intra_costs, uint16_t *inter_costs, uint16_t *inv_qscales, float *fps_factor, int len ); +void x264_mbtree_propagate_cost_avx2_fma3( int *dst, uint16_t *propagate_in, uint16_t *intra_costs, + uint16_t *inter_costs, uint16_t *inv_qscales, float *fps_factor, int len ); #define MC_CHROMA(cpu)\ void x264_mc_chroma_##cpu( pixel *dstu, pixel *dstv, intptr_t i_dst, pixel *src, intptr_t i_src,\ @@ -212,6 +214,7 @@ PIXEL_AVG_WTAB(sse2, mmx2, mmx2, sse2, sse2, sse2) PIXEL_AVG_WTAB(sse2_misalign, mmx2, mmx2, sse2, sse2, sse2_misalign) PIXEL_AVG_WTAB(cache64_sse2, mmx2, cache64_mmx2, cache64_sse2, cache64_sse2, cache64_sse2) PIXEL_AVG_WTAB(cache64_ssse3, mmx2, cache64_mmx2, cache64_ssse3, cache64_ssse3, cache64_sse2) +PIXEL_AVG_WTAB(cache64_ssse3_atom, mmx2, mmx2, cache64_ssse3, cache64_ssse3, sse2) #endif // HIGH_BIT_DEPTH #define MC_COPY_WTAB(instr, name1, name2, name3)\ @@ -226,9 +229,9 @@ static void (* const x264_mc_copy_wtab_##instr[5])( pixel *, intptr_t, pixel *, MC_COPY_WTAB(mmx,mmx,mmx,mmx) #if HIGH_BIT_DEPTH -MC_COPY_WTAB(sse2,mmx,sse2,sse2) +MC_COPY_WTAB(sse,mmx,sse,sse) #else -MC_COPY_WTAB(sse2,mmx,mmx,sse2) +MC_COPY_WTAB(sse,mmx,mmx,sse) #endif #define MC_WEIGHT_WTAB(function, instr, name1, name2, w12version)\ @@ -355,14 +358,15 @@ static void mc_luma_##name( pixel *dst, intptr_t i_dst_stride,\ } MC_LUMA(mmx2,mmx2,mmx) -MC_LUMA(sse2,sse2,sse2) +MC_LUMA(sse2,sse2,sse) #if !HIGH_BIT_DEPTH #if ARCH_X86 MC_LUMA(cache32_mmx2,cache32_mmx2,mmx) MC_LUMA(cache64_mmx2,cache64_mmx2,mmx) #endif -MC_LUMA(cache64_sse2,cache64_sse2,sse2) -MC_LUMA(cache64_ssse3,cache64_ssse3,sse2) +MC_LUMA(cache64_sse2,cache64_sse2,sse) +MC_LUMA(cache64_ssse3,cache64_ssse3,sse) +MC_LUMA(cache64_ssse3_atom,cache64_ssse3_atom,sse) #endif // !HIGH_BIT_DEPTH #define GET_REF(name)\ @@ -406,6 +410,7 @@ GET_REF(cache64_mmx2) GET_REF(sse2_misalign) GET_REF(cache64_sse2) GET_REF(cache64_ssse3) +GET_REF(cache64_ssse3_atom) #endif // !HIGH_BIT_DEPTH #define HPEL(align, cpu, cpuv, cpuc, cpuh)\ @@ -543,6 +548,12 @@ void x264_mc_init_mmx( int cpu, x264_mc_functions_t *pf ) pf->frame_init_lowres_core = x264_frame_init_lowres_core_mmx2; + if( cpu&X264_CPU_SSE ) + { + pf->memcpy_aligned = x264_memcpy_aligned_sse; + pf->memzero_aligned = x264_memzero_aligned_sse; + } + #if HIGH_BIT_DEPTH #if ARCH_X86 // all x86_64 cpus with cacheline split issues use sse2 instead if( cpu&(X264_CPU_CACHELINE_32|X264_CPU_CACHELINE_64) ) @@ -567,8 +578,6 @@ void x264_mc_init_mmx( int cpu, x264_mc_functions_t *pf ) pf->hpel_filter = x264_hpel_filter_sse2; } - pf->memcpy_aligned = x264_memcpy_aligned_sse2; - pf->memzero_aligned = x264_memzero_aligned_sse2; pf->integral_init4v = x264_integral_init4v_sse2; pf->integral_init8v = x264_integral_init8v_sse2; pf->mbtree_propagate_cost = x264_mbtree_propagate_cost_sse2; @@ -589,7 +598,7 @@ void x264_mc_init_mmx( int cpu, x264_mc_functions_t *pf ) pf->avg[PIXEL_4x4] = x264_pixel_avg_4x4_sse2; pf->avg[PIXEL_4x2] = x264_pixel_avg_4x2_sse2; - pf->copy[PIXEL_16x16] = x264_mc_copy_w16_aligned_sse2; + pf->copy[PIXEL_16x16] = x264_mc_copy_w16_aligned_sse; pf->weight = x264_mc_weight_wtab_sse2; if( !(cpu&X264_CPU_STACK_MOD4) ) @@ -600,7 +609,7 @@ void x264_mc_init_mmx( int cpu, x264_mc_functions_t *pf ) pf->frame_init_lowres_core = x264_frame_init_lowres_core_ssse3; - if( (cpu&X264_CPU_SHUFFLE_IS_FAST) && !(cpu&X264_CPU_SLOW_ATOM) ) + if( !(cpu&(X264_CPU_SLOW_SHUFFLE|X264_CPU_SLOW_ATOM|X264_CPU_SLOW_PALIGNR)) ) pf->integral_init4v = x264_integral_init4v_ssse3; if( !(cpu&X264_CPU_AVX) ) @@ -638,55 +647,53 @@ void x264_mc_init_mmx( int cpu, x264_mc_functions_t *pf ) if( !(cpu&X264_CPU_SSE2) ) return; - pf->memcpy_aligned = x264_memcpy_aligned_sse2; - pf->memzero_aligned = x264_memzero_aligned_sse2; pf->integral_init4v = x264_integral_init4v_sse2; pf->integral_init8v = x264_integral_init8v_sse2; pf->hpel_filter = x264_hpel_filter_sse2_amd; pf->mbtree_propagate_cost = x264_mbtree_propagate_cost_sse2; - if( cpu&X264_CPU_SSE2_IS_SLOW ) - return; - - pf->weight = x264_mc_weight_wtab_sse2; - if( !(cpu&X264_CPU_SLOW_ATOM) ) - { - pf->offsetadd = x264_mc_offsetadd_wtab_sse2; - pf->offsetsub = x264_mc_offsetsub_wtab_sse2; - } - - pf->copy[PIXEL_16x16] = x264_mc_copy_w16_aligned_sse2; - pf->avg[PIXEL_16x16] = x264_pixel_avg_16x16_sse2; - pf->avg[PIXEL_16x8] = x264_pixel_avg_16x8_sse2; - pf->avg[PIXEL_8x16] = x264_pixel_avg_8x16_sse2; - pf->avg[PIXEL_8x8] = x264_pixel_avg_8x8_sse2; - pf->avg[PIXEL_8x4] = x264_pixel_avg_8x4_sse2; - pf->hpel_filter = x264_hpel_filter_sse2; - if( cpu&X264_CPU_SSE_MISALIGN ) - pf->hpel_filter = x264_hpel_filter_sse2_misalign; - pf->frame_init_lowres_core = x264_frame_init_lowres_core_sse2; - if( !(cpu&X264_CPU_STACK_MOD4) ) - pf->mc_chroma = x264_mc_chroma_sse2; - - if( cpu&X264_CPU_SSE2_IS_FAST ) + if( !(cpu&X264_CPU_SSE2_IS_SLOW) ) { - pf->store_interleave_chroma = x264_store_interleave_chroma_sse2; // FIXME sse2fast? sse2medium? - pf->load_deinterleave_chroma_fenc = x264_load_deinterleave_chroma_fenc_sse2; - pf->load_deinterleave_chroma_fdec = x264_load_deinterleave_chroma_fdec_sse2; - pf->plane_copy_interleave = x264_plane_copy_interleave_sse2; - pf->plane_copy_deinterleave = x264_plane_copy_deinterleave_sse2; - pf->mc_luma = mc_luma_sse2; - pf->get_ref = get_ref_sse2; - if( cpu&X264_CPU_CACHELINE_64 ) + pf->weight = x264_mc_weight_wtab_sse2; + if( !(cpu&X264_CPU_SLOW_ATOM) ) { - pf->mc_luma = mc_luma_cache64_sse2; - pf->get_ref = get_ref_cache64_sse2; + pf->offsetadd = x264_mc_offsetadd_wtab_sse2; + pf->offsetsub = x264_mc_offsetsub_wtab_sse2; } + + pf->copy[PIXEL_16x16] = x264_mc_copy_w16_aligned_sse; + pf->avg[PIXEL_16x16] = x264_pixel_avg_16x16_sse2; + pf->avg[PIXEL_16x8] = x264_pixel_avg_16x8_sse2; + pf->avg[PIXEL_8x16] = x264_pixel_avg_8x16_sse2; + pf->avg[PIXEL_8x8] = x264_pixel_avg_8x8_sse2; + pf->avg[PIXEL_8x4] = x264_pixel_avg_8x4_sse2; + pf->hpel_filter = x264_hpel_filter_sse2; if( cpu&X264_CPU_SSE_MISALIGN ) + pf->hpel_filter = x264_hpel_filter_sse2_misalign; + pf->frame_init_lowres_core = x264_frame_init_lowres_core_sse2; + if( !(cpu&X264_CPU_STACK_MOD4) ) + pf->mc_chroma = x264_mc_chroma_sse2; + + if( cpu&X264_CPU_SSE2_IS_FAST ) { - pf->get_ref = get_ref_sse2_misalign; - if( !(cpu&X264_CPU_STACK_MOD4) ) - pf->mc_chroma = x264_mc_chroma_sse2_misalign; + pf->store_interleave_chroma = x264_store_interleave_chroma_sse2; // FIXME sse2fast? sse2medium? + pf->load_deinterleave_chroma_fenc = x264_load_deinterleave_chroma_fenc_sse2; + pf->load_deinterleave_chroma_fdec = x264_load_deinterleave_chroma_fdec_sse2; + pf->plane_copy_interleave = x264_plane_copy_interleave_sse2; + pf->plane_copy_deinterleave = x264_plane_copy_deinterleave_sse2; + pf->mc_luma = mc_luma_sse2; + pf->get_ref = get_ref_sse2; + if( cpu&X264_CPU_CACHELINE_64 ) + { + pf->mc_luma = mc_luma_cache64_sse2; + pf->get_ref = get_ref_cache64_sse2; + } + if( cpu&X264_CPU_SSE_MISALIGN ) + { + pf->get_ref = get_ref_sse2_misalign; + if( !(cpu&X264_CPU_STACK_MOD4) ) + pf->mc_chroma = x264_mc_chroma_sse2_misalign; + } } } @@ -703,12 +710,21 @@ void x264_mc_init_mmx( int cpu, x264_mc_functions_t *pf ) pf->avg[PIXEL_4x4] = x264_pixel_avg_4x4_ssse3; pf->avg[PIXEL_4x2] = x264_pixel_avg_4x2_ssse3; - pf->load_deinterleave_chroma_fenc = x264_load_deinterleave_chroma_fenc_ssse3; - pf->load_deinterleave_chroma_fdec = x264_load_deinterleave_chroma_fdec_ssse3; - pf->plane_copy_deinterleave = x264_plane_copy_deinterleave_ssse3; + if( !(cpu&X264_CPU_SLOW_PSHUFB) ) + { + pf->load_deinterleave_chroma_fenc = x264_load_deinterleave_chroma_fenc_ssse3; + pf->load_deinterleave_chroma_fdec = x264_load_deinterleave_chroma_fdec_ssse3; + pf->plane_copy_deinterleave = x264_plane_copy_deinterleave_ssse3; + } - pf->hpel_filter = x264_hpel_filter_ssse3; - pf->frame_init_lowres_core = x264_frame_init_lowres_core_ssse3; + if( !(cpu&X264_CPU_SLOW_PALIGNR) ) + { +#if ARCH_X86_64 + if( !(cpu&X264_CPU_SLOW_ATOM) ) /* The 64-bit version is slower, but the 32-bit version is faster? */ +#endif + pf->hpel_filter = x264_hpel_filter_ssse3; + pf->frame_init_lowres_core = x264_frame_init_lowres_core_ssse3; + } if( !(cpu&X264_CPU_STACK_MOD4) ) pf->mc_chroma = x264_mc_chroma_ssse3; @@ -718,13 +734,17 @@ void x264_mc_init_mmx( int cpu, x264_mc_functions_t *pf ) pf->mc_chroma = x264_mc_chroma_ssse3_cache64; pf->mc_luma = mc_luma_cache64_ssse3; pf->get_ref = get_ref_cache64_ssse3; - - /* ssse3 weight is slower on Nehalem, so only assign here. */ - pf->weight_cache = x264_weight_cache_ssse3; - pf->weight = x264_mc_weight_wtab_ssse3; + if( cpu&X264_CPU_SLOW_ATOM ) + { + pf->mc_luma = mc_luma_cache64_ssse3_atom; + pf->get_ref = get_ref_cache64_ssse3_atom; + } } - if( (cpu&X264_CPU_SHUFFLE_IS_FAST) && !(cpu&X264_CPU_SLOW_ATOM) ) + pf->weight_cache = x264_weight_cache_ssse3; + pf->weight = x264_mc_weight_wtab_ssse3; + + if( !(cpu&(X264_CPU_SLOW_SHUFFLE|X264_CPU_SLOW_ATOM|X264_CPU_SLOW_PALIGNR)) ) pf->integral_init4v = x264_integral_init4v_ssse3; if( !(cpu&X264_CPU_SSE4) ) @@ -740,9 +760,6 @@ void x264_mc_init_mmx( int cpu, x264_mc_functions_t *pf ) pf->integral_init8h = x264_integral_init8h_avx; pf->hpel_filter = x264_hpel_filter_avx; - /* ssse3 weight seems to be faster again on Sandy Bridge and Bulldozer. */ - pf->weight_cache = x264_weight_cache_ssse3; - pf->weight = x264_mc_weight_wtab_ssse3; if( !(cpu&X264_CPU_STACK_MOD4) ) pf->mc_chroma = x264_mc_chroma_avx; @@ -754,7 +771,12 @@ void x264_mc_init_mmx( int cpu, x264_mc_functions_t *pf ) return; pf->mbtree_propagate_cost = x264_mbtree_propagate_cost_avx; - if( !(cpu&X264_CPU_FMA4) ) + if( cpu&X264_CPU_FMA4 ) + pf->mbtree_propagate_cost = x264_mbtree_propagate_cost_fma4; + + if( !(cpu&X264_CPU_AVX2) ) return; - pf->mbtree_propagate_cost = x264_mbtree_propagate_cost_fma4; + + if( cpu&X264_CPU_FMA3 ) + pf->mbtree_propagate_cost = x264_mbtree_propagate_cost_avx2_fma3; } diff --git a/common/x86/mc.h b/common/x86/mc.h index 82e2b5a7..4287f6d0 100644 --- a/common/x86/mc.h +++ b/common/x86/mc.h @@ -1,7 +1,7 @@ /***************************************************************************** * mc.h: x86 motion compensation ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Loren Merritt * Laurent Aimar diff --git a/common/x86/pixel-32.asm b/common/x86/pixel-32.asm index 77a87421..58324bf8 100644 --- a/common/x86/pixel-32.asm +++ b/common/x86/pixel-32.asm @@ -1,7 +1,7 @@ ;***************************************************************************** ;* pixel-32.asm: x86_32 pixel metrics ;***************************************************************************** -;* Copyright (C) 2003-2012 x264 project +;* Copyright (C) 2003-2013 x264 project ;* ;* Authors: Loren Merritt ;* Laurent Aimar diff --git a/common/x86/pixel-a.asm b/common/x86/pixel-a.asm index b8803232..bf0d27a8 100644 --- a/common/x86/pixel-a.asm +++ b/common/x86/pixel-a.asm @@ -1,7 +1,7 @@ ;***************************************************************************** ;* pixel.asm: x86 pixel metrics ;***************************************************************************** -;* Copyright (C) 2003-2012 x264 project +;* Copyright (C) 2003-2013 x264 project ;* ;* Authors: Loren Merritt ;* Holger Lubitz @@ -136,6 +136,7 @@ cextern pw_ppppmmmm cextern pw_ppmmppmm cextern pw_pmpmpmpm cextern pw_pmmpzzzz +cextern pd_1 cextern hsub_mul ;============================================================================= @@ -147,69 +148,67 @@ cextern hsub_mul ; int pixel_ssd_MxN( uint16_t *, intptr_t, uint16_t *, intptr_t ) ;----------------------------------------------------------------------------- %macro SSD_ONE 2 -cglobal pixel_ssd_%1x%2, 4,5,6 - mov r4, %1*%2/mmsize +cglobal pixel_ssd_%1x%2, 4,7,6 + FIX_STRIDES r1, r3 +%if mmsize == %1*2 + %define offset0_1 r1 + %define offset0_2 r1*2 + %define offset0_3 r5 + %define offset1_1 r3 + %define offset1_2 r3*2 + %define offset1_3 r6 + lea r5, [3*r1] + lea r6, [3*r3] +%elif mmsize == %1 + %define offset0_1 mmsize + %define offset0_2 r1 + %define offset0_3 r1+mmsize + %define offset1_1 mmsize + %define offset1_2 r3 + %define offset1_3 r3+mmsize +%elif mmsize == %1/2 + %define offset0_1 mmsize + %define offset0_2 mmsize*2 + %define offset0_3 mmsize*3 + %define offset1_1 mmsize + %define offset1_2 mmsize*2 + %define offset1_3 mmsize*3 +%endif + %assign %%n %2/(2*mmsize/%1) +%if %%n > 1 + mov r4d, %%n +%endif pxor m0, m0 .loop mova m1, [r0] -%if %1 <= mmsize/2 - mova m3, [r0+r1*2] - %define offset r3*2 - %define num_rows 2 -%else - mova m3, [r0+mmsize] - %define offset mmsize - %define num_rows 1 -%endif - lea r0, [r0+r1*2*num_rows] + mova m2, [r0+offset0_1] + mova m3, [r0+offset0_2] + mova m4, [r0+offset0_3] psubw m1, [r2] - psubw m3, [r2+offset] - lea r2, [r2+r3*2*num_rows] + psubw m2, [r2+offset1_1] + psubw m3, [r2+offset1_2] + psubw m4, [r2+offset1_3] +%if %%n > 1 + lea r0, [r0+r1*(%2/%%n)] + lea r2, [r2+r3*(%2/%%n)] +%endif pmaddwd m1, m1 + pmaddwd m2, m2 pmaddwd m3, m3 + pmaddwd m4, m4 + paddd m1, m2 + paddd m3, m4 paddd m0, m1 paddd m0, m3 - dec r4 +%if %%n > 1 + dec r4d jg .loop +%endif HADDD m0, m5 movd eax, m0 RET %endmacro -%macro SSD_16_MMX 2 -cglobal pixel_ssd_%1x%2, 4,5 - mov r4, %1*%2/mmsize/2 - pxor m0, m0 -.loop - mova m1, [r0] - mova m2, [r2] - mova m3, [r0+mmsize] - mova m4, [r2+mmsize] - mova m5, [r0+mmsize*2] - mova m6, [r2+mmsize*2] - mova m7, [r0+mmsize*3] - psubw m1, m2 - psubw m3, m4 - mova m2, [r2+mmsize*3] - psubw m5, m6 - pmaddwd m1, m1 - psubw m7, m2 - pmaddwd m3, m3 - pmaddwd m5, m5 - lea r0, [r0+r1*2] - lea r2, [r2+r3*2] - pmaddwd m7, m7 - paddd m1, m3 - paddd m5, m7 - paddd m0, m1 - paddd m0, m5 - dec r4 - jg .loop - HADDD m0, m7 - movd eax, m0 - RET -%endmacro - INIT_MMX mmx2 SSD_ONE 4, 4 SSD_ONE 4, 8 @@ -217,8 +216,8 @@ SSD_ONE 4, 16 SSD_ONE 8, 4 SSD_ONE 8, 8 SSD_ONE 8, 16 -SSD_16_MMX 16, 8 -SSD_16_MMX 16, 16 +SSD_ONE 16, 8 +SSD_ONE 16, 16 INIT_XMM sse2 SSD_ONE 8, 4 SSD_ONE 8, 8 @@ -962,7 +961,7 @@ VAR2_8x8_SSSE3 16, 7 %if cpuflag(sse4) ; just use shufps on anything post conroe shufps %1, %2, 0 -%elif cpuflag(ssse3) +%elif cpuflag(ssse3) && notcpuflag(atom) ; join 2x 32 bit and duplicate them ; emulating shufps is faster on conroe punpcklqdq %1, %2 @@ -1023,7 +1022,7 @@ VAR2_8x8_SSSE3 16, 7 DIFF_SUMSUB_SSSE3 %1, %3, %2, %4, %5 %endmacro -%macro LOAD_SUMSUB_8x4P_SSSE3 7-10 r0, r2, 0 +%macro LOAD_SUMSUB_8x4P_SSSE3 7-11 r0, r2, 0, 0 ; 4x dest, 2x tmp, 1x mul, [2* ptr], [increment?] LOAD_SUMSUB_8x2P %1, %2, %5, %6, %7, [%8], [%9], [%8+r1], [%9+r3] LOAD_SUMSUB_8x2P %3, %4, %5, %6, %7, [%8+2*r1], [%9+2*r3], [%8+r4], [%9+r5] @@ -1080,8 +1079,9 @@ VAR2_8x8_SSSE3 16, 7 SWAP %%n, 4 %endmacro +; in: %1 = horizontal if 0, vertical if 1 %macro SATD_8x4_SSE 8-9 -%ifidn %1, sse2 +%if %1 HADAMARD4_2D_SSE %2, %3, %4, %5, %6, amax %else HADAMARD4_V %2, %3, %4, %5, %6 @@ -1095,7 +1095,7 @@ VAR2_8x8_SSSE3 16, 7 %else SWAP %8, %2 %endif -%ifidn %1, sse2 +%if %1 paddw m%8, m%4 %else HADAMARD 1, max, %3, %5, %6, %7 @@ -1250,8 +1250,11 @@ cglobal pixel_satd_4x4, 4,6 SATD_4x4_MMX m0, 0, 0 SATD_END_MMX -%macro SATD_START_SSE2 2 -%if cpuflag(ssse3) +%macro SATD_START_SSE2 2-3 0 + FIX_STRIDES r1, r3 +%if HIGH_BIT_DEPTH && %3 + pxor %2, %2 +%elif cpuflag(ssse3) && notcpuflag(atom) mova %2, [hmul_8p] %endif lea r4, [3*r1] @@ -1259,12 +1262,27 @@ cglobal pixel_satd_4x4, 4,6 pxor %1, %1 %endmacro -%macro SATD_END_SSE2 1 +%macro SATD_END_SSE2 1-2 +%if HIGH_BIT_DEPTH + HADDUW %1, m0 +%if %0 == 2 + paddd %1, %2 +%endif +%else HADDW %1, m7 +%endif movd eax, %1 RET %endmacro +%macro SATD_ACCUM 3 +%if HIGH_BIT_DEPTH + HADDUW %1, %2 + paddd %3, %1 + pxor %1, %1 +%endif +%endmacro + %macro BACKUP_POINTERS 0 %if ARCH_X86_64 %if WIN64 @@ -1277,20 +1295,44 @@ cglobal pixel_satd_4x4, 4,6 %macro RESTORE_AND_INC_POINTERS 0 %if ARCH_X86_64 - lea r0, [r6+8] - lea r2, [r7+8] + lea r0, [r6+8*SIZEOF_PIXEL] + lea r2, [r7+8*SIZEOF_PIXEL] %if WIN64 POP r7 %endif %else mov r0, r0mp mov r2, r2mp - add r0, 8 - add r2, 8 + add r0, 8*SIZEOF_PIXEL + add r2, 8*SIZEOF_PIXEL %endif %endmacro -%macro SATD_4x8_SSE 2 +%macro SATD_4x8_SSE 3 +%if HIGH_BIT_DEPTH + movh m0, [r0+0*r1] + movh m4, [r2+0*r3] + movh m1, [r0+1*r1] + movh m5, [r2+1*r3] + movhps m0, [r0+4*r1] + movhps m4, [r2+4*r3] + movh m2, [r0+2*r1] + movh m6, [r2+2*r3] + psubw m0, m4 + movh m3, [r0+r4] + movh m4, [r2+r5] + lea r0, [r0+4*r1] + lea r2, [r2+4*r3] + movhps m1, [r0+1*r1] + movhps m5, [r2+1*r3] + movhps m2, [r0+2*r1] + movhps m6, [r2+2*r3] + psubw m1, m5 + movhps m3, [r0+r4] + movhps m4, [r2+r5] + psubw m2, m6 + psubw m3, m4 +%else ; !HIGH_BIT_DEPTH movd m4, [r2] movd m5, [r2+r3] movd m6, [r2+2*r3] @@ -1307,7 +1349,7 @@ cglobal pixel_satd_4x4, 4,6 JDUP m5, m3 movd m3, [r0+2*r1] JDUP m1, m3 -%if cpuflag(ssse3) && %1==1 +%if %1==0 && %2==1 mova m3, [hmul_4p] DIFFOP 0, 4, 1, 5, 3 %else @@ -1325,20 +1367,23 @@ cglobal pixel_satd_4x4, 4,6 JDUP m5, m4 movd m4, [r0+r1] JDUP m3, m4 -%if cpuflag(ssse3) && %1==1 +%if %1==0 && %2==1 mova m4, [hmul_4p] DIFFOP 2, 6, 3, 5, 4 %else DIFFOP 2, 6, 3, 5, 7 %endif - SATD_8x4_SSE cpuname, 0, 1, 2, 3, 4, 5, 7, %2 +%endif ; HIGH_BIT_DEPTH + SATD_8x4_SSE %1, 0, 1, 2, 3, 4, 5, 7, %3 %endmacro ;----------------------------------------------------------------------------- ; int pixel_satd_8x4( uint8_t *, intptr_t, uint8_t *, intptr_t ) ;----------------------------------------------------------------------------- %macro SATDS_SSE2 0 -%if cpuflag(ssse3) +%define vertical ((notcpuflag(ssse3) || cpuflag(atom)) || HIGH_BIT_DEPTH) + +%if vertical==0 || HIGH_BIT_DEPTH cglobal pixel_satd_4x4, 4, 6, 6 SATD_START_MMX mova m4, [hmul_4p] @@ -1357,55 +1402,57 @@ cglobal pixel_satd_4x4, 4, 6, 6 cglobal pixel_satd_4x8, 4, 6, 8 SATD_START_MMX -%if cpuflag(ssse3) +%if vertical==0 mova m7, [hmul_4p] %endif - SATD_4x8_SSE 0, swap + SATD_4x8_SSE vertical, 0, swap HADDW m7, m1 movd eax, m7 RET cglobal pixel_satd_4x16, 4, 6, 8 SATD_START_MMX -%if cpuflag(ssse3) +%if vertical==0 mova m7, [hmul_4p] %endif - SATD_4x8_SSE 0, swap - lea r0, [r0+r1*2] - lea r2, [r2+r3*2] - SATD_4x8_SSE 1, add + SATD_4x8_SSE vertical, 0, swap + lea r0, [r0+r1*2*SIZEOF_PIXEL] + lea r2, [r2+r3*2*SIZEOF_PIXEL] + SATD_4x8_SSE vertical, 1, add HADDW m7, m1 movd eax, m7 RET cglobal pixel_satd_8x8_internal - LOAD_SUMSUB_8x4P 0, 1, 2, 3, 4, 5, 7, r0, r2, 1 - SATD_8x4_SSE cpuname, 0, 1, 2, 3, 4, 5, 6 + LOAD_SUMSUB_8x4P 0, 1, 2, 3, 4, 5, 7, r0, r2, 1, 0 + SATD_8x4_SSE vertical, 0, 1, 2, 3, 4, 5, 6 %%pixel_satd_8x4_internal: - LOAD_SUMSUB_8x4P 0, 1, 2, 3, 4, 5, 7, r0, r2, 1 - SATD_8x4_SSE cpuname, 0, 1, 2, 3, 4, 5, 6 + LOAD_SUMSUB_8x4P 0, 1, 2, 3, 4, 5, 7, r0, r2, 1, 0 + SATD_8x4_SSE vertical, 0, 1, 2, 3, 4, 5, 6 ret -%if UNIX64 ; 16x8 regresses on phenom win64, 16x16 is almost the same +; 16x8 regresses on phenom win64, 16x16 is almost the same (too many spilled registers) +; These aren't any faster on AVX systems with fast movddup (Bulldozer, Sandy Bridge) +%if HIGH_BIT_DEPTH == 0 && UNIX64 && notcpuflag(avx) cglobal pixel_satd_16x4_internal LOAD_SUMSUB_16x4P 0, 1, 2, 3, 4, 8, 5, 9, 6, 7, r0, r2, 11 lea r2, [r2+4*r3] lea r0, [r0+4*r1] - ; FIXME: this doesn't really mean ssse3, but rather selects between two different behaviors implemented with sse2? - SATD_8x4_SSE ssse3, 0, 1, 2, 3, 6, 11, 10 - SATD_8x4_SSE ssse3, 4, 8, 5, 9, 6, 3, 10 + ; always use horizontal mode here + SATD_8x4_SSE 0, 0, 1, 2, 3, 6, 11, 10 + SATD_8x4_SSE 0, 4, 8, 5, 9, 6, 3, 10 ret cglobal pixel_satd_16x8, 4,6,12 SATD_START_SSE2 m10, m7 -%if notcpuflag(ssse3) +%if vertical mova m7, [pw_00ff] %endif jmp %%pixel_satd_16x8_internal cglobal pixel_satd_16x16, 4,6,12 SATD_START_SSE2 m10, m7 -%if notcpuflag(ssse3) +%if vertical mova m7, [pw_00ff] %endif call pixel_satd_16x4_internal @@ -1424,14 +1471,15 @@ cglobal pixel_satd_16x8, 4,6,8 SATD_END_SSE2 m6 cglobal pixel_satd_16x16, 4,6,8 - SATD_START_SSE2 m6, m7 + SATD_START_SSE2 m6, m7, 1 BACKUP_POINTERS call pixel_satd_8x8_internal call pixel_satd_8x8_internal + SATD_ACCUM m6, m0, m7 RESTORE_AND_INC_POINTERS call pixel_satd_8x8_internal call pixel_satd_8x8_internal - SATD_END_SSE2 m6 + SATD_END_SSE2 m6, m7 %endif cglobal pixel_satd_8x16, 4,6,8 @@ -1468,11 +1516,8 @@ cglobal pixel_satd_8x4, 4,6,8 %endmacro %macro SA8D 0 -%if HIGH_BIT_DEPTH - %define vertical 1 -%else ; sse2 doesn't seem to like the horizontal way of doing things - %define vertical (cpuflags == cpuflags_sse2) -%endif +; sse2 doesn't seem to like the horizontal way of doing things +%define vertical ((notcpuflag(ssse3) || cpuflag(atom)) || HIGH_BIT_DEPTH) %if ARCH_X86_64 ;----------------------------------------------------------------------------- @@ -1678,6 +1723,158 @@ cglobal pixel_sa8d_16x16, 4,7 %endif ; !ARCH_X86_64 %endmacro ; SA8D +;============================================================================= +; SA8D_SATD +;============================================================================= + +; %1: vertical/horizontal mode +; %2-%5: sa8d output regs (m0,m1,m2,m3,m4,m5,m8,m9) +; m10: satd result +; m6, m11-15: tmp regs +%macro SA8D_SATD_8x4 5 +%if %1 + LOAD_DIFF_8x4P %2, %3, %4, %5, 6, 11, 7, r0, r2, 1 + HADAMARD 0, sumsub, %2, %3, 6 + HADAMARD 0, sumsub, %4, %5, 6 + SBUTTERFLY wd, %2, %3, 6 + SBUTTERFLY wd, %4, %5, 6 + HADAMARD2_2D %2, %4, %3, %5, 6, dq + + mova m12, m%2 + mova m13, m%3 + mova m14, m%4 + mova m15, m%5 + HADAMARD 0, sumsub, %2, %3, 6 + HADAMARD 0, sumsub, %4, %5, 6 + SBUTTERFLY qdq, 12, 13, 6 + HADAMARD 0, amax, 12, 13, 6 + SBUTTERFLY qdq, 14, 15, 6 + paddw m10, m12 + HADAMARD 0, amax, 14, 15, 6 + paddw m10, m14 +%else + LOAD_SUMSUB_8x4P_SSSE3 %2, %3, %4, %5, 6, 11, 7, r0, r2, 1 + HADAMARD4_V %2, %3, %4, %5, 6 + + pabsw m12, m%2 ; doing the abs first is a slight advantage + pabsw m14, m%4 + pabsw m13, m%3 + pabsw m15, m%5 + HADAMARD 1, max, 12, 14, 6, 11 + paddw m10, m12 + HADAMARD 1, max, 13, 15, 6, 11 + paddw m10, m13 +%endif +%endmacro ; SA8D_SATD_8x4 + +; %1: add spilled regs? +; %2: spill regs? +%macro SA8D_SATD_ACCUM 2 +%if HIGH_BIT_DEPTH + pmaddwd m10, [pw_1] + HADDUWD m0, m1 +%if %1 + paddd m10, temp1 + paddd m0, temp0 +%endif +%if %2 + mova temp1, m10 + pxor m10, m10 +%endif +%elif %1 + paddw m0, temp0 +%endif +%if %2 + mova temp0, m0 +%endif +%endmacro + +%macro SA8D_SATD 0 +%define vertical ((notcpuflag(ssse3) || cpuflag(atom)) || HIGH_BIT_DEPTH) +cglobal pixel_sa8d_satd_8x8_internal + SA8D_SATD_8x4 vertical, 0, 1, 2, 3 + SA8D_SATD_8x4 vertical, 4, 5, 8, 9 + +%if vertical ; sse2-style + HADAMARD2_2D 0, 4, 2, 8, 6, qdq, amax + HADAMARD2_2D 1, 5, 3, 9, 6, qdq, amax +%else ; complete sa8d + SUMSUB_BADC w, 0, 4, 1, 5, 12 + HADAMARD 2, sumsub, 0, 4, 12, 11 + HADAMARD 2, sumsub, 1, 5, 12, 11 + SUMSUB_BADC w, 2, 8, 3, 9, 12 + HADAMARD 2, sumsub, 2, 8, 12, 11 + HADAMARD 2, sumsub, 3, 9, 12, 11 + HADAMARD 1, amax, 0, 4, 12, 11 + HADAMARD 1, amax, 1, 5, 12, 4 + HADAMARD 1, amax, 2, 8, 12, 4 + HADAMARD 1, amax, 3, 9, 12, 4 +%endif + + ; create sa8d sub results + paddw m1, m2 + paddw m0, m3 + paddw m0, m1 + + SAVE_MM_PERMUTATION + ret + +;------------------------------------------------------------------------------- +; uint64_t pixel_sa8d_satd_16x16( pixel *, intptr_t, pixel *, intptr_t ) +;------------------------------------------------------------------------------- +cglobal pixel_sa8d_satd_16x16, 4,8,16,SIZEOF_PIXEL*mmsize + %define temp0 [rsp+0*mmsize] + %define temp1 [rsp+1*mmsize] + FIX_STRIDES r1, r3 +%if vertical==0 + mova m7, [hmul_8p] +%endif + lea r4, [3*r1] + lea r5, [3*r3] + lea r6, [r2+8*SIZEOF_PIXEL] + lea r7, [r0+8*SIZEOF_PIXEL] + pxor m10, m10 + + call pixel_sa8d_satd_8x8_internal + SA8D_SATD_ACCUM 0, 1 + call pixel_sa8d_satd_8x8_internal + SA8D_SATD_ACCUM 1, 1 + + mov r0, r7 + mov r2, r6 + + call pixel_sa8d_satd_8x8_internal + SA8D_SATD_ACCUM 1, 1 + call pixel_sa8d_satd_8x8_internal + SA8D_SATD_ACCUM 1, 0 + +; xop already has fast horizontal sums +%if cpuflag(sse4) && notcpuflag(xop) && HIGH_BIT_DEPTH==0 + pmaddwd m10, [pw_1] + HADDUWD m0, m1 + phaddd m0, m10 ; sa8d1 sa8d2 satd1 satd2 + pshufd m1, m0, q2301 ; sa8d2 sa8d1 satd2 satd1 + paddd m0, m1 ; sa8d sa8d satd satd + movd r0d, m0 + pextrd eax, m0, 2 +%else +%if HIGH_BIT_DEPTH + HADDD m0, m1 + HADDD m10, m2 +%else + HADDUW m0, m1 + HADDW m10, m2 +%endif + movd r0d, m0 + movd eax, m10 +%endif + add r0d, 1 + shl rax, 32 + shr r0d, 1 + or rax, r0 + RET +%endmacro ; SA8D_SATD + ;============================================================================= ; INTRA SATD ;============================================================================= @@ -1913,15 +2110,16 @@ cglobal hadamard_load ; void intra_satd_x3_4x4( uint8_t *fenc, uint8_t *fdec, int *res ) ;----------------------------------------------------------------------------- cglobal intra_satd_x3_4x4, 3,3 -%if ARCH_X86_64 +%if UNIX64 ; stack is 16 byte aligned because abi says so %define top_1d rsp-8 ; size 8 %define left_1d rsp-16 ; size 8 %else - ; stack is 16 byte aligned at least in gcc, and we've pushed 3 regs + return address, so it's still aligned - SUB esp, 16 - %define top_1d esp+8 - %define left_1d esp + ; WIN64: stack is 16 byte aligned because abi says so + ; X86_32: stack is 16 byte aligned at least in gcc, and we've pushed 3 regs + return address, so it's still aligned + SUB rsp, 16 + %define top_1d rsp+8 + %define left_1d rsp %endif call hadamard_load @@ -1943,8 +2141,8 @@ cglobal intra_satd_x3_4x4, 3,3 movd [r2+0], m0 ; i4x4_v satd movd [r2+4], m4 ; i4x4_h satd movd [r2+8], m5 ; i4x4_dc satd -%if ARCH_X86_64 == 0 - ADD esp, 16 +%if UNIX64 == 0 + ADD rsp, 16 %endif RET @@ -2526,7 +2724,7 @@ ALIGN 16 psubw m1, m9 psubw m2, m10 psubw m3, m11 - SATD_8x4_SSE cpuname, 0, 1, 2, 3, 13, 14, 0, swap + SATD_8x4_SSE 0, 0, 1, 2, 3, 13, 14, 0, swap pmaddwd m0, [pw_1] %if cpuflag(sse4) pshufd m1, m0, q0032 @@ -2634,7 +2832,7 @@ ALIGN 16 psubw m2, [fenc_buf+0x20] .satd_8x4b: psubw m3, [fenc_buf+0x30] - SATD_8x4_SSE cpuname, 0, 1, 2, 3, 4, 5, 0, swap + SATD_8x4_SSE 0, 0, 1, 2, 3, 4, 5, 0, swap pmaddwd m0, [pw_1] %if cpuflag(sse4) pshufd m1, m0, q0032 @@ -3579,7 +3777,7 @@ cglobal hadamard_ac_8x8 %endif %if HIGH_BIT_DEPTH %define vertical 1 -%elif cpuflag(ssse3) +%elif cpuflag(ssse3) && notcpuflag(atom) %define vertical 0 ;LOAD_INC loads sumsubs mova m7, [hmul_8p] @@ -3775,6 +3973,9 @@ SA8D INIT_XMM sse2 SA8D SATDS_SSE2 +%if ARCH_X86_64 +SA8D_SATD +%endif %if HIGH_BIT_DEPTH == 0 INTRA_SA8D_SSE2 %endif @@ -3783,6 +3984,16 @@ INTRA_X3_MMX INIT_XMM sse2 HADAMARD_AC_SSE2 +%if HIGH_BIT_DEPTH == 0 +INIT_XMM ssse3,atom +SATDS_SSE2 +SA8D +HADAMARD_AC_SSE2 +%if ARCH_X86_64 +SA8D_SATD +%endif +%endif + %define DIFFOP DIFF_SUMSUB_SSSE3 %define LOAD_DUP_4x8P LOAD_DUP_4x8P_CONROE %if HIGH_BIT_DEPTH == 0 @@ -3794,6 +4005,9 @@ INIT_XMM ssse3 SATDS_SSE2 SA8D HADAMARD_AC_SSE2 +%if ARCH_X86_64 +SA8D_SATD +%endif %if HIGH_BIT_DEPTH == 0 INTRA_X9 INTRA8_X9 @@ -3812,14 +4026,23 @@ INIT_XMM sse4 SATDS_SSE2 SA8D HADAMARD_AC_SSE2 +%if ARCH_X86_64 +SA8D_SATD +%endif %if HIGH_BIT_DEPTH == 0 INTRA_X9 INTRA8_X9 %endif +; Sandy/Ivy Bridge and Bulldozer do movddup in the load unit, so +; it's effectively free. +%define LOAD_DUP_4x8P LOAD_DUP_4x8P_CONROE INIT_XMM avx SATDS_SSE2 SA8D +%if ARCH_X86_64 +SA8D_SATD +%endif %if HIGH_BIT_DEPTH == 0 INTRA_X9 INTRA8_X9 @@ -3830,6 +4053,9 @@ HADAMARD_AC_SSE2 INIT_XMM xop SATDS_SSE2 SA8D +%if ARCH_X86_64 +SA8D_SATD +%endif %if HIGH_BIT_DEPTH == 0 INTRA_X9 ; no xop INTRA8_X9. it's slower than avx on bulldozer. dunno why. @@ -4001,6 +4227,73 @@ SSIM INIT_XMM avx SSIM +;----------------------------------------------------------------------------- +; int pixel_asd8( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2, int height ); +;----------------------------------------------------------------------------- +%macro ASD8 0 +cglobal pixel_asd8, 5,5 + pxor m0, m0 + pxor m1, m1 +.loop: +%if HIGH_BIT_DEPTH + paddw m0, [r0] + paddw m1, [r2] + paddw m0, [r0+2*r1] + paddw m1, [r2+2*r3] + lea r0, [r0+4*r1] + paddw m0, [r0] + paddw m1, [r2+4*r3] + lea r2, [r2+4*r3] + paddw m0, [r0+2*r1] + paddw m1, [r2+2*r3] + lea r0, [r0+4*r1] + lea r2, [r2+4*r3] +%else + movq m2, [r0] + movq m3, [r2] + movhps m2, [r0+r1] + movhps m3, [r2+r3] + lea r0, [r0+2*r1] + psadbw m2, m1 + psadbw m3, m1 + movq m4, [r0] + movq m5, [r2+2*r3] + lea r2, [r2+2*r3] + movhps m4, [r0+r1] + movhps m5, [r2+r3] + lea r0, [r0+2*r1] + paddw m0, m2 + psubw m0, m3 + psadbw m4, m1 + psadbw m5, m1 + lea r2, [r2+2*r3] + paddw m0, m4 + psubw m0, m5 +%endif + sub r4d, 4 + jg .loop +%if HIGH_BIT_DEPTH + psubw m0, m1 + HADDW m0, m1 + ABSD m1, m0 +%else + movhlps m1, m0 + paddw m0, m1 + ABSW m1, m0 +%endif + movd eax, m1 + RET +%endmacro + +INIT_XMM sse2 +ASD8 +INIT_XMM ssse3 +ASD8 +%if HIGH_BIT_DEPTH +INIT_XMM xop +ASD8 +%endif + ;============================================================================= ; Successive Elimination ADS ;============================================================================= @@ -4117,8 +4410,8 @@ cglobal pixel_ads4, 5,7,12 punpckhqdq xmm5, xmm5 punpckhqdq xmm4, xmm4 %if ARCH_X86_64 - pshuflw xmm8, r6m, 0 - punpcklqdq xmm8, xmm8 + movd xmm8, r6m + SPLATW xmm8, xmm8 ADS_START movdqu xmm10, [r1] movdqu xmm11, [r1+r2] diff --git a/common/x86/pixel.h b/common/x86/pixel.h index 5f71c2ae..b7b977dc 100644 --- a/common/x86/pixel.h +++ b/common/x86/pixel.h @@ -1,7 +1,7 @@ /***************************************************************************** * pixel.h: x86 pixel metrics ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Laurent Aimar * Loren Merritt @@ -66,12 +66,14 @@ DECL_X1( ssd, xop ) DECL_X1( satd, mmx2 ) DECL_X1( satd, sse2 ) DECL_X1( satd, ssse3 ) +DECL_X1( satd, ssse3_atom ) DECL_X1( satd, sse4 ) DECL_X1( satd, avx ) DECL_X1( satd, xop ) DECL_X1( sa8d, mmx2 ) DECL_X1( sa8d, sse2 ) DECL_X1( sa8d, ssse3 ) +DECL_X1( sa8d, ssse3_atom ) DECL_X1( sa8d, sse4 ) DECL_X1( sa8d, avx ) DECL_X1( sa8d, xop ) @@ -91,6 +93,7 @@ DECL_PIXELS( uint64_t, var, xop, ( pixel *pix, intptr_t i_stride )) DECL_PIXELS( uint64_t, hadamard_ac, mmx2, ( pixel *pix, intptr_t i_stride )) DECL_PIXELS( uint64_t, hadamard_ac, sse2, ( pixel *pix, intptr_t i_stride )) DECL_PIXELS( uint64_t, hadamard_ac, ssse3, ( pixel *pix, intptr_t i_stride )) +DECL_PIXELS( uint64_t, hadamard_ac, ssse3_atom, ( pixel *pix, intptr_t i_stride )) DECL_PIXELS( uint64_t, hadamard_ac, sse4, ( pixel *pix, intptr_t i_stride )) DECL_PIXELS( uint64_t, hadamard_ac, avx, ( pixel *pix, intptr_t i_stride )) DECL_PIXELS( uint64_t, hadamard_ac, xop, ( pixel *pix, intptr_t i_stride )) @@ -159,6 +162,15 @@ int x264_pixel_vsad_mmx2 ( pixel *src, intptr_t stride, int height ); int x264_pixel_vsad_sse2 ( pixel *src, intptr_t stride, int height ); int x264_pixel_vsad_ssse3( pixel *src, intptr_t stride, int height ); int x264_pixel_vsad_xop ( pixel *src, intptr_t stride, int height ); +int x264_pixel_asd8_sse2 ( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2, int height ); +int x264_pixel_asd8_ssse3( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2, int height ); +int x264_pixel_asd8_xop ( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2, int height ); +uint64_t x264_pixel_sa8d_satd_16x16_sse2 ( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2 ); +uint64_t x264_pixel_sa8d_satd_16x16_ssse3 ( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2 ); +uint64_t x264_pixel_sa8d_satd_16x16_ssse3_atom( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2 ); +uint64_t x264_pixel_sa8d_satd_16x16_sse4 ( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2 ); +uint64_t x264_pixel_sa8d_satd_16x16_avx ( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2 ); +uint64_t x264_pixel_sa8d_satd_16x16_xop ( pixel *pix1, intptr_t stride1, pixel *pix2, intptr_t stride2 ); #define DECL_ADS( size, suffix ) \ int x264_pixel_ads##size##_##suffix( int enc_dc[size], uint16_t *sums, int delta,\ diff --git a/common/x86/predict-a.asm b/common/x86/predict-a.asm index 11c4056f..06245a67 100644 --- a/common/x86/predict-a.asm +++ b/common/x86/predict-a.asm @@ -1,7 +1,7 @@ ;***************************************************************************** ;* predict-a.asm: x86 intra prediction ;***************************************************************************** -;* Copyright (C) 2005-2012 x264 project +;* Copyright (C) 2005-2013 x264 project ;* ;* Authors: Loren Merritt ;* Holger Lubitz @@ -760,7 +760,7 @@ cglobal predict_8x8_v, 2,2 %endmacro %if HIGH_BIT_DEPTH -INIT_XMM sse2 +INIT_XMM sse PREDICT_8x8_V %else INIT_MMX mmx2 @@ -807,7 +807,7 @@ cglobal predict_8x8_dc, 2,2 psrlw m0, 4 SPLATW m0, m0 STORE8x8 m0, m0 - REP_RET + RET %else ; !HIGH_BIT_DEPTH INIT_MMX mmx2 @@ -1103,7 +1103,7 @@ ALIGN 4 add r0, FDEC_STRIDE dec r1d jg .loop - REP_RET + RET %endmacro ; PREDICT_CHROMA_P_MMX INIT_MMX mmx2 @@ -1140,7 +1140,7 @@ cglobal predict_8x%1c_p_core, 1,2,7 add r0, FDEC_STRIDEB dec r1d jg .loop - REP_RET + RET %else ; !HIGH_BIT_DEPTH cglobal predict_8x%1c_p_core, 1,2 movd m0, r1m @@ -1225,7 +1225,7 @@ ALIGN 4 add r0, FDEC_STRIDE dec r1d jg .loop - REP_RET + RET %endif ; !ARCH_X86_64 %macro PREDICT_16x16_P 0 @@ -1282,7 +1282,7 @@ ALIGN 4 dec r1d jg .loop %endif ; !HIGH_BIT_DEPTH - REP_RET + RET %endmacro ; PREDICT_16x16_P INIT_XMM sse2 @@ -1630,7 +1630,7 @@ cglobal predict_8x8c_v, 1,1 %endmacro %if HIGH_BIT_DEPTH -INIT_XMM sse2 +INIT_XMM sse PREDICT_8x8C_V %else INIT_MMX mmx @@ -1664,7 +1664,7 @@ cglobal predict_8x16c_v, 1,1 %endmacro %if HIGH_BIT_DEPTH -INIT_XMM sse2 +INIT_XMM sse PREDICT_8x16C_V %else INIT_MMX mmx @@ -1996,24 +1996,24 @@ cglobal predict_16x16_v_mmx2, 1,2 mova m2, [r0 - FDEC_STRIDEB+16] mova m3, [r0 - FDEC_STRIDEB+24] STORE16x16 m0, m1, m2, m3 - REP_RET -INIT_XMM -cglobal predict_16x16_v_sse2, 2,2 + RET +INIT_XMM sse +cglobal predict_16x16_v, 1,2 mova m0, [r0 - FDEC_STRIDEB+ 0] mova m1, [r0 - FDEC_STRIDEB+16] STORE16x16_SSE2 m0, m1 - REP_RET + RET %else ; !HIGH_BIT_DEPTH INIT_MMX cglobal predict_16x16_v_mmx2, 1,2 movq m0, [r0 - FDEC_STRIDE + 0] movq m1, [r0 - FDEC_STRIDE + 8] STORE16x16 m0, m1 - REP_RET -INIT_XMM -cglobal predict_16x16_v_sse2, 1,1 - movdqa xmm0, [r0 - FDEC_STRIDE] - STORE16x16_SSE2 xmm0 + RET +INIT_XMM sse +cglobal predict_16x16_v, 1,1 + mova m0, [r0 - FDEC_STRIDE] + STORE16x16_SSE2 m0 RET %endif @@ -2055,7 +2055,7 @@ cglobal predict_16x16_h, 1,2 %endif ; HIGH_BIT_DEPTH sub r1, 4*FDEC_STRIDEB jge .vloop - REP_RET + RET %endmacro INIT_MMX mmx2 @@ -2106,12 +2106,12 @@ cglobal predict_16x16_dc_core, 1,2 %else PRED16x16_DC r1m, 5 %endif - REP_RET + RET INIT_MMX mmx2 cglobal predict_16x16_dc_top, 1,2 PRED16x16_DC [pw_8], 4 - REP_RET + RET INIT_MMX mmx2 %if HIGH_BIT_DEPTH @@ -2119,14 +2119,14 @@ cglobal predict_16x16_dc_left_core, 1,2 movd m0, r1m SPLATW m0, m0 STORE16x16 m0, m0, m0, m0 - REP_RET + RET %else ; !HIGH_BIT_DEPTH cglobal predict_16x16_dc_left_core, 1,1 movd m0, r1m pshufw m0, m0, 0 packuswb m0, m0 STORE16x16 m0, m0 - REP_RET + RET %endif ;----------------------------------------------------------------------------- @@ -2159,11 +2159,11 @@ INIT_XMM sse2 cglobal predict_16x16_dc_core, 2,2,4 movd m3, r1m PRED16x16_DC_SSE2 m3, 5 - REP_RET + RET cglobal predict_16x16_dc_top, 1,2 PRED16x16_DC_SSE2 [pw_8], 4 - REP_RET + RET INIT_XMM sse2 %if HIGH_BIT_DEPTH @@ -2171,7 +2171,7 @@ cglobal predict_16x16_dc_left_core, 1,2 movd m0, r1m SPLATW m0, m0 STORE16x16_SSE2 m0, m0 - REP_RET + RET %else ; !HIGH_BIT_DEPTH cglobal predict_16x16_dc_left_core, 1,1 movd m0, r1m diff --git a/common/x86/predict-c.c b/common/x86/predict-c.c index 9f720650..96757ea8 100644 --- a/common/x86/predict-c.c +++ b/common/x86/predict-c.c @@ -1,7 +1,7 @@ /***************************************************************************** * predict-c.c: intra prediction ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Laurent Aimar * Loren Merritt @@ -329,12 +329,14 @@ void x264_predict_16x16_init_mmx( int cpu, x264_predict_t pf[7] ) pf[I_PRED_16x16_V] = x264_predict_16x16_v_mmx2; pf[I_PRED_16x16_H] = x264_predict_16x16_h_mmx2; #if HIGH_BIT_DEPTH + if( !(cpu&X264_CPU_SSE) ) + return; + pf[I_PRED_16x16_V] = x264_predict_16x16_v_sse; if( !(cpu&X264_CPU_SSE2) ) return; pf[I_PRED_16x16_DC] = x264_predict_16x16_dc_sse2; pf[I_PRED_16x16_DC_TOP] = x264_predict_16x16_dc_top_sse2; pf[I_PRED_16x16_DC_LEFT] = x264_predict_16x16_dc_left_sse2; - pf[I_PRED_16x16_V] = x264_predict_16x16_v_sse2; pf[I_PRED_16x16_H] = x264_predict_16x16_h_sse2; #if HAVE_X86_INLINE_ASM pf[I_PRED_16x16_P] = x264_predict_16x16_p_sse2; @@ -343,10 +345,12 @@ void x264_predict_16x16_init_mmx( int cpu, x264_predict_t pf[7] ) #if !ARCH_X86_64 pf[I_PRED_16x16_P] = x264_predict_16x16_p_mmx2; #endif + if( !(cpu&X264_CPU_SSE) ) + return; + pf[I_PRED_16x16_V] = x264_predict_16x16_v_sse; if( !(cpu&X264_CPU_SSE2) ) return; pf[I_PRED_16x16_DC] = x264_predict_16x16_dc_sse2; - pf[I_PRED_16x16_V] = x264_predict_16x16_v_sse2; if( cpu&X264_CPU_SSE2_IS_SLOW ) return; pf[I_PRED_16x16_DC_TOP] = x264_predict_16x16_dc_top_sse2; @@ -354,7 +358,8 @@ void x264_predict_16x16_init_mmx( int cpu, x264_predict_t pf[7] ) pf[I_PRED_16x16_P] = x264_predict_16x16_p_sse2; if( !(cpu&X264_CPU_SSSE3) ) return; - pf[I_PRED_16x16_H] = x264_predict_16x16_h_ssse3; + if( !(cpu&X264_CPU_SLOW_PSHUFB) ) + pf[I_PRED_16x16_H] = x264_predict_16x16_h_ssse3; #if HAVE_X86_INLINE_ASM pf[I_PRED_16x16_P] = x264_predict_16x16_p_ssse3; #endif @@ -374,9 +379,11 @@ void x264_predict_8x8c_init_mmx( int cpu, x264_predict_t pf[7] ) return; pf[I_PRED_CHROMA_DC] = x264_predict_8x8c_dc_mmx2; pf[I_PRED_CHROMA_H] = x264_predict_8x8c_h_mmx2; + if( !(cpu&X264_CPU_SSE) ) + return; + pf[I_PRED_CHROMA_V] = x264_predict_8x8c_v_sse; if( !(cpu&X264_CPU_SSE2) ) return; - pf[I_PRED_CHROMA_V] = x264_predict_8x8c_v_sse2; pf[I_PRED_CHROMA_DC] = x264_predict_8x8c_dc_sse2; pf[I_PRED_CHROMA_DC_TOP] = x264_predict_8x8c_dc_top_sse2; pf[I_PRED_CHROMA_H] = x264_predict_8x8c_h_sse2; @@ -423,9 +430,11 @@ void x264_predict_8x16c_init_mmx( int cpu, x264_predict_t pf[7] ) return; pf[I_PRED_CHROMA_DC] = x264_predict_8x16c_dc_mmx2; pf[I_PRED_CHROMA_H] = x264_predict_8x16c_h_mmx2; + if( !(cpu&X264_CPU_SSE) ) + return; + pf[I_PRED_CHROMA_V] = x264_predict_8x16c_v_sse; if( !(cpu&X264_CPU_SSE2) ) return; - pf[I_PRED_CHROMA_V] = x264_predict_8x16c_v_sse2; pf[I_PRED_CHROMA_DC_TOP] = x264_predict_8x16c_dc_top_sse2; pf[I_PRED_CHROMA_DC] = x264_predict_8x16c_dc_sse2; pf[I_PRED_CHROMA_H] = x264_predict_8x16c_h_sse2; @@ -460,9 +469,11 @@ void x264_predict_8x8_init_mmx( int cpu, x264_predict8x8_t pf[12], x264_predict_ if( !(cpu&X264_CPU_MMX2) ) return; #if HIGH_BIT_DEPTH + if( !(cpu&X264_CPU_SSE) ) + return; + pf[I_PRED_8x8_V] = x264_predict_8x8_v_sse; if( !(cpu&X264_CPU_SSE2) ) return; - pf[I_PRED_8x8_V] = x264_predict_8x8_v_sse2; pf[I_PRED_8x8_H] = x264_predict_8x8_h_sse2; pf[I_PRED_8x8_DC] = x264_predict_8x8_dc_sse2; pf[I_PRED_8x8_DC_TOP] = x264_predict_8x8_dc_top_sse2; @@ -520,8 +531,11 @@ void x264_predict_8x8_init_mmx( int cpu, x264_predict8x8_t pf[12], x264_predict_ pf[I_PRED_8x8_HU] = x264_predict_8x8_hu_sse2; if( !(cpu&X264_CPU_SSSE3) ) return; - pf[I_PRED_8x8_DDL] = x264_predict_8x8_ddl_ssse3; - pf[I_PRED_8x8_VR] = x264_predict_8x8_vr_ssse3; + if( !(cpu&X264_CPU_SLOW_PALIGNR) ) + { + pf[I_PRED_8x8_DDL] = x264_predict_8x8_ddl_ssse3; + pf[I_PRED_8x8_VR] = x264_predict_8x8_vr_ssse3; + } pf[I_PRED_8x8_HU] = x264_predict_8x8_hu_ssse3; *predict_8x8_filter = x264_predict_8x8_filter_ssse3; if( !(cpu&X264_CPU_AVX) ) diff --git a/common/x86/predict.h b/common/x86/predict.h index 5884de60..ca2c20fa 100644 --- a/common/x86/predict.h +++ b/common/x86/predict.h @@ -1,7 +1,7 @@ /***************************************************************************** * predict.h: x86 intra prediction ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Laurent Aimar * Loren Merritt @@ -34,7 +34,7 @@ void x264_predict_4x4_init_mmx ( int cpu, x264_predict_t pf[12] ); void x264_predict_8x8_init_mmx ( int cpu, x264_predict8x8_t pf[12], x264_predict_8x8_filter_t *predict_8x8_filter ); void x264_predict_16x16_v_mmx2( pixel *src ); -void x264_predict_16x16_v_sse2( pixel *src ); +void x264_predict_16x16_v_sse ( pixel *src ); void x264_predict_16x16_h_mmx2( pixel *src ); void x264_predict_16x16_h_sse2( uint16_t *src ); void x264_predict_16x16_h_ssse3( uint8_t *src ); @@ -55,7 +55,7 @@ void x264_predict_8x16c_dc_sse2( uint16_t *src ); void x264_predict_8x16c_dc_top_mmx2( uint8_t *src ); void x264_predict_8x16c_dc_top_sse2( uint16_t *src ); void x264_predict_8x16c_v_mmx( uint8_t *src ); -void x264_predict_8x16c_v_sse2( uint16_t *src ); +void x264_predict_8x16c_v_sse( uint16_t *src ); void x264_predict_8x16c_h_mmx2( pixel *src ); void x264_predict_8x16c_h_sse2( pixel *src ); void x264_predict_8x16c_h_ssse3( uint8_t *src ); @@ -70,12 +70,12 @@ void x264_predict_8x8c_dc_sse2( uint16_t *src ); void x264_predict_8x8c_dc_top_mmx2( uint8_t *src ); void x264_predict_8x8c_dc_top_sse2( uint16_t *src ); void x264_predict_8x8c_v_mmx( pixel *src ); -void x264_predict_8x8c_v_sse2( uint16_t *src ); +void x264_predict_8x8c_v_sse( uint16_t *src ); void x264_predict_8x8c_h_mmx2( pixel *src ); void x264_predict_8x8c_h_sse2( pixel *src ); void x264_predict_8x8c_h_ssse3( uint8_t *src ); void x264_predict_8x8_v_mmx2( uint8_t *src, uint8_t edge[36] ); -void x264_predict_8x8_v_sse2( uint16_t *src, uint16_t edge[36] ); +void x264_predict_8x8_v_sse ( uint16_t *src, uint16_t edge[36] ); void x264_predict_8x8_h_mmx2( uint8_t *src, uint8_t edge[36] ); void x264_predict_8x8_h_sse2( uint16_t *src, uint16_t edge[36] ); void x264_predict_8x8_hd_mmx2( uint8_t *src, uint8_t edge[36] ); diff --git a/common/x86/quant-a.asm b/common/x86/quant-a.asm index fefc435a..e2cb5d7d 100644 --- a/common/x86/quant-a.asm +++ b/common/x86/quant-a.asm @@ -1,7 +1,7 @@ ;***************************************************************************** ;* quant-a.asm: x86 quantization and level-run ;***************************************************************************** -;* Copyright (C) 2005-2012 x264 project +;* Copyright (C) 2005-2013 x264 project ;* ;* Authors: Loren Merritt ;* Jason Garrett-Glaser @@ -175,7 +175,7 @@ cextern pd_1024 %endif ; cpuflag %endmacro -%macro QUANT_ONE_AC_MMX 4 +%macro QUANT_ONE_AC_MMX 5 mova m0, [%1] mova m2, [%2] ABSD m1, m0 @@ -191,10 +191,10 @@ cextern pd_1024 psrad m1, 16 PSIGND m1, m0 mova [%1], m1 - ACCUM por, 5, 1, %4 + ACCUM por, %5, 1, %4 %endmacro -%macro QUANT_TWO_AC 4 +%macro QUANT_TWO_AC 5 %if cpuflag(sse4) mova m0, [%1 ] mova m1, [%1+mmsize] @@ -210,11 +210,11 @@ cextern pd_1024 PSIGND m3, m1 mova [%1 ], m2 mova [%1+mmsize], m3 - ACCUM por, 5, 2, %4 - por m5, m3 + ACCUM por, %5, 2, %4 + ACCUM por, %5, 3, %4+mmsize %else ; !sse4 - QUANT_ONE_AC_MMX %1, %2, %3, %4 - QUANT_ONE_AC_MMX %1+mmsize, %2+mmsize, %3+mmsize, %4+mmsize + QUANT_ONE_AC_MMX %1, %2, %3, %4, %5 + QUANT_ONE_AC_MMX %1+mmsize, %2+mmsize, %3+mmsize, %4+mmsize, %5 %endif ; cpuflag %endmacro @@ -244,30 +244,58 @@ cglobal quant_%1x%2_dc, 3,3,8 cglobal quant_%1x%2, 3,3,8 %assign x 0 %rep %1*%2/(mmsize/2) - QUANT_TWO_AC r0+x, r1+x, r2+x, x + QUANT_TWO_AC r0+x, r1+x, r2+x, x, 5 %assign x x+mmsize*2 %endrep QUANT_END RET %endmacro +%macro QUANT_4x4 2 + QUANT_TWO_AC r0+%1+mmsize*0, r1+mmsize*0, r2+mmsize*0, mmsize*0, %2 + QUANT_TWO_AC r0+%1+mmsize*2, r1+mmsize*2, r2+mmsize*2, mmsize*2, %2 +%endmacro + +%macro QUANT_4x4x4 0 +cglobal quant_4x4x4, 3,3,8 + QUANT_4x4 0, 5 + QUANT_4x4 64, 6 + add r0, 128 + packssdw m5, m6 + QUANT_4x4 0, 6 + QUANT_4x4 64, 7 + packssdw m6, m7 + packssdw m5, m6 + packssdw m5, m5 ; AA BB CC DD + packsswb m5, m5 ; A B C D + pxor m4, m4 + pcmpeqb m5, m4 + pmovmskb eax, m5 + not eax + and eax, 0xf + RET +%endmacro + INIT_XMM sse2 QUANT_DC 2, 2 QUANT_DC 4, 4 QUANT_AC 4, 4 QUANT_AC 8, 8 +QUANT_4x4x4 INIT_XMM ssse3 QUANT_DC 2, 2 QUANT_DC 4, 4 QUANT_AC 4, 4 QUANT_AC 8, 8 +QUANT_4x4x4 INIT_XMM sse4 QUANT_DC 2, 2 QUANT_DC 4, 4 QUANT_AC 4, 4 QUANT_AC 8, 8 +QUANT_4x4x4 %endif ; HIGH_BIT_DEPTH @@ -285,7 +313,7 @@ QUANT_AC 8, 8 ACCUM por, 5, 0, %4 %endmacro -%macro QUANT_TWO 7 +%macro QUANT_TWO 8 mova m1, %1 mova m3, %2 ABSW m0, m1, sign @@ -298,8 +326,8 @@ QUANT_AC 8, 8 PSIGNW m2, m3 mova %1, m0 mova %2, m2 - ACCUM por, 5, 0, %7 - por m5, m2 + ACCUM por, %8, 0, %7 + ACCUM por, %8, 2, %7+mmsize %endmacro ;----------------------------------------------------------------------------- @@ -313,7 +341,7 @@ cglobal %1, 1,1,%3 %else %assign x 0 %rep %2/2 - QUANT_TWO [r0+x], [r0+x+mmsize], m6, m6, m7, m7, x + QUANT_TWO [r0+x], [r0+x+mmsize], m6, m6, m7, m7, x, 5 %assign x x+mmsize*2 %endrep %endif @@ -328,13 +356,51 @@ cglobal %1, 1,1,%3 cglobal %1, 3,3 %assign x 0 %rep %2/2 - QUANT_TWO [r0+x], [r0+x+mmsize], [r1+x], [r1+x+mmsize], [r2+x], [r2+x+mmsize], x + QUANT_TWO [r0+x], [r0+x+mmsize], [r1+x], [r1+x+mmsize], [r2+x], [r2+x+mmsize], x, 5 %assign x x+mmsize*2 %endrep QUANT_END RET %endmacro +%macro QUANT_4x4 2 +%if UNIX64 + QUANT_TWO [r0+%1+mmsize*0], [r0+%1+mmsize*1], m8, m9, m10, m11, mmsize*0, %2 +%else + QUANT_TWO [r0+%1+mmsize*0], [r0+%1+mmsize*1], [r1+mmsize*0], [r1+mmsize*1], [r2+mmsize*0], [r2+mmsize*1], mmsize*0, %2 +%if mmsize==8 + QUANT_TWO [r0+%1+mmsize*2], [r0+%1+mmsize*3], [r1+mmsize*2], [r1+mmsize*3], [r2+mmsize*2], [r2+mmsize*3], mmsize*2, %2 +%endif +%endif +%endmacro + +%macro QUANT_4x4x4 0 +cglobal quant_4x4x4, 3,3,7 +%if UNIX64 + mova m8, [r1+mmsize*0] + mova m9, [r1+mmsize*1] + mova m10, [r2+mmsize*0] + mova m11, [r2+mmsize*1] +%endif + QUANT_4x4 0, 4 + QUANT_4x4 32, 5 + packssdw m4, m5 + QUANT_4x4 64, 5 + QUANT_4x4 96, 6 + packssdw m5, m6 + packssdw m4, m5 +%if mmsize == 16 + packssdw m4, m4 ; AA BB CC DD +%endif + packsswb m4, m4 ; A B C D + pxor m3, m3 + pcmpeqb m4, m3 + pmovmskb eax, m4 + not eax + and eax, 0xf + RET +%endmacro + INIT_MMX mmx2 QUANT_DC quant_2x2_dc, 1 %if ARCH_X86_64 == 0 ; not needed because sse2 is faster @@ -342,17 +408,20 @@ QUANT_DC quant_4x4_dc, 4 INIT_MMX mmx QUANT_AC quant_4x4, 4 QUANT_AC quant_8x8, 16 +QUANT_4x4x4 %endif INIT_XMM sse2 QUANT_DC quant_4x4_dc, 2, 8 QUANT_AC quant_4x4, 2 QUANT_AC quant_8x8, 8 +QUANT_4x4x4 INIT_XMM ssse3 QUANT_DC quant_4x4_dc, 2, 8 QUANT_AC quant_4x4, 2 QUANT_AC quant_8x8, 8 +QUANT_4x4x4 INIT_MMX ssse3 QUANT_DC quant_2x2_dc, 1 @@ -416,7 +485,7 @@ QUANT_AC quant_8x8, 8 %1 [r0+(t0+8*%3)*SIZEOF_PIXEL], [r1+t0*2+16*%3], [r1+t0*2+24*%3] sub t0d, 16*%3 jge %%loop - REP_RET + RET %else %1 [r0+(8*%3)*SIZEOF_PIXEL], [r1+16*%3], [r1+24*%3] %1 [r0+(0 )*SIZEOF_PIXEL], [r1+0 ], [r1+ 8*%3] @@ -738,7 +807,7 @@ cglobal optimize_chroma_2x2_dc, 0,%%regs,7 PSIGND m5, m2, m1 test t3d, t3d jnz .outer_loop_0 - REP_RET + RET %endmacro %if HIGH_BIT_DEPTH == 0 @@ -783,7 +852,7 @@ cglobal denoise_dct, 4,4,8 mova [r1+r3*4-1*mmsize], m5 sub r3, mmsize/2 jg .loop - REP_RET + RET %endmacro %if ARCH_X86_64 == 0 @@ -831,7 +900,7 @@ cglobal denoise_dct, 4,4,7 mova [r1+r3*4-1*mmsize], m1 sub r3, mmsize jg .loop - REP_RET + RET %endmacro %if ARCH_X86_64 == 0 @@ -954,7 +1023,7 @@ cglobal decimate_score%1, 1,3 jne .loop %endif .ret: - RET + REP_RET .ret9: mov eax, 9 RET @@ -1066,7 +1135,7 @@ cglobal decimate_score64, 1,5 .tryret: xor r4, -1 jne .cont - REP_RET + RET .ret9: mov eax, 9 RET @@ -1077,7 +1146,7 @@ cglobal decimate_score64, 1,5 shr r3, cl shr r3, 1 jne .loop - REP_RET + RET %endif ; ARCH %endmacro @@ -1381,7 +1450,7 @@ cglobal coeff_level_run%1,0,7 inc t6d sub t4d, t3d jge .loop - REP_RET + RET %endmacro INIT_MMX mmx2 diff --git a/common/x86/quant.h b/common/x86/quant.h index c9585667..4082fe7e 100644 --- a/common/x86/quant.h +++ b/common/x86/quant.h @@ -1,7 +1,7 @@ /***************************************************************************** * quant.h: x86 quantization and level-run ***************************************************************************** - * Copyright (C) 2005-2012 x264 project + * Copyright (C) 2005-2013 x264 project * * Authors: Loren Merritt * Jason Garrett-Glaser @@ -31,18 +31,22 @@ int x264_quant_2x2_dc_mmx2( dctcoef dct[4], int mf, int bias ); int x264_quant_4x4_dc_mmx2( dctcoef dct[16], int mf, int bias ); int x264_quant_4x4_mmx( dctcoef dct[16], udctcoef mf[16], udctcoef bias[16] ); +int x264_quant_4x4x4_mmx( dctcoef dct[4][16], udctcoef mf[16], udctcoef bias[16] ); int x264_quant_8x8_mmx( dctcoef dct[64], udctcoef mf[64], udctcoef bias[64] ); int x264_quant_2x2_dc_sse2( dctcoef dct[16], int mf, int bias ); int x264_quant_4x4_dc_sse2( dctcoef dct[16], int mf, int bias ); int x264_quant_4x4_sse2( dctcoef dct[16], udctcoef mf[16], udctcoef bias[16] ); +int x264_quant_4x4x4_sse2( dctcoef dct[4][16], udctcoef mf[16], udctcoef bias[16] ); int x264_quant_8x8_sse2( dctcoef dct[64], udctcoef mf[64], udctcoef bias[64] ); int x264_quant_2x2_dc_ssse3( dctcoef dct[4], int mf, int bias ); int x264_quant_4x4_dc_ssse3( dctcoef dct[16], int mf, int bias ); int x264_quant_4x4_ssse3( dctcoef dct[16], udctcoef mf[16], udctcoef bias[16] ); +int x264_quant_4x4x4_ssse3( dctcoef dct[4][16], udctcoef mf[16], udctcoef bias[16] ); int x264_quant_8x8_ssse3( dctcoef dct[64], udctcoef mf[64], udctcoef bias[64] ); int x264_quant_2x2_dc_sse4( dctcoef dct[16], int mf, int bias ); int x264_quant_4x4_dc_sse4( dctcoef dct[16], int mf, int bias ); int x264_quant_4x4_sse4( dctcoef dct[16], udctcoef mf[16], udctcoef bias[16] ); +int x264_quant_4x4x4_sse4( dctcoef dct[4][16], udctcoef mf[16], udctcoef bias[16] ); int x264_quant_8x8_sse4( dctcoef dct[64], udctcoef mf[64], udctcoef bias[64] ); void x264_dequant_4x4_mmx( int16_t dct[16], int dequant_mf[6][16], int i_qp ); void x264_dequant_4x4dc_mmx2( int16_t dct[16], int dequant_mf[6][16], int i_qp ); diff --git a/common/x86/sad-a.asm b/common/x86/sad-a.asm index fc213bb2..57231991 100644 --- a/common/x86/sad-a.asm +++ b/common/x86/sad-a.asm @@ -1,7 +1,7 @@ ;***************************************************************************** ;* sad-a.asm: x86 sad functions ;***************************************************************************** -;* Copyright (C) 2003-2012 x264 project +;* Copyright (C) 2003-2013 x264 project ;* ;* Authors: Loren Merritt ;* Jason Garrett-Glaser diff --git a/common/x86/sad16-a.asm b/common/x86/sad16-a.asm index 273d0a01..8e3dba7b 100644 --- a/common/x86/sad16-a.asm +++ b/common/x86/sad16-a.asm @@ -1,7 +1,7 @@ ;***************************************************************************** ;* sad16-a.asm: x86 high depth sad functions ;***************************************************************************** -;* Copyright (C) 2010-2012 x264 project +;* Copyright (C) 2010-2013 x264 project ;* ;* Authors: Oskar Arvidsson ;* diff --git a/common/x86/trellis-64.asm b/common/x86/trellis-64.asm index 2511ca00..df95f0a4 100644 --- a/common/x86/trellis-64.asm +++ b/common/x86/trellis-64.asm @@ -1,7 +1,7 @@ ;***************************************************************************** ;* trellis-64.asm: x86_64 trellis quantization ;***************************************************************************** -;* Copyright (C) 2012 x264 project +;* Copyright (C) 2012-2013 x264 project ;* ;* Authors: Loren Merritt ;* diff --git a/common/x86/util.h b/common/x86/util.h index e901043b..fd652b9c 100644 --- a/common/x86/util.h +++ b/common/x86/util.h @@ -1,7 +1,7 @@ /***************************************************************************** * util.h: x86 inline asm ***************************************************************************** - * Copyright (C) 2008-2012 x264 project + * Copyright (C) 2008-2013 x264 project * * Authors: Jason Garrett-Glaser * Loren Merritt @@ -121,42 +121,132 @@ static ALWAYS_INLINE uint16_t x264_cabac_mvd_sum_mmx2(uint8_t *mvdleft, uint8_t return amvd; } +#define x264_predictor_clip x264_predictor_clip_mmx2 +static int ALWAYS_INLINE x264_predictor_clip_mmx2( int16_t (*dst)[2], int16_t (*mvc)[2], int i_mvc, int16_t mv_limit[2][2], uint32_t pmv ) +{ + static const uint32_t pd_32 = 0x20; + intptr_t tmp = (intptr_t)mv_limit, mvc_max = i_mvc, i = 0; + + asm( + "movq (%2), %%mm5 \n" + "movd %6, %%mm3 \n" + "psllw $2, %%mm5 \n" // Convert to subpel + "pshufw $0xEE, %%mm5, %%mm6 \n" + "dec %k3 \n" + "jz 2f \n" // if( i_mvc == 1 ) {do the last iteration} + "punpckldq %%mm3, %%mm3 \n" + "punpckldq %%mm5, %%mm5 \n" + "movd %7, %%mm4 \n" + "lea (%0,%3,4), %3 \n" + "1: \n" + "movq (%0), %%mm0 \n" + "add $8, %0 \n" + "movq %%mm3, %%mm1 \n" + "pxor %%mm2, %%mm2 \n" + "pcmpeqd %%mm0, %%mm1 \n" // mv == pmv + "pcmpeqd %%mm0, %%mm2 \n" // mv == 0 + "por %%mm1, %%mm2 \n" // (mv == pmv || mv == 0) * -1 + "pmovmskb %%mm2, %k2 \n" // (mv == pmv || mv == 0) * 0xf + "pmaxsw %%mm5, %%mm0 \n" + "pminsw %%mm6, %%mm0 \n" + "pand %%mm4, %%mm2 \n" // (mv0 == pmv || mv0 == 0) * 32 + "psrlq %%mm2, %%mm0 \n" // drop mv0 if it's skipped + "movq %%mm0, (%5,%4,4) \n" + "and $24, %k2 \n" + "add $2, %4 \n" + "add $8, %k2 \n" + "shr $4, %k2 \n" // (4-val)>>1 + "sub %2, %4 \n" // +1 for each valid motion vector + "cmp %3, %0 \n" + "jl 1b \n" + "jg 3f \n" // if( i == i_mvc - 1 ) {do the last iteration} + + /* Do the last iteration */ + "2: \n" + "movd (%0), %%mm0 \n" + "pxor %%mm2, %%mm2 \n" + "pcmpeqd %%mm0, %%mm3 \n" + "pcmpeqd %%mm0, %%mm2 \n" + "por %%mm3, %%mm2 \n" + "pmovmskb %%mm2, %k2 \n" + "pmaxsw %%mm5, %%mm0 \n" + "pminsw %%mm6, %%mm0 \n" + "movd %%mm0, (%5,%4,4) \n" + "inc %4 \n" + "and $1, %k2 \n" + "sub %2, %4 \n" // output += !(mv == pmv || mv == 0) + "3: \n" + :"+r"(mvc), "=m"(M64( dst )), "+r"(tmp), "+r"(mvc_max), "+r"(i) + :"r"(dst), "g"(pmv), "m"(pd_32), "m"(M64( mvc )) + ); + return i; +} + +/* Same as the above, except we do (mv + 2) >> 2 on the input. */ #define x264_predictor_roundclip x264_predictor_roundclip_mmx2 -static void ALWAYS_INLINE x264_predictor_roundclip_mmx2( int16_t (*dst)[2], int16_t (*mvc)[2], int i_mvc, int mv_x_min, int mv_x_max, int mv_y_min, int mv_y_max ) +static int ALWAYS_INLINE x264_predictor_roundclip_mmx2( int16_t (*dst)[2], int16_t (*mvc)[2], int i_mvc, int16_t mv_limit[2][2], uint32_t pmv ) { - uint32_t mv_min = pack16to32_mask( mv_x_min, mv_y_min ); - uint32_t mv_max = pack16to32_mask( mv_x_max, mv_y_max ); static const uint64_t pw_2 = 0x0002000200020002ULL; - intptr_t i = i_mvc; + static const uint32_t pd_32 = 0x20; + intptr_t tmp = (intptr_t)mv_limit, mvc_max = i_mvc, i = 0; + asm( - "movd %2, %%mm5 \n" - "movd %3, %%mm6 \n" - "movq %4, %%mm7 \n" - "punpckldq %%mm5, %%mm5 \n" - "punpckldq %%mm6, %%mm6 \n" - "test $1, %0 \n" - "jz 1f \n" - "movd -4(%6,%0,4), %%mm0 \n" - "paddw %%mm7, %%mm0 \n" - "psraw $2, %%mm0 \n" - "pmaxsw %%mm5, %%mm0 \n" - "pminsw %%mm6, %%mm0 \n" - "movd %%mm0, -4(%5,%0,4) \n" - "dec %0 \n" - "jz 2f \n" - "1: \n" - "movq -8(%6,%0,4), %%mm0 \n" - "paddw %%mm7, %%mm0 \n" - "psraw $2, %%mm0 \n" - "pmaxsw %%mm5, %%mm0 \n" - "pminsw %%mm6, %%mm0 \n" - "movq %%mm0, -8(%5,%0,4) \n" - "sub $2, %0 \n" - "jnz 1b \n" - "2: \n" - :"+r"(i), "=m"(M64( dst )) - :"g"(mv_min), "g"(mv_max), "m"(pw_2), "r"(dst), "r"(mvc), "m"(M64( mvc )) + "movq (%2), %%mm5 \n" + "movq %6, %%mm7 \n" + "movd %7, %%mm3 \n" + "pshufw $0xEE, %%mm5, %%mm6 \n" + "dec %k3 \n" + "jz 2f \n" + "punpckldq %%mm3, %%mm3 \n" + "punpckldq %%mm5, %%mm5 \n" + "movd %8, %%mm4 \n" + "lea (%0,%3,4), %3 \n" + "1: \n" + "movq (%0), %%mm0 \n" + "add $8, %0 \n" + "paddw %%mm7, %%mm0 \n" + "psraw $2, %%mm0 \n" + "movq %%mm3, %%mm1 \n" + "pxor %%mm2, %%mm2 \n" + "pcmpeqd %%mm0, %%mm1 \n" + "pcmpeqd %%mm0, %%mm2 \n" + "por %%mm1, %%mm2 \n" + "pmovmskb %%mm2, %k2 \n" + "pmaxsw %%mm5, %%mm0 \n" + "pminsw %%mm6, %%mm0 \n" + "pand %%mm4, %%mm2 \n" + "psrlq %%mm2, %%mm0 \n" + "movq %%mm0, (%5,%4,4) \n" + "and $24, %k2 \n" + "add $2, %4 \n" + "add $8, %k2 \n" + "shr $4, %k2 \n" + "sub %2, %4 \n" + "cmp %3, %0 \n" + "jl 1b \n" + "jg 3f \n" + + /* Do the last iteration */ + "2: \n" + "movd (%0), %%mm0 \n" + "paddw %%mm7, %%mm0 \n" + "psraw $2, %%mm0 \n" + "pxor %%mm2, %%mm2 \n" + "pcmpeqd %%mm0, %%mm3 \n" + "pcmpeqd %%mm0, %%mm2 \n" + "por %%mm3, %%mm2 \n" + "pmovmskb %%mm2, %k2 \n" + "pmaxsw %%mm5, %%mm0 \n" + "pminsw %%mm6, %%mm0 \n" + "movd %%mm0, (%5,%4,4) \n" + "inc %4 \n" + "and $1, %k2 \n" + "sub %2, %4 \n" + "3: \n" + :"+r"(mvc), "=m"(M64( dst )), "+r"(tmp), "+r"(mvc_max), "+r"(i) + :"r"(dst), "m"(pw_2), "g"(pmv), "m"(pd_32), "m"(M64( mvc )) ); + return i; } #endif diff --git a/common/x86/x86inc.asm b/common/x86/x86inc.asm index 582cc9c1..d9d86b25 100644 --- a/common/x86/x86inc.asm +++ b/common/x86/x86inc.asm @@ -1,7 +1,7 @@ ;***************************************************************************** ;* x86inc.asm: x264asm abstraction layer ;***************************************************************************** -;* Copyright (C) 2005-2012 x264 project +;* Copyright (C) 2005-2013 x264 project ;* ;* Authors: Loren Merritt ;* Anton Mitrofanov @@ -34,7 +34,13 @@ ; as this feature might be useful for others as well. Send patches or ideas ; to x264-devel@videolan.org . -%define program_name x264 +%ifndef private_prefix + %define private_prefix x264 +%endif + +%ifndef public_prefix + %define public_prefix private_prefix +%endif %define WIN64 0 %define UNIX64 0 @@ -103,7 +109,12 @@ CPU amdnop ; %1 = number of arguments. loads them from stack if needed. ; %2 = number of registers used. pushes callee-saved regs if needed. ; %3 = number of xmm registers used. pushes callee-saved xmm regs if needed. -; %4 = list of names to define to registers +; %4 = (optional) stack size to be allocated. If not aligned (x86-32 ICC 10.x, +; MSVC or YMM), the stack will be manually aligned (to 16 or 32 bytes), +; and an extra register will be allocated to hold the original stack +; pointer (to not invalidate r0m etc.). To prevent the use of an extra +; register as stack pointer, request a negative stack size. +; %4+/%5+ = list of names to define to registers ; PROLOGUE can also be invoked by adding the same options to cglobal ; e.g. @@ -118,8 +129,7 @@ CPU amdnop ; Pops anything that was pushed by PROLOGUE, and returns. ; REP_RET: -; Same, but if it doesn't pop anything it becomes a 2-byte ret, for athlons -; which are slow when a normal ret follows a branch. +; Use this instead of RET if it's a branch target. ; registers: ; rN and rNq are the native-size register holding function argument N @@ -138,11 +148,11 @@ CPU amdnop %define r%1m %2d %define r%1mp %2 %elif ARCH_X86_64 ; memory - %define r%1m [rsp + stack_offset + %3] - %define r%1mp qword r %+ %1m + %define r%1m [rstk + stack_offset + %3] + %define r%1mp qword r %+ %1 %+ m %else - %define r%1m [esp + stack_offset + %3] - %define r%1mp dword r %+ %1m + %define r%1m [rstk + stack_offset + %3] + %define r%1mp dword r %+ %1 %+ m %endif %define r%1 %2 %endmacro @@ -203,12 +213,16 @@ DECLARE_REG_TMP_SIZE 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14 %macro PUSH 1 push %1 - %assign stack_offset stack_offset+gprsize + %ifidn rstk, rsp + %assign stack_offset stack_offset+gprsize + %endif %endmacro %macro POP 1 pop %1 - %assign stack_offset stack_offset-gprsize + %ifidn rstk, rsp + %assign stack_offset stack_offset-gprsize + %endif %endmacro %macro PUSH_IF_USED 1-* @@ -240,14 +254,14 @@ DECLARE_REG_TMP_SIZE 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14 %macro SUB 2 sub %1, %2 - %ifidn %1, rsp + %ifidn %1, rstk %assign stack_offset stack_offset+(%2) %endif %endmacro %macro ADD 2 add %1, %2 - %ifidn %1, rsp + %ifidn %1, rstk %assign stack_offset stack_offset-(%2) %endif %endmacro @@ -280,12 +294,13 @@ DECLARE_REG_TMP_SIZE 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14 CAT_UNDEF arg_name %+ %%i, h CAT_UNDEF arg_name %+ %%i, b CAT_UNDEF arg_name %+ %%i, m + CAT_UNDEF arg_name %+ %%i, mp CAT_UNDEF arg_name, %%i %assign %%i %%i+1 %endrep %endif - %assign %%stack_offset stack_offset + %xdefine %%stack_offset stack_offset %undef stack_offset ; so that the current value of stack_offset doesn't get baked in by xdefine %assign %%i 0 %rep %0 @@ -295,14 +310,88 @@ DECLARE_REG_TMP_SIZE 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14 %xdefine %1h r %+ %%i %+ h %xdefine %1b r %+ %%i %+ b %xdefine %1m r %+ %%i %+ m + %xdefine %1mp r %+ %%i %+ mp CAT_XDEFINE arg_name, %%i, %1 %assign %%i %%i+1 %rotate 1 %endrep - %assign stack_offset %%stack_offset + %xdefine stack_offset %%stack_offset %assign n_arg_names %0 %endmacro +%macro ALLOC_STACK 1-2 0 ; stack_size, n_xmm_regs (for win64 only) + %ifnum %1 + %if %1 != 0 + %assign %%stack_alignment ((mmsize + 15) & ~15) + %assign stack_size %1 + %if stack_size < 0 + %assign stack_size -stack_size + %endif + %if mmsize != 8 + %assign xmm_regs_used %2 + %endif + %if mmsize <= 16 && HAVE_ALIGNED_STACK + %assign stack_size_padded stack_size + %%stack_alignment - gprsize - (stack_offset & (%%stack_alignment - 1)) + %if xmm_regs_used > 6 + %assign stack_size_padded stack_size_padded + (xmm_regs_used - 6) * 16 + %endif + SUB rsp, stack_size_padded + %else + %assign %%reg_num (regs_used - 1) + %xdefine rstk r %+ %%reg_num + ; align stack, and save original stack location directly above + ; it, i.e. in [rsp+stack_size_padded], so we can restore the + ; stack in a single instruction (i.e. mov rsp, rstk or mov + ; rsp, [rsp+stack_size_padded]) + mov rstk, rsp + %assign stack_size_padded stack_size + %if xmm_regs_used > 6 + %assign stack_size_padded stack_size_padded + (xmm_regs_used - 6) * 16 + %if mmsize == 32 && xmm_regs_used & 1 + ; re-align to 32 bytes + %assign stack_size_padded (stack_size_padded + 16) + %endif + %endif + %if %1 < 0 ; need to store rsp on stack + sub rsp, gprsize+stack_size_padded + and rsp, ~(%%stack_alignment-1) + %xdefine rstkm [rsp+stack_size_padded] + mov rstkm, rstk + %else ; can keep rsp in rstk during whole function + sub rsp, stack_size_padded + and rsp, ~(%%stack_alignment-1) + %xdefine rstkm rstk + %endif + %endif + %if xmm_regs_used > 6 + WIN64_PUSH_XMM + %endif + %endif + %endif +%endmacro + +%macro SETUP_STACK_POINTER 1 + %ifnum %1 + %if %1 != 0 && (HAVE_ALIGNED_STACK == 0 || mmsize == 32) + %if %1 > 0 + %assign regs_used (regs_used + 1) + %elif ARCH_X86_64 && regs_used == num_args && num_args <= 4 + UNIX64 * 2 + %warning "Stack pointer will overwrite register argument" + %endif + %endif + %endif +%endmacro + +%macro DEFINE_ARGS_INTERNAL 3+ + %ifnum %2 + DEFINE_ARGS %3 + %elif %1 == 4 + DEFINE_ARGS %2 + %elif %1 > 4 + DEFINE_ARGS %2, %3 + %endif +%endmacro + %if WIN64 ; Windows x64 ;================================================= DECLARE_REG 0, rcx @@ -321,30 +410,35 @@ DECLARE_REG 12, R13, 104 DECLARE_REG 13, R14, 112 DECLARE_REG 14, R15, 120 -%macro PROLOGUE 2-4+ 0 ; #args, #regs, #xmm_regs, arg_names... +%macro PROLOGUE 2-5+ 0 ; #args, #regs, #xmm_regs, [stack_size,] arg_names... %assign num_args %1 %assign regs_used %2 ASSERT regs_used >= num_args + SETUP_STACK_POINTER %4 ASSERT regs_used <= 15 PUSH_IF_USED 7, 8, 9, 10, 11, 12, 13, 14 - WIN64_SPILL_XMM %3 + ALLOC_STACK %4, %3 + %if mmsize != 8 && stack_size == 0 + WIN64_SPILL_XMM %3 + %endif LOAD_IF_USED 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 - DEFINE_ARGS %4 + DEFINE_ARGS_INTERNAL %0, %4, %5 +%endmacro + +%macro WIN64_PUSH_XMM 0 + %assign %%i xmm_regs_used + %rep (xmm_regs_used-6) + %assign %%i %%i-1 + movaps [rsp + (%%i-6)*16 + stack_size + (~stack_offset&8)], xmm %+ %%i + %endrep %endmacro %macro WIN64_SPILL_XMM 1 %assign xmm_regs_used %1 - %if mmsize == 8 - %assign xmm_regs_used 0 - %endif ASSERT xmm_regs_used <= 16 %if xmm_regs_used > 6 SUB rsp, (xmm_regs_used-6)*16+16 - %assign %%i xmm_regs_used - %rep (xmm_regs_used-6) - %assign %%i %%i-1 - movdqa [rsp + (%%i-6)*16+(~stack_offset&8)], xmm %+ %%i - %endrep + WIN64_PUSH_XMM %endif %endmacro @@ -353,24 +447,36 @@ DECLARE_REG 14, R15, 120 %assign %%i xmm_regs_used %rep (xmm_regs_used-6) %assign %%i %%i-1 - movdqa xmm %+ %%i, [%1 + (%%i-6)*16+(~stack_offset&8)] + movaps xmm %+ %%i, [%1 + (%%i-6)*16+stack_size+(~stack_offset&8)] %endrep - add %1, (xmm_regs_used-6)*16+16 + %if stack_size_padded == 0 + add %1, (xmm_regs_used-6)*16+16 + %endif + %endif + %if stack_size_padded > 0 + %if stack_size > 0 && (mmsize == 32 || HAVE_ALIGNED_STACK == 0) + mov rsp, rstkm + %else + add %1, stack_size_padded + %endif %endif %endmacro %macro WIN64_RESTORE_XMM 1 WIN64_RESTORE_XMM_INTERNAL %1 - %assign stack_offset stack_offset-(xmm_regs_used-6)*16+16 + %assign stack_offset (stack_offset-stack_size_padded) %assign xmm_regs_used 0 %endmacro -%define has_epilogue regs_used > 7 || xmm_regs_used > 6 +%define has_epilogue regs_used > 7 || xmm_regs_used > 6 || mmsize == 32 || stack_size > 0 %macro RET 0 WIN64_RESTORE_XMM_INTERNAL rsp POP_IF_USED 14, 13, 12, 11, 10, 9, 8, 7 - ret +%if mmsize == 32 + vzeroupper +%endif + AUTO_REP_RET %endmacro %elif ARCH_X86_64 ; *nix x64 ;============================================= @@ -391,21 +497,33 @@ DECLARE_REG 12, R13, 56 DECLARE_REG 13, R14, 64 DECLARE_REG 14, R15, 72 -%macro PROLOGUE 2-4+ ; #args, #regs, #xmm_regs, arg_names... +%macro PROLOGUE 2-5+ ; #args, #regs, #xmm_regs, [stack_size,] arg_names... %assign num_args %1 %assign regs_used %2 ASSERT regs_used >= num_args + SETUP_STACK_POINTER %4 ASSERT regs_used <= 15 PUSH_IF_USED 9, 10, 11, 12, 13, 14 + ALLOC_STACK %4 LOAD_IF_USED 6, 7, 8, 9, 10, 11, 12, 13, 14 - DEFINE_ARGS %4 + DEFINE_ARGS_INTERNAL %0, %4, %5 %endmacro -%define has_epilogue regs_used > 9 +%define has_epilogue regs_used > 9 || mmsize == 32 || stack_size > 0 %macro RET 0 +%if stack_size_padded > 0 +%if mmsize == 32 || HAVE_ALIGNED_STACK == 0 + mov rsp, rstkm +%else + add rsp, stack_size_padded +%endif +%endif POP_IF_USED 14, 13, 12, 11, 10, 9 - ret +%if mmsize == 32 + vzeroupper +%endif + AUTO_REP_RET %endmacro %else ; X86_32 ;============================================================== @@ -421,7 +539,7 @@ DECLARE_REG 6, ebp, 28 %macro DECLARE_ARG 1-* %rep %0 - %define r%1m [esp + stack_offset + 4*%1 + 4] + %define r%1m [rstk + stack_offset + 4*%1 + 4] %define r%1mp dword r%1m %rotate 1 %endrep @@ -429,23 +547,39 @@ DECLARE_REG 6, ebp, 28 DECLARE_ARG 7, 8, 9, 10, 11, 12, 13, 14 -%macro PROLOGUE 2-4+ ; #args, #regs, #xmm_regs, arg_names... +%macro PROLOGUE 2-5+ ; #args, #regs, #xmm_regs, [stack_size,] arg_names... %assign num_args %1 %assign regs_used %2 + ASSERT regs_used >= num_args + %if num_args > 7 + %assign num_args 7 + %endif %if regs_used > 7 %assign regs_used 7 %endif - ASSERT regs_used >= num_args + SETUP_STACK_POINTER %4 + ASSERT regs_used <= 7 PUSH_IF_USED 3, 4, 5, 6 + ALLOC_STACK %4 LOAD_IF_USED 0, 1, 2, 3, 4, 5, 6 - DEFINE_ARGS %4 + DEFINE_ARGS_INTERNAL %0, %4, %5 %endmacro -%define has_epilogue regs_used > 3 +%define has_epilogue regs_used > 3 || mmsize == 32 || stack_size > 0 %macro RET 0 +%if stack_size_padded > 0 +%if mmsize == 32 || HAVE_ALIGNED_STACK == 0 + mov rsp, rstkm +%else + add rsp, stack_size_padded +%endif +%endif POP_IF_USED 6, 5, 4, 3 - ret +%if mmsize == 32 + vzeroupper +%endif + AUTO_REP_RET %endmacro %endif ;====================================================================== @@ -455,8 +589,14 @@ DECLARE_ARG 7, 8, 9, 10, 11, 12, 13, 14 %endmacro %macro WIN64_RESTORE_XMM 1 %endmacro +%macro WIN64_PUSH_XMM 0 +%endmacro %endif +; On AMD cpus <=K10, an ordinary ret is slow if it immediately follows either +; a branch or a branch target. So switch to a 2-byte form of ret in that case. +; We can automatically detect "follows a branch", but not a branch target. +; (SSSE3 is a sufficient condition to know that your cpu doesn't have this problem.) %macro REP_RET 0 %if has_epilogue RET @@ -465,6 +605,29 @@ DECLARE_ARG 7, 8, 9, 10, 11, 12, 13, 14 %endif %endmacro +%define last_branch_adr $$ +%macro AUTO_REP_RET 0 + %ifndef cpuflags + times ((last_branch_adr-$)>>31)+1 rep ; times 1 iff $ != last_branch_adr. + %elif notcpuflag(ssse3) + times ((last_branch_adr-$)>>31)+1 rep + %endif + ret +%endmacro + +%macro BRANCH_INSTR 0-* + %rep %0 + %macro %1 1-2 %1 + %2 %1 + %%branch_instr: + %xdefine last_branch_adr %%branch_instr + %endmacro + %rotate 1 + %endrep +%endmacro + +BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, jna, jnae, jb, jbe, jnb, jnbe, jc, jnc, js, jns, jo, jno, jp, jnp + %macro TAIL_CALL 2 ; callee, is_nonadjacent %if has_epilogue call %1 @@ -484,36 +647,48 @@ DECLARE_ARG 7, 8, 9, 10, 11, 12, 13, 14 ; Applies any symbol mangling needed for C linkage, and sets up a define such that ; subsequent uses of the function name automatically refer to the mangled version. ; Appends cpuflags to the function name if cpuflags has been specified. -%macro cglobal 1-2+ ; name, [PROLOGUE args] -%if %0 == 1 - cglobal_internal %1 %+ SUFFIX -%else - cglobal_internal %1 %+ SUFFIX, %2 -%endif +; The "" empty default parameter is a workaround for nasm, which fails if SUFFIX +; is empty and we call cglobal_internal with just %1 %+ SUFFIX (without %2). +%macro cglobal 1-2+ "" ; name, [PROLOGUE args] + cglobal_internal 1, %1 %+ SUFFIX, %2 %endmacro -%macro cglobal_internal 1-2+ - %ifndef cglobaled_%1 - %xdefine %1 mangle(program_name %+ _ %+ %1) - %xdefine %1.skip_prologue %1 %+ .skip_prologue - CAT_XDEFINE cglobaled_, %1, 1 +%macro cvisible 1-2+ "" ; name, [PROLOGUE args] + cglobal_internal 0, %1 %+ SUFFIX, %2 +%endmacro +%macro cglobal_internal 2-3+ + %if %1 + %xdefine %%FUNCTION_PREFIX private_prefix + %xdefine %%VISIBILITY hidden + %else + %xdefine %%FUNCTION_PREFIX public_prefix + %xdefine %%VISIBILITY + %endif + %ifndef cglobaled_%2 + %xdefine %2 mangle(%%FUNCTION_PREFIX %+ _ %+ %2) + %xdefine %2.skip_prologue %2 %+ .skip_prologue + CAT_XDEFINE cglobaled_, %2, 1 %endif - %xdefine current_function %1 + %xdefine current_function %2 %ifidn __OUTPUT_FORMAT__,elf - global %1:function hidden + global %2:function %%VISIBILITY %else - global %1 + global %2 %endif align function_align - %1: + %2: RESET_MM_PERMUTATION ; not really needed, but makes disassembly somewhat nicer + %xdefine rstk rsp %assign stack_offset 0 - %if %0 > 1 - PROLOGUE %2 + %assign stack_size 0 + %assign stack_size_padded 0 + %assign xmm_regs_used 0 + %ifnidn %3, "" + PROLOGUE %3 %endif %endmacro %macro cextern 1 - %xdefine %1 mangle(program_name %+ _ %+ %1) + %xdefine %1 mangle(private_prefix %+ _ %+ %1) CAT_XDEFINE cglobaled_, %1, 1 extern %1 %endmacro @@ -526,8 +701,12 @@ DECLARE_ARG 7, 8, 9, 10, 11, 12, 13, 14 %endmacro %macro const 2+ - %xdefine %1 mangle(program_name %+ _ %+ %1) - global %1 + %xdefine %1 mangle(private_prefix %+ _ %+ %1) + %ifidn __OUTPUT_FORMAT__,elf + global %1:data hidden + %else + global %1 + %endif %1: %2 %endmacro @@ -541,18 +720,20 @@ SECTION .note.GNU-stack noalloc noexec nowrite progbits %assign cpuflags_mmx (1<<0) %assign cpuflags_mmx2 (1<<1) | cpuflags_mmx -%assign cpuflags_sse (1<<2) | cpuflags_mmx2 -%assign cpuflags_sse2 (1<<3) | cpuflags_sse -%assign cpuflags_sse2slow (1<<4) | cpuflags_sse2 -%assign cpuflags_sse3 (1<<5) | cpuflags_sse2 -%assign cpuflags_ssse3 (1<<6) | cpuflags_sse3 -%assign cpuflags_sse4 (1<<7) | cpuflags_ssse3 -%assign cpuflags_sse42 (1<<8) | cpuflags_sse4 -%assign cpuflags_avx (1<<9) | cpuflags_sse42 -%assign cpuflags_xop (1<<10)| cpuflags_avx -%assign cpuflags_fma4 (1<<11)| cpuflags_avx -%assign cpuflags_avx2 (1<<12)| cpuflags_avx -%assign cpuflags_fma3 (1<<13)| cpuflags_avx +%assign cpuflags_3dnow (1<<2) | cpuflags_mmx +%assign cpuflags_3dnowext (1<<3) | cpuflags_3dnow +%assign cpuflags_sse (1<<4) | cpuflags_mmx2 +%assign cpuflags_sse2 (1<<5) | cpuflags_sse +%assign cpuflags_sse2slow (1<<6) | cpuflags_sse2 +%assign cpuflags_sse3 (1<<7) | cpuflags_sse2 +%assign cpuflags_ssse3 (1<<8) | cpuflags_sse3 +%assign cpuflags_sse4 (1<<9) | cpuflags_ssse3 +%assign cpuflags_sse42 (1<<10)| cpuflags_sse4 +%assign cpuflags_avx (1<<11)| cpuflags_sse42 +%assign cpuflags_xop (1<<12)| cpuflags_avx +%assign cpuflags_fma4 (1<<13)| cpuflags_avx +%assign cpuflags_avx2 (1<<14)| cpuflags_avx +%assign cpuflags_fma3 (1<<15)| cpuflags_avx %assign cpuflags_cache32 (1<<16) %assign cpuflags_cache64 (1<<17) @@ -560,9 +741,10 @@ SECTION .note.GNU-stack noalloc noexec nowrite progbits %assign cpuflags_lzcnt (1<<19) %assign cpuflags_misalign (1<<20) %assign cpuflags_aligned (1<<21) ; not a cpu feature, but a function variant -%assign cpuflags_bmi1 (1<<22) -%assign cpuflags_bmi2 (1<<23)|cpuflags_bmi1 -%assign cpuflags_tbm (1<<24)|cpuflags_bmi1 +%assign cpuflags_atom (1<<22) +%assign cpuflags_bmi1 (1<<23) +%assign cpuflags_bmi2 (1<<24)|cpuflags_bmi1 +%assign cpuflags_tbm (1<<25)|cpuflags_bmi1 %define cpuflag(x) ((cpuflags & (cpuflags_ %+ x)) == (cpuflags_ %+ x)) %define notcpuflag(x) ((cpuflags & (cpuflags_ %+ x)) != (cpuflags_ %+ x)) @@ -571,6 +753,7 @@ SECTION .note.GNU-stack noalloc noexec nowrite progbits ; All subsequent functions (up to the next INIT_CPUFLAGS) is built for the specified cpu. ; You shouldn't need to invoke this macro directly, it's a subroutine for INIT_MMX &co. %macro INIT_CPUFLAGS 0-2 + CPU amdnop %if %0 >= 1 %xdefine cpuname %1 %assign cpuflags cpuflags_%1 @@ -582,11 +765,19 @@ SECTION .note.GNU-stack noalloc noexec nowrite progbits %if cpuflag(avx) %assign avx_enabled 1 %endif + %if (mmsize == 16 && notcpuflag(sse2)) || (mmsize == 32 && notcpuflag(avx2)) + %define mova movaps + %define movu movups + %define movnta movntps + %endif %if cpuflag(aligned) %define movu mova %elifidn %1, sse3 %define movu lddqu %endif + %if ARCH_X86_64 == 0 && notcpuflag(sse2) + CPU basicnop + %endif %else %xdefine SUFFIX %undef cpuname @@ -656,10 +847,10 @@ SECTION .note.GNU-stack noalloc noexec nowrite progbits %if ARCH_X86_64 %define num_mmregs 16 %endif - %define mova vmovaps - %define movu vmovups + %define mova movdqa + %define movu movdqu %undef movh - %undef movnta + %define movnta movntdq %assign %%i 0 %rep num_mmregs CAT_XDEFINE m, %%i, ymm %+ %%i @@ -820,101 +1011,107 @@ INIT_XMM ;%1 == instruction ;%2 == 1 if float, 0 if int -;%3 == 1 if 4-operand (xmm, xmm, xmm, imm), 0 if 3-operand (xmm, xmm, xmm) -;%4 == number of operands given +;%3 == 1 if non-destructive or 4-operand (xmm, xmm, xmm, imm), 0 otherwise +;%4 == 1 if commutative (i.e. doesn't matter which src arg is which), 0 if not ;%5+: operands -%macro RUN_AVX_INSTR 6-7+ - %ifid %6 - %define %%sizeofreg sizeof%6 - %elifid %5 - %define %%sizeofreg sizeof%5 +%macro RUN_AVX_INSTR 5-8+ + %ifnum sizeof%6 + %assign %%sizeofreg sizeof%6 + %elifnum sizeof%5 + %assign %%sizeofreg sizeof%5 %else - %define %%sizeofreg mmsize + %assign %%sizeofreg mmsize %endif - %if %%sizeofreg==32 - %if %4>=3 - v%1 %5, %6, %7 - %else - v%1 %5, %6 - %endif + %assign %%emulate_avx 0 + %if avx_enabled && %%sizeofreg >= 16 + %xdefine %%instr v%1 %else - %if %%sizeofreg==8 - %define %%regmov movq - %elif %2 - %define %%regmov movaps - %else - %define %%regmov movdqa + %xdefine %%instr %1 + %if %0 >= 7+%3 + %assign %%emulate_avx 1 %endif + %endif - %if %4>=3+%3 - %ifnidn %5, %6 - %if avx_enabled && %%sizeofreg==16 - v%1 %5, %6, %7 - %else - CHECK_AVX_INSTR_EMU {%1 %5, %6, %7}, %5, %7 - %%regmov %5, %6 - %1 %5, %7 + %if %%emulate_avx + %xdefine %%src1 %6 + %xdefine %%src2 %7 + %ifnidn %5, %6 + %if %0 >= 8 + CHECK_AVX_INSTR_EMU {%1 %5, %6, %7, %8}, %5, %7, %8 + %else + CHECK_AVX_INSTR_EMU {%1 %5, %6, %7}, %5, %7 + %endif + %if %4 && %3 == 0 + %ifnid %7 + ; 3-operand AVX instructions with a memory arg can only have it in src2, + ; whereas SSE emulation prefers to have it in src1 (i.e. the mov). + ; So, if the instruction is commutative with a memory arg, swap them. + %xdefine %%src1 %7 + %xdefine %%src2 %6 %endif + %endif + %if %%sizeofreg == 8 + MOVQ %5, %%src1 + %elif %2 + MOVAPS %5, %%src1 %else - %1 %5, %7 + MOVDQA %5, %%src1 %endif - %elif %4>=3 - %1 %5, %6, %7 - %else - %1 %5, %6 %endif - %endif -%endmacro - -; 3arg AVX ops with a memory arg can only have it in src2, -; whereas SSE emulation of 3arg prefers to have it in src1 (i.e. the mov). -; So, if the op is symmetric and the wrong one is memory, swap them. -%macro RUN_AVX_INSTR1 8 - %assign %%swap 0 - %if avx_enabled - %ifnid %6 - %assign %%swap 1 - %endif - %elifnidn %5, %6 - %ifnid %7 - %assign %%swap 1 + %if %0 >= 8 + %1 %5, %%src2, %8 + %else + %1 %5, %%src2 %endif - %endif - %if %%swap && %3 == 0 && %8 == 1 - RUN_AVX_INSTR %1, %2, %3, %4, %5, %7, %6 + %elif %0 >= 8 + %%instr %5, %6, %7, %8 + %elif %0 == 7 + %%instr %5, %6, %7 + %elif %0 == 6 + %%instr %5, %6 %else - RUN_AVX_INSTR %1, %2, %3, %4, %5, %6, %7 + %%instr %5 %endif %endmacro ;%1 == instruction ;%2 == 1 if float, 0 if int -;%3 == 1 if 4-operand (xmm, xmm, xmm, imm), 0 if 3-operand (xmm, xmm, xmm) -;%4 == 1 if symmetric (i.e. doesn't matter which src arg is which), 0 if not -%macro AVX_INSTR 4 - %macro %1 2-9 fnord, fnord, fnord, %1, %2, %3, %4 - %ifidn %3, fnord - RUN_AVX_INSTR %6, %7, %8, 2, %1, %2 +;%3 == 1 if non-destructive or 4-operand (xmm, xmm, xmm, imm), 0 otherwise +;%4 == 1 if commutative (i.e. doesn't matter which src arg is which), 0 if not +%macro AVX_INSTR 1-4 0, 1, 0 + %macro %1 1-9 fnord, fnord, fnord, fnord, %1, %2, %3, %4 + %ifidn %2, fnord + RUN_AVX_INSTR %6, %7, %8, %9, %1 + %elifidn %3, fnord + RUN_AVX_INSTR %6, %7, %8, %9, %1, %2 %elifidn %4, fnord - RUN_AVX_INSTR1 %6, %7, %8, 3, %1, %2, %3, %9 + RUN_AVX_INSTR %6, %7, %8, %9, %1, %2, %3 %elifidn %5, fnord - RUN_AVX_INSTR %6, %7, %8, 4, %1, %2, %3, %4 + RUN_AVX_INSTR %6, %7, %8, %9, %1, %2, %3, %4 %else - RUN_AVX_INSTR %6, %7, %8, 5, %1, %2, %3, %4, %5 + RUN_AVX_INSTR %6, %7, %8, %9, %1, %2, %3, %4, %5 %endif %endmacro %endmacro +; Instructions with both VEX and non-VEX encodings +; Non-destructive instructions are written without parameters AVX_INSTR addpd, 1, 0, 1 AVX_INSTR addps, 1, 0, 1 AVX_INSTR addsd, 1, 0, 1 AVX_INSTR addss, 1, 0, 1 AVX_INSTR addsubpd, 1, 0, 0 AVX_INSTR addsubps, 1, 0, 0 -AVX_INSTR andpd, 1, 0, 1 -AVX_INSTR andps, 1, 0, 1 +AVX_INSTR aesdec, 0, 0, 0 +AVX_INSTR aesdeclast, 0, 0, 0 +AVX_INSTR aesenc, 0, 0, 0 +AVX_INSTR aesenclast, 0, 0, 0 +AVX_INSTR aesimc +AVX_INSTR aeskeygenassist AVX_INSTR andnpd, 1, 0, 0 AVX_INSTR andnps, 1, 0, 0 +AVX_INSTR andpd, 1, 0, 1 +AVX_INSTR andps, 1, 0, 1 AVX_INSTR blendpd, 1, 0, 0 AVX_INSTR blendps, 1, 0, 0 AVX_INSTR blendvpd, 1, 0, 0 @@ -923,16 +1120,39 @@ AVX_INSTR cmppd, 1, 0, 0 AVX_INSTR cmpps, 1, 0, 0 AVX_INSTR cmpsd, 1, 0, 0 AVX_INSTR cmpss, 1, 0, 0 +AVX_INSTR comisd +AVX_INSTR comiss +AVX_INSTR cvtdq2pd +AVX_INSTR cvtdq2ps +AVX_INSTR cvtpd2dq +AVX_INSTR cvtpd2ps +AVX_INSTR cvtps2dq +AVX_INSTR cvtps2pd +AVX_INSTR cvtsd2si +AVX_INSTR cvtsd2ss +AVX_INSTR cvtsi2sd +AVX_INSTR cvtsi2ss +AVX_INSTR cvtss2sd +AVX_INSTR cvtss2si +AVX_INSTR cvttpd2dq +AVX_INSTR cvttps2dq +AVX_INSTR cvttsd2si +AVX_INSTR cvttss2si AVX_INSTR divpd, 1, 0, 0 AVX_INSTR divps, 1, 0, 0 AVX_INSTR divsd, 1, 0, 0 AVX_INSTR divss, 1, 0, 0 AVX_INSTR dppd, 1, 1, 0 AVX_INSTR dpps, 1, 1, 0 +AVX_INSTR extractps AVX_INSTR haddpd, 1, 0, 0 AVX_INSTR haddps, 1, 0, 0 AVX_INSTR hsubpd, 1, 0, 0 AVX_INSTR hsubps, 1, 0, 0 +AVX_INSTR insertps, 1, 1, 0 +AVX_INSTR lddqu +AVX_INSTR ldmxcsr +AVX_INSTR maskmovdqu AVX_INSTR maxpd, 1, 0, 1 AVX_INSTR maxps, 1, 0, 1 AVX_INSTR maxsd, 1, 0, 1 @@ -941,8 +1161,31 @@ AVX_INSTR minpd, 1, 0, 1 AVX_INSTR minps, 1, 0, 1 AVX_INSTR minsd, 1, 0, 1 AVX_INSTR minss, 1, 0, 1 +AVX_INSTR movapd +AVX_INSTR movaps +AVX_INSTR movd +AVX_INSTR movddup +AVX_INSTR movdqa +AVX_INSTR movdqu +AVX_INSTR movhlps, 1, 0, 0 +AVX_INSTR movhpd, 1, 0, 0 +AVX_INSTR movhps, 1, 0, 0 +AVX_INSTR movlhps, 1, 0, 0 +AVX_INSTR movlpd, 1, 0, 0 +AVX_INSTR movlps, 1, 0, 0 +AVX_INSTR movmskpd +AVX_INSTR movmskps +AVX_INSTR movntdq +AVX_INSTR movntdqa +AVX_INSTR movntpd +AVX_INSTR movntps +AVX_INSTR movq AVX_INSTR movsd, 1, 0, 0 +AVX_INSTR movshdup +AVX_INSTR movsldup AVX_INSTR movss, 1, 0, 0 +AVX_INSTR movupd +AVX_INSTR movups AVX_INSTR mpsadbw, 0, 1, 0 AVX_INSTR mulpd, 1, 0, 1 AVX_INSTR mulps, 1, 0, 1 @@ -950,9 +1193,9 @@ AVX_INSTR mulsd, 1, 0, 1 AVX_INSTR mulss, 1, 0, 1 AVX_INSTR orpd, 1, 0, 1 AVX_INSTR orps, 1, 0, 1 -AVX_INSTR pabsb, 0, 0, 0 -AVX_INSTR pabsw, 0, 0, 0 -AVX_INSTR pabsd, 0, 0, 0 +AVX_INSTR pabsb +AVX_INSTR pabsd +AVX_INSTR pabsw AVX_INSTR packsswb, 0, 0, 0 AVX_INSTR packssdw, 0, 0, 0 AVX_INSTR packuswb, 0, 0, 0 @@ -972,10 +1215,11 @@ AVX_INSTR pavgb, 0, 0, 1 AVX_INSTR pavgw, 0, 0, 1 AVX_INSTR pblendvb, 0, 0, 0 AVX_INSTR pblendw, 0, 1, 0 -AVX_INSTR pcmpestri, 0, 0, 0 -AVX_INSTR pcmpestrm, 0, 0, 0 -AVX_INSTR pcmpistri, 0, 0, 0 -AVX_INSTR pcmpistrm, 0, 0, 0 +AVX_INSTR pclmulqdq, 0, 1, 0 +AVX_INSTR pcmpestri +AVX_INSTR pcmpestrm +AVX_INSTR pcmpistri +AVX_INSTR pcmpistrm AVX_INSTR pcmpeqb, 0, 0, 1 AVX_INSTR pcmpeqw, 0, 0, 1 AVX_INSTR pcmpeqd, 0, 0, 1 @@ -984,12 +1228,21 @@ AVX_INSTR pcmpgtb, 0, 0, 0 AVX_INSTR pcmpgtw, 0, 0, 0 AVX_INSTR pcmpgtd, 0, 0, 0 AVX_INSTR pcmpgtq, 0, 0, 0 +AVX_INSTR pextrb +AVX_INSTR pextrd +AVX_INSTR pextrq +AVX_INSTR pextrw AVX_INSTR phaddw, 0, 0, 0 AVX_INSTR phaddd, 0, 0, 0 AVX_INSTR phaddsw, 0, 0, 0 +AVX_INSTR phminposuw AVX_INSTR phsubw, 0, 0, 0 AVX_INSTR phsubd, 0, 0, 0 AVX_INSTR phsubsw, 0, 0, 0 +AVX_INSTR pinsrb, 0, 1, 0 +AVX_INSTR pinsrd, 0, 1, 0 +AVX_INSTR pinsrq, 0, 1, 0 +AVX_INSTR pinsrw, 0, 1, 0 AVX_INSTR pmaddwd, 0, 0, 1 AVX_INSTR pmaddubsw, 0, 0, 0 AVX_INSTR pmaxsb, 0, 0, 1 @@ -1004,20 +1257,32 @@ AVX_INSTR pminsd, 0, 0, 1 AVX_INSTR pminub, 0, 0, 1 AVX_INSTR pminuw, 0, 0, 1 AVX_INSTR pminud, 0, 0, 1 -AVX_INSTR pmovmskb, 0, 0, 0 -AVX_INSTR pmulhuw, 0, 0, 1 +AVX_INSTR pmovmskb +AVX_INSTR pmovsxbw +AVX_INSTR pmovsxbd +AVX_INSTR pmovsxbq +AVX_INSTR pmovsxwd +AVX_INSTR pmovsxwq +AVX_INSTR pmovsxdq +AVX_INSTR pmovzxbw +AVX_INSTR pmovzxbd +AVX_INSTR pmovzxbq +AVX_INSTR pmovzxwd +AVX_INSTR pmovzxwq +AVX_INSTR pmovzxdq +AVX_INSTR pmuldq, 0, 0, 1 AVX_INSTR pmulhrsw, 0, 0, 1 +AVX_INSTR pmulhuw, 0, 0, 1 AVX_INSTR pmulhw, 0, 0, 1 AVX_INSTR pmullw, 0, 0, 1 AVX_INSTR pmulld, 0, 0, 1 AVX_INSTR pmuludq, 0, 0, 1 -AVX_INSTR pmuldq, 0, 0, 1 AVX_INSTR por, 0, 0, 1 AVX_INSTR psadbw, 0, 0, 1 AVX_INSTR pshufb, 0, 0, 0 -AVX_INSTR pshufd, 0, 1, 0 -AVX_INSTR pshufhw, 0, 1, 0 -AVX_INSTR pshuflw, 0, 1, 0 +AVX_INSTR pshufd +AVX_INSTR pshufhw +AVX_INSTR pshuflw AVX_INSTR psignb, 0, 0, 0 AVX_INSTR psignw, 0, 0, 0 AVX_INSTR psignd, 0, 0, 0 @@ -1039,7 +1304,7 @@ AVX_INSTR psubsb, 0, 0, 0 AVX_INSTR psubsw, 0, 0, 0 AVX_INSTR psubusb, 0, 0, 0 AVX_INSTR psubusw, 0, 0, 0 -AVX_INSTR ptest, 0, 0, 0 +AVX_INSTR ptest AVX_INSTR punpckhbw, 0, 0, 0 AVX_INSTR punpckhwd, 0, 0, 0 AVX_INSTR punpckhdq, 0, 0, 0 @@ -1049,11 +1314,27 @@ AVX_INSTR punpcklwd, 0, 0, 0 AVX_INSTR punpckldq, 0, 0, 0 AVX_INSTR punpcklqdq, 0, 0, 0 AVX_INSTR pxor, 0, 0, 1 +AVX_INSTR rcpps, 1, 0, 0 +AVX_INSTR rcpss, 1, 0, 0 +AVX_INSTR roundpd +AVX_INSTR roundps +AVX_INSTR roundsd +AVX_INSTR roundss +AVX_INSTR rsqrtps, 1, 0, 0 +AVX_INSTR rsqrtss, 1, 0, 0 +AVX_INSTR shufpd, 1, 1, 0 AVX_INSTR shufps, 1, 1, 0 +AVX_INSTR sqrtpd, 1, 0, 0 +AVX_INSTR sqrtps, 1, 0, 0 +AVX_INSTR sqrtsd, 1, 0, 0 +AVX_INSTR sqrtss, 1, 0, 0 +AVX_INSTR stmxcsr AVX_INSTR subpd, 1, 0, 0 AVX_INSTR subps, 1, 0, 0 AVX_INSTR subsd, 1, 0, 0 AVX_INSTR subss, 1, 0, 0 +AVX_INSTR ucomisd +AVX_INSTR ucomiss AVX_INSTR unpckhpd, 1, 0, 0 AVX_INSTR unpckhps, 1, 0, 0 AVX_INSTR unpcklpd, 1, 0, 0 @@ -1099,6 +1380,44 @@ FMA_INSTR pmacsdd, pmulld, paddd FMA_INSTR pmacsww, pmullw, paddw FMA_INSTR pmadcswd, pmaddwd, paddd -; tzcnt is equivalent to "rep bsf" and is backwards-compatible with bsf. -; This lets us use tzcnt without bumping the yasm version requirement yet. -%define tzcnt rep bsf +; convert FMA4 to FMA3 if possible +%macro FMA4_INSTR 4 + %macro %1 4-8 %1, %2, %3, %4 + %if cpuflag(fma4) + v%5 %1, %2, %3, %4 + %elifidn %1, %2 + v%6 %1, %4, %3 ; %1 = %1 * %3 + %4 + %elifidn %1, %3 + v%7 %1, %2, %4 ; %1 = %2 * %1 + %4 + %elifidn %1, %4 + v%8 %1, %2, %3 ; %1 = %2 * %3 + %1 + %else + %error fma3 emulation of ``%5 %1, %2, %3, %4'' is not supported + %endif + %endmacro +%endmacro + +FMA4_INSTR fmaddpd, fmadd132pd, fmadd213pd, fmadd231pd +FMA4_INSTR fmaddps, fmadd132ps, fmadd213ps, fmadd231ps +FMA4_INSTR fmaddsd, fmadd132sd, fmadd213sd, fmadd231sd +FMA4_INSTR fmaddss, fmadd132ss, fmadd213ss, fmadd231ss + +FMA4_INSTR fmaddsubpd, fmaddsub132pd, fmaddsub213pd, fmaddsub231pd +FMA4_INSTR fmaddsubps, fmaddsub132ps, fmaddsub213ps, fmaddsub231ps +FMA4_INSTR fmsubaddpd, fmsubadd132pd, fmsubadd213pd, fmsubadd231pd +FMA4_INSTR fmsubaddps, fmsubadd132ps, fmsubadd213ps, fmsubadd231ps + +FMA4_INSTR fmsubpd, fmsub132pd, fmsub213pd, fmsub231pd +FMA4_INSTR fmsubps, fmsub132ps, fmsub213ps, fmsub231ps +FMA4_INSTR fmsubsd, fmsub132sd, fmsub213sd, fmsub231sd +FMA4_INSTR fmsubss, fmsub132ss, fmsub213ss, fmsub231ss + +FMA4_INSTR fnmaddpd, fnmadd132pd, fnmadd213pd, fnmadd231pd +FMA4_INSTR fnmaddps, fnmadd132ps, fnmadd213ps, fnmadd231ps +FMA4_INSTR fnmaddsd, fnmadd132sd, fnmadd213sd, fnmadd231sd +FMA4_INSTR fnmaddss, fnmadd132ss, fnmadd213ss, fnmadd231ss + +FMA4_INSTR fnmsubpd, fnmsub132pd, fnmsub213pd, fnmsub231pd +FMA4_INSTR fnmsubps, fnmsub132ps, fnmsub213ps, fnmsub231ps +FMA4_INSTR fnmsubsd, fnmsub132sd, fnmsub213sd, fnmsub231sd +FMA4_INSTR fnmsubss, fnmsub132ss, fnmsub213ss, fnmsub231ss diff --git a/common/x86/x86util.asm b/common/x86/x86util.asm index cb8c0216..9f3fc4db 100644 --- a/common/x86/x86util.asm +++ b/common/x86/x86util.asm @@ -1,7 +1,7 @@ ;***************************************************************************** ;* x86util.asm: x86 utility macros ;***************************************************************************** -;* Copyright (C) 2008-2012 x264 project +;* Copyright (C) 2008-2013 x264 project ;* ;* Authors: Holger Lubitz ;* Loren Merritt @@ -294,16 +294,24 @@ %endif %endmacro +%macro HADDUWD 2 +%if cpuflag(xop) + vphadduwd %1, %1 +%else + psrld %2, %1, 16 + pslld %1, 16 + psrld %1, 16 + paddd %1, %2 +%endif +%endmacro + %macro HADDUW 2 %if cpuflag(xop) && mmsize == 16 vphadduwq %1, %1 movhlps %2, %1 paddd %1, %2 %else - psrld %2, %1, 16 - pslld %1, 16 - psrld %1, 16 - paddd %1, %2 + HADDUWD %1, %2 HADDD %1, %2 %endif %endmacro @@ -675,11 +683,18 @@ %endmacro -%macro LOAD_DIFF 5 +%macro LOAD_DIFF 5-6 1 %if HIGH_BIT_DEPTH +%if %6 ; %5 aligned? mova %1, %4 psubw %1, %5 -%elifidn %3, none +%else + movu %1, %4 + movu %2, %5 + psubw %1, %2 +%endif +%else ; !HIGH_BIT_DEPTH +%ifidn %3, none movh %1, %4 movh %2, %5 punpcklbw %1, %2 @@ -692,6 +707,7 @@ punpcklbw %2, %3 psubw %1, %2 %endif +%endif ; HIGH_BIT_DEPTH %endmacro %macro LOAD_DIFF8x4 8 ; 4x dst, 1x tmp, 1x mul, 2x ptr @@ -742,11 +758,11 @@ movh [r0+3*FDEC_STRIDE], %4 %endmacro -%macro LOAD_DIFF_8x4P 7-10 r0,r2,0 ; 4x dest, 2x temp, 2x pointer, increment? - LOAD_DIFF m%1, m%5, m%7, [%8], [%9] - LOAD_DIFF m%2, m%6, m%7, [%8+r1], [%9+r3] - LOAD_DIFF m%3, m%5, m%7, [%8+2*r1], [%9+2*r3] - LOAD_DIFF m%4, m%6, m%7, [%8+r4], [%9+r5] +%macro LOAD_DIFF_8x4P 7-11 r0,r2,0,1 ; 4x dest, 2x temp, 2x pointer, increment, aligned? + LOAD_DIFF m%1, m%5, m%7, [%8], [%9], %11 + LOAD_DIFF m%2, m%6, m%7, [%8+r1], [%9+r3], %11 + LOAD_DIFF m%3, m%5, m%7, [%8+2*r1], [%9+2*r3], %11 + LOAD_DIFF m%4, m%6, m%7, [%8+r4], [%9+r5], %11 %if %10 lea %8, [%8+4*r1] lea %9, [%9+4*r3] diff --git a/config.guess b/config.guess index e792aac6..872b96a1 100755 --- a/config.guess +++ b/config.guess @@ -1,10 +1,10 @@ #! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, -# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 -# Free Software Foundation, Inc. +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +# 2011, 2012 Free Software Foundation, Inc. -timestamp='2009-09-18' +timestamp='2012-09-25' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -17,9 +17,7 @@ timestamp='2009-09-18' # General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA -# 02110-1301, USA. +# along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a @@ -56,8 +54,9 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, -2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 +Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -144,7 +143,7 @@ UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or - # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward @@ -180,7 +179,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in fi ;; *) - os=netbsd + os=netbsd ;; esac # The OS release @@ -201,6 +200,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} + exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} @@ -223,7 +226,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) - UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on @@ -269,7 +272,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - exit ;; + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead @@ -295,12 +301,12 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in echo s390-ibm-zvmoe exit ;; *:OS400:*:*) - echo powerpc-ibm-os400 + echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; - arm:riscos:*:*|arm:RISCOS:*:*) + arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) @@ -333,6 +339,9 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" @@ -391,23 +400,23 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} + echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} - exit ;; + exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} + echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) - echo m68k-milan-mint${UNAME_RELEASE} - exit ;; + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) - echo m68k-hades-mint${UNAME_RELEASE} - exit ;; + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) - echo m68k-unknown-mint${UNAME_RELEASE} - exit ;; + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; @@ -477,8 +486,8 @@ EOF echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) - # DG/UX returns AViiON for all architectures - UNAME_PROCESSOR=`/usr/bin/uname -p` + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ @@ -491,7 +500,7 @@ EOF else echo i586-dg-dgux${UNAME_RELEASE} fi - exit ;; + exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; @@ -548,7 +557,7 @@ EOF echo rs6000-ibm-aix3.2 fi exit ;; - *:AIX:*:[456]) + *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 @@ -591,52 +600,52 @@ EOF 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` - sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` - case "${sc_cpu_version}" in - 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 - 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 - 532) # CPU_PA_RISC2_0 - case "${sc_kernel_bits}" in - 32) HP_ARCH="hppa2.0n" ;; - 64) HP_ARCH="hppa2.0w" ;; + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 - esac ;; - esac + esac ;; + esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + sed 's/^ //' << EOF >$dummy.c - #define _HPUX_SOURCE - #include - #include + #define _HPUX_SOURCE + #include + #include - int main () - { - #if defined(_SC_KERNEL_BITS) - long bits = sysconf(_SC_KERNEL_BITS); - #endif - long cpu = sysconf (_SC_CPU_VERSION); + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); - switch (cpu) - { - case CPU_PA_RISC1_0: puts ("hppa1.0"); break; - case CPU_PA_RISC1_1: puts ("hppa1.1"); break; - case CPU_PA_RISC2_0: - #if defined(_SC_KERNEL_BITS) - switch (bits) - { - case 64: puts ("hppa2.0w"); break; - case 32: puts ("hppa2.0n"); break; - default: puts ("hppa2.0"); break; - } break; - #else /* !defined(_SC_KERNEL_BITS) */ - puts ("hppa2.0"); break; - #endif - default: puts ("hppa1.0"); break; - } - exit (0); - } + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa @@ -727,22 +736,22 @@ EOF exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd - exit ;; + exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi - exit ;; + exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd - exit ;; + exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd - exit ;; + exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd - exit ;; + exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; @@ -766,14 +775,14 @@ EOF exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` - echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit ;; + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; 5000:UNIX_System_V:4.*:*) - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` - echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} @@ -785,34 +794,39 @@ EOF echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) - case ${UNAME_MACHINE} in - pc98) - echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + UNAME_PROCESSOR=`/usr/bin/uname -p` + case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) - echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; + *:MINGW64*:*) + echo ${UNAME_MACHINE}-pc-mingw64 + exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; + i*:MSYS*:*) + echo ${UNAME_MACHINE}-pc-msys + exit ;; i*:windows32*:*) - # uname -m includes "-pc" on this system. - echo ${UNAME_MACHINE}-mingw32 + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; - *:Interix*:[3456]*) - case ${UNAME_MACHINE} in + *:Interix*:*) + case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; - EM64T | authenticamd | genuineintel) + authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) @@ -854,6 +868,13 @@ EOF i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; + aarch64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; @@ -863,7 +884,7 @@ EOF EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; - esac + esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} @@ -875,23 +896,40 @@ EOF then echo ${UNAME_MACHINE}-unknown-linux-gnu else - echo ${UNAME_MACHINE}-unknown-linux-gnueabi + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo ${UNAME_MACHINE}-unknown-linux-gnueabi + else + echo ${UNAME_MACHINE}-unknown-linux-gnueabihf + fi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) - echo cris-axis-linux-gnu + echo ${UNAME_MACHINE}-axis-linux-gnu exit ;; crisv32:Linux:*:*) - echo crisv32-axis-linux-gnu + echo ${UNAME_MACHINE}-axis-linux-gnu exit ;; frv:Linux:*:*) - echo frv-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + hexagon:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:Linux:*:*) - echo ${UNAME_MACHINE}-pc-linux-gnu + LIBC=gnu + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu @@ -918,15 +956,11 @@ EOF #endif #endif EOF - eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' - /^CPU/{ - s: ::g - p - }'`" + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) - echo or32-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; padre:Linux:*:*) echo sparc-unknown-linux-gnu @@ -952,7 +986,7 @@ EOF echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu @@ -960,14 +994,17 @@ EOF sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; + tile*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) - echo x86_64-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; xtensa*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. @@ -976,11 +1013,11 @@ EOF echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) - # Unixware is an offshoot of SVR4, but it has its own version - # number series starting with 2... - # I am not positive that other SVR4 systems won't match this, + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. - # Use sysv4.2uw... so that sysv4* matches it. + # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) @@ -1012,7 +1049,7 @@ EOF fi exit ;; i*86:*:5:[678]*) - # UnixWare 7.x, OpenUNIX and OpenServer 6. + # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; @@ -1040,13 +1077,13 @@ EOF exit ;; pc:*:*:*) # Left here for compatibility: - # uname -m prints for DJGPP always 'pc', but it prints nothing about - # the processor, so we play safe by assuming i586. + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp - exit ;; + exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; @@ -1081,8 +1118,8 @@ EOF /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4; exit; } ;; + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ @@ -1125,10 +1162,10 @@ EOF echo ns32k-sni-sysv fi exit ;; - PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort - # says - echo i586-unisys-sysv4 - exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm @@ -1154,11 +1191,11 @@ EOF exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then - echo mips-nec-sysv${UNAME_RELEASE} + echo mips-nec-sysv${UNAME_RELEASE} else - echo mips-unknown-sysv${UNAME_RELEASE} + echo mips-unknown-sysv${UNAME_RELEASE} fi - exit ;; + exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; @@ -1171,6 +1208,9 @@ EOF BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; + x86_64:Haiku:*:*) + echo x86_64-unknown-haiku + exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; @@ -1223,7 +1263,10 @@ EOF *:QNX:*:4*) echo i386-pc-qnx exit ;; - NSE-?:NONSTOP_KERNEL:*:*) + NEO-?:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + exit ;; + NSE-*:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) @@ -1268,13 +1311,13 @@ EOF echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) - echo mips-sei-seiux${UNAME_RELEASE} + echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) - UNAME_MACHINE=`(uname -p) 2>/dev/null` + UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; @@ -1292,11 +1335,11 @@ EOF i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; + x86_64:VMkernel:*:*) + echo ${UNAME_MACHINE}-unknown-esx + exit ;; esac -#echo '(No uname command or uname output not recognized.)' 1>&2 -#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 - eval $set_cc_for_build cat >$dummy.c < printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 - "4" + "4" #else - "" + "" #endif - ); exit (0); + ); exit (0); #endif #endif diff --git a/config.sub b/config.sub index 8ca084bf..8df55110 100755 --- a/config.sub +++ b/config.sub @@ -1,10 +1,10 @@ #! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, -# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 -# Free Software Foundation, Inc. +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +# 2011, 2012 Free Software Foundation, Inc. -timestamp='2009-08-19' +timestamp='2012-12-06' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software @@ -21,9 +21,7 @@ timestamp='2009-08-19' # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA -# 02110-1301, USA. +# along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a @@ -75,8 +73,9 @@ Report bugs and patches to ." version="\ GNU config.sub ($timestamp) -Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, -2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 +Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -123,13 +122,18 @@ esac # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in - nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ - uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; + android-linux) + os=-linux-android + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown + ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] @@ -152,12 +156,12 @@ case $os in -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ - -apple | -axis | -knuth | -cray | -microblaze) + -apple | -axis | -knuth | -cray | -microblaze*) os= basic_machine=$1 ;; - -bluegene*) - os=-cnk + -bluegene*) + os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= @@ -173,10 +177,10 @@ case $os in os=-chorusos basic_machine=$1 ;; - -chorusrdb) - os=-chorusrdb + -chorusrdb) + os=-chorusrdb basic_machine=$1 - ;; + ;; -hiux*) os=-hiuxwe2 ;; @@ -221,6 +225,12 @@ case $os in -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; + -lynx*178) + os=-lynxos178 + ;; + -lynx*5) + os=-lynxos5 + ;; -lynx*) os=-lynxos ;; @@ -245,20 +255,27 @@ case $basic_machine in # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ + | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ - | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | arc \ + | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ + | avr | avr32 \ + | be32 | be64 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ + | epiphany \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ + | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ - | maxq | mb | microblaze | mcore | mep | metag \ + | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ @@ -281,27 +298,39 @@ case $basic_machine in | moxie \ | mt \ | msp430 \ + | nds32 | nds32le | nds32be \ | nios | nios2 \ | ns16k | ns32k \ + | open8 \ | or32 \ | pdp10 | pdp11 | pj | pjl \ - | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ + | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ - | spu | strongarm \ - | tahoe | thumb | tic4x | tic80 | tron \ - | v850 | v850e \ + | spu \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | we32k \ - | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ + | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; - m6811 | m68hc11 | m6812 | m68hc12) - # Motorola 68HC11/12. + c54x) + basic_machine=tic54x-unknown + ;; + c55x) + basic_machine=tic55x-unknown + ;; + c6x) + basic_machine=tic6x-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) basic_machine=$basic_machine-unknown os=-none ;; @@ -311,6 +340,21 @@ case $basic_machine in basic_machine=mt-unknown ;; + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; + xgate) + basic_machine=$basic_machine-unknown + os=-none + ;; + xscaleeb) + basic_machine=armeb-unknown + ;; + + xscaleel) + basic_machine=armel-unknown + ;; + # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. @@ -325,25 +369,30 @@ case $basic_machine in # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ + | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ + | be32-* | be64-* \ | bfin-* | bs2000-* \ - | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ + | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ - | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ + | microblaze-* | microblazeel-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ @@ -365,24 +414,29 @@ case $basic_machine in | mmix-* \ | mt-* \ | msp430-* \ + | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* \ | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ - | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ - | romp-* | rs6000-* \ + | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ - | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ - | tahoe-* | thumb-* \ - | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ + | tahoe-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile*-* \ | tron-* \ - | v850-* | v850e-* | vax-* \ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ | we32k-* \ - | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) @@ -407,7 +461,7 @@ case $basic_machine in basic_machine=a29k-amd os=-udi ;; - abacus) + abacus) basic_machine=abacus-unknown ;; adobe68k) @@ -477,11 +531,20 @@ case $basic_machine in basic_machine=powerpc-ibm os=-cnk ;; + c54x-*) + basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c55x-*) + basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c6x-*) + basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; c90) basic_machine=c90-cray os=-unicos ;; - cegcc) + cegcc) basic_machine=arm-unknown os=-cegcc ;; @@ -513,7 +576,7 @@ case $basic_machine in basic_machine=craynv-cray os=-unicosmp ;; - cr16) + cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; @@ -671,7 +734,6 @@ case $basic_machine in i370-ibm* | ibm*) basic_machine=i370-ibm ;; -# I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 @@ -729,9 +791,13 @@ case $basic_machine in basic_machine=ns32k-utek os=-sysv ;; - microblaze) + microblaze*) basic_machine=microblaze-xilinx ;; + mingw64) + basic_machine=x86_64-pc + os=-mingw64 + ;; mingw32) basic_machine=i386-pc os=-mingw32 @@ -768,10 +834,18 @@ case $basic_machine in ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; + msys) + basic_machine=i386-pc + os=-msys + ;; mvs) basic_machine=i370-ibm os=-mvs ;; + nacl) + basic_machine=le32-unknown + os=-nacl + ;; ncr3000) basic_machine=i486-ncr os=-sysv4 @@ -836,6 +910,12 @@ case $basic_machine in np1) basic_machine=np1-gould ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; nsr-tandem) basic_machine=nsr-tandem ;; @@ -918,9 +998,10 @@ case $basic_machine in ;; power) basic_machine=power-ibm ;; - ppc) basic_machine=powerpc-unknown + ppc | ppcbe) basic_machine=powerpc-unknown ;; - ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ppc-* | ppcbe-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown @@ -945,7 +1026,11 @@ case $basic_machine in basic_machine=i586-unknown os=-pw32 ;; - rdos) + rdos | rdos64) + basic_machine=x86_64-pc + os=-rdos + ;; + rdos32) basic_machine=i386-pc os=-rdos ;; @@ -1014,6 +1099,9 @@ case $basic_machine in basic_machine=i860-stratus os=-sysv4 ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; sun2) basic_machine=m68000-sun ;; @@ -1070,20 +1158,8 @@ case $basic_machine in basic_machine=t90-cray os=-unicos ;; - tic54x | c54x*) - basic_machine=tic54x-unknown - os=-coff - ;; - tic55x | c55x*) - basic_machine=tic55x-unknown - os=-coff - ;; - tic6x | c6x*) - basic_machine=tic6x-unknown - os=-coff - ;; tile*) - basic_machine=tile-unknown + basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) @@ -1153,6 +1229,9 @@ case $basic_machine in xps | xps100) basic_machine=xps100-honeywell ;; + xscale-* | xscalee[bl]-*) + basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` + ;; ymp) basic_machine=ymp-cray os=-unicos @@ -1250,9 +1329,12 @@ esac if [ x"$os" != x"" ] then case $os in - # First match some system type aliases - # that might get confused with valid system types. + # First match some system type aliases + # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; @@ -1274,21 +1356,22 @@ case $os in # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ - | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ - | -kopensolaris* \ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ - | -openbsd* | -solidbsd* \ + | -bitrig* | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ - | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ @@ -1296,7 +1379,7 @@ case $os in | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ - | -skyos* | -haiku* | -rdos* | -toppers* | -drops*) + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) @@ -1335,7 +1418,7 @@ case $os in -opened*) os=-openedition ;; - -os400*) + -os400*) os=-os400 ;; -wince*) @@ -1384,7 +1467,7 @@ case $os in -sinix*) os=-sysv4 ;; - -tpf*) + -tpf*) os=-tpf ;; -triton*) @@ -1429,6 +1512,8 @@ case $os in -dicos*) os=-dicos ;; + -nacl*) + ;; -none) ;; *) @@ -1451,10 +1536,10 @@ else # system, and we'll never get to this point. case $basic_machine in - score-*) + score-*) os=-elf ;; - spu-*) + spu-*) os=-elf ;; *-acorn) @@ -1466,8 +1551,20 @@ case $basic_machine in arm*-semi) os=-aout ;; - c4x-* | tic4x-*) - os=-coff + c4x-* | tic4x-*) + os=-coff + ;; + hexagon-*) + os=-elf + ;; + tic54x-*) + os=-coff + ;; + tic55x-*) + os=-coff + ;; + tic6x-*) + os=-coff ;; # This must come before the *-dec entry. pdp10-*) @@ -1487,14 +1584,11 @@ case $basic_machine in ;; m68000-sun) os=-sunos3 - # This also exists in the configure program, but was not the - # default. - # os=-sunos4 ;; m68*-cisco) os=-aout ;; - mep-*) + mep-*) os=-elf ;; mips*-cisco) @@ -1521,7 +1615,7 @@ case $basic_machine in *-ibm) os=-aix ;; - *-knuth) + *-knuth) os=-mmixware ;; *-wec) diff --git a/configure b/configure old mode 100755 new mode 100644 index 01feaf7c..622c6680 --- a/configure +++ b/configure @@ -18,6 +18,7 @@ Standard options: --extra-asflags=EASFLAGS add EASFLAGS to ASFLAGS --extra-cflags=ECFLAGS add ECFLAGS to CFLAGS --extra-ldflags=ELDFLAGS add ELDFLAGS to LDFLAGS + --extra-rcflags=ERCFLAGS add ERCFLAGS to RCFLAGS Configuration options: --disable-cli disable cli @@ -45,7 +46,7 @@ Cross-compilation: --sysroot=SYSROOT root of cross-build tree External library support: - --disable-avs disable avisynth support (windows only) + --disable-avs disable avisynth support --disable-swscale disable swscale support --disable-lavf disable libavformat support --disable-ffms disable ffmpegsource support @@ -204,9 +205,9 @@ rc_check() { log_check "whether $RC works" echo "$1" > conftest.rc if [ $compiler = ICL ]; then - rc_cmd="$RC -foconftest.o conftest.rc" + rc_cmd="$RC $RCFLAGS -foconftest.o conftest.rc" else - rc_cmd="$RC -o conftest.o conftest.rc" + rc_cmd="$RC $RCFLAGS -o conftest.o conftest.rc" fi if $rc_cmd >conftest.log 2>&1; then res=$? @@ -277,6 +278,7 @@ CFLAGS="$CFLAGS -Wall -I. -I\$(SRCPATH)" LDFLAGS="$LDFLAGS" LDFLAGSCLI="$LDFLAGSCLI" ASFLAGS="$ASFLAGS" +RCFLAGS="$RCFLAGS" HAVE_GETOPT_LONG=1 cross_prefix="" @@ -347,6 +349,9 @@ for opt do --extra-ldflags=*) LDFLAGS="$LDFLAGS $optarg" ;; + --extra-rcflags=*) + RCFLAGS="$RCFLAGS $optarg" + ;; --disable-thread) thread="no" ;; @@ -443,6 +448,7 @@ else fi fi +libm="" case $host_os in beos*) SYS="BEOS" @@ -451,37 +457,37 @@ case $host_os in darwin*) SYS="MACOSX" CFLAGS="$CFLAGS -falign-loops=16" - LDFLAGS="$LDFLAGS -lm" + libm="-lm" if [ "$pic" = "no" ]; then cc_check "" -mdynamic-no-pic && CFLAGS="$CFLAGS -mdynamic-no-pic" fi ;; freebsd*) SYS="FREEBSD" - LDFLAGS="$LDFLAGS -lm" + libm="-lm" ;; kfreebsd*-gnu) SYS="FREEBSD" define HAVE_MALLOC_H - LDFLAGS="$LDFLAGS -lm" + libm="-lm" ;; netbsd*) SYS="NETBSD" - LDFLAGS="$LDFLAGS -lm" + libm="-lm" ;; openbsd*) SYS="OPENBSD" - LDFLAGS="$LDFLAGS -lm" + libm="-lm" ;; *linux*) SYS="LINUX" define HAVE_MALLOC_H - LDFLAGS="$LDFLAGS -lm -lrt" + LDFLAGS="$LDFLAGS -lrt" ;; gnu*) SYS="HURD" define HAVE_MALLOC_H - LDFLAGS="$LDFLAGS -lm" + libm="-lm" ;; cygwin*) EXE=".exe" @@ -495,17 +501,19 @@ case $host_os in else SYS="WINDOWS" DEVNULL="NUL" + RC="${RC-${cross_prefix}windres}" fi ;; mingw*) SYS="WINDOWS" EXE=".exe" DEVNULL="NUL" + [ $compiler = ICL ] && RC="${RC-rc}" || RC="${RC-${cross_prefix}windres}" ;; sunos*|solaris*) SYS="SunOS" define HAVE_MALLOC_H - LDFLAGS="$LDFLAGS -lm" + libm="-lm" if cc_check "" /usr/lib/64/values-xpg6.o; then LDFLAGS="$LDFLAGS /usr/lib/64/values-xpg6.o" else @@ -513,11 +521,21 @@ case $host_os in fi HAVE_GETOPT_LONG=0 ;; + *qnx*) + SYS="QNX" + define HAVE_MALLOC_H + libm="-lm" + HAVE_GETOPT_LONG=0 + CFLAGS="$CFLAGS -I\$(SRCPATH)/extras" + ;; *) die "Unknown system $host, edit the configure" ;; esac +LDFLAGS="$LDFLAGS $libm" + +aligned_stack=1 case $host_cpu in i*86) ARCH="X86" @@ -530,12 +548,15 @@ case $host_cpu in if [[ "$asm" == auto && "$CFLAGS" != *-mfpmath* ]]; then CFLAGS="$CFLAGS -mfpmath=sse -msse" fi + CFLAGS="-m32 $CFLAGS" + LDFLAGS="-m32 $LDFLAGS" else # icc on linux has various degrees of mod16 stack support if [ $SYS = LINUX ]; then # < 11 is completely incapable of keeping a mod16 stack if cpp_check "" "" "__INTEL_COMPILER < 1100" ; then define BROKEN_STACK_ALIGNMENT + aligned_stack=0 # 11 <= x < 12 is capable of keeping a mod16 stack, but defaults to not doing so. elif cpp_check "" "" "__INTEL_COMPILER < 1200" ; then CFLAGS="$CFLAGS -falign-stack=assume-16-byte" @@ -543,13 +564,15 @@ case $host_cpu in # >= 12 defaults to a mod16 stack fi # icl on windows has no mod16 stack support - [ $SYS = WINDOWS ] && define BROKEN_STACK_ALIGNMENT + [ $SYS = WINDOWS ] && define BROKEN_STACK_ALIGNMENT && aligned_stack=0 fi if [ "$SYS" = MACOSX ]; then ASFLAGS="$ASFLAGS -f macho -DPREFIX" elif [ "$SYS" = WINDOWS -o "$SYS" = CYGWIN ]; then ASFLAGS="$ASFLAGS -f win32 -DPREFIX" LDFLAGS="$LDFLAGS -Wl,--large-address-aware" + [ $compiler = GNU ] && LDFLAGS="$LDFLAGS -Wl,--nxcompat -Wl,--dynamicbase" + [ $compiler = GNU ] && RCFLAGS="--target=pe-i386 $RCFLAGS" else ASFLAGS="$ASFLAGS -f elf" fi @@ -557,6 +580,7 @@ case $host_cpu in x86_64) ARCH="X86_64" AS="yasm" + [ $compiler = GNU ] && CFLAGS="-m64 $CFLAGS" && LDFLAGS="-m64 $LDFLAGS" if [ "$SYS" = MACOSX ]; then ASFLAGS="$ASFLAGS -f macho64 -m amd64 -DPIC -DPREFIX" if cc_check '' "-arch x86_64"; then @@ -567,6 +591,8 @@ case $host_cpu in ASFLAGS="$ASFLAGS -f win32 -m amd64" # only the GNU toolchain is inconsistent in prefixing function names with _ [ $compiler = GNU ] && cc_check "" "-S" && grep -q "_main:" conftest && ASFLAGS="$ASFLAGS -DPREFIX" + [ $compiler = GNU ] && LDFLAGS="$LDFLAGS -Wl,--nxcompat -Wl,--dynamicbase" + [ $compiler = GNU ] && RCFLAGS="--target=pe-x86-64 $RCFLAGS" else ASFLAGS="$ASFLAGS -f elf -m amd64" fi @@ -633,10 +659,9 @@ case $host_cpu in ARCH="$(echo $host_cpu | tr a-z A-Z)" ;; esac +ASFLAGS="$ASFLAGS -DHAVE_ALIGNED_STACK=${aligned_stack}" -RC="" if [ $SYS = WINDOWS ]; then - [ $compiler = ICL ] && RC="rc" || RC="${cross_prefix}windres" if ! rc_check "0 RCDATA {0}" ; then RC="" fi @@ -671,10 +696,10 @@ if [ $shared = yes -a \( $ARCH = "X86_64" -o $ARCH = "PPC" -o $ARCH = "ALPHA" -o fi if [ $asm = auto -a \( $ARCH = X86 -o $ARCH = X86_64 \) ] ; then - if ! as_check "vpperm xmm0, xmm0, xmm0, xmm0" ; then + if ! as_check "vpmovzxwd ymm0, xmm0" ; then VER=`($AS --version || echo no assembler) 2>/dev/null | head -n 1` echo "Found $VER" - echo "Minimum version is yasm-1.0.0" + echo "Minimum version is yasm-1.2.0" echo "If you really want to compile without asm, configure with --disable-asm." exit 1 fi @@ -754,8 +779,8 @@ if [ "$thread" = "auto" ]; then thread="win32" fi ;; - OPENBSD) - cc_check pthread.h -pthread && thread="posix" && libpthread="-pthread" + QNX) + cc_check pthread.h -lc && thread="posix" && libpthread="-lc" ;; *) cc_check pthread.h -lpthread && thread="posix" && libpthread="-lpthread" @@ -825,7 +850,7 @@ if [ "$lavf" = "auto" ] ; then done fi LAVF_LIBS="-L. $LAVF_LIBS" - if cc_check libavformat/avformat.h "$LAVF_CFLAGS $LAVF_LIBS" "avformat_find_stream_info(0,0); avcodec_open2(0,0,0);" ; then + if cc_check libavformat/avformat.h "$LAVF_CFLAGS $LAVF_LIBS" "avformat_close_input(0);" ; then if [ "$swscale" = "yes" ]; then lavf="yes" else @@ -894,7 +919,7 @@ if [ "$gpac" = "auto" ] ; then fi if [ "$gpac" = "yes" ] ; then define HAVE_GPAC - if cc_check gpac/isomedia.h "-Werror $GPAC_LIBS" "gf_malloc(1); gf_free(NULL);" ; then + if cc_check gpac/isomedia.h "-Werror $GPAC_LIBS" "void *p; p = gf_malloc(1); gf_free(p);" ; then define HAVE_GF_MALLOC fi LDFLAGSCLI="$GPAC_LIBS $LDFLAGSCLI" @@ -905,7 +930,17 @@ if [ "$avs" = "auto" ] ; then # cygwin can use avisynth if it can use LoadLibrary if [ $SYS = WINDOWS ] || ([ $SYS = CYGWIN ] && cc_check windows.h "" "LoadLibrary(0);") ; then avs="yes" + avstype="avisynth" + define HAVE_AVS + define USE_AVXSYNTH 0 + elif [ "$SYS" = "LINUX" -o "$SYS" = "MACOSX" ] ; then + # AvxSynth currently only supports Linux and OSX + avs="yes" + avstype="avxsynth" define HAVE_AVS + define USE_AVXSYNTH 1 + AVS_LIBS="-ldl" + LDFLAGSCLI="$AVS_LIBS $LDFLAGSCLI" fi fi @@ -994,7 +1029,7 @@ if [ $compiler = ICL ]; then LDFLAGSCLI="$(icl_ldflags $LDFLAGSCLI)" LIBX264=libx264.lib RANLIB= - [ -n "$RC" ] && RC="$RC -I. -I\$(SRCPATH)/extras -fo" + [ -n "$RC" ] && RCFLAGS="$RCFLAGS -I. -I\$(SRCPATH)/extras -fo" STRIP= if [ $debug = yes ]; then LDFLAGS="-debug $LDFLAGS" @@ -1008,7 +1043,7 @@ else DEPMT="-MT" LD="$CC -o " LIBX264=libx264.a - [ -n "$RC" ] && RC="$RC -I. -o " + [ -n "$RC" ] && RCFLAGS="$RCFLAGS -I. -o " fi if [ $compiler = GNU ]; then PROF_GEN_CC="-fprofile-generate" @@ -1062,6 +1097,7 @@ STRIP=$STRIP AS=$AS ASFLAGS=$ASFLAGS RC=$RC +RCFLAGS=$RCFLAGS EXE=$EXE HAVE_GETOPT_LONG=$HAVE_GETOPT_LONG DEVNULL=$DEVNULL @@ -1073,7 +1109,7 @@ EOF if [ $compiler = ICL ]; then echo '%.o: %.c' >> config.mak - echo ' $(CC) $(CFLAGS) -c -Fo$@ $<' >> config.mak + echo ' $(CC) $(CFLAGS) -c -Fo$@ $<' >> config.mak fi if [ "$cli" = "yes" ]; then @@ -1091,7 +1127,10 @@ if [ "$shared" = "yes" ]; then # MSVC link does not act similarly, so it is required to make an export definition out of x264.h and use it at link time echo "SOFLAGS=-dll -def:x264.def -implib:\$(IMPLIBNAME) $SOFLAGS" >> config.mak echo "EXPORTS" > x264.def - grep "^\(int\|void\|x264_t\|extern\).*x264.*[\[(;]" ${SRCPATH}/x264.h | sed -e "s/.*\(x264.*\)[\[(].*/\1/;s/.*\(x264.*\);/\1/;s/open/open_$API/g" >> x264.def + # export API functions + grep "^\(int\|void\|x264_t\).*x264" ${SRCPATH}/x264.h | sed -e "s/.*\(x264.*\)(.*/\1/;s/open/open_$API/g" >> x264.def + # export API variables/data. must be flagged with the DATA keyword + grep "extern.*x264" ${SRCPATH}/x264.h | sed -e "s/.*\(x264\w*\)\W.*/\1 DATA/;" >> x264.def else echo 'IMPLIBNAME=libx264.dll.a' >> config.mak echo "SOFLAGS=-shared -Wl,--out-implib,\$(IMPLIBNAME) -Wl,--enable-auto-image-base $SOFLAGS" >> config.mak @@ -1135,8 +1174,6 @@ echo "CLI_LIBX264 = $CLI_LIBX264" >> config.mak ${SRCPATH}/version.sh "${SRCPATH}" >> x264_config.h -pclibs="-L$libdir -lx264 $libpthread" - cat > x264.pc << EOF prefix=$prefix exec_prefix=$exec_prefix @@ -1146,7 +1183,8 @@ includedir=$includedir Name: x264 Description: H.264 (MPEG4 AVC) encoder library Version: $(grep POINTVER < x264_config.h | sed -e 's/.* "//; s/".*//') -Libs: $pclibs +Libs: -L$libdir -lx264 +Libs.private: $libpthread $libm Cflags: -I$includedir EOF @@ -1164,7 +1202,7 @@ shared: $shared static: $static asm: $asm interlaced: $interlaced -avs: $avs +avs: $avstype lavf: $lavf ffms: $ffms gpac: $gpac diff --git a/doc/regression_test.txt b/doc/regression_test.txt index 5563238f..3e38a9ea 100644 --- a/doc/regression_test.txt +++ b/doc/regression_test.txt @@ -4,7 +4,7 @@ This ensures that there is no distortion besides what is inherently caused by compression. # Install and compile x264 : -svn co svn://svn.videolan.org/x264/trunk x264 +git clone git://git.videolan.org/x264.git x264 cd x264 ./configure make diff --git a/encoder/analyse.c b/encoder/analyse.c index f653d661..3f1f48a6 100644 --- a/encoder/analyse.c +++ b/encoder/analyse.c @@ -1,7 +1,7 @@ /***************************************************************************** * analyse.c: macroblock analysis ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Laurent Aimar * Loren Merritt @@ -467,8 +467,8 @@ static void x264_mb_analyse_init( x264_t *h, x264_mb_analysis_t *a, int qp ) if( max_mv > 0 && h->mb.i_mb_x < h->fdec->i_pir_start_col ) h->mb.mv_max_spel[0] = X264_MIN( h->mb.mv_max_spel[0], max_mv ); } - h->mb.mv_min_fpel[0] = (h->mb.mv_min_spel[0]>>2) + i_fpel_border; - h->mb.mv_max_fpel[0] = (h->mb.mv_max_spel[0]>>2) - i_fpel_border; + h->mb.mv_limit_fpel[0][0] = (h->mb.mv_min_spel[0]>>2) + i_fpel_border; + h->mb.mv_limit_fpel[1][0] = (h->mb.mv_max_spel[0]>>2) - i_fpel_border; if( h->mb.i_mb_x == 0 && !(h->mb.i_mb_y & PARAM_INTERLACED) ) { int mb_y = h->mb.i_mb_y >> SLICE_MBAFF; @@ -516,8 +516,8 @@ static void x264_mb_analyse_init( x264_t *h, x264_mb_analysis_t *a, int qp ) h->mb.mv_min_spel[1] = x264_clip3( h->mb.mv_min[1], -i_fmv_range, i_fmv_range ); h->mb.mv_max_spel[1] = CLIP_FMV( h->mb.mv_max[1] ); h->mb.mv_max_spel[1] = X264_MIN( h->mb.mv_max_spel[1], thread_mvy_range*4 ); - h->mb.mv_min_fpel[1] = (h->mb.mv_min_spel[1]>>2) + i_fpel_border; - h->mb.mv_max_fpel[1] = (h->mb.mv_max_spel[1]>>2) - i_fpel_border; + h->mb.mv_limit_fpel[0][1] = (h->mb.mv_min_spel[1]>>2) + i_fpel_border; + h->mb.mv_limit_fpel[1][1] = (h->mb.mv_max_spel[1]>>2) - i_fpel_border; } } if( PARAM_INTERLACED ) @@ -527,8 +527,8 @@ static void x264_mb_analyse_init( x264_t *h, x264_mb_analysis_t *a, int qp ) h->mb.mv_max[1] = h->mb.mv_maxy_row[i]; h->mb.mv_min_spel[1] = h->mb.mv_miny_spel_row[i]; h->mb.mv_max_spel[1] = h->mb.mv_maxy_spel_row[i]; - h->mb.mv_min_fpel[1] = h->mb.mv_miny_fpel_row[i]; - h->mb.mv_max_fpel[1] = h->mb.mv_maxy_fpel_row[i]; + h->mb.mv_limit_fpel[0][1] = h->mb.mv_miny_fpel_row[i]; + h->mb.mv_limit_fpel[1][1] = h->mb.mv_maxy_fpel_row[i]; } #undef CLIP_FMV @@ -2836,12 +2836,28 @@ static inline void x264_mb_analyse_transform( x264_t *h ) int plane_count = CHROMA444 && h->mb.b_chroma_me ? 3 : 1; int i_cost8 = 0, i_cost4 = 0; - for( int p = 0; p < plane_count; p++ ) + /* Not all platforms have a merged SATD function */ + if( h->pixf.sa8d_satd[PIXEL_16x16] ) { - i_cost8 += h->pixf.sa8d[PIXEL_16x16]( h->mb.pic.p_fenc[p], FENC_STRIDE, - h->mb.pic.p_fdec[p], FDEC_STRIDE ); - i_cost4 += h->pixf.satd[PIXEL_16x16]( h->mb.pic.p_fenc[p], FENC_STRIDE, - h->mb.pic.p_fdec[p], FDEC_STRIDE ); + uint64_t cost = 0; + for( int p = 0; p < plane_count; p++ ) + { + cost += h->pixf.sa8d_satd[PIXEL_16x16]( h->mb.pic.p_fenc[p], FENC_STRIDE, + h->mb.pic.p_fdec[p], FDEC_STRIDE ); + + } + i_cost8 = (uint32_t)cost; + i_cost4 = (uint32_t)(cost >> 32); + } + else + { + for( int p = 0; p < plane_count; p++ ) + { + i_cost8 += h->pixf.sa8d[PIXEL_16x16]( h->mb.pic.p_fenc[p], FENC_STRIDE, + h->mb.pic.p_fdec[p], FDEC_STRIDE ); + i_cost4 += h->pixf.satd[PIXEL_16x16]( h->mb.pic.p_fenc[p], FENC_STRIDE, + h->mb.pic.p_fdec[p], FDEC_STRIDE ); + } } h->mb.b_transform_8x8 = i_cost8 < i_cost4; @@ -2851,8 +2867,15 @@ static inline void x264_mb_analyse_transform( x264_t *h ) static inline void x264_mb_analyse_transform_rd( x264_t *h, x264_mb_analysis_t *a, int *i_satd, int *i_rd ) { - if( x264_mb_transform_8x8_allowed( h ) && h->param.analyse.b_transform_8x8 ) + if( h->param.analyse.b_transform_8x8 && h->pps->b_transform_8x8_mode ) { + uint32_t subpart_bak = M32( h->mb.i_sub_partition ); + /* Try switching the subpartitions to 8x8 so that we can use 8x8 transform mode */ + if( h->mb.i_type == P_8x8 ) + M32( h->mb.i_sub_partition ) = D_L0_8x8*0x01010101; + else if( !x264_transform_allowed[h->mb.i_type] ) + return; + x264_analyse_update_cache( h, a ); h->mb.b_transform_8x8 ^= 1; /* FIXME only luma is needed for 4:2:0, but the score for comparison already includes chroma */ @@ -2865,7 +2888,10 @@ static inline void x264_mb_analyse_transform_rd( x264_t *h, x264_mb_analysis_t * *i_rd = i_rd8; } else + { h->mb.b_transform_8x8 ^= 1; + M32( h->mb.i_sub_partition ) = subpart_bak; + } } } @@ -2912,7 +2938,7 @@ static inline void x264_mb_analyse_qp_rd( x264_t *h, x264_mb_analysis_t *a ) { if( !origcbp ) { - h->mb.i_qp = X264_MAX( h->mb.i_qp - threshold - 1, h->param.rc.i_qp_min ); + h->mb.i_qp = X264_MAX( h->mb.i_qp - threshold - 1, SPEC_QP( h->param.rc.i_qp_min ) ); h->mb.i_chroma_qp = h->chroma_qp_table[h->mb.i_qp]; already_checked_cost = x264_rd_cost_mb( h, a->i_lambda2 ); if( !h->mb.cbp[h->mb.i_mb_xy] ) @@ -2992,9 +3018,11 @@ void x264_macroblock_analyse( x264_t *h ) h->mb.i_qp = x264_ratecontrol_mb_qp( h ); /* If the QP of this MB is within 1 of the previous MB, code the same QP as the previous MB, * to lower the bit cost of the qp_delta. Don't do this if QPRD is enabled. */ - if( h->param.rc.i_aq_mode && h->param.analyse.i_subpel_refine < 10 && abs(h->mb.i_qp - h->mb.i_last_qp) == 1 ) - h->mb.i_qp = h->mb.i_last_qp; + if( h->param.rc.i_aq_mode && h->param.analyse.i_subpel_refine < 10 ) + h->mb.i_qp = abs(h->mb.i_qp - h->mb.i_last_qp) == 1 ? h->mb.i_last_qp : h->mb.i_qp; + if( h->param.analyse.b_mb_info ) + h->fdec->effective_qp[h->mb.i_mb_xy] = h->mb.i_qp; /* Store the real analysis QP. */ x264_mb_analyse_init( h, &analysis, h->mb.i_qp ); /*--------------------------- Do the analysis ---------------------------*/ @@ -3034,6 +3062,33 @@ void x264_macroblock_analyse( x264_t *h ) } else { + /* Special fast-skip logic using information from mb_info. */ + if( h->fdec->mb_info && (h->fdec->mb_info[h->mb.i_mb_xy]&X264_MBINFO_CONSTANT) ) + { + if( !SLICE_MBAFF && (h->fdec->i_frame - h->fref[0][0]->i_frame) == 1 && !h->sh.b_weighted_pred && + h->fref[0][0]->effective_qp[h->mb.i_mb_xy] <= h->mb.i_qp ) + { + h->mb.i_partition = D_16x16; + /* Use the P-SKIP MV if we can... */ + if( !M32(h->mb.cache.pskip_mv) ) + { + b_skip = 1; + h->mb.i_type = P_SKIP; + } + /* Otherwise, just force a 16x16 block. */ + else + { + h->mb.i_type = P_L0; + analysis.l0.me16x16.i_ref = 0; + M32( analysis.l0.me16x16.mv ) = 0; + } + goto skip_analysis; + } + /* Reset the information accordingly */ + else if( h->param.analyse.b_mb_info_update ) + h->fdec->mb_info[h->mb.i_mb_xy] &= ~X264_MBINFO_CONSTANT; + } + int skip_invalid = h->i_thread_frames > 1 && h->mb.cache.pskip_mv[1] > h->mb.mv_max_spel[1]; /* If the current macroblock is off the frame, just skip it. */ if( HAVE_INTERLACED && !MB_INTERLACED && h->mb.i_mb_y * 16 >= h->param.i_height && !skip_invalid ) @@ -3061,6 +3116,7 @@ void x264_macroblock_analyse( x264_t *h ) h->mb.i_type = P_SKIP; h->mb.i_partition = D_16x16; assert( h->mb.cache.pskip_mv[1] <= h->mb.mv_max_spel[1] || h->i_thread_frames == 1 ); +skip_analysis: /* Set up MVs for future predictors */ for( int i = 0; i < h->mb.pic.i_fref[0]; i++ ) M32( h->mb.mvr[0][i][h->mb.i_mb_xy] ) = 0; diff --git a/encoder/analyse.h b/encoder/analyse.h index c5919c4c..cbbb0dfa 100644 --- a/encoder/analyse.h +++ b/encoder/analyse.h @@ -1,7 +1,7 @@ /***************************************************************************** * analyse.h: macroblock analysis ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Laurent Aimar * Loren Merritt @@ -34,7 +34,7 @@ void x264_analyse_weight_frame( x264_t *h, int end ); void x264_macroblock_analyse( x264_t *h ); void x264_slicetype_decide( x264_t *h ); -void x264_slicetype_analyse( x264_t *h, int keyframe ); +void x264_slicetype_analyse( x264_t *h, int intra_minigop ); int x264_weighted_reference_duplicate( x264_t *h, int i_ref, const x264_weight_t *w ); diff --git a/encoder/cabac.c b/encoder/cabac.c index f009da42..5fcc4ffa 100644 --- a/encoder/cabac.c +++ b/encoder/cabac.c @@ -1,7 +1,7 @@ /***************************************************************************** * cabac.c: cabac bitstream writing ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Laurent Aimar * Loren Merritt @@ -659,11 +659,12 @@ static const uint16_t coeff_abs_level_m1_offset[14] = 227+0, 227+10, 227+20, 227+30, 227+39, 426, 952+0, 952+10, 952+20, 708, 982+0, 982+10, 982+20, 766 }; #if RDO_SKIP_BS -extern const uint8_t x264_significant_coeff_flag_offset_8x8[2][63]; +extern const uint8_t x264_significant_coeff_flag_offset_8x8[2][64]; extern const uint8_t x264_last_coeff_flag_offset_8x8[63]; extern const uint8_t x264_coeff_flag_offset_chroma_422_dc[7]; #else -const uint8_t x264_significant_coeff_flag_offset_8x8[2][63] = +/* Padded to [64] for easier addressing */ +const uint8_t x264_significant_coeff_flag_offset_8x8[2][64] = {{ 0, 1, 2, 3, 4, 5, 5, 4, 4, 3, 3, 4, 4, 4, 5, 5, 4, 4, 4, 4, 3, 3, 6, 7, 7, 7, 8, 9,10, 9, 8, 7, @@ -1051,25 +1052,23 @@ if( (h->mb.i_neighbour & MB_TOP) && !h->mb.mb_transform_size[h->mb.i_mb_top_xy] MUNGE_8x8_NNZ( BACKUP ) for( int p = 0; p < 3; p++ ) - for( int i = 0; i < 4; i++ ) - if( h->mb.i_cbp_luma & ( 1 << i ) ) - x264_cabac_block_residual_8x8_cbf( h, cb, ctx_cat_plane[DCT_LUMA_8x8][p], i*4+p*16, h->dct.luma8x8[i+p*4], b_intra ); + FOREACH_BIT( i, 0, h->mb.i_cbp_luma ) + x264_cabac_block_residual_8x8_cbf( h, cb, ctx_cat_plane[DCT_LUMA_8x8][p], i*4+p*16, h->dct.luma8x8[i+p*4], b_intra ); MUNGE_8x8_NNZ( RESTORE ) } else { - for( int i = 0; i < 4; i++ ) - if( h->mb.i_cbp_luma & ( 1 << i ) ) - x264_cabac_block_residual_8x8( h, cb, DCT_LUMA_8x8, h->dct.luma8x8[i] ); + FOREACH_BIT( i, 0, h->mb.i_cbp_luma ) + x264_cabac_block_residual_8x8( h, cb, DCT_LUMA_8x8, h->dct.luma8x8[i] ); } } else { for( int p = 0; p < plane_count; p++ ) - for( int i = 0; i < 16; i++ ) - if( h->mb.i_cbp_luma & ( 1 << ( i >> 2 ) ) ) - x264_cabac_block_residual_cbf( h, cb, ctx_cat_plane[DCT_LUMA_4x4][p], i+p*16, h->dct.luma4x4[i+p*16], b_intra ); + FOREACH_BIT( i8x8, 0, h->mb.i_cbp_luma ) + for( int i = 0; i < 4; i++ ) + x264_cabac_block_residual_cbf( h, cb, ctx_cat_plane[DCT_LUMA_4x4][p], i+i8x8*4+p*16, h->dct.luma4x4[i+i8x8*4+p*16], b_intra ); } if( chroma && h->mb.i_cbp_chroma ) /* Chroma DC residual present */ diff --git a/encoder/cavlc.c b/encoder/cavlc.c index c7342790..e0434f30 100644 --- a/encoder/cavlc.c +++ b/encoder/cavlc.c @@ -1,7 +1,7 @@ /***************************************************************************** * cavlc.c: cavlc bitstream writing ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Laurent Aimar * Loren Merritt @@ -268,20 +268,33 @@ static inline void x264_cavlc_8x8_mvd( x264_t *h, int i ) } } -static inline void x264_cavlc_macroblock_luma_residual( x264_t *h, int i8start, int i8end ) +static ALWAYS_INLINE void x264_cavlc_macroblock_luma_residual( x264_t *h, int plane_count ) { if( h->mb.b_transform_8x8 ) { /* shuffle 8x8 dct coeffs into 4x4 lists */ - for( int i8 = i8start; i8 <= i8end; i8++ ) - if( h->mb.cache.non_zero_count[x264_scan8[i8*4]] ) - h->zigzagf.interleave_8x8_cavlc( h->dct.luma4x4[i8*4], h->dct.luma8x8[i8], &h->mb.cache.non_zero_count[x264_scan8[i8*4]] ); + for( int p = 0; p < plane_count; p++ ) + for( int i8 = 0; i8 < 4; i8++ ) + if( h->mb.cache.non_zero_count[x264_scan8[p*16+i8*4]] ) + h->zigzagf.interleave_8x8_cavlc( h->dct.luma4x4[p*16+i8*4], h->dct.luma8x8[p*4+i8], + &h->mb.cache.non_zero_count[x264_scan8[p*16+i8*4]] ); } - for( int i8 = i8start; i8 <= i8end; i8++ ) - if( h->mb.i_cbp_luma & (1 << (i8&3)) ) + for( int p = 0; p < plane_count; p++ ) + FOREACH_BIT( i8, 0, h->mb.i_cbp_luma ) for( int i4 = 0; i4 < 4; i4++ ) - x264_cavlc_block_residual( h, DCT_LUMA_4x4, i4+i8*4, h->dct.luma4x4[i4+i8*4] ); + x264_cavlc_block_residual( h, DCT_LUMA_4x4, i4+i8*4+p*16, h->dct.luma4x4[i4+i8*4+p*16] ); +} + +static ALWAYS_INLINE void x264_cavlc_partition_luma_residual( x264_t *h, int i8, int p ) +{ + if( h->mb.b_transform_8x8 && h->mb.cache.non_zero_count[x264_scan8[i8*4]] ) + h->zigzagf.interleave_8x8_cavlc( h->dct.luma4x4[i8*4+p*16], h->dct.luma8x8[i8+p*4], + &h->mb.cache.non_zero_count[x264_scan8[i8*4+p*16]] ); + + if( h->mb.i_cbp_luma & (1 << i8) ) + for( int i4 = 0; i4 < 4; i4++ ) + x264_cavlc_block_residual( h, DCT_LUMA_4x4, i4+i8*4+p*16, h->dct.luma4x4[i4+i8*4+p*16] ); } static void x264_cavlc_mb_header_i( x264_t *h, int i_mb_type, int i_mb_i_offset, int chroma ) @@ -552,7 +565,7 @@ void x264_macroblock_write_cavlc( x264_t *h ) else if( h->mb.i_cbp_luma | h->mb.i_cbp_chroma ) { x264_cavlc_qp_delta( h ); - x264_cavlc_macroblock_luma_residual( h, 0, plane_count*4-1 ); + x264_cavlc_macroblock_luma_residual( h, plane_count ); } if( h->mb.i_cbp_chroma ) { @@ -612,7 +625,7 @@ static int x264_partition_size_cavlc( x264_t *h, int i8, int i_pixel ) for( j = (i_pixel < PIXEL_8x8); j >= 0; j-- ) { for( int p = 0; p < plane_count; p++ ) - x264_cavlc_macroblock_luma_residual( h, p*4+i8, p*4+i8 ); + x264_cavlc_partition_luma_residual( h, i8, p ); if( h->mb.i_cbp_chroma ) { if( CHROMA_FORMAT == CHROMA_422 ) @@ -665,7 +678,7 @@ static int x264_partition_i8x8_size_cavlc( x264_t *h, int i8, int i_mode ) h->out.bs.i_bits_encoded = x264_cavlc_intra4x4_pred_size( h, 4*i8, i_mode ); bs_write_ue( &h->out.bs, cbp_to_golomb[!CHROMA444][1][(h->mb.i_cbp_chroma << 4)|h->mb.i_cbp_luma] ); for( int p = 0; p < plane_count; p++ ) - x264_cavlc_macroblock_luma_residual( h, p*4+i8, p*4+i8 ); + x264_cavlc_partition_luma_residual( h, i8, p ); return h->out.bs.i_bits_encoded; } diff --git a/encoder/encoder.c b/encoder/encoder.c index 8b4a03a8..8ce9b0d3 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -1,7 +1,7 @@ /***************************************************************************** * encoder.c: top-level encoder functions ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Laurent Aimar * Loren Merritt @@ -280,8 +280,10 @@ static void x264_slice_header_write( bs_t *s, x264_slice_header_t *sh, int i_nal } } + sh->b_weighted_pred = 0; if( sh->pps->b_weighted_pred && sh->i_type == SLICE_TYPE_P ) { + sh->b_weighted_pred = sh->weight[0][0].weightfn || sh->weight[0][1].weightfn || sh->weight[0][2].weightfn; /* pred_weight_table() */ bs_write_ue( s, sh->weight[0][0].i_denom ); bs_write_ue( s, sh->weight[0][1].i_denom ); @@ -393,6 +395,15 @@ static void x264_encoder_thread_init( x264_t *h ) x264_cpu_mask_misalign_sse(); #endif } + +static void x264_lookahead_thread_init( x264_t *h ) +{ +#if HAVE_MMX + /* Misalign mask has to be set separately for each thread. */ + if( h->param.cpu&X264_CPU_SSE_MISALIGN ) + x264_cpu_mask_misalign_sse(); +#endif +} #endif /**************************************************************************** @@ -406,17 +417,33 @@ static void x264_encoder_thread_init( x264_t *h ) static int x264_validate_parameters( x264_t *h, int b_open ) { #if HAVE_MMX -#ifdef __SSE__ - if( b_open && !(x264_cpu_detect() & X264_CPU_SSE) ) + if( b_open ) { - x264_log( h, X264_LOG_ERROR, "your cpu does not support SSE1, but x264 was compiled with asm support\n"); + int cpuflags = x264_cpu_detect(); + int fail = 0; +#ifdef __SSE__ + if( !(cpuflags & X264_CPU_SSE) ) + { + x264_log( h, X264_LOG_ERROR, "your cpu does not support SSE1, but x264 was compiled with asm\n"); + fail = 1; + } #else - if( b_open && !(x264_cpu_detect() & X264_CPU_MMX2) ) - { - x264_log( h, X264_LOG_ERROR, "your cpu does not support MMXEXT, but x264 was compiled with asm support\n"); + if( !(cpuflags & X264_CPU_MMX2) ) + { + x264_log( h, X264_LOG_ERROR, "your cpu does not support MMXEXT, but x264 was compiled with asm\n"); + fail = 1; + } #endif - x264_log( h, X264_LOG_ERROR, "to run x264, recompile without asm support (configure --disable-asm)\n"); - return -1; + if( !fail && !(cpuflags & X264_CPU_CMOV) ) + { + x264_log( h, X264_LOG_ERROR, "your cpu does not support CMOV, but x264 was compiled with asm\n"); + fail = 1; + } + if( fail ) + { + x264_log( h, X264_LOG_ERROR, "to run x264, recompile without asm (configure --disable-asm)\n"); + return -1; + } } #endif @@ -492,6 +519,7 @@ static int x264_validate_parameters( x264_t *h, int b_open ) if( h->param.i_threads == X264_THREADS_AUTO ) h->param.i_threads = x264_cpu_num_processors() * (h->param.b_sliced_threads?2:3)/2; + int max_sliced_threads = X264_MAX( 1, (h->param.i_height+15)/16 / 4 ); if( h->param.i_threads > 1 ) { #if !HAVE_THREAD @@ -501,14 +529,14 @@ static int x264_validate_parameters( x264_t *h, int b_open ) /* Avoid absurdly small thread slices as they can reduce performance * and VBV compliance. Capped at an arbitrary 4 rows per thread. */ if( h->param.b_sliced_threads ) - { - int max_threads = (h->param.i_height+15)/16 / 4; - h->param.i_threads = X264_MIN( h->param.i_threads, max_threads ); - } + h->param.i_threads = X264_MIN( h->param.i_threads, max_sliced_threads ); } h->param.i_threads = x264_clip3( h->param.i_threads, 1, X264_THREAD_MAX ); if( h->param.i_threads == 1 ) + { h->param.b_sliced_threads = 0; + h->param.i_lookahead_threads = 1; + } h->i_thread_frames = h->param.b_sliced_threads ? 1 : h->param.i_threads; if( h->i_thread_frames > 1 ) h->param.nalu_process = NULL; @@ -562,7 +590,7 @@ static int x264_validate_parameters( x264_t *h, int b_open ) h->param.rc.i_qp_constant = h->param.rc.f_rf_constant + QP_BD_OFFSET; h->param.rc.i_bitrate = 0; } - if( (h->param.rc.i_rc_method == X264_RC_CQP || h->param.rc.i_rc_method == X264_RC_CRF) + if( b_open && (h->param.rc.i_rc_method == X264_RC_CQP || h->param.rc.i_rc_method == X264_RC_CRF) && h->param.rc.i_qp_constant == 0 ) { h->mb.b_lossless = 1; @@ -598,6 +626,11 @@ static int x264_validate_parameters( x264_t *h, int b_open ) h->param.rc.i_qp_min = x264_clip3( h->param.rc.i_qp_min, 0, h->param.rc.i_qp_max ); h->param.rc.i_qp_step = x264_clip3( h->param.rc.i_qp_step, 2, QP_MAX ); h->param.rc.i_bitrate = x264_clip3( h->param.rc.i_bitrate, 0, 2000000 ); + if( h->param.rc.i_rc_method == X264_RC_ABR && !h->param.rc.i_bitrate ) + { + x264_log( h, X264_LOG_ERROR, "bitrate not specified\n" ); + return -1; + } h->param.rc.i_vbv_buffer_size = x264_clip3( h->param.rc.i_vbv_buffer_size, 0, 2000000 ); h->param.rc.i_vbv_max_bitrate = x264_clip3( h->param.rc.i_vbv_max_bitrate, 0, 2000000 ); h->param.rc.f_vbv_buffer_init = x264_clip3f( h->param.rc.f_vbv_buffer_init, 0, 2000000 ); @@ -706,7 +739,12 @@ static int x264_validate_parameters( x264_t *h, int b_open ) x264_log( h, X264_LOG_WARNING, "intra-refresh is not compatible with open-gop\n" ); h->param.b_open_gop = 0; } - float fps = h->param.i_fps_num > 0 && h->param.i_fps_den > 0 ? (float) h->param.i_fps_num / h->param.i_fps_den : 25.0; + if( !h->param.i_fps_num || !h->param.i_fps_den ) + { + h->param.i_fps_num = 25; + h->param.i_fps_den = 1; + } + float fps = (float) h->param.i_fps_num / h->param.i_fps_den; if( h->param.i_keyint_min == X264_KEYINT_MIN_AUTO ) h->param.i_keyint_min = X264_MIN( h->param.i_keyint_max / 10, fps ); h->param.i_keyint_min = x264_clip3( h->param.i_keyint_min, 1, h->param.i_keyint_max/2+1 ); @@ -732,7 +770,7 @@ static int x264_validate_parameters( x264_t *h, int b_open ) x264_log( h, X264_LOG_WARNING, "lookaheadless mb-tree requires intra refresh or infinite keyint\n" ); h->param.rc.b_mb_tree = 0; } - if( h->param.rc.b_stat_read ) + if( b_open && h->param.rc.b_stat_read ) h->param.rc.i_lookahead = 0; #if HAVE_THREAD if( h->param.i_sync_lookahead < 0 ) @@ -870,6 +908,35 @@ static int x264_validate_parameters( x264_t *h, int b_open ) h->param.analyse.i_weighted_pred = x264_clip3( h->param.analyse.i_weighted_pred, X264_WEIGHTP_NONE, X264_WEIGHTP_SMART ); + if( h->param.i_lookahead_threads == X264_THREADS_AUTO ) + { + if( h->param.b_sliced_threads ) + h->param.i_lookahead_threads = h->param.i_threads; + else + { + /* If we're using much slower lookahead settings than encoding settings, it helps a lot to use + * more lookahead threads. This typically happens in the first pass of a two-pass encode, so + * try to guess at this sort of case. + * + * Tuned by a little bit of real encoding with the various presets. */ + int badapt = h->param.i_bframe_adaptive == X264_B_ADAPT_TRELLIS; + int subme = X264_MIN( h->param.analyse.i_subpel_refine / 3, 3 ) + (h->param.analyse.i_subpel_refine > 1); + int bframes = X264_MIN( (h->param.i_bframe - 1) / 3, 3 ); + + /* [b-adapt 0/1 vs 2][quantized subme][quantized bframes] */ + static const uint8_t lookahead_thread_div[2][5][4] = + {{{6,6,6,6}, {3,3,3,3}, {4,4,4,4}, {6,6,6,6}, {12,12,12,12}}, + {{3,2,1,1}, {2,1,1,1}, {4,3,2,1}, {6,4,3,2}, {12, 9, 6, 4}}}; + + h->param.i_lookahead_threads = h->param.i_threads / lookahead_thread_div[badapt][subme][bframes]; + /* Since too many lookahead threads significantly degrades lookahead accuracy, limit auto + * lookahead threads to about 8 macroblock rows high each at worst. This number is chosen + * pretty much arbitrarily. */ + h->param.i_lookahead_threads = X264_MIN( h->param.i_lookahead_threads, h->param.i_height / 128 ); + } + } + h->param.i_lookahead_threads = x264_clip3( h->param.i_lookahead_threads, 1, X264_MIN( max_sliced_threads, X264_LOOKAHEAD_THREAD_MAX ) ); + if( PARAM_INTERLACED ) { if( h->param.analyse.i_me_method >= X264_ME_ESA ) @@ -1221,6 +1288,9 @@ x264_t *x264_encoder_open( x264_param_t *param ) p = buf + sprintf( buf, "using cpu capabilities:" ); for( int i = 0; x264_cpu_names[i].flags; i++ ) { + if( !strcmp(x264_cpu_names[i].name, "SSE") + && h->param.cpu & (X264_CPU_SSE2) ) + continue; if( !strcmp(x264_cpu_names[i].name, "SSE2") && h->param.cpu & (X264_CPU_SSE2_IS_FAST|X264_CPU_SSE2_IS_SLOW) ) continue; @@ -1262,7 +1332,7 @@ x264_t *x264_encoder_open( x264_param_t *param ) { x264_log( h, X264_LOG_ERROR, "CLZ test failed: x264 has been miscompiled!\n" ); #if ARCH_X86 || ARCH_X86_64 - x264_log( h, X264_LOG_ERROR, "Are you attempting to run an SSE4a-targeted build on a CPU that\n" ); + x264_log( h, X264_LOG_ERROR, "Are you attempting to run an SSE4a/LZCNT-targeted build on a CPU that\n" ); x264_log( h, X264_LOG_ERROR, "doesn't support it?\n" ); #endif goto fail; @@ -1279,10 +1349,19 @@ x264_t *x264_encoder_open( x264_param_t *param ) if( h->param.i_threads > 1 && x264_threadpool_init( &h->threadpool, h->param.i_threads, (void*)x264_encoder_thread_init, h ) ) goto fail; + if( h->param.i_lookahead_threads > 1 && + x264_threadpool_init( &h->lookaheadpool, h->param.i_lookahead_threads, (void*)x264_lookahead_thread_init, h ) ) + goto fail; h->thread[0] = h; for( int i = 1; i < h->param.i_threads + !!h->param.i_sync_lookahead; i++ ) CHECKED_MALLOC( h->thread[i], sizeof(x264_t) ); + if( h->param.i_lookahead_threads > 1 ) + for( int i = 0; i < h->param.i_lookahead_threads; i++ ) + { + CHECKED_MALLOC( h->lookahead_thread[i], sizeof(x264_t) ); + *h->lookahead_thread[i] = *h; + } for( int i = 0; i < h->param.i_threads; i++ ) { @@ -1356,7 +1435,7 @@ x264_t *x264_encoder_open( x264_param_t *param ) char level[4]; snprintf( level, sizeof(level), "%d.%d", h->sps->i_level_idc/10, h->sps->i_level_idc%10 ); if( h->sps->i_level_idc == 9 || ( h->sps->i_level_idc == 11 && h->sps->b_constraint_set3 && - (h->sps->i_profile_idc >= PROFILE_BASELINE && h->sps->i_profile_idc <= PROFILE_EXTENDED) ) ) + (h->sps->i_profile_idc == PROFILE_BASELINE || h->sps->i_profile_idc == PROFILE_MAIN) ) ) strcpy( level, "1b" ); if( h->sps->i_profile_idc < PROFILE_HIGH10 ) @@ -1509,7 +1588,7 @@ static int x264_nal_end( x264_t *h ) * While undefined padding wouldn't actually affect the output, it makes valgrind unhappy. */ memset( end, 0xff, 32 ); if( h->param.nalu_process ) - h->param.nalu_process( h, nal ); + h->param.nalu_process( h, nal, h->fenc->opaque ); h->out.i_nal++; return x264_nal_check_buffer( h ); @@ -2212,14 +2291,11 @@ static int x264_slice_write( x264_t *h ) /* Slice header */ x264_macroblock_thread_init( h ); - /* If this isn't the first slice in the threadslice, set the slice QP - * equal to the last QP in the previous slice for more accurate - * CABAC initialization. */ - if( h->sh.i_first_mb != h->i_threadslice_start * h->mb.i_mb_width ) - { - h->sh.i_qp = h->mb.i_last_qp; - h->sh.i_qp_delta = h->sh.i_qp - h->pps->i_pic_init_qp; - } + /* Set the QP equal to the first QP in the slice for more accurate CABAC initialization. */ + h->mb.i_mb_xy = h->sh.i_first_mb; + h->sh.i_qp = x264_ratecontrol_mb_qp( h ); + h->sh.i_qp = SPEC_QP( h->sh.i_qp ); + h->sh.i_qp_delta = h->sh.i_qp - h->pps->i_pic_init_qp; x264_slice_header_write( &h->out.bs, &h->sh, h->i_nal_ref_idc ); if( h->param.b_cabac ) @@ -2518,6 +2594,14 @@ static int x264_slice_write( x264_t *h ) x264_fdec_filter_row( h, h->i_threadslice_start + (1 << SLICE_MBAFF), 2 ); } } + + /* Free mb info after the last thread's done using it */ + if( h->fdec->mb_info_free && (!h->param.b_sliced_threads || h->i_thread_idx == (h->param.i_threads-1)) ) + { + h->fdec->mb_info_free( h->fdec->mb_info ); + h->fdec->mb_info = NULL; + h->fdec->mb_info_free = NULL; + } } return 0; @@ -2854,7 +2938,10 @@ int x264_encoder_encode( x264_t *h, { x264_encoder_reconfig( h, h->fenc->param ); if( h->fenc->param->param_free ) + { h->fenc->param->param_free( h->fenc->param ); + h->fenc->param = NULL; + } } // ok to call this before encoding any frames, since the initial values of fdec have b_kept_as_ref=0 @@ -2939,6 +3026,11 @@ int x264_encoder_encode( x264_t *h, h->fenc->b_kept_as_ref = h->fdec->b_kept_as_ref = i_nal_ref_idc != NAL_PRIORITY_DISPOSABLE && h->param.i_keyint_max > 1; + h->fdec->mb_info = h->fenc->mb_info; + h->fdec->mb_info_free = h->fenc->mb_info_free; + h->fenc->mb_info = NULL; + h->fenc->mb_info_free = NULL; + h->fdec->i_pts = h->fenc->i_pts; if( h->frames.i_bframe_delay ) { @@ -3074,12 +3166,19 @@ int x264_encoder_encode( x264_t *h, if( x264_nal_end( h ) ) return -1; overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD - (h->param.b_annexb && h->out.i_nal-1); - if( h->fenc->extra_sei.sei_free && h->fenc->extra_sei.payloads[i].payload ) + if( h->fenc->extra_sei.sei_free ) + { h->fenc->extra_sei.sei_free( h->fenc->extra_sei.payloads[i].payload ); + h->fenc->extra_sei.payloads[i].payload = NULL; + } } - if( h->fenc->extra_sei.sei_free && h->fenc->extra_sei.payloads ) + if( h->fenc->extra_sei.sei_free ) + { h->fenc->extra_sei.sei_free( h->fenc->extra_sei.payloads ); + h->fenc->extra_sei.payloads = NULL; + h->fenc->extra_sei.sei_free = NULL; + } if( h->fenc->b_keyframe ) { @@ -3268,6 +3367,7 @@ static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current, return -1; pic_out->hrd_timing = h->fenc->hrd_timing; + pic_out->prop.f_crf_avg = h->fdec->f_crf_avg; while( filler > 0 ) { @@ -3471,6 +3571,8 @@ void x264_encoder_close ( x264_t *h ) 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++ ) @@ -3781,6 +3883,10 @@ void x264_encoder_close ( x264_t *h ) 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; diff --git a/encoder/lookahead.c b/encoder/lookahead.c index fda59ab0..ad8a3e68 100644 --- a/encoder/lookahead.c +++ b/encoder/lookahead.c @@ -1,7 +1,7 @@ /***************************************************************************** * lookahead.c: high-level lookahead functions ***************************************************************************** - * Copyright (C) 2010-2012 Avail Media and x264 project + * Copyright (C) 2010-2013 Avail Media and x264 project * * Authors: Michael Kazmier * Alex Giladi @@ -70,23 +70,24 @@ static void x264_lookahead_slicetype_decide( x264_t *h ) x264_stack_align( x264_slicetype_decide, h ); x264_lookahead_update_last_nonb( h, h->lookahead->next.list[0] ); + int shift_frames = h->lookahead->next.list[0]->i_bframes + 1; x264_pthread_mutex_lock( &h->lookahead->ofbuf.mutex ); while( h->lookahead->ofbuf.i_size == h->lookahead->ofbuf.i_max_size ) x264_pthread_cond_wait( &h->lookahead->ofbuf.cv_empty, &h->lookahead->ofbuf.mutex ); x264_pthread_mutex_lock( &h->lookahead->next.mutex ); - x264_lookahead_shift( &h->lookahead->ofbuf, &h->lookahead->next, h->lookahead->next.list[0]->i_bframes + 1 ); + x264_lookahead_shift( &h->lookahead->ofbuf, &h->lookahead->next, shift_frames ); x264_pthread_mutex_unlock( &h->lookahead->next.mutex ); /* For MB-tree and VBV lookahead, we have to perform propagation analysis on I-frames too. */ if( h->lookahead->b_analyse_keyframe && IS_X264_TYPE_I( h->lookahead->last_nonb->i_type ) ) - x264_stack_align( x264_slicetype_analyse, h, 1 ); + x264_stack_align( x264_slicetype_analyse, h, shift_frames ); x264_pthread_mutex_unlock( &h->lookahead->ofbuf.mutex ); } -static void x264_lookahead_thread( x264_t *h ) +static void *x264_lookahead_thread( x264_t *h ) { int shift; #if HAVE_MMX @@ -123,6 +124,7 @@ static void x264_lookahead_thread( x264_t *h ) h->lookahead->b_thread_active = 0; x264_pthread_cond_broadcast( &h->lookahead->ofbuf.cv_fill ); x264_pthread_mutex_unlock( &h->lookahead->ofbuf.mutex ); + return NULL; } #endif @@ -235,11 +237,12 @@ void x264_lookahead_get_frames( x264_t *h ) x264_stack_align( x264_slicetype_decide, h ); x264_lookahead_update_last_nonb( h, h->lookahead->next.list[0] ); - x264_lookahead_shift( &h->lookahead->ofbuf, &h->lookahead->next, h->lookahead->next.list[0]->i_bframes + 1 ); + int shift_frames = h->lookahead->next.list[0]->i_bframes + 1; + x264_lookahead_shift( &h->lookahead->ofbuf, &h->lookahead->next, shift_frames ); /* For MB-tree and VBV lookahead, we have to perform propagation analysis on I-frames too. */ if( h->lookahead->b_analyse_keyframe && IS_X264_TYPE_I( h->lookahead->last_nonb->i_type ) ) - x264_stack_align( x264_slicetype_analyse, h, 1 ); + x264_stack_align( x264_slicetype_analyse, h, shift_frames ); x264_lookahead_encoder_shift( h ); } diff --git a/encoder/macroblock.c b/encoder/macroblock.c index 418e7d38..74cf69bf 100644 --- a/encoder/macroblock.c +++ b/encoder/macroblock.c @@ -1,7 +1,7 @@ /***************************************************************************** * macroblock.c: macroblock encoding ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Laurent Aimar * Loren Merritt @@ -157,28 +157,51 @@ static void x264_mb_encode_i16x16( x264_t *h, int p, int i_qp ) return; } + M32( &h->mb.cache.non_zero_count[x264_scan8[ 0+p*16]] ) = 0; + M32( &h->mb.cache.non_zero_count[x264_scan8[ 2+p*16]] ) = 0; + M32( &h->mb.cache.non_zero_count[x264_scan8[ 8+p*16]] ) = 0; + M32( &h->mb.cache.non_zero_count[x264_scan8[10+p*16]] ) = 0; + h->dctf.sub16x16_dct( dct4x4, p_src, p_dst ); - for( int i = 0; i < 16; i++ ) + if( h->mb.b_noise_reduction ) + for( int idx = 0; idx < 16; idx++ ) + h->quantf.denoise_dct( dct4x4[idx], h->nr_residual_sum[0], h->nr_offset[0], 16 ); + + for( int idx = 0; idx < 16; idx++ ) { - /* copy dc coeff */ - if( h->mb.b_noise_reduction ) - h->quantf.denoise_dct( dct4x4[i], h->nr_residual_sum[0], h->nr_offset[0], 16 ); - dct_dc4x4[block_idx_xy_1d[i]] = dct4x4[i][0]; - dct4x4[i][0] = 0; + dct_dc4x4[block_idx_xy_1d[idx]] = dct4x4[idx][0]; + dct4x4[idx][0] = 0; + } - /* quant/scan/dequant */ - if( h->mb.b_trellis ) - nz = x264_quant_4x4_trellis( h, dct4x4[i], i_quant_cat, i_qp, ctx_cat_plane[DCT_LUMA_AC][p], 1, !!p, i ); - else - nz = h->quantf.quant_4x4( dct4x4[i], h->quant4_mf[i_quant_cat][i_qp], h->quant4_bias[i_quant_cat][i_qp] ); - h->mb.cache.non_zero_count[x264_scan8[16*p+i]] = nz; - if( nz ) + if( h->mb.b_trellis ) + { + for( int idx = 0; idx < 16; idx++ ) + if( x264_quant_4x4_trellis( h, dct4x4[idx], i_quant_cat, i_qp, ctx_cat_plane[DCT_LUMA_AC][p], 1, !!p, idx ) ) + { + block_cbp = 0xf; + h->zigzagf.scan_4x4( h->dct.luma4x4[16*p+idx], dct4x4[idx] ); + h->quantf.dequant_4x4( dct4x4[idx], h->dequant4_mf[i_quant_cat], i_qp ); + if( decimate_score < 6 ) decimate_score += h->quantf.decimate_score15( h->dct.luma4x4[16*p+idx] ); + h->mb.cache.non_zero_count[x264_scan8[16*p+idx]] = 1; + } + } + else + { + for( int i8x8 = 0; i8x8 < 4; i8x8++ ) { - h->zigzagf.scan_4x4( h->dct.luma4x4[16*p+i], dct4x4[i] ); - h->quantf.dequant_4x4( dct4x4[i], h->dequant4_mf[i_quant_cat], i_qp ); - if( decimate_score < 6 ) decimate_score += h->quantf.decimate_score15( h->dct.luma4x4[16*p+i] ); - block_cbp = 0xf; + nz = h->quantf.quant_4x4x4( &dct4x4[i8x8*4], h->quant4_mf[i_quant_cat][i_qp], h->quant4_bias[i_quant_cat][i_qp] ); + if( nz ) + { + block_cbp = 0xf; + FOREACH_BIT( idx, i8x8*4, nz ) + { + h->zigzagf.scan_4x4( h->dct.luma4x4[16*p+idx], dct4x4[idx] ); + h->quantf.dequant_4x4( dct4x4[idx], h->dequant4_mf[i_quant_cat], i_qp ); + if( decimate_score < 6 ) decimate_score += h->quantf.decimate_score15( h->dct.luma4x4[16*p+idx] ); + h->mb.cache.non_zero_count[x264_scan8[16*p+idx]] = 1; + } + } } } @@ -245,6 +268,18 @@ static ALWAYS_INLINE void x264_mb_encode_chroma_internal( x264_t *h, int b_inter h->mb.i_cbp_chroma = 0; h->nr_count[2] += h->mb.b_noise_reduction * 4; + M16( &h->mb.cache.non_zero_count[x264_scan8[16]] ) = 0; + M16( &h->mb.cache.non_zero_count[x264_scan8[18]] ) = 0; + M16( &h->mb.cache.non_zero_count[x264_scan8[32]] ) = 0; + M16( &h->mb.cache.non_zero_count[x264_scan8[34]] ) = 0; + if( chroma422 ) + { + M16( &h->mb.cache.non_zero_count[x264_scan8[24]] ) = 0; + M16( &h->mb.cache.non_zero_count[x264_scan8[26]] ) = 0; + M16( &h->mb.cache.non_zero_count[x264_scan8[40]] ) = 0; + M16( &h->mb.cache.non_zero_count[x264_scan8[42]] ) = 0; + } + /* Early termination: check variance of chroma residual before encoding. * Don't bother trying early termination at low QPs. * Values are experimentally derived. */ @@ -259,17 +294,6 @@ static ALWAYS_INLINE void x264_mb_encode_chroma_internal( x264_t *h, int b_inter score += h->pixf.var2[chromapix]( h->mb.pic.p_fenc[2], FENC_STRIDE, h->mb.pic.p_fdec[2], FDEC_STRIDE, &ssd[1] ); if( score < thresh*4 ) { - M16( &h->mb.cache.non_zero_count[x264_scan8[16]] ) = 0; - M16( &h->mb.cache.non_zero_count[x264_scan8[18]] ) = 0; - M16( &h->mb.cache.non_zero_count[x264_scan8[32]] ) = 0; - M16( &h->mb.cache.non_zero_count[x264_scan8[34]] ) = 0; - if( chroma422 ) - { - M16( &h->mb.cache.non_zero_count[x264_scan8[24]] ) = 0; - M16( &h->mb.cache.non_zero_count[x264_scan8[26]] ) = 0; - M16( &h->mb.cache.non_zero_count[x264_scan8[40]] ) = 0; - M16( &h->mb.cache.non_zero_count[x264_scan8[42]] ) = 0; - } h->mb.cache.non_zero_count[x264_scan8[CHROMA_DC+0]] = 0; h->mb.cache.non_zero_count[x264_scan8[CHROMA_DC+1]] = 0; @@ -326,7 +350,7 @@ static ALWAYS_INLINE void x264_mb_encode_chroma_internal( x264_t *h, int b_inter { pixel *p_src = h->mb.pic.p_fenc[1+ch]; pixel *p_dst = h->mb.pic.p_fdec[1+ch]; - int i_decimate_score = 0; + int i_decimate_score = b_decimate ? 0 : 7; int nz_ac = 0; ALIGNED_ARRAY_16( dctcoef, dct4x4,[8],[16] ); @@ -361,20 +385,40 @@ static ALWAYS_INLINE void x264_mb_encode_chroma_internal( x264_t *h, int b_inter dct2x2dc( dct_dc, dct4x4 ); /* calculate dct coeffs */ - for( int i = 0; i < (chroma422?8:4); i++ ) + for( int i8x8 = 0; i8x8 < (chroma422?2:1); i8x8++ ) { if( h->mb.b_trellis ) - nz = x264_quant_4x4_trellis( h, dct4x4[i], CQM_4IC+b_inter, i_qp, DCT_CHROMA_AC, !b_inter, 1, 0 ); + { + for( int i4x4 = 0; i4x4 < 4; i4x4++ ) + { + if( x264_quant_4x4_trellis( h, dct4x4[i8x8*4+i4x4], CQM_4IC+b_inter, i_qp, DCT_CHROMA_AC, !b_inter, 1, 0 ) ) + { + int idx = 16+ch*16+i8x8*8+i4x4; + h->zigzagf.scan_4x4( h->dct.luma4x4[idx], dct4x4[i8x8*4+i4x4] ); + h->quantf.dequant_4x4( dct4x4[i8x8*4+i4x4], dequant_mf, i_qp ); + if( i_decimate_score < 7 ) + i_decimate_score += h->quantf.decimate_score15( h->dct.luma4x4[idx] ); + h->mb.cache.non_zero_count[x264_scan8[idx]] = 1; + nz_ac = 1; + } + } + } else - nz = h->quantf.quant_4x4( dct4x4[i], h->quant4_mf[CQM_4IC+b_inter][i_qp], h->quant4_bias[CQM_4IC+b_inter][i_qp] ); - h->mb.cache.non_zero_count[x264_scan8[16+i+(chroma422?i&4:0)+ch*16]] = nz; - if( nz ) { - nz_ac = 1; - h->zigzagf.scan_4x4( h->dct.luma4x4[16+i+(chroma422?i&4:0)+ch*16], dct4x4[i] ); - h->quantf.dequant_4x4( dct4x4[i], dequant_mf, i_qp ); - if( b_decimate ) - i_decimate_score += h->quantf.decimate_score15( h->dct.luma4x4[16+i+(chroma422?i&4:0)+ch*16] ); + nz = h->quantf.quant_4x4x4( &dct4x4[i8x8*4], h->quant4_mf[CQM_4IC+b_inter][i_qp], + h->quant4_bias[CQM_4IC+b_inter][i_qp] ); + nz_ac |= nz; + + FOREACH_BIT( i4x4, 0, nz ) + { + int idx = 16+ch*16+i8x8*8+i4x4; + + h->zigzagf.scan_4x4( h->dct.luma4x4[idx], dct4x4[i8x8*4+i4x4] ); + h->quantf.dequant_4x4( dct4x4[i8x8*4+i4x4], dequant_mf, i_qp ); + if( i_decimate_score < 7 ) + i_decimate_score += h->quantf.decimate_score15( h->dct.luma4x4[idx] ); + h->mb.cache.non_zero_count[x264_scan8[idx]] = 1; + } } } @@ -390,7 +434,7 @@ static ALWAYS_INLINE void x264_mb_encode_chroma_internal( x264_t *h, int b_inter h->mb.cache.non_zero_count[x264_scan8[CHROMA_DC+ch]] = nz_dc; - if( (b_decimate && i_decimate_score < 7) || !nz_ac ) + if( i_decimate_score < 7 || !nz_ac ) { /* Decimate the block */ M16( &h->mb.cache.non_zero_count[x264_scan8[16+16*ch]] ) = 0; @@ -646,11 +690,8 @@ static ALWAYS_INLINE void x264_macroblock_encode_internal( x264_t *h, int plane_ { h->mb.b_transform_8x8 = 0; - for( int p = 0; p < plane_count; p++ ) - { + for( int p = 0; p < plane_count; p++, i_qp = h->mb.i_chroma_qp ) x264_mb_encode_i16x16( h, p, i_qp ); - i_qp = h->mb.i_chroma_qp; - } } else if( h->mb.i_type == I_8x8 ) { @@ -668,14 +709,13 @@ static ALWAYS_INLINE void x264_macroblock_encode_internal( x264_t *h, int plane_ if( h->mb.i_skip_intra == 2 ) h->mc.memcpy_aligned( h->dct.luma8x8, h->mb.pic.i8x8_dct_buf, sizeof(h->mb.pic.i8x8_dct_buf) ); } - for( int p = 0; p < plane_count; p++ ) + for( int p = 0; p < plane_count; p++, i_qp = h->mb.i_chroma_qp ) { for( int i = (p == 0 && h->mb.i_skip_intra) ? 3 : 0 ; i < 4; i++ ) { int i_mode = h->mb.cache.intra4x4_pred_mode[x264_scan8[4*i]]; x264_mb_encode_i8x8( h, p, i, i_qp, i_mode, NULL, 1 ); } - i_qp = h->mb.i_chroma_qp; } } else if( h->mb.i_type == I_4x4 ) @@ -694,7 +734,7 @@ static ALWAYS_INLINE void x264_macroblock_encode_internal( x264_t *h, int plane_ if( h->mb.i_skip_intra == 2 ) h->mc.memcpy_aligned( h->dct.luma4x4, h->mb.pic.i4x4_dct_buf, sizeof(h->mb.pic.i4x4_dct_buf) ); } - for( int p = 0; p < plane_count; p++ ) + for( int p = 0; p < plane_count; p++, i_qp = h->mb.i_chroma_qp ) { for( int i = (p == 0 && h->mb.i_skip_intra) ? 15 : 0 ; i < 16; i++ ) { @@ -707,7 +747,6 @@ static ALWAYS_INLINE void x264_macroblock_encode_internal( x264_t *h, int plane_ x264_mb_encode_i4x4( h, p, i, i_qp, i_mode, 1 ); } - i_qp = h->mb.i_chroma_qp; } } else /* Inter MB */ @@ -747,8 +786,9 @@ static ALWAYS_INLINE void x264_macroblock_encode_internal( x264_t *h, int plane_ ALIGNED_ARRAY_16( dctcoef, dct8x8,[4],[64] ); b_decimate &= !h->mb.b_trellis || !h->param.b_cabac; // 8x8 trellis is inherently optimal decimation for CABAC - for( int p = 0; p < plane_count; p++ ) + for( int p = 0; p < plane_count; p++, i_qp = h->mb.i_chroma_qp ) { + CLEAR_16x16_NNZ( p ); h->dctf.sub16x16_dct8( dct8x8, h->mb.pic.p_fenc[p], h->mb.pic.p_fdec[p] ); h->nr_count[1+!!p*2] += h->mb.b_noise_reduction * 4; @@ -772,99 +812,92 @@ static ALWAYS_INLINE void x264_macroblock_encode_internal( x264_t *h, int plane_ } } - if( i_decimate_mb < 6 && b_decimate ) - { - plane_cbp = 0; - CLEAR_16x16_NNZ( p ); - } - else + if( i_decimate_mb >= 6 || !b_decimate ) { - for( int idx = 0; idx < 4; idx++ ) + h->mb.i_cbp_luma |= plane_cbp; + FOREACH_BIT( idx, 0, plane_cbp ) { - int x = idx&1; - int y = idx>>1; - - if( plane_cbp&(1<quantf.dequant_8x8( dct8x8[idx], h->dequant8_mf[p?CQM_8PC:CQM_8PY], i_qp ); - h->dctf.add8x8_idct8( &h->mb.pic.p_fdec[p][8*x + 8*y*FDEC_STRIDE], dct8x8[idx] ); - STORE_8x8_NNZ( p, idx, 1 ); - } - else - STORE_8x8_NNZ( p, idx, 0 ); + h->quantf.dequant_8x8( dct8x8[idx], h->dequant8_mf[p?CQM_8PC:CQM_8PY], i_qp ); + h->dctf.add8x8_idct8( &h->mb.pic.p_fdec[p][8*(idx&1) + 8*(idx>>1)*FDEC_STRIDE], dct8x8[idx] ); + STORE_8x8_NNZ( p, idx, 1 ); } } - h->mb.i_cbp_luma |= plane_cbp; - i_qp = h->mb.i_chroma_qp; } } else { ALIGNED_ARRAY_16( dctcoef, dct4x4,[16],[16] ); - for( int p = 0; p < plane_count; p++ ) + for( int p = 0; p < plane_count; p++, i_qp = h->mb.i_chroma_qp ) { + CLEAR_16x16_NNZ( p ); h->dctf.sub16x16_dct( dct4x4, h->mb.pic.p_fenc[p], h->mb.pic.p_fdec[p] ); - h->nr_count[0+!!p*2] += h->mb.b_noise_reduction * 16; + + if( h->mb.b_noise_reduction ) + { + h->nr_count[0+!!p*2] += 16; + for( int idx = 0; idx < 16; idx++ ) + h->quantf.denoise_dct( dct4x4[idx], h->nr_residual_sum[0+!!p*2], h->nr_offset[0+!!p*2], 16 ); + } int plane_cbp = 0; for( int i8x8 = 0; i8x8 < 4; i8x8++ ) { - int i_decimate_8x8 = 0; - int cbp = 0; - - /* encode one 4x4 block */ - for( int i4x4 = 0; i4x4 < 4; i4x4++ ) + int i_decimate_8x8 = b_decimate ? 0 : 6; + int nnz8x8 = 0; + if( h->mb.b_trellis ) { - int idx = i8x8 * 4 + i4x4; - - nz = x264_quant_4x4( h, dct4x4[idx], i_qp, ctx_cat_plane[DCT_LUMA_4x4][p], 0, p, idx ); - h->mb.cache.non_zero_count[x264_scan8[p*16+idx]] = nz; - + for( int i4x4 = 0; i4x4 < 4; i4x4++ ) + { + int idx = i8x8*4+i4x4; + if( x264_quant_4x4_trellis( h, dct4x4[idx], CQM_4PY, i_qp, ctx_cat_plane[DCT_LUMA_4x4][p], 0, !!p, p*16+idx ) ) + { + h->zigzagf.scan_4x4( h->dct.luma4x4[p*16+idx], dct4x4[idx] ); + h->quantf.dequant_4x4( dct4x4[idx], h->dequant4_mf[p?CQM_4PC:CQM_4PY], i_qp ); + if( i_decimate_8x8 < 6 ) + i_decimate_8x8 += h->quantf.decimate_score16( h->dct.luma4x4[p*16+idx] ); + h->mb.cache.non_zero_count[x264_scan8[p*16+idx]] = 1; + nnz8x8 = 1; + } + } + } + else + { + nnz8x8 = nz = h->quantf.quant_4x4x4( &dct4x4[i8x8*4], h->quant4_mf[CQM_4PY][i_qp], h->quant4_bias[CQM_4PY][i_qp] ); if( nz ) { - h->zigzagf.scan_4x4( h->dct.luma4x4[p*16+idx], dct4x4[idx] ); - h->quantf.dequant_4x4( dct4x4[idx], h->dequant4_mf[p?CQM_4PC:CQM_4PY], i_qp ); - if( b_decimate && i_decimate_8x8 < 6 ) - i_decimate_8x8 += h->quantf.decimate_score16( h->dct.luma4x4[p*16+idx] ); - cbp = 1; + FOREACH_BIT( idx, i8x8*4, nz ) + { + h->zigzagf.scan_4x4( h->dct.luma4x4[p*16+idx], dct4x4[idx] ); + h->quantf.dequant_4x4( dct4x4[idx], h->dequant4_mf[p?CQM_4PC:CQM_4PY], i_qp ); + if( i_decimate_8x8 < 6 ) + i_decimate_8x8 += h->quantf.decimate_score16( h->dct.luma4x4[p*16+idx] ); + h->mb.cache.non_zero_count[x264_scan8[p*16+idx]] = 1; + } } } - - int x = i8x8&1; - int y = i8x8>>1; - - /* decimate this 8x8 block */ - i_decimate_mb += i_decimate_8x8; - if( b_decimate ) + if( nnz8x8 ) { + i_decimate_mb += i_decimate_8x8; if( i_decimate_8x8 < 4 ) STORE_8x8_NNZ( p, i8x8, 0 ); else plane_cbp |= 1<dctf.add8x8_idct( &h->mb.pic.p_fdec[p][8*x + 8*y*FDEC_STRIDE], &dct4x4[i8x8*4] ); - plane_cbp |= 1<mb.i_cbp_luma |= plane_cbp; + FOREACH_BIT( i8x8, 0, plane_cbp ) { - for( int i8x8 = 0; i8x8 < 4; i8x8++ ) - if( plane_cbp&(1<dctf.add8x8_idct( &h->mb.pic.p_fdec[p][(i8x8&1)*8 + (i8x8>>1)*8*FDEC_STRIDE], &dct4x4[i8x8*4] ); + h->dctf.add8x8_idct( &h->mb.pic.p_fdec[p][(i8x8&1)*8 + (i8x8>>1)*8*FDEC_STRIDE], &dct4x4[i8x8*4] ); } } - h->mb.i_cbp_luma |= plane_cbp; - i_qp = h->mb.i_chroma_qp; } } } @@ -938,7 +971,7 @@ static ALWAYS_INLINE int x264_macroblock_probe_skip_internal( x264_t *h, int b_b ALIGNED_4( int16_t mvp[2] ); int i_qp = h->mb.i_qp; - for( int p = 0; p < plane_count; p++ ) + for( int p = 0; p < plane_count; p++, i_qp = h->mb.i_chroma_qp ) { int quant_cat = p ? CQM_4PC : CQM_4PY; if( !b_bidir ) @@ -957,23 +990,23 @@ static ALWAYS_INLINE int x264_macroblock_probe_skip_internal( x264_t *h, int b_b { int fenc_offset = (i8x8&1) * 8 + (i8x8>>1) * FENC_STRIDE * 8; int fdec_offset = (i8x8&1) * 8 + (i8x8>>1) * FDEC_STRIDE * 8; - /* get luma diff */ + h->dctf.sub8x8_dct( dct4x4, h->mb.pic.p_fenc[p] + fenc_offset, h->mb.pic.p_fdec[p] + fdec_offset ); - /* encode one 4x4 block */ - for( int i4x4 = 0; i4x4 < 4; i4x4++ ) - { - if( h->mb.b_noise_reduction ) + + if( h->mb.b_noise_reduction ) + for( int i4x4 = 0; i4x4 < 4; i4x4++ ) h->quantf.denoise_dct( dct4x4[i4x4], h->nr_residual_sum[0+!!p*2], h->nr_offset[0+!!p*2], 16 ); - if( !h->quantf.quant_4x4( dct4x4[i4x4], h->quant4_mf[quant_cat][i_qp], h->quant4_bias[quant_cat][i_qp] ) ) - continue; - h->zigzagf.scan_4x4( dctscan, dct4x4[i4x4] ); + + int nz = h->quantf.quant_4x4x4( dct4x4, h->quant4_mf[quant_cat][i_qp], h->quant4_bias[quant_cat][i_qp] ); + FOREACH_BIT( idx, 0, nz ) + { + h->zigzagf.scan_4x4( dctscan, dct4x4[idx] ); i_decimate_mb += h->quantf.decimate_score16( dctscan ); if( i_decimate_mb >= 6 ) return 0; } } - i_qp = h->mb.i_chroma_qp; } if( chroma == CHROMA_420 || chroma == CHROMA_422 ) @@ -1023,6 +1056,7 @@ static ALWAYS_INLINE int x264_macroblock_probe_skip_internal( x264_t *h, int b_b { h->quantf.denoise_dct( dct4x4[i4x4], h->nr_residual_sum[2], h->nr_offset[2], 16 ); dct_dc[i4x4] = dct4x4[i4x4][0]; + dct4x4[i4x4][0] = 0; } } else @@ -1043,21 +1077,26 @@ static ALWAYS_INLINE int x264_macroblock_probe_skip_internal( x264_t *h, int b_b continue; if( !h->mb.b_noise_reduction ) - for( int i = 0; i <= chroma422; i++ ) + for( int i = 0; i <= chroma422; i++ ) + { h->dctf.sub8x8_dct( &dct4x4[4*i], p_src + 8*i*FENC_STRIDE, p_dst + 8*i*FDEC_STRIDE ); + dct4x4[i*4+0][0] = 0; + dct4x4[i*4+1][0] = 0; + dct4x4[i*4+2][0] = 0; + dct4x4[i*4+3][0] = 0; + } /* calculate dct coeffs */ - for( int i4x4 = 0, i_decimate_mb = 0; i4x4 < (chroma422?8:4); i4x4++ ) + for( int i8x8 = 0, i_decimate_mb = 0; i8x8 < (chroma422?2:1); i8x8++ ) { - dct4x4[i4x4][0] = 0; - if( h->mb.b_noise_reduction ) - h->quantf.denoise_dct( dct4x4[i4x4], h->nr_residual_sum[2], h->nr_offset[2], 16 ); - if( !h->quantf.quant_4x4( dct4x4[i4x4], h->quant4_mf[CQM_4PC][i_qp], h->quant4_bias[CQM_4PC][i_qp] ) ) - continue; - h->zigzagf.scan_4x4( dctscan, dct4x4[i4x4] ); - i_decimate_mb += h->quantf.decimate_score15( dctscan ); - if( i_decimate_mb >= 7 ) - return 0; + int nz = h->quantf.quant_4x4x4( &dct4x4[i8x8*4], h->quant4_mf[CQM_4PC][i_qp], h->quant4_bias[CQM_4PC][i_qp] ); + FOREACH_BIT( idx, i8x8*4, nz ) + { + h->zigzagf.scan_4x4( dctscan, dct4x4[idx] ); + i_decimate_mb += h->quantf.decimate_score15( dctscan ); + if( i_decimate_mb >= 7 ) + return 0; + } } } } @@ -1176,12 +1215,13 @@ static ALWAYS_INLINE void x264_macroblock_encode_p8x8_internal( x264_t *h, int i { if( h->mb.b_transform_8x8 ) { - for( int p = 0; p < plane_count; p++ ) + for( int p = 0; p < plane_count; p++, i_qp = h->mb.i_chroma_qp ) { int quant_cat = p ? CQM_8PC : CQM_8PY; pixel *p_fenc = h->mb.pic.p_fenc[p] + 8*x + 8*y*FENC_STRIDE; pixel *p_fdec = h->mb.pic.p_fdec[p] + 8*x + 8*y*FDEC_STRIDE; ALIGNED_ARRAY_16( dctcoef, dct8x8,[64] ); + h->dctf.sub8x8_dct8( dct8x8, p_fenc, p_fdec ); int nnz8x8 = x264_quant_8x8( h, dct8x8, i_qp, ctx_cat_plane[DCT_LUMA_8x8][p], 0, p, i8 ); if( nnz8x8 ) @@ -1196,50 +1236,74 @@ static ALWAYS_INLINE void x264_macroblock_encode_p8x8_internal( x264_t *h, int i h->quantf.dequant_8x8( dct8x8, h->dequant8_mf[quant_cat], i_qp ); h->dctf.add8x8_idct8( p_fdec, dct8x8 ); STORE_8x8_NNZ( p, i8, 1 ); + h->mb.i_cbp_luma |= 1 << i8; } else STORE_8x8_NNZ( p, i8, 0 ); } else STORE_8x8_NNZ( p, i8, 0 ); - h->mb.i_cbp_luma |= nnz8x8 << i8; - i_qp = h->mb.i_chroma_qp; } } else { - for( int p = 0; p < plane_count; p++ ) + for( int p = 0; p < plane_count; p++, i_qp = h->mb.i_chroma_qp ) { int quant_cat = p ? CQM_4PC : CQM_4PY; pixel *p_fenc = h->mb.pic.p_fenc[p] + 8*x + 8*y*FENC_STRIDE; pixel *p_fdec = h->mb.pic.p_fdec[p] + 8*x + 8*y*FDEC_STRIDE; - int i_decimate_8x8 = 0, nnz8x8 = 0; + int i_decimate_8x8 = b_decimate ? 0 : 4; ALIGNED_ARRAY_16( dctcoef, dct4x4,[4],[16] ); + int nnz8x8 = 0; + h->dctf.sub8x8_dct( dct4x4, p_fenc, p_fdec ); - for( int i4 = 0; i4 < 4; i4++ ) + STORE_8x8_NNZ( p, i8, 0 ); + + if( h->mb.b_noise_reduction ) + for( int idx = 0; idx < 4; idx++ ) + h->quantf.denoise_dct( dct4x4[idx], h->nr_residual_sum[0+!!p*2], h->nr_offset[0+!!p*2], 16 ); + + if( h->mb.b_trellis ) { - nz = x264_quant_4x4( h, dct4x4[i4], i_qp, ctx_cat_plane[DCT_LUMA_4x4][p], 0, p, i8*4+i4 ); - h->mb.cache.non_zero_count[x264_scan8[p*16+i8*4+i4]] = nz; + for( int i4x4 = 0; i4x4 < 4; i4x4++ ) + { + if( x264_quant_4x4_trellis( h, dct4x4[i4x4], quant_cat, i_qp, ctx_cat_plane[DCT_LUMA_4x4][p], 0, !!p, i8*4+i4x4+p*16 ) ) + { + h->zigzagf.scan_4x4( h->dct.luma4x4[p*16+i8*4+i4x4], dct4x4[i4x4] ); + h->quantf.dequant_4x4( dct4x4[i4x4], h->dequant4_mf[quant_cat], i_qp ); + if( i_decimate_8x8 < 4 ) + i_decimate_8x8 += h->quantf.decimate_score16( h->dct.luma4x4[p*16+i8*4+i4x4] ); + h->mb.cache.non_zero_count[x264_scan8[p*16+i8*4+i4x4]] = 1; + nnz8x8 = 1; + } + } + } + else + { + nnz8x8 = nz = h->quantf.quant_4x4x4( dct4x4, h->quant4_mf[quant_cat][i_qp], h->quant4_bias[quant_cat][i_qp] ); if( nz ) { - h->zigzagf.scan_4x4( h->dct.luma4x4[p*16+i8*4+i4], dct4x4[i4] ); - h->quantf.dequant_4x4( dct4x4[i4], h->dequant4_mf[quant_cat], i_qp ); - if( b_decimate ) - i_decimate_8x8 += h->quantf.decimate_score16( h->dct.luma4x4[p*16+i8*4+i4] ); - nnz8x8 = 1; + FOREACH_BIT( i4x4, 0, nz ) + { + h->zigzagf.scan_4x4( h->dct.luma4x4[p*16+i8*4+i4x4], dct4x4[i4x4] ); + h->quantf.dequant_4x4( dct4x4[i4x4], h->dequant4_mf[quant_cat], i_qp ); + if( i_decimate_8x8 < 4 ) + i_decimate_8x8 += h->quantf.decimate_score16( h->dct.luma4x4[p*16+i8*4+i4x4] ); + h->mb.cache.non_zero_count[x264_scan8[p*16+i8*4+i4x4]] = 1; + } } } - - if( b_decimate && i_decimate_8x8 < 4 ) - nnz8x8 = 0; - if( nnz8x8 ) - h->dctf.add8x8_idct( p_fdec, dct4x4 ); - else - STORE_8x8_NNZ( p, i8, 0 ); - - h->mb.i_cbp_luma |= nnz8x8 << i8; - i_qp = h->mb.i_chroma_qp; + { + /* decimate this 8x8 block */ + if( i_decimate_8x8 < 4 ) + STORE_8x8_NNZ( p, i8, 0 ); + else + { + h->dctf.add8x8_idct( p_fdec, dct4x4 ); + h->mb.i_cbp_luma |= 1 << i8; + } + } } } @@ -1297,7 +1361,7 @@ static ALWAYS_INLINE void x264_macroblock_encode_p4x4_internal( x264_t *h, int i { int i_qp = h->mb.i_qp; - for( int p = 0; p < plane_count; p++ ) + for( int p = 0; p < plane_count; p++, i_qp = h->mb.i_chroma_qp ) { int quant_cat = p ? CQM_4PC : CQM_4PY; pixel *p_fenc = &h->mb.pic.p_fenc[p][block_idx_xy_fenc[i4]]; @@ -1324,7 +1388,6 @@ static ALWAYS_INLINE void x264_macroblock_encode_p4x4_internal( x264_t *h, int i h->dctf.add4x4_idct( p_fdec, dct4x4 ); } } - i_qp = h->mb.i_chroma_qp; } } diff --git a/encoder/macroblock.h b/encoder/macroblock.h index 45ce19de..f0342cf3 100644 --- a/encoder/macroblock.h +++ b/encoder/macroblock.h @@ -1,7 +1,7 @@ /***************************************************************************** * macroblock.h: macroblock encoding ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Loren Merritt * Laurent Aimar @@ -104,6 +104,10 @@ do\ M32( &h->mb.cache.non_zero_count[x264_scan8[16*p+10]] ) = 0;\ } while(0) +/* A special for loop that iterates branchlessly over each set + * bit in a 4-bit input. */ +#define FOREACH_BIT(idx,start,mask) for( int idx = start, msk = mask, skip; msk && (skip = x264_ctz_4bit(msk), idx += skip, msk >>= skip+1, 1); idx++ ) + static ALWAYS_INLINE void x264_mb_encode_i4x4( x264_t *h, int p, int idx, int i_qp, int i_mode, int b_predict ) { int nz; diff --git a/encoder/me.c b/encoder/me.c index 22098b2d..44410934 100644 --- a/encoder/me.c +++ b/encoder/me.c @@ -1,7 +1,7 @@ /***************************************************************************** * me.c: motion estimation ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Loren Merritt * Laurent Aimar @@ -61,21 +61,22 @@ static void refine_subpel( x264_t *h, x264_me_t *m, int hpel_iters, int qpel_ite (p_cost_mvx[(mx)<<2] + p_cost_mvy[(my)<<2]) #define COST_MV( mx, my )\ +do\ {\ int cost = h->pixf.fpelcmp[i_pixel]( p_fenc, FENC_STRIDE,\ &p_fref_w[(my)*stride+(mx)], stride )\ + BITS_MVD(mx,my);\ COPY3_IF_LT( bcost, cost, bmx, mx, bmy, my );\ -} +} while(0) -#define COST_MV_HPEL( mx, my ) \ -{ \ - intptr_t stride2 = 16; \ - pixel *src = h->mc.get_ref( pix, &stride2, m->p_fref, stride, mx, my, bw, bh, &m->weight[0] ); \ - int cost = h->pixf.fpelcmp[i_pixel]( p_fenc, FENC_STRIDE, src, stride2 ) \ - + p_cost_mvx[ mx ] + p_cost_mvy[ my ]; \ - COPY3_IF_LT( bpred_cost, cost, bpred_mx, mx, bpred_my, my ); \ -} +#define COST_MV_HPEL( mx, my, cost )\ +do\ +{\ + intptr_t stride2 = 16;\ + pixel *src = h->mc.get_ref( pix, &stride2, m->p_fref, stride, mx, my, bw, bh, &m->weight[0] );\ + cost = h->pixf.fpelcmp[i_pixel]( p_fenc, FENC_STRIDE, src, stride2 )\ + + p_cost_mvx[ mx ] + p_cost_mvy[ my ];\ +} while(0) #define COST_MV_X3_DIR( m0x, m0y, m1x, m1y, m2x, m2y, costs )\ {\ @@ -174,6 +175,10 @@ static void refine_subpel( x264_t *h, x264_me_t *m, int hpel_iters, int qpel_ite }\ } +#define FPEL(mv) (((mv)+2)>>2) /* Convert subpel MV to fullpel with rounding... */ +#define SPEL(mv) ((mv)<<2) /* ... and the reverse. */ +#define SPELx2(mv) (SPEL(mv)&0xFFFCFFFC) /* for two packed MVs */ + void x264_me_search_ref( x264_t *h, x264_me_t *m, int16_t (*mvc)[2], int i_mvc, int *p_halfpel_thresh ) { const int bw = x264_pixel_size[m->i_pixel].w; @@ -181,99 +186,136 @@ void x264_me_search_ref( x264_t *h, x264_me_t *m, int16_t (*mvc)[2], int i_mvc, const int i_pixel = m->i_pixel; const int stride = m->i_stride[0]; int i_me_range = h->param.analyse.i_me_range; - int bmx, bmy, bcost; - int bpred_mx = 0, bpred_my = 0, bpred_cost = COST_MAX; + int bmx, bmy, bcost = COST_MAX; + int bpred_cost = COST_MAX; int omx, omy, pmx, pmy; pixel *p_fenc = m->p_fenc[0]; pixel *p_fref_w = m->p_fref_w; ALIGNED_ARRAY_16( pixel, pix,[16*16] ); + ALIGNED_ARRAY_8( int16_t, mvc_temp,[16],[2] ); int costs[16]; - int mv_x_min = h->mb.mv_min_fpel[0]; - int mv_y_min = h->mb.mv_min_fpel[1]; - int mv_x_max = h->mb.mv_max_fpel[0]; - int mv_y_max = h->mb.mv_max_fpel[1]; - int mv_x_min_qpel = mv_x_min << 2; - int mv_y_min_qpel = mv_y_min << 2; - int mv_x_max_qpel = mv_x_max << 2; - int mv_y_max_qpel = mv_y_max << 2; + int mv_x_min = h->mb.mv_limit_fpel[0][0]; + int mv_y_min = h->mb.mv_limit_fpel[0][1]; + int mv_x_max = h->mb.mv_limit_fpel[1][0]; + int mv_y_max = h->mb.mv_limit_fpel[1][1]; /* Special version of pack to allow shortcuts in CHECK_MVRANGE */ #define pack16to32_mask2(mx,my) ((mx<<16)|(my&0x7FFF)) uint32_t mv_min = pack16to32_mask2( -mv_x_min, -mv_y_min ); uint32_t mv_max = pack16to32_mask2( mv_x_max, mv_y_max )|0x8000; + uint32_t pmv, bpred_mv = 0; #define CHECK_MVRANGE(mx,my) (!(((pack16to32_mask2(mx,my) + mv_min) | (mv_max - pack16to32_mask2(mx,my))) & 0x80004000)) const uint16_t *p_cost_mvx = m->p_cost_mv - m->mvp[0]; const uint16_t *p_cost_mvy = m->p_cost_mv - m->mvp[1]; - uint32_t pmv; - bmx = x264_clip3( m->mvp[0], mv_x_min_qpel, mv_x_max_qpel ); - bmy = x264_clip3( m->mvp[1], mv_y_min_qpel, mv_y_max_qpel ); - pmx = ( bmx + 2 ) >> 2; - pmy = ( bmy + 2 ) >> 2; - bcost = COST_MAX; - - /* try extra predictors if provided */ + /* Try extra predictors if provided. If subme >= 3, check subpel predictors, + * otherwise round them to fullpel. */ if( h->mb.i_subpel_refine >= 3 ) { - pmv = pack16to32_mask(bmx,bmy); - if( i_mvc ) - COST_MV_HPEL( bmx, bmy ); - for( int i = 0; i < i_mvc; i++ ) + /* Calculate and check the MVP first */ + int bpred_mx = x264_clip3( m->mvp[0], SPEL(mv_x_min), SPEL(mv_x_max) ); + int bpred_my = x264_clip3( m->mvp[1], SPEL(mv_y_min), SPEL(mv_y_max) ); + pmv = pack16to32_mask( bpred_mx, bpred_my ); + pmx = FPEL( bpred_mx ); + pmy = FPEL( bpred_my ); + + COST_MV_HPEL( bpred_mx, bpred_my, bpred_cost ); + int pmv_cost = bpred_cost; + + if( i_mvc > 0 ) { - if( M32( mvc[i] ) && (pmv != M32( mvc[i] )) ) + /* Clip MV candidates and eliminate those equal to zero and pmv. */ + int valid_mvcs = x264_predictor_clip( mvc_temp+2, mvc, i_mvc, h->mb.mv_limit_fpel, pmv ); + if( valid_mvcs > 0 ) { - int mx = x264_clip3( mvc[i][0], mv_x_min_qpel, mv_x_max_qpel ); - int my = x264_clip3( mvc[i][1], mv_y_min_qpel, mv_y_max_qpel ); - COST_MV_HPEL( mx, my ); + int i = 1, cost; + /* We stuff pmv here to branchlessly pick between pmv and the various + * MV candidates. [0] gets skipped in order to maintain alignment for + * x264_predictor_clip. */ + M32( mvc_temp[1] ) = pmv; + bpred_cost <<= 4; + do + { + int mx = mvc_temp[i+1][0]; + int my = mvc_temp[i+1][1]; + COST_MV_HPEL( mx, my, cost ); + COPY1_IF_LT( bpred_cost, (cost << 4) + i ); + } while( ++i <= valid_mvcs ); + bpred_mx = mvc_temp[(bpred_cost&15)+1][0]; + bpred_my = mvc_temp[(bpred_cost&15)+1][1]; + bpred_cost >>= 4; } } - bmx = ( bpred_mx + 2 ) >> 2; - bmy = ( bpred_my + 2 ) >> 2; - COST_MV( bmx, bmy ); + + /* Round the best predictor back to fullpel and get the cost, since this is where + * we'll be starting the fullpel motion search. */ + bmx = FPEL( bpred_mx ); + bmy = FPEL( bpred_my ); + bpred_mv = pack16to32_mask(bpred_mx, bpred_my); + if( bpred_mv&0x00030003 ) /* Only test if the tested predictor is actually subpel... */ + COST_MV( bmx, bmy ); + else /* Otherwise just copy the cost (we already know it) */ + bcost = bpred_cost; + + /* Test the zero vector if it hasn't been tested yet. */ + if( pmv ) + { + if( bmx|bmy ) COST_MV( 0, 0 ); + } + /* If a subpel mv candidate was better than the zero vector, the previous + * fullpel check won't have gotten it even if the pmv was zero. So handle + * that possibility here. */ + else + { + COPY3_IF_LT( bcost, pmv_cost, bmx, 0, bmy, 0 ); + } } else { - /* check the MVP */ - bmx = pmx; - bmy = pmy; + /* Calculate and check the fullpel MVP first */ + bmx = pmx = x264_clip3( FPEL(m->mvp[0]), mv_x_min, mv_x_max ); + bmy = pmy = x264_clip3( FPEL(m->mvp[1]), mv_y_min, mv_y_max ); + pmv = pack16to32_mask( bmx, bmy ); + /* Because we are rounding the predicted motion vector to fullpel, there will be * an extra MV cost in 15 out of 16 cases. However, when the predicted MV is * chosen as the best predictor, it is often the case that the subpel search will - * result in a vector at or next to the predicted motion vector. Therefore, it is - * sensible to omit the cost of the MV from the rounded MVP to avoid unfairly - * biasing against use of the predicted motion vector. */ + * result in a vector at or next to the predicted motion vector. Therefore, we omit + * the cost of the MV from the rounded MVP to avoid unfairly biasing against use of + * the predicted motion vector. + * + * Disclaimer: this is a post-hoc rationalization for why this hack works. */ bcost = h->pixf.fpelcmp[i_pixel]( p_fenc, FENC_STRIDE, &p_fref_w[bmy*stride+bmx], stride ); - pmv = pack16to32_mask( bmx, bmy ); + if( i_mvc > 0 ) { - ALIGNED_ARRAY_8( int16_t, mvc_fpel,[16],[2] ); - x264_predictor_roundclip( mvc_fpel, mvc, i_mvc, mv_x_min, mv_x_max, mv_y_min, mv_y_max ); - bcost <<= 4; - for( int i = 1; i <= i_mvc; i++ ) + /* Like in subme>=3, except we also round the candidates to fullpel. */ + int valid_mvcs = x264_predictor_roundclip( mvc_temp+2, mvc, i_mvc, h->mb.mv_limit_fpel, pmv ); + if( valid_mvcs > 0 ) { - if( M32( mvc_fpel[i-1] ) && (pmv != M32( mvc[i-1] )) ) + int i = 1, cost; + M32( mvc_temp[1] ) = pmv; + bcost <<= 4; + do { - int mx = mvc_fpel[i-1][0]; - int my = mvc_fpel[i-1][1]; - int cost = h->pixf.fpelcmp[i_pixel]( p_fenc, FENC_STRIDE, &p_fref_w[my*stride+mx], stride ) + BITS_MVD( mx, my ); - cost = (cost << 4) + i; - COPY1_IF_LT( bcost, cost ); - } + int mx = mvc_temp[i+1][0]; + int my = mvc_temp[i+1][1]; + cost = h->pixf.fpelcmp[i_pixel]( p_fenc, FENC_STRIDE, &p_fref_w[my*stride+mx], stride ) + BITS_MVD( mx, my ); + COPY1_IF_LT( bcost, (cost << 4) + i ); + } while( ++i <= valid_mvcs ); + bmx = mvc_temp[(bcost&15)+1][0]; + bmy = mvc_temp[(bcost&15)+1][1]; + bcost >>= 4; } - if( bcost&15 ) - { - bmx = mvc_fpel[(bcost&15)-1][0]; - bmy = mvc_fpel[(bcost&15)-1][1]; - } - bcost >>= 4; } - } - if( pmv ) - COST_MV( 0, 0 ); + /* Same as above, except the condition is simpler. */ + if( pmv ) + COST_MV( 0, 0 ); + } switch( h->mb.i_me_method ) { @@ -360,19 +402,20 @@ void x264_me_search_ref( x264_t *h, x264_me_t *m, int16_t (*mvc)[2], int i_mvc, bcost >>= 3; #endif /* square refine */ - int dir = 0; + bcost <<= 4; COST_MV_X4_DIR( 0,-1, 0,1, -1,0, 1,0, costs ); - COPY2_IF_LT( bcost, costs[0], dir, 1 ); - COPY2_IF_LT( bcost, costs[1], dir, 2 ); - COPY2_IF_LT( bcost, costs[2], dir, 3 ); - COPY2_IF_LT( bcost, costs[3], dir, 4 ); + COPY1_IF_LT( bcost, (costs[0]<<4)+1 ); + COPY1_IF_LT( bcost, (costs[1]<<4)+2 ); + COPY1_IF_LT( bcost, (costs[2]<<4)+3 ); + COPY1_IF_LT( bcost, (costs[3]<<4)+4 ); COST_MV_X4_DIR( -1,-1, -1,1, 1,-1, 1,1, costs ); - COPY2_IF_LT( bcost, costs[0], dir, 5 ); - COPY2_IF_LT( bcost, costs[1], dir, 6 ); - COPY2_IF_LT( bcost, costs[2], dir, 7 ); - COPY2_IF_LT( bcost, costs[3], dir, 8 ); - bmx += square1[dir][0]; - bmy += square1[dir][1]; + COPY1_IF_LT( bcost, (costs[0]<<4)+5 ); + COPY1_IF_LT( bcost, (costs[1]<<4)+6 ); + COPY1_IF_LT( bcost, (costs[2]<<4)+7 ); + COPY1_IF_LT( bcost, (costs[3]<<4)+8 ); + bmx += square1[bcost&15][0]; + bmy += square1[bcost&15][1]; + bcost >>= 4; break; } @@ -729,24 +772,22 @@ void x264_me_search_ref( x264_t *h, x264_me_t *m, int16_t (*mvc)[2], int i_mvc, } /* -> qpel mv */ - if( bpred_cost < bcost ) + uint32_t bmv = pack16to32_mask(bmx,bmy); + uint32_t bmv_spel = SPELx2(bmv); + if( h->mb.i_subpel_refine < 3 ) { - m->mv[0] = bpred_mx; - m->mv[1] = bpred_my; - m->cost = bpred_cost; + m->cost_mv = p_cost_mvx[bmx<<2] + p_cost_mvy[bmy<<2]; + m->cost = bcost; + /* compute the real cost */ + if( bmv == pmv ) m->cost += m->cost_mv; + M32( m->mv ) = bmv_spel; } else { - m->mv[0] = bmx << 2; - m->mv[1] = bmy << 2; - m->cost = bcost; + M32(m->mv) = bpred_cost < bcost ? bpred_mv : bmv_spel; + m->cost = X264_MIN( bpred_cost, bcost ); } - /* compute the real cost */ - m->cost_mv = p_cost_mvx[ m->mv[0] ] + p_cost_mvy[ m->mv[1] ]; - if( bmx == pmx && bmy == pmy && h->mb.i_subpel_refine < 3 ) - m->cost += m->cost_mv; - /* subpel refine */ if( h->mb.i_subpel_refine >= 2 ) { @@ -840,33 +881,45 @@ static void refine_subpel( x264_t *h, x264_me_t *m, int hpel_iters, int qpel_ite int bcost = m->cost; int odir = -1, bdir; - /* try the subpel component of the predicted mv */ - if( hpel_iters && h->mb.i_subpel_refine < 3 ) - { - int mx = x264_clip3( m->mvp[0], h->mb.mv_min_spel[0]+2, h->mb.mv_max_spel[0]-2 ); - int my = x264_clip3( m->mvp[1], h->mb.mv_min_spel[1]+2, h->mb.mv_max_spel[1]-2 ); - if( (mx-bmx)|(my-bmy) ) - COST_MV_SAD( mx, my ); - } - /* halfpel diamond search */ - for( int i = hpel_iters; i > 0; i-- ) + if( hpel_iters ) { - int omx = bmx, omy = bmy; - int costs[4]; - intptr_t stride = 64; // candidates are either all hpel or all qpel, so one stride is enough - pixel *src0, *src1, *src2, *src3; - src0 = h->mc.get_ref( pix, &stride, m->p_fref, m->i_stride[0], omx, omy-2, bw, bh+1, &m->weight[0] ); - src2 = h->mc.get_ref( pix+32, &stride, m->p_fref, m->i_stride[0], omx-2, omy, bw+4, bh, &m->weight[0] ); - src1 = src0 + stride; - src3 = src2 + 1; - h->pixf.fpelcmp_x4[i_pixel]( m->p_fenc[0], src0, src1, src2, src3, stride, costs ); - COPY2_IF_LT( bcost, costs[0] + p_cost_mvx[omx ] + p_cost_mvy[omy-2], bmy, omy-2 ); - COPY2_IF_LT( bcost, costs[1] + p_cost_mvx[omx ] + p_cost_mvy[omy+2], bmy, omy+2 ); - COPY3_IF_LT( bcost, costs[2] + p_cost_mvx[omx-2] + p_cost_mvy[omy ], bmx, omx-2, bmy, omy ); - COPY3_IF_LT( bcost, costs[3] + p_cost_mvx[omx+2] + p_cost_mvy[omy ], bmx, omx+2, bmy, omy ); - if( (bmx == omx) & (bmy == omy) ) - break; + /* try the subpel component of the predicted mv */ + if( h->mb.i_subpel_refine < 3 ) + { + int mx = x264_clip3( m->mvp[0], h->mb.mv_min_spel[0]+2, h->mb.mv_max_spel[0]-2 ); + int my = x264_clip3( m->mvp[1], h->mb.mv_min_spel[1]+2, h->mb.mv_max_spel[1]-2 ); + if( (mx-bmx)|(my-bmy) ) + COST_MV_SAD( mx, my ); + } + + bcost <<= 6; + for( int i = hpel_iters; i > 0; i-- ) + { + int omx = bmx, omy = bmy; + int costs[4]; + intptr_t stride = 64; // candidates are either all hpel or all qpel, so one stride is enough + pixel *src0, *src1, *src2, *src3; + src0 = h->mc.get_ref( pix, &stride, m->p_fref, m->i_stride[0], omx, omy-2, bw, bh+1, &m->weight[0] ); + src2 = h->mc.get_ref( pix+32, &stride, m->p_fref, m->i_stride[0], omx-2, omy, bw+4, bh, &m->weight[0] ); + src1 = src0 + stride; + src3 = src2 + 1; + h->pixf.fpelcmp_x4[i_pixel]( m->p_fenc[0], src0, src1, src2, src3, stride, costs ); + costs[0] += p_cost_mvx[omx ] + p_cost_mvy[omy-2]; + costs[1] += p_cost_mvx[omx ] + p_cost_mvy[omy+2]; + costs[2] += p_cost_mvx[omx-2] + p_cost_mvy[omy ]; + costs[3] += p_cost_mvx[omx+2] + p_cost_mvy[omy ]; + COPY1_IF_LT( bcost, (costs[0]<<6)+2 ); + COPY1_IF_LT( bcost, (costs[1]<<6)+6 ); + COPY1_IF_LT( bcost, (costs[2]<<6)+16 ); + COPY1_IF_LT( bcost, (costs[3]<<6)+48 ); + if( !(bcost&63) ) + break; + bmx -= (bcost<<26)>>29; + bmy -= (bcost<<29)>>29; + bcost &= ~63; + } + bcost >>= 6; } if( !b_refine_qpel && (h->pixf.mbcmp_unaligned[0] != h->pixf.fpelcmp[0] || b_chroma_me) ) @@ -919,10 +972,18 @@ static void refine_subpel( x264_t *h, x264_me_t *m, int hpel_iters, int qpel_ite h->mc.mc_luma( pix+32, 64, m->p_fref, m->i_stride[0], omx-1, omy, bw, bh, &m->weight[0] ); h->mc.mc_luma( pix+48, 64, m->p_fref, m->i_stride[0], omx+1, omy, bw, bh, &m->weight[0] ); h->pixf.fpelcmp_x4[i_pixel]( m->p_fenc[0], pix, pix+16, pix+32, pix+48, 64, costs ); - COPY2_IF_LT( bcost, costs[0] + p_cost_mvx[omx ] + p_cost_mvy[omy-1], bmy, omy-1 ); - COPY2_IF_LT( bcost, costs[1] + p_cost_mvx[omx ] + p_cost_mvy[omy+1], bmy, omy+1 ); - COPY3_IF_LT( bcost, costs[2] + p_cost_mvx[omx-1] + p_cost_mvy[omy ], bmx, omx-1, bmy, omy ); - COPY3_IF_LT( bcost, costs[3] + p_cost_mvx[omx+1] + p_cost_mvy[omy ], bmx, omx+1, bmy, omy ); + costs[0] += p_cost_mvx[omx ] + p_cost_mvy[omy-1]; + costs[1] += p_cost_mvx[omx ] + p_cost_mvy[omy+1]; + costs[2] += p_cost_mvx[omx-1] + p_cost_mvy[omy ]; + costs[3] += p_cost_mvx[omx+1] + p_cost_mvy[omy ]; + bcost <<= 4; + COPY1_IF_LT( bcost, (costs[0]<<4)+1 ); + COPY1_IF_LT( bcost, (costs[1]<<4)+3 ); + COPY1_IF_LT( bcost, (costs[2]<<4)+4 ); + COPY1_IF_LT( bcost, (costs[3]<<4)+12 ); + bmx -= (bcost<<28)>>30; + bmy -= (bcost<<30)>>30; + bcost >>= 4; } m->cost = bcost; diff --git a/encoder/me.h b/encoder/me.h index 64ce3186..5857bad6 100644 --- a/encoder/me.h +++ b/encoder/me.h @@ -1,7 +1,7 @@ /***************************************************************************** * me.h: motion estimation ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Loren Merritt * Laurent Aimar diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index 3ecd3c63..6d8e849f 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -1,7 +1,7 @@ /***************************************************************************** * ratecontrol.c: ratecontrol ***************************************************************************** - * Copyright (C) 2005-2012 x264 project + * Copyright (C) 2005-2013 x264 project * * Authors: Loren Merritt * Michael Niedermayer @@ -62,6 +62,7 @@ typedef struct typedef struct { + float coeff_min; float coeff; float count; float decay; @@ -135,9 +136,21 @@ struct x264_ratecontrol_t double lmin[3]; /* min qscale by frame type */ double lmax[3]; double lstep; /* max change (multiply) in qscale per frame */ - uint16_t *qp_buffer[2]; /* Global buffers for converting MB-tree quantizer data. */ - int qpbuf_pos; /* In order to handle pyramid reordering, QP buffer acts as a stack. + struct + { + uint16_t *qp_buffer[2]; /* Global buffers for converting MB-tree quantizer data. */ + int qpbuf_pos; /* In order to handle pyramid reordering, QP buffer acts as a stack. * This value is the current position (0 or 1). */ + int src_mb_count; + + /* For rescaling */ + int rescale_enabled; + float *scale_buffer[2]; /* Intermediate buffers */ + int filtersize[2]; /* filter size (H/V) */ + float *coeffs[2]; + int *pos[2]; + int srcdim[2]; /* Source dimensions (W/H) */ + } mbtree; /* MBRC stuff */ float frame_size_estimated; /* Access to this variable must be atomic: double is @@ -395,6 +408,130 @@ void x264_adaptive_quant_frame( x264_t *h, x264_frame_t *frame, float *quant_off } } +static int x264_macroblock_tree_rescale_init( x264_t *h, x264_ratecontrol_t *rc ) +{ + /* Use fractional QP array dimensions to compensate for edge padding */ + float srcdim[2] = {rc->mbtree.srcdim[0] / 16.f, rc->mbtree.srcdim[1] / 16.f}; + float dstdim[2] = { h->param.i_width / 16.f, h->param.i_height / 16.f}; + int srcdimi[2] = {ceil(srcdim[0]), ceil(srcdim[1])}; + int dstdimi[2] = {ceil(dstdim[0]), ceil(dstdim[1])}; + if( PARAM_INTERLACED ) + { + srcdimi[1] = (srcdimi[1]+1)&~1; + dstdimi[1] = (dstdimi[1]+1)&~1; + } + + rc->mbtree.src_mb_count = srcdimi[0] * srcdimi[1]; + + CHECKED_MALLOC( rc->mbtree.qp_buffer[0], rc->mbtree.src_mb_count * sizeof(uint16_t) ); + if( h->param.i_bframe_pyramid && h->param.rc.b_stat_read ) + CHECKED_MALLOC( rc->mbtree.qp_buffer[1], rc->mbtree.src_mb_count * sizeof(uint16_t) ); + rc->mbtree.qpbuf_pos = -1; + + /* No rescaling to do */ + if( srcdimi[0] == dstdimi[0] && srcdimi[1] == dstdimi[1] ) + return 0; + + rc->mbtree.rescale_enabled = 1; + + /* Allocate intermediate scaling buffers */ + CHECKED_MALLOC( rc->mbtree.scale_buffer[0], srcdimi[0] * srcdimi[1] * sizeof(float) ); + CHECKED_MALLOC( rc->mbtree.scale_buffer[1], dstdimi[0] * srcdimi[1] * sizeof(float) ); + + /* Allocate and calculate resize filter parameters and coefficients */ + for( int i = 0; i < 2; i++ ) + { + if( srcdim[i] > dstdim[i] ) // downscale + rc->mbtree.filtersize[i] = 1 + (2 * srcdimi[i] + dstdimi[i] - 1) / dstdimi[i]; + else // upscale + rc->mbtree.filtersize[i] = 3; + + CHECKED_MALLOC( rc->mbtree.coeffs[i], rc->mbtree.filtersize[i] * dstdimi[i] * sizeof(float) ); + CHECKED_MALLOC( rc->mbtree.pos[i], dstdimi[i] * sizeof(int) ); + + /* Initialize filter coefficients */ + float inc = srcdim[i] / dstdim[i]; + float dmul = inc > 1.f ? dstdim[i] / srcdim[i] : 1.f; + float dstinsrc = 0.5f * inc - 0.5f; + int filtersize = rc->mbtree.filtersize[i]; + for( int j = 0; j < dstdimi[i]; j++ ) + { + int pos = dstinsrc - (filtersize - 2.f) * 0.5f; + float sum = 0.0; + rc->mbtree.pos[i][j] = pos; + for( int k = 0; k < filtersize; k++ ) + { + float d = fabs( pos + k - dstinsrc ) * dmul; + float coeff = X264_MAX( 1.f - d, 0 ); + rc->mbtree.coeffs[i][j * filtersize + k] = coeff; + sum += coeff; + } + sum = 1.0f / sum; + for( int k = 0; k < filtersize; k++ ) + rc->mbtree.coeffs[i][j * filtersize + k] *= sum; + dstinsrc += inc; + } + } + + /* Write back actual qp array dimensions */ + rc->mbtree.srcdim[0] = srcdimi[0]; + rc->mbtree.srcdim[1] = srcdimi[1]; + return 0; +fail: + return -1; +} + +static void x264_macroblock_tree_rescale_destroy( x264_ratecontrol_t *rc ) +{ + for( int i = 0; i < 2; i++ ) + { + x264_free( rc->mbtree.qp_buffer[i] ); + x264_free( rc->mbtree.scale_buffer[i] ); + x264_free( rc->mbtree.coeffs[i] ); + x264_free( rc->mbtree.pos[i] ); + } +} + +static ALWAYS_INLINE float tapfilter( float *src, int pos, int max, int stride, float *coeff, int filtersize ) +{ + float sum = 0.f; + for( int i = 0; i < filtersize; i++, pos++ ) + sum += src[x264_clip3( pos, 0, max-1 )*stride] * coeff[i]; + return sum; +} + +static void x264_macroblock_tree_rescale( x264_t *h, x264_ratecontrol_t *rc, float *dst ) +{ + float *input, *output; + int filtersize, stride, height; + + /* H scale first */ + input = rc->mbtree.scale_buffer[0]; + output = rc->mbtree.scale_buffer[1]; + filtersize = rc->mbtree.filtersize[0]; + stride = rc->mbtree.srcdim[0]; + height = rc->mbtree.srcdim[1]; + for( int y = 0; y < height; y++, input += stride, output += h->mb.i_mb_width ) + { + float *coeff = rc->mbtree.coeffs[0]; + for( int x = 0; x < h->mb.i_mb_width; x++, coeff+=filtersize ) + output[x] = tapfilter( input, rc->mbtree.pos[0][x], stride, 1, coeff, filtersize ); + } + + /* V scale next */ + input = rc->mbtree.scale_buffer[1]; + output = dst; + filtersize = rc->mbtree.filtersize[1]; + stride = h->mb.i_mb_width; + height = rc->mbtree.srcdim[1]; + for( int x = 0; x < h->mb.i_mb_width; x++, input++, output++ ) + { + float *coeff = rc->mbtree.coeffs[1]; + for( int y = 0; y < h->mb.i_mb_height; y++, coeff+=filtersize ) + output[y*stride] = tapfilter( input, rc->mbtree.pos[1][y], height, stride, coeff, filtersize ); + } +} + int x264_macroblock_tree_read( x264_t *h, x264_frame_t *frame, float *quant_offsets ) { x264_ratecontrol_t *rc = h->rc; @@ -403,18 +540,18 @@ int x264_macroblock_tree_read( x264_t *h, x264_frame_t *frame, float *quant_offs if( rc->entry[frame->i_frame].kept_as_ref ) { uint8_t i_type; - if( rc->qpbuf_pos < 0 ) + if( rc->mbtree.qpbuf_pos < 0 ) { do { - rc->qpbuf_pos++; + rc->mbtree.qpbuf_pos++; if( !fread( &i_type, 1, 1, rc->p_mbtree_stat_file_in ) ) goto fail; - if( fread( rc->qp_buffer[rc->qpbuf_pos], sizeof(uint16_t), h->mb.i_mb_count, rc->p_mbtree_stat_file_in ) != h->mb.i_mb_count ) + if( fread( rc->mbtree.qp_buffer[rc->mbtree.qpbuf_pos], sizeof(uint16_t), rc->mbtree.src_mb_count, rc->p_mbtree_stat_file_in ) != rc->mbtree.src_mb_count ) goto fail; - if( i_type != i_type_actual && rc->qpbuf_pos == 1 ) + if( i_type != i_type_actual && rc->mbtree.qpbuf_pos == 1 ) { x264_log( h, X264_LOG_ERROR, "MB-tree frametype %d doesn't match actual frametype %d.\n", i_type, i_type_actual ); return -1; @@ -422,13 +559,18 @@ int x264_macroblock_tree_read( x264_t *h, x264_frame_t *frame, float *quant_offs } while( i_type != i_type_actual ); } - for( int i = 0; i < h->mb.i_mb_count; i++ ) + float *dst = rc->mbtree.rescale_enabled ? rc->mbtree.scale_buffer[0] : frame->f_qp_offset; + for( int i = 0; i < rc->mbtree.src_mb_count; i++ ) { - frame->f_qp_offset[i] = ((float)(int16_t)endian_fix16( rc->qp_buffer[rc->qpbuf_pos][i] )) * (1/256.0); - if( h->frames.b_have_lowres ) - frame->i_inv_qscale_factor[i] = x264_exp2fix8(frame->f_qp_offset[i]); + int16_t qp_fix8 = endian_fix16( rc->mbtree.qp_buffer[rc->mbtree.qpbuf_pos][i] ); + dst[i] = qp_fix8 * (1.f/256.f); } - rc->qpbuf_pos--; + if( rc->mbtree.rescale_enabled ) + x264_macroblock_tree_rescale( h, rc, frame->f_qp_offset ); + if( h->frames.b_have_lowres ) + for( int i = 0; i < h->mb.i_mb_count; i++ ) + frame->i_inv_qscale_factor[i] = x264_exp2fix8( frame->f_qp_offset[i] ); + rc->mbtree.qpbuf_pos--; } else x264_stack_align( x264_adaptive_quant_frame, h, frame, quant_offsets ); @@ -697,17 +839,19 @@ int x264_ratecontrol_new( x264_t *h ) rc->lmax[i] = qp2qscale( h->param.rc.i_qp_max ); for( int j = 0; j < num_preds; j++ ) { - rc->pred[i+j*5].coeff= 2.0; - rc->pred[i+j*5].count= 1.0; - rc->pred[i+j*5].decay= 0.5; - rc->pred[i+j*5].offset= 0.0; + rc->pred[i+j*5].coeff_min = 2.0 / 4; + rc->pred[i+j*5].coeff = 2.0; + rc->pred[i+j*5].count = 1.0; + rc->pred[i+j*5].decay = 0.5; + rc->pred[i+j*5].offset = 0.0; } for( int j = 0; j < 2; j++ ) { - rc->row_preds[i][j].coeff= .25; - rc->row_preds[i][j].count= 1.0; - rc->row_preds[i][j].decay= 0.5; - rc->row_preds[i][j].offset= 0.0; + rc->row_preds[i][j].coeff_min = .25 / 4; + rc->row_preds[i][j].coeff = .25; + rc->row_preds[i][j].count = 1.0; + rc->row_preds[i][j].decay = 0.5; + rc->row_preds[i][j].offset = 0.0; } } *rc->pred_b_from_p = rc->pred[0]; @@ -767,11 +911,10 @@ int x264_ratecontrol_new( x264_t *h ) x264_log( h, X264_LOG_ERROR, "resolution specified in stats file not valid\n" ); return -1; } - else if( h->param.rc.b_mb_tree && (i != h->param.i_width || j != h->param.i_height) ) + else if( h->param.rc.b_mb_tree ) { - x264_log( h, X264_LOG_ERROR, "MB-tree doesn't support different resolution than 1st pass (%dx%d vs %dx%d)\n", - h->param.i_width, h->param.i_height, i, j ); - return -1; + rc->mbtree.srcdim[0] = i; + rc->mbtree.srcdim[1] = j; } res_factor = (float)h->param.i_width * h->param.i_height / (i*j); /* Change in bits relative to resolution isn't quite linear on typical sources, @@ -883,6 +1026,7 @@ int x264_ratecontrol_new( x264_t *h ) /* read stats */ p = stats_in; + double total_qp_aq = 0; for( int i = 0; i < rc->num_entries; i++ ) { ratecontrol_entry_t *rce; @@ -890,7 +1034,7 @@ int x264_ratecontrol_new( x264_t *h ) char pict_type; int e; char *next; - float qp; + float qp_rc, qp_aq; int ref; next= strchr(p, ';'); @@ -906,8 +1050,8 @@ int x264_ratecontrol_new( x264_t *h ) rce = &rc->entry[frame_number]; rce->direct_mode = 0; - e += sscanf( p, " in:%*d out:%*d type:%c dur:%"SCNd64" cpbdur:%"SCNd64" q:%f tex:%d mv:%d misc:%d imb:%d pmb:%d smb:%d d:%c", - &pict_type, &rce->i_duration, &rce->i_cpb_duration, &qp, &rce->tex_bits, + e += sscanf( p, " in:%*d out:%*d type:%c dur:%"SCNd64" cpbdur:%"SCNd64" q:%f aq:%f tex:%d mv:%d misc:%d imb:%d pmb:%d smb:%d d:%c", + &pict_type, &rce->i_duration, &rce->i_cpb_duration, &qp_rc, &qp_aq, &rce->tex_bits, &rce->mv_bits, &rce->misc_bits, &rce->i_count, &rce->p_count, &rce->s_count, &rce->direct_mode ); rce->tex_bits *= res_factor_bits; @@ -972,15 +1116,17 @@ int x264_ratecontrol_new( x264_t *h ) break; default: e = -1; break; } - if( e < 12 ) + if( e < 13 ) { parse_error: x264_log( h, X264_LOG_ERROR, "statistics are damaged at line %d, parser out=%d\n", i, e ); return -1; } - rce->qscale = qp2qscale( qp ); + rce->qscale = qp2qscale( qp_rc ); + total_qp_aq += qp_aq; p = next; } + h->pps->i_pic_init_qp = SPEC_QP( (int)(total_qp_aq / rc->num_entries + 0.5) ); x264_free( stats_buf ); @@ -1030,10 +1176,13 @@ int x264_ratecontrol_new( x264_t *h ) if( h->param.rc.b_mb_tree && (h->param.rc.b_stat_read || h->param.rc.b_stat_write) ) { - CHECKED_MALLOC( rc->qp_buffer[0], h->mb.i_mb_count * sizeof(uint16_t) ); - if( h->param.i_bframe_pyramid && h->param.rc.b_stat_read ) - CHECKED_MALLOC( rc->qp_buffer[1], h->mb.i_mb_count * sizeof(uint16_t) ); - rc->qpbuf_pos = -1; + if( !h->param.rc.b_stat_read ) + { + rc->mbtree.srcdim[0] = h->param.i_width; + rc->mbtree.srcdim[1] = h->param.i_height; + } + if( x264_macroblock_tree_rescale_init( h, rc ) < 0 ) + return -1; } for( int i = 0; iparam.i_threads; i++ ) @@ -1221,8 +1370,7 @@ void x264_ratecontrol_delete( x264_t *h ) x264_free( rc->pred ); x264_free( rc->pred_b_from_p ); x264_free( rc->entry ); - x264_free( rc->qp_buffer[0] ); - x264_free( rc->qp_buffer[1] ); + x264_macroblock_tree_rescale_destroy( rc ); if( rc->zones ) { x264_free( rc->zones[0].param ); @@ -1650,6 +1798,7 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) h->fdec->f_qp_avg_rc = rc->qpa_rc /= h->mb.i_mb_count; h->fdec->f_qp_avg_aq = (float)rc->qpa_aq / h->mb.i_mb_count; + h->fdec->f_crf_avg = h->param.rc.f_rf_constant + h->fdec->f_qp_avg_rc - rc->qp_novbv; if( h->param.rc.b_stat_write ) { @@ -1663,10 +1812,11 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) dir_avg>0 ? 's' : dir_avg<0 ? 't' : '-' ) : '-'; if( fprintf( rc->p_stat_file_out, - "in:%d out:%d type:%c dur:%"PRId64" cpbdur:%"PRId64" q:%.2f tex:%d mv:%d misc:%d imb:%d pmb:%d smb:%d d:%c ref:", + "in:%d out:%d type:%c dur:%"PRId64" cpbdur:%"PRId64" q:%.2f aq:%.2f tex:%d mv:%d misc:%d imb:%d pmb:%d smb:%d d:%c ref:", h->fenc->i_frame, h->i_frame, c_type, h->fenc->i_duration, - h->fenc->i_cpb_duration, rc->qpa_rc, + h->fenc->i_cpb_duration, + rc->qpa_rc, h->fdec->f_qp_avg_aq, h->stat.frame.i_tex_bits, h->stat.frame.i_mv_bits, h->stat.frame.i_misc_bits, @@ -1713,10 +1863,10 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler ) uint8_t i_type = h->sh.i_type; /* Values are stored as big-endian FIX8.8 */ for( int i = 0; i < h->mb.i_mb_count; i++ ) - rc->qp_buffer[0][i] = endian_fix16( h->fenc->f_qp_offset[i]*256.0 ); + rc->mbtree.qp_buffer[0][i] = endian_fix16( h->fenc->f_qp_offset[i]*256.0 ); if( fwrite( &i_type, 1, 1, rc->p_mbtree_stat_file_out ) < 1 ) goto fail; - if( fwrite( rc->qp_buffer[0], sizeof(uint16_t), h->mb.i_mb_count, rc->p_mbtree_stat_file_out ) < h->mb.i_mb_count ) + if( fwrite( rc->mbtree.qp_buffer[0], sizeof(uint16_t), h->mb.i_mb_count, rc->p_mbtree_stat_file_out ) < h->mb.i_mb_count ) goto fail; } } @@ -1948,7 +2098,7 @@ static void update_predictor( predictor_t *p, float q, float var, float bits ) if( var < 10 ) return; float old_coeff = p->coeff / p->count; - float new_coeff = bits*q / var; + float new_coeff = X264_MAX( bits*q / var, p->coeff_min ); float new_coeff_clipped = x264_clip3f( new_coeff, old_coeff/range, old_coeff*range ); float new_offset = bits*q - new_coeff_clipped * var; if( new_offset >= 0 ) @@ -2310,6 +2460,7 @@ static float rate_estimate_qscale( x264_t *h ) double w = x264_clip3f( cur_time*100, 0.0, 1.0 ); q *= pow( (double)total_bits / rcc->expected_bits_sum, w ); } + rcc->qp_novbv = qscale2qp( q ); if( rcc->b_vbv ) { /* Do not overflow vbv */ @@ -2550,7 +2701,7 @@ void x264_thread_sync_ratecontrol( x264_t *cur, x264_t *prev, x264_t *next ) COPY(short_term_cplxcount); COPY(bframes); COPY(prev_zone); - COPY(qpbuf_pos); + COPY(mbtree.qpbuf_pos); /* these vars can be updated by x264_ratecontrol_init_reconfigurable */ COPY(bitrate); COPY(buffer_size); diff --git a/encoder/ratecontrol.h b/encoder/ratecontrol.h index c6b5bd74..1f51d6dc 100644 --- a/encoder/ratecontrol.h +++ b/encoder/ratecontrol.h @@ -1,7 +1,7 @@ /***************************************************************************** * ratecontrol.h: ratecontrol ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Loren Merritt * Laurent Aimar diff --git a/encoder/rdo.c b/encoder/rdo.c index 017c780b..a7ba073e 100644 --- a/encoder/rdo.c +++ b/encoder/rdo.c @@ -1,7 +1,7 @@ /***************************************************************************** * rdo.c: rate-distortion optimization ***************************************************************************** - * Copyright (C) 2005-2012 x264 project + * Copyright (C) 2005-2013 x264 project * * Authors: Loren Merritt * Jason Garrett-Glaser @@ -1161,5 +1161,6 @@ int x264_quant_8x8_trellis( x264_t *h, dctcoef *dct, int i_quant_cat, h->mb.cache.non_zero_count[x264_scan8[idx*4+i]] = nz; nzaccum |= nz; } + STORE_8x8_NNZ( 0, idx, 0 ); return nzaccum; } diff --git a/encoder/set.c b/encoder/set.c index 5027b79d..6e65c4de 100644 --- a/encoder/set.c +++ b/encoder/set.c @@ -1,7 +1,7 @@ /***************************************************************************** * set: header writing ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Laurent Aimar * Loren Merritt @@ -130,9 +130,9 @@ void x264_sps_init( x264_sps_t *sps, int i_id, x264_param_t *param ) sps->b_constraint_set3 = 0; sps->i_level_idc = param->i_level_idc; - if( param->i_level_idc == 9 && ( sps->i_profile_idc >= PROFILE_BASELINE && sps->i_profile_idc <= PROFILE_EXTENDED ) ) + if( param->i_level_idc == 9 && ( sps->i_profile_idc == PROFILE_BASELINE || sps->i_profile_idc == PROFILE_MAIN ) ) { - sps->b_constraint_set3 = 1; /* level 1b with Baseline, Main or Extended profile is signalled via constraint_set3 */ + sps->b_constraint_set3 = 1; /* level 1b with Baseline or Main profile is signalled via constraint_set3 */ sps->i_level_idc = 11; } /* Intra profiles */ @@ -575,7 +575,7 @@ int x264_sei_version_write( x264_t *h, bs_t *s ) memcpy( payload, uuid, 16 ); sprintf( payload+16, "x264 - core %d%s - H.264/MPEG-4 AVC codec - " - "Copy%s 2003-2012 - http://www.videolan.org/x264.html - options: %s", + "Copy%s 2003-2013 - http://www.videolan.org/x264.html - options: %s", X264_BUILD, X264_VERSION, HAVE_GPL?"left":"right", opts ); length = strlen(payload)+1; @@ -727,22 +727,23 @@ void x264_sei_dec_ref_pic_marking_write( x264_t *h, bs_t *s ) const x264_level_t x264_levels[] = { - { 10, 1485, 99, 152064, 64, 175, 64, 64, 0, 2, 0, 0, 1 }, - { 9, 1485, 99, 152064, 128, 350, 64, 64, 0, 2, 0, 0, 1 }, /* "1b" */ - { 11, 3000, 396, 345600, 192, 500, 128, 64, 0, 2, 0, 0, 1 }, - { 12, 6000, 396, 912384, 384, 1000, 128, 64, 0, 2, 0, 0, 1 }, - { 13, 11880, 396, 912384, 768, 2000, 128, 64, 0, 2, 0, 0, 1 }, - { 20, 11880, 396, 912384, 2000, 2000, 128, 64, 0, 2, 0, 0, 1 }, - { 21, 19800, 792, 1824768, 4000, 4000, 256, 64, 0, 2, 0, 0, 0 }, - { 22, 20250, 1620, 3110400, 4000, 4000, 256, 64, 0, 2, 0, 0, 0 }, - { 30, 40500, 1620, 3110400, 10000, 10000, 256, 32, 22, 2, 0, 1, 0 }, - { 31, 108000, 3600, 6912000, 14000, 14000, 512, 16, 60, 4, 1, 1, 0 }, - { 32, 216000, 5120, 7864320, 20000, 20000, 512, 16, 60, 4, 1, 1, 0 }, - { 40, 245760, 8192, 12582912, 20000, 25000, 512, 16, 60, 4, 1, 1, 0 }, - { 41, 245760, 8192, 12582912, 50000, 62500, 512, 16, 24, 2, 1, 1, 0 }, - { 42, 522240, 8704, 13369344, 50000, 62500, 512, 16, 24, 2, 1, 1, 1 }, - { 50, 589824, 22080, 42393600, 135000, 135000, 512, 16, 24, 2, 1, 1, 1 }, - { 51, 983040, 36864, 70778880, 240000, 240000, 512, 16, 24, 2, 1, 1, 1 }, + { 10, 1485, 99, 396, 64, 175, 64, 64, 0, 2, 0, 0, 1 }, + { 9, 1485, 99, 396, 128, 350, 64, 64, 0, 2, 0, 0, 1 }, /* "1b" */ + { 11, 3000, 396, 900, 192, 500, 128, 64, 0, 2, 0, 0, 1 }, + { 12, 6000, 396, 2376, 384, 1000, 128, 64, 0, 2, 0, 0, 1 }, + { 13, 11880, 396, 2376, 768, 2000, 128, 64, 0, 2, 0, 0, 1 }, + { 20, 11880, 396, 2376, 2000, 2000, 128, 64, 0, 2, 0, 0, 1 }, + { 21, 19800, 792, 4752, 4000, 4000, 256, 64, 0, 2, 0, 0, 0 }, + { 22, 20250, 1620, 8100, 4000, 4000, 256, 64, 0, 2, 0, 0, 0 }, + { 30, 40500, 1620, 8100, 10000, 10000, 256, 32, 22, 2, 0, 1, 0 }, + { 31, 108000, 3600, 18000, 14000, 14000, 512, 16, 60, 4, 1, 1, 0 }, + { 32, 216000, 5120, 20480, 20000, 20000, 512, 16, 60, 4, 1, 1, 0 }, + { 40, 245760, 8192, 32768, 20000, 25000, 512, 16, 60, 4, 1, 1, 0 }, + { 41, 245760, 8192, 32768, 50000, 62500, 512, 16, 24, 2, 1, 1, 0 }, + { 42, 522240, 8704, 34816, 50000, 62500, 512, 16, 24, 2, 1, 1, 1 }, + { 50, 589824, 22080, 110400, 135000, 135000, 512, 16, 24, 2, 1, 1, 1 }, + { 51, 983040, 36864, 184320, 240000, 240000, 512, 16, 24, 2, 1, 1, 1 }, + { 52, 2073600, 36864, 184320, 240000, 240000, 512, 16, 24, 2, 1, 1, 1 }, { 0 } }; @@ -757,7 +758,7 @@ int x264_validate_levels( x264_t *h, int verbose ) { int ret = 0; int mbs = h->sps->i_mb_width * h->sps->i_mb_height; - int dpb = mbs * 384 * h->sps->vui.i_max_dec_frame_buffering; + int dpb = mbs * h->sps->vui.i_max_dec_frame_buffering; int cbp_factor = h->sps->i_profile_idc>=PROFILE_HIGH422 ? 16 : h->sps->i_profile_idc==PROFILE_HIGH10 ? 12 : h->sps->i_profile_idc==PROFILE_HIGH ? 5 : 4; @@ -772,12 +773,12 @@ int x264_validate_levels( x264_t *h, int verbose ) ERROR( "frame MB size (%dx%d) > level limit (%d)\n", h->sps->i_mb_width, h->sps->i_mb_height, l->frame_size ); if( dpb > l->dpb ) - ERROR( "DPB size (%d frames, %d bytes) > level limit (%d frames, %d bytes)\n", - h->sps->vui.i_max_dec_frame_buffering, dpb, (int)(l->dpb / (384*mbs)), l->dpb ); + ERROR( "DPB size (%d frames, %d mbs) > level limit (%d frames, %d mbs)\n", + h->sps->vui.i_max_dec_frame_buffering, dpb, l->dpb / mbs, l->dpb ); #define CHECK( name, limit, val ) \ if( (val) > (limit) ) \ - ERROR( name " (%d) > level limit (%d)\n", (int)(val), (limit) ); + ERROR( name " (%"PRId64") > level limit (%d)\n", (int64_t)(val), (limit) ); CHECK( "VBV bitrate", (l->bitrate * cbp_factor) / 4, h->param.rc.i_vbv_max_bitrate ); CHECK( "VBV buffer", (l->cpb * cbp_factor) / 4, h->param.rc.i_vbv_buffer_size ); diff --git a/encoder/set.h b/encoder/set.h index cb8a03c7..11f0c483 100644 --- a/encoder/set.h +++ b/encoder/set.h @@ -1,7 +1,7 @@ /***************************************************************************** * set.h: header writing ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Laurent Aimar * Loren Merritt diff --git a/encoder/slicetype.c b/encoder/slicetype.c index 9bd862de..8a6c226d 100644 --- a/encoder/slicetype.c +++ b/encoder/slicetype.c @@ -1,7 +1,7 @@ /***************************************************************************** * slicetype.c: lookahead analysis ***************************************************************************** - * Copyright (C) 2005-2012 x264 project + * Copyright (C) 2005-2013 x264 project * * Authors: Jason Garrett-Glaser * Loren Merritt @@ -220,15 +220,12 @@ static NOINLINE unsigned int x264_weight_cost_chroma( x264_t *h, x264_frame_t *f { unsigned int cost = 0; int i_stride = fenc->i_stride[1]; - int i_offset = i_stride / 2; int i_lines = fenc->i_lines[1]; int i_width = fenc->i_width[1]; - pixel *src = ref + i_offset; + pixel *src = ref + (i_stride >> 1); ALIGNED_ARRAY_16( pixel, buf, [8*16] ); int pixoff = 0; - int chromapix = h->luma2chroma_pixel[PIXEL_16x16]; int height = 16 >> CHROMA_V_SHIFT; - ALIGNED_16( static pixel flat[8] ) = {0}; if( w ) { for( int y = 0; y < i_lines; y += height, pixoff = y*i_stride ) @@ -239,19 +236,15 @@ static NOINLINE unsigned int x264_weight_cost_chroma( x264_t *h, x264_frame_t *f * But testing shows that for chroma the DC coefficient is by far the most * important part of the coding cost. Thus a more useful chroma weight is * obtained by comparing each block's DC coefficient instead of the actual - * pixels. - * - * FIXME: add a (faster) asm sum function to replace sad. */ - cost += abs( h->pixf.sad_aligned[chromapix]( buf, 8, flat, 0 ) - - h->pixf.sad_aligned[chromapix]( &src[pixoff], i_stride, flat, 0 ) ); + * pixels. */ + cost += h->pixf.asd8( buf, 8, &src[pixoff], i_stride, height ); } cost += x264_weight_slice_header_cost( h, w, 1 ); } else for( int y = 0; y < i_lines; y += height, pixoff = y*i_stride ) for( int x = 0; x < i_width; x += 8, pixoff += 8 ) - cost += abs( h->pixf.sad_aligned[chromapix]( &ref[pixoff], i_stride, flat, 0 ) - - h->pixf.sad_aligned[chromapix]( &src[pixoff], i_stride, flat, 0 ) ); + cost += h->pixf.asd8( &ref[pixoff], i_stride, &src[pixoff], i_stride, height ); x264_emms(); return cost; } @@ -431,9 +424,21 @@ static void x264_weights_analyse( x264_t *h, x264_frame_t *fenc, x264_frame_t *r } } +/* Output buffers are separated by 128 bytes to avoid false sharing of cachelines + * in multithreaded lookahead. */ +#define PAD_SIZE 32 +/* cost_est, cost_est_aq, intra_mbs, num rows */ +#define NUM_INTS 4 +#define COST_EST 0 +#define COST_EST_AQ 1 +#define INTRA_MBS 2 +#define NUM_ROWS 3 +#define ROW_SATD (NUM_INTS + (h->mb.i_mb_y - h->i_threadslice_start)) + static void x264_slicetype_mb_cost( x264_t *h, x264_mb_analysis_t *a, x264_frame_t **frames, int p0, int p1, int b, - int dist_scale_factor, int do_search[2], const x264_weight_t *w ) + int dist_scale_factor, int do_search[2], const x264_weight_t *w, + int *output_inter, int *output_intra ) { x264_frame_t *fref0 = frames[p0]; x264_frame_t *fref1 = frames[p1]; @@ -467,16 +472,16 @@ static void x264_slicetype_mb_cost( x264_t *h, x264_mb_analysis_t *a, goto lowres_intra_mb; // no need for h->mb.mv_min[] - h->mb.mv_min_fpel[0] = -8*h->mb.i_mb_x - 4; - h->mb.mv_max_fpel[0] = 8*( h->mb.i_mb_width - h->mb.i_mb_x - 1 ) + 4; - h->mb.mv_min_spel[0] = 4*( h->mb.mv_min_fpel[0] - 8 ); - h->mb.mv_max_spel[0] = 4*( h->mb.mv_max_fpel[0] + 8 ); + h->mb.mv_limit_fpel[0][0] = -8*h->mb.i_mb_x - 4; + h->mb.mv_limit_fpel[1][0] = 8*( h->mb.i_mb_width - h->mb.i_mb_x - 1 ) + 4; + h->mb.mv_min_spel[0] = 4*( h->mb.mv_limit_fpel[0][0] - 8 ); + h->mb.mv_max_spel[0] = 4*( h->mb.mv_limit_fpel[1][0] + 8 ); if( h->mb.i_mb_x >= h->mb.i_mb_width - 2 ) { - h->mb.mv_min_fpel[1] = -8*h->mb.i_mb_y - 4; - h->mb.mv_max_fpel[1] = 8*( h->mb.i_mb_height - h->mb.i_mb_y - 1 ) + 4; - h->mb.mv_min_spel[1] = 4*( h->mb.mv_min_fpel[1] - 8 ); - h->mb.mv_max_spel[1] = 4*( h->mb.mv_max_fpel[1] + 8 ); + h->mb.mv_limit_fpel[0][1] = -8*h->mb.i_mb_y - 4; + h->mb.mv_limit_fpel[1][1] = 8*( h->mb.i_mb_height - h->mb.i_mb_y - 1 ) + 4; + h->mb.mv_min_spel[1] = 4*( h->mb.mv_limit_fpel[0][1] - 8 ); + h->mb.mv_max_spel[1] = 4*( h->mb.mv_limit_fpel[1][1] + 8 ); } #define LOAD_HPELS_LUMA(dst, src) \ @@ -578,7 +583,7 @@ static void x264_slicetype_mb_cost( x264_t *h, x264_mb_analysis_t *a, #define MVC(mv) { CP32( mvc[i_mvc], mv ); i_mvc++; } if( i_mb_x < h->mb.i_mb_width - 1 ) MVC( fenc_mv[1] ); - if( i_mb_y < h->mb.i_mb_height - 1 ) + if( i_mb_y < h->i_threadslice_end - 1 ) { MVC( fenc_mv[i_mb_stride] ); if( i_mb_x > 0 ) @@ -628,15 +633,16 @@ static void x264_slicetype_mb_cost( x264_t *h, x264_mb_analysis_t *a, if( !fenc->b_intra_calculated ) { ALIGNED_ARRAY_16( pixel, edge,[36] ); - pixel *pix = &pix1[8+FDEC_STRIDE - 1]; - pixel *src = &fenc->lowres[0][i_pel_offset - 1]; + pixel *pix = &pix1[8+FDEC_STRIDE]; + pixel *src = &fenc->lowres[0][i_pel_offset]; const int intra_penalty = 5 * a->i_lambda; int satds[3]; + int pixoff = 4 / sizeof(pixel); - memcpy( pix-FDEC_STRIDE, src-i_stride, 17 * sizeof(pixel) ); - for( int i = 0; i < 8; i++ ) - pix[i*FDEC_STRIDE] = src[i*i_stride]; - pix++; + /* Avoid store forwarding stalls by writing larger chunks */ + memcpy( pix-FDEC_STRIDE, src-i_stride, 16 * sizeof(pixel) ); + for( int i = -1; i < 8; i++ ) + M32( &pix[i*FDEC_STRIDE-pixoff] ) = M32( &src[i*i_stride-pixoff] ); h->pixf.intra_mbcmp_x3_8x8c( h->mb.pic.p_fenc[0], pix, satds ); int i_icost = X264_MIN3( satds[0], satds[1], satds[2] ); @@ -660,11 +666,11 @@ static void x264_slicetype_mb_cost( x264_t *h, x264_mb_analysis_t *a, int i_icost_aq = i_icost; if( h->param.rc.i_aq_mode ) i_icost_aq = (i_icost_aq * fenc->i_inv_qscale_factor[i_mb_xy] + 128) >> 8; - fenc->i_row_satds[0][0][h->mb.i_mb_y] += i_icost_aq; + output_intra[ROW_SATD] += i_icost_aq; if( b_frame_score_mb ) { - fenc->i_cost_est[0][0] += i_icost; - fenc->i_cost_est_aq[0][0] += i_icost_aq; + output_intra[COST_EST] += i_icost; + output_intra[COST_EST_AQ] += i_icost_aq; } } i_bcost += lowres_penalty; @@ -681,7 +687,7 @@ static void x264_slicetype_mb_cost( x264_t *h, x264_mb_analysis_t *a, list_used = 0; } if( b_frame_score_mb ) - fenc->i_intra_mbs[b-p0] += b_intra; + output_inter[INTRA_MBS] += b_intra; } /* In an I-frame, we've already added the results above in the intra section. */ @@ -690,12 +696,12 @@ static void x264_slicetype_mb_cost( x264_t *h, x264_mb_analysis_t *a, int i_bcost_aq = i_bcost; if( h->param.rc.i_aq_mode ) i_bcost_aq = (i_bcost_aq * fenc->i_inv_qscale_factor[i_mb_xy] + 128) >> 8; - fenc->i_row_satds[b-p0][p1-b][h->mb.i_mb_y] += i_bcost_aq; + output_inter[ROW_SATD] += i_bcost_aq; if( b_frame_score_mb ) { /* Don't use AQ-weighted costs for slicetype decision, only for ratecontrol. */ - fenc->i_cost_est[b-p0][p1-b] += i_bcost; - fenc->i_cost_est_aq[b-p0][p1-b] += i_bcost_aq; + output_inter[COST_EST] += i_bcost; + output_inter[COST_EST_AQ] += i_bcost_aq; } } @@ -708,6 +714,43 @@ static void x264_slicetype_mb_cost( x264_t *h, x264_mb_analysis_t *a, (h->mb.i_mb_width - 2) * (h->mb.i_mb_height - 2) :\ h->mb.i_mb_width * h->mb.i_mb_height) +typedef struct +{ + x264_t *h; + x264_mb_analysis_t *a; + x264_frame_t **frames; + int p0; + int p1; + int b; + int dist_scale_factor; + int *do_search; + const x264_weight_t *w; + int *output_inter; + int *output_intra; +} x264_slicetype_slice_t; + +static void x264_slicetype_slice_cost( x264_slicetype_slice_t *s ) +{ + x264_t *h = s->h; + + /* Lowres lookahead goes backwards because the MVs are used as predictors in the main encode. + * This considerably improves MV prediction overall. */ + + /* The edge mbs seem to reduce the predictive quality of the + * whole frame's score, but are needed for a spatial distribution. */ + int do_edges = h->param.rc.b_mb_tree || h->param.rc.i_vbv_buffer_size || h->mb.i_mb_width <= 2 || h->mb.i_mb_height <= 2; + + int start_y = X264_MIN( h->i_threadslice_end - 1, h->mb.i_mb_height - 2 + do_edges ); + int end_y = X264_MAX( h->i_threadslice_start, 1 - do_edges ); + int start_x = h->mb.i_mb_width - 2 + do_edges; + int end_x = 1 - do_edges; + + for( h->mb.i_mb_y = start_y; h->mb.i_mb_y >= end_y; h->mb.i_mb_y-- ) + for( h->mb.i_mb_x = start_x; h->mb.i_mb_x >= end_x; h->mb.i_mb_x-- ) + x264_slicetype_mb_cost( h, s->a, s->frames, s->p0, s->p1, s->b, s->dist_scale_factor, + s->do_search, s->w, s->output_inter, s->output_intra ); +} + static int x264_slicetype_frame_cost( x264_t *h, x264_mb_analysis_t *a, x264_frame_t **frames, int p0, int p1, int b, int b_intra_penalty ) @@ -715,77 +758,131 @@ static int x264_slicetype_frame_cost( x264_t *h, x264_mb_analysis_t *a, int i_score = 0; int do_search[2]; const x264_weight_t *w = x264_weight_none; + x264_frame_t *fenc = frames[b]; + /* Check whether we already evaluated this frame * If we have tried this frame as P, then we have also tried * the preceding frames as B. (is this still true?) */ /* Also check that we already calculated the row SATDs for the current frame. */ - if( frames[b]->i_cost_est[b-p0][p1-b] >= 0 && (!h->param.rc.i_vbv_buffer_size || frames[b]->i_row_satds[b-p0][p1-b][0] != -1) ) - i_score = frames[b]->i_cost_est[b-p0][p1-b]; + if( fenc->i_cost_est[b-p0][p1-b] >= 0 && (!h->param.rc.i_vbv_buffer_size || fenc->i_row_satds[b-p0][p1-b][0] != -1) ) + i_score = fenc->i_cost_est[b-p0][p1-b]; else { int dist_scale_factor = 128; - int *row_satd = frames[b]->i_row_satds[b-p0][p1-b]; - int *row_satd_intra = frames[b]->i_row_satds[0][0]; /* For each list, check to see whether we have lowres motion-searched this reference frame before. */ - do_search[0] = b != p0 && frames[b]->lowres_mvs[0][b-p0-1][0][0] == 0x7FFF; - do_search[1] = b != p1 && frames[b]->lowres_mvs[1][p1-b-1][0][0] == 0x7FFF; + do_search[0] = b != p0 && fenc->lowres_mvs[0][b-p0-1][0][0] == 0x7FFF; + do_search[1] = b != p1 && fenc->lowres_mvs[1][p1-b-1][0][0] == 0x7FFF; if( do_search[0] ) { if( h->param.analyse.i_weighted_pred && b == p1 ) { x264_emms(); - x264_weights_analyse( h, frames[b], frames[p0], 1 ); - w = frames[b]->weight[0]; + x264_weights_analyse( h, fenc, frames[p0], 1 ); + w = fenc->weight[0]; } - frames[b]->lowres_mvs[0][b-p0-1][0][0] = 0; + fenc->lowres_mvs[0][b-p0-1][0][0] = 0; } - if( do_search[1] ) frames[b]->lowres_mvs[1][p1-b-1][0][0] = 0; + if( do_search[1] ) fenc->lowres_mvs[1][p1-b-1][0][0] = 0; - if( b == p1 ) - frames[b]->i_intra_mbs[b-p0] = 0; - if( !frames[b]->b_intra_calculated ) - { - frames[b]->i_cost_est[0][0] = 0; - frames[b]->i_cost_est_aq[0][0] = 0; - } if( p1 != p0 ) dist_scale_factor = ( ((b-p0) << 8) + ((p1-p0) >> 1) ) / (p1-p0); - frames[b]->i_cost_est[b-p0][p1-b] = 0; - frames[b]->i_cost_est_aq[b-p0][p1-b] = 0; - - /* Lowres lookahead goes backwards because the MVs are used as predictors in the main encode. - * This considerably improves MV prediction overall. */ + int output_buf_size = h->mb.i_mb_height + (NUM_INTS + PAD_SIZE) * h->param.i_lookahead_threads; + int *output_inter[X264_LOOKAHEAD_THREAD_MAX+1]; + int *output_intra[X264_LOOKAHEAD_THREAD_MAX+1]; + output_inter[0] = h->scratch_buffer2; + output_intra[0] = output_inter[0] + output_buf_size; - /* The edge mbs seem to reduce the predictive quality of the - * whole frame's score, but are needed for a spatial distribution. */ - if( h->param.rc.b_mb_tree || h->param.rc.i_vbv_buffer_size || - h->mb.i_mb_width <= 2 || h->mb.i_mb_height <= 2 ) + if( h->param.i_lookahead_threads > 1 ) { - for( h->mb.i_mb_y = h->mb.i_mb_height - 1; h->mb.i_mb_y >= 0; h->mb.i_mb_y-- ) + x264_slicetype_slice_t s[X264_LOOKAHEAD_THREAD_MAX]; + + for( int i = 0; i < h->param.i_lookahead_threads; i++ ) { - row_satd[h->mb.i_mb_y] = 0; - if( !frames[b]->b_intra_calculated ) - row_satd_intra[h->mb.i_mb_y] = 0; - for( h->mb.i_mb_x = h->mb.i_mb_width - 1; h->mb.i_mb_x >= 0; h->mb.i_mb_x-- ) - x264_slicetype_mb_cost( h, a, frames, p0, p1, b, dist_scale_factor, do_search, w ); + x264_t *t = h->lookahead_thread[i]; + + /* FIXME move this somewhere else */ + t->mb.i_me_method = h->mb.i_me_method; + t->mb.i_subpel_refine = h->mb.i_subpel_refine; + t->mb.b_chroma_me = h->mb.b_chroma_me; + + s[i] = (x264_slicetype_slice_t){ t, a, frames, p0, p1, b, dist_scale_factor, do_search, w, + output_inter[i], output_intra[i] }; + + t->i_threadslice_start = ((h->mb.i_mb_height * i + h->param.i_lookahead_threads/2) / h->param.i_lookahead_threads); + t->i_threadslice_end = ((h->mb.i_mb_height * (i+1) + h->param.i_lookahead_threads/2) / h->param.i_lookahead_threads); + + int thread_height = t->i_threadslice_end - t->i_threadslice_start; + int thread_output_size = thread_height + NUM_INTS; + memset( output_inter[i], 0, thread_output_size * sizeof(int) ); + memset( output_intra[i], 0, thread_output_size * sizeof(int) ); + output_inter[i][NUM_ROWS] = output_intra[i][NUM_ROWS] = thread_height; + + output_inter[i+1] = output_inter[i] + thread_output_size + PAD_SIZE; + output_intra[i+1] = output_intra[i] + thread_output_size + PAD_SIZE; + + x264_threadpool_run( h->lookaheadpool, (void*)x264_slicetype_slice_cost, &s[i] ); } + for( int i = 0; i < h->param.i_lookahead_threads; i++ ) + x264_threadpool_wait( h->lookaheadpool, &s[i] ); } else { - for( h->mb.i_mb_y = h->mb.i_mb_height - 2; h->mb.i_mb_y >= 1; h->mb.i_mb_y-- ) - for( h->mb.i_mb_x = h->mb.i_mb_width - 2; h->mb.i_mb_x >= 1; h->mb.i_mb_x-- ) - x264_slicetype_mb_cost( h, a, frames, p0, p1, b, dist_scale_factor, do_search, w ); + h->i_threadslice_start = 0; + h->i_threadslice_end = h->mb.i_mb_height; + memset( output_inter[0], 0, (output_buf_size - PAD_SIZE) * sizeof(int) ); + memset( output_intra[0], 0, (output_buf_size - PAD_SIZE) * sizeof(int) ); + output_inter[0][NUM_ROWS] = output_intra[0][NUM_ROWS] = h->mb.i_mb_height; + x264_slicetype_slice_t s = (x264_slicetype_slice_t){ h, a, frames, p0, p1, b, dist_scale_factor, do_search, w, + output_inter[0], output_intra[0] }; + x264_slicetype_slice_cost( &s ); + } + + /* Sum up accumulators */ + if( b == p1 ) + fenc->i_intra_mbs[b-p0] = 0; + if( !fenc->b_intra_calculated ) + { + fenc->i_cost_est[0][0] = 0; + fenc->i_cost_est_aq[0][0] = 0; } + fenc->i_cost_est[b-p0][p1-b] = 0; + fenc->i_cost_est_aq[b-p0][p1-b] = 0; - i_score = frames[b]->i_cost_est[b-p0][p1-b]; + int *row_satd_inter = fenc->i_row_satds[b-p0][p1-b]; + int *row_satd_intra = fenc->i_row_satds[0][0]; + for( int i = 0; i < h->param.i_lookahead_threads; i++ ) + { + if( b == p1 ) + fenc->i_intra_mbs[b-p0] += output_inter[i][INTRA_MBS]; + if( !fenc->b_intra_calculated ) + { + fenc->i_cost_est[0][0] += output_intra[i][COST_EST]; + fenc->i_cost_est_aq[0][0] += output_intra[i][COST_EST_AQ]; + } + + fenc->i_cost_est[b-p0][p1-b] += output_inter[i][COST_EST]; + fenc->i_cost_est_aq[b-p0][p1-b] += output_inter[i][COST_EST_AQ]; + + if( h->param.rc.i_vbv_buffer_size ) + { + int row_count = output_inter[i][NUM_ROWS]; + memcpy( row_satd_inter, output_inter[i] + NUM_INTS, row_count * sizeof(int) ); + if( !fenc->b_intra_calculated ) + memcpy( row_satd_intra, output_intra[i] + NUM_INTS, row_count * sizeof(int) ); + row_satd_inter += row_count; + row_satd_intra += row_count; + } + } + + i_score = fenc->i_cost_est[b-p0][p1-b]; if( b != p1 ) i_score = (uint64_t)i_score * 100 / (120 + h->param.i_bframe_bias); else - frames[b]->b_intra_calculated = 1; + fenc->b_intra_calculated = 1; - frames[b]->i_cost_est[b-p0][p1-b] = i_score; + fenc->i_cost_est[b-p0][p1-b] = i_score; x264_emms(); } @@ -793,7 +890,7 @@ static int x264_slicetype_frame_cost( x264_t *h, x264_mb_analysis_t *a, { // arbitrary penalty for I-blocks after B-frames int nmb = NUM_MBS; - i_score += (uint64_t)i_score * frames[b]->i_intra_mbs[b-p0] / (nmb * 8); + i_score += (uint64_t)i_score * fenc->i_intra_mbs[b-p0] / (nmb * 8); } return i_score; } @@ -1028,6 +1125,7 @@ static void x264_macroblock_tree( x264_t *h, x264_mb_analysis_t *a, x264_frame_t if( !h->param.rc.i_lookahead ) { + x264_slicetype_frame_cost( h, a, frames, 0, last_nonb, last_nonb, 0 ); x264_macroblock_tree_propagate( h, frames, average_duration, 0, last_nonb, last_nonb, 1 ); XCHG( uint16_t*, frames[last_nonb]->i_propagate_cost, frames[0]->i_propagate_cost ); } @@ -1296,7 +1394,7 @@ static int scenecut( x264_t *h, x264_mb_analysis_t *a, x264_frame_t **frames, in return scenecut_internal( h, a, frames, p0, p1, real_scenecut ); } -void x264_slicetype_analyse( x264_t *h, int keyframe ) +void x264_slicetype_analyse( x264_t *h, int intra_minigop ) { x264_mb_analysis_t a; x264_frame_t *frames[X264_LOOKAHEAD_MAX+3] = { NULL, }; @@ -1305,8 +1403,13 @@ void x264_slicetype_analyse( x264_t *h, int keyframe ) int cost1p0, cost2p0, cost1b1, cost2p1; int i_max_search = X264_MIN( h->lookahead->next.i_size, X264_LOOKAHEAD_MAX ); int vbv_lookahead = h->param.rc.i_vbv_buffer_size && h->param.rc.i_lookahead; + /* For determinism we should limit the search to the number of frames lookahead has for sure + * in h->lookahead->next.list buffer, except at the end of stream. + * For normal calls with (intra_minigop == 0) that is h->lookahead->i_slicetype_length + 1 frames. + * And for I-frame calls (intra_minigop != 0) we already removed intra_minigop frames from there. */ if( h->param.b_deterministic ) - i_max_search = X264_MIN( i_max_search, h->lookahead->i_slicetype_length + !keyframe ); + i_max_search = X264_MIN( i_max_search, h->lookahead->i_slicetype_length + 1 - intra_minigop ); + int keyframe = !!intra_minigop; assert( h->frames.b_have_lowres ); @@ -1554,7 +1657,10 @@ void x264_slicetype_decide( x264_t *h ) if( warn && h->param.b_open_gop ) warn &= frm->i_type != X264_TYPE_I; if( warn ) + { x264_log( h, X264_LOG_WARNING, "specified frame type (%d) at %d is not compatible with keyframe interval\n", frm->i_type, frm->i_frame ); + frm->i_type = h->param.b_open_gop && h->lookahead->i_last_keyframe >= 0 ? X264_TYPE_I : X264_TYPE_IDR; + } } if( frm->i_type == X264_TYPE_I && frm->i_frame - h->lookahead->i_last_keyframe >= h->param.i_keyint_min ) { diff --git a/extras/avxsynth_c.h b/extras/avxsynth_c.h new file mode 100644 index 00000000..2375dd2a --- /dev/null +++ b/extras/avxsynth_c.h @@ -0,0 +1,727 @@ +// Avisynth C Interface Version 0.20 +// Copyright 2003 Kevin Atkinson + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit +// http://www.gnu.org/copyleft/gpl.html . +// +// As a special exception, I give you permission to link to the +// Avisynth C interface with independent modules that communicate with +// the Avisynth C interface solely through the interfaces defined in +// avisynth_c.h, regardless of the license terms of these independent +// modules, and to copy and distribute the resulting combined work +// under terms of your choice, provided that every copy of the +// combined work is accompanied by a complete copy of the source code +// of the Avisynth C interface and Avisynth itself (with the version +// used to produce the combined work), being distributed under the +// terms of the GNU General Public License plus this exception. An +// independent module is a module which is not derived from or based +// on Avisynth C Interface, such as 3rd-party filters, import and +// export plugins, or graphical user interfaces. + +#ifndef __AVXSYNTH_C__ +#define __AVXSYNTH_C__ + +#include "windowsPorts/windows2linux.h" +#include + +#ifdef __cplusplus +# define EXTERN_C extern "C" +#else +# define EXTERN_C +#endif + +#define AVSC_USE_STDCALL 1 + +#ifndef AVSC_USE_STDCALL +# define AVSC_CC __cdecl +#else +# define AVSC_CC __stdcall +#endif + +#define AVSC_INLINE static __inline + +#ifdef AVISYNTH_C_EXPORTS +# define AVSC_EXPORT EXTERN_C +# define AVSC_API(ret, name) EXTERN_C __declspec(dllexport) ret AVSC_CC name +#else +# define AVSC_EXPORT EXTERN_C __declspec(dllexport) +# ifndef AVSC_NO_DECLSPEC +# define AVSC_API(ret, name) EXTERN_C __declspec(dllimport) ret AVSC_CC name +# else +# define AVSC_API(ret, name) typedef ret (AVSC_CC *name##_func) +# endif +#endif + +#ifdef __GNUC__ +typedef long long int INT64; +#else +typedef __int64 INT64; +#endif + + +///////////////////////////////////////////////////////////////////// +// +// Constants +// + +#ifndef __AVXSYNTH_H__ +enum { AVISYNTH_INTERFACE_VERSION = 3 }; +#endif + +enum {AVS_SAMPLE_INT8 = 1<<0, + AVS_SAMPLE_INT16 = 1<<1, + AVS_SAMPLE_INT24 = 1<<2, + AVS_SAMPLE_INT32 = 1<<3, + AVS_SAMPLE_FLOAT = 1<<4}; + +enum {AVS_PLANAR_Y=1<<0, + AVS_PLANAR_U=1<<1, + AVS_PLANAR_V=1<<2, + AVS_PLANAR_ALIGNED=1<<3, + AVS_PLANAR_Y_ALIGNED=AVS_PLANAR_Y|AVS_PLANAR_ALIGNED, + AVS_PLANAR_U_ALIGNED=AVS_PLANAR_U|AVS_PLANAR_ALIGNED, + AVS_PLANAR_V_ALIGNED=AVS_PLANAR_V|AVS_PLANAR_ALIGNED}; + + // Colorspace properties. +enum {AVS_CS_BGR = 1<<28, + AVS_CS_YUV = 1<<29, + AVS_CS_INTERLEAVED = 1<<30, + AVS_CS_PLANAR = 1<<31}; + + // Specific colorformats +enum { + AVS_CS_UNKNOWN = 0, + AVS_CS_BGR24 = 1<<0 | AVS_CS_BGR | AVS_CS_INTERLEAVED, + AVS_CS_BGR32 = 1<<1 | AVS_CS_BGR | AVS_CS_INTERLEAVED, + AVS_CS_YUY2 = 1<<2 | AVS_CS_YUV | AVS_CS_INTERLEAVED, + AVS_CS_YV12 = 1<<3 | AVS_CS_YUV | AVS_CS_PLANAR, // y-v-u, planar + AVS_CS_I420 = 1<<4 | AVS_CS_YUV | AVS_CS_PLANAR, // y-u-v, planar + AVS_CS_IYUV = 1<<4 | AVS_CS_YUV | AVS_CS_PLANAR // same as above +}; + +enum { + AVS_IT_BFF = 1<<0, + AVS_IT_TFF = 1<<1, + AVS_IT_FIELDBASED = 1<<2}; + +enum { + AVS_FILTER_TYPE=1, + AVS_FILTER_INPUT_COLORSPACE=2, + AVS_FILTER_OUTPUT_TYPE=9, + AVS_FILTER_NAME=4, + AVS_FILTER_AUTHOR=5, + AVS_FILTER_VERSION=6, + AVS_FILTER_ARGS=7, + AVS_FILTER_ARGS_INFO=8, + AVS_FILTER_ARGS_DESCRIPTION=10, + AVS_FILTER_DESCRIPTION=11}; + +enum { //SUBTYPES + AVS_FILTER_TYPE_AUDIO=1, + AVS_FILTER_TYPE_VIDEO=2, + AVS_FILTER_OUTPUT_TYPE_SAME=3, + AVS_FILTER_OUTPUT_TYPE_DIFFERENT=4}; + +enum { + AVS_CACHE_NOTHING=0, + AVS_CACHE_RANGE=1, + AVS_CACHE_ALL=2, + AVS_CACHE_AUDIO=3, + AVS_CACHE_AUDIO_NONE=4, + AVS_CACHE_AUDIO_AUTO=5 +}; + +#define AVS_FRAME_ALIGN 16 + +typedef struct AVS_Clip AVS_Clip; +typedef struct AVS_ScriptEnvironment AVS_ScriptEnvironment; + +///////////////////////////////////////////////////////////////////// +// +// AVS_VideoInfo +// + +// AVS_VideoInfo is layed out identicly to VideoInfo +typedef struct AVS_VideoInfo { + int width, height; // width=0 means no video + unsigned fps_numerator, fps_denominator; + int num_frames; + + int pixel_type; + + int audio_samples_per_second; // 0 means no audio + int sample_type; + INT64 num_audio_samples; + int nchannels; + + // Imagetype properties + + int image_type; +} AVS_VideoInfo; + +// useful functions of the above +AVSC_INLINE int avs_has_video(const AVS_VideoInfo * p) + { return (p->width!=0); } + +AVSC_INLINE int avs_has_audio(const AVS_VideoInfo * p) + { return (p->audio_samples_per_second!=0); } + +AVSC_INLINE int avs_is_rgb(const AVS_VideoInfo * p) + { return !!(p->pixel_type&AVS_CS_BGR); } + +AVSC_INLINE int avs_is_rgb24(const AVS_VideoInfo * p) + { return (p->pixel_type&AVS_CS_BGR24)==AVS_CS_BGR24; } // Clear out additional properties + +AVSC_INLINE int avs_is_rgb32(const AVS_VideoInfo * p) + { return (p->pixel_type & AVS_CS_BGR32) == AVS_CS_BGR32 ; } + +AVSC_INLINE int avs_is_yuv(const AVS_VideoInfo * p) + { return !!(p->pixel_type&AVS_CS_YUV ); } + +AVSC_INLINE int avs_is_yuy2(const AVS_VideoInfo * p) + { return (p->pixel_type & AVS_CS_YUY2) == AVS_CS_YUY2; } + +AVSC_INLINE int avs_is_yv12(const AVS_VideoInfo * p) + { return ((p->pixel_type & AVS_CS_YV12) == AVS_CS_YV12)||((p->pixel_type & AVS_CS_I420) == AVS_CS_I420); } + +AVSC_INLINE int avs_is_color_space(const AVS_VideoInfo * p, int c_space) + { return ((p->pixel_type & c_space) == c_space); } + +AVSC_INLINE int avs_is_property(const AVS_VideoInfo * p, int property) + { return ((p->pixel_type & property)==property ); } + +AVSC_INLINE int avs_is_planar(const AVS_VideoInfo * p) + { return !!(p->pixel_type & AVS_CS_PLANAR); } + +AVSC_INLINE int avs_is_field_based(const AVS_VideoInfo * p) + { return !!(p->image_type & AVS_IT_FIELDBASED); } + +AVSC_INLINE int avs_is_parity_known(const AVS_VideoInfo * p) + { return ((p->image_type & AVS_IT_FIELDBASED)&&(p->image_type & (AVS_IT_BFF | AVS_IT_TFF))); } + +AVSC_INLINE int avs_is_bff(const AVS_VideoInfo * p) + { return !!(p->image_type & AVS_IT_BFF); } + +AVSC_INLINE int avs_is_tff(const AVS_VideoInfo * p) + { return !!(p->image_type & AVS_IT_TFF); } + +AVSC_INLINE int avs_bits_per_pixel(const AVS_VideoInfo * p) +{ + switch (p->pixel_type) { + case AVS_CS_BGR24: return 24; + case AVS_CS_BGR32: return 32; + case AVS_CS_YUY2: return 16; + case AVS_CS_YV12: + case AVS_CS_I420: return 12; + default: return 0; + } +} +AVSC_INLINE int avs_bytes_from_pixels(const AVS_VideoInfo * p, int pixels) + { return pixels * (avs_bits_per_pixel(p)>>3); } // Will work on planar images, but will return only luma planes + +AVSC_INLINE int avs_row_size(const AVS_VideoInfo * p) + { return avs_bytes_from_pixels(p,p->width); } // Also only returns first plane on planar images + +AVSC_INLINE int avs_bmp_size(const AVS_VideoInfo * vi) + { if (avs_is_planar(vi)) {int p = vi->height * ((avs_row_size(vi)+3) & ~3); p+=p>>1; return p; } return vi->height * ((avs_row_size(vi)+3) & ~3); } + +AVSC_INLINE int avs_samples_per_second(const AVS_VideoInfo * p) + { return p->audio_samples_per_second; } + + +AVSC_INLINE int avs_bytes_per_channel_sample(const AVS_VideoInfo * p) +{ + switch (p->sample_type) { + case AVS_SAMPLE_INT8: return sizeof(signed char); + case AVS_SAMPLE_INT16: return sizeof(signed short); + case AVS_SAMPLE_INT24: return 3; + case AVS_SAMPLE_INT32: return sizeof(signed int); + case AVS_SAMPLE_FLOAT: return sizeof(float); + default: return 0; + } +} +AVSC_INLINE int avs_bytes_per_audio_sample(const AVS_VideoInfo * p) + { return p->nchannels*avs_bytes_per_channel_sample(p);} + +AVSC_INLINE INT64 avs_audio_samples_from_frames(const AVS_VideoInfo * p, INT64 frames) + { return ((INT64)(frames) * p->audio_samples_per_second * p->fps_denominator / p->fps_numerator); } + +AVSC_INLINE int avs_frames_from_audio_samples(const AVS_VideoInfo * p, INT64 samples) + { return (int)(samples * (INT64)p->fps_numerator / (INT64)p->fps_denominator / (INT64)p->audio_samples_per_second); } + +AVSC_INLINE INT64 avs_audio_samples_from_bytes(const AVS_VideoInfo * p, INT64 bytes) + { return bytes / avs_bytes_per_audio_sample(p); } + +AVSC_INLINE INT64 avs_bytes_from_audio_samples(const AVS_VideoInfo * p, INT64 samples) + { return samples * avs_bytes_per_audio_sample(p); } + +AVSC_INLINE int avs_audio_channels(const AVS_VideoInfo * p) + { return p->nchannels; } + +AVSC_INLINE int avs_sample_type(const AVS_VideoInfo * p) + { return p->sample_type;} + +// useful mutator +AVSC_INLINE void avs_set_property(AVS_VideoInfo * p, int property) + { p->image_type|=property; } + +AVSC_INLINE void avs_clear_property(AVS_VideoInfo * p, int property) + { p->image_type&=~property; } + +AVSC_INLINE void avs_set_field_based(AVS_VideoInfo * p, int isfieldbased) + { if (isfieldbased) p->image_type|=AVS_IT_FIELDBASED; else p->image_type&=~AVS_IT_FIELDBASED; } + +AVSC_INLINE void avs_set_fps(AVS_VideoInfo * p, unsigned numerator, unsigned denominator) +{ + unsigned x=numerator, y=denominator; + while (y) { // find gcd + unsigned t = x%y; x = y; y = t; + } + p->fps_numerator = numerator/x; + p->fps_denominator = denominator/x; +} + +AVSC_INLINE int avs_is_same_colorspace(AVS_VideoInfo * x, AVS_VideoInfo * y) +{ + return (x->pixel_type == y->pixel_type) + || (avs_is_yv12(x) && avs_is_yv12(y)); +} + +///////////////////////////////////////////////////////////////////// +// +// AVS_VideoFrame +// + +// VideoFrameBuffer holds information about a memory block which is used +// for video data. For efficiency, instances of this class are not deleted +// when the refcount reaches zero; instead they're stored in a linked list +// to be reused. The instances are deleted when the corresponding AVS +// file is closed. + +// AVS_VideoFrameBuffer is layed out identicly to VideoFrameBuffer +// DO NOT USE THIS STRUCTURE DIRECTLY +typedef struct AVS_VideoFrameBuffer { + unsigned char * data; + int data_size; + // sequence_number is incremented every time the buffer is changed, so + // that stale views can tell they're no longer valid. + long sequence_number; + + long refcount; +} AVS_VideoFrameBuffer; + +// VideoFrame holds a "window" into a VideoFrameBuffer. + +// AVS_VideoFrame is layed out identicly to IVideoFrame +// DO NOT USE THIS STRUCTURE DIRECTLY +typedef struct AVS_VideoFrame { + int refcount; + AVS_VideoFrameBuffer * vfb; + int offset, pitch, row_size, height, offsetU, offsetV, pitchUV; // U&V offsets are from top of picture. +} AVS_VideoFrame; + +// Access functions for AVS_VideoFrame +AVSC_INLINE int avs_get_pitch(const AVS_VideoFrame * p) { + return p->pitch;} + +AVSC_INLINE int avs_get_pitch_p(const AVS_VideoFrame * p, int plane) { + switch (plane) { + case AVS_PLANAR_U: case AVS_PLANAR_V: return p->pitchUV;} + return p->pitch;} + +AVSC_INLINE int avs_get_row_size(const AVS_VideoFrame * p) { + return p->row_size; } + +AVSC_INLINE int avs_get_row_size_p(const AVS_VideoFrame * p, int plane) { + int r; + switch (plane) { + case AVS_PLANAR_U: case AVS_PLANAR_V: + if (p->pitchUV) return p->row_size>>1; + else return 0; + case AVS_PLANAR_U_ALIGNED: case AVS_PLANAR_V_ALIGNED: + if (p->pitchUV) { + r = ((p->row_size+AVS_FRAME_ALIGN-1)&(~(AVS_FRAME_ALIGN-1)) )>>1; // Aligned rowsize + if (r < p->pitchUV) + return r; + return p->row_size>>1; + } else return 0; + case AVS_PLANAR_Y_ALIGNED: + r = (p->row_size+AVS_FRAME_ALIGN-1)&(~(AVS_FRAME_ALIGN-1)); // Aligned rowsize + if (r <= p->pitch) + return r; + return p->row_size; + } + return p->row_size; +} + +AVSC_INLINE int avs_get_height(const AVS_VideoFrame * p) { + return p->height;} + +AVSC_INLINE int avs_get_height_p(const AVS_VideoFrame * p, int plane) { + switch (plane) { + case AVS_PLANAR_U: case AVS_PLANAR_V: + if (p->pitchUV) return p->height>>1; + return 0; + } + return p->height;} + +AVSC_INLINE const unsigned char* avs_get_read_ptr(const AVS_VideoFrame * p) { + return p->vfb->data + p->offset;} + +AVSC_INLINE const unsigned char* avs_get_read_ptr_p(const AVS_VideoFrame * p, int plane) +{ + switch (plane) { + case AVS_PLANAR_U: return p->vfb->data + p->offsetU; + case AVS_PLANAR_V: return p->vfb->data + p->offsetV; + default: return p->vfb->data + p->offset;} +} + +AVSC_INLINE int avs_is_writable(const AVS_VideoFrame * p) { + return (p->refcount == 1 && p->vfb->refcount == 1);} + +AVSC_INLINE unsigned char* avs_get_write_ptr(const AVS_VideoFrame * p) +{ + if (avs_is_writable(p)) { + ++p->vfb->sequence_number; + return p->vfb->data + p->offset; + } else + return 0; +} + +AVSC_INLINE unsigned char* avs_get_write_ptr_p(const AVS_VideoFrame * p, int plane) +{ + if (plane==AVS_PLANAR_Y && avs_is_writable(p)) { + ++p->vfb->sequence_number; + return p->vfb->data + p->offset; + } else if (plane==AVS_PLANAR_Y) { + return 0; + } else { + switch (plane) { + case AVS_PLANAR_U: return p->vfb->data + p->offsetU; + case AVS_PLANAR_V: return p->vfb->data + p->offsetV; + default: return p->vfb->data + p->offset; + } + } +} + +#if defined __cplusplus +extern "C" +{ +#endif // __cplusplus +AVSC_API(void, avs_release_video_frame)(AVS_VideoFrame *); +// makes a shallow copy of a video frame +AVSC_API(AVS_VideoFrame *, avs_copy_video_frame)(AVS_VideoFrame *); +#if defined __cplusplus +} +#endif // __cplusplus + +#ifndef AVSC_NO_DECLSPEC +AVSC_INLINE void avs_release_frame(AVS_VideoFrame * f) + {avs_release_video_frame(f);} +AVSC_INLINE AVS_VideoFrame * avs_copy_frame(AVS_VideoFrame * f) + {return avs_copy_video_frame(f);} +#endif + +///////////////////////////////////////////////////////////////////// +// +// AVS_Value +// + +// Treat AVS_Value as a fat pointer. That is use avs_copy_value +// and avs_release_value appropiaty as you would if AVS_Value was +// a pointer. + +// To maintain source code compatibility with future versions of the +// avisynth_c API don't use the AVS_Value directly. Use the helper +// functions below. + +// AVS_Value is layed out identicly to AVSValue +typedef struct AVS_Value AVS_Value; +struct AVS_Value { + short type; // 'a'rray, 'c'lip, 'b'ool, 'i'nt, 'f'loat, 's'tring, 'v'oid, or 'l'ong + // for some function e'rror + short array_size; + union { + void * clip; // do not use directly, use avs_take_clip + char boolean; + int integer; + INT64 integer64; // match addition of __int64 to avxplugin.h + float floating_pt; + const char * string; + const AVS_Value * array; + } d; +}; + +// AVS_Value should be initilized with avs_void. +// Should also set to avs_void after the value is released +// with avs_copy_value. Consider it the equalvent of setting +// a pointer to NULL +static const AVS_Value avs_void = {'v'}; + +AVSC_API(void, avs_copy_value)(AVS_Value * dest, AVS_Value src); +AVSC_API(void, avs_release_value)(AVS_Value); + +AVSC_INLINE int avs_defined(AVS_Value v) { return v.type != 'v'; } +AVSC_INLINE int avs_is_clip(AVS_Value v) { return v.type == 'c'; } +AVSC_INLINE int avs_is_bool(AVS_Value v) { return v.type == 'b'; } +AVSC_INLINE int avs_is_int(AVS_Value v) { return v.type == 'i'; } +AVSC_INLINE int avs_is_float(AVS_Value v) { return v.type == 'f' || v.type == 'i'; } +AVSC_INLINE int avs_is_string(AVS_Value v) { return v.type == 's'; } +AVSC_INLINE int avs_is_array(AVS_Value v) { return v.type == 'a'; } +AVSC_INLINE int avs_is_error(AVS_Value v) { return v.type == 'e'; } + +#if defined __cplusplus +extern "C" +{ +#endif // __cplusplus +AVSC_API(AVS_Clip *, avs_take_clip)(AVS_Value, AVS_ScriptEnvironment *); +AVSC_API(void, avs_set_to_clip)(AVS_Value *, AVS_Clip *); +#if defined __cplusplus +} +#endif // __cplusplus + +AVSC_INLINE int avs_as_bool(AVS_Value v) + { return v.d.boolean; } +AVSC_INLINE int avs_as_int(AVS_Value v) + { return v.d.integer; } +AVSC_INLINE const char * avs_as_string(AVS_Value v) + { return avs_is_error(v) || avs_is_string(v) ? v.d.string : 0; } +AVSC_INLINE double avs_as_float(AVS_Value v) + { return avs_is_int(v) ? v.d.integer : v.d.floating_pt; } +AVSC_INLINE const char * avs_as_error(AVS_Value v) + { return avs_is_error(v) ? v.d.string : 0; } +AVSC_INLINE const AVS_Value * avs_as_array(AVS_Value v) + { return v.d.array; } +AVSC_INLINE int avs_array_size(AVS_Value v) + { return avs_is_array(v) ? v.array_size : 1; } +AVSC_INLINE AVS_Value avs_array_elt(AVS_Value v, int index) + { return avs_is_array(v) ? v.d.array[index] : v; } + +// only use these functions on am AVS_Value that does not already have +// an active value. Remember, treat AVS_Value as a fat pointer. +AVSC_INLINE AVS_Value avs_new_value_bool(int v0) + { AVS_Value v; v.type = 'b'; v.d.boolean = v0 == 0 ? 0 : 1; return v; } +AVSC_INLINE AVS_Value avs_new_value_int(int v0) + { AVS_Value v; v.type = 'i'; v.d.integer = v0; return v; } +AVSC_INLINE AVS_Value avs_new_value_string(const char * v0) + { AVS_Value v; v.type = 's'; v.d.string = v0; return v; } +AVSC_INLINE AVS_Value avs_new_value_float(float v0) + { AVS_Value v; v.type = 'f'; v.d.floating_pt = v0; return v;} +AVSC_INLINE AVS_Value avs_new_value_error(const char * v0) + { AVS_Value v; v.type = 'e'; v.d.string = v0; return v; } +#ifndef AVSC_NO_DECLSPEC +AVSC_INLINE AVS_Value avs_new_value_clip(AVS_Clip * v0) + { AVS_Value v; avs_set_to_clip(&v, v0); return v; } +#endif +AVSC_INLINE AVS_Value avs_new_value_array(AVS_Value * v0, int size) + { AVS_Value v; v.type = 'a'; v.d.array = v0; v.array_size = size; return v; } + +///////////////////////////////////////////////////////////////////// +// +// AVS_Clip +// +#if defined __cplusplus +extern "C" +{ +#endif // __cplusplus +AVSC_API(void, avs_release_clip)(AVS_Clip *); +AVSC_API(AVS_Clip *, avs_copy_clip)(AVS_Clip *); + +AVSC_API(const char *, avs_clip_get_error)(AVS_Clip *); // return 0 if no error + +AVSC_API(const AVS_VideoInfo *, avs_get_video_info)(AVS_Clip *); + +AVSC_API(int, avs_get_version)(AVS_Clip *); + +AVSC_API(AVS_VideoFrame *, avs_get_frame)(AVS_Clip *, int n); +// The returned video frame must be released with avs_release_video_frame + +AVSC_API(int, avs_get_parity)(AVS_Clip *, int n); +// return field parity if field_based, else parity of first field in frame + +AVSC_API(int, avs_get_audio)(AVS_Clip *, void * buf, + INT64 start, INT64 count); +// start and count are in samples + +AVSC_API(int, avs_set_cache_hints)(AVS_Clip *, + int cachehints, size_t frame_range); +#if defined __cplusplus +} +#endif // __cplusplus + +// This is the callback type used by avs_add_function +typedef AVS_Value (AVSC_CC * AVS_ApplyFunc) + (AVS_ScriptEnvironment *, AVS_Value args, void * user_data); + +typedef struct AVS_FilterInfo AVS_FilterInfo; +struct AVS_FilterInfo +{ + // these members should not be modified outside of the AVS_ApplyFunc callback + AVS_Clip * child; + AVS_VideoInfo vi; + AVS_ScriptEnvironment * env; + AVS_VideoFrame * (AVSC_CC * get_frame)(AVS_FilterInfo *, int n); + int (AVSC_CC * get_parity)(AVS_FilterInfo *, int n); + int (AVSC_CC * get_audio)(AVS_FilterInfo *, void * buf, + INT64 start, INT64 count); + int (AVSC_CC * set_cache_hints)(AVS_FilterInfo *, int cachehints, + int frame_range); + void (AVSC_CC * free_filter)(AVS_FilterInfo *); + + // Should be set when ever there is an error to report. + // It is cleared before any of the above methods are called + const char * error; + // this is to store whatever and may be modified at will + void * user_data; +}; + +// Create a new filter +// fi is set to point to the AVS_FilterInfo so that you can +// modify it once it is initilized. +// store_child should generally be set to true. If it is not +// set than ALL methods (the function pointers) must be defined +// If it is set than you do not need to worry about freeing the child +// clip. +#if defined __cplusplus +extern "C" +{ +#endif // __cplusplus +AVSC_API(AVS_Clip *, avs_new_c_filter)(AVS_ScriptEnvironment * e, + AVS_FilterInfo * * fi, + AVS_Value child, int store_child); +#if defined __cplusplus +} +#endif // __cplusplus + + +///////////////////////////////////////////////////////////////////// +// +// AVS_ScriptEnvironment +// + +// For GetCPUFlags. These are backwards-compatible with those in VirtualDub. +enum { + /* slowest CPU to support extension */ + AVS_CPU_FORCE = 0x01, // N/A + AVS_CPU_FPU = 0x02, // 386/486DX + AVS_CPU_MMX = 0x04, // P55C, K6, PII + AVS_CPU_INTEGER_SSE = 0x08, // PIII, Athlon + AVS_CPU_SSE = 0x10, // PIII, Athlon XP/MP + AVS_CPU_SSE2 = 0x20, // PIV, Hammer + AVS_CPU_3DNOW = 0x40, // K6-2 + AVS_CPU_3DNOW_EXT = 0x80, // Athlon + AVS_CPU_X86_64 = 0xA0, // Hammer (note: equiv. to 3DNow + SSE2, + // which only Hammer will have anyway) +}; + +#if defined __cplusplus +extern "C" +{ +#endif // __cplusplus +AVSC_API(const char *, avs_get_error)(AVS_ScriptEnvironment *); // return 0 if no error + +AVSC_API(long, avs_get_cpu_flags)(AVS_ScriptEnvironment *); +AVSC_API(int, avs_check_version)(AVS_ScriptEnvironment *, int version); + +AVSC_API(char *, avs_save_string)(AVS_ScriptEnvironment *, const char* s, int length); +AVSC_API(char *, avs_sprintf)(AVS_ScriptEnvironment *, const char * fmt, ...); + +AVSC_API(char *, avs_vsprintf)(AVS_ScriptEnvironment *, const char * fmt, va_list val); + // note: val is really a va_list; I hope everyone typedefs va_list to a pointer + +AVSC_API(int, avs_add_function)(AVS_ScriptEnvironment *, + const char * name, const char * params, + AVS_ApplyFunc apply, void * user_data); + +AVSC_API(int, avs_function_exists)(AVS_ScriptEnvironment *, const char * name); + +AVSC_API(AVS_Value, avs_invoke)(AVS_ScriptEnvironment *, const char * name, + AVS_Value args, const char** arg_names); +// The returned value must be be released with avs_release_value + +AVSC_API(AVS_Value, avs_get_var)(AVS_ScriptEnvironment *, const char* name); +// The returned value must be be released with avs_release_value + +AVSC_API(int, avs_set_var)(AVS_ScriptEnvironment *, const char* name, AVS_Value val); + +AVSC_API(int, avs_set_global_var)(AVS_ScriptEnvironment *, const char* name, const AVS_Value val); + +//void avs_push_context(AVS_ScriptEnvironment *, int level=0); +//void avs_pop_context(AVS_ScriptEnvironment *); + +AVSC_API(AVS_VideoFrame *, avs_new_video_frame_a)(AVS_ScriptEnvironment *, + const AVS_VideoInfo * vi, int align); +// align should be at least 16 +#if defined __cplusplus +} +#endif // __cplusplus + +#ifndef AVSC_NO_DECLSPEC +AVSC_INLINE +AVS_VideoFrame * avs_new_video_frame(AVS_ScriptEnvironment * env, + const AVS_VideoInfo * vi) + {return avs_new_video_frame_a(env,vi,AVS_FRAME_ALIGN);} + +AVSC_INLINE +AVS_VideoFrame * avs_new_frame(AVS_ScriptEnvironment * env, + const AVS_VideoInfo * vi) + {return avs_new_video_frame_a(env,vi,AVS_FRAME_ALIGN);} +#endif + +#if defined __cplusplus +extern "C" +{ +#endif // __cplusplus +AVSC_API(int, avs_make_writable)(AVS_ScriptEnvironment *, AVS_VideoFrame * * pvf); + +AVSC_API(void, avs_bit_blt)(AVS_ScriptEnvironment *, unsigned char* dstp, int dst_pitch, const unsigned char* srcp, int src_pitch, int row_size, int height); + +typedef void (AVSC_CC *AVS_ShutdownFunc)(void* user_data, AVS_ScriptEnvironment * env); +AVSC_API(void, avs_at_exit)(AVS_ScriptEnvironment *, AVS_ShutdownFunc function, void * user_data); + +AVSC_API(AVS_VideoFrame *, avs_subframe)(AVS_ScriptEnvironment *, AVS_VideoFrame * src, int rel_offset, int new_pitch, int new_row_size, int new_height); +// The returned video frame must be be released + +AVSC_API(int, avs_set_memory_max)(AVS_ScriptEnvironment *, int mem); + +AVSC_API(int, avs_set_working_dir)(AVS_ScriptEnvironment *, const char * newdir); + +// avisynth.dll exports this; it's a way to use it as a library, without +// writing an AVS script or without going through AVIFile. +AVSC_API(AVS_ScriptEnvironment *, avs_create_script_environment)(int version); +#if defined __cplusplus +} +#endif // __cplusplus + +// this symbol is the entry point for the plugin and must +// be defined +AVSC_EXPORT +const char * AVSC_CC avisynth_c_plugin_init(AVS_ScriptEnvironment* env); + + +#if defined __cplusplus +extern "C" +{ +#endif // __cplusplus +AVSC_API(void, avs_delete_script_environment)(AVS_ScriptEnvironment *); + + +AVSC_API(AVS_VideoFrame *, avs_subframe_planar)(AVS_ScriptEnvironment *, AVS_VideoFrame * src, int rel_offset, int new_pitch, int new_row_size, int new_height, int rel_offsetU, int rel_offsetV, int new_pitchUV); +// The returned video frame must be be released +#if defined __cplusplus +} +#endif // __cplusplus + +#endif //__AVXSYNTH_C__ diff --git a/extras/windowsPorts/basicDataTypeConversions.h b/extras/windowsPorts/basicDataTypeConversions.h new file mode 100644 index 00000000..b757ee73 --- /dev/null +++ b/extras/windowsPorts/basicDataTypeConversions.h @@ -0,0 +1,85 @@ +#ifndef __DATA_TYPE_CONVERSIONS_H__ +#define __DATA_TYPE_CONVERSIONS_H__ + +#include +#include + +#ifdef __cplusplus +namespace avxsynth { +#endif // __cplusplus + +typedef int64_t __int64; +typedef int32_t __int32; +#ifdef __cplusplus +typedef bool BOOL; +#else +typedef uint32_t BOOL; +#endif // __cplusplus +typedef void* HMODULE; +typedef void* LPVOID; +typedef void* PVOID; +typedef PVOID HANDLE; +typedef HANDLE HWND; +typedef HANDLE HINSTANCE; +typedef void* HDC; +typedef void* HBITMAP; +typedef void* HICON; +typedef void* HFONT; +typedef void* HGDIOBJ; +typedef void* HBRUSH; +typedef void* HMMIO; +typedef void* HACMSTREAM; +typedef void* HACMDRIVER; +typedef void* HIC; +typedef void* HACMOBJ; +typedef HACMSTREAM* LPHACMSTREAM; +typedef void* HACMDRIVERID; +typedef void* LPHACMDRIVER; +typedef unsigned char BYTE; +typedef BYTE* LPBYTE; +typedef char TCHAR; +typedef TCHAR* LPTSTR; +typedef const TCHAR* LPCTSTR; +typedef char* LPSTR; +typedef LPSTR LPOLESTR; +typedef const char* LPCSTR; +typedef LPCSTR LPCOLESTR; +typedef wchar_t WCHAR; +typedef unsigned short WORD; +typedef unsigned int UINT; +typedef UINT MMRESULT; +typedef uint32_t DWORD; +typedef DWORD COLORREF; +typedef DWORD FOURCC; +typedef DWORD HRESULT; +typedef DWORD* LPDWORD; +typedef DWORD* DWORD_PTR; +typedef int32_t LONG; +typedef int32_t* LONG_PTR; +typedef LONG_PTR LRESULT; +typedef uint32_t ULONG; +typedef uint32_t* ULONG_PTR; +//typedef __int64_t intptr_t; +typedef uint64_t _fsize_t; + + +// +// Structures +// + +typedef struct _GUID { + DWORD Data1; + WORD Data2; + WORD Data3; + BYTE Data4[8]; +} GUID; + +typedef GUID REFIID; +typedef GUID CLSID; +typedef CLSID* LPCLSID; +typedef GUID IID; + +#ifdef __cplusplus +}; // namespace avxsynth +#endif // __cplusplus +#endif // __DATA_TYPE_CONVERSIONS_H__ diff --git a/extras/windowsPorts/windows2linux.h b/extras/windowsPorts/windows2linux.h new file mode 100644 index 00000000..fd2948aa --- /dev/null +++ b/extras/windowsPorts/windows2linux.h @@ -0,0 +1,77 @@ +#ifndef __WINDOWS2LINUX_H__ +#define __WINDOWS2LINUX_H__ + +/* + * LINUX SPECIFIC DEFINITIONS +*/ +// +// Data types conversions +// +#include +#include +#include "basicDataTypeConversions.h" + +#ifdef __cplusplus +namespace avxsynth { +#endif // __cplusplus +// +// purposefully define the following MSFT definitions +// to mean nothing (as they do not mean anything on Linux) +// +#define __stdcall +#define __cdecl +#define noreturn +#define __declspec(x) +#define STDAPI extern "C" HRESULT +#define STDMETHODIMP HRESULT __stdcall +#define STDMETHODIMP_(x) x __stdcall + +#define STDMETHOD(x) virtual HRESULT x +#define STDMETHOD_(a, x) virtual a x + +#ifndef TRUE +#define TRUE true +#endif + +#ifndef FALSE +#define FALSE false +#endif + +#define S_OK (0x00000000) +#define S_FALSE (0x00000001) +#define E_NOINTERFACE (0X80004002) +#define E_POINTER (0x80004003) +#define E_FAIL (0x80004005) +#define E_OUTOFMEMORY (0x8007000E) + +#define INVALID_HANDLE_VALUE ((HANDLE)((LONG_PTR)-1)) +#define FAILED(hr) ((hr) & 0x80000000) +#define SUCCEEDED(hr) (!FAILED(hr)) + + +// +// Functions +// +#define MAKEDWORD(a,b,c,d) ((a << 24) | (b << 16) | (c << 8) | (d)) +#define MAKEWORD(a,b) ((a << 8) | (b)) + +#define lstrlen strlen +#define lstrcpy strcpy +#define lstrcmpi strcasecmp +#define _stricmp strcasecmp +#define InterlockedIncrement(x) __sync_fetch_and_add((x), 1) +#define InterlockedDecrement(x) __sync_fetch_and_sub((x), 1) +// Windows uses (new, old) ordering but GCC has (old, new) +#define InterlockedCompareExchange(x,y,z) __sync_val_compare_and_swap(x,z,y) + +#define UInt32x32To64(a, b) ( (uint64_t) ( ((uint64_t)((uint32_t)(a))) * ((uint32_t)(b)) ) ) +#define Int64ShrlMod32(a, b) ( (uint64_t) ( (uint64_t)(a) >> (b) ) ) +#define Int32x32To64(a, b) ((__int64)(((__int64)((long)(a))) * ((long)(b)))) + +#define MulDiv(nNumber, nNumerator, nDenominator) (int32_t) (((int64_t) (nNumber) * (int64_t) (nNumerator) + (int64_t) ((nDenominator)/2)) / (int64_t) (nDenominator)) + +#ifdef __cplusplus +}; // namespace avxsynth +#endif // __cplusplus + +#endif // __WINDOWS2LINUX_H__ diff --git a/filters/filters.c b/filters/filters.c index dbfdf043..bf3dad45 100644 --- a/filters/filters.c +++ b/filters/filters.c @@ -1,7 +1,7 @@ /***************************************************************************** * filters.c: common filter functions ***************************************************************************** - * Copyright (C) 2010-2012 x264 project + * Copyright (C) 2010-2013 x264 project * * Authors: Diogo Franco * Steven Walters diff --git a/filters/filters.h b/filters/filters.h index 30b4500e..b75f3f16 100644 --- a/filters/filters.h +++ b/filters/filters.h @@ -1,7 +1,7 @@ /***************************************************************************** * filters.h: common filter functions ***************************************************************************** - * Copyright (C) 2010-2012 x264 project + * Copyright (C) 2010-2013 x264 project * * Authors: Diogo Franco * Steven Walters diff --git a/filters/video/cache.c b/filters/video/cache.c index b76de039..cc2cef0e 100644 --- a/filters/video/cache.c +++ b/filters/video/cache.c @@ -1,7 +1,7 @@ /***************************************************************************** * cache.c: cache video filter ***************************************************************************** - * Copyright (C) 2010-2012 x264 project + * Copyright (C) 2010-2013 x264 project * * Authors: Steven Walters * diff --git a/filters/video/crop.c b/filters/video/crop.c index b4e2b905..a58813b7 100644 --- a/filters/video/crop.c +++ b/filters/video/crop.c @@ -1,7 +1,7 @@ /***************************************************************************** * crop.c: crop video filter ***************************************************************************** - * Copyright (C) 2010-2012 x264 project + * Copyright (C) 2010-2013 x264 project * * Authors: Steven Walters * James Darnley diff --git a/filters/video/depth.c b/filters/video/depth.c index e01aaae4..a20f3b3f 100644 --- a/filters/video/depth.c +++ b/filters/video/depth.c @@ -1,7 +1,7 @@ /***************************************************************************** * depth.c: bit-depth conversion video filter ***************************************************************************** - * Copyright (C) 2010-2012 x264 project + * Copyright (C) 2010-2013 x264 project * * Authors: Oskar Arvidsson * @@ -50,13 +50,19 @@ static int depth_filter_csp_is_supported( int csp ) csp_mask == X264_CSP_YV16 || csp_mask == X264_CSP_YV24 || csp_mask == X264_CSP_NV12 || - csp_mask == X264_CSP_NV16; + csp_mask == X264_CSP_NV16 || + csp_mask == X264_CSP_BGR || + csp_mask == X264_CSP_RGB || + csp_mask == X264_CSP_BGRA; } static int csp_num_interleaved( int csp, int plane ) { int csp_mask = csp & X264_CSP_MASK; - return ( (csp_mask == X264_CSP_NV12 || csp_mask == X264_CSP_NV16) && plane == 1 ) ? 2 : 1; + return (csp_mask == X264_CSP_NV12 || csp_mask == X264_CSP_NV16) && plane == 1 ? 2 : + csp_mask == X264_CSP_BGR || csp_mask == X264_CSP_RGB ? 3 : + csp_mask == X264_CSP_BGRA ? 4 : + 1; } /* The dithering algorithm is based on Sierra-2-4A error diffusion. It has been @@ -86,6 +92,8 @@ static void dither_plane_##pitch( pixel *dst, int dst_stride, uint16_t *src, int DITHER_PLANE( 1 ) DITHER_PLANE( 2 ) +DITHER_PLANE( 3 ) +DITHER_PLANE( 4 ) static void dither_image( cli_image_t *out, cli_image_t *img, int16_t *error_buf ) { @@ -100,15 +108,28 @@ static void dither_image( cli_image_t *out, cli_image_t *img, int16_t *error_buf dither_plane_##pitch( ((pixel*)out->plane[i])+off, out->stride[i]/sizeof(pixel), \ ((uint16_t*)img->plane[i])+off, img->stride[i]/2, width, height, error_buf ) - if( num_interleaved == 1 ) + if( num_interleaved == 4 ) { - CALL_DITHER_PLANE( 1, 0 ); + CALL_DITHER_PLANE( 4, 0 ); + CALL_DITHER_PLANE( 4, 1 ); + CALL_DITHER_PLANE( 4, 2 ); + CALL_DITHER_PLANE( 4, 3 ); //we probably can skip this one } - else + else if( num_interleaved == 3 ) + { + CALL_DITHER_PLANE( 3, 0 ); + CALL_DITHER_PLANE( 3, 1 ); + CALL_DITHER_PLANE( 3, 2 ); + } + else if( num_interleaved == 2 ) { CALL_DITHER_PLANE( 2, 0 ); CALL_DITHER_PLANE( 2, 1 ); } + else //if( num_interleaved == 1 ) + { + CALL_DITHER_PLANE( 1, 0 ); + } } } diff --git a/filters/video/fix_vfr_pts.c b/filters/video/fix_vfr_pts.c index ab0031b6..80138f17 100644 --- a/filters/video/fix_vfr_pts.c +++ b/filters/video/fix_vfr_pts.c @@ -1,7 +1,7 @@ /***************************************************************************** * fix_vfr_pts.c: vfr pts fixing video filter ***************************************************************************** - * Copyright (C) 2010-2012 x264 project + * Copyright (C) 2010-2013 x264 project * * Authors: Steven Walters * diff --git a/filters/video/internal.c b/filters/video/internal.c index bf48f7c3..c146064c 100644 --- a/filters/video/internal.c +++ b/filters/video/internal.c @@ -1,7 +1,7 @@ /***************************************************************************** * internal.c: video filter utilities ***************************************************************************** - * Copyright (C) 2010-2012 x264 project + * Copyright (C) 2010-2013 x264 project * * Authors: Steven Walters * diff --git a/filters/video/internal.h b/filters/video/internal.h index 7e8c1b23..7d112a0f 100644 --- a/filters/video/internal.h +++ b/filters/video/internal.h @@ -1,7 +1,7 @@ /***************************************************************************** * internal.h: video filter utilities ***************************************************************************** - * Copyright (C) 2010-2012 x264 project + * Copyright (C) 2010-2013 x264 project * * Authors: Steven Walters * diff --git a/filters/video/resize.c b/filters/video/resize.c index 6d8c3e61..197a0e38 100644 --- a/filters/video/resize.c +++ b/filters/video/resize.c @@ -1,7 +1,7 @@ /***************************************************************************** * resize.c: resize video filter ***************************************************************************** - * Copyright (C) 2010-2012 x264 project + * Copyright (C) 2010-2013 x264 project * * Authors: Steven Walters * diff --git a/filters/video/select_every.c b/filters/video/select_every.c index d560ebef..e7c70cee 100644 --- a/filters/video/select_every.c +++ b/filters/video/select_every.c @@ -1,7 +1,7 @@ /***************************************************************************** * select_every.c: select-every video filter ***************************************************************************** - * Copyright (C) 2010-2012 x264 project + * Copyright (C) 2010-2013 x264 project * * Authors: Steven Walters * diff --git a/filters/video/source.c b/filters/video/source.c index c129c0d4..754b9d0a 100644 --- a/filters/video/source.c +++ b/filters/video/source.c @@ -1,7 +1,7 @@ /***************************************************************************** * source.c: source video filter ***************************************************************************** - * Copyright (C) 2010-2012 x264 project + * Copyright (C) 2010-2013 x264 project * * Authors: Steven Walters * diff --git a/filters/video/video.c b/filters/video/video.c index 35b351e4..c6f9e224 100644 --- a/filters/video/video.c +++ b/filters/video/video.c @@ -1,7 +1,7 @@ /***************************************************************************** * video.c: video filters ***************************************************************************** - * Copyright (C) 2010-2012 x264 project + * Copyright (C) 2010-2013 x264 project * * Authors: Steven Walters * diff --git a/filters/video/video.h b/filters/video/video.h index 6913c5a4..41bf277d 100644 --- a/filters/video/video.h +++ b/filters/video/video.h @@ -1,7 +1,7 @@ /***************************************************************************** * video.h: video filters ***************************************************************************** - * Copyright (C) 2010-2012 x264 project + * Copyright (C) 2010-2013 x264 project * * Authors: Steven Walters * diff --git a/input/avs.c b/input/avs.c index bf4d39ad..d237a446 100644 --- a/input/avs.c +++ b/input/avs.c @@ -1,7 +1,7 @@ /***************************************************************************** * avs.c: avisynth input ***************************************************************************** - * Copyright (C) 2009-2012 x264 project + * Copyright (C) 2009-2013 x264 project * * Authors: Steven Walters * @@ -24,12 +24,30 @@ *****************************************************************************/ #include "input.h" +#if USE_AVXSYNTH +#include +#if SYS_MACOSX +#define avs_open dlopen( "libavxsynth.dylib", RTLD_NOW ) +#else +#define avs_open dlopen( "libavxsynth.so", RTLD_NOW ) +#endif +#define avs_close dlclose +#define avs_address dlsym +#else #include +#define avs_open LoadLibrary( "avisynth" ) +#define avs_close FreeLibrary +#define avs_address GetProcAddress +#endif #define FAIL_IF_ERROR( cond, ... ) FAIL_IF_ERR( cond, "avs", __VA_ARGS__ ) #define AVSC_NO_DECLSPEC #undef EXTERN_C +#if USE_AVXSYNTH +#include "extras/avxsynth_c.h" +#else #include "extras/avisynth_c.h" +#endif #define AVSC_DECLARE_FUNC(name) name##_func name /* AVS uses a versioned interface to control backwards compatibility */ @@ -40,12 +58,20 @@ #include #endif +/* AvxSynth doesn't have yv24, yv16, yv411, or y8, so disable them. */ +#if USE_AVXSYNTH +#define avs_is_yv24( vi ) 0 +#define avs_is_yv16( vi ) 0 +#define avs_is_yv411( vi ) 0 +#define avs_is_y8( vi ) 0 +#endif + /* maximum size of the sequence of filters to try on non script files */ #define AVS_MAX_SEQUENCE 5 #define LOAD_AVS_FUNC(name, continue_on_fail)\ {\ - h->func.name = (void*)GetProcAddress( h->library, #name );\ + h->func.name = (void*)avs_address( h->library, #name );\ if( !continue_on_fail && !h->func.name )\ goto fail;\ } @@ -76,7 +102,7 @@ typedef struct /* load the library and functions we require from it */ static int x264_avs_load_library( avs_hnd_t *h ) { - h->library = LoadLibrary( "avisynth" ); + h->library = avs_open; if( !h->library ) return -1; LOAD_AVS_FUNC( avs_clip_get_error, 0 ); @@ -93,7 +119,7 @@ static int x264_avs_load_library( avs_hnd_t *h ) LOAD_AVS_FUNC( avs_take_clip, 0 ); return 0; fail: - FreeLibrary( h->library ); + avs_close( h->library ); return -1; } @@ -101,6 +127,9 @@ static int x264_avs_load_library( avs_hnd_t *h ) static void avs_build_filter_sequence( char *filename_ext, const char *filter[AVS_MAX_SEQUENCE+1] ) { int i = 0; +#if USE_AVXSYNTH + const char *all_purpose[] = { "FFVideoSource", 0 }; +#else const char *all_purpose[] = { "FFmpegSource2", "DSS2", "DirectShowSource", 0 }; if( !strcasecmp( filename_ext, "avi" ) ) filter[i++] = "AVISource"; @@ -108,6 +137,7 @@ static void avs_build_filter_sequence( char *filename_ext, const char *filter[AV filter[i++] = "MPEG2Source"; if( !strcasecmp( filename_ext, "dga" ) ) filter[i++] = "AVCSource"; +#endif for( int j = 0; all_purpose[j] && i < AVS_MAX_SEQUENCE; j++ ) filter[i++] = all_purpose[j]; } @@ -123,6 +153,13 @@ static AVS_Value update_clip( avs_hnd_t *h, const AVS_VideoInfo **vi, AVS_Value static float get_avs_version( avs_hnd_t *h ) { +/* AvxSynth has its version defined starting at 4.0, even though it's based on + AviSynth 2.5.8. This is troublesome for get_avs_version and working around + the new colorspaces in 2.6. So if AvxSynth is detected, explicitly define + the version as 2.58. */ +#if USE_AVXSYNTH + return 2.58f; +#else FAIL_IF_ERROR( !h->func.avs_function_exists( h->env, "VersionNumber" ), "VersionNumber does not exist\n" ) AVS_Value ver = h->func.avs_invoke( h->env, "VersionNumber", avs_new_value_array( NULL, 0 ), NULL ); FAIL_IF_ERROR( avs_is_error( ver ), "unable to determine avisynth version: %s\n", avs_as_error( ver ) ) @@ -130,6 +167,7 @@ static float get_avs_version( avs_hnd_t *h ) float ret = avs_as_float( ver ); h->func.avs_release_value( ver ); return ret; +#endif } static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, cli_input_opt_t *opt ) @@ -219,11 +257,11 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c } #if !HAVE_SWSCALE /* if swscale is not available, convert the CSP if necessary */ + FAIL_IF_ERROR( avs_version < 2.6f && (opt->output_csp == X264_CSP_I422 || opt->output_csp == X264_CSP_I444), + "avisynth >= 2.6 is required for i422/i444 output\n" ) if( (opt->output_csp == X264_CSP_I420 && !avs_is_yv12( vi )) || (opt->output_csp == X264_CSP_I422 && !avs_is_yv16( vi )) || (opt->output_csp == X264_CSP_I444 && !avs_is_yv24( vi )) || (opt->output_csp == X264_CSP_RGB && !avs_is_rgb( vi )) ) { - FAIL_IF_ERROR( avs_version < 2.6f && (opt->output_csp == X264_CSP_I422 || opt->output_csp == X264_CSP_I444), - "avisynth >= 2.6 is required for i422/i444 output\n" ) const char *csp = opt->output_csp == X264_CSP_I420 ? "YV12" : opt->output_csp == X264_CSP_I422 ? "YV16" : @@ -270,6 +308,7 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c opt->input_range = opt->output_range; } #endif + h->func.avs_release_value( res ); info->width = vi->width; @@ -357,7 +396,7 @@ static int close_file( hnd_t handle ) h->func.avs_release_clip( h->clip ); if( h->func.avs_delete_script_environment ) h->func.avs_delete_script_environment( h->env ); - FreeLibrary( h->library ); + avs_close( h->library ); free( h ); return 0; } diff --git a/input/ffms.c b/input/ffms.c index 03d786ea..1a067780 100644 --- a/input/ffms.c +++ b/input/ffms.c @@ -1,7 +1,7 @@ /***************************************************************************** * ffms.c: ffmpegsource input ***************************************************************************** - * Copyright (C) 2009-2012 x264 project + * Copyright (C) 2009-2013 x264 project * * Authors: Mike Gurlitz * Steven Walters diff --git a/input/input.c b/input/input.c index 4cac01c2..9c6763d2 100644 --- a/input/input.c +++ b/input/input.c @@ -1,7 +1,7 @@ /***************************************************************************** * input.c: common input functions ***************************************************************************** - * Copyright (C) 2010-2012 x264 project + * Copyright (C) 2010-2013 x264 project * * Authors: Steven Walters * diff --git a/input/input.h b/input/input.h index f281d7e9..5137be31 100644 --- a/input/input.h +++ b/input/input.h @@ -1,7 +1,7 @@ /***************************************************************************** * input.h: file input ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Laurent Aimar * Loren Merritt diff --git a/input/lavf.c b/input/lavf.c index b3b7fc6f..e36632df 100644 --- a/input/lavf.c +++ b/input/lavf.c @@ -1,7 +1,7 @@ /***************************************************************************** * lavf.c: libavformat input ***************************************************************************** - * Copyright (C) 2009-2012 x264 project + * Copyright (C) 2009-2013 x264 project * * Authors: Mike Gurlitz * Steven Walters @@ -28,12 +28,14 @@ #define FAIL_IF_ERROR( cond, ... ) FAIL_IF_ERR( cond, "lavf", __VA_ARGS__ ) #undef DECLARE_ALIGNED #include +#include #include #include typedef struct { AVFormatContext *lavf; + AVFrame *frame; int stream_id; int next_frame; int vfr_input; @@ -80,8 +82,8 @@ static int read_frame_internal( cli_pic_t *p_pic, lavf_hnd_t *h, int i_frame, vi AVCodecContext *c = h->lavf->streams[h->stream_id]->codec; AVPacket *pkt = p_pic->opaque; - AVFrame frame; - avcodec_get_frame_defaults( &frame ); + + avcodec_get_frame_defaults( h->frame ); while( i_frame >= h->next_frame ) { @@ -97,7 +99,7 @@ static int read_frame_internal( cli_pic_t *p_pic, lavf_hnd_t *h, int i_frame, vi pkt->size = 0; c->reordered_opaque = pkt->pts; - if( avcodec_decode_video2( c, &frame, &finished, pkt ) < 0 ) + if( avcodec_decode_video2( c, h->frame, &finished, pkt ) < 0 ) x264_cli_log( "lavf", X264_LOG_WARNING, "video decoding failed on frame %d\n", h->next_frame ); } /* if the packet successfully decoded but the data from it is not desired, free it */ @@ -111,8 +113,8 @@ static int read_frame_internal( cli_pic_t *p_pic, lavf_hnd_t *h, int i_frame, vi h->next_frame++; } - memcpy( p_pic->img.stride, frame.linesize, sizeof(p_pic->img.stride) ); - memcpy( p_pic->img.plane, frame.data, sizeof(p_pic->img.plane) ); + memcpy( p_pic->img.stride, h->frame->linesize, sizeof(p_pic->img.stride) ); + memcpy( p_pic->img.plane, h->frame->data, sizeof(p_pic->img.plane) ); int is_fullrange = 0; p_pic->img.width = c->width; p_pic->img.height = c->height; @@ -121,15 +123,15 @@ static int read_frame_internal( cli_pic_t *p_pic, lavf_hnd_t *h, int i_frame, vi if( info ) { info->fullrange = is_fullrange; - info->interlaced = frame.interlaced_frame; - info->tff = frame.top_field_first; + info->interlaced = h->frame->interlaced_frame; + info->tff = h->frame->top_field_first; } if( h->vfr_input ) { p_pic->pts = p_pic->duration = 0; - if( c->has_b_frames && frame.reordered_opaque != AV_NOPTS_VALUE ) - p_pic->pts = frame.reordered_opaque; + if( c->has_b_frames && h->frame->reordered_opaque != AV_NOPTS_VALUE ) + p_pic->pts = h->frame->reordered_opaque; else if( pkt->dts != AV_NOPTS_VALUE ) p_pic->pts = pkt->dts; // for AVI files else if( info ) @@ -151,6 +153,10 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c if( !strcmp( psz_filename, "-" ) ) psz_filename = "pipe:"; + h->frame = avcodec_alloc_frame(); + if( !h->frame ) + return -1; + /* if resolution was passed in, place it and colorspace into options. this allows raw video support */ AVDictionary *options = NULL; if( opt->resolution ) @@ -245,7 +251,12 @@ static int close_file( hnd_t handle ) { lavf_hnd_t *h = handle; avcodec_close( h->lavf->streams[h->stream_id]->codec ); - av_close_input_file( h->lavf ); + avformat_close_input( &h->lavf ); +#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 28, 0) + avcodec_free_frame( &h->frame ); +#else + av_freep( &h->frame ); +#endif free( h ); return 0; } diff --git a/input/raw.c b/input/raw.c index a9b2de1a..e853dd0a 100644 --- a/input/raw.c +++ b/input/raw.c @@ -1,7 +1,7 @@ /***************************************************************************** * raw.c: raw input ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Laurent Aimar * Loren Merritt diff --git a/input/thread.c b/input/thread.c index 74474892..9cb422a1 100644 --- a/input/thread.c +++ b/input/thread.c @@ -1,7 +1,7 @@ /***************************************************************************** * thread.c: threaded input ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Laurent Aimar * Loren Merritt diff --git a/input/timecode.c b/input/timecode.c index f7da8fb5..a476e5d4 100644 --- a/input/timecode.c +++ b/input/timecode.c @@ -1,7 +1,7 @@ /***************************************************************************** * timecode.c: timecode file input ***************************************************************************** - * Copyright (C) 2010-2012 x264 project + * Copyright (C) 2010-2013 x264 project * * Authors: Yusuke Nakamura * diff --git a/input/y4m.c b/input/y4m.c index 6f37b0e8..009afa6d 100644 --- a/input/y4m.c +++ b/input/y4m.c @@ -1,7 +1,7 @@ /***************************************************************************** * y4m.c: y4m input ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Laurent Aimar * Loren Merritt @@ -35,6 +35,7 @@ typedef struct int frame_header_len; uint64_t frame_size; uint64_t plane_size[3]; + int bit_depth; } y4m_hnd_t; #define Y4M_MAGIC "YUV4MPEG2" @@ -42,15 +43,23 @@ typedef struct #define Y4M_FRAME_MAGIC "FRAME" #define MAX_FRAME_HEADER 80 -static int csp_string_to_int( char *csp_name ) +static int parse_csp_and_depth( char *csp_name, int *bit_depth ) { - int csp = X264_CSP_MAX; + int csp = X264_CSP_MAX; + *bit_depth = 8; + + /* Set colorspace from known variants */ if( !strncmp( "420", csp_name, 3 ) ) csp = X264_CSP_I420; else if( !strncmp( "422", csp_name, 3 ) ) csp = X264_CSP_I422; else if( !strncmp( "444", csp_name, 3 ) && strncmp( "444alpha", csp_name, 8 ) ) // only accept alphaless 4:4:4 csp = X264_CSP_I444; + + /* Set high bit depth from known extensions */ + if( !strncmp( "p", csp_name + 3, 1 ) ) + *bit_depth = strtol( csp_name + 4, NULL, 10 ); + return csp; } @@ -63,6 +72,7 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c char *tokend, *header_end; int colorspace = X264_CSP_NONE; int alt_colorspace = X264_CSP_NONE; + int alt_bit_depth = 8; if( !h ) return -1; @@ -112,7 +122,7 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c tokstart=tokend; break; case 'C': /* Color space */ - colorspace = csp_string_to_int( tokstart ); + colorspace = parse_csp_and_depth( tokstart, &h->bit_depth ); tokstart = strchr( tokstart, 0x20 ); break; case 'I': /* Interlace type */ @@ -159,7 +169,7 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c { /* Older nonstandard pixel format representation */ tokstart += 6; - alt_colorspace = csp_string_to_int( tokstart ); + alt_colorspace = parse_csp_and_depth( tokstart, &alt_bit_depth ); } tokstart = strchr( tokstart, 0x20 ); break; @@ -167,22 +177,37 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c } if( colorspace == X264_CSP_NONE ) - colorspace = alt_colorspace; + { + colorspace = alt_colorspace; + h->bit_depth = alt_bit_depth; + } - // default to 4:2:0 if nothing is specified + // default to 8bit 4:2:0 if nothing is specified if( colorspace == X264_CSP_NONE ) - colorspace = X264_CSP_I420; + { + colorspace = X264_CSP_I420; + h->bit_depth = 8; + } FAIL_IF_ERROR( colorspace <= X264_CSP_NONE || colorspace >= X264_CSP_MAX, "colorspace unhandled\n" ) + FAIL_IF_ERROR( h->bit_depth < 8 || h->bit_depth > 16, "unsupported bit depth `%d'\n", h->bit_depth ); info->thread_safe = 1; info->num_frames = 0; info->csp = colorspace; h->frame_size = h->frame_header_len; - for( i = 0; i < x264_cli_csps[info->csp].planes; i++ ) + + if( h->bit_depth > 8 ) + info->csp |= X264_CSP_HIGH_DEPTH; + + const x264_cli_csp_t *csp = x264_cli_get_csp( info->csp ); + + for( i = 0; i < csp->planes; i++ ) { h->plane_size[i] = x264_cli_pic_plane_size( info->csp, info->width, info->height, i ); h->frame_size += h->plane_size[i]; + /* x264_cli_pic_plane_size returns the size in bytes, we need the value in pixels from here on */ + h->plane_size[i] /= x264_cli_csp_depth_factor( info->csp ); } /* Most common case: frame_header = "FRAME" */ @@ -202,6 +227,7 @@ static int open_file( char *psz_filename, hnd_t *p_handle, video_info_t *info, c static int read_frame_internal( cli_pic_t *pic, y4m_hnd_t *h ) { size_t slen = strlen( Y4M_FRAME_MAGIC ); + int pixel_depth = x264_cli_csp_depth_factor( pic->img.csp ); int i = 0; char header[16]; @@ -222,7 +248,19 @@ static int read_frame_internal( cli_pic_t *pic, y4m_hnd_t *h ) int error = 0; for( i = 0; i < pic->img.planes && !error; i++ ) - error |= fread( pic->img.plane[i], h->plane_size[i], 1, h->fh ) <= 0; + { + error |= fread( pic->img.plane[i], pixel_depth, h->plane_size[i], h->fh ) != h->plane_size[i]; + if( h->bit_depth & 7 ) + { + /* upconvert non 16bit high depth planes to 16bit using the same + * algorithm as used in the depth filter. */ + uint16_t *plane = (uint16_t*)pic->img.plane[i]; + uint64_t pixel_count = h->plane_size[i]; + int lshift = 16 - h->bit_depth; + for( uint64_t j = 0; j < pixel_count; j++ ) + plane[j] = plane[j] << lshift; + } + } return error; } diff --git a/output/flv.c b/output/flv.c index e9f2276a..6f972f74 100644 --- a/output/flv.c +++ b/output/flv.c @@ -1,7 +1,7 @@ /***************************************************************************** * flv.c: flv muxer ***************************************************************************** - * Copyright (C) 2009-2012 x264 project + * Copyright (C) 2009-2013 x264 project * * Authors: Kieran Kunhya * diff --git a/output/flv_bytestream.c b/output/flv_bytestream.c index 57d40dae..44c19238 100644 --- a/output/flv_bytestream.c +++ b/output/flv_bytestream.c @@ -1,7 +1,7 @@ /***************************************************************************** * flv_bytestream.c: flv muxer utilities ***************************************************************************** - * Copyright (C) 2009-2012 x264 project + * Copyright (C) 2009-2013 x264 project * * Authors: Kieran Kunhya * diff --git a/output/flv_bytestream.h b/output/flv_bytestream.h index 9b5da3c1..325abb61 100644 --- a/output/flv_bytestream.h +++ b/output/flv_bytestream.h @@ -1,7 +1,7 @@ /***************************************************************************** * flv_bytestream.h: flv muxer utilities ***************************************************************************** - * Copyright (C) 2009-2012 x264 project + * Copyright (C) 2009-2013 x264 project * * Authors: Kieran Kunhya * diff --git a/output/matroska.c b/output/matroska.c index 94a4b0f8..9b832845 100644 --- a/output/matroska.c +++ b/output/matroska.c @@ -1,7 +1,7 @@ /***************************************************************************** * matroska.c: matroska muxer ***************************************************************************** - * Copyright (C) 2005-2012 x264 project + * Copyright (C) 2005-2013 x264 project * * Authors: Mike Matsnev * diff --git a/output/matroska_ebml.c b/output/matroska_ebml.c index f58d47de..2f41a2d1 100644 --- a/output/matroska_ebml.c +++ b/output/matroska_ebml.c @@ -1,7 +1,7 @@ /***************************************************************************** * matroska_ebml.c: matroska muxer utilities ***************************************************************************** - * Copyright (C) 2005-2012 x264 project + * Copyright (C) 2005-2013 x264 project * * Authors: Mike Matsnev * diff --git a/output/matroska_ebml.h b/output/matroska_ebml.h index f3d43c01..fa61eded 100644 --- a/output/matroska_ebml.h +++ b/output/matroska_ebml.h @@ -1,7 +1,7 @@ /***************************************************************************** * matroska_ebml.h: matroska muxer utilities ***************************************************************************** - * Copyright (C) 2005-2012 x264 project + * Copyright (C) 2005-2013 x264 project * * Authors: Mike Matsnev * diff --git a/output/mp4.c b/output/mp4.c index 7f123657..ee54e66f 100644 --- a/output/mp4.c +++ b/output/mp4.c @@ -1,7 +1,7 @@ /***************************************************************************** * mp4.c: mp4 muxer ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Laurent Aimar * Loren Merritt @@ -207,8 +207,8 @@ static int set_param( hnd_t handle, x264_param_t *p_param ) p_mp4->i_delay_frames = p_param->i_bframe ? (p_param->i_bframe_pyramid ? 2 : 1) : 0; p_mp4->i_dts_compress_multiplier = p_mp4->b_dts_compress * p_mp4->i_delay_frames + 1; - p_mp4->i_time_res = p_param->i_timebase_den * p_mp4->i_dts_compress_multiplier; - p_mp4->i_time_inc = p_param->i_timebase_num * p_mp4->i_dts_compress_multiplier; + p_mp4->i_time_res = (uint64_t)p_param->i_timebase_den * p_mp4->i_dts_compress_multiplier; + p_mp4->i_time_inc = (uint64_t)p_param->i_timebase_num * p_mp4->i_dts_compress_multiplier; FAIL_IF_ERR( p_mp4->i_time_res > UINT32_MAX, "mp4", "MP4 media timescale %"PRIu64" exceeds maximum\n", p_mp4->i_time_res ) p_mp4->i_track = gf_isom_new_track( p_mp4->p_file, 0, GF_ISOM_MEDIA_VISUAL, diff --git a/output/output.h b/output/output.h index d48f45cc..e32dbbea 100644 --- a/output/output.h +++ b/output/output.h @@ -1,7 +1,7 @@ /***************************************************************************** * output.h: x264 file output modules ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Laurent Aimar * Loren Merritt diff --git a/output/raw.c b/output/raw.c index ed3174cd..d8ed3a98 100644 --- a/output/raw.c +++ b/output/raw.c @@ -1,7 +1,7 @@ /***************************************************************************** * raw.c: raw muxer ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Laurent Aimar * Loren Merritt diff --git a/tools/checkasm-a.asm b/tools/checkasm-a.asm index 47a4f65e..7b39d93c 100644 --- a/tools/checkasm-a.asm +++ b/tools/checkasm-a.asm @@ -1,7 +1,7 @@ ;***************************************************************************** ;* checkasm-a.asm: assembly check tool ;***************************************************************************** -;* Copyright (C) 2008-2012 x264 project +;* Copyright (C) 2008-2013 x264 project ;* ;* Authors: Loren Merritt ;* Henrik Gramner @@ -199,7 +199,7 @@ cglobal checkasm_call, 1,7 mov dword [r1], 0 mov eax, r3 .ok: - RET + REP_RET %endif ; ARCH_X86_64 diff --git a/tools/checkasm.c b/tools/checkasm.c index 630a01d4..9135b70b 100644 --- a/tools/checkasm.c +++ b/tools/checkasm.c @@ -1,7 +1,7 @@ /***************************************************************************** * checkasm.c: assembly check tool ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Loren Merritt * Laurent Aimar @@ -164,6 +164,8 @@ static void print_bench(void) if( k < j ) continue; printf( "%s_%s%s: %"PRId64"\n", benchs[i].name, +#if HAVE_MMX + b->cpu&X264_CPU_AVX2 && b->cpu&X264_CPU_FMA3 ? "avx2_fma3" : b->cpu&X264_CPU_AVX2 ? "avx2" : b->cpu&X264_CPU_FMA3 ? "fma3" : b->cpu&X264_CPU_FMA4 ? "fma4" : @@ -175,21 +177,30 @@ static void print_bench(void) /* print sse2slow only if there's also a sse2fast version of the same func */ b->cpu&X264_CPU_SSE2_IS_SLOW && jcpu&X264_CPU_SSE2 ? "sse2" : + b->cpu&X264_CPU_SSE ? "sse" : b->cpu&X264_CPU_MMX ? "mmx" : +#elif ARCH_PPC b->cpu&X264_CPU_ALTIVEC ? "altivec" : +#elif ARCH_ARM b->cpu&X264_CPU_NEON ? "neon" : - b->cpu&X264_CPU_ARMV6 ? "armv6" : "c", + b->cpu&X264_CPU_ARMV6 ? "armv6" : +#endif + "c", +#if HAVE_MMX b->cpu&X264_CPU_CACHELINE_32 ? "_c32" : + b->cpu&X264_CPU_SLOW_ATOM && b->cpu&X264_CPU_CACHELINE_64 ? "_c64_atom" : b->cpu&X264_CPU_CACHELINE_64 ? "_c64" : - b->cpu&X264_CPU_SHUFFLE_IS_FAST && !(b->cpu&X264_CPU_SSE4) ? "_fastshuffle" : + b->cpu&X264_CPU_SLOW_SHUFFLE ? "_slowshuffle" : b->cpu&X264_CPU_SSE_MISALIGN ? "_misalign" : b->cpu&X264_CPU_LZCNT ? "_lzcnt" : b->cpu&X264_CPU_BMI2 ? "_bmi2" : - b->cpu&X264_CPU_TBM ? "_tbm" : b->cpu&X264_CPU_BMI1 ? "_bmi1" : - b->cpu&X264_CPU_FAST_NEON_MRC ? "_fast_mrc" : b->cpu&X264_CPU_SLOW_CTZ ? "_slow_ctz" : - b->cpu&X264_CPU_SLOW_ATOM ? "_slow_atom" : "", + b->cpu&X264_CPU_SLOW_ATOM ? "_atom" : +#elif ARCH_ARM + b->cpu&X264_CPU_FAST_NEON_MRC ? "_fast_mrc" : +#endif + "", ((int64_t)10*b->cycles/b->den - nop_time)/4 ); } } @@ -336,6 +347,43 @@ static int check_pixel( int cpu_ref, int cpu_new ) TEST_PIXEL( satd, 0 ); TEST_PIXEL( sa8d, 1 ); + ok = 1, used_asm = 0; + if( pixel_asm.sa8d_satd[PIXEL_16x16] != pixel_ref.sa8d_satd[PIXEL_16x16] ) + { + set_func_name( "sa8d_satd_%s", pixel_names[PIXEL_16x16] ); + used_asm = 1; + for( int j = 0; j < 64; j++ ) + { + uint32_t cost8_c = pixel_c.sa8d[PIXEL_16x16]( pbuf1, 16, pbuf2, 64 ); + uint32_t cost4_c = pixel_c.satd[PIXEL_16x16]( pbuf1, 16, pbuf2, 64 ); + uint64_t res_a = call_a( pixel_asm.sa8d_satd[PIXEL_16x16], pbuf1, (intptr_t)16, pbuf2, (intptr_t)64 ); + uint32_t cost8_a = res_a; + uint32_t cost4_a = res_a >> 32; + if( cost8_a != cost8_c || cost4_a != cost4_c ) + { + ok = 0; + fprintf( stderr, "sa8d_satd [%d]: (%d,%d) != (%d,%d) [FAILED]\n", PIXEL_16x16, + cost8_c, cost4_c, cost8_a, cost4_a ); + break; + } + } + for( int j = 0; j < 0x1000 && ok; j += 256 ) \ + { + uint32_t cost8_c = pixel_c.sa8d[PIXEL_16x16]( pbuf3+j, 16, pbuf4+j, 16 ); + uint32_t cost4_c = pixel_c.satd[PIXEL_16x16]( pbuf3+j, 16, pbuf4+j, 16 ); + uint64_t res_a = pixel_asm.sa8d_satd[PIXEL_16x16]( pbuf3+j, 16, pbuf4+j, 16 ); + uint32_t cost8_a = res_a; + uint32_t cost4_a = res_a >> 32; + if( cost8_a != cost8_c || cost4_a != cost4_c ) + { + ok = 0; + fprintf( stderr, "sa8d_satd [%d]: overflow (%d,%d) != (%d,%d) [FAILED]\n", PIXEL_16x16, + cost8_c, cost4_c, cost8_a, cost4_a ); + } + } + } + report( "pixel sa8d_satd :" ); + #define TEST_PIXEL_X( N ) \ ok = 1; used_asm = 0; \ for( int i = 0; i < 7; i++ ) \ @@ -475,6 +523,21 @@ static int check_pixel( int cpu_ref, int cpu_new ) } report( "pixel vsad :" ); + ok = 1; used_asm = 0; + if( pixel_asm.asd8 != pixel_ref.asd8 ) + { + set_func_name( "asd8" ); + used_asm = 1; + int res_c = call_c( pixel_c.asd8, pbuf1, (intptr_t)8, pbuf2, (intptr_t)8, 16 ); + int res_a = call_a( pixel_asm.asd8, pbuf1, (intptr_t)8, pbuf2, (intptr_t)8, 16 ); + if( res_c != res_a ) + { + ok = 0; + fprintf( stderr, "asd: %d != %d\n", res_c, res_a ); + } + } + report( "pixel asd :" ); + #define TEST_INTRA_X3( name, i8x8, ... ) \ if( pixel_asm.name && pixel_asm.name != pixel_ref.name ) \ { \ @@ -1715,23 +1778,23 @@ static int check_quant( int cpu_ref, int cpu_new ) x264_quant_init( h, cpu_ref, &qf_ref ); x264_quant_init( h, cpu_new, &qf_a ); -#define INIT_QUANT8(j) \ +#define INIT_QUANT8(j,max) \ { \ static const int scale1d[8] = {32,31,24,31,32,31,24,31}; \ - for( int i = 0; i < 64; i++ ) \ + for( int i = 0; i < max; i++ ) \ { \ - unsigned int scale = (255*scale1d[i>>3]*scale1d[i&7])/16; \ - dct1[i] = dct2[i] = j ? (rand()%(2*scale+1))-scale : 0; \ + unsigned int scale = (255*scale1d[(i>>3)&7]*scale1d[i&7])/16; \ + dct1[i] = dct2[i] = (j>>(i>>6))&1 ? (rand()%(2*scale+1))-scale : 0; \ } \ } -#define INIT_QUANT4(j) \ +#define INIT_QUANT4(j,max) \ { \ static const int scale1d[4] = {4,6,4,6}; \ - for( int i = 0; i < 16; i++ ) \ + for( int i = 0; i < max; i++ ) \ { \ - unsigned int scale = 255*scale1d[i>>2]*scale1d[i&3]; \ - dct1[i] = dct2[i] = j ? (rand()%(2*scale+1))-scale : 0; \ + unsigned int scale = 255*scale1d[(i>>2)&3]*scale1d[i&3]; \ + dct1[i] = dct2[i] = (j>>(i>>4))&1 ? (rand()%(2*scale+1))-scale : 0; \ } \ } @@ -1761,34 +1824,36 @@ static int check_quant( int cpu_ref, int cpu_new ) } \ } -#define TEST_QUANT( qname, block, w ) \ +#define TEST_QUANT( qname, block, type, w, maxj ) \ if( qf_a.qname != qf_ref.qname ) \ { \ set_func_name( #qname ); \ used_asms[0] = 1; \ for( int qp = h->param.rc.i_qp_max; qp >= h->param.rc.i_qp_min; qp-- ) \ { \ - for( int j = 0; j < 2; j++ ) \ + for( int j = 0; j < maxj; j++ ) \ { \ - INIT_QUANT##w(j) \ - int result_c = call_c1( qf_c.qname, dct1, h->quant##w##_mf[block][qp], h->quant##w##_bias[block][qp] ); \ - int result_a = call_a1( qf_a.qname, dct2, h->quant##w##_mf[block][qp], h->quant##w##_bias[block][qp] ); \ + INIT_QUANT##type(j, w*w) \ + int result_c = call_c1( qf_c.qname, (void*)dct1, h->quant##type##_mf[block][qp], h->quant##type##_bias[block][qp] ); \ + int result_a = call_a1( qf_a.qname, (void*)dct2, h->quant##type##_mf[block][qp], h->quant##type##_bias[block][qp] ); \ if( memcmp( dct1, dct2, w*w*sizeof(dctcoef) ) || result_c != result_a ) \ { \ oks[0] = 0; \ fprintf( stderr, #qname "(qp=%d, cqm=%d, block="#block"): [FAILED]\n", qp, i_cqm ); \ break; \ } \ - call_c2( qf_c.qname, dct1, h->quant##w##_mf[block][qp], h->quant##w##_bias[block][qp] ); \ - call_a2( qf_a.qname, dct2, h->quant##w##_mf[block][qp], h->quant##w##_bias[block][qp] ); \ + call_c2( qf_c.qname, (void*)dct1, h->quant##type##_mf[block][qp], h->quant##type##_bias[block][qp] ); \ + call_a2( qf_a.qname, (void*)dct2, h->quant##type##_mf[block][qp], h->quant##type##_bias[block][qp] ); \ } \ } \ } - TEST_QUANT( quant_8x8, CQM_8IY, 8 ); - TEST_QUANT( quant_8x8, CQM_8PY, 8 ); - TEST_QUANT( quant_4x4, CQM_4IY, 4 ); - TEST_QUANT( quant_4x4, CQM_4PY, 4 ); + TEST_QUANT( quant_8x8, CQM_8IY, 8, 8, 2 ); + TEST_QUANT( quant_8x8, CQM_8PY, 8, 8, 2 ); + TEST_QUANT( quant_4x4, CQM_4IY, 4, 4, 2 ); + TEST_QUANT( quant_4x4, CQM_4PY, 4, 4, 2 ); + TEST_QUANT( quant_4x4x4, CQM_4IY, 4, 8, 16 ); + TEST_QUANT( quant_4x4x4, CQM_4PY, 4, 8, 16 ); TEST_QUANT_DC( quant_4x4_dc, **h->quant4_mf[CQM_4IY] ); TEST_QUANT_DC( quant_2x2_dc, **h->quant4_mf[CQM_4IC] ); @@ -1799,7 +1864,7 @@ static int check_quant( int cpu_ref, int cpu_new ) used_asms[1] = 1; \ for( int qp = h->param.rc.i_qp_max; qp >= h->param.rc.i_qp_min; qp-- ) \ { \ - INIT_QUANT##w(1) \ + INIT_QUANT##w(1, w*w) \ qf_c.qname( dct1, h->quant##w##_mf[block][qp], h->quant##w##_bias[block][qp] ); \ memcpy( dct2, dct1, w*w*sizeof(dctcoef) ); \ call_c1( qf_c.dqname, dct1, h->dequant##w##_mf[block], qp ); \ @@ -2378,18 +2443,18 @@ static int check_all_flags( void ) ret |= add_flags( &cpu0, &cpu1, X264_CPU_SLOW_CTZ, "MMX SlowCTZ" ); cpu1 &= ~X264_CPU_SLOW_CTZ; } + if( x264_cpu_detect() & X264_CPU_SSE ) + ret |= add_flags( &cpu0, &cpu1, X264_CPU_SSE, "SSE" ); if( x264_cpu_detect() & X264_CPU_SSE2 ) { - ret |= add_flags( &cpu0, &cpu1, X264_CPU_SSE | X264_CPU_SSE2 | X264_CPU_SSE2_IS_SLOW, "SSE2Slow" ); + ret |= add_flags( &cpu0, &cpu1, X264_CPU_SSE2 | X264_CPU_SSE2_IS_SLOW, "SSE2Slow" ); ret |= add_flags( &cpu0, &cpu1, X264_CPU_SSE2_IS_FAST, "SSE2Fast" ); ret |= add_flags( &cpu0, &cpu1, X264_CPU_CACHELINE_64, "SSE2Fast Cache64" ); cpu1 &= ~X264_CPU_CACHELINE_64; - ret |= add_flags( &cpu0, &cpu1, X264_CPU_SHUFFLE_IS_FAST, "SSE2 FastShuffle" ); - cpu1 &= ~X264_CPU_SHUFFLE_IS_FAST; + ret |= add_flags( &cpu0, &cpu1, X264_CPU_SLOW_SHUFFLE, "SSE2 SlowShuffle" ); + cpu1 &= ~X264_CPU_SLOW_SHUFFLE; ret |= add_flags( &cpu0, &cpu1, X264_CPU_SLOW_CTZ, "SSE2 SlowCTZ" ); cpu1 &= ~X264_CPU_SLOW_CTZ; - ret |= add_flags( &cpu0, &cpu1, X264_CPU_SLOW_ATOM, "SSE2 SlowAtom" ); - cpu1 &= ~X264_CPU_SLOW_ATOM; } if( x264_cpu_detect() & X264_CPU_SSE_MISALIGN ) { @@ -2411,15 +2476,17 @@ static int check_all_flags( void ) ret |= add_flags( &cpu0, &cpu1, X264_CPU_SSSE3, "SSSE3" ); ret |= add_flags( &cpu0, &cpu1, X264_CPU_CACHELINE_64, "SSSE3 Cache64" ); cpu1 &= ~X264_CPU_CACHELINE_64; - ret |= add_flags( &cpu0, &cpu1, X264_CPU_SHUFFLE_IS_FAST, "SSSE3 FastShuffle" ); - cpu1 &= ~X264_CPU_SHUFFLE_IS_FAST; + ret |= add_flags( &cpu0, &cpu1, X264_CPU_SLOW_SHUFFLE, "SSSE3 SlowShuffle" ); + cpu1 &= ~X264_CPU_SLOW_SHUFFLE; ret |= add_flags( &cpu0, &cpu1, X264_CPU_SLOW_CTZ, "SSSE3 SlowCTZ" ); cpu1 &= ~X264_CPU_SLOW_CTZ; ret |= add_flags( &cpu0, &cpu1, X264_CPU_SLOW_ATOM, "SSSE3 SlowAtom" ); + ret |= add_flags( &cpu0, &cpu1, X264_CPU_CACHELINE_64, "SSSE3 Cache64 SlowAtom" ); + cpu1 &= ~X264_CPU_CACHELINE_64; cpu1 &= ~X264_CPU_SLOW_ATOM; } if( x264_cpu_detect() & X264_CPU_SSE4 ) - ret |= add_flags( &cpu0, &cpu1, X264_CPU_SSE4 | X264_CPU_SHUFFLE_IS_FAST, "SSE4" ); + ret |= add_flags( &cpu0, &cpu1, X264_CPU_SSE4, "SSE4" ); if( x264_cpu_detect() & X264_CPU_AVX ) ret |= add_flags( &cpu0, &cpu1, X264_CPU_AVX, "AVX" ); if( x264_cpu_detect() & X264_CPU_XOP ) @@ -2429,19 +2496,9 @@ static int check_all_flags( void ) ret |= add_flags( &cpu0, &cpu1, X264_CPU_FMA4, "FMA4" ); cpu1 &= ~X264_CPU_FMA4; } - if( x264_cpu_detect() & X264_CPU_FMA3 ) - { - ret |= add_flags( &cpu0, &cpu1, X264_CPU_FMA3, "FMA3" ); - cpu1 &= ~X264_CPU_FMA3; - } if( x264_cpu_detect() & X264_CPU_BMI1 ) { ret |= add_flags( &cpu0, &cpu1, X264_CPU_BMI1, "BMI1" ); - if( x264_cpu_detect() & X264_CPU_TBM ) - { - ret |= add_flags( &cpu0, &cpu1, X264_CPU_TBM, "TBM" ); - cpu1 &= ~X264_CPU_TBM; - } if( x264_cpu_detect() & X264_CPU_BMI2 ) { ret |= add_flags( &cpu0, &cpu1, X264_CPU_BMI2, "BMI2" ); @@ -2451,6 +2508,11 @@ static int check_all_flags( void ) } if( x264_cpu_detect() & X264_CPU_AVX2 ) ret |= add_flags( &cpu0, &cpu1, X264_CPU_AVX2, "AVX2" ); + if( x264_cpu_detect() & X264_CPU_FMA3 ) + { + ret |= add_flags( &cpu0, &cpu1, X264_CPU_FMA3, "FMA3" ); + cpu1 &= ~X264_CPU_FMA3; + } #elif ARCH_PPC if( x264_cpu_detect() & X264_CPU_ALTIVEC ) { diff --git a/x264.c b/x264.c index 103b8085..6077f2bf 100644 --- a/x264.c +++ b/x264.c @@ -1,7 +1,7 @@ /***************************************************************************** * x264: top-level x264cli functions ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Loren Merritt * Laurent Aimar @@ -225,7 +225,7 @@ void x264_cli_printf( int i_level, const char *fmt, ... ) va_end( arg ); } -static void print_version_info() +static void print_version_info( void ) { #ifdef X264_POINTVER printf( "x264 "X264_POINTVER"\n" ); @@ -805,6 +805,7 @@ static void help( x264_param_t *defaults, int longhelp ) H1( " --psnr Enable PSNR computation\n" ); H1( " --ssim Enable SSIM computation\n" ); H1( " --threads Force a specific number of threads\n" ); + H2( " --lookahead-threads Force a specific number of lookahead threads\n" ); H2( " --sliced-threads Low-latency but lower-efficiency threading\n" ); H2( " --thread-input Run Avisynth in its own thread\n" ); H2( " --sync-lookahead Number of buffer frames for threaded lookahead\n" ); @@ -975,6 +976,7 @@ static struct option long_options[] = { "speed", required_argument, NULL, 0 }, { "speed-bufsize", required_argument, NULL, 0 }, { "threads", required_argument, NULL, 0 }, + { "lookahead-threads", required_argument, NULL, 0 }, { "sliced-threads", no_argument, NULL, 0 }, { "no-sliced-threads", no_argument, NULL, 0 }, { "slice-max-size", required_argument, NULL, 0 }, @@ -1507,7 +1509,7 @@ static int parse( int argc, char **argv, x264_param_t *param, cli_opt_t *opt ) x264_reduce_fraction( &info.sar_width, &info.sar_height ); x264_reduce_fraction( &info.fps_num, &info.fps_den ); - x264_cli_log( demuxername, X264_LOG_INFO, "%dx%d%c %d:%d @ %d/%d fps (%cfr)\n", info.width, + x264_cli_log( demuxername, X264_LOG_INFO, "%dx%d%c %u:%u @ %u/%u fps (%cfr)\n", info.width, info.height, info.interlaced ? 'i' : 'p', info.sar_width, info.sar_height, info.fps_num, info.fps_den, info.vfr ? 'v' : 'c' ); @@ -1624,11 +1626,8 @@ static int parse( int argc, char **argv, x264_param_t *param, cli_opt_t *opt ) for( int i = 0; x264_levels[i].level_idc != 0; i++ ) if( param->i_level_idc == x264_levels[i].level_idc ) { - while( mbs * 384 * param->i_frame_reference > x264_levels[i].dpb && - param->i_frame_reference > 1 ) - { + while( mbs * param->i_frame_reference > x264_levels[i].dpb && param->i_frame_reference > 1 ) param->i_frame_reference--; - } break; } } diff --git a/x264.h b/x264.h index 21c8c648..6cfcd1a8 100644 --- a/x264.h +++ b/x264.h @@ -1,7 +1,7 @@ /***************************************************************************** * x264.h: x264 public header ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Laurent Aimar * Loren Merritt @@ -28,7 +28,7 @@ #ifndef X264_X264_H #define X264_X264_H -#if !defined(_STDINT_H) && !defined(_STDINT_H_) && \ +#if !defined(_STDINT_H) && !defined(_STDINT_H_) && !defined(_STDINT_H_INCLUDED) &&\ !defined(_INTTYPES_H) && !defined(_INTTYPES_H_) # ifdef _MSC_VER # pragma message("You must include stdint.h or inttypes.h before x264.h") @@ -41,7 +41,18 @@ #include "x264_config.h" -#define X264_BUILD 122 +#define X264_BUILD 130 + +/* Application developers planning to link against a shared library version of + * libx264 from a Microsoft Visual Studio or similar development environment + * will need to define X264_API_IMPORTS before including this header. + * This clause does not apply to MinGW, similar development environments, or non + * Windows platforms. */ +#ifdef X264_API_IMPORTS +#define X264_API __declspec(dllimport) +#else +#define X264_API +#endif /* x264_t: * opaque handler for encoder */ @@ -98,43 +109,53 @@ typedef struct /**************************************************************************** * Encoder parameters ****************************************************************************/ -/* CPU flags - */ -#define X264_CPU_CACHELINE_32 0x0000001 /* avoid memory loads that span the border between two cachelines */ -#define X264_CPU_CACHELINE_64 0x0000002 /* 32/64 is the size of a cacheline in bytes */ -#define X264_CPU_ALTIVEC 0x0000004 -#define X264_CPU_MMX 0x0000008 -#define X264_CPU_MMX2 0x0000010 /* MMX2 aka MMXEXT aka ISSE */ +/* CPU flags */ + +/* x86 */ +#define X264_CPU_CMOV 0x0000001 +#define X264_CPU_MMX 0x0000002 +#define X264_CPU_MMX2 0x0000004 /* MMX2 aka MMXEXT aka ISSE */ #define X264_CPU_MMXEXT X264_CPU_MMX2 -#define X264_CPU_SSE 0x0000020 -#define X264_CPU_SSE2 0x0000040 -#define X264_CPU_SSE2_IS_SLOW 0x0000080 /* avoid most SSE2 functions on Athlon64 */ -#define X264_CPU_SSE2_IS_FAST 0x0000100 /* a few functions are only faster on Core2 and Phenom */ -#define X264_CPU_SSE3 0x0000200 -#define X264_CPU_SSSE3 0x0000400 -#define X264_CPU_SHUFFLE_IS_FAST 0x0000800 /* Penryn, Nehalem, and Phenom have fast shuffle units */ -#define X264_CPU_STACK_MOD4 0x0001000 /* if stack is only mod4 and not mod16 */ -#define X264_CPU_SSE4 0x0002000 /* SSE4.1 */ -#define X264_CPU_SSE42 0x0004000 /* SSE4.2 */ -#define X264_CPU_SSE_MISALIGN 0x0008000 /* Phenom support for misaligned SSE instruction arguments */ -#define X264_CPU_LZCNT 0x0010000 /* Phenom support for "leading zero count" instruction. */ -#define X264_CPU_ARMV6 0x0020000 -#define X264_CPU_NEON 0x0040000 /* ARM NEON */ -#define X264_CPU_FAST_NEON_MRC 0x0080000 /* Transfer from NEON to ARM register is fast (Cortex-A9) */ -#define X264_CPU_SLOW_CTZ 0x0100000 /* BSR/BSF x86 instructions are really slow on some CPUs */ -#define X264_CPU_SLOW_ATOM 0x0200000 /* The Atom just sucks */ -#define X264_CPU_AVX 0x0400000 /* AVX support: requires OS support even if YMM registers - * aren't used. */ -#define X264_CPU_XOP 0x0800000 /* AMD XOP */ -#define X264_CPU_FMA4 0x1000000 /* AMD FMA4 */ -#define X264_CPU_AVX2 0x2000000 /* AVX2 */ -#define X264_CPU_FMA3 0x4000000 /* Intel FMA3 */ -#define X264_CPU_BMI1 0x8000000 /* BMI1 */ -#define X264_CPU_BMI2 0x10000000 /* BMI2 */ -#define X264_CPU_TBM 0x20000000 /* AMD TBM */ - -/* Analyse flags - */ +#define X264_CPU_SSE 0x0000008 +#define X264_CPU_SSE2 0x0000010 +#define X264_CPU_SSE3 0x0000020 +#define X264_CPU_SSSE3 0x0000040 +#define X264_CPU_SSE4 0x0000080 /* SSE4.1 */ +#define X264_CPU_SSE42 0x0000100 /* SSE4.2 */ +#define X264_CPU_SSE_MISALIGN 0x0000200 /* Phenom support for misaligned SSE instruction arguments */ +#define X264_CPU_LZCNT 0x0000400 /* Phenom support for "leading zero count" instruction. */ +#define X264_CPU_AVX 0x0000800 /* AVX support: requires OS support even if YMM registers aren't used. */ +#define X264_CPU_XOP 0x0001000 /* AMD XOP */ +#define X264_CPU_FMA4 0x0002000 /* AMD FMA4 */ +#define X264_CPU_AVX2 0x0004000 /* AVX2 */ +#define X264_CPU_FMA3 0x0008000 /* Intel FMA3 */ +#define X264_CPU_BMI1 0x0010000 /* BMI1 */ +#define X264_CPU_BMI2 0x0020000 /* BMI2 */ +/* x86 modifiers */ +#define X264_CPU_CACHELINE_32 0x0040000 /* avoid memory loads that span the border between two cachelines */ +#define X264_CPU_CACHELINE_64 0x0080000 /* 32/64 is the size of a cacheline in bytes */ +#define X264_CPU_SSE2_IS_SLOW 0x0100000 /* avoid most SSE2 functions on Athlon64 */ +#define X264_CPU_SSE2_IS_FAST 0x0200000 /* a few functions are only faster on Core2 and Phenom */ +#define X264_CPU_SLOW_SHUFFLE 0x0400000 /* The Conroe has a slow shuffle unit (relative to overall SSE performance) */ +#define X264_CPU_STACK_MOD4 0x0800000 /* if stack is only mod4 and not mod16 */ +#define X264_CPU_SLOW_CTZ 0x1000000 /* BSR/BSF x86 instructions are really slow on some CPUs */ +#define X264_CPU_SLOW_ATOM 0x2000000 /* The Atom is terrible: slow SSE unaligned loads, slow + * SIMD multiplies, slow SIMD variable shifts, slow pshufb, + * cacheline split penalties -- gather everything here that + * isn't shared by other CPUs to avoid making half a dozen + * new SLOW flags. */ +#define X264_CPU_SLOW_PSHUFB 0x4000000 /* such as on the Intel Atom */ +#define X264_CPU_SLOW_PALIGNR 0x8000000 /* such as on the AMD Bobcat */ + +/* PowerPC */ +#define X264_CPU_ALTIVEC 0x0000001 + +/* ARM */ +#define X264_CPU_ARMV6 0x0000001 +#define X264_CPU_NEON 0x0000002 /* ARM NEON */ +#define X264_CPU_FAST_NEON_MRC 0x0000004 /* Transfer from NEON to ARM register is fast (Cortex-A9) */ + +/* Analyse flags */ #define X264_ANALYSE_I4x4 0x0001 /* Analyse i4x4 */ #define X264_ANALYSE_I8x8 0x0002 /* Analyse i8x8 (requires 8x8 transform) */ #define X264_ANALYSE_PSUB16x16 0x0010 /* Analyse p16x8, p8x16 and p8x8 */ @@ -246,7 +267,8 @@ typedef struct x264_param_t { /* CPU flags */ unsigned int cpu; - int i_threads; /* encode multiple frames in parallel */ + int i_threads; /* encode multiple frames in parallel */ + int i_lookahead_threads; /* multiple threads for lookahead analysis */ int b_sliced_threads; /* Whether to use slice-based threading. */ int b_deterministic; /* whether to allow non-deterministic optimizations when threaded */ int b_cpu_independent; /* force canonical behavior rather than cpu-dependent optimal algorithms */ @@ -357,6 +379,9 @@ typedef struct x264_param_t float f_psy_trellis; /* Psy trellis strength */ int b_psy; /* Toggle all psy optimizations */ + int b_mb_info; /* Use input mb_info data in x264_picture_t */ + int b_mb_info_update; /* Update the values in mb_info according to the results of encoding. */ + /* the deadzone size that will be used in luma quantization */ int i_luma_deadzone[2]; /* {inter, intra} */ @@ -502,8 +527,13 @@ typedef struct x264_param_t * the calling application is expected to acquire all output NALs through the callback. * * It is generally sensible to combine this callback with a use of slice-max-mbs or - * slice-max-size. */ - void (*nalu_process) ( x264_t *h, x264_nal_t *nal ); + * slice-max-size. + * + * The opaque pointer is the opaque pointer from the input frame associated with this + * NAL unit. This helps distinguish between nalu_process calls from different sources, + * e.g. if doing multiple encodes in one process. + */ + void (*nalu_process) ( x264_t *h, x264_nal_t *nal, void *opaque ); } x264_param_t; void x264_nal_encode( x264_t *h, uint8_t *dst, x264_nal_t *nal ); @@ -517,7 +547,7 @@ typedef struct int level_idc; int mbps; /* max macroblock processing rate (macroblocks/sec) */ int frame_size; /* max frame size (macroblocks) */ - int dpb; /* max decoded picture buffer (bytes) */ + int dpb; /* max decoded picture buffer (mbs) */ int bitrate; /* max bitrate (kbit/sec) */ int cpb; /* max vbv buffer (kbit) */ int mv_range; /* max vertical mv component range (pixels) */ @@ -530,7 +560,7 @@ typedef struct } x264_level_t; /* all of the levels defined in the standard, terminated by .level_idc=0 */ -extern const x264_level_t x264_levels[]; +X264_API extern const x264_level_t x264_levels[]; /**************************************************************************** * Basic parameter handling functions @@ -627,14 +657,14 @@ int x264_param_apply_profile( x264_param_t *, const char *profile ); * (16-x264_bit_depth) bits to be zero. * Note: The flag X264_CSP_HIGH_DEPTH must be used to specify the * colorspace depth as well. */ -extern const int x264_bit_depth; +X264_API extern const int x264_bit_depth; /* x264_chroma_format: * Specifies the chroma formats that x264 supports encoding. When this * value is non-zero, then it represents a X264_CSP_* that is the only * chroma format that x264 supports encoding. If the value is 0 then * there are no restrictions. */ -extern const int x264_chroma_format; +X264_API extern const int x264_chroma_format; enum pic_struct_e { @@ -692,24 +722,58 @@ typedef struct typedef struct { + /* All arrays of data here are ordered as follows: + * each array contains one offset per macroblock, in raster scan order. In interlaced + * mode, top-field MBs and bottom-field MBs are interleaved at the row level. + * Macroblocks are 16x16 blocks of pixels (with respect to the luma plane). For the + * purposes of calculating the number of macroblocks, width and height are rounded up to + * the nearest 16. If in interlaced mode, height is rounded up to the nearest 32 instead. */ + /* In: an array of quantizer offsets to be applied to this image during encoding. * These are added on top of the decisions made by x264. * Offsets can be fractional; they are added before QPs are rounded to integer. * Adaptive quantization must be enabled to use this feature. Behavior if quant - * offsets differ between encoding passes is undefined. - * - * Array contains one offset per macroblock, in raster scan order. In interlaced - * mode, top-field MBs and bottom-field MBs are interleaved at the row level. */ + * offsets differ between encoding passes is undefined. */ float *quant_offsets; /* In: optional callback to free quant_offsets when used. * Useful if one wants to use a different quant_offset array for each frame. */ void (*quant_offsets_free)( void* ); + + /* In: optional array of flags for each macroblock. + * Allows specifying additional information for the encoder such as which macroblocks + * remain unchanged. Usable flags are listed below. + * x264_param_t.analyse.b_mb_info must be set to use this, since x264 needs to track + * extra data internally to make full use of this information. + * + * Out: if b_mb_info_update is set, x264 will update this array as a result of encoding. + * + * For "MBINFO_CONSTANT", it will remove this flag on any macroblock whose decoded + * pixels have changed. This can be useful for e.g. noting which areas of the + * frame need to actually be blitted. Note: this intentionally ignores the effects + * of deblocking for the current frame, which should be fine unless one needs exact + * pixel-perfect accuracy. + * + * Results for MBINFO_CONSTANT are currently only set for P-frames, and are not + * guaranteed to enumerate all blocks which haven't changed. (There may be false + * negatives, but no false positives.) + */ + uint8_t *mb_info; + /* In: optional callback to free mb_info when used. */ + void (*mb_info_free)( void* ); + + /* The macroblock is constant and remains unchanged from the previous frame. */ + #define X264_MBINFO_CONSTANT (1<<0) + /* More flags may be added in the future. */ + /* Out: SSIM of the the frame luma (if x264_param_t.b_ssim is set) */ double f_ssim; /* Out: Average PSNR of the frame (if x264_param_t.b_psnr is set) */ double f_psnr_avg; /* Out: PSNR of Y, U, and V (if x264_param_t.b_psnr is set) */ double f_psnr[3]; + + /* Out: Average effective CRF of the encoded frame */ + double f_crf_avg; } x264_image_properties_t; typedef struct @@ -794,7 +858,13 @@ x264_t *x264_encoder_open( x264_param_t * ); * due to delay, this may not be the next frame passed to encoder_encode. * if the change should apply to some particular frame, use x264_picture_t->param instead. * returns 0 on success, negative on parameter validation error. - * not all parameters can be changed; see the actual function for a detailed breakdown. */ + * not all parameters can be changed; see the actual function for a detailed breakdown. + * + * since not all parameters can be changed, moving from preset to preset may not always + * fully copy all relevant parameters, but should still work usably in practice. however, + * more so than for other presets, many of the speed shortcuts used in ultrafast cannot be + * switched out of; using reconfig to switch between ultrafast and other presets is not + * recommended without a more fine-grained breakdown of parameters to take this into account. */ int x264_encoder_reconfig( x264_t *, x264_param_t * ); /* x264_encoder_parameters: * copies the current internal set of parameters to the pointer provided diff --git a/x264cli.h b/x264cli.h index a5c10397..74376025 100644 --- a/x264cli.h +++ b/x264cli.h @@ -1,7 +1,7 @@ /***************************************************************************** * x264cli.h: x264cli common ***************************************************************************** - * Copyright (C) 2003-2012 x264 project + * Copyright (C) 2003-2013 x264 project * * Authors: Laurent Aimar * Loren Merritt diff --git a/x264dll.c b/x264dll.c index acf4bd6b..cc0d4d39 100644 --- a/x264dll.c +++ b/x264dll.c @@ -1,7 +1,7 @@ /***************************************************************************** * x264dll: x264 DLLMain for win32 ***************************************************************************** - * Copyright (C) 2009-2012 x264 project + * Copyright (C) 2009-2013 x264 project * * Authors: Anton Mitrofanov * diff --git a/x264res.rc b/x264res.rc index 4762be5b..73c82ef9 100644 --- a/x264res.rc +++ b/x264res.rc @@ -1,7 +1,7 @@ /***************************************************************************** * x264res.rc: windows resource file ***************************************************************************** - * Copyright (C) 2012 x264 project + * Copyright (C) 2012-2013 x264 project * * Authors: Henrik Gramner * @@ -60,7 +60,7 @@ BEGIN #endif VALUE "FileVersion", X264_POINTVER VALUE "InternalName", "x264" - VALUE "LegalCopyright", "Copyright (C) 2003-2012 x264 project" + VALUE "LegalCopyright", "Copyright (C) 2003-2013 x264 project" #ifdef DLL VALUE "OriginalFilename", "libx264-" xstr(X264_BUILD) ".dll" #else From f53b90dd15c99baefea9979c76b3b68e9b60371c Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Mon, 11 Mar 2013 14:05:25 +0000 Subject: [PATCH 79/81] Temporarily disable speedcontrol for x262. Causes a lot of artefacts. --- encoder/speed.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/encoder/speed.c b/encoder/speed.c index faade8e6..dcc389ab 100644 --- a/encoder/speed.c +++ b/encoder/speed.c @@ -124,7 +124,7 @@ static void apply_preset( x264_t *h, int preset ) { x264_speedcontrol_t *sc = h->sc; preset = x264_clip3( preset, 0, h->param.sc.max_preset-1 ); - //if( preset != sc->preset ) + if( 0 ) { const sc_preset_t *s = &presets[preset]; x264_param_t p = h->param; @@ -221,7 +221,7 @@ void x264_speedcontrol_frame( x264_t *h ) / (sc->buffer_size*3/4 + sc->compensation_period); float cplx = sc->cplx_num / sc->cplx_den; float set, t0, t1; - float filled = (float) sc->buffer_fill / sc->buffer_size; + float filled = (float) sc->buffer_fill / sc->buffer_size; int i; t0 = presets[0].time * cplx; for( i=1;; i++ ) From bd3331c74d05a76eac76532683b37c53370afa7e Mon Sep 17 00:00:00 2001 From: Michael Kazmier Date: Wed, 13 Mar 2013 15:47:11 -0600 Subject: [PATCH 80/81] update low delay flag when no bframes are used --- encoder/set.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encoder/set.c b/encoder/set.c index 7dc78ad8..34dfa835 100644 --- a/encoder/set.c +++ b/encoder/set.c @@ -906,7 +906,7 @@ void x264_seq_extension_write_mpeg2( x264_t *h, bs_t *s ) bs_write( s, 12, (h->param.rc.i_vbv_max_bitrate * 1000 + 399) / 400 >> 18 & 0xfff ); // bit_rate_extension bs_write1( s, 1 ); // marker_bit bs_write( s, 8, (h->param.rc.i_vbv_buffer_size * 1000 + 16383) / 16384 >> 10 & 0xff ); // vbv_buffer_size_extension - bs_write1( s, 0 ); // low_delay + bs_write1( s, !h->param.i_bframe ); // low_delay bs_write( s, 2, 0 ); // frame_rate_extension_n bs_write( s, 5, 0 ); // frame_rate_extension_d From 9679f15fc30241a5f64e8cbdff03e5804dfea836 Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Thu, 21 May 2020 18:13:43 +0100 Subject: [PATCH 81/81] Disable crashing AVX2 --- common/quant.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/quant.c b/common/quant.c index b16895dc..883ef158 100644 --- a/common/quant.c +++ b/common/quant.c @@ -730,7 +730,7 @@ void x264_quant_init( x264_t *h, int cpu, x264_quant_function_t *pf ) { pf->quant_4x4 = x264_quant_4x4_avx2; pf->quant_4x4_dc = x264_quant_4x4_dc_avx2; - pf->quant_8x8 = x264_quant_8x8_avx2; + //pf->quant_8x8 = x264_quant_8x8_avx2; pf->quant_4x4x4 = x264_quant_4x4x4_avx2; pf->dequant_4x4 = x264_dequant_4x4_avx2; pf->dequant_8x8 = x264_dequant_8x8_avx2;