From: Kieran Kunhya Date: Fri, 10 Jan 2014 23:27:33 +0000 (+0000) Subject: Add support for AVC-Intra Class 200 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=dd6a303498d1f55c73037ed925a6ece8e28a95bc;p=libx264 Add support for AVC-Intra Class 200 --- diff --git a/common/common.c b/common/common.c index 76e80b94..a9e1c732 100644 --- a/common/common.c +++ b/common/common.c @@ -671,8 +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("avcintra-class") + p->i_avcintra_class = atoi(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 fa8fab36..ab14a632 100644 --- a/common/common.h +++ b/common/common.h @@ -109,7 +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))) +#define SEI_OVERHEAD (NALU_OVERHEAD - (h->param.b_annexb && !h->param.i_avcintra_class && (h->out.i_nal-1))) /**************************************************************************** * Includes diff --git a/encoder/analyse.c b/encoder/analyse.c index 0e8a280f..9131d3d7 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->param.b_avcintra_compat && !h->mb.i_psy_rd && a->i_mbrd && pcm_cost < COST_MAX ? pcm_cost : COST_MAX; + a->i_satd_pcm = !h->param.i_avcintra_class && !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; @@ -812,7 +812,7 @@ static void x264_mb_analyse_intra( x264_t *h, x264_mb_analysis_t *a, int i_satd_ /*---------------- Try all mode and calculate their score ---------------*/ /* Disabled i16x16 for AVC-Intra compat */ - if( !h->param.b_avcintra_compat ) + if( !h->param.i_avcintra_class ) { const int8_t *predict_mode = predict_16x16_mode_available( h->mb.i_neighbour_intra ); diff --git a/encoder/encoder.c b/encoder/encoder.c index d7302963..4ef02ed2 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -609,7 +609,7 @@ static int x264_validate_parameters( x264_t *h, int b_open ) if( PARAM_INTERLACED ) h->param.b_pic_struct = 1; - if( h->param.b_avcintra_compat ) + if( h->param.i_avcintra_class ) { if( BIT_DEPTH != 10 ) { @@ -618,7 +618,16 @@ static int x264_validate_parameters( x264_t *h, int b_open ) return -1; } - /* [50/100][res][fps] */ + int type = h->param.i_avcintra_class == 200 ? 2 : + h->param.i_avcintra_class == 100 ? 1 : + h->param.i_avcintra_class == 50 ? 0 : -1; + if( type < 0 ) + { + x264_log( h, X264_LOG_ERROR, "Invalid AVC-Intra class\n" ); + return -1; + } + + /* [50/100/200][res][fps] */ static const struct { uint16_t fps_num; @@ -627,7 +636,7 @@ static int x264_validate_parameters( x264_t *h, int b_open ) uint16_t frame_size; const uint8_t *cqm_4ic; const uint8_t *cqm_8iy; - } avcintra_lut[2][2][7] = + } avcintra_lut[3][2][7] = { {{{ 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 }, @@ -652,31 +661,39 @@ static int x264_validate_parameters( x264_t *h, int b_open ) { 30000, 1001, 0, 3692, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy }, { 50, 1, 0, 4444, 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 }}} + { 24000, 1001, 0, 3692, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy }}}, + {{{ 60000, 1001, 0, 3724, x264_cqm_avci100_720p_4ic, x264_cqm_avci100_720p_8iy }, + { 50, 1, 0, 4472, x264_cqm_avci100_720p_4ic, x264_cqm_avci100_720p_8iy }}, + {{ 30000, 1001, 1, 7444, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080i_8iy }, + { 25, 1, 1, 8940, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080i_8iy }, + { 60000, 1001, 0, 7444, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy }, + { 30000, 1001, 0, 7444, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy }, + { 50, 1, 0, 8940, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy }, + { 25, 1, 0, 8940, x264_cqm_avci100_1080_4ic, x264_cqm_avci100_1080p_8iy }, + { 24000, 1001, 0, 7444, 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( i_csp >= X264_CSP_I420 && i_csp < X264_CSP_I422 && !type ) { 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 if( i_csp >= X264_CSP_I422 && i_csp < X264_CSP_I444 && 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 { - x264_log( h, X264_LOG_ERROR, "Invalid colorspace for AVC-Intra\n" ); + x264_log( h, X264_LOG_ERROR, "Invalid colorspace for AVC-Intra %d\n", h->param.i_avcintra_class ); 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" ); + x264_log( h, X264_LOG_ERROR, "Resolution %dx%d invalid for AVC-Intra %d\n", + h->param.i_width, h->param.i_height, h->param.i_avcintra_class ); return -1; } @@ -765,8 +782,9 @@ static int x264_validate_parameters( x264_t *h, int b_open ) 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 ); + /* Official encoder doesn't appear to go under 13 + * and Avid cannot handle negative QPs */ + h->param.rc.i_qp_min = X264_MAX( h->param.rc.i_qp_min, QP_BD_OFFSET + 1 ); } h->param.rc.f_rf_constant = x264_clip3f( h->param.rc.f_rf_constant, -QP_BD_OFFSET, 51 ); @@ -1070,10 +1088,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 && !h->param.b_avcintra_compat ) + if( b_open && h->mb.i_psy_rd && !h->param.i_avcintra_class ) 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 && !h->param.b_avcintra_compat ) + if( b_open && h->mb.i_psy_trellis && !h->param.i_avcintra_class ) 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. */ @@ -1234,7 +1252,6 @@ 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 ); @@ -1894,10 +1911,10 @@ static int x264_encoder_encapsulate_nals( x264_t *h, int start ) { 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; + h->param.i_avcintra_class; x264_nal_encode( h, nal_buffer, &h->out.nal[i] ); nal_buffer += h->out.nal[i].i_payload; - if( h->param.b_avcintra_compat ) + if( h->param.i_avcintra_class ) { 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 ) @@ -3443,7 +3460,7 @@ int x264_encoder_encode( x264_t *h, if( x264_nal_end( h ) ) return -1; /* Pad AUD/SPS to 256 bytes like Panasonic */ - if( h->param.b_avcintra_compat ) + if( h->param.i_avcintra_class ) 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; @@ -3452,7 +3469,7 @@ int x264_encoder_encode( x264_t *h, x264_pps_write( &h->out.bs, h->sps, h->pps ); if( x264_nal_end( h ) ) return -1; - if( h->param.b_avcintra_compat ) + if( h->param.i_avcintra_class ) 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; } @@ -3495,7 +3512,7 @@ int x264_encoder_encode( x264_t *h, if( h->fenc->b_keyframe ) { /* 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 ) + if( h->param.b_repeat_headers && h->fenc->i_frame == 0 && !h->param.i_avcintra_class ) { /* identify ourself */ x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE ); @@ -3551,7 +3568,7 @@ int x264_encoder_encode( x264_t *h, 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 ) + if( h->param.i_avcintra_class ) { /* Write an empty filler NAL to mimic the AUD in the P2 format*/ x264_nal_start( h, NAL_FILLER, NAL_PRIORITY_DISPOSABLE ); @@ -3723,7 +3740,7 @@ static int x264_encoder_frame_end( x264_t *h, x264_t *thread_current, /* 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 ) + if( h->param.i_avcintra_class ) { x264_t *h0 = h->thread[0]; int ret = x264_check_encapsulated_buffer( h, h0, h->out.i_nal, frame_size, frame_size + filler ); diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index 3bf62d17..e408b00f 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -653,7 +653,7 @@ void x264_ratecontrol_init_reconfigurable( x264_t *h, int b_init ) h->param.rc.i_vbv_buffer_size ); } - int kilobit_size = h->param.b_avcintra_compat ? 1024 : 1000; + int kilobit_size = h->param.i_avcintra_class ? 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; @@ -759,7 +759,7 @@ int x264_ratecontrol_new( x264_t *h ) else rc->qcompress = h->param.rc.f_qcompress; - rc->bitrate = h->param.rc.i_bitrate * (h->param.b_avcintra_compat ? 1024. : 1000.); + rc->bitrate = h->param.rc.i_bitrate * (h->param.i_avcintra_class ? 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; @@ -2115,7 +2115,7 @@ static int update_vbv( x264_t *h, int bits ) } rct->buffer_fill_final = X264_MAX( rct->buffer_fill_final, 0 ); - if( h->param.b_avcintra_compat ) + if( h->param.i_avcintra_class ) 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; @@ -2124,7 +2124,7 @@ static int update_vbv( x264_t *h, int bits ) { int64_t scale = (int64_t)h->sps->vui.i_time_scale * 8; filler = (rct->buffer_fill_final - buffer_size + scale - 1) / scale; - bits = h->param.b_avcintra_compat ? filler * 8 : X264_MAX( (FILLER_OVERHEAD - h->param.b_annexb), filler ) * 8; + bits = h->param.i_avcintra_class ? 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 c3aa7c28..e867a7d7 100644 --- a/encoder/set.c +++ b/encoder/set.c @@ -422,7 +422,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_avcintra_compat && param->b_interlaced; + pps->b_pic_order = !param->i_avcintra_class && param->b_interlaced; pps->i_num_slice_groups = 1; pps->i_num_ref_idx_l0_default_active = param->i_frame_reference; diff --git a/x264.c b/x264.c index 79d14108..f1c758ac 100644 --- a/x264.c +++ b/x264.c @@ -880,7 +880,8 @@ 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( " --avcintra-class Use compatibility hacks for AVC-Intra class\n" + " - 50, 100, 200\n" ); H1( " --stitchable Don't optimize headers based on video content\n" " Ensures ability to recombine a segmented encode\n" ); H1( "\n" ); @@ -982,7 +983,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 }, + { "avcintra-class", required_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 625a2d9e..6ad63080 100644 --- a/x264.h +++ b/x264.h @@ -41,7 +41,7 @@ #include "x264_config.h" -#define X264_BUILD 141 +#define X264_BUILD 142 /* Application developers planning to link against a shared library version of * libx264 from a Microsoft Visual Studio or similar development environment @@ -322,7 +322,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 i_avcintra_class; int b_deblocking_filter; int i_deblocking_filter_alphac0; /* [-6, 6] -6 light filter, 6 strong */