]> granicus.if.org Git - libx264/commitdiff
Add support for frame-accurate parameter changes
authorFiona Glaser <fiona@x264.com>
Wed, 19 Aug 2009 01:37:26 +0000 (18:37 -0700)
committerFiona Glaser <fiona@x264.com>
Wed, 19 Aug 2009 02:39:11 +0000 (19:39 -0700)
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.

common/common.c
common/frame.c
common/frame.h
encoder/encoder.c
encoder/ratecontrol.c
x264.h

index 84bf49f79fd83d18344a870d0713f98679d30795..1f0103066bc148ddf66708fab426516910dcec95 100644 (file)
@@ -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;
 }
 
index 0d37c7e53b2cfb088371897870296fcba6060173..d13cc7429ea9df5438c3e969f90c91b9ede8a004 100644 (file)
@@ -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++ )
     {
index 5fd49d5479ddc472a6bfd8545bb396bbbc8fdff0..3459117f28130b7f54180154664f5a288fc5623a 100644 (file)
@@ -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;
index 3ce8d80c993ee3e016dd1292cd743b742cc66eeb..03faab47b525151f0d3e30d522b1e3eb7dda4abe 100644 (file)
@@ -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;
index 65314655844ee9065b61f213f3407b681644447e..f37747becf3a55bac91a2ec4ef04357115b1c2e8 100644 (file)
@@ -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 964e093092259842dae2cb581019479e9dd26866..37a643cb9ddfebbb9f650b09c0c9d3f04ebcca10 100644 (file)
--- 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 */