[x264-devel] commit: Add support for frame-accurate parameter changes ( Jason Garrett-Glaser )
git version control
git at videolan.org
Wed Aug 19 04:53:59 CEST 2009
x264 | branch: master | Jason Garrett-Glaser <darkshikari at gmail.com> | Tue Aug 18 18:37:26 2009 -0700| [d6846d3d17ac7289eb3d82f54d19459d3a1a5b21] | committer: Jason Garrett-Glaser
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.
> http://git.videolan.org/gitweb.cgi/x264.git/?a=commit;h=d6846d3d17ac7289eb3d82f54d19459d3a1a5b21
---
common/common.c | 1 +
common/frame.c | 1 +
common/frame.h | 2 +
encoder/encoder.c | 73 +++++++++++++++++++++++++++++++------------------
encoder/ratecontrol.c | 8 +++---
x264.h | 21 ++++++++++++--
6 files changed, 72 insertions(+), 34 deletions(-)
diff --git a/common/common.c b/common/common.c
index 84bf49f..1f01030 100644
--- a/common/common.c
+++ b/common/common.c
@@ -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;
}
diff --git a/common/frame.c b/common/frame.c
index 3c34c17..d3094ab 100644
--- a/common/frame.c
+++ b/common/frame.c
@@ -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++ )
{
diff --git a/common/frame.h b/common/frame.h
index 5fd49d5..3459117 100644
--- a/common/frame.h
+++ b/common/frame.h
@@ -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;
diff --git a/encoder/encoder.c b/encoder/encoder.c
index 02399fe..66d7dda 100644
--- a/encoder/encoder.c
+++ b/encoder/encoder.c
@@ -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;
diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c
index 47491d9..96ad190 100644
--- a/encoder/ratecontrol.c
+++ b/encoder/ratecontrol.c
@@ -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 );
diff --git a/x264.h b/x264.h
index 964e093..37a643c 100644
--- a/x264.h
+++ b/x264.h
@@ -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 */
More information about the x264-devel
mailing list