Index: contrib/patch-x264-vbv-2pass.patch =================================================================== --- contrib/patch-x264-vbv-2pass.patch (revision 1243) +++ contrib/patch-x264-vbv-2pass.patch (working copy) @@ -1,6 +1,6 @@ Index: encoder/ratecontrol.c =================================================================== ---- encoder/ratecontrol.c (revision 680) +--- encoder/ratecontrol.c (revision 736) +++ encoder/ratecontrol.c (working copy) @@ -43,6 +43,7 @@ int p_tex_bits; @@ -12,14 +12,14 @@ int i_count; @@ -1149,7 +1150,7 @@ return; - + rct->buffer_fill_final += rct->buffer_rate - bits; - if( rct->buffer_fill_final < 0 && !rct->b_2pass ) + if( rct->buffer_fill_final < 0 ) x264_log( h, X264_LOG_WARNING, "VBV underflow (%.0f bits)\n", rct->buffer_fill_final ); rct->buffer_fill_final = x264_clip3f( rct->buffer_fill_final, 0, rct->buffer_size ); } -@@ -1325,6 +1326,28 @@ +@@ -1325,6 +1326,22 @@ double w = x264_clip3f( time*100, 0.0, 1.0 ); q *= pow( (double)total_bits / rcc->expected_bits_sum, w ); } @@ -37,21 +37,15 @@ + expected_size = qscale2bits(&rce, q); + expected_vbv = rcc->buffer_fill + rcc->buffer_rate - expected_size; + } -+/* x264_log( h, X264_LOG_INFO, -+ "frame %d rcc expected vbv = %d encoding expected vbv = %d\n", -+ (int)(h->fenc->i_frame), -+ (int)(rce.expected_vbv), -+ (int)(expected_vbv));*/ -+ + } + } q = x264_clip3f( q, lmin, lmax ); } else /* 1pass ABR */ -@@ -1455,6 +1478,137 @@ +@@ -1455,6 +1472,137 @@ /* the rest of the variables are either constant or thread-local */ } - + +FILE *fh_vbv; + +static int find_underflow( x264_t *h, double *fills, int *t0, int *t1, int over ) @@ -84,15 +78,17 @@ + return start>=0 && end>=0; +} + -+static void fix_underflow( x264_t *h, int t0, int t1, double adjustment ) ++static void fix_underflow( x264_t *h, int t0, int t1, double adjustment, double qscale_min, double qscale_max) +{ + x264_ratecontrol_t *rcc = h->rc; ++ double qscale_new; + int i; + if(t0 > 0) + t0++; -+// printf("interval [%d,%d] %.4f\n", t0, t1, adjustment); -+ for(i=t0; i<=t1; i++) -+ rcc->entry[i].new_qscale *= adjustment; ++ for(i=t0; i<=t1; i++) { ++ qscale_new = rcc->entry[i].new_qscale *= adjustment; ++ rcc->entry[i].new_qscale = x264_clip3f(qscale_new, qscale_min, qscale_max); ++ } +} + +static double count_expected_bits( x264_t *h ) @@ -136,9 +132,10 @@ + double all_available_bits = h->param.rc.i_bitrate * 1000. * rcc->num_entries / rcc->fps; + double expected_bits, prev_bits, adjustment; + int i, t0, t1, space; ++ double qscale_min = qp2qscale(h->param.rc.i_qp_min); ++ double qscale_max = qp2qscale(h->param.rc.i_qp_max); + + fills++; -+// fh_vbv = fopen("vbv.log", "w"); + + //adjust overall stream size + do { @@ -149,7 +146,7 @@ + //fix underflows + while(find_underflow(h, fills, &t0, &t1, 0)) + { -+ fix_underflow(h, t0, t1, 1.001); ++ fix_underflow(h, t0, t1, 1.001, qscale_min, qscale_max); + space = 1; + } + @@ -160,7 +157,7 @@ + //fix overflows + while(find_underflow(h, fills, &t0, &t1, 1)) + { -+ fix_underflow(h, t0, t1, adjustment); ++ fix_underflow(h, t0, t1, adjustment, qscale_min, qscale_max); + t0 = t1; + space = 1; + } @@ -171,30 +168,27 @@ + fills[-1] = rcc->buffer_size * (1. - h->param.rc.f_vbv_buffer_init); + t0 = 0; + while(find_underflow(h, fills, &t0, &t1, 0)) -+ fix_underflow(h, t0, t1, 1.001); ++ fix_underflow(h, t0, t1, 1.001, qscale_min, qscale_max); + -+// debug_dump_vbv(h); -+ + //store expected vbv filling values for tracking when encoding + for(i=0; inum_entries; i++) + rcc->entry[i].expected_vbv = rcc->buffer_size - fills[i]; + -+// fclose(fh_vbv); + x264_free(fills-1); +} + static int init_pass2( x264_t *h ) { x264_ratecontrol_t *rcc = h->rc; -@@ -1543,7 +1697,6 @@ +@@ -1543,7 +1691,6 @@ rcc->last_non_b_pict_type = -1; rcc->last_accum_p_norm = 1; rcc->accum_p_norm = 0; - rcc->buffer_fill = rcc->buffer_size * h->param.rc.f_vbv_buffer_init; - + /* find qscale */ for(i=0; inum_entries; i++){ -@@ -1580,15 +1733,9 @@ +@@ -1580,18 +1727,11 @@ /* find expected bits */ for(i=0; inum_entries; i++){ ratecontrol_entry_t *rce = &rcc->entry[i]; @@ -209,12 +203,15 @@ - rcc->buffer_fill = rcc->buffer_fill_final; + expected_bits += qscale2bits(rce, rce->new_qscale); } - - //printf("expected:%llu available:%llu factor:%lf avgQ:%lf\n", (uint64_t)expected_bits, all_available_bits, rate_factor); -@@ -1599,6 +1746,10 @@ + +-//printf("expected:%llu available:%llu factor:%lf avgQ:%lf\n", (uint64_t)expected_bits, all_available_bits, rate_factor); + if(expected_bits > all_available_bits) rate_factor -= step; + } + +@@ -1599,6 +1739,10 @@ if(filter_size > 1) x264_free(blurred_qscale); - + + if(rcc->b_vbv) + vbv_pass2(h); + expected_bits = count_expected_bits(h); @@ -222,17 +219,17 @@ if(fabs(expected_bits/all_available_bits - 1.0) > 0.01) { double avgq = 0; -@@ -1606,7 +1757,8 @@ +@@ -1606,7 +1750,8 @@ avgq += rcc->entry[i].new_qscale; avgq = qscale2qp(avgq / rcc->num_entries); - + - x264_log(h, X264_LOG_WARNING, "Error: 2pass curve failed to converge\n"); + if ((expected_bits > all_available_bits) || (!rcc->b_vbv)) + x264_log(h, X264_LOG_WARNING, "Error: 2pass curve failed to converge\n"); x264_log(h, X264_LOG_WARNING, "target: %.2f kbit/s, expected: %.2f kbit/s, avg QP: %.4f\n", (float)h->param.rc.i_bitrate, expected_bits * rcc->fps / (rcc->num_entries * 1000.), -@@ -1625,7 +1777,7 @@ +@@ -1625,7 +1770,7 @@ else x264_log(h, X264_LOG_WARNING, "try increasing target bitrate\n"); } @@ -240,9 +237,10 @@ + else if(!(rcc->b_2pass && rcc->b_vbv)) x264_log(h, X264_LOG_WARNING, "internal error\n"); } - -@@ -1633,3 +1785,4 @@ + +@@ -1633,3 +1778,4 @@ } + - + + Index: contrib/Jamfile =================================================================== --- contrib/Jamfile (revision 1243) +++ contrib/Jamfile (working copy) @@ -359,9 +359,11 @@ { LIBX264_PATCH += " $(PATCH) -p1 < ../patch-x264-solaris.patch && " ; } -# AQ is temporarily disabled LIBX264_PATCH += "$(PATCH) -p0 < ../patch-x264-aq.patch && " ; +# VBV 2 Pass v3 (must be applied *before* patch-x264-vaq48.patch) Uncomment to use both + #LIBX264_PATCH += "$(PATCH) -p0 < ../patch-x264-vbv-2pass.patch && " ; +# VAQ .48 Patch (Dark_Shikari) + LIBX264_PATCH += "$(PATCH) -p0 < ../patch-x264-vaq48.patch && " ; LIBX264_PATCH += "$(PATCH) -p0 < ../patch-x264-idr.patch && " ; - LIBX264_PATCH += "$(PATCH) -p0 < ../patch-x264-vbv-2pass.patch && " ; Depends $(<) : $(>) ; Depends lib : $(<) ; } Index: contrib/version_x264.txt =================================================================== --- contrib/version_x264.txt (revision 1243) +++ contrib/version_x264.txt (working copy) @@ -1 +1 @@ -http://download.m0k.org/handbrake/contrib/x264-r720.tar.gz +http://download.m0k.org/handbrake/contrib/x264-r736.tar.gz Index: contrib/patch-x264-vaq48.patch =================================================================== --- contrib/patch-x264-vaq48.patch (revision 0) +++ contrib/patch-x264-vaq48.patch (revision 0) @@ -0,0 +1,300 @@ +Index: encoder/ratecontrol.h +=================================================================== +--- encoder/ratecontrol.h (revision 736) ++++ encoder/ratecontrol.h (working copy) +@@ -34,6 +34,7 @@ + int x264_ratecontrol_qp( x264_t * ); + void x264_ratecontrol_end( x264_t *, int bits ); + void x264_ratecontrol_summary( x264_t * ); ++void x264_adaptive_quant ( x264_t * ); + + #endif + +Index: encoder/encoder.c +=================================================================== +--- encoder/encoder.c (revision 736) ++++ encoder/encoder.c (working copy) +@@ -401,6 +401,7 @@ + h->param.analyse.b_fast_pskip = 0; + h->param.analyse.i_noise_reduction = 0; + h->param.analyse.i_subpel_refine = x264_clip3( h->param.analyse.i_subpel_refine, 1, 6 ); ++ h->param.analyse.b_aq = 0; + } + if( h->param.rc.i_rc_method == X264_RC_CQP ) + { +@@ -475,6 +476,10 @@ + if( !h->param.b_cabac ) + h->param.analyse.i_trellis = 0; + h->param.analyse.i_trellis = x264_clip3( h->param.analyse.i_trellis, 0, 2 ); ++ h->param.analyse.b_aq = h->param.analyse.b_aq && h->param.analyse.f_aq_strength > 0; ++ /* VAQ on static sensitivity mode effectively replaces qcomp, so qcomp is raised towards 1 to compensate. */ ++ if(h->param.analyse.b_aq && h->param.analyse.f_aq_sensitivity != 0) ++ h->param.rc.f_qcompress = x264_clip3f(h->param.rc.f_qcompress + h->param.analyse.f_aq_strength * 0.4 / 0.28, 0, 1); + h->param.analyse.i_noise_reduction = x264_clip3( h->param.analyse.i_noise_reduction, 0, 1<<16 ); + + { +Index: encoder/ratecontrol.c +=================================================================== +--- encoder/ratecontrol.c (revision 736) ++++ encoder/ratecontrol.c (working copy) +@@ -127,6 +127,10 @@ + predictor_t *pred_b_from_p; /* predict B-frame size from P-frame satd */ + int bframes; /* # consecutive B-frames before this P-frame */ + int bframe_bits; /* total cost of those frames */ ++ ++ /* AQ stuff */ ++ float aq_threshold; ++ int *ac_energy; + + int i_zones; + x264_zone_t *zones; +@@ -169,7 +173,97 @@ + + rce->misc_bits; + } + ++// Find the total AC energy of the block in all planes. ++static int ac_energy_mb( x264_t *h, int mb_x, int mb_y, int *satd ) ++{ ++ DECLARE_ALIGNED( static uint8_t, flat[16], 16 ) = {128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128}; ++// DECLARE_ALIGNED( static uint8_t, flat[16], 16 ); ++ unsigned int var=0, sad, ssd, i; ++ for( i=0; i<3; i++ ) ++ { ++ int w = i ? 8 : 16; ++ int stride = h->fenc->i_stride[i]; ++ int offset = h->mb.b_interlaced ++ ? w * (mb_x + (mb_y&~1) * stride) + (mb_y&1) * stride ++ : w * (mb_x + mb_y * stride); ++ int pix = i ? PIXEL_8x8 : PIXEL_16x16; ++ stride <<= h->mb.b_interlaced; ++ sad = h->pixf.sad[pix](flat, 0, h->fenc->plane[i]+offset, stride); ++ ssd = h->pixf.ssd[pix](flat, 0, h->fenc->plane[i]+offset, stride); ++ var += ssd - (sad * sad >> (i?6:8)); ++ // SATD to represent the block's overall complexity (bit cost) for intra encoding. ++ // exclude the DC coef, because nothing short of an actual intra prediction will estimate DC cost. ++ if( var && satd ) ++ *satd += h->pixf.satd[pix](flat, 0, h->fenc->plane[i]+offset, stride) - sad/2; ++ } ++ return var; ++} ++ ++void x264_autosense_aq( x264_t *h ) ++{ ++ double total = 0; ++ double n = 0; ++ int mb_x, mb_y; ++ /* FIXME: Some of the SATDs might be already calculated elsewhere (ratecontrol?). Can we reuse them? */ ++ /* FIXME: Is chroma SATD necessary? */ ++ for( mb_y=0; mb_ysps->i_mb_height; mb_y++ ) ++ for( mb_x=0; mb_xsps->i_mb_width; mb_x++ ) ++ { ++ int energy, satd=0; ++ energy = ac_energy_mb( h, mb_x, mb_y, &satd ); ++ h->rc->ac_energy[mb_x + mb_y * h->sps->i_mb_width] = energy; ++ /* Weight the energy value by the SATD value of the MB. This represents the fact that ++ the more complex blocks in a frame should be weighted more when calculating the optimal sensitivity. ++ This also helps diminish the negative effect of large numbers of simple blocks in a frame, such as in the case ++ of a letterboxed film. */ ++ if( energy ) ++ { ++ x264_cpu_restore(h->param.cpu); ++ total += logf(energy) * satd; ++ n += satd; ++ } ++ } ++ x264_cpu_restore(h->param.cpu); ++ /* Calculate and store the threshold. */ ++ h->rc->aq_threshold = n ? total/n : 15; ++} + ++/***************************************************************************** ++* x264_adaptive_quant: ++ * adjust macroblock QP based on variance (AC energy) of the MB. ++ * high variance = higher QP ++ * low variance = lower QP ++ * This generally increases SSIM and lowers PSNR. ++*****************************************************************************/ ++void x264_adaptive_quant( x264_t *h ) ++{ ++ int qp = h->mb.i_qp; ++ int energy; ++ x264_cpu_restore(h->param.cpu); ++ if(h->param.analyse.f_aq_sensitivity != 0) ++ energy = ac_energy_mb( h, h->mb.i_mb_x, h->mb.i_mb_y, NULL ); ++ else ++ energy = h->rc->ac_energy[h->mb.i_mb_xy]; ++ if(energy == 0) ++ { ++ h->mb.i_qp = h->mb.i_last_qp; ++ } ++ else ++ { ++ x264_cpu_restore(h->param.cpu); ++ float result = energy; ++ /* Adjust the QP based on the AC energy of the macroblock. */ ++ float qp_adj = 3 * (logf(result) - h->rc->aq_threshold); ++ if(h->param.analyse.f_aq_sensitivity == 0) qp_adj = x264_clip3f(qp_adj, -5, 5); ++ int new_qp = x264_clip3(qp + qp_adj * h->param.analyse.f_aq_strength + .5, h->param.rc.i_qp_min, h->param.rc.i_qp_max); ++ /* 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. */ ++ if(abs(new_qp - h->mb.i_last_qp) == 1) new_qp = h->mb.i_last_qp; ++ h->mb.i_qp = new_qp; ++ } ++ h->mb.i_chroma_qp = i_chroma_qp_table[x264_clip3( h->mb.i_qp + h->pps->i_chroma_qp_index_offset, 0, 51 )]; ++} ++ + int x264_ratecontrol_new( x264_t *h ) + { + x264_ratecontrol_t *rc; +@@ -244,7 +338,7 @@ + rc->rate_tolerance = 0.01; + } + +- h->mb.b_variable_qp = rc->b_vbv && !rc->b_2pass; ++ h->mb.b_variable_qp = (rc->b_vbv && !rc->b_2pass) || h->param.analyse.b_aq; + + if( rc->b_abr ) + { +@@ -458,10 +552,13 @@ + x264_free( p ); + } + +- for( i=1; iparam.i_threads; i++ ) ++ for( i=0; iparam.i_threads; i++ ) + { + h->thread[i]->rc = rc+i; +- rc[i] = rc[0]; ++ if( i ) ++ rc[i] = rc[0]; ++ if( h->param.analyse.b_aq ) ++ rc[i].ac_energy = x264_malloc( h->mb.i_mb_count * sizeof(int) ); + } + + return 0; +@@ -623,6 +720,8 @@ + x264_free( rc->zones[i].param ); + x264_free( rc->zones ); + } ++ for( i=0; iparam.i_threads; i++ ) ++ x264_free( rc[i].ac_energy ); + x264_free( rc ); + } + +@@ -729,6 +828,15 @@ + + if( h->sh.i_type != SLICE_TYPE_B ) + rc->last_non_b_pict_type = h->sh.i_type; ++ ++ /* Adaptive AQ sensitivity algorithm. */ ++ if( h->param.analyse.b_aq ) ++ { ++ if( h->param.analyse.f_aq_sensitivity > 0 ) ++ h->rc->aq_threshold = logf(powf(h->param.analyse.f_aq_sensitivity,4)/2); //FIXME simplify ++ else ++ x264_autosense_aq(h); ++ } + } + + double predict_row_size( x264_t *h, int y, int qp ) +Index: encoder/analyse.c +=================================================================== +--- encoder/analyse.c (revision 736) ++++ encoder/analyse.c (working copy) +@@ -2047,8 +2047,13 @@ + int i_cost = COST_MAX; + int i; + +- /* init analysis */ +- x264_mb_analyse_init( h, &analysis, x264_ratecontrol_qp( h ) ); ++ h->mb.i_qp = x264_ratecontrol_qp( h ); ++ ++ if( h->param.analyse.b_aq ) ++ x264_adaptive_quant( h ); ++ ++ /* init analysis */ ++ x264_mb_analyse_init( h, &analysis, h->mb.i_qp ); + + /*--------------------------- Do the analysis ---------------------------*/ + if( h->sh.i_type == SLICE_TYPE_I ) +Index: x264.c +=================================================================== +--- x264.c (revision 736) ++++ x264.c (working copy) +@@ -244,6 +244,14 @@ + " - 2: enabled on all mode decisions\n", defaults->analyse.i_trellis ); + H0( " --no-fast-pskip Disables early SKIP detection on P-frames\n" ); + H0( " --no-dct-decimate Disables coefficient thresholding on P-frames\n" ); ++ H0( " --aq-strength Amount to adjust QP/lambda per MB [%.1f]\n" ++ " 0.0: no AQ\n" ++ " 1.0: medium AQ\n", defaults->analyse.f_aq_strength ); ++ H0( " --aq-sensitivity \"Center\" of AQ curve. [%.1f]\n" ++ " 0: automatic sensitivity (avoids moving bits between frames)\n" ++ " 10: most QPs are raised\n" ++ " 20: good general-use sensitivity\n" ++ " 30: most QPs are lowered\n", defaults->analyse.f_aq_sensitivity ); + H0( " --nr Noise reduction [%d]\n", defaults->analyse.i_noise_reduction ); + H1( "\n" ); + H1( " --deadzone-inter Set the size of the inter luma quantization deadzone [%d]\n", defaults->analyse.i_luma_deadzone[0] ); +@@ -407,6 +415,8 @@ + { "trellis", required_argument, NULL, 't' }, + { "no-fast-pskip", no_argument, NULL, 0 }, + { "no-dct-decimate", no_argument, NULL, 0 }, ++ { "aq-strength", required_argument, NULL, 0 }, ++ { "aq-sensitivity", required_argument, NULL, 0 }, + { "deadzone-inter", required_argument, NULL, '0' }, + { "deadzone-intra", required_argument, NULL, '0' }, + { "level", required_argument, NULL, 0 }, +Index: common/common.c +=================================================================== +--- common/common.c (revision 736) ++++ common/common.c (working copy) +@@ -123,6 +123,9 @@ + param->analyse.i_chroma_qp_offset = 0; + param->analyse.b_fast_pskip = 1; + param->analyse.b_dct_decimate = 1; ++ param->analyse.b_aq = 1; ++ param->analyse.f_aq_strength = 0.5; ++ param->analyse.f_aq_sensitivity = 13; + param->analyse.i_luma_deadzone[0] = 21; + param->analyse.i_luma_deadzone[1] = 11; + param->analyse.b_psnr = 1; +@@ -455,6 +458,13 @@ + p->analyse.b_fast_pskip = atobool(value); + OPT("dct-decimate") + p->analyse.b_dct_decimate = atobool(value); ++ OPT("aq-strength") ++ { ++ p->analyse.f_aq_strength = atof(value); ++ p->analyse.b_aq = 1; ++ } ++ OPT("aq-sensitivity") ++ p->analyse.f_aq_sensitivity = atof(value); + OPT("deadzone-inter") + p->analyse.i_luma_deadzone[0] = atoi(value); + OPT("deadzone-intra") +@@ -883,6 +893,10 @@ + s += sprintf( s, " ip_ratio=%.2f", p->rc.f_ip_factor ); + if( p->i_bframe ) + s += sprintf( s, " pb_ratio=%.2f", p->rc.f_pb_factor ); ++ if( p->analyse.b_aq ) ++ s += sprintf( s, " aq=1:%.1f:%.1f", p->analyse.f_aq_strength, p->analyse.f_aq_sensitivity ); ++ else ++ s += sprintf( s, " aq=0" ); + if( p->rc.psz_zones ) + s += sprintf( s, " zones=%s", p->rc.psz_zones ); + else if( p->rc.i_zones ) +Index: x264.h +=================================================================== +--- x264.h (revision 736) ++++ x264.h (working copy) +@@ -232,6 +232,9 @@ + int i_trellis; /* trellis RD quantization */ + int b_fast_pskip; /* early SKIP detection on P-frames */ + int b_dct_decimate; /* transform coefficient thresholding on P-frames */ ++ int b_aq; /* psy adaptive QP */ ++ float f_aq_strength; ++ float f_aq_sensitivity; + int i_noise_reduction; /* adaptive pseudo-deadzone */ + + /* the deadzone size that will be used in luma quantization */ +