]> git.sesse.net Git - x264/commitdiff
extend zones to support (some) encoding parameters in addition to ratecontrol.
authorLoren Merritt <pengvado@videolan.org>
Thu, 12 Jul 2007 23:48:23 +0000 (23:48 +0000)
committerLoren Merritt <pengvado@videolan.org>
Thu, 12 Jul 2007 23:48:23 +0000 (23:48 +0000)
git-svn-id: svn://svn.videolan.org/x264/trunk@665 df754926-b1dd-0310-bc7b-ec298dee348c

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

index 64ba37a1fc9dca4127bfe87a597d7930f5c1b6b4..e771dc07fcf7b8aebba5837bb022a16abbe14b94 100644 (file)
@@ -862,8 +862,11 @@ char *x264_slurp_file( const char *filename )
  ****************************************************************************/
 char *x264_param2string( x264_param_t *p, int b_res )
 {
-    char *buf = x264_malloc( 1000 );
-    char *s = buf;
+    int len = 1000;
+    char *buf, *s;
+    if( p->rc.psz_zones )
+        len += strlen(p->rc.psz_zones);
+    buf = s = x264_malloc( len );
 
     if( b_res )
     {
@@ -932,7 +935,9 @@ char *x264_param2string( x264_param_t *p, int b_res )
         s += sprintf( s, " ip_ratio=%.2f", p->rc.f_ip_factor );
         if( p->i_bframe )
             s += sprintf( s, " pb_ratio=%.2f", p->rc.f_pb_factor );
-        if( p->rc.i_zones )
+        if( p->rc.psz_zones )
+            s += sprintf( s, " zones=%s", p->rc.psz_zones );
+        else if( p->rc.i_zones )
             s += sprintf( s, " zones" );
     }
 
index 9723da63e57d44fe1a72d2c346374548f695e826..8917ae1ac6af79aae3696ccfaef718842b5e7dcb 100644 (file)
@@ -757,10 +757,12 @@ int x264_encoder_reconfig( x264_t *h, x264_param_t *param )
     COPY( analyse.b_dct_decimate );
     COPY( analyse.b_fast_pskip );
     COPY( analyse.b_mixed_references );
-#undef COPY
-
+    // can only twiddle these if they were enabled to begin with:
     if( h->pps->b_transform_8x8_mode )
-        h->param.analyse.b_transform_8x8 = param->analyse.b_transform_8x8;
+        COPY( analyse.b_transform_8x8 );
+    if( h->frames.i_max_ref1 > 1 )
+        COPY( b_bframe_pyramid );
+#undef COPY
 
     mbcmp_init( h );
 
index dce7d331badb07a7b7b6f023e469481182fa24c5..9b92dbeb55f41d5179254dd44126ded6025a8c90 100644 (file)
@@ -144,6 +144,7 @@ struct x264_ratecontrol_t
 
     int i_zones;
     x264_zone_t *zones;
+    x264_zone_t *prev_zone;
 };
 
 
@@ -302,7 +303,10 @@ int x264_ratecontrol_new( x264_t *h )
     *rc->pred_b_from_p = rc->pred[0];
 
     if( parse_zones( h ) < 0 )
+    {
+        x264_log( h, X264_LOG_ERROR, "failed to parse zones\n" );
         return -1;
+    }
 
     /* Load stat file and init 2pass algo */
     if( h->param.rc.b_stat_read )
@@ -475,34 +479,68 @@ int x264_ratecontrol_new( x264_t *h )
     return 0;
 }
 
+static int parse_zone( x264_t *h, x264_zone_t *z, char *p )
+{
+    int len = 0;
+    char *tok, *saveptr;
+    z->param = NULL;
+    z->f_bitrate_factor = 1;
+    if( 3 <= sscanf(p, "%u,%u,q=%u%n", &z->i_start, &z->i_end, &z->i_qp, &len) )
+        z->b_force_qp = 1;
+    else if( 3 <= sscanf(p, "%u,%u,b=%f%n", &z->i_start, &z->i_end, &z->f_bitrate_factor, &len) )
+        z->b_force_qp = 0;
+    else if( 2 <= sscanf(p, "%u,%u%n", &z->i_start, &z->i_end, &len) )
+        z->b_force_qp = 0;
+    else
+    {
+        x264_log( h, X264_LOG_ERROR, "invalid zone: \"%s\"\n", p );
+        return -1;
+    }
+    p += len;
+    if( !*p )
+        return 0;
+    z->param = malloc( sizeof(x264_param_t) );
+    memcpy( z->param, &h->param, sizeof(x264_param_t) );
+    while( (tok = strtok_r( p, ",", &saveptr )) )
+    {
+        char *val = strchr( tok, '=' );
+        if( val )
+        {
+            *val = '\0';
+            val++;
+        }
+        if( x264_param_parse( z->param, tok, val ) )
+        {
+            x264_log( h, X264_LOG_ERROR, "invalid zone param: %s = %s\n", tok, val );
+            return -1;
+        }
+        p = NULL;
+    }
+    return 0;
+}
+
 static int parse_zones( x264_t *h )
 {
     x264_ratecontrol_t *rc = h->rc;
     int i;
     if( h->param.rc.psz_zones && !h->param.rc.i_zones )
     {
-        char *p;
+        char *p, *tok, *saveptr;
+        char *psz_zones = x264_malloc( strlen(h->param.rc.psz_zones)+1 );
+        strcpy( psz_zones, h->param.rc.psz_zones );
         h->param.rc.i_zones = 1;
-        for( p = h->param.rc.psz_zones; *p; p++ )
+        for( p = psz_zones; *p; p++ )
             h->param.rc.i_zones += (*p == '/');
         h->param.rc.zones = x264_malloc( h->param.rc.i_zones * sizeof(x264_zone_t) );
-        p = h->param.rc.psz_zones;
-        for( i = 0; i < h->param.rc.i_zones; i++)
+        p = psz_zones;
+        for( i = 0; i < h->param.rc.i_zones; i++ )
         {
-            x264_zone_t *z = &h->param.rc.zones[i];
-            if( 3 == sscanf(p, "%u,%u,q=%u", &z->i_start, &z->i_end, &z->i_qp) )
-                z->b_force_qp = 1;
-            else if( 3 == sscanf(p, "%u,%u,b=%f", &z->i_start, &z->i_end, &z->f_bitrate_factor) )
-                z->b_force_qp = 0;
-            else
-            {
-                char *slash = strchr(p, '/');
-                if(slash) *slash = '\0';
-                x264_log( h, X264_LOG_ERROR, "invalid zone: \"%s\"\n", p );
+            tok = strtok_r( p, "/", &saveptr );
+            if( !tok || parse_zone( h, &h->param.rc.zones[i], tok ) )
                 return -1;
-            }
-            p = strchr(p, '/') + 1;
+            p = NULL;
         }
+        x264_free( psz_zones );
     }
 
     if( h->param.rc.i_zones > 0 )
@@ -524,9 +562,22 @@ static int parse_zones( x264_t *h )
             }
         }
 
-        rc->i_zones = h->param.rc.i_zones;
+        rc->i_zones = h->param.rc.i_zones + 1;
         rc->zones = x264_malloc( rc->i_zones * sizeof(x264_zone_t) );
-        memcpy( rc->zones, h->param.rc.zones, rc->i_zones * sizeof(x264_zone_t) );
+        memcpy( rc->zones+1, h->param.rc.zones, (rc->i_zones-1) * sizeof(x264_zone_t) );
+
+        // default zone to fall back to if none of the others match
+        rc->zones[0].i_start = 0;
+        rc->zones[0].i_end = INT_MAX;
+        rc->zones[0].b_force_qp = 0;
+        rc->zones[0].f_bitrate_factor = 1;
+        rc->zones[0].param = x264_malloc( sizeof(x264_param_t) );
+        memcpy( rc->zones[0].param, &h->param, sizeof(x264_param_t) );
+        for( i = 1; i < rc->i_zones; i++ )
+        {
+            if( !rc->zones[i].param )
+                rc->zones[i].param = rc->zones[0].param;
+        }
     }
 
     return 0;
@@ -559,6 +610,7 @@ void x264_ratecontrol_summary( x264_t *h )
 void x264_ratecontrol_delete( x264_t *h )
 {
     x264_ratecontrol_t *rc = h->rc;
+    int i;
 
     if( rc->p_stat_file_out )
     {
@@ -574,7 +626,15 @@ void x264_ratecontrol_delete( x264_t *h )
     x264_free( rc->pred );
     x264_free( rc->pred_b_from_p );
     x264_free( rc->entry );
-    x264_free( rc->zones );
+    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 );
+        x264_free( rc->zones );
+    }
     x264_free( rc );
 }
 
@@ -595,10 +655,15 @@ void x264_ratecontrol_start( x264_t *h, int i_force_qp )
 {
     x264_ratecontrol_t *rc = h->rc;
     ratecontrol_entry_t *rce = NULL;
+    x264_zone_t *zone = get_zone( h, h->fenc->i_frame );
     float q;
 
     x264_cpu_restore( h->param.cpu );
 
+    if( zone && (!rc->prev_zone || zone->param != rc->prev_zone->param) )
+        x264_encoder_reconfig( h, zone->param );
+    rc->prev_zone = zone;
+
     rc->qp_force = i_force_qp;
 
     if( h->param.rc.b_stat_read )
@@ -646,7 +711,6 @@ void x264_ratecontrol_start( x264_t *h, int i_force_qp )
     }
     else /* CQP */
     {
-        x264_zone_t *zone = get_zone( h, h->fenc->i_frame );
         if( h->sh.i_type == SLICE_TYPE_B && h->fdec->b_kept_as_ref )
             q = ( rc->qp_constant[ SLICE_TYPE_B ] + rc->qp_constant[ SLICE_TYPE_P ] ) / 2;
         else
@@ -1384,6 +1448,7 @@ void x264_thread_sync_ratecontrol( x264_t *cur, x264_t *prev, x264_t *next )
         COPY(short_term_cplxsum);
         COPY(short_term_cplxcount);
         COPY(bframes);
+        COPY(prev_zone);
 #undef COPY
     }
     if( cur != next )
index dba5571c1ade047098630d3fc59d55c6da23c4ee..200840b5cda5eb2eb12d967d2aefed0ae5b99bbc 100644 (file)
@@ -479,14 +479,13 @@ void x264_sei_version_write( x264_t *h, bs_t *s )
         0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7,
         0x96, 0x2c, 0xd8, 0x20, 0xd9, 0x23, 0xee, 0xef
     };
-    char version[1200];
-    int length;
     char *opts = x264_param2string( &h->param, 0 );
+    char *version = x264_malloc( 200 + strlen(opts) );
+    int length;
 
     sprintf( version, "x264 - core %d%s - H.264/MPEG-4 AVC codec - "
              "Copyleft 2005 - http://www.videolan.org/x264.html - options: %s",
              X264_BUILD, X264_VERSION, opts );
-    x264_free( opts );
     length = strlen(version)+1+16;
 
     bs_write( s, 8, 0x5 ); // payload_type = user_data_unregistered
@@ -501,6 +500,9 @@ void x264_sei_version_write( x264_t *h, bs_t *s )
         bs_write( s, 8, version[i] );
 
     bs_rbsp_trailing( s );
+
+    x264_free( opts );
+    x264_free( version );
 }
 
 const x264_level_t x264_levels[] =
diff --git a/x264.h b/x264.h
index ae0e87dcad3037fe8cade8c3ae903f05ddfbc611..c5b16984140a3d2ae0c89b72ede91911a0015c9c 100644 (file)
--- a/x264.h
+++ b/x264.h
@@ -35,7 +35,7 @@
 
 #include <stdarg.h>
 
-#define X264_BUILD 55
+#define X264_BUILD 56
 
 /* x264_t:
  *      opaque handler for encoder */
@@ -122,15 +122,19 @@ static const char * const x264_colmatrix_names[] = { "GBR", "bt709", "undef", ""
 #define X264_LOG_INFO           2
 #define X264_LOG_DEBUG          3
 
+/* Zones: override ratecontrol or other options for specific sections of the video.
+ * See x264_encoder_reconfig() for which options can be changed.
+ * If zones overlap, whichever comes later in the list takes precedence. */
 typedef struct
 {
-    int i_start, i_end;
-    int b_force_qp;
+    int i_start, i_end; /* range of frame numbers */
+    int b_force_qp; /* whether to use qp vs bitrate factor */
     int i_qp;
     float f_bitrate_factor;
+    struct x264_param_t *param;
 } x264_zone_t;
 
-typedef struct
+typedef struct x264_param_t
 {
     /* CPU flags */
     unsigned int cpu;