]> granicus.if.org Git - libx264/commitdiff
Changes the mechanics of max keyframe interval:
authorLoren Merritt <pengvado@videolan.org>
Wed, 12 Jan 2005 09:50:38 +0000 (09:50 +0000)
committerLoren Merritt <pengvado@videolan.org>
Wed, 12 Jan 2005 09:50:38 +0000 (09:50 +0000)
Now enforces min and max GOP sizes, and allows variable numbers of
non-IDR I-frames within a GOP.

git-svn-id: svn://svn.videolan.org/x264/trunk@93 df754926-b1dd-0310-bc7b-ec298dee348c

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

index a50ce975e825ab7bd7be070e0a6df41a4d59fd53..4148b8af2b434d0217648d0ba03571ad7ec02dc5 100644 (file)
@@ -58,8 +58,8 @@ void    x264_param_default( x264_param_t *param )
 
     /* Encoder parameters */
     param->i_frame_reference = 1;
-    param->i_idrframe = 2;
-    param->i_iframe = 250;
+    param->i_keyint_max = 250;
+    param->i_keyint_min = 100;
     param->i_bframe = 0;
     param->i_scenecut_threshold = 40;
 
index dfbfc8be21c7340f78de4dee5c102c02d6d31348..c7e21cdd28b5a8c00442cba999f4b34785ae12f3 100644 (file)
@@ -215,8 +215,7 @@ struct x264_t
         /* frames used for reference +1 for decoding */
         x264_frame_t *reference[16+1];
 
-        int i_last_idr; /* How many I non IDR frames from last IDR */
-        int i_last_i;   /* How many P/B frames from last I */
+        int i_last_idr; /* How many frames since last IDR */
 
         int i_input;    /* Number of input frames already accepted */
     } frames;
index 76dd6f160ea9b49acf1211498f19f3e58145f249..9a0f53bbb8639804f106a118008ff0809bc18158 100644 (file)
@@ -332,10 +332,9 @@ x264_t *x264_encoder_open   ( x264_param_t *param )
 
     /* Fix parameters values */
     h->param.i_frame_reference = x264_clip3( h->param.i_frame_reference, 1, 15 );
-    if( h->param.i_idrframe <= 0 )
-        h->param.i_idrframe = 1;
-    if( h->param.i_iframe <= 0 )
-        h->param.i_iframe = 1;
+    if( h->param.i_keyint_max <= 0 )
+        h->param.i_keyint_max = 1;
+    h->param.i_keyint_min = x264_clip3( h->param.i_keyint_min, 1, h->param.i_keyint_max/2+1 );
     h->param.i_bframe = x264_clip3( h->param.i_bframe, 0, X264_BFRAME_MAX );
 
     h->param.i_deblocking_filter_alphac0 = x264_clip3( h->param.i_deblocking_filter_alphac0, -6, 6 );
@@ -343,9 +342,9 @@ x264_t *x264_encoder_open   ( x264_param_t *param )
 
     h->param.i_cabac_init_idc = x264_clip3( h->param.i_cabac_init_idc, -1, 2 );
 
-    param->analyse.i_subpel_refine = x264_clip3( param->analyse.i_subpel_refine, 1, 5 );
-    if( param->analyse.inter & X264_ANALYSE_PSUB8x8 )
-        param->analyse.inter &= X264_ANALYSE_PSUB16x16;
+    h->param.analyse.i_subpel_refine = x264_clip3( h->param.analyse.i_subpel_refine, 1, 5 );
+    if( h->param.analyse.inter & X264_ANALYSE_PSUB8x8 )
+        h->param.analyse.inter &= X264_ANALYSE_PSUB16x16;
 
     if( h->param.rc.f_qblur < 0 )
         h->param.rc.f_qblur = 0;
@@ -428,8 +427,7 @@ x264_t *x264_encoder_open   ( x264_param_t *param )
         /* 2 = 1 backward ref  + 1 fdec */
         h->frames.reference[i] = x264_frame_new( h );
     }
-    h->frames.i_last_idr = h->param.i_idrframe;
-    h->frames.i_last_i   = h->param.i_iframe;
+    h->frames.i_last_idr = h->param.i_keyint_max;
     h->frames.i_input    = 0;
 
     h->i_ref0 = 0;
@@ -956,30 +954,25 @@ int     x264_encoder_encode( x264_t *h,
         {
             frm = h->frames.next[bframes];
 
-            if( h->frames.i_last_i + bframes + 1 >= h->param.i_iframe
-                && frm->i_type != X264_TYPE_IDR )
+            /* Limit GOP size */
+            if( ( h->frames.i_last_idr + bframes + 1 >= h->param.i_keyint_min
+                  && frm->i_type == X264_TYPE_I )
+               || h->frames.i_last_idr + bframes + 1 >= h->param.i_keyint_max )
             {
                 if(    frm->i_type == X264_TYPE_P
                     || frm->i_type == X264_TYPE_B )
                     x264_log( h, X264_LOG_ERROR, "specified frame type is not compatible with keyframe interval\n" );
 
-                frm->i_type = X264_TYPE_I;
-            }
-
-            if( frm->i_type == X264_TYPE_IDR
-                || ( frm->i_type == X264_TYPE_I &&
-                   ( h->frames.i_last_idr + 1 >= h->param.i_idrframe
-                     && (bframes == 0 || !h->param.rc.b_stat_read ))))
-            {
                 frm->i_type = X264_TYPE_IDR;
+                h->i_poc = 0;
+                h->i_frame_num = 0;
+
+                /* Close GOP */
                 if( bframes > 0 )
                 {
                     bframes--;
                     h->frames.next[bframes]->i_type = X264_TYPE_P;
                 }
-
-                h->i_poc = 0;
-                h->i_frame_num = 0;
             }
 
             if( bframes == h->param.i_bframe
@@ -1025,16 +1018,10 @@ do_encode:
     if( h->fenc->i_type == X264_TYPE_IDR )
     {
         h->frames.i_last_idr = 0;
-        h->frames.i_last_i = 0;
-    }
-    else if( h->fenc->i_type == X264_TYPE_I )
-    {
-        h->frames.i_last_idr++;
-        h->frames.i_last_i = 0;
     }
     else
     {
-        h->frames.i_last_i++;
+        h->frames.i_last_idr++;
     }
 
     /* ------------------- Setup frame context ----------------------------- */
@@ -1118,12 +1105,13 @@ do_encode:
     /* Write the slice */
     x264_slice_write( h, i_nal_type, i_nal_ref_idc );
 
+    /* restore CPU state (before using float again) */
+    x264_cpu_restore( h->param.cpu );
+
     /* XXX: this scene cut won't work with B frame (it may never create IDR -> bad) */
     if( i_slice_type == SLICE_TYPE_P && !h->param.rc.b_stat_read 
         && h->param.i_scenecut_threshold >= 0 )
     {
-        int i_bias;
-
         int i_mb_i = h->stat.frame.i_mb_count[I_4x4] + h->stat.frame.i_mb_count[I_16x16];
         int i_mb_p = h->stat.frame.i_mb_count[P_L0] + h->stat.frame.i_mb_count[P_8x8];
         int i_mb_s = h->stat.frame.i_mb_count[P_SKIP];
@@ -1131,21 +1119,36 @@ do_encode:
         int64_t i_inter_cost = h->stat.frame.i_inter_cost;
         int64_t i_intra_cost = h->stat.frame.i_intra_cost;
 
+        float f_thresh_max = h->param.i_scenecut_threshold / 100.0;
+        /* ratio of 10 pulled out of thin air */
+        float f_thresh_min = f_thresh_max * h->param.i_keyint_min
+                             / ( h->param.i_keyint_max * 4 );
+        if( h->param.i_keyint_min == h->param.i_keyint_max )
+             f_thresh_min= f_thresh_max;
+        float f_bias;
+
         /* macroblock_analyse() doesn't further analyse skipped mbs,
          * so we have to guess their cost */
         if( i_mb_s < i_mb )
             i_intra_cost = i_intra_cost * i_mb / (i_mb - i_mb_s);
 
-        if( h->param.i_iframe > 0 )
-            i_bias = h->param.i_scenecut_threshold * h->frames.i_last_i / h->param.i_iframe;
+        if( h->frames.i_last_idr < h->param.i_keyint_min / 4 )
+            f_bias = f_thresh_min / 4;
+        else if( h->frames.i_last_idr <= h->param.i_keyint_min )
+            f_bias = f_thresh_min * h->frames.i_last_idr / h->param.i_keyint_min;
         else
-            i_bias = 15;
-        i_bias = X264_MIN( i_bias, 100 );
+        {
+            f_bias = f_thresh_min
+                     + ( f_thresh_max - f_thresh_min )
+                       * ( h->frames.i_last_idr - h->param.i_keyint_min )
+                       / ( h->param.i_keyint_max - h->param.i_keyint_min );
+        }
+        f_bias = X264_MIN( f_bias, 1.0 );
 
         /* Bad P will be reencoded as I */
         if( i_mb_s < i_mb &&
-            100 * i_inter_cost >= (100 - i_bias) * i_intra_cost )
-            /* 100 * i_mb_i >= (100 - i_bias) * i_mb ) */
+            i_inter_cost >= (1.0 - f_bias) * i_intra_cost )
+            /* i_mb_i >= (1.0 - f_bias) * i_mb ) */
             /*
             h->out.nal[h->out.i_nal-1].i_payload > h->i_last_intra_size +
             h->i_last_intra_size * (3+h->i_last_intra_qp - i_global_qp) / 16 &&
@@ -1154,52 +1157,53 @@ do_encode:
             h->frames.i_last_i > 4)*/
         {
 
-            x264_log( h, X264_LOG_DEBUG, "scene cut at %d size=%d last I:%d last P:%d Intra:%lld Inter:%lld Ratio:%lld Bias=%d (I:%d P:%d Skip:%d)\n",
+            x264_log( h, X264_LOG_DEBUG, "scene cut at %d size=%d I_cost:%lld P_cost:%lld ratio:%.3f bias=%.3f last_IDR:%d (I:%d P:%d Skip:%d)\n",
                       h->fenc->i_frame,
                       h->out.nal[h->out.i_nal-1].i_payload,
-                      h->i_last_intra_size, h->i_last_inter_size,
                       i_intra_cost, i_inter_cost,
-                      100 * i_inter_cost / i_intra_cost,
-                      i_bias, i_mb_i, i_mb_p, i_mb_s );
+                      (float)i_inter_cost / i_intra_cost,
+                      f_bias, h->frames.i_last_idr,
+                      i_mb_i, i_mb_p, i_mb_s );
 
             /* Restore frame num */
             h->i_frame_num--;
 
+            for( i = 0; h->frames.current[i] && h->frames.current[i]->i_type == X264_TYPE_B; i++ );
+            if( i > 0 )
+            {
+                /* If using B-frames, force GOP to be closed.
+                 * Even if this frame is going to be I and not IDR, forcing a
+                 * P-frame before the scenecut will probably help compression.
+                 * 
+                 * We don't yet know exactly which frame is the scene cut, so
+                 * we can't assign an I-frame. Instead, change the previous
+                 * B-frame to P, and rearrange coding order. */
+
+                x264_frame_t *tmp = h->frames.current[i-1];
+                h->frames.current[i-1] = h->fenc;
+                h->fenc = tmp;
+                h->fenc->i_type = X264_TYPE_P;
+            }
             /* Do IDR if needed */
-            if( h->frames.i_last_idr + 1 >= h->param.i_idrframe )
+            else if( h->frames.i_last_idr + 1 >= h->param.i_keyint_min )
             {
-                /* If using B-frames, make sure GOP is closed */
-                for( i = 0; h->frames.current[i] && h->frames.current[i]->i_type == X264_TYPE_B; i++ );
-                if( i > 0 )
-                {
-                    /* We don't know which frame is the scene cut, so we can't
-                     * assign an I-frame yet. Instead, change the previous
-                     * B-frame to P, and rearrange coding order. */
-                    x264_frame_t *tmp = h->frames.current[i-1];
-                    h->frames.current[i-1] = h->fenc;
-                    h->fenc = tmp;
-                    h->fenc->i_type = X264_TYPE_P;
-                }
-                else
-                {
-                    x264_frame_t *tmp;
+                x264_frame_t *tmp;
 
-                    /* Reset */
-                    h->i_poc       = 0;
-                    h->i_frame_num = 0;
+                /* Reset */
+                h->i_poc       = 0;
+                h->i_frame_num = 0;
 
-                    /* Reinit field of fenc */
-                    h->fenc->i_type = X264_TYPE_IDR;
-                    h->fenc->i_poc = h->i_poc;
+                /* Reinit field of fenc */
+                h->fenc->i_type = X264_TYPE_IDR;
+                h->fenc->i_poc = 0;
 
-                    /* Next Poc */
-                    h->i_poc += 2;
+                /* Next Poc */
+                h->i_poc += 2;
 
-                    /* Put enqueued frames back in the pool */
-                    while( (tmp = x264_frame_get( h->frames.current ) ) != NULL )
-                        x264_frame_put( h->frames.next, tmp );
-                    x264_frame_sort( h->frames.next );
-                }
+                /* Put enqueued frames back in the pool */
+                while( (tmp = x264_frame_get( h->frames.current ) ) != NULL )
+                    x264_frame_put( h->frames.next, tmp );
+                x264_frame_sort( h->frames.next );
             }
             else
             {
@@ -1245,6 +1249,7 @@ do_encode:
     h->i_frame++;
 
     /* restore CPU state (before using float again) */
+    /* XXX: not needed? (done above) */
     x264_cpu_restore( h->param.cpu );
 
     /* update rc */
index 21d423fb4206060b3e749ea6e1b42bb450cbb796..8f810f419ae3a9820c6f9bd968969d810b835284 100644 (file)
@@ -171,7 +171,7 @@ int x264_ratecontrol_new( x264_t *h )
     else
         rc->fps = 25.0;
 
-    rc->gop_size = h->param.i_iframe;
+    rc->gop_size = h->param.i_keyint_max;
     rc->bitrate = h->param.rc.i_bitrate * 1000;
     rc->nmb = h->mb.i_mb_count;
 
index 9b9278f7b31d78733c030d7d136a944ab48b4298..052e84834a094b6cce3d05921dc63e19dbe5d891 100644 (file)
@@ -50,7 +50,7 @@ void x264_sps_init( x264_sps_t *sps, int i_id, x264_param_t *param )
     sps->b_constraint_set2  = 0;
 
     sps->i_log2_max_frame_num = 4;  /* at least 4 */
-    while( (1 << sps->i_log2_max_frame_num) <= param->i_idrframe * param->i_iframe )
+    while( (1 << sps->i_log2_max_frame_num) <= param->i_keyint_max )
     {
         sps->i_log2_max_frame_num++;
     }
diff --git a/x264.c b/x264.c
index bd630e55618887347ee62348624ba58600bf11a0..52d40066c18e74b4502c0ad87c56826248a41a56 100644 (file)
--- a/x264.c
+++ b/x264.c
@@ -102,8 +102,8 @@ static void Help( x264_param_t *defaults )
              "\n"
              "  -h, --help                  Print this help\n"
              "\n"
-             "  -I, --idrframe <integer>    Each 'number' I frames are IDR frames [%d]\n"
-             "  -i, --iframe <integer>      Max interval between I frames [%d]\n"
+             "  -I, --keyint <integer  >    Maximum GOP size [%d]\n"
+             "  -i, --min-keyint <integer>  Minimum GOP size [%d]\n"
              "      --scenecut <integer>    How aggresively to insert extra I frames [%d]\n"
              "  -b, --bframe <integer>      Number of B-frames between I and P [%d]\n"
              "\n"
@@ -150,8 +150,8 @@ static void Help( x264_param_t *defaults )
              "  -v, --verbose               Print stats for each frame\n"
              "\n",
             X264_BUILD,
-            defaults->i_idrframe,
-            defaults->i_iframe,
+            defaults->i_keyint_max,
+            defaults->i_keyint_min,
             defaults->i_scenecut_threshold,
             defaults->i_bframe,
             defaults->i_frame_reference,
@@ -219,8 +219,8 @@ static int  Parse( int argc, char **argv,
             { "help",    no_argument,       NULL, 'h' },
             { "bitrate", required_argument, NULL, 'B' },
             { "bframe",  required_argument, NULL, 'b' },
-            { "iframe",  required_argument, NULL, 'i' },
-            { "idrframe",required_argument, NULL, 'I' },
+            { "min-keyint",required_argument,NULL,'i' },
+            { "keyint",  required_argument, NULL, 'I' },
             { "scenecut",required_argument, NULL, OPT_SCENECUT },
             { "nf",      no_argument,       NULL, 'n' },
             { "filter",  required_argument, NULL, 'f' },
@@ -281,10 +281,10 @@ static int  Parse( int argc, char **argv,
                 param->i_bframe = atol( optarg );
                 break;
             case 'i':
-                param->i_iframe = atol( optarg );
+                param->i_keyint_min = atol( optarg );
                 break;
             case 'I':
-                param->i_idrframe = atol( optarg );
+                param->i_keyint_max = atol( optarg );
                 break;
             case OPT_SCENECUT:
                 param->i_scenecut_threshold = atol( optarg );
diff --git a/x264.h b/x264.h
index ede99ba5861ee8859e9d4bf27e73d5d0ec633204..3cd571daf9731d8dea495270c748d72ce8ed1084 100644 (file)
--- a/x264.h
+++ b/x264.h
@@ -26,7 +26,7 @@
 
 #include <stdarg.h>
 
-#define X264_BUILD 0x000d
+#define X264_BUILD 0x000e
 
 /* x264_t:
  *      opaque handler for decoder and encoder */
@@ -108,8 +108,8 @@ typedef struct
 
     /* Bitstream parameters */
     int         i_frame_reference;  /* Maximum number of reference frames */
-    int         i_idrframe; /* every i_idrframe I frame are marked as IDR */
-    int         i_iframe;   /* every i_iframe are intra */
+    int         i_keyint_max;       /* Force an IDR keyframe at this interval */
+    int         i_keyint_min;       /* Scenecuts closer together than this are coded as I, not IDR. */
     int         i_scenecut_threshold; /* how aggressively to insert extra I frames */
     int         i_bframe;   /* how many b-frame between 2 references pictures */