]> granicus.if.org Git - libx264/commitdiff
Zoned ratecontrol.
authorLoren Merritt <pengvado@videolan.org>
Tue, 24 May 2005 01:34:57 +0000 (01:34 +0000)
committerLoren Merritt <pengvado@videolan.org>
Tue, 24 May 2005 01:34:57 +0000 (01:34 +0000)
git-svn-id: svn://svn.videolan.org/x264/trunk@237 df754926-b1dd-0310-bc7b-ec298dee348c

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

index e5cd0702786f849bd1aa011b2feadc5dd5971b84..c9231f3a61db18436ef0a4255db67231369c207c 100644 (file)
@@ -95,6 +95,7 @@ void    x264_param_default( x264_param_t *param )
     param->rc.f_qcompress = 0.6;
     param->rc.f_qblur = 0.5;
     param->rc.f_complexity_blur = 20;
+    param->rc.i_zones = 0;
 
     /* Log */
     param->pf_log = x264_log_default;
index 6e44a95e2bf52754029e0eca492eb54b47e2a546..f79e925c4a69d6711a64426c5df53810b3444ac0 100644 (file)
@@ -126,6 +126,9 @@ struct x264_ratecontrol_t
     double p_cplx_sum[5];
     double mv_bits_sum[5];
     int frame_count[5];         /* number of frames of each type */
+
+    int i_zones;
+    x264_zone_t *zones;
 };
 
 
@@ -249,6 +252,30 @@ int x264_ratecontrol_new( x264_t *h )
     rc->lmax[SLICE_TYPE_B] *= fabs(h->param.f_pb_factor);
 #endif
 
+    if( h->param.rc.i_zones > 0 )
+    {
+        for( i = 0; i < h->param.rc.i_zones; i++ )
+        {
+            x264_zone_t z = h->param.rc.zones[i];
+            if( z.i_start < 0 || z.i_start > z.i_end )
+            {
+                x264_log( h, X264_LOG_ERROR, "invalid zone: start=%d end=%d\n",
+                          z.i_start, z.i_end );
+                return -1;
+            }
+            else if( !z.b_force_qp && z.f_bitrate_factor <= 0 )
+            {
+                x264_log( h, X264_LOG_ERROR, "invalid zone: bitrate_factor=%f\n",
+                          z.f_bitrate_factor );
+                return -1;
+            }
+        }
+
+        rc->i_zones = h->param.rc.i_zones;
+        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) );
+    }
+
     /* Load stat file and init 2pass algo */
     if( h->param.rc.b_stat_read )
     {
@@ -383,8 +410,8 @@ void x264_ratecontrol_delete( x264_t *h )
             }
         x264_free( rc->psz_stat_file_tmpname );
     }
-    if( rc->entry )
-        x264_free(rc->entry);
+    x264_free( rc->entry );
+    x264_free( rc->zones );
     x264_free( rc );
 }
 
@@ -543,11 +570,12 @@ double x264_eval( char *s, double *const_value, const char **const_name,
 /**
  * modify the bitrate curve from pass1 for one frame
  */
-static double get_qscale(x264_t *h, ratecontrol_entry_t *rce, double rate_factor)
+static double get_qscale(x264_t *h, ratecontrol_entry_t *rce, double rate_factor, int frame_num)
 {
     x264_ratecontrol_t *rcc= h->rc;
     const int pict_type = rce->pict_type;
     double q;
+    int i;
 
     double const_values[]={
         rce->i_tex_bits * rce->qscale,
@@ -601,13 +629,28 @@ static double get_qscale(x264_t *h, ratecontrol_entry_t *rce, double rate_factor
     };
 
     q = x264_eval((char*)h->param.rc.psz_rc_eq, const_values, const_names, func1, func1_names, NULL, NULL, rce);
-    q /= rate_factor;
 
     // avoid NaN's in the rc_eq
     if(q != q || rce->i_tex_bits + rce->p_tex_bits + rce->mv_bits == 0)
         q = rcc->last_qscale;
-    else
+    else {
+        rcc->last_rceq = q;
+        q /= rate_factor;
         rcc->last_qscale = q;
+    }
+
+    for( i = rcc->i_zones-1; i >= 0; i-- )
+    {
+        x264_zone_t *z = &rcc->zones[i];
+        if( frame_num >= z->i_start && frame_num <= z->i_end )
+        {
+            if( z->b_force_qp )
+                q = qp2qscale(z->i_qp);
+            else
+                q /= z->f_bitrate_factor;
+            break;
+        }
+    }
 
     return q;
 }
@@ -835,13 +878,12 @@ static float rate_estimate_qscale(x264_t *h, int pict_type)
             rce.s_count = 0;
             rce.qscale = 1;
             rce.pict_type = pict_type;
-            rcc->last_rceq = get_qscale(h, &rce, 1);
+            q = get_qscale(h, &rce, rcc->wanted_bits_window / rcc->cplxr_sum, h->fenc->i_frame);
 
             wanted_bits = h->fenc->i_frame * rcc->bitrate / rcc->fps;
             abr_buffer *= X264_MAX( 1, sqrt(h->fenc->i_frame/25) );
             overflow = x264_clip3f( 1.0 + (total_bits - wanted_bits) / abr_buffer, .5, 2 );
-
-            q = rcc->last_rceq * overflow * rcc->cplxr_sum / rcc->wanted_bits_window;
+            q *= overflow;
 
             if( pict_type == SLICE_TYPE_I
                 /* should test _next_ pict type, but that isn't decided yet */
@@ -959,7 +1001,7 @@ static int init_pass2( x264_t *h )
 
     expected_bits = 1;
     for(i=0; i<rcc->num_entries; i++)
-        expected_bits += qscale2bits(&rcc->entry[i], get_qscale(h, &rcc->entry[i], 1.0));
+        expected_bits += qscale2bits(&rcc->entry[i], get_qscale(h, &rcc->entry[i], 1.0, i));
     step_mult = all_available_bits / expected_bits;
 
     rate_factor = 0;
@@ -974,7 +1016,7 @@ static int init_pass2( x264_t *h )
 
         /* find qscale */
         for(i=0; i<rcc->num_entries; i++){
-            qscale[i] = get_qscale(h, &rcc->entry[i], rate_factor);
+            qscale[i] = get_qscale(h, &rcc->entry[i], rate_factor, i);
         }
 
         /* fixed I/B qscale relative to P */
diff --git a/x264.c b/x264.c
index 63a5707fe8fef01bd9ed1ac517869fde3b5a4555..702ee98dcde9cbeb66c329e69b06ff52fbba7500 100644 (file)
--- a/x264.c
+++ b/x264.c
@@ -163,6 +163,8 @@ static void Help( x264_param_t *defaults )
              "\n"
              "  -h, --help                  Print this help\n"
              "\n"
+             "Frame-type options:\n"
+             "\n"
              "  -I, --keyint <integer>      Maximum GOP size [%d]\n"
              "  -i, --min-keyint <integer>  Minimum GOP size [%d]\n"
              "      --scenecut <integer>    How aggressively to insert extra I-frames [%d]\n"
@@ -176,6 +178,8 @@ static void Help( x264_param_t *defaults )
              "      --nf                    Disable loop filter\n"
              "  -f, --filter <alpha:beta>   Loop filter AlphaC0 and Beta parameters [%d:%d]\n"
              "\n"
+             "Ratecontrol:\n"
+             "\n"
              "  -q, --qp <integer>          Set QP [%d]\n"
              "  -B, --bitrate <integer>     Set bitrate\n"
              "      --qpmin <integer>       Set min QP [%d]\n"
@@ -200,9 +204,18 @@ static void Help( x264_param_t *defaults )
              "      --cplxblur <float>      Reduce fluctuations in QP (before curve compression) [%.1f]\n"
              "      --qblur <float>         Reduce fluctuations in QP (after curve compression) [%.1f]\n"
              "\n"
+             "      --zones <zone0>/<zone1>/...\n"
+             "                              Tweak the bitrate of some regions of the video\n"
+             "                              Each zone is of the form\n"
+             "                                  <start frame>,<end frame>,<option>\n"
+             "                                  where <option> is either\n"
+             "                                      q=<integer> (force QP)\n"
+             "                                  or  b=<float> (bitrate multiplier)\n"
+             "\n"
+             "Analysis:\n"
+             "\n"
              "  -A, --analyse <string>      Analyse options: [\"i4x4,p8x8,b8x8\"]\n"
-             "                                  - i4x4\n"
-             "                                  - p8x8, p4x4, b8x8\n"
+             "                                  - i4x4, p8x8, p4x4, b8x8\n"
              "                                  - none, all\n"
              "      --direct <string>       Direct MV prediction mode [\"temporal\"]\n"
              "                                  - none, spatial, temporal\n"
@@ -215,6 +228,8 @@ static void Help( x264_param_t *defaults )
              "  -m, --subme <integer>       Subpixel motion estimation quality: 1=fast, 5=best. [%d]\n"
              "      --no-chroma-me          Ignore chroma in motion estimation\n"
              "\n"
+             "Input/Output:\n"
+             "\n"
              "      --level <integer>       Specify level (as defined by Annex A)\n"
              "      --sar width:height      Specify Sample Aspect Ratio\n"
              "      --fps <float|rational>  Specify framerate\n"
@@ -337,6 +352,7 @@ static int  Parse( int argc, char **argv,
 #define OPT_VBVINIT 289
 #define OPT_VISUALIZE 290
 #define OPT_SEEK 291
+#define OPT_ZONES 292
 
         static struct option long_options[] =
         {
@@ -384,6 +400,7 @@ static int  Parse( int argc, char **argv,
             { "qcomp",   required_argument, NULL, OPT_QCOMP },
             { "qblur",   required_argument, NULL, OPT_QBLUR },
             { "cplxblur",required_argument, NULL, OPT_CPLXBLUR },
+            { "zones",   required_argument, NULL, OPT_ZONES },
             { "no-psnr", no_argument,       NULL, OPT_NOPSNR },
             { "quiet",   no_argument,       NULL, OPT_QUIET },
             { "verbose", no_argument,       NULL, 'v' },
@@ -622,6 +639,33 @@ static int  Parse( int argc, char **argv,
             case OPT_CPLXBLUR:
                 param->rc.f_complexity_blur = atof(optarg);
                 break;
+            case OPT_ZONES:
+                {
+                    int i;
+                    char *p;
+                    param->rc.i_zones = 1;
+                    for( p = optarg; *p; p++ )
+                        param->rc.i_zones += (*p == '/');
+                    param->rc.zones = (x264_zone_t*)malloc( param->rc.i_zones * sizeof(x264_zone_t) );
+                    p = optarg;
+                    for( i = 0; i < param->rc.i_zones; i++)
+                    {
+                        x264_zone_t *z = &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';
+                            fprintf( stderr, "invalid zone: \"%s\"\n", p );
+                            return -1;
+                        }
+                        p = strchr(p, '/') + 1;
+                    }
+                }
+                break;
             case OPT_NOPSNR:
                 param->analyse.b_psnr = 0;
                 break;
diff --git a/x264.h b/x264.h
index 53a5871440c7ef8cf573908b2594fae282c12fe4..790e583e7911b8828769536d2e13e4d810537b11 100644 (file)
--- a/x264.h
+++ b/x264.h
@@ -26,7 +26,7 @@
 
 #include <stdarg.h>
 
-#define X264_BUILD 25
+#define X264_BUILD 26
 
 /* x264_t:
  *      opaque handler for decoder and encoder */
@@ -91,6 +91,14 @@ typedef struct x264_t x264_t;
 #define X264_LOG_INFO           2
 #define X264_LOG_DEBUG          3
 
+typedef struct
+{
+    int i_start, i_end;
+    int b_force_qp;
+    int i_qp;
+    float f_bitrate_factor;
+} x264_zone_t;
+
 typedef struct
 {
     /* CPU flags */
@@ -179,11 +187,13 @@ typedef struct
         int         b_stat_read;    /* Read stat from psz_stat_in and use it */
         char        *psz_stat_in;
 
-        /* 2pass params (same than ffmpeg ones) */
+        /* 2pass params (same as ffmpeg ones) */
         char        *psz_rc_eq;     /* 2 pass rate control equation */
         float       f_qcompress;    /* 0.0 => cbr, 1.0 => constant qp */
         float       f_qblur;        /* temporally blur quants */
         float       f_complexity_blur; /* temporally blur complexity */
+        int         i_zones;
+        x264_zone_t *zones;         /* ratecontrol overrides */
     } rc;
 
     int b_aud;                  /* generate access unit delimiters */