Commit c83699f1 authored by Fiona Glaser's avatar Fiona Glaser
Browse files

Add support for frame-accurate parameter changes

Parameter structs can now be passed with individual frames.
The previous method would only change the parameter of what was currently being encoded, which due to delay might be very far from an intended exact frame.
Also add support for changing aspect ratio.  Only works in a stream with repeating headers and requires the caller to force an IDR to ensure instant effect.
parent 6a5a2043
......@@ -660,6 +660,7 @@ int x264_picture_alloc( x264_picture_t *pic, int i_csp, int i_width, int i_heigh
pic->img.i_stride[0] = i_width;
pic->img.i_stride[1] = i_width / 2;
pic->img.i_stride[2] = i_width / 2;
pic->param = NULL;
return 0;
}
......
......@@ -211,6 +211,7 @@ int x264_frame_copy_picture( x264_t *h, x264_frame_t *dst, x264_picture_t *src )
dst->i_type = src->i_type;
dst->i_qpplus1 = src->i_qpplus1;
dst->i_pts = src->i_pts;
dst->param = src->param;
for( i=0; i<3; i++ )
{
......
......@@ -35,6 +35,8 @@ typedef struct
int i_type;
int i_qpplus1;
int64_t i_pts;
x264_param_t *param;
int i_frame; /* Presentation frame number */
int i_frame_num; /* Coded frame number */
int b_kept_as_ref;
......
......@@ -680,6 +680,40 @@ static void mbcmp_init( x264_t *h )
memcpy( h->pixf.fpelcmp_x4, satd ? h->pixf.satd_x4 : h->pixf.sad_x4, sizeof(h->pixf.fpelcmp_x4) );
}
static void x264_set_aspect_ratio( x264_t *h, x264_param_t *param, int initial )
{
/* VUI */
if( param->vui.i_sar_width > 0 && param->vui.i_sar_height > 0 )
{
int i_w = param->vui.i_sar_width;
int i_h = param->vui.i_sar_height;
int old_w = h->param.vui.i_sar_width;
int old_h = h->param.vui.i_sar_height;
x264_reduce_fraction( &i_w, &i_h );
while( i_w > 65535 || i_h > 65535 )
{
i_w /= 2;
i_h /= 2;
}
if( i_w != old_w || i_h != old_h || initial )
{
h->param.vui.i_sar_width = 0;
h->param.vui.i_sar_height = 0;
if( i_w == 0 || i_h == 0 )
x264_log( h, X264_LOG_WARNING, "cannot create valid sample aspect ratio\n" );
else
{
x264_log( h, initial?X264_LOG_INFO:X264_LOG_DEBUG, "using SAR=%d/%d\n", i_w, i_h );
h->param.vui.i_sar_width = i_w;
h->param.vui.i_sar_height = i_h;
}
}
}
}
/****************************************************************************
* x264_encoder_open:
****************************************************************************/
......@@ -694,6 +728,9 @@ x264_t *x264_encoder_open ( x264_param_t *param )
/* Create a copy of param */
memcpy( &h->param, param, sizeof(x264_param_t) );
if( param->param_free )
param->param_free( param );
if( x264_validate_parameters( h ) < 0 )
goto fail;
......@@ -706,33 +743,7 @@ x264_t *x264_encoder_open ( x264_param_t *param )
if( h->param.rc.psz_stat_in )
h->param.rc.psz_stat_in = strdup( h->param.rc.psz_stat_in );
/* VUI */
if( h->param.vui.i_sar_width > 0 && h->param.vui.i_sar_height > 0 )
{
int i_w = param->vui.i_sar_width;
int i_h = param->vui.i_sar_height;
x264_reduce_fraction( &i_w, &i_h );
while( i_w > 65535 || i_h > 65535 )
{
i_w /= 2;
i_h /= 2;
}
h->param.vui.i_sar_width = 0;
h->param.vui.i_sar_height = 0;
if( i_w == 0 || i_h == 0 )
{
x264_log( h, X264_LOG_WARNING, "cannot create valid sample aspect ratio\n" );
}
else
{
x264_log( h, X264_LOG_INFO, "using SAR=%d/%d\n", i_w, i_h );
h->param.vui.i_sar_width = i_w;
h->param.vui.i_sar_height = i_h;
}
}
x264_set_aspect_ratio( h, param, 1 );
x264_reduce_fraction( &h->param.i_fps_num, &h->param.i_fps_den );
......@@ -883,6 +894,7 @@ fail:
int x264_encoder_reconfig( x264_t *h, x264_param_t *param )
{
h = h->thread[h->i_thread_phase%h->param.i_threads];
x264_set_aspect_ratio( h, param, 0 );
#define COPY(var) h->param.var = param->var
COPY( i_frame_reference ); // but never uses more refs than initially specified
COPY( i_bframe_bias );
......@@ -1565,6 +1577,13 @@ int x264_encoder_encode( x264_t *h,
return 0;
}
if( h->fenc->param )
{
x264_encoder_reconfig( h, h->fenc->param );
if( h->fenc->param->param_free )
h->fenc->param->param_free( h->fenc->param );
}
if( h->fenc->i_type == X264_TYPE_IDR )
{
h->frames.i_last_idr = h->fenc->i_frame;
......
......@@ -703,6 +703,7 @@ static int parse_zone( x264_t *h, x264_zone_t *z, char *p )
return 0;
CHECKED_MALLOC( z->param, sizeof(x264_param_t) );
memcpy( z->param, &h->param, sizeof(x264_param_t) );
z->param->param_free = x264_free;
while( (tok = strtok_r( p, ",", &saveptr )) )
{
char *val = strchr( tok, '=' );
......@@ -849,10 +850,9 @@ void x264_ratecontrol_delete( x264_t *h )
if( rc->zones )
{
x264_free( rc->zones[0].param );
if( h->param.rc.psz_zones )
for( i=1; i<rc->i_zones; i++ )
if( rc->zones[i].param != rc->zones[0].param )
x264_free( rc->zones[i].param );
for( i=1; i<rc->i_zones; i++ )
if( rc->zones[i].param != rc->zones[0].param && rc->zones[i].param->param_free )
rc->zones[i].param->param_free( rc->zones[i].param );
x264_free( rc->zones );
}
x264_free( rc );
......
......@@ -35,7 +35,7 @@
#include <stdarg.h>
#define X264_BUILD 71
#define X264_BUILD 72
/* x264_t:
* opaque handler for encoder */
......@@ -294,6 +294,12 @@ typedef struct x264_param_t
int b_aud; /* generate access unit delimiters */
int b_repeat_headers; /* put SPS/PPS before each keyframe */
int i_sps_id; /* SPS and PPS id number */
/* Optional callback for freeing this x264_param_t when it is done being used.
* Only used when the x264_param_t sits in memory for an indefinite period of time,
* i.e. when an x264_param_t is passed to x264_t in an x264_picture_t or in zones.
* Not used when x264_encoder_reconfig is called directly. */
void (*param_free)( void* );
} x264_param_t;
typedef struct {
......@@ -354,6 +360,13 @@ typedef struct
int i_qpplus1;
/* In: user pts, Out: pts of encoded picture (user)*/
int64_t i_pts;
/* In: custom encoding parameters to be set from this frame forwards
(in coded order, not display order). If NULL, continue using
parameters from the previous frame. Some parameters, such as
aspect ratio, can only be changed per-GOP due to the limitations
of H.264 itself; in this case, the caller must force an IDR frame
if it needs the changed parameter to apply immediately. */
x264_param_t *param;
/* In: raw data */
x264_image_t img;
......@@ -419,8 +432,10 @@ int x264_nal_encode( void *, int *, int b_annexeb, x264_nal_t *nal );
* create a new encoder handler, all parameters from x264_param_t are copied */
x264_t *x264_encoder_open ( x264_param_t * );
/* x264_encoder_reconfig:
* change encoder options while encoding,
* analysis-related parameters from x264_param_t are copied */
* analysis-related parameters from x264_param_t are copied.
* this takes effect immediately, on whichever frame is encoded next;
* due to delay, this may not be the next frame passed to encoder_encode.
* if the change should apply to some particular frame, use x264_picture_t->param instead. */
int x264_encoder_reconfig( x264_t *, x264_param_t * );
/* x264_encoder_headers:
* return the SPS and PPS that will be used for the whole stream */
......
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