New option: "B-frame pyramid" keeps the middle of 2+ consecutive B-frames as a refere...
authorLoren Merritt <pengvado@videolan.org>
Fri, 4 Mar 2005 12:52:35 +0000 (12:52 +0000)
committerLoren Merritt <pengvado@videolan.org>
Fri, 4 Mar 2005 12:52:35 +0000 (12:52 +0000)
git-svn-id: svn://svn.videolan.org/x264/trunk@150 df754926-b1dd-0310-bc7b-ec298dee348c

13 files changed:
common/common.c
common/common.h
common/frame.c
common/frame.h
common/macroblock.c
encoder/analyse.c
encoder/cabac.c
encoder/encoder.c
encoder/ratecontrol.c
encoder/set.c
encoder/slicetype_decision.c
x264.c
x264.h

index 9b87e5e..4d634be 100644 (file)
@@ -61,17 +61,18 @@ void    x264_param_default( x264_param_t *param )
     /* Encoder parameters */
     param->i_frame_reference = 1;
     param->i_keyint_max = 250;
-    param->i_keyint_min = 100;
+    param->i_keyint_min = 25;
     param->i_bframe = 0;
     param->i_scenecut_threshold = 40;
     param->b_bframe_adaptive = 1;
     param->i_bframe_bias = 0;
+    param->b_bframe_pyramid = 0;
 
     param->b_deblocking_filter = 1;
     param->i_deblocking_filter_alphac0 = 0;
     param->i_deblocking_filter_beta = 0;
 
-    param->b_cabac = 0;
+    param->b_cabac = 1;
     param->i_cabac_init_idc = -1;
 
     param->rc.b_cbr = 0;
index d76f054..80f41dc 100644 (file)
@@ -140,6 +140,13 @@ typedef struct
     int i_num_ref_idx_l0_active;
     int i_num_ref_idx_l1_active;
 
+    int b_ref_pic_list_reordering_l0;
+    int b_ref_pic_list_reordering_l1;
+    struct {
+        int idc;
+        int arg;
+    } ref_pic_list_order[2][16];
+
     int i_cabac_init_idc;
 
     int i_qp_delta;
@@ -237,13 +244,16 @@ struct x264_t
         /* For adaptive B decision */
         x264_frame_t *last_nonb;
 
-        /* frames used for reference +1 for decoding */
-        x264_frame_t *reference[16+1];
+        /* frames used for reference +1 for decoding +1 sentinel */
+        x264_frame_t *reference[16+2+1+1];
 
         int i_last_idr; /* Frame number of the last IDR */
 
         int i_input;    /* Number of input frames already accepted */
-        
+
+        int i_max_dpb;  /* Number of frames allocated in the decoded picture buffer */
+        int i_max_ref0;
+        int i_max_ref1;
         int i_delay;    /* Number of frames buffered for B reordering */
     } frames;
 
@@ -258,6 +268,7 @@ struct x264_t
     x264_frame_t    *fref0[16];       /* ref list 0 */
     int             i_ref1;
     x264_frame_t    *fref1[16];       /* ref list 1 */
+    int             b_ref_reorder[2];
 
 
 
@@ -371,6 +382,9 @@ struct x264_t
         /* B_direct and weighted prediction */
         int     dist_scale_factor[16][16];
         int     bipred_weight[16][16];
+        /* maps fref1[0]'s ref indices into the current list0 */
+        int     map_col_to_list0_buf[2]; // for negative indices
+        int     map_col_to_list0[16];
     } mb;
 
     /* rate control encoding only */
index a36b390..1eaeaba 100644 (file)
@@ -91,7 +91,9 @@ x264_frame_t *x264_frame_new( x264_t *h )
     frame->i_qpplus1 = 0;
     frame->i_pts = -1;
     frame->i_frame = -1;
+    frame->i_frame_num = -1;
 
+    frame->mb_type= x264_malloc( i_mb_count * sizeof( int8_t) );
     frame->mv[0]  = x264_malloc( 2*16 * i_mb_count * sizeof( int16_t ) );
     frame->ref[0] = x264_malloc( 4 * i_mb_count * sizeof( int8_t ) );
     if( h->param.i_bframe )
@@ -119,6 +121,7 @@ void x264_frame_delete( x264_frame_t *frame )
     {
         x264_free( frame->buffer[i] );
     }
+    x264_free( frame->mb_type );
     x264_free( frame->mv[0] );
     x264_free( frame->mv[1] );
     x264_free( frame->ref[0] );
index 9c638a3..a29d723 100644 (file)
@@ -32,6 +32,8 @@ typedef struct
     int     i_qpplus1;
     int64_t i_pts;
     int     i_frame;    /* Presentation frame number */
+    int     i_frame_num; /* Coded frame number */
+    int     b_kept_as_ref;
 
     /* YUV buffer */
     int     i_plane;
@@ -48,6 +50,7 @@ typedef struct
     void    *buffer[11];
 
     /* motion data */
+    int8_t  *mb_type;
     int16_t (*mv[2])[2];
     int8_t  *ref[2];
     int     i_ref[2];
index b548153..a28d552 100644 (file)
@@ -341,21 +341,23 @@ static int x264_mb_predict_mv_direct16x16_temporal( x264_t *h )
     
     x264_macroblock_cache_ref( h, 0, 0, 4, 4, 1, 0 );
     
+    if( IS_INTRA( h->fref1[0]->mb_type[ h->mb.i_mb_xy ] ) )
+    {
+        x264_macroblock_cache_ref( h, 0, 0, 4, 4, 0, 0 );
+        x264_macroblock_cache_mv(  h, 0, 0, 4, 4, 0, 0, 0 );
+        x264_macroblock_cache_mv(  h, 0, 0, 4, 4, 1, 0, 0 );
+        return 1;
+    }
+
     /* FIXME: optimize per block size */
     for( i = 0; i < 4; i++ )
     {
         const int x8 = 2*(i%2);
         const int y8 = 2*(i/2);
-        /* TODO: MapColToList0 */
-        const int i_ref = h->fref1[0]->ref[0][ i_mb_8x8 + x8/2 + y8 * h->mb.i_mb_stride ];
+        const int i_part_8x8 = i_mb_8x8 + x8/2 + y8 * h->mb.i_mb_stride;
+        const int i_ref = h->mb.map_col_to_list0[ h->fref1[0]->ref[0][ i_part_8x8 ] ];
 
-        if( i_ref == -1 )
-        {
-            x264_macroblock_cache_ref( h, x8, y8, 2, 2, 0, 0 );
-            x264_macroblock_cache_mv(  h, x8, y8, 2, 2, 0, 0, 0 );
-            x264_macroblock_cache_mv(  h, x8, y8, 2, 2, 1, 0, 0 );
-        }
-        else
+        if( i_ref >= 0 )
         {
             const int dist_scale_factor = h->mb.dist_scale_factor[i_ref][0];
             int x4, y4;
@@ -373,6 +375,12 @@ static int x264_mb_predict_mv_direct16x16_temporal( x264_t *h )
                     x264_macroblock_cache_mv( h, x4, y4, 1, 1, 1, mv_l0[0] - mv_col[0], mv_l0[1] - mv_col[1] );
                 }
         }
+        else
+        {
+            /* the colocated ref isn't in the current list0 */
+            /* FIXME: we might still be able to use direct_8x8 on some partitions */
+            return 0;
+        }
     }
 
     return 1;
@@ -821,7 +829,6 @@ void x264_macroblock_cache_init( x264_t *h )
     h->mb.i_b8_stride = h->sps->i_mb_width * 2;
     h->mb.i_b4_stride = h->sps->i_mb_width * 4;
 
-    h->mb.type= x264_malloc( i_mb_count * sizeof( int8_t) );
     h->mb.qp  = x264_malloc( i_mb_count * sizeof( int8_t) );
     h->mb.cbp = x264_malloc( i_mb_count * sizeof( int16_t) );
     h->mb.skipbp = x264_malloc( i_mb_count * sizeof( int8_t) );
@@ -840,8 +847,11 @@ void x264_macroblock_cache_init( x264_t *h )
     }
 
     for( i=0; i<2; i++ )
-        for( j=0; j < ( i ? 1 : h->param.i_frame_reference ); j++ )
+    {
+        int i_refs = i ? 1 + h->param.b_bframe_pyramid : h->param.i_frame_reference;
+        for( j=0; j < i_refs; j++ )
             h->mb.mvr[i][j] = x264_malloc( 2 * i_mb_count * sizeof( int16_t ) );
+    }
 
     /* init with not avaiable (for top right idx=7,15) */
     memset( h->mb.cache.ref[0], -2, X264_SCAN8_SIZE * sizeof( int8_t ) );
@@ -851,8 +861,11 @@ void x264_macroblock_cache_end( x264_t *h )
 {
     int i, j;
     for( i=0; i<2; i++ )
-        for( j=0; j < ( i ? 1 : h->param.i_frame_reference ); j++ )
+    {
+        int i_refs = i ? 1 + h->param.b_bframe_pyramid : h->param.i_frame_reference;
+        for( j=0; j < i_refs; j++ )
             x264_free( h->mb.mvr[i][j] );
+    }
     if( h->param.b_cabac )
     {
         x264_free( h->mb.chroma_pred_mode );
@@ -864,16 +877,16 @@ void x264_macroblock_cache_end( x264_t *h )
     x264_free( h->mb.skipbp );
     x264_free( h->mb.cbp );
     x264_free( h->mb.qp );
-    x264_free( h->mb.type );
 }
 void x264_macroblock_slice_init( x264_t *h )
 {
-    int i;
+    int i, j;
 
     h->mb.mv[0] = h->fdec->mv[0];
     h->mb.mv[1] = h->fdec->mv[1];
     h->mb.ref[0] = h->fdec->ref[0];
     h->mb.ref[1] = h->fdec->ref[1];
+    h->mb.type = h->fdec->mb_type;
 
     h->fdec->i_ref[0] = h->i_ref0;
     h->fdec->i_ref[1] = h->i_ref1;
@@ -883,6 +896,20 @@ void x264_macroblock_slice_init( x264_t *h )
     {
         for( i = 0; i < h->i_ref1; i++ )
             h->fdec->ref_poc[1][i] = h->fref1[i]->i_poc;
+
+        h->mb.map_col_to_list0[-1] = -1;
+        h->mb.map_col_to_list0[-2] = -2;
+        for( i = 0; i < h->fref1[0]->i_ref[0]; i++ )
+        {
+            int poc = h->fref1[0]->ref_poc[0][i];
+            h->mb.map_col_to_list0[i] = -2;
+            for( j = 0; j < h->i_ref0; j++ )
+                if( h->fref0[j]->i_poc == poc )
+                {
+                    h->mb.map_col_to_list0[i] = j;
+                    break;
+                }
+        }
     }
 }
 
index 6e8c429..7eb749a 100644 (file)
@@ -874,7 +874,8 @@ static void x264_mb_analyse_inter_b16x16( x264_t *h, x264_mb_analysis_t *a )
     a->l0.me16x16.cost -= a->i_lambda * bs_size_te( h->sh.i_num_ref_idx_l0_active - 1, a->l0.i_ref );
 
     /* ME for list 1 */
-    /* not using fullpel_thresh since we don't yet do more than 1 list 1 ref */
+    i_fullpel_thresh = INT_MAX;
+    p_fullpel_thresh = h->i_ref1>1 ? &i_fullpel_thresh : NULL;
     a->l1.me16x16.cost = INT_MAX;
     for( i_ref = 0; i_ref < h->i_ref1; i_ref++ )
     {
@@ -882,7 +883,7 @@ static void x264_mb_analyse_inter_b16x16( x264_t *h, x264_mb_analysis_t *a )
         LOAD_HPELS( m.p_fref, h->mb.pic.p_fref[1][i_ref], 0 );
         x264_mb_predict_mv_16x16( h, 1, i_ref, m.mvp );
         x264_mb_predict_mv_ref16x16( h, 1, i_ref, mvc, &i_mvc );
-        x264_me_search( h, &m, mvc, i_mvc );
+        x264_me_search_ref( h, &m, mvc, i_mvc, p_fullpel_thresh );
 
         /* add ref cost */
         m.cost += a->i_lambda * bs_size_te( h->sh.i_num_ref_idx_l1_active - 1, i_ref );
index d071a40..91e0983 100644 (file)
@@ -1069,7 +1069,7 @@ void x264_macroblock_write_cabac( x264_t *h, bs_t *s )
                 continue;
             for( i = 0; i < 4; i++ )
             {
-                if( x264_mb_partition_listX_table[0][ h->mb.i_sub_partition[i] ] )
+                if( x264_mb_partition_listX_table[i_list][ h->mb.i_sub_partition[i] ] )
                 {
                     x264_cabac_mb_ref( h, i_list, 4*i );
                 }
index 61ff00f..70b57a2 100644 (file)
@@ -124,6 +124,7 @@ static void x264_slice_header_init( x264_t *h, x264_slice_header_t *sh,
                                     int i_type, int i_idr_pic_id, int i_frame, int i_qp )
 {
     x264_param_t *param = &h->param;
+    int i;
 
     /* First we fill all field */
     sh->sps = sps;
@@ -154,6 +155,25 @@ static void x264_slice_header_init( x264_t *h, x264_slice_header_t *sh,
     sh->i_num_ref_idx_l0_active = 1;
     sh->i_num_ref_idx_l1_active = 1;
 
+    sh->b_ref_pic_list_reordering_l0 = h->b_ref_reorder[0];
+    sh->b_ref_pic_list_reordering_l1 = h->b_ref_reorder[1];
+
+    /* If the ref list isn't in the default order, construct reordering header */
+    /* List1 reordering isn't needed yet */
+    if( sh->b_ref_pic_list_reordering_l0 )
+    {
+        int pred_frame_num = i_frame;
+        for( i = 0; i < h->i_ref0; i++ )
+        {
+            int diff = h->fref0[i]->i_frame_num - pred_frame_num;
+            if( diff == 0 )
+                x264_log( h, X264_LOG_ERROR, "diff frame num == 0\n" );
+            sh->ref_pic_list_order[0][i].idc = ( diff > 0 );
+            sh->ref_pic_list_order[0][i].arg = abs( diff ) - 1;
+            pred_frame_num = h->fref0[i]->i_frame_num;
+        }
+    }
+
     sh->i_cabac_init_idc = param->i_cabac_init_idc;
 
     sh->i_qp_delta = i_qp - pps->i_pic_init_qp;
@@ -177,6 +197,8 @@ static void x264_slice_header_init( x264_t *h, x264_slice_header_t *sh,
 
 static void x264_slice_header_write( bs_t *s, x264_slice_header_t *sh, int i_nal_ref_idc )
 {
+    int i;
+
     bs_write_ue( s, sh->i_first_mb );
     bs_write_ue( s, sh->i_type + 5 );   /* same type things */
     bs_write_ue( s, sh->i_pps_id );
@@ -229,20 +251,29 @@ static void x264_slice_header_write( bs_t *s, x264_slice_header_t *sh, int i_nal
     /* ref pic list reordering */
     if( sh->i_type != SLICE_TYPE_I )
     {
-        int b_ref_pic_list_reordering_l0 = 0;
-        bs_write1( s, b_ref_pic_list_reordering_l0 );
-        if( b_ref_pic_list_reordering_l0 )
+        bs_write1( s, sh->b_ref_pic_list_reordering_l0 );
+        if( sh->b_ref_pic_list_reordering_l0 )
         {
-            /* FIXME */
+            for( i = 0; i < sh->i_num_ref_idx_l0_active; i++ )
+            {
+                bs_write_ue( s, sh->ref_pic_list_order[0][i].idc );
+                bs_write_ue( s, sh->ref_pic_list_order[0][i].arg );
+                        
+            }
+            bs_write_ue( s, 3 );
         }
     }
     if( sh->i_type == SLICE_TYPE_B )
     {
-        int b_ref_pic_list_reordering_l1 = 0;
-        bs_write1( s, b_ref_pic_list_reordering_l1 );
-        if( b_ref_pic_list_reordering_l1 )
+        bs_write1( s, sh->b_ref_pic_list_reordering_l1 );
+        if( sh->b_ref_pic_list_reordering_l1 )
         {
-            /* FIXME */
+            for( i = 0; i < sh->i_num_ref_idx_l1_active; i++ )
+            {
+                bs_write_ue( s, sh->ref_pic_list_order[1][i].idc );
+                bs_write_ue( s, sh->ref_pic_list_order[1][i].arg );
+            }
+            bs_write_ue( s, 3 );
         }
     }
 
@@ -349,7 +380,12 @@ x264_t *x264_encoder_open   ( x264_param_t *param )
 
     h->param.i_bframe = x264_clip3( h->param.i_bframe, 0, X264_BFRAME_MAX );
     h->param.i_bframe_bias = x264_clip3( h->param.i_bframe_bias, -90, 100 );
+    h->param.b_bframe_pyramid = h->param.b_bframe_pyramid && h->param.i_bframe;
     h->frames.i_delay = h->param.i_bframe;
+    h->frames.i_max_ref0 = h->param.i_frame_reference;
+    h->frames.i_max_ref1 = h->param.b_bframe_pyramid ? 2
+                            : h->param.i_bframe ? 1 : 0;
+    h->frames.i_max_dpb = h->frames.i_max_ref0 + h->frames.i_max_ref1 + 1;
 
     h->param.i_deblocking_filter_alphac0 = x264_clip3( h->param.i_deblocking_filter_alphac0, -6, 6 );
     h->param.i_deblocking_filter_beta    = x264_clip3( h->param.i_deblocking_filter_beta, -6, 6 );
@@ -436,11 +472,11 @@ x264_t *x264_encoder_open   ( x264_param_t *param )
     {
         h->frames.unused[i] =  x264_frame_new( h );
     }
-    for( i = 0; i < 2 + h->param.i_frame_reference; i++ )
+    for( i = 0; i < h->frames.i_max_dpb; i++ )
     {
-        /* 2 = 1 backward ref  + 1 fdec */
         h->frames.reference[i] = x264_frame_new( h );
     }
+    h->frames.reference[h->frames.i_max_dpb] = NULL;
     h->frames.i_last_idr = - h->param.i_keyint_max;
     h->frames.i_input    = 0;
 
@@ -560,35 +596,40 @@ int x264_encoder_headers( x264_t *h, x264_nal_t **pp_nal, int *pi_nal )
 static void x264_frame_put( x264_frame_t *list[X264_BFRAME_MAX], x264_frame_t *frame )
 {
     int i = 0;
-
-    while( list[i] != NULL ) i++;
-
+    while( list[i] ) i++;
     list[i] = frame;
 }
 
+static void x264_frame_push( x264_frame_t *list[X264_BFRAME_MAX], x264_frame_t *frame )
+{
+    int i = 0;
+    while( list[i] ) i++;
+    while( i-- )
+        list[i+1] = list[i];
+    list[0] = frame;
+}
+
 static x264_frame_t *x264_frame_get( x264_frame_t *list[X264_BFRAME_MAX+1] )
 {
     x264_frame_t *frame = list[0];
     int i;
-
-    for( i = 0; i < X264_BFRAME_MAX; i++ )
-    {
+    for( i = 0; i < X264_BFRAME_MAX && list[i]; i++ )
         list[i] = list[i+1];
-    }
-    list[X264_BFRAME_MAX] = NULL;
-
     return frame;
 }
 
-/* Sort queued frames into input order */
-static void x264_frame_sort( x264_frame_t *list[X264_BFRAME_MAX+1] )
+static void x264_frame_sort( x264_frame_t *list[X264_BFRAME_MAX+1], int b_dts )
 {
     int i, b_ok;
     do {
         b_ok = 1;
         for( i = 0; i < X264_BFRAME_MAX && list[i+1]; i++ )
         {
-            if( list[i]->i_frame > list[i+1]->i_frame )
+            int dtype = list[i]->i_type - list[i+1]->i_type;
+            int dtime = list[i]->i_frame - list[i+1]->i_frame;
+            int swap = b_dts ? dtype > 0 || ( dtype == 0 && dtime > 0 )
+                             : dtime > 0;
+            if( swap )
             {
                 x264_frame_t *tmp = list[i+1];
                 list[i+1] = list[i];
@@ -598,8 +639,10 @@ static void x264_frame_sort( x264_frame_t *list[X264_BFRAME_MAX+1] )
         }
     } while( !b_ok );
 }
+#define x264_frame_sort_dts(list) x264_frame_sort(list, 1)
+#define x264_frame_sort_pts(list) x264_frame_sort(list, 0)
 
-static inline void x264_reference_build_list( x264_t *h, int i_poc )
+static inline void x264_reference_build_list( x264_t *h, int i_poc, int i_slice_type )
 {
     int i;
     int b_ok;
@@ -607,7 +650,7 @@ static inline void x264_reference_build_list( x264_t *h, int i_poc )
     /* build ref list 0/1 */
     h->i_ref0 = 0;
     h->i_ref1 = 0;
-    for( i = 1; i < h->param.i_frame_reference+2; i++ )
+    for( i = 1; i < h->frames.i_max_dpb; i++ )
     {
         if( h->frames.reference[i]->i_poc >= 0 )
         {
@@ -621,6 +664,7 @@ static inline void x264_reference_build_list( x264_t *h, int i_poc )
             }
         }
     }
+
     /* Order ref0 from higher to lower poc */
     do
     {
@@ -656,14 +700,22 @@ static inline void x264_reference_build_list( x264_t *h, int i_poc )
         }
     } while( !b_ok );
 
-    if( h->i_ref0 > h->param.i_frame_reference )
-    {
-        h->i_ref0 = h->param.i_frame_reference;
-    }
-    if( h->i_ref1 > 1 )
+    /* In the standard, a P-frame's ref list is sorted by frame_num.
+     * We use POC, but check whether explicit reordering is needed */
+    h->b_ref_reorder[0] =
+    h->b_ref_reorder[1] = 0;
+    if( i_slice_type == SLICE_TYPE_P )
     {
-        h->i_ref1 = 1;
+        for( i = 0; i < h->i_ref0 - 1; i++ )
+            if( h->fref0[i]->i_frame_num < h->fref0[i+1]->i_frame_num )
+            {
+                h->b_ref_reorder[0] = 1;
+                break;
+            }
     }
+
+    h->i_ref0 = X264_MIN( h->i_ref0, h->frames.i_max_ref0 );
+    h->i_ref1 = X264_MIN( h->i_ref1, h->frames.i_max_ref1 );
 }
 
 static inline void x264_reference_update( x264_t *h )
@@ -699,8 +751,9 @@ static inline void x264_reference_update( x264_t *h )
         h->frames.last_nonb = h->fdec;
 
     /* move frame in the buffer */
-    h->fdec = h->frames.reference[h->param.i_frame_reference+1];
-    for( i = h->param.i_frame_reference+1; i > 0; i-- )
+    /* FIXME: override to forget earliest pts, not earliest dts */
+    h->fdec = h->frames.reference[h->frames.i_max_dpb-1];
+    for( i = h->frames.i_max_dpb-1; i > 0; i-- )
     {
         h->frames.reference[i] = h->frames.reference[i-1];
     }
@@ -712,7 +765,7 @@ static inline void x264_reference_reset( x264_t *h )
     int i;
 
     /* reset ref pictures */
-    for( i = 1; i < h->param.i_frame_reference+2; i++ )
+    for( i = 1; i < h->frames.i_max_dpb; i++ )
     {
         h->frames.reference[i]->i_poc = -1;
     }
@@ -739,6 +792,8 @@ static inline void x264_slice_init( x264_t *h, int i_nal_type, int i_slice_type,
         h->sh.i_num_ref_idx_l1_active = h->i_ref1 <= 0 ? 1 : h->i_ref1;
     }
 
+    h->fdec->i_frame_num = h->sh.i_frame_num;
+
     if( h->sps->i_poc_type == 0 )
     {
         h->sh.i_poc_lsb = h->fdec->i_poc & ( (1 << h->sps->i_log2_max_poc_lsb) - 1 );
@@ -982,12 +1037,19 @@ int     x264_encoder_encode( x264_t *h,
         x264_slicetype_decide( h );
 
         /* 3: move some B-frames and 1 non-B to encode queue */
-        while( h->frames.next[bframes]->i_type == X264_TYPE_B )
+        while( IS_X264_TYPE_B( h->frames.next[bframes]->i_type ) )
             bframes++;
-        x264_frame_put( h->frames.current, h->frames.next[bframes] );
+        x264_frame_put( h->frames.current, x264_frame_get( &h->frames.next[bframes] ) );
+        /* FIXME: when max B-frames > 3, BREF may no longer be centered after GOP closing */
+        if( h->param.b_bframe_pyramid && bframes > 1 )
+        {
+            x264_frame_t *mid = x264_frame_get( &h->frames.next[bframes/2] );
+            mid->i_type = X264_TYPE_BREF;
+            x264_frame_put( h->frames.current, mid );
+            bframes--;
+        }
         while( bframes-- )
             x264_frame_put( h->frames.current, x264_frame_get( h->frames.next ) );
-        x264_frame_get( h->frames.next );
     }
     TIMER_STOP( i_mtime_encode_frame );
 
@@ -1033,6 +1095,12 @@ do_encode:
         i_nal_ref_idc = NAL_PRIORITY_HIGH; /* Not completely true but for now it is (as all I/P are kept as ref)*/
         i_slice_type = SLICE_TYPE_P;
     }
+    else if( h->fenc->i_type == X264_TYPE_BREF )
+    {
+        i_nal_type    = NAL_SLICE;
+        i_nal_ref_idc = NAL_PRIORITY_HIGH; /* maybe add MMCO to forget it? -> low */
+        i_slice_type = SLICE_TYPE_B;
+    }
     else    /* B frame */
     {
         i_nal_type    = NAL_SLICE;
@@ -1043,6 +1111,8 @@ do_encode:
     h->fdec->i_type = h->fenc->i_type;
     h->fdec->i_poc  = h->fenc->i_poc;
     h->fdec->i_frame = h->fenc->i_frame;
+    h->fenc->b_kept_as_ref =
+    h->fdec->b_kept_as_ref = i_nal_ref_idc != NAL_PRIORITY_DISPOSABLE;
 
 
 
@@ -1054,7 +1124,7 @@ do_encode:
     h->fdec->i_qpplus1 = i_global_qp + 1;
 
     /* build ref list 0/1 */
-    x264_reference_build_list( h, h->fdec->i_poc );
+    x264_reference_build_list( h, h->fdec->i_poc, i_slice_type );
 
     if( i_slice_type == SLICE_TYPE_B )
         x264_macroblock_bipred_init( h );
@@ -1101,7 +1171,6 @@ do_encode:
     /* 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 )
     {
@@ -1150,6 +1219,7 @@ do_encode:
             h->out.nal[h->out.i_nal-1].i_payload > 2 * h->i_last_inter_size &&
             h->frames.i_last_i > 4)*/
         {
+            int b;
 
             x264_log( h, X264_LOG_DEBUG, "scene cut at %d size=%d Icost:%.0f Pcost:%.0f ratio:%.3f bias=%.3f lastIDR:%d (I:%d P:%d Skip:%d)\n",
                       h->fenc->i_frame,
@@ -1162,8 +1232,8 @@ do_encode:
             /* 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 )
+            for( b = 0; h->frames.current[b] && IS_X264_TYPE_B( h->frames.current[b]->i_type ); b++ );
+            if( b > 0 )
             {
                 /* If using B-frames, force GOP to be closed.
                  * Even if this frame is going to be I and not IDR, forcing a
@@ -1173,10 +1243,14 @@ do_encode:
                  * 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;
+                if( h->param.b_bframe_adaptive || b > 1 )
+                    h->fenc->i_type = X264_TYPE_AUTO;
+                x264_frame_sort_pts( h->frames.current );
+                x264_frame_push( h->frames.next, h->fenc );
+                h->fenc = h->frames.current[b-1];
+                h->frames.current[b-1] = NULL;
                 h->fenc->i_type = X264_TYPE_P;
+                x264_frame_sort_dts( h->frames.current );
             }
             /* Do IDR if needed */
             else if( i_gop_size >= h->param.i_keyint_min )
@@ -1197,7 +1271,7 @@ do_encode:
                 /* 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 );
+                x264_frame_sort_pts( h->frames.next );
             }
             else
             {
@@ -1465,7 +1539,7 @@ void    x264_encoder_close  ( x264_t *h )
         if( h->frames.unused[i] )  x264_frame_delete( h->frames.unused[i] );
     }
     /* ref frames */
-    for( i = 0; i < h->param.i_frame_reference+2; i++ )
+    for( i = 0; i < h->frames.i_max_dpb; i++ )
     {
         x264_frame_delete( h->frames.reference[i] );
     }
index 47f9de3..6d51d68 100644 (file)
@@ -53,7 +53,7 @@
 typedef struct
 {
     int pict_type;
-    int idr;
+    int kept_as_ref;
     float qscale;
     int mv_bits;
     int i_tex_bits;
@@ -313,10 +313,11 @@ int x264_ratecontrol_new( x264_t *h )
                    &rce->mv_bits, &rce->misc_bits, &rce->i_count, &rce->p_count, &rce->s_count);
 
             switch(pict_type){
-                case 'I': rce->idr = 1;
+                case 'I': rce->kept_as_ref = 1;
                 case 'i': rce->pict_type = SLICE_TYPE_I; break;
                 case 'P': rce->pict_type = SLICE_TYPE_P; break;
-                case 'B': rce->pict_type = SLICE_TYPE_B; break;
+                case 'B': rce->kept_as_ref = 1;
+                case 'b': rce->pict_type = SLICE_TYPE_B; break;
                 default:  e = -1; break;
             }
             if(e != 10){
@@ -392,8 +393,12 @@ void x264_ratecontrol_start( x264_t *h, int i_slice_type )
 
     if( !h->param.rc.b_cbr )
     {
-        rc->qpm = rc->qpa = rc->qp =
-            rc->qp_constant[ i_slice_type ];
+        int q;
+        if( i_slice_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
+            q = rc->qp_constant[ i_slice_type ];
+        rc->qpm = rc->qpa = rc->qp = q;
         return;
     }
     else if( h->param.rc.b_stat_read )
@@ -579,10 +584,10 @@ int x264_ratecontrol_slice_type( x264_t *h, int frame_num )
         switch( h->rc->entry[frame_num].pict_type )
         {
             case SLICE_TYPE_I:
-                return h->rc->entry[frame_num].idr ? X264_TYPE_IDR : X264_TYPE_I;
+                return h->rc->entry[frame_num].kept_as_ref ? X264_TYPE_IDR : X264_TYPE_I;
 
             case SLICE_TYPE_B:
-                return X264_TYPE_B;
+                return h->rc->entry[frame_num].kept_as_ref ? X264_TYPE_BREF : X264_TYPE_B;
 
             case SLICE_TYPE_P:
             default:
@@ -610,7 +615,8 @@ void x264_ratecontrol_end( x264_t *h, int bits )
     if( h->param.rc.b_stat_write )
     {
         char c_type = rc->slice_type==SLICE_TYPE_I ? (h->fenc->i_poc==0 ? 'I' : 'i')
-                    : rc->slice_type==SLICE_TYPE_P ? 'P' : 'B';
+                    : rc->slice_type==SLICE_TYPE_P ? 'P'
+                    : h->fenc->b_kept_as_ref ? 'B' : 'b';
         fprintf( rc->p_stat_file_out,
                  "in:%d out:%d type:%c q:%.3f itex:%d ptex:%d mv:%d misc:%d imb:%d pmb:%d smb:%d;\n",
                  h->fenc->i_frame, h->i_frame-1,
@@ -763,7 +769,8 @@ static double get_diff_limited_q(x264_t *h, ratecontrol_entry_t *rce, double q)
     {
         if( h->param.rc.f_pb_factor > 0 )
             q = last_non_b_q;
-        q *= fabs( h->param.rc.f_pb_factor );
+        if( !rce->kept_as_ref )
+            q *= fabs( h->param.rc.f_pb_factor );
     }
     else if( pict_type == SLICE_TYPE_P
              && rcc->last_non_b_pict_type == SLICE_TYPE_P
@@ -845,7 +852,10 @@ static float rate_estimate_qscale(x264_t *h, int pict_type)
 
     if(rce->pict_type == SLICE_TYPE_B)
     {
-        return rcc->last_qscale * h->param.rc.f_pb_factor;
+        if(rce->kept_as_ref)
+            return rcc->last_qscale * sqrtf(h->param.rc.f_pb_factor);
+        else
+            return rcc->last_qscale * h->param.rc.f_pb_factor;
     }
     else
     {
index 234cfc1..f6e1b87 100644 (file)
@@ -79,7 +79,9 @@ void x264_sps_init( x264_sps_t *sps, int i_id, x264_param_t *param )
 
     sps->i_num_ref_frames = param->i_frame_reference;
     if( param->i_bframe )
-        sps->i_num_ref_frames++; /* for 2 ref in B */
+        sps->i_num_ref_frames++; /* for backwards ref in B */
+    if( param->b_bframe_pyramid )
+        sps->i_num_ref_frames++; /* for 2nd backwards ref */
     sps->b_gaps_in_frame_num_value_allowed = 0;
     sps->i_mb_width = ( param->i_width + 15 ) / 16;
     sps->i_mb_height= ( param->i_height + 15 )/ 16;
index 93f6dc6..897cae5 100644 (file)
@@ -377,31 +377,33 @@ void x264_slicetype_decide( x264_t *h )
         }
         if( 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;
             }
+            else
+            {
+                h->i_poc = 0;
+                h->i_frame_num = 0;
+            }
         }
 
         if( bframes == h->param.i_bframe
             || h->frames.next[bframes+1] == NULL )
         {
-            if( frm->i_type == X264_TYPE_B )
+            if( IS_X264_TYPE_B( frm->i_type ) )
                 x264_log( h, X264_LOG_ERROR, "specified frame type is not compatible with max B-frames\n" );
-            if(    frm->i_type == X264_TYPE_AUTO
-                || frm->i_type == X264_TYPE_B )
+            if( frm->i_type == X264_TYPE_AUTO
+                || IS_X264_TYPE_B( frm->i_type ) )
                 frm->i_type = X264_TYPE_P;
         }
 
         frm->i_poc = h->i_poc;
         h->i_poc += 2;
 
-        if( frm->i_type != X264_TYPE_AUTO && frm->i_type != X264_TYPE_B )
+        if( frm->i_type != X264_TYPE_AUTO && frm->i_type != X264_TYPE_B && frm->i_type != X264_TYPE_BREF )
             break;
 
         frm->i_type = X264_TYPE_B;
diff --git a/x264.c b/x264.c
index 5a2ed14..85dda95 100644 (file)
--- a/x264.c
+++ b/x264.c
@@ -73,6 +73,7 @@ int main( int argc, char **argv )
 #endif
 
     x264_param_default( &param );
+    param.b_cabac = 0;
 
     /* Parse command line */
     if( Parse( argc, argv, &param, &fin, &fout, &b_decompress ) < 0 )
@@ -108,6 +109,7 @@ static void Help( x264_param_t *defaults )
              "  -b, --bframe <integer>      Number of B-frames between I and P [%d]\n"
              "      --no-b-adapt            Disable adaptive B-frame decision\n"
              "      --b-bias <integer>      Influences how often B-frames are used [%d]\n"
+             "      --b-pyramid             Keep some B-frames as references\n"
              "\n"
              "  -c, --cabac                 Enable CABAC\n"
              "  -r, --ref <integer>         Number of reference frames [%d]\n"
@@ -221,6 +223,7 @@ static int  Parse( int argc, char **argv,
 #define OPT_LEVEL 276
 #define OPT_NOBADAPT 277
 #define OPT_BBIAS 278
+#define OPT_BPYRAMID 279
 
         static struct option long_options[] =
         {
@@ -229,6 +232,7 @@ static int  Parse( int argc, char **argv,
             { "bframe",  required_argument, NULL, 'b' },
             { "no-b-adapt", no_argument,    NULL, OPT_NOBADAPT },
             { "b-bias",  required_argument, NULL, OPT_BBIAS },
+            { "b-pyramid", no_argument,     NULL, OPT_BPYRAMID },
             { "min-keyint",required_argument,NULL,'i' },
             { "keyint",  required_argument, NULL, 'I' },
             { "scenecut",required_argument, NULL, OPT_SCENECUT },
@@ -298,6 +302,9 @@ static int  Parse( int argc, char **argv,
             case OPT_BBIAS:
                 param->i_bframe_bias = atol( optarg );
                 break;
+            case OPT_BPYRAMID:
+                param->b_bframe_pyramid = 1;
+                break;
             case 'i':
                 param->i_keyint_min = atol( optarg );
                 break;
diff --git a/x264.h b/x264.h
index d8963bf..c4df922 100644 (file)
--- a/x264.h
+++ b/x264.h
@@ -26,7 +26,7 @@
 
 #include <stdarg.h>
 
-#define X264_BUILD 0x0013
+#define X264_BUILD 0x0014
 
 /* x264_t:
  *      opaque handler for decoder and encoder */
@@ -75,7 +75,10 @@ typedef struct x264_t x264_t;
 #define X264_TYPE_IDR           0x0001
 #define X264_TYPE_I             0x0002
 #define X264_TYPE_P             0x0003
-#define X264_TYPE_B             0x0004
+#define X264_TYPE_BREF          0x0004  /* Non-disposable B-frame */
+#define X264_TYPE_B             0x0005
+#define IS_X264_TYPE_I(x) ((x)==X264_TYPE_I || (x)==X264_TYPE_IDR)
+#define IS_X264_TYPE_B(x) ((x)==X264_TYPE_B || (x)==X264_TYPE_BREF)
 
 /* Log level
  */
@@ -115,6 +118,7 @@ typedef struct
     int         i_bframe;   /* how many b-frame between 2 references pictures */
     int         b_bframe_adaptive;
     int         i_bframe_bias;
+    int         b_bframe_pyramid;   /* Keep some B-frames as references */
 
     int         b_deblocking_filter;
     int         i_deblocking_filter_alphac0;    /* [-6, 6] -6 light filter, 6 strong */