[x264-devel] Improve Blu-ray compliance

Jason Garrett-Glaser git at videolan.org
Wed Apr 13 04:04:30 CEST 2011


x264 | branch: master | Jason Garrett-Glaser <jason at x264.com> | Wed Apr  6 02:16:42 2011 -0700| [7a9e08d301212fc37516562269d5fbbc040cf84c] | committer: Jason Garrett-Glaser

Improve Blu-ray compliance
Use dec_ref_pic_marking SEIs to repeat B-ref referencing information.
Don't allow B-frames to reference frames outside their minigop.

> http://git.videolan.org/gitweb.cgi/x264.git/?a=commit;h=7a9e08d301212fc37516562269d5fbbc040cf84c
---

 common/common.h   |    5 +++++
 encoder/encoder.c |   21 +++++++++++++++++++++
 encoder/set.c     |   33 ++++++++++++++++++++++++++++++++-
 encoder/set.h     |    1 +
 4 files changed, 59 insertions(+), 1 deletions(-)

diff --git a/common/common.h b/common/common.h
index 496542e..a9be078 100644
--- a/common/common.h
+++ b/common/common.h
@@ -310,6 +310,7 @@ enum sei_payload_type_e
     SEI_USER_DATA_REGISTERED   = 4,
     SEI_USER_DATA_UNREGISTERED = 5,
     SEI_RECOVERY_POINT         = 6,
+    SEI_DEC_REF_PIC_MARKING    = 7,
     SEI_FRAME_PACKING          = 45,
 };
 
@@ -473,6 +474,10 @@ struct x264_t
     /* Slice header */
     x264_slice_header_t sh;
 
+    /* Slice header backup, for SEI_DEC_REF_PIC_MARKING */
+    int b_sh_backup;
+    x264_slice_header_t sh_backup;
+
     /* cabac context */
     x264_cabac_t    cabac;
 
diff --git a/encoder/encoder.c b/encoder/encoder.c
index b0fc7b9..56cbd27 100644
--- a/encoder/encoder.c
+++ b/encoder/encoder.c
@@ -1665,6 +1665,10 @@ static inline void x264_reference_build_list( x264_t *h, int i_poc )
     h->i_ref[0] = X264_MIN( h->i_ref[0], h->frames.i_max_ref0 );
     h->i_ref[0] = X264_MIN( h->i_ref[0], h->param.i_frame_reference ); // if reconfig() has lowered the limit
 
+    /* For Blu-ray compliance, don't reference frames outside of the minigop. */
+    if( IS_X264_TYPE_B( h->fenc->i_type ) && h->param.b_bluray_compat )
+        h->i_ref[0] = X264_MIN( h->i_ref[0], IS_X264_TYPE_B( h->fref[0][0]->i_type ) + 1 );
+
     /* add duplicates */
     if( h->fenc->i_type == X264_TYPE_P )
     {
@@ -1879,6 +1883,12 @@ static inline void x264_slice_init( x264_t *h, int i_nal_type, int i_global_qp )
         }
     }
 
+    if( h->fenc->i_type == X264_TYPE_BREF && h->param.b_bluray_compat && h->sh.i_mmco_command_count )
+    {
+        h->b_sh_backup = 1;
+        h->sh_backup = h->sh;
+    }
+
     h->fdec->i_frame_num = h->sh.i_frame_num;
 
     if( h->sps->i_poc_type == 0 )
@@ -2775,6 +2785,17 @@ int     x264_encoder_encode( x264_t *h,
         overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD - (h->param.b_annexb && h->out.i_nal-1);
     }
 
+    /* As required by Blu-ray. */
+    if( !IS_X264_TYPE_B( h->fenc->i_type ) && h->b_sh_backup )
+    {
+        h->b_sh_backup = 0;
+        x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE );
+        x264_sei_dec_ref_pic_marking_write( h, &h->out.bs );
+        if( x264_nal_end( h ) )
+            return -1;
+        overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD - (h->param.b_annexb && h->out.i_nal-1);
+    }
+
     if( h->fenc->b_keyframe && h->param.b_intra_refresh )
         h->i_cpb_delay_pir_offset = h->fenc->i_cpb_delay;
 
diff --git a/encoder/set.c b/encoder/set.c
index 78f1b56..e7cdf1c 100644
--- a/encoder/set.c
+++ b/encoder/set.c
@@ -551,7 +551,6 @@ void x264_sei_recovery_point_write( x264_t *h, bs_t *s, int recovery_frame_cnt )
     bs_flush( &q );
 
     x264_sei_write( s, tmp_buf, bs_pos( &q ) / 8, SEI_RECOVERY_POINT );
-
 }
 
 int x264_sei_version_write( x264_t *h, bs_t *s )
@@ -689,6 +688,38 @@ void x264_filler_write( x264_t *h, bs_t *s, int filler )
     bs_flush( s );
 }
 
+void x264_sei_dec_ref_pic_marking_write( x264_t *h, bs_t *s )
+{
+    x264_slice_header_t *sh = &h->sh_backup;
+    bs_t q;
+    uint8_t tmp_buf[100];
+    bs_init( &q, tmp_buf, 100 );
+
+    bs_realign( &q );
+
+    /* We currently only use this for repeating B-refs, as required by Blu-ray. */
+    bs_write1( &q, 0 );                 //original_idr_flag
+    bs_write_ue( &q, sh->i_frame_num ); //original_frame_num
+    if( !h->sps->b_frame_mbs_only )
+        bs_write1( &q, 0 );             //original_field_pic_flag
+
+    bs_write1( &q, sh->i_mmco_command_count > 0 );
+    if( sh->i_mmco_command_count > 0 )
+    {
+        for( int i = 0; i < sh->i_mmco_command_count; i++ )
+        {
+            bs_write_ue( &q, 1 );
+            bs_write_ue( &q, sh->mmco[i].i_difference_of_pic_nums - 1 );
+        }
+        bs_write_ue( &q, 0 );
+    }
+
+    bs_align_10( &q );
+    bs_flush( &q );
+
+    x264_sei_write( s, tmp_buf, bs_pos( &q ) / 8, SEI_DEC_REF_PIC_MARKING );
+}
+
 const x264_level_t x264_levels[] =
 {
     { 10,   1485,    99,   152064,     64,    175,  64, 64,  0, 2, 0, 0, 1 },
diff --git a/encoder/set.h b/encoder/set.h
index 7fcca13..4f1eeab 100644
--- a/encoder/set.h
+++ b/encoder/set.h
@@ -36,6 +36,7 @@ int  x264_sei_version_write( x264_t *h, bs_t *s );
 int  x264_validate_levels( x264_t *h, int verbose );
 void x264_sei_buffering_period_write( x264_t *h, bs_t *s );
 void x264_sei_pic_timing_write( x264_t *h, bs_t *s );
+void x264_sei_dec_ref_pic_marking_write( x264_t *h, bs_t *s );
 void x264_sei_frame_packing_write( x264_t *h, bs_t *s );
 void x264_sei_write( bs_t *s, uint8_t *payload, int payload_size, int payload_type );
 void x264_filler_write( x264_t *h, bs_t *s, int filler );



More information about the x264-devel mailing list