Commit fdfffa30 authored by Fiona Glaser's avatar Fiona Glaser

Add slice-min-mbs feature

Works in conjunction with slice-max-mbs and/or slice-max-size to avoid overly
small slices.
Useful with certain decoders that barf on extremely small slices.

If slice-min-mbs would be violated as a result of slice-max-size, x264 will
exceed slice-max-size and print a warning.
parent 8a3a41de
......@@ -778,6 +778,8 @@ int x264_param_parse( x264_param_t *p, const char *name, const char *value )
p->i_slice_max_size = atoi(value);
OPT("slice-max-mbs")
p->i_slice_max_mbs = atoi(value);
OPT("slice-min-mbs")
p->i_slice_min_mbs = atoi(value);
OPT("slices")
p->i_slice_count = atoi(value);
OPT("cabac")
......@@ -1309,6 +1311,8 @@ char *x264_param2string( x264_param_t *p, int b_res )
s += sprintf( s, " slice_max_size=%d", p->i_slice_max_size );
if( p->i_slice_max_mbs )
s += sprintf( s, " slice_max_mbs=%d", p->i_slice_max_mbs );
if( p->i_slice_min_mbs )
s += sprintf( s, " slice_min_mbs=%d", p->i_slice_min_mbs );
s += sprintf( s, " nr=%d", p->analyse.i_noise_reduction );
s += sprintf( s, " decimate=%d", p->analyse.b_dct_decimate );
s += sprintf( s, " interlaced=%s", p->b_interlaced ? p->b_tff ? "tff" : "bff" : p->b_fake_interlaced ? "fake" : "0" );
......
......@@ -670,6 +670,22 @@ static int x264_validate_parameters( x264_t *h, int b_open )
h->param.i_slice_max_size = X264_MAX( h->param.i_slice_max_size, 0 );
h->param.i_slice_max_mbs = X264_MAX( h->param.i_slice_max_mbs, 0 );
h->param.i_slice_min_mbs = X264_MAX( h->param.i_slice_min_mbs, 0 );
if( h->param.i_slice_max_mbs )
h->param.i_slice_min_mbs = X264_MIN( h->param.i_slice_min_mbs, h->param.i_slice_max_mbs/2 );
else if( !h->param.i_slice_max_size )
h->param.i_slice_min_mbs = 0;
if( PARAM_INTERLACED && h->param.i_slice_min_mbs )
{
x264_log( h, X264_LOG_WARNING, "interlace + slice-min-mbs is not implemented\n" );
h->param.i_slice_min_mbs = 0;
}
int mb_width = (h->param.i_width+15)/16;
if( h->param.i_slice_min_mbs > mb_width )
{
x264_log( h, X264_LOG_WARNING, "slice-min-mbs > row mb size (%d) not implemented\n", mb_width );
h->param.i_slice_min_mbs = mb_width;
}
int max_slices = (h->param.i_height+((16<<PARAM_INTERLACED)-1))/(16<<PARAM_INTERLACED);
if( h->param.b_sliced_threads )
......@@ -1497,6 +1513,7 @@ int x264_encoder_reconfig( x264_t *h, x264_param_t *param )
COPY( i_bframe_pyramid );
COPY( i_slice_max_size );
COPY( i_slice_max_mbs );
COPY( i_slice_min_mbs );
COPY( i_slice_count );
COPY( b_tff );
......@@ -2269,8 +2286,12 @@ static int x264_slice_write( x264_t *h )
int b_deblock = h->sh.i_disable_deblocking_filter_idc != 1;
int b_hpel = h->fdec->b_kept_as_ref;
int orig_last_mb = h->sh.i_last_mb;
int thread_last_mb = h->i_threadslice_end * h->mb.i_mb_width - 1;
uint8_t *last_emu_check;
x264_bs_bak_t bs_bak[2];
#define BS_BAK_SLICE_MAX_SIZE 0
#define BS_BAK_SLICE_MIN_MBS 1
#define BS_BAK_ROW_VBV 2
x264_bs_bak_t bs_bak[3];
b_deblock &= b_hpel || h->param.b_full_recon || h->param.psz_dump_yuv;
bs_realign( &h->out.bs );
......@@ -2318,13 +2339,17 @@ static int x264_slice_write( x264_t *h )
if( x264_bitstream_check_buffer( h ) )
return -1;
if( !(i_mb_y & SLICE_MBAFF) && h->param.rc.i_vbv_buffer_size )
x264_bitstream_backup( h, &bs_bak[1], i_skip, 1 );
x264_bitstream_backup( h, &bs_bak[BS_BAK_ROW_VBV], i_skip, 1 );
if( !h->mb.b_reencode_mb )
x264_fdec_filter_row( h, i_mb_y, 0 );
}
if( !(i_mb_y & SLICE_MBAFF) && back_up_bitstream )
x264_bitstream_backup( h, &bs_bak[0], i_skip, 0 );
{
x264_bitstream_backup( h, &bs_bak[BS_BAK_SLICE_MAX_SIZE], i_skip, 0 );
if( slice_max_size && (thread_last_mb+1-mb_xy) == h->param.i_slice_min_mbs )
x264_bitstream_backup( h, &bs_bak[BS_BAK_SLICE_MIN_MBS], i_skip, 0 );
}
if( PARAM_INTERLACED )
{
......@@ -2387,7 +2412,7 @@ reencode:
h->mb.i_skip_intra = 0;
h->mb.b_skip_mc = 0;
h->mb.b_overflow = 0;
x264_bitstream_restore( h, &bs_bak[0], &i_skip, 0 );
x264_bitstream_restore( h, &bs_bak[BS_BAK_SLICE_MAX_SIZE], &i_skip, 0 );
goto reencode;
}
}
......@@ -2412,9 +2437,27 @@ reencode:
/* We'll just re-encode this last macroblock if we go over the max slice size. */
if( total_bits - starting_bits > slice_max_size && !h->mb.b_reencode_mb )
{
/* Handle the most obnoxious slice-min-mbs edge case: we need to end the slice
* because it's gone over the maximum size, but doing so would violate slice-min-mbs.
* If possible, roll back to the last checkpoint and try again.
* We could try raising QP, but that would break in the case where a slice spans multiple
* rows, which the re-encoding infrastructure can't currently handle. */
if( mb_xy < thread_last_mb && (thread_last_mb+1-mb_xy) < h->param.i_slice_min_mbs )
{
if( thread_last_mb-h->param.i_slice_min_mbs < h->sh.i_first_mb+h->param.i_slice_min_mbs )
{
x264_log( h, X264_LOG_WARNING, "slice-max-size violated (frame %d, cause: slice-min-mbs)\n", h->i_frame );
slice_max_size = 0;
goto cont;
}
x264_bitstream_restore( h, &bs_bak[BS_BAK_SLICE_MIN_MBS], &i_skip, 0 );
h->mb.b_reencode_mb = 1;
h->sh.i_last_mb = thread_last_mb-h->param.i_slice_min_mbs;
break;
}
if( mb_xy-SLICE_MBAFF*h->mb.i_mb_stride != h->sh.i_first_mb )
{
x264_bitstream_restore( h, &bs_bak[0], &i_skip, 0 );
x264_bitstream_restore( h, &bs_bak[BS_BAK_SLICE_MAX_SIZE], &i_skip, 0 );
h->mb.b_reencode_mb = 1;
if( SLICE_MBAFF )
{
......@@ -2432,6 +2475,7 @@ reencode:
h->sh.i_last_mb = mb_xy;
}
}
cont:
h->mb.b_reencode_mb = 0;
#if HAVE_VISUALIZE
......@@ -2444,7 +2488,7 @@ reencode:
if( x264_ratecontrol_mb( h, mb_size ) < 0 )
{
x264_bitstream_restore( h, &bs_bak[1], &i_skip, 1 );
x264_bitstream_restore( h, &bs_bak[BS_BAK_ROW_VBV], &i_skip, 1 );
h->mb.b_reencode_mb = 1;
i_mb_x = 0;
i_mb_y = i_mb_y - SLICE_MBAFF;
......@@ -2543,6 +2587,9 @@ reencode:
i_mb_x = 0;
}
}
if( h->sh.i_last_mb < h->sh.i_first_mb )
return 0;
h->out.nal[h->out.i_nal].i_last_mb = h->sh.i_last_mb;
if( h->param.b_cabac )
......@@ -2654,7 +2701,11 @@ static void *x264_slices_write( x264_t *h )
h->sh.i_last_mb = last_x + h->mb.i_mb_stride*last_y;
}
else
{
h->sh.i_last_mb = h->sh.i_first_mb + h->param.i_slice_max_mbs - 1;
if( h->sh.i_last_mb < last_thread_mb && last_thread_mb - h->sh.i_last_mb < h->param.i_slice_min_mbs )
h->sh.i_last_mb = last_thread_mb - h->param.i_slice_min_mbs;
}
}
else if( h->param.i_slice_count && !h->param.b_sliced_threads )
{
......
......@@ -597,7 +597,8 @@ static void help( x264_param_t *defaults, int longhelp )
" slices and is overridden by other slicing options\n" );
else H1( " --slices <integer> Number of slices per frame\n" );
H2( " --slice-max-size <integer> Limit the size of each slice in bytes\n");
H2( " --slice-max-mbs <integer> Limit the size of each slice in macroblocks\n");
H2( " --slice-max-mbs <integer> Limit the size of each slice in macroblocks (max)\n");
H2( " --slice-min-mbs <integer> Limit the size of each slice in macroblocks (min)\n");
H0( " --tff Enable interlaced mode (top field first)\n" );
H0( " --bff Enable interlaced mode (bottom field first)\n" );
H2( " --constrained-intra Enable constrained intra prediction.\n" );
......@@ -971,6 +972,7 @@ static struct option long_options[] =
{ "no-sliced-threads", no_argument, NULL, 0 },
{ "slice-max-size", required_argument, NULL, 0 },
{ "slice-max-mbs", required_argument, NULL, 0 },
{ "slice-min-mbs", required_argument, NULL, 0 },
{ "slices", required_argument, NULL, 0 },
{ "thread-input", no_argument, NULL, OPT_THREAD_INPUT },
{ "sync-lookahead", required_argument, NULL, 0 },
......
......@@ -41,7 +41,7 @@
#include "x264_config.h"
#define X264_BUILD 130
#define X264_BUILD 131
/* Application developers planning to link against a shared library version of
* libx264 from a Microsoft Visual Studio or similar development environment
......@@ -477,6 +477,7 @@ typedef struct x264_param_t
/* Slicing parameters */
int i_slice_max_size; /* Max size per slice in bytes; includes estimated NAL overhead. */
int i_slice_max_mbs; /* Max number of MBs per slice; overrides i_slice_count. */
int i_slice_min_mbs; /* Min number of MBs per slice */
int i_slice_count; /* Number of slices per frame: forces rectangular slices. */
/* Optional callback for freeing this x264_param_t when it is done being used.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment