X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=encoder%2Fslicetype.c;h=810779af1f1dd482a5b44da6ae84c86db800e498;hb=669cc1def2034a7ef55946df9f6e1ae13963eb8a;hp=8aff7eaee6fdddc767b20e7dfc7e4df975412438;hpb=fcda8dd98eaf9ceea950c95661f8228fb364fc0b;p=x264 diff --git a/encoder/slicetype.c b/encoder/slicetype.c index 8aff7eae..810779af 100644 --- a/encoder/slicetype.c +++ b/encoder/slicetype.c @@ -734,7 +734,7 @@ static void x264_macroblock_tree_propagate( x264_t *h, x264_frame_t **frames, in } } - if( h->param.rc.i_vbv_buffer_size && referenced ) + if( h->param.rc.i_vbv_buffer_size && h->param.rc.i_lookahead && referenced ) x264_macroblock_tree_finish( h, frames[b], b == p1 ? b - p0 : 0 ); } @@ -743,7 +743,8 @@ static void x264_macroblock_tree( x264_t *h, x264_mb_analysis_t *a, x264_frame_t int idx = !b_intra; int last_nonb, cur_nonb = 1; int bframes = 0; - int i = num_frames - 1; + int i = num_frames; + if( b_intra ) x264_slicetype_frame_cost( h, a, frames, 0, 0, 0, 0 ); @@ -751,10 +752,27 @@ static void x264_macroblock_tree( x264_t *h, x264_mb_analysis_t *a, x264_frame_t i--; last_nonb = i; - if( last_nonb < idx ) - return; + /* Lookaheadless MB-tree is not a theoretically distinct case; the same extrapolation could + * be applied to the end of a lookahead buffer of any size. However, it's most needed when + * lookahead=0, so that's what's currently implemented. */ + if( !h->param.rc.i_lookahead ) + { + if( b_intra ) + { + memset( frames[0]->i_propagate_cost, 0, h->mb.i_mb_count * sizeof(uint16_t) ); + memcpy( frames[0]->f_qp_offset, frames[0]->f_qp_offset_aq, h->mb.i_mb_count * sizeof(float) ); + return; + } + XCHG( uint16_t*, frames[last_nonb]->i_propagate_cost, frames[0]->i_propagate_cost ); + memset( frames[0]->i_propagate_cost, 0, h->mb.i_mb_count * sizeof(uint16_t) ); + } + else + { + if( last_nonb < idx ) + return; + memset( frames[last_nonb]->i_propagate_cost, 0, h->mb.i_mb_count * sizeof(uint16_t) ); + } - memset( frames[last_nonb]->i_propagate_cost, 0, h->mb.i_mb_count * sizeof(uint16_t) ); while( i-- > idx ) { cur_nonb = i; @@ -796,6 +814,12 @@ static void x264_macroblock_tree( x264_t *h, x264_mb_analysis_t *a, x264_frame_t last_nonb = cur_nonb; } + if( !h->param.rc.i_lookahead ) + { + x264_macroblock_tree_propagate( h, frames, 0, last_nonb, last_nonb, 1 ); + XCHG( uint16_t*, frames[last_nonb]->i_propagate_cost, frames[0]->i_propagate_cost ); + } + x264_macroblock_tree_finish( h, frames[last_nonb], last_nonb ); if( h->param.i_bframe_pyramid && bframes > 1 && !h->param.rc.i_vbv_buffer_size ) x264_macroblock_tree_finish( h, frames[last_nonb+(bframes+1)/2], 0 ); @@ -1058,10 +1082,11 @@ void x264_slicetype_analyse( x264_t *h, int keyframe ) { x264_mb_analysis_t a; x264_frame_t *frames[X264_LOOKAHEAD_MAX+3] = { NULL, }; - int num_frames, orig_num_frames, keyint_limit, idr_frame_type, framecnt; + int num_frames, orig_num_frames, keyint_limit, framecnt; int i_mb_count = NUM_MBS; 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; if( h->param.b_deterministic ) i_max_search = X264_MIN( i_max_search, h->lookahead->i_slicetype_length + !keyframe ); @@ -1074,30 +1099,26 @@ void x264_slicetype_analyse( x264_t *h, int keyframe ) frames[framecnt+1] = h->lookahead->next.list[framecnt]; if( !framecnt ) + { + if( h->param.rc.b_mb_tree ) + x264_macroblock_tree( h, &a, frames, 0, keyframe ); return; + } keyint_limit = h->param.i_keyint_max - frames[0]->i_frame + h->lookahead->i_last_keyframe - 1; orig_num_frames = num_frames = h->param.b_intra_refresh ? framecnt : X264_MIN( framecnt, keyint_limit ); x264_lowres_context_init( h, &a ); - idr_frame_type = frames[1]->i_frame - h->lookahead->i_last_keyframe >= h->param.i_keyint_min ? X264_TYPE_IDR : X264_TYPE_I; /* This is important psy-wise: if we have a non-scenecut keyframe, * there will be significant visual artifacts if the frames just before * go down in quality due to being referenced less, despite it being * more RD-optimal. */ - if( (h->param.analyse.b_psy && h->param.rc.b_mb_tree) || h->param.rc.i_vbv_buffer_size ) + if( (h->param.analyse.b_psy && h->param.rc.b_mb_tree) || vbv_lookahead ) num_frames = framecnt; - else if( num_frames == 1 ) - { - frames[1]->i_type = X264_TYPE_P; - if( h->param.i_scenecut_threshold && scenecut( h, &a, frames, 0, 1, 1, orig_num_frames ) ) - frames[1]->i_type = idr_frame_type; - return; - } else if( num_frames == 0 ) { - frames[1]->i_type = idr_frame_type; + frames[1]->i_type = X264_TYPE_I; return; } @@ -1106,7 +1127,7 @@ void x264_slicetype_analyse( x264_t *h, int keyframe ) int reset_start; if( h->param.i_scenecut_threshold && scenecut( h, &a, frames, 0, 1, 1, orig_num_frames ) ) { - frames[1]->i_type = idr_frame_type; + frames[1]->i_type = X264_TYPE_I; return; } @@ -1210,18 +1231,22 @@ void x264_slicetype_analyse( x264_t *h, int keyframe ) /* Enforce keyframe limit. */ if( !h->param.b_intra_refresh ) - for( int j = 0; j < num_frames; j++ ) + for( int i = keyint_limit+1; i <= num_frames; i += h->param.i_keyint_max ) { - if( ((j-keyint_limit) % h->param.i_keyint_max) == 0 ) + int j = i; + if( h->param.i_open_gop == X264_OPEN_GOP_CODED_ORDER ) { - if( j && h->param.i_keyint_max > 1 ) - frames[j]->i_type = X264_TYPE_P; - frames[j+1]->i_type = X264_TYPE_IDR; - reset_start = X264_MIN( reset_start, j+2 ); + while( IS_X264_TYPE_B( frames[i]->i_type ) ) + i++; + while( IS_X264_TYPE_B( frames[j-1]->i_type ) ) + j--; } + frames[i]->i_type = X264_TYPE_I; + reset_start = X264_MIN( reset_start, i+1 ); + i = j; } - if( h->param.rc.i_vbv_buffer_size ) + if( vbv_lookahead ) x264_vbv_lookahead( h, &a, frames, num_frames, keyframe ); /* Restore frametypes for all frames that haven't actually been decided yet. */ @@ -1303,13 +1328,39 @@ void x264_slicetype_decide( x264_t *h ) 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.i_open_gop ? X264_TYPE_I : X264_TYPE_IDR; + /* Limit GOP size */ if( (!h->param.b_intra_refresh || frm->i_frame == 0) && frm->i_frame - h->lookahead->i_last_keyframe >= h->param.i_keyint_max ) { - if( frm->i_type == X264_TYPE_AUTO ) + if( frm->i_type == X264_TYPE_AUTO || frm->i_type == X264_TYPE_I ) + frm->i_type = h->param.i_open_gop && h->lookahead->i_last_keyframe >= 0 ? X264_TYPE_I : X264_TYPE_IDR; + int warn = frm->i_type != X264_TYPE_IDR; + if( warn && h->param.i_open_gop == X264_OPEN_GOP_DISPLAY_ORDER ) + warn &= frm->i_type != X264_TYPE_I && frm->i_type != X264_TYPE_KEYFRAME; + if( warn && h->param.i_open_gop == X264_OPEN_GOP_CODED_ORDER ) + { + /* if this minigop ends with i, it's not a violation */ + int j = bframes; + while( IS_X264_TYPE_B( h->lookahead->next.list[j]->i_type ) ) + j++; + warn = h->lookahead->next.list[j]->i_type != X264_TYPE_I && h->lookahead->next.list[j]->i_type != X264_TYPE_KEYFRAME; + } + 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.i_open_gop ) + { + h->lookahead->i_last_keyframe = frm->i_frame; // Use display order + if( h->param.i_open_gop == X264_OPEN_GOP_CODED_ORDER ) + h->lookahead->i_last_keyframe -= bframes; // Use coded order + frm->b_keyframe = 1; + } + else frm->i_type = X264_TYPE_IDR; - if( frm->i_type != X264_TYPE_IDR ) - x264_log( h, X264_LOG_WARNING, "specified frame type (%d) is not compatible with keyframe interval\n", frm->i_type ); } if( frm->i_type == X264_TYPE_IDR ) { @@ -1405,10 +1456,10 @@ void x264_slicetype_decide( x264_t *h ) int i_coded = h->lookahead->next.list[0]->i_frame; if( bframes ) { - int index[] = { brefs+1, 1 }; + int idx_list[] = { brefs+1, 1 }; for( int i = 0; i < bframes; i++ ) { - int idx = index[h->lookahead->next.list[i]->i_type == X264_TYPE_BREF]++; + int idx = idx_list[h->lookahead->next.list[i]->i_type == X264_TYPE_BREF]++; frames[idx] = h->lookahead->next.list[i]; frames[idx]->i_reordered_pts = h->lookahead->next.list[idx]->i_pts; }