[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