[x264-devel] [PATCH] interlaced framework with PAFF implementation

Loïc Le Loarer lll+vlc at m4x.org
Tue Jun 13 01:33:06 CEST 2006


Hi,

Here my first interlace patch. This patch adds all the necessary
parameters for interlace support (PAFF, MBAFF and fields). The
parameters are :
- b_frame_mbs_only: 0 -> interlaced, 1 -> progressive
- b_mb_adaptive_frame_field: when !b_frame_mbs_only, 0->PAFF, 1->MBAFF
- b_top_field_first: necessary to know the fields order
- analyse.i_fields: 0-> don't create fields,
                    1-> automatically create fields or frame, which one
                        is the best
                    2-> create only fields

The x264 command line parameters are a bit different, to enable
interlace, ones should use either --paff, --mbaff or --fields n option
(where n is 0, 1 or 2). The first two are exclusive, --fields is 0 by
default and can be set to 1 or 2 to enable fields creation (but this is
not supported yet). --bottom-field-first set b_top_field_first to 0, the
default is 1.

For the moment, this patch allows only frames in a PAFF sequences and no
fields, and as PAFF frames are identical to progressive frame, there is
no compression improvement from progressive (default) setting.
Nonetheless, this patch sets the POCs differently for top and bottom
fields so that a decoder using the POCs will be able to display the
interlaced content correctly on an interlaced display (with the fields
in the correct order). For this only reason, it is a good idea to use
--paff and --bottom-field-first option if necessary to encode interlaced
content.

But I'm working on MBAFF implementation which will gives much better
result and the patch from Alex Izvorski from Auroras can be merge with
this as it covers the "--fields 2" options (fields forced).

Hope this can be included to be used a basis for futur improvements.

This applies on top of revision 532 patched with my previous patch
x264_fixes_1.diff sent a few minutes earlier.

Best regards.

-- 
Loïc

"heaven is not a place, it's a feeling"
-------------- next part --------------
Index: encoder/encoder.c
===================================================================
--- encoder/encoder.c	(.../branches/fixes1)	(révision 18)
+++ encoder/encoder.c	(.../trunk)	(révision 18)
@@ -193,6 +193,10 @@
     bs_write_ue( s, sh->i_pps_id );
     bs_write( s, sh->sps->i_log2_max_frame_num, sh->i_frame_num );
 
+    if( !sh->sps->b_frame_mbs_only )
+    {
+        bs_write1( s, 0 ); // Frame
+    }
     if( sh->i_idr_pic_id >= 0 ) /* NAL IDR */
     {
         bs_write_ue( s, sh->i_idr_pic_id );
@@ -325,12 +329,27 @@
                   h->param.i_width, h->param.i_height );
         return -1;
     }
+
+    if( !h->param.b_frame_mbs_only && h->param.i_height % 4 )
+    {
+        x264_log( h, X264_LOG_ERROR, "height not divisible by 4 in interlaced content (%dx%d)\n",
+                  h->param.i_width, h->param.i_height );
+        return -1;
+    }
+
     if( h->param.i_csp != X264_CSP_I420 )
     {
         x264_log( h, X264_LOG_ERROR, "invalid CSP (only I420 supported)\n" );
         return -1;
     }
 
+    h->param.analyse.i_fields = x264_clip3( h->param.analyse.i_fields, 0, 2 );
+    if ( !h->param.b_frame_mbs_only && h->param.analyse.i_fields == 2 )
+    {
+        x264_log( h, X264_LOG_ERROR, "Fields generation is not supported yet\n" );
+        return -1;
+    }
+
     h->param.i_threads = x264_clip3( h->param.i_threads, 1, X264_SLICE_MAX );
     h->param.i_threads = X264_MIN( h->param.i_threads, (h->param.i_height + 15) / 16 );
 #ifndef HAVE_PTHREAD
@@ -441,11 +460,17 @@
             /* The flag isn't forced, set it to 0 if the level doesn't
              * limit it to 1 and it is possible to generate P macroblocks
              * with partitions smaller than 8x8 */
-            h->param.i_direct_8x8_inference_flag = l->direct8x8 ? 1 : !(h->param.analyse.inter & X264_ANALYSE_PSUB8x8);
+            h->param.i_direct_8x8_inference_flag = l->direct8x8 || !h->param.b_frame_mbs_only || !(h->param.analyse.inter & X264_ANALYSE_PSUB8x8);
         }
         else
         {
             h->param.i_direct_8x8_inference_flag = x264_clip3( h->param.i_direct_8x8_inference_flag, 0, 1 );
+            /* direct_8x8_inference_flag must be 1 in interlace */
+            if (!h->param.b_frame_mbs_only && !h->param.i_direct_8x8_inference_flag)
+            {
+                x264_log( h, X264_LOG_ERROR, "direct_8x8_inference_flag must be 1 if frame_mbs_only_flag is 0\n" );
+                return -1;
+            }
             /* if the level limits this flag to 1, check it isn't forced to 0 */
             if (h->param.i_direct_8x8_inference_flag < l->direct8x8)
             {
@@ -468,6 +493,9 @@
 #define BOOLIFY(x) h->param.x = !!h->param.x
     BOOLIFY( b_cabac );
     BOOLIFY( b_deblocking_filter );
+    BOOLIFY( b_frame_mbs_only );
+    BOOLIFY( b_top_field_first );
+    BOOLIFY( b_mb_adaptive_frame_field );
     BOOLIFY( analyse.b_transform_8x8 );
     BOOLIFY( analyse.b_bidir_me );
     BOOLIFY( analyse.b_chroma_me );
@@ -986,7 +1014,12 @@
     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 );
-        h->sh.i_delta_poc_bottom = 0;   /* XXX won't work for field */
+        h->sh.i_delta_poc_bottom = !h->param.b_frame_mbs_only;
+        if (!h->param.b_frame_mbs_only && !h->param.b_top_field_first)
+        {
+            h->sh.i_poc_lsb += 1;
+            h->sh.i_delta_poc_bottom = -1;
+        }
     }
     else if( h->sps->i_poc_type == 1 )
     {
Index: encoder/set.c
===================================================================
--- encoder/set.c	(.../branches/fixes1)	(révision 18)
+++ encoder/set.c	(.../trunk)	(révision 18)
@@ -77,12 +77,13 @@
 {
     sps->i_id = i_id;
 
+    sps->b_frame_mbs_only = param->b_frame_mbs_only;
     sps->b_qpprime_y_zero_transform_bypass = !param->rc.b_cbr && param->rc.i_qp_constant == 0;
     if( sps->b_qpprime_y_zero_transform_bypass )
         sps->i_profile_idc  = PROFILE_HIGH444;
     else if( param->analyse.b_transform_8x8 || param->i_cqm_preset != X264_CQM_FLAT )
         sps->i_profile_idc  = PROFILE_HIGH;
-    else if( param->b_cabac || param->i_bframe > 0 )
+    else if( param->b_cabac || param->i_bframe > 0 || !sps->b_frame_mbs_only )
         sps->i_profile_idc  = PROFILE_MAIN;
     else
         sps->i_profile_idc  = PROFILE_BASELINE;
@@ -128,13 +129,14 @@
     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;
-    sps->b_frame_mbs_only = 1;
-    sps->b_mb_adaptive_frame_field = 0;
+    if (!sps->b_frame_mbs_only)
+        sps->i_mb_height= ( sps->i_mb_height + 1 ) & ~1;
+    sps->b_mb_adaptive_frame_field = param->b_mb_adaptive_frame_field;
     sps->b_direct8x8_inference = param->i_direct_8x8_inference_flag;
     sps->crop.i_left   = 0;
     sps->crop.i_top    = 0;
-    sps->crop.i_right  = (- param->i_width)  & 15;
-    sps->crop.i_bottom = (- param->i_height) & 15;
+    sps->crop.i_right  = (- param->i_width) & 15;
+    sps->crop.i_bottom = sps->i_mb_height*16 - param->i_height;
     sps->b_crop = sps->crop.i_left  || sps->crop.i_top ||
                   sps->crop.i_right || sps->crop.i_bottom;
 
@@ -252,7 +254,10 @@
     bs_write_ue( s, sps->i_num_ref_frames );
     bs_write( s, 1, sps->b_gaps_in_frame_num_value_allowed );
     bs_write_ue( s, sps->i_mb_width - 1 );
-    bs_write_ue( s, sps->i_mb_height - 1);
+    {
+        int i_map_height = sps->i_mb_height >> !sps->b_frame_mbs_only;
+        bs_write_ue( s, i_map_height - 1);
+    }
     bs_write( s, 1, sps->b_frame_mbs_only );
     if( !sps->b_frame_mbs_only )
     {
@@ -265,8 +270,8 @@
     {
         bs_write_ue( s, sps->crop.i_left   / 2 );
         bs_write_ue( s, sps->crop.i_right  / 2 );
-        bs_write_ue( s, sps->crop.i_top    / 2 );
-        bs_write_ue( s, sps->crop.i_bottom / 2 );
+        bs_write_ue( s, sps->crop.i_top    / (2 * (1+!sps->b_frame_mbs_only)) ); // Divide by 2 if frame_mb_only and 4 else
+        bs_write_ue( s, sps->crop.i_bottom / (2 * (1+!sps->b_frame_mbs_only)) ); // Divide by 2 if frame_mb_only and 4 else
     }
 
     bs_write( s, 1, sps->b_vui );
@@ -361,7 +366,7 @@
     pps->i_sps_id = sps->i_id;
     pps->b_cabac = param->b_cabac;
 
-    pps->b_pic_order = 0;
+    pps->b_pic_order = !sps->b_frame_mbs_only;
     pps->i_num_slice_groups = 1;
 
     pps->i_num_ref_idx_l0_active = 1;
Index: x264.c
===================================================================
--- x264.c	(.../branches/fixes1)	(révision 18)
+++ x264.c	(.../trunk)	(révision 18)
@@ -458,6 +458,10 @@
 #define OPT_NO_DCT_DECIMATE 321
 #define OPT_SPS_ID 322
 #define OPT_DIRECT_8X8 323
+#define OPT_MBAFF 324
+#define OPT_PAFF 325
+#define OPT_FIELDS 326
+#define OPT_BOTTOMFIELDFIRST 327
 
         static struct option long_options[] =
         {
@@ -544,6 +548,10 @@
             { "transfer", required_argument, NULL, OPT_TRANSFER },
             { "colormatrix", required_argument, NULL, OPT_COLOURMATRIX },
             { "chromaloc", required_argument, NULL, OPT_CHROMALOC },
+            { "mbaff", no_argument, NULL, OPT_MBAFF },
+            { "paff", no_argument, NULL, OPT_PAFF },
+            { "fields", required_argument, NULL, OPT_FIELDS },
+            { "bottom-field-first", no_argument, NULL, OPT_BOTTOMFIELDFIRST },
             {0, 0, 0, 0}
         };
 
@@ -924,6 +932,21 @@
                 param->vui.i_chroma_loc = atoi( optarg );
                 b_error = ( param->vui.i_chroma_loc < 0 || param->vui.i_chroma_loc > 5 );
                 break;
+            case OPT_MBAFF:
+                param->b_frame_mbs_only = 0;
+                param->b_mb_adaptive_frame_field = 1;
+                break;
+            case OPT_PAFF:
+                param->b_frame_mbs_only = 0;
+                param->b_mb_adaptive_frame_field = 0;
+                break;
+            case OPT_FIELDS:
+                param->b_frame_mbs_only = 0;
+                param->analyse.i_fields = atoi( optarg );
+                break;
+            case OPT_BOTTOMFIELDFIRST:
+                param->b_top_field_first= 0;
+                break;
             default:
                 fprintf( stderr, "unknown option (%c)\n", optopt );
                 return -1;
Index: common/common.c
===================================================================
--- common/common.c	(.../branches/fixes1)	(révision 18)
+++ common/common.c	(.../trunk)	(révision 18)
@@ -48,10 +48,10 @@
 
     /* Video properties */
     param->i_csp           = X264_CSP_I420;
-    param->i_width         = 0;
-    param->i_height        = 0;
-    param->vui.i_sar_width = 0;
-    param->vui.i_sar_height= 0;
+    param->i_width         = 0;  /* must be set */
+    param->i_height        = 0;  /* must be set */
+    param->vui.i_sar_width = 0;  /* undef */
+    param->vui.i_sar_height= 0;  /* undef */
     param->vui.i_overscan  = 0;  /* undef */
     param->vui.i_vidformat = 5;  /* undef */
     param->vui.b_fullrange = 0;  /* off */
@@ -73,6 +73,9 @@
     param->i_bframe_bias = 0;
     param->b_bframe_pyramid = 0;
     param->i_direct_8x8_inference_flag = -1;
+    param->b_frame_mbs_only = 1;
+    param->b_top_field_first = 1;
+    param->b_mb_adaptive_frame_field = 1;
 
     param->b_deblocking_filter = 1;
     param->i_deblocking_filter_alphac0 = 0;
@@ -125,6 +128,7 @@
     param->analyse.b_fast_pskip = 1;
     param->analyse.b_dct_decimate = 1;
     param->analyse.b_psnr = 1;
+    param->analyse.i_fields = 1;
 
     param->i_cqm_preset = X264_CQM_FLAT;
     memset( param->cqm_4iy, 16, 16 );
@@ -472,6 +476,11 @@
 
     s += sprintf( s, "cabac=%d", p->b_cabac );
     s += sprintf( s, " ref=%d", p->i_frame_reference );
+    s += sprintf( s, " frame_mbs_only=%d", p->b_frame_mbs_only );
+    if ( !p->b_frame_mbs_only ) {
+        s += sprintf( s, " mbaff=%d", p->b_mb_adaptive_frame_field );
+        s += sprintf( s, " fields=%d", p->analyse.i_fields );
+    }
     s += sprintf( s, " deblock=%d:%d:%d", p->b_deblocking_filter,
                   p->i_deblocking_filter_alphac0, p->i_deblocking_filter_beta );
     s += sprintf( s, " analyse=%#x:%#x", p->analyse.intra, p->analyse.inter );
Index: x264.h
===================================================================
--- x264.h	(.../branches/fixes1)	(révision 18)
+++ x264.h	(.../trunk)	(révision 18)
@@ -160,6 +160,9 @@
     int         i_bframe_bias;
     int         b_bframe_pyramid;   /* Keep some B-frames as references */
     int         i_direct_8x8_inference_flag; /* Use direct_8x8_inference_flag in SPS: (-1: 0 if possible according to level and partition mode) */
+    int         b_frame_mbs_only; /* If 1, progressive sequence, if 0, interlaced sequence and b_top_field_first and b_mb_adaptive_frame_field are used */
+    int         b_top_field_first;
+    int         b_mb_adaptive_frame_field;
 
     int         b_deblocking_filter;
     int         i_deblocking_filter_alphac0;    /* [-6, 6] -6 light filter, 6 strong */
@@ -209,6 +212,9 @@
         int          i_noise_reduction; /* adaptive pseudo-deadzone */
 
         int          b_psnr;    /* Do we compute PSNR stats (save a few % of cpu) */
+        int          i_fields; /* In interlaced, 0 -> don't generate fields */
+                               /*                1 -> automaticaly generate fields */
+                               /*                2 -> generate fields only */
     } analyse;
 
     /* Rate control parameters */
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
Url : http://mailman.videolan.org/pipermail/x264-devel/attachments/20060613/9da3bcdc/attachment.pgp 


More information about the x264-devel mailing list