From 9b94896b3735052cabb52d081de3b50020a077cb Mon Sep 17 00:00:00 2001 From: Kieran Kunhya Date: Sat, 20 Jul 2013 18:47:59 +0100 Subject: [PATCH] AVC-Intra support This format has been reverse engineered and x264's output has almost exactly the same bitstream as Panasonic cameras and encoders produce. It therefore does not comply with SMPTE RP2027 since Panasonic themselves do not comply with their own specification. It has been tested in Avid, Premiere, Edius and Quantel. Parts of this patch were written by Fiona Glaser and some reverse engineering was done by Joseph Artsimovich. --- common/common.c | 2 + common/common.h | 1 + common/set.h | 92 +++++++++++ encoder/analyse.c | 92 +++++------ encoder/encoder.c | 364 +++++++++++++++++++++++++++++++++++------- encoder/ratecontrol.c | 30 ++-- encoder/set.c | 25 ++- encoder/set.h | 1 + x264.c | 4 +- x264.h | 8 +- 10 files changed, 499 insertions(+), 120 deletions(-) diff --git a/common/common.c b/common/common.c index 4e5ca82f..ba9f5d1c 100644 --- a/common/common.c +++ b/common/common.c @@ -671,6 +671,8 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value ) } OPT("bluray-compat") p->b_bluray_compat = atobool(value); + OPT("avcintra-compat") + p->b_avcintra_compat = atobool(value); OPT("sar") { b_error = ( 2 != sscanf( value, "%d:%d", &p->vui.i_sar_width, &p->vui.i_sar_height ) && diff --git a/common/common.h b/common/common.h index 12e5763b..c9f7bf0e 100644 --- a/common/common.h +++ b/common/common.h @@ -109,6 +109,7 @@ do {\ #define NALU_OVERHEAD 5 // startcode + NAL type costs 5 bytes per frame #define FILLER_OVERHEAD (NALU_OVERHEAD+1) +#define SEI_OVERHEAD (NALU_OVERHEAD - (h->param.b_annexb && !h->param.b_avcintra_compat && (h->out.i_nal-1))) /**************************************************************************** * Includes diff --git a/common/set.h b/common/set.h index b41ad5c8..2bb11fc4 100644 --- a/common/set.h +++ b/common/set.h @@ -248,6 +248,98 @@ static const uint8_t * const x264_cqm_jvt[8] = x264_cqm_jvt8i, x264_cqm_jvt8p }; +// 1080i25_avci50, 1080p25_avci50 +static const uint8_t x264_cqm_avci50_4ic[16] = +{ + 16,22,28,40, + 22,28,40,44, + 28,40,44,48, + 40,44,48,60 +}; + +// 1080i25_avci50, +static const uint8_t x264_cqm_avci50_1080i_8iy[64] = +{ + 16,18,19,21,27,33,81,87, + 18,19,21,24,30,33,81,87, + 19,21,24,27,30,78,84,90, + 21,24,27,30,33,78,84,90, + 24,27,30,33,78,81,84,90, + 24,27,30,33,78,81,84,93, + 27,30,33,78,78,81,87,93, + 30,33,33,78,81,84,87,96 +}; + +// 1080p25_avci50, 720p25_avci50, 720p50_avci50 +static const uint8_t x264_cqm_avci50_p_8iy[64] = +{ + 16,18,19,21,24,27,30,33, + 18,19,21,24,27,30,33,78, + 19,21,24,27,30,33,78,81, + 21,24,27,30,33,78,81,84, + 24,27,30,33,78,81,84,87, + 27,30,33,78,81,84,87,90, + 30,33,78,81,84,87,90,93, + 33,78,81,84,87,90,93,96 +}; + +// 1080i25_avci100, 1080p25_avci100 +static const uint8_t x264_cqm_avci100_1080_4ic[16] = +{ + 16,20,26,32, + 20,26,32,38, + 26,32,38,44, + 32,38,44,50 +}; + +// 720p25_avci100, 720p50_avci100 +static const uint8_t x264_cqm_avci100_720p_4ic[16] = +{ + 16,21,27,34, + 21,27,34,41, + 27,34,41,46, + 34,41,46,54 +}; + +// 1080i25_avci100, +static const uint8_t x264_cqm_avci100_1080i_8iy[64] = +{ + 16,19,20,23,24,26,32,42, + 18,19,22,24,26,32,36,42, + 18,20,23,24,26,32,36,63, + 19,20,23,26,32,36,42,63, + 20,22,24,26,32,36,59,63, + 22,23,24,26,32,36,59,68, + 22,23,24,26,32,42,59,68, + 22,23,24,26,36,42,59,72 +}; + +// 1080p25_avci100, +static const uint8_t x264_cqm_avci100_1080p_8iy[64] = +{ + 16,18,19,20,22,23,24,26, + 18,19,20,22,23,24,26,32, + 19,20,22,23,24,26,32,36, + 20,22,23,24,26,32,36,42, + 22,23,24,26,32,36,42,59, + 23,24,26,32,36,42,59,63, + 24,26,32,36,42,59,63,68, + 26,32,36,42,59,63,68,72 +}; + +// 720p25_avci100, 720p50_avci100 +static const uint8_t x264_cqm_avci100_720p_8iy[64] = +{ + 16,18,19,21,22,24,26,32, + 18,19,19,21,22,24,26,32, + 19,19,21,22,22,24,26,32, + 21,21,22,22,23,24,26,34, + 22,22,22,23,24,25,26,34, + 24,24,24,24,25,26,34,36, + 26,26,26,26,26,34,36,38, + 32,32,32,34,34,36,38,42 +}; + int x264_cqm_init( x264_t *h ); void x264_cqm_delete( x264_t *h ); int x264_cqm_parse_file( x264_t *h, const char *filename ); diff --git a/encoder/analyse.c b/encoder/analyse.c index 3780ddee..d1b00f46 100644 --- a/encoder/analyse.c +++ b/encoder/analyse.c @@ -436,7 +436,7 @@ static void x264_mb_analyse_init( x264_t *h, x264_mb_analysis_t *a, int qp ) /* non-RD PCM decision is inaccurate (as is psy-rd), so don't do it. * PCM cost can overflow with high lambda2, so cap it at COST_MAX. */ uint64_t pcm_cost = ((uint64_t)X264_PCM_COST*a->i_lambda2 + 128) >> 8; - a->i_satd_pcm = !h->mb.i_psy_rd && a->i_mbrd && pcm_cost < COST_MAX ? pcm_cost : COST_MAX; + a->i_satd_pcm = !h->param.b_avcintra_compat && !h->mb.i_psy_rd && a->i_mbrd && pcm_cost < COST_MAX ? pcm_cost : COST_MAX; a->b_fast_intra = 0; a->b_avoid_topright = 0; @@ -811,58 +811,60 @@ static void x264_mb_analyse_intra( x264_t *h, x264_mb_analysis_t *a, int i_satd_ int lambda = a->i_lambda; /*---------------- Try all mode and calculate their score ---------------*/ - - /* 16x16 prediction selection */ - const int8_t *predict_mode = predict_16x16_mode_available( h->mb.i_neighbour_intra ); - - /* Not heavily tuned */ - static const uint8_t i16x16_thresh_lut[11] = { 2, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4 }; - int i16x16_thresh = a->b_fast_intra ? (i16x16_thresh_lut[h->mb.i_subpel_refine]*i_satd_inter)>>1 : COST_MAX; - - if( !h->mb.b_lossless && predict_mode[3] >= 0 ) + /* Disabled i16x16 for AVC-Intra compat */ + if( !h->param.b_avcintra_compat ) { - h->pixf.intra_mbcmp_x3_16x16( p_src, p_dst, a->i_satd_i16x16_dir ); - a->i_satd_i16x16_dir[0] += lambda * bs_size_ue(0); - a->i_satd_i16x16_dir[1] += lambda * bs_size_ue(1); - a->i_satd_i16x16_dir[2] += lambda * bs_size_ue(2); - COPY2_IF_LT( a->i_satd_i16x16, a->i_satd_i16x16_dir[0], a->i_predict16x16, 0 ); - COPY2_IF_LT( a->i_satd_i16x16, a->i_satd_i16x16_dir[1], a->i_predict16x16, 1 ); - COPY2_IF_LT( a->i_satd_i16x16, a->i_satd_i16x16_dir[2], a->i_predict16x16, 2 ); + const int8_t *predict_mode = predict_16x16_mode_available( h->mb.i_neighbour_intra ); - /* Plane is expensive, so don't check it unless one of the previous modes was useful. */ - if( a->i_satd_i16x16 <= i16x16_thresh ) + /* Not heavily tuned */ + static const uint8_t i16x16_thresh_lut[11] = { 2, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4 }; + int i16x16_thresh = a->b_fast_intra ? (i16x16_thresh_lut[h->mb.i_subpel_refine]*i_satd_inter)>>1 : COST_MAX; + + if( !h->mb.b_lossless && predict_mode[3] >= 0 ) { - h->predict_16x16[I_PRED_16x16_P]( p_dst ); - a->i_satd_i16x16_dir[I_PRED_16x16_P] = h->pixf.mbcmp[PIXEL_16x16]( p_dst, FDEC_STRIDE, p_src, FENC_STRIDE ); - a->i_satd_i16x16_dir[I_PRED_16x16_P] += lambda * bs_size_ue(3); - COPY2_IF_LT( a->i_satd_i16x16, a->i_satd_i16x16_dir[I_PRED_16x16_P], a->i_predict16x16, 3 ); + h->pixf.intra_mbcmp_x3_16x16( p_src, p_dst, a->i_satd_i16x16_dir ); + a->i_satd_i16x16_dir[0] += lambda * bs_size_ue(0); + a->i_satd_i16x16_dir[1] += lambda * bs_size_ue(1); + a->i_satd_i16x16_dir[2] += lambda * bs_size_ue(2); + COPY2_IF_LT( a->i_satd_i16x16, a->i_satd_i16x16_dir[0], a->i_predict16x16, 0 ); + COPY2_IF_LT( a->i_satd_i16x16, a->i_satd_i16x16_dir[1], a->i_predict16x16, 1 ); + COPY2_IF_LT( a->i_satd_i16x16, a->i_satd_i16x16_dir[2], a->i_predict16x16, 2 ); + + /* Plane is expensive, so don't check it unless one of the previous modes was useful. */ + if( a->i_satd_i16x16 <= i16x16_thresh ) + { + h->predict_16x16[I_PRED_16x16_P]( p_dst ); + a->i_satd_i16x16_dir[I_PRED_16x16_P] = h->pixf.mbcmp[PIXEL_16x16]( p_dst, FDEC_STRIDE, p_src, FENC_STRIDE ); + a->i_satd_i16x16_dir[I_PRED_16x16_P] += lambda * bs_size_ue(3); + COPY2_IF_LT( a->i_satd_i16x16, a->i_satd_i16x16_dir[I_PRED_16x16_P], a->i_predict16x16, 3 ); + } } - } - else - { - for( ; *predict_mode >= 0; predict_mode++ ) + else { - int i_satd; - int i_mode = *predict_mode; + for( ; *predict_mode >= 0; predict_mode++ ) + { + int i_satd; + int i_mode = *predict_mode; - if( h->mb.b_lossless ) - x264_predict_lossless_16x16( h, 0, i_mode ); - else - h->predict_16x16[i_mode]( p_dst ); + if( h->mb.b_lossless ) + x264_predict_lossless_16x16( h, 0, i_mode ); + else + h->predict_16x16[i_mode]( p_dst ); - i_satd = h->pixf.mbcmp[PIXEL_16x16]( p_dst, FDEC_STRIDE, p_src, FENC_STRIDE ) + - lambda * bs_size_ue( x264_mb_pred_mode16x16_fix[i_mode] ); - COPY2_IF_LT( a->i_satd_i16x16, i_satd, a->i_predict16x16, i_mode ); - a->i_satd_i16x16_dir[i_mode] = i_satd; + i_satd = h->pixf.mbcmp[PIXEL_16x16]( p_dst, FDEC_STRIDE, p_src, FENC_STRIDE ) + + lambda * bs_size_ue( x264_mb_pred_mode16x16_fix[i_mode] ); + COPY2_IF_LT( a->i_satd_i16x16, i_satd, a->i_predict16x16, i_mode ); + a->i_satd_i16x16_dir[i_mode] = i_satd; + } } - } - if( h->sh.i_type == SLICE_TYPE_B ) - /* cavlc mb type prefix */ - a->i_satd_i16x16 += lambda * i_mb_b_cost_table[I_16x16]; + if( h->sh.i_type == SLICE_TYPE_B ) + /* cavlc mb type prefix */ + a->i_satd_i16x16 += lambda * i_mb_b_cost_table[I_16x16]; - if( a->i_satd_i16x16 > i16x16_thresh ) - return; + if( a->i_satd_i16x16 > i16x16_thresh ) + return; + } uint16_t *cost_i4x4_mode = (uint16_t*)ALIGN((intptr_t)x264_cost_i4x4_mode,64) + a->i_qp*32 + 8; /* 8x8 prediction selection */ @@ -888,7 +890,7 @@ static void x264_mb_analyse_intra( x264_t *h, x264_mb_analysis_t *a, int i_satd_ int i_best = COST_MAX; int i_pred_mode = x264_mb_predict_intra4x4_mode( h, 4*idx ); - predict_mode = predict_8x8_mode_available( a->b_avoid_topright, h->mb.i_neighbour8[idx], idx ); + const int8_t *predict_mode = predict_8x8_mode_available( a->b_avoid_topright, h->mb.i_neighbour8[idx], idx ); h->predict_8x8_filter( p_dst_by, edge, h->mb.i_neighbour8[idx], ALL_NEIGHBORS ); if( h->pixf.intra_mbcmp_x9_8x8 && predict_mode[8] >= 0 ) @@ -1003,7 +1005,7 @@ static void x264_mb_analyse_intra( x264_t *h, x264_mb_analysis_t *a, int i_satd_ int i_best = COST_MAX; int i_pred_mode = x264_mb_predict_intra4x4_mode( h, idx ); - predict_mode = predict_4x4_mode_available( a->b_avoid_topright, h->mb.i_neighbour4[idx], idx ); + const int8_t *predict_mode = predict_4x4_mode_available( a->b_avoid_topright, h->mb.i_neighbour4[idx], idx ); if( (h->mb.i_neighbour4[idx] & (MB_TOPRIGHT|MB_TOP)) == MB_TOP ) /* emulate missing topright samples */ diff --git a/encoder/encoder.c b/encoder/encoder.c index 9ff8acf1..3b3bc638 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -568,6 +568,8 @@ static int x264_validate_parameters( x264_t *h, int b_open ) { h->param.b_intra_refresh = 0; h->param.analyse.i_weighted_pred = 0; + h->param.i_frame_reference = 1; + h->param.i_dpb_size = 1; } h->param.i_frame_packing = x264_clip3( h->param.i_frame_packing, -1, 5 ); @@ -601,6 +603,165 @@ static int x264_validate_parameters( x264_t *h, int b_open ) x264_log( h, X264_LOG_ERROR, "no ratecontrol method specified\n" ); return -1; } + + if( PARAM_INTERLACED ) + h->param.b_pic_struct = 1; + + if( h->param.b_avcintra_compat ) + { + if( BIT_DEPTH != 10 ) + { + x264_log( h, X264_LOG_ERROR, "%2d-bit AVC-Intra is not widely compatible\n", BIT_DEPTH ); + x264_log( h, X264_LOG_ERROR, "10-bit x264 is required to encode AVC-Intra\n" ); + return -1; + } + + /* [50/100][res][fps] */ + static const struct + { + uint16_t fps_num; + uint16_t fps_den; + uint8_t interlaced; + uint16_t frame_size; + const uint8_t *cqm_4ic; + const uint8_t *cqm_8iy; + } avcintra_lut[2][2][5] = + { + {{{ 60000, 1001, 0, 912, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy }, + { 50, 1, 0, 1100, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy }, + { 30000, 1001, 0, 912, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy }, + { 25, 1, 0, 1100, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy }, + { 24000, 1001, 0, 912, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy }}, + {{ 30000, 1001, 1, 1820, x264_cqm_avci50_4ic, x264_cqm_avci50_1080i_8iy }, + { 25, 1, 1, 2196, x264_cqm_avci50_4ic, x264_cqm_avci50_1080i_8iy }, + { 30000, 1001, 0, 1820, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy }, + { 25, 1, 0, 2196, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy }, + { 24000, 1001, 0, 1820, x264_cqm_avci50_4ic, x264_cqm_avci50_p_8iy }}}, + {{{ 60000, 1001, 0, 1848, x264_cqm_avci100_720p_4ic, x264_cqm_avci100_720p_8iy }, + { 50, 1, 0, 2224, x264_cqm_avci100_720p_4ic, x264_cqm_avci100_720p_8iy }, + { 30000, 1001, 0, 1848, x264_cqm_avci100_720p_4ic, x264_cqm_avci100_720p_8iy }, + { 25, 1, 0, 2224, x264_cqm_avci100_720p_4ic, x264_cqm_avci100_720p_8iy }, + { 24000, 1001, 0, 1848, x264_cqm_avci100_720p_4ic, x264_cqm_avci100_720p_8iy }}, + {{ 30000, 1001, 1, 3692, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080i_8iy }, + { 25, 1, 1, 4444, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080i_8iy }, + { 30000, 1001, 0, 3692, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy }, + { 25, 1, 0, 4444, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy }, + { 24000, 1001, 0, 3692, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy }}} + }; + + int res = -1; + int type = i_csp == X264_CSP_I422; + if( type ) + { + if( h->param.i_width == 1920 && h->param.i_height == 1080 ) res = 1; + else if( h->param.i_width == 1280 && h->param.i_height == 720 ) res = 0; + } + else if( i_csp == X264_CSP_I420 ) + { + if( h->param.i_width == 1440 && h->param.i_height == 1080 ) res = 1; + else if( h->param.i_width == 960 && h->param.i_height == 720 ) res = 0; + } + else + { + x264_log( h, X264_LOG_ERROR, "Invalid colorspace for AVC-Intra\n" ); + return -1; + } + + if( res < 0 ) + { + x264_log( h, X264_LOG_ERROR, "Resolution %dx%d invalid for AVC-Intra %s\n", + h->param.i_width, h->param.i_height, type ? "100" : "50" ); + return -1; + } + + if( h->param.nalu_process ) + { + x264_log( h, X264_LOG_ERROR, "nalu_process is not supported in AVC-Intra mode\n" ); + return -1; + } + + if( !h->param.b_repeat_headers ) + { + x264_log( h, X264_LOG_ERROR, "Separate headers not supported in AVC-Intra mode\n" ); + return -1; + } + + int i; + uint32_t fps_num = h->param.i_fps_num, fps_den = h->param.i_fps_den; + x264_reduce_fraction( &fps_num, &fps_den ); + for( i = 0; i < 5; i++ ) + { + if( avcintra_lut[type][res][i].fps_num == fps_num && + avcintra_lut[type][res][i].fps_den == fps_den && + avcintra_lut[type][res][i].interlaced == PARAM_INTERLACED ) + { + break; + } + } + if( i == 5 ) + { + x264_log( h, X264_LOG_ERROR, "FPS %d/%d%c not compatible with AVC-Intra\n", + h->param.i_fps_num, h->param.i_fps_den, PARAM_INTERLACED ? 'i' : 'p' ); + return -1; + } + + h->param.i_keyint_max = 1; + h->param.b_intra_refresh = 0; + h->param.analyse.i_weighted_pred = 0; + h->param.i_frame_reference = 1; + h->param.i_dpb_size = 1; + + h->param.b_bluray_compat = 0; + h->param.b_vfr_input = 0; + h->param.b_aud = 1; + h->param.vui.i_chroma_loc = 0; + h->param.i_nal_hrd = X264_NAL_HRD_NONE; + h->param.b_deblocking_filter = 0; + h->param.b_stitchable = 1; + h->param.b_pic_struct = 0; + h->param.analyse.b_transform_8x8 = 1; + h->param.analyse.intra = X264_ANALYSE_I8x8; + h->param.analyse.i_chroma_qp_offset = res && type ? 3 : 4; + h->param.b_cabac = !type; + h->param.rc.i_vbv_buffer_size = avcintra_lut[type][res][i].frame_size; + h->param.rc.i_vbv_max_bitrate = + h->param.rc.i_bitrate = h->param.rc.i_vbv_buffer_size * fps_num / fps_den; + h->param.rc.i_rc_method = X264_RC_ABR; + h->param.rc.f_vbv_buffer_init = 1.0; + h->param.i_cqm_preset = X264_CQM_CUSTOM; + memcpy( h->param.cqm_4iy, x264_cqm_jvt4i, sizeof(h->param.cqm_4iy) ); + memcpy( h->param.cqm_4ic, avcintra_lut[type][res][i].cqm_4ic, sizeof(h->param.cqm_4ic) ); + memcpy( h->param.cqm_8iy, avcintra_lut[type][res][i].cqm_8iy, sizeof(h->param.cqm_8iy) ); + + /* Need exactly 10 slices of equal MB count... why? $deity knows... */ + h->param.i_slice_max_mbs = ((h->param.i_width + 15) / 16) * ((h->param.i_height + 15) / 16) / 10; + h->param.i_slice_max_size = 0; + /* The slice structure only allows a maximum of 2 threads for 1080i/p + * and 1 or 5 threads for 720p */ + if( h->param.b_sliced_threads ) + { + if( res ) + h->param.i_threads = X264_MIN( 2, h->param.i_threads ); + else + { + h->param.i_threads = X264_MIN( 5, h->param.i_threads ); + if( h->param.i_threads < 5 ) + h->param.i_threads = 1; + } + } + + if( type ) + h->param.vui.i_sar_width = h->param.vui.i_sar_height = 1; + else + { + h->param.vui.i_sar_width = 4; + h->param.vui.i_sar_height = 3; + } + + /* Avid cannot handle negative QPs */ + h->param.rc.i_qp_min = X264_MAX( h->param.rc.i_qp_min, QP_BD_OFFSET ); + } + h->param.rc.f_rf_constant = x264_clip3f( h->param.rc.f_rf_constant, -QP_BD_OFFSET, 51 ); h->param.rc.f_rf_constant_max = x264_clip3f( h->param.rc.f_rf_constant_max, -QP_BD_OFFSET, 51 ); h->param.rc.i_qp_constant = x264_clip3( h->param.rc.i_qp_constant, 0, QP_MAX ); @@ -902,10 +1063,10 @@ static int x264_validate_parameters( x264_t *h, int b_open ) h->param.analyse.i_chroma_qp_offset += 6; /* Psy RDO increases overall quantizers to improve the quality of luma--this indirectly hurts chroma quality */ /* so we lower the chroma QP offset to compensate */ - if( b_open && h->mb.i_psy_rd ) + if( b_open && h->mb.i_psy_rd && !h->param.b_avcintra_compat ) h->param.analyse.i_chroma_qp_offset -= h->param.analyse.f_psy_rd < 0.25 ? 1 : 2; /* Psy trellis has a similar effect. */ - if( b_open && h->mb.i_psy_trellis ) + if( b_open && h->mb.i_psy_trellis && !h->param.b_avcintra_compat ) h->param.analyse.i_chroma_qp_offset -= h->param.analyse.f_psy_trellis < 0.25 ? 1 : 2; h->param.analyse.i_chroma_qp_offset = x264_clip3(h->param.analyse.i_chroma_qp_offset, -12, 12); /* MB-tree requires AQ to be on, even if the strength is zero. */ @@ -1026,9 +1187,6 @@ static int x264_validate_parameters( x264_t *h, int b_open ) h->param.i_sps_id &= 31; - 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 ); if( h->param.i_nal_hrd && !h->param.rc.i_vbv_buffer_size ) @@ -1067,6 +1225,7 @@ static int x264_validate_parameters( x264_t *h, int b_open ) BOOLIFY( b_stitchable ); BOOLIFY( b_full_recon ); BOOLIFY( b_opencl ); + BOOLIFY( b_avcintra_compat ); BOOLIFY( analyse.b_transform_8x8 ); BOOLIFY( analyse.b_weighted_bipred ); BOOLIFY( analyse.b_chroma_me ); @@ -1615,6 +1774,7 @@ static void x264_nal_start( x264_t *h, int i_type, int i_ref_idc ) nal->i_payload= 0; nal->p_payload= &h->out.p_bitstream[bs_pos( &h->out.bs ) / 8]; + nal->i_padding= 0; } /* if number of allocated nals is not enough, re-allocate a larger one. */ @@ -1648,6 +1808,30 @@ static int x264_nal_end( x264_t *h ) return x264_nal_check_buffer( h ); } +static int x264_check_encapsulated_buffer( x264_t *h, x264_t *h0, int start, + int previous_nal_size, int necessary_size ) +{ + if( h0->nal_buffer_size < necessary_size ) + { + necessary_size *= 2; + uint8_t *buf = x264_malloc( necessary_size ); + if( !buf ) + return -1; + if( previous_nal_size ) + memcpy( buf, h0->nal_buffer, previous_nal_size ); + + intptr_t delta = buf - h0->nal_buffer; + for( int i = 0; i < start; i++ ) + h->out.nal[i].p_payload += delta; + + x264_free( h0->nal_buffer ); + h0->nal_buffer = buf; + h0->nal_buffer_size = necessary_size; + } + + return 0; +} + static int x264_encoder_encapsulate_nals( x264_t *h, int start ) { x264_t *h0 = h->thread[0]; @@ -1668,31 +1852,31 @@ static int x264_encoder_encapsulate_nals( x264_t *h, int start ) /* Worst-case NAL unit escaping: reallocate the buffer if it's too small. */ int necessary_size = previous_nal_size + nal_size * 3/2 + h->out.i_nal * 4 + 4 + 64; - if( h0->nal_buffer_size < necessary_size ) - { - necessary_size *= 2; - uint8_t *buf = x264_malloc( necessary_size ); - if( !buf ) - return -1; - if( previous_nal_size ) - memcpy( buf, h0->nal_buffer, previous_nal_size ); - - intptr_t delta = buf - h0->nal_buffer; - for( int i = 0; i < start; i++ ) - h->out.nal[i].p_payload += delta; - - x264_free( h0->nal_buffer ); - h0->nal_buffer = buf; - h0->nal_buffer_size = necessary_size; - } + for( int i = start; i < h->out.i_nal; i++ ) + necessary_size += h->out.nal[i].i_padding; + if( x264_check_encapsulated_buffer( h, h0, start, previous_nal_size, necessary_size ) ) + return -1; uint8_t *nal_buffer = h0->nal_buffer + previous_nal_size; for( int i = start; i < h->out.i_nal; i++ ) { - h->out.nal[i].b_long_startcode = !i || h->out.nal[i].i_type == NAL_SPS || h->out.nal[i].i_type == NAL_PPS; + int old_payload_len = h->out.nal[i].i_payload; + h->out.nal[i].b_long_startcode = !i || h->out.nal[i].i_type == NAL_SPS || h->out.nal[i].i_type == NAL_PPS || + h->param.b_avcintra_compat; x264_nal_encode( h, nal_buffer, &h->out.nal[i] ); nal_buffer += h->out.nal[i].i_payload; + if( h->param.b_avcintra_compat ) + { + h->out.nal[i].i_padding -= h->out.nal[i].i_payload - (old_payload_len + NALU_OVERHEAD); + if( h->out.nal[i].i_padding > 0 ) + { + memset( nal_buffer, 0, h->out.nal[i].i_padding ); + nal_buffer += h->out.nal[i].i_padding; + h->out.nal[i].i_payload += h->out.nal[i].i_padding; + } + h->out.nal[i].i_padding = X264_MAX( h->out.nal[i].i_padding, 0 ); + } } x264_emms(); @@ -3188,7 +3372,7 @@ int x264_encoder_encode( x264_t *h, bs_rbsp_trailing( &h->out.bs ); 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); + overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD; } h->i_nal_type = i_nal_type; @@ -3240,14 +3424,19 @@ int x264_encoder_encode( x264_t *h, x264_sps_write( &h->out.bs, h->sps ); if( x264_nal_end( h ) ) return -1; - overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD; + /* Pad AUD/SPS to 256 bytes like Panasonic */ + if( h->param.b_avcintra_compat ) + h->out.nal[h->out.i_nal-1].i_padding = 256 - bs_pos( &h->out.bs ) / 8 - 2*NALU_OVERHEAD; + overhead += h->out.nal[h->out.i_nal-1].i_payload + h->out.nal[h->out.i_nal-1].i_padding + NALU_OVERHEAD; /* generate picture parameters */ x264_nal_start( h, NAL_PPS, NAL_PRIORITY_HIGHEST ); x264_pps_write( &h->out.bs, h->sps, h->pps ); if( x264_nal_end( h ) ) return -1; - overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD; + if( h->param.b_avcintra_compat ) + h->out.nal[h->out.i_nal-1].i_padding = 256 - h->out.nal[h->out.i_nal-1].i_payload - NALU_OVERHEAD; + overhead += h->out.nal[h->out.i_nal-1].i_payload + h->out.nal[h->out.i_nal-1].i_padding + NALU_OVERHEAD; } /* when frame threading is used, buffering period sei is written in x264_encoder_frame_end */ @@ -3258,7 +3447,7 @@ int x264_encoder_encode( x264_t *h, x264_sei_buffering_period_write( h, &h->out.bs ); if( x264_nal_end( h ) ) return -1; - overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD; + overhead += h->out.nal[h->out.i_nal-1].i_payload + SEI_OVERHEAD; } } @@ -3270,7 +3459,7 @@ int x264_encoder_encode( x264_t *h, h->fenc->extra_sei.payloads[i].payload_type ); 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); + overhead += h->out.nal[h->out.i_nal-1].i_payload + SEI_OVERHEAD; if( h->fenc->extra_sei.sei_free ) { h->fenc->extra_sei.sei_free( h->fenc->extra_sei.payloads[i].payload ); @@ -3287,7 +3476,8 @@ int x264_encoder_encode( x264_t *h, if( h->fenc->b_keyframe ) { - if( h->param.b_repeat_headers && h->fenc->i_frame == 0 ) + /* Avid's decoder strictly wants two SEIs for AVC-Intra so we can't insert the x264 SEI */ + if( h->param.b_repeat_headers && h->fenc->i_frame == 0 && !h->param.b_avcintra_compat ) { /* identify ourself */ x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); @@ -3295,7 +3485,7 @@ int x264_encoder_encode( x264_t *h, return -1; 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); + overhead += h->out.nal[h->out.i_nal-1].i_payload + SEI_OVERHEAD; } if( h->fenc->i_type != X264_TYPE_IDR ) @@ -3305,16 +3495,16 @@ int x264_encoder_encode( x264_t *h, x264_sei_recovery_point_write( h, &h->out.bs, time_to_recovery ); 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); + overhead += h->out.nal[h->out.i_nal-1].i_payload + SEI_OVERHEAD; } - if ( h->param.i_frame_packing >= 0 ) + if( h->param.i_frame_packing >= 0 ) { x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); x264_sei_frame_packing_write( h, &h->out.bs ); 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); + overhead += h->out.nal[h->out.i_nal-1].i_payload + SEI_OVERHEAD; } } @@ -3325,7 +3515,7 @@ int x264_encoder_encode( x264_t *h, x264_sei_pic_timing_write( h, &h->out.bs ); 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); + overhead += h->out.nal[h->out.i_nal-1].i_payload + SEI_OVERHEAD; } /* As required by Blu-ray. */ @@ -3336,12 +3526,58 @@ int x264_encoder_encode( x264_t *h, x264_sei_dec_ref_pic_marking_write( h, &h->out.bs ); 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); + overhead += h->out.nal[h->out.i_nal-1].i_payload + SEI_OVERHEAD; } if( h->fenc->b_keyframe && h->param.b_intra_refresh ) h->i_cpb_delay_pir_offset_next = h->fenc->i_cpb_delay; + /* Filler space: 10 or 18 SEIs' worth of space, depending on resolution */ + if( h->param.b_avcintra_compat ) + { + /* Write an empty filler NAL to mimic the AUD in the P2 format*/ + if( h->param.b_avcintra_compat ) + { + x264_nal_start( h, NAL_FILLER, NAL_PRIORITY_DISPOSABLE ); + x264_filler_write( h, &h->out.bs, 0 ); + if( x264_nal_end( h ) ) + return -1; + overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD; + } + + /* All lengths are magic lengths that decoders expect to see */ + /* "UMID" SEI */ + x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); + if( x264_sei_avcintra_write( h, &h->out.bs, 497, "UMID" ) < 0 ) + return -1; + if( x264_nal_end( h ) ) + return -1; + overhead += h->out.nal[h->out.i_nal-1].i_payload + SEI_OVERHEAD; + + + int unpadded_len; + int total_len; + if( h->param.i_height == 1080 ) + { + unpadded_len = 5780; + total_len = 17*512; + } + else + { + unpadded_len = 2900; + total_len = 9*512; + } + /* "VANC" SEI */ + x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); + if( x264_sei_avcintra_write( h, &h->out.bs, unpadded_len, "VANC" ) < 0 ) + return -1; + if( x264_nal_end( h ) ) + return -1; + + h->out.nal[h->out.i_nal-1].i_padding = total_len - h->out.nal[h->out.i_nal-1].i_payload - SEI_OVERHEAD; + overhead += h->out.nal[h->out.i_nal-1].i_payload + h->out.nal[h->out.i_nal-1].i_padding + SEI_OVERHEAD; + } + /* Init the rate control */ /* FIXME: Include slice header bit cost. */ x264_ratecontrol_start( h, h->fenc->i_qpplus1, overhead*8 ); @@ -3471,30 +3707,46 @@ static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current, pic_out->hrd_timing = h->fenc->hrd_timing; pic_out->prop.f_crf_avg = h->fdec->f_crf_avg; - while( filler > 0 ) + /* Filler in AVC-Intra mode is written as zero bytes to the last slice + * We don't know the size of the last slice until encapsulation so we add filler to the encapsulated NAL */ + if( h->param.b_avcintra_compat ) + { + x264_t *h0 = h->thread[0]; + int ret = x264_check_encapsulated_buffer( h, h0, h->out.i_nal, frame_size, frame_size + filler ); + if( ret < 0 ) + return -1; + memset( h->out.nal[0].p_payload + frame_size, 0, filler ); + h->out.nal[h->out.i_nal-1].i_payload += filler; + h->out.nal[h->out.i_nal-1].i_padding = filler; + frame_size += filler; + } + else { - int f, overhead; - overhead = (FILLER_OVERHEAD - h->param.b_annexb); - if( h->param.i_slice_max_size && filler > h->param.i_slice_max_size ) + while( filler > 0 ) { - int next_size = filler - h->param.i_slice_max_size; - int overflow = X264_MAX( overhead - next_size, 0 ); - f = h->param.i_slice_max_size - overhead - overflow; - } - else - f = X264_MAX( 0, filler - overhead ); + int f, overhead; + overhead = (FILLER_OVERHEAD - h->param.b_annexb); + if( h->param.i_slice_max_size && filler > h->param.i_slice_max_size ) + { + int next_size = filler - h->param.i_slice_max_size; + int overflow = X264_MAX( overhead - next_size, 0 ); + f = h->param.i_slice_max_size - overhead - overflow; + } + else + f = X264_MAX( 0, filler - overhead ); - if( x264_bitstream_check_buffer_filler( h, f ) ) - return -1; - x264_nal_start( h, NAL_FILLER, NAL_PRIORITY_DISPOSABLE ); - x264_filler_write( h, &h->out.bs, f ); - if( x264_nal_end( h ) ) - return -1; - int total_size = x264_encoder_encapsulate_nals( h, h->out.i_nal-1 ); - if( total_size < 0 ) - return -1; - frame_size += total_size; - filler -= total_size; + if( x264_bitstream_check_buffer_filler( h, f ) ) + return -1; + x264_nal_start( h, NAL_FILLER, NAL_PRIORITY_DISPOSABLE ); + x264_filler_write( h, &h->out.bs, f ); + if( x264_nal_end( h ) ) + return -1; + int total_size = x264_encoder_encapsulate_nals( h, h->out.i_nal-1 ); + if( total_size < 0 ) + return -1; + frame_size += total_size; + filler -= total_size; + } } /* End bitstream, set output */ diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index f7659228..00121847 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -653,8 +653,9 @@ void x264_ratecontrol_init_reconfigurable( x264_t *h, int b_init ) h->param.rc.i_vbv_buffer_size ); } - int vbv_buffer_size = h->param.rc.i_vbv_buffer_size * 1000; - int vbv_max_bitrate = h->param.rc.i_vbv_max_bitrate * 1000; + int kilobit_size = h->param.b_avcintra_compat ? 1024 : 1000; + int vbv_buffer_size = h->param.rc.i_vbv_buffer_size * kilobit_size; + int vbv_max_bitrate = h->param.rc.i_vbv_max_bitrate * kilobit_size; /* Init HRD */ if( h->param.i_nal_hrd && b_init ) @@ -666,15 +667,12 @@ 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_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( 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_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 @@ -701,11 +699,13 @@ void x264_ratecontrol_init_reconfigurable( x264_t *h, int b_init ) x264_log( h, X264_LOG_WARNING, "VBV parameters cannot be changed when NAL HRD is in use\n" ); return; } + if( h->param.b_avcintra_compat ) + h->sps->vui.hrd.b_cbr_hrd = 1; 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.; + rc->bitrate = (double)h->param.rc.i_bitrate * kilobit_size; rc->buffer_rate = vbv_max_bitrate / rc->fps; rc->vbv_max_rate = vbv_max_bitrate; rc->buffer_size = vbv_buffer_size; @@ -761,7 +761,7 @@ int x264_ratecontrol_new( x264_t *h ) else rc->qcompress = h->param.rc.f_qcompress; - rc->bitrate = h->param.rc.i_bitrate * 1000.; + rc->bitrate = h->param.rc.i_bitrate * (h->param.b_avcintra_compat ? 1024. : 1000.); rc->rate_tolerance = h->param.rc.f_rate_tolerance; rc->nmb = h->mb.i_mb_count; rc->last_non_b_pict_type = -1; @@ -2110,13 +2110,17 @@ static int update_vbv( x264_t *h, int bits ) if( rct->buffer_fill_final < 0 ) x264_log( h, X264_LOG_WARNING, "VBV underflow (frame %d, %.0f bits)\n", h->i_frame, (double)rct->buffer_fill_final / h->sps->vui.i_time_scale ); rct->buffer_fill_final = X264_MAX( rct->buffer_fill_final, 0 ); - rct->buffer_fill_final += (uint64_t)bitrate * h->sps->vui.i_num_units_in_tick * h->fenc->i_cpb_duration; + + if( h->param.b_avcintra_compat ) + rct->buffer_fill_final += buffer_size; + else + rct->buffer_fill_final += (uint64_t)bitrate * h->sps->vui.i_num_units_in_tick * h->fenc->i_cpb_duration; if( h->sps->vui.hrd.b_cbr_hrd && rct->buffer_fill_final > buffer_size ) { int64_t scale = (int64_t)h->sps->vui.i_time_scale * 8; filler = (rct->buffer_fill_final - buffer_size + scale - 1) / scale; - bits = X264_MAX( (FILLER_OVERHEAD - h->param.b_annexb), filler ) * 8; + bits = h->param.b_avcintra_compat ? filler * 8 : X264_MAX( (FILLER_OVERHEAD - h->param.b_annexb), filler ) * 8; rct->buffer_fill_final -= (uint64_t)bits * h->sps->vui.i_time_scale; } else diff --git a/encoder/set.c b/encoder/set.c index bdd25d7b..bf83a0d4 100644 --- a/encoder/set.c +++ b/encoder/set.c @@ -91,7 +91,7 @@ void x264_sei_write( bs_t *s, uint8_t *payload, int payload_size, int payload_ty bs_write( s, 8, payload_size-i ); for( i = 0; i < payload_size; i++ ) - bs_write(s, 8, payload[i] ); + bs_write( s, 8, payload[i] ); bs_rbsp_trailing( s ); bs_flush( s ); @@ -249,7 +249,7 @@ void x264_sps_init( x264_sps_t *sps, int i_id, x264_param_t *param ) // NOTE: HRD related parts of the SPS are initialised in x264_ratecontrol_init_reconfigurable - sps->vui.b_bitstream_restriction = 1; + sps->vui.b_bitstream_restriction = param->i_keyint_max > 1; if( sps->vui.b_bitstream_restriction ) { sps->vui.b_motion_vectors_over_pic_boundaries = 1; @@ -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_avcintra_compat && param->b_interlaced; pps->i_num_slice_groups = 1; pps->i_num_ref_idx_l0_default_active = param->i_frame_reference; @@ -725,6 +725,25 @@ void x264_sei_dec_ref_pic_marking_write( x264_t *h, bs_t *s ) x264_sei_write( s, tmp_buf, bs_pos( &q ) / 8, SEI_DEC_REF_PIC_MARKING ); } +int x264_sei_avcintra_write( x264_t *h, bs_t *s, int len, const char *msg ) +{ + const static uint8_t avcintra_uuid[] = {0xF7, 0x49, 0x3E, 0xB3, 0xD4, 0x00, 0x47, 0x96, 0x86, 0x86, 0xC9, 0x70, 0x7B, 0x64, 0x37, 0x2A}; + uint8_t data[6000]; + if( len > sizeof(data) ) + { + x264_log( h, X264_LOG_ERROR, "AVC-Intra SEI is too large (%d)\n", len ); + return -1; + } + + memset( data, 0xff, len ); + memcpy( data, avcintra_uuid, sizeof(avcintra_uuid) ); + memcpy( data+16, msg, strlen(msg) ); + + x264_sei_write( &h->out.bs, data, len, SEI_USER_DATA_UNREGISTERED ); + + return 0; +} + const x264_level_t x264_levels[] = { { 10, 1485, 99, 396, 64, 175, 64, 64, 0, 2, 0, 0, 1 }, diff --git a/encoder/set.h b/encoder/set.h index 11f0c483..d6fb60a5 100644 --- a/encoder/set.h +++ b/encoder/set.h @@ -38,6 +38,7 @@ void x264_sei_buffering_period_write( x264_t *h, bs_t *s ); void x264_sei_pic_timing_write( x264_t *h, bs_t *s ); void x264_sei_dec_ref_pic_marking_write( x264_t *h, bs_t *s ); void x264_sei_frame_packing_write( x264_t *h, bs_t *s ); +int x264_sei_avcintra_write( x264_t *h, bs_t *s, int len, const char *msg ); void x264_sei_write( bs_t *s, uint8_t *payload, int payload_size, int payload_type ); void x264_filler_write( x264_t *h, bs_t *s, int filler ); diff --git a/x264.c b/x264.c index 4d6465e8..e2296048 100644 --- a/x264.c +++ b/x264.c @@ -792,6 +792,7 @@ static void help( x264_param_t *defaults, int longhelp ) H0( " --frames Maximum number of frames to encode\n" ); H0( " --level Specify level (as defined by Annex A)\n" ); H1( " --bluray-compat Enable compatibility hacks for Blu-ray support\n" ); + H1( " --avcintra-compat Enable compatibility hacks for AVC-Intra support\n" ); H1( " --stitchable Don't optimize headers based on video content\n" " Ensures ability to recombine a segmented encode\n" ); H1( "\n" ); @@ -815,7 +816,7 @@ static void help( x264_param_t *defaults, int longhelp ) H2( " --no-asm Disable all CPU optimizations\n" ); H2( " --opencl Enable use of OpenCL\n" ); H2( " --opencl-clbin Specify path of compiled OpenCL kernel cache\n" ); - H2( " --opencl-device Specify OpenCL device ordinal\n" ); + H2( " --opencl-device Specify OpenCL device ordinal\n" ); H2( " --visualize Show MB types overlayed on the encoded video\n" ); H2( " --dump-yuv Save reconstructed frames\n" ); H2( " --sps-id Set SPS and PPS id numbers [%d]\n", defaults->i_sps_id ); @@ -895,6 +896,7 @@ static struct option long_options[] = { "b-pyramid", required_argument, NULL, 0 }, { "open-gop", no_argument, NULL, 0 }, { "bluray-compat", no_argument, NULL, 0 }, + { "avcintra-compat", no_argument, NULL, 0 }, { "min-keyint", required_argument, NULL, 'i' }, { "keyint", required_argument, NULL, 'I' }, { "intra-refresh", no_argument, NULL, 0 }, diff --git a/x264.h b/x264.h index 4e44c835..f6611385 100644 --- a/x264.h +++ b/x264.h @@ -41,7 +41,7 @@ #include "x264_config.h" -#define X264_BUILD 136 +#define X264_BUILD 137 /* Application developers planning to link against a shared library version of * libx264 from a Microsoft Visual Studio or similar development environment @@ -98,12 +98,15 @@ typedef struct int i_first_mb; /* If this NAL is a slice, the index of the first MB in the slice. */ int i_last_mb; /* If this NAL is a slice, the index of the last MB in the slice. */ - /* Size of payload in bytes. */ + /* Size of payload (including any padding) in bytes. */ int i_payload; /* If param->b_annexb is set, Annex-B bytestream with startcode. * Otherwise, startcode is replaced with a 4-byte size. * This size is the size used in mp4/similar muxing; it is equal to i_payload-4 */ uint8_t *p_payload; + + /* Size of padding in bytes. */ + int i_padding; } x264_nal_t; /**************************************************************************** @@ -318,6 +321,7 @@ typedef struct x264_param_t int i_bframe_pyramid; /* Keep some B-frames as references: 0=off, 1=strict hierarchical, 2=normal */ int b_open_gop; int b_bluray_compat; + int b_avcintra_compat; int b_deblocking_filter; int i_deblocking_filter_alphac0; /* [-6, 6] -6 light filter, 6 strong */ -- 2.40.0