changeset 8107:e61f76efc9f3 libavcodec

h264: Implement decoding of picture timing SEI message. Now correct values are propagated to interlaced_frame, top_field_first and repeat_pict in AVFrame structure. patch by ffdshow tryouts
author andoma
date Tue, 04 Nov 2008 18:31:48 +0000
parents 2f5101a67500
children 5de6db4225d6
files h264.c h264.h h264data.h
diffstat 3 files changed, 144 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/h264.c	Tue Nov 04 06:54:42 2008 +0000
+++ b/h264.c	Tue Nov 04 18:31:48 2008 +0000
@@ -6803,6 +6803,53 @@
     return -1; //not reached
 }
 
+static int decode_picture_timing(H264Context *h){
+    MpegEncContext * const s = &h->s;
+    if(h->sps.nal_hrd_parameters_present_flag || h->sps.vcl_hrd_parameters_present_flag){
+        skip_bits(&s->gb, h->sps.cpb_removal_delay_length); /* cpb_removal_delay */
+        skip_bits(&s->gb, h->sps.dpb_output_delay_length);  /* dpb_output_delay */
+    }
+    if(h->sps.pic_struct_present_flag){
+        unsigned int i, num_clock_ts;
+        h->sei_pic_struct = get_bits(&s->gb, 4);
+
+        if (h->sei_pic_struct > SEI_PIC_STRUCT_FRAME_TRIPLING)
+            return -1;
+
+        num_clock_ts = sei_num_clock_ts_table[h->sei_pic_struct];
+
+        for (i = 0 ; i < num_clock_ts ; i++){
+            if(get_bits(&s->gb, 1)){                  /* clock_timestamp_flag */
+                unsigned int full_timestamp_flag;
+                skip_bits(&s->gb, 2);                 /* ct_type */
+                skip_bits(&s->gb, 1);                 /* nuit_field_based_flag */
+                skip_bits(&s->gb, 5);                 /* counting_type */
+                full_timestamp_flag = get_bits(&s->gb, 1);
+                skip_bits(&s->gb, 1);                 /* discontinuity_flag */
+                skip_bits(&s->gb, 1);                 /* cnt_dropped_flag */
+                skip_bits(&s->gb, 8);                 /* n_frames */
+                if(full_timestamp_flag){
+                    skip_bits(&s->gb, 6);             /* seconds_value 0..59 */
+                    skip_bits(&s->gb, 6);             /* minutes_value 0..59 */
+                    skip_bits(&s->gb, 5);             /* hours_value 0..23 */
+                }else{
+                    if(get_bits(&s->gb, 1)){          /* seconds_flag */
+                        skip_bits(&s->gb, 6);         /* seconds_value range 0..59 */
+                        if(get_bits(&s->gb, 1)){      /* minutes_flag */
+                            skip_bits(&s->gb, 6);     /* minutes_value 0..59 */
+                            if(get_bits(&s->gb, 1))   /* hours_flag */
+                                skip_bits(&s->gb, 5); /* hours_value 0..23 */
+                        }
+                    }
+                }
+                if(h->sps.time_offset_length > 0)
+                    skip_bits(&s->gb, h->sps.time_offset_length); /* time_offset */
+            }
+        }
+    }
+    return 0;
+}
+
 static int decode_unregistered_user_data(H264Context *h, int size){
     MpegEncContext * const s = &h->s;
     uint8_t user_data[16+256];
@@ -6846,6 +6893,10 @@
         }while(get_bits(&s->gb, 8) == 255);
 
         switch(type){
+        case 1: // Picture timing SEI
+            if(decode_picture_timing(h) < 0)
+                return -1;
+            break;
         case 5:
             if(decode_unregistered_user_data(h, size) < 0)
                 return -1;
@@ -6873,16 +6924,15 @@
         get_bits1(&s->gb);     /* cbr_flag */
     }
     get_bits(&s->gb, 5); /* initial_cpb_removal_delay_length_minus1 */
-    get_bits(&s->gb, 5); /* cpb_removal_delay_length_minus1 */
-    get_bits(&s->gb, 5); /* dpb_output_delay_length_minus1 */
-    get_bits(&s->gb, 5); /* time_offset_length */
+    sps->cpb_removal_delay_length = get_bits(&s->gb, 5) + 1;
+    sps->dpb_output_delay_length = get_bits(&s->gb, 5) + 1;
+    sps->time_offset_length = get_bits(&s->gb, 5);
 }
 
 static inline int decode_vui_parameters(H264Context *h, SPS *sps){
     MpegEncContext * const s = &h->s;
     int aspect_ratio_info_present_flag;
     unsigned int aspect_ratio_idc;
-    int nal_hrd_parameters_present_flag, vcl_hrd_parameters_present_flag;
 
     aspect_ratio_info_present_flag= get_bits1(&s->gb);
 
@@ -6929,15 +6979,15 @@
         sps->fixed_frame_rate_flag = get_bits1(&s->gb);
     }
 
-    nal_hrd_parameters_present_flag = get_bits1(&s->gb);
-    if(nal_hrd_parameters_present_flag)
+    sps->nal_hrd_parameters_present_flag = get_bits1(&s->gb);
+    if(sps->nal_hrd_parameters_present_flag)
         decode_hrd_parameters(h, sps);
-    vcl_hrd_parameters_present_flag = get_bits1(&s->gb);
-    if(vcl_hrd_parameters_present_flag)
+    sps->vcl_hrd_parameters_present_flag = get_bits1(&s->gb);
+    if(sps->vcl_hrd_parameters_present_flag)
         decode_hrd_parameters(h, sps);
-    if(nal_hrd_parameters_present_flag || vcl_hrd_parameters_present_flag)
+    if(sps->nal_hrd_parameters_present_flag || sps->vcl_hrd_parameters_present_flag)
         get_bits1(&s->gb);     /* low_delay_hrd_flag */
-    get_bits1(&s->gb);         /* pic_struct_present_flag */
+    sps->pic_struct_present_flag = get_bits1(&s->gb);
 
     sps->bitstream_restriction_flag = get_bits1(&s->gb);
     if(sps->bitstream_restriction_flag){
@@ -7639,9 +7689,60 @@
             *data_size = 0;
 
         } else {
-            cur->interlaced_frame = FIELD_OR_MBAFF_PICTURE;
-            /* Derive top_field_first from field pocs. */
-            cur->top_field_first = cur->field_poc[0] < cur->field_poc[1];
+            cur->repeat_pict = 0;
+
+            /* Signal interlacing information externally. */
+            /* Prioritize picture timing SEI information over used decoding process if it exists. */
+            if(h->sps.pic_struct_present_flag){
+                switch (h->sei_pic_struct)
+                {
+                case SEI_PIC_STRUCT_FRAME:
+                    cur->interlaced_frame = 0;
+                    break;
+                case SEI_PIC_STRUCT_TOP_FIELD:
+                case SEI_PIC_STRUCT_BOTTOM_FIELD:
+                case SEI_PIC_STRUCT_TOP_BOTTOM:
+                case SEI_PIC_STRUCT_BOTTOM_TOP:
+                    cur->interlaced_frame = 1;
+                    break;
+                case SEI_PIC_STRUCT_TOP_BOTTOM_TOP:
+                case SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM:
+                    // Signal the possibility of telecined film externally (pic_struct 5,6)
+                    // From these hints, let the applications decide if they apply deinterlacing.
+                    cur->repeat_pict = 1;
+                    cur->interlaced_frame = FIELD_OR_MBAFF_PICTURE;
+                    break;
+                case SEI_PIC_STRUCT_FRAME_DOUBLING:
+                    // Force progressive here, as doubling interlaced frame is a bad idea.
+                    cur->interlaced_frame = 0;
+                    cur->repeat_pict = 2;
+                    break;
+                case SEI_PIC_STRUCT_FRAME_TRIPLING:
+                    cur->interlaced_frame = 0;
+                    cur->repeat_pict = 4;
+                    break;
+                }
+            }else{
+                /* Derive interlacing flag from used decoding process. */
+                cur->interlaced_frame = FIELD_OR_MBAFF_PICTURE;
+            }
+
+            if (cur->field_poc[0] != cur->field_poc[1]){
+                /* Derive top_field_first from field pocs. */
+                cur->top_field_first = cur->field_poc[0] < cur->field_poc[1];
+            }else{
+                if(cur->interlaced_frame || h->sps.pic_struct_present_flag){
+                    /* Use picture timing SEI information. Even if it is a information of a past frame, better than nothing. */
+                    if(h->sei_pic_struct == SEI_PIC_STRUCT_TOP_BOTTOM
+                      || h->sei_pic_struct == SEI_PIC_STRUCT_TOP_BOTTOM_TOP)
+                        cur->top_field_first = 1;
+                    else
+                        cur->top_field_first = 0;
+                }else{
+                    /* Most likely progressive */
+                    cur->top_field_first = 0;
+                }
+            }
 
         //FIXME do something with unavailable reference frames
 
--- a/h264.h	Tue Nov 04 06:54:42 2008 +0000
+++ b/h264.h	Tue Nov 04 18:31:48 2008 +0000
@@ -111,6 +111,21 @@
 };
 
 /**
+ * pic_struct in picture timing SEI message
+ */
+typedef enum {
+    SEI_PIC_STRUCT_FRAME             = 0, ///<  0: %frame
+    SEI_PIC_STRUCT_TOP_FIELD         = 1, ///<  1: top field
+    SEI_PIC_STRUCT_BOTTOM_FIELD      = 2, ///<  2: bottom field
+    SEI_PIC_STRUCT_TOP_BOTTOM        = 3, ///<  3: top field, bottom field, in that order
+    SEI_PIC_STRUCT_BOTTOM_TOP        = 4, ///<  4: bottom field, top field, in that order
+    SEI_PIC_STRUCT_TOP_BOTTOM_TOP    = 5, ///<  5: top field, bottom field, top field repeated, in that order
+    SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM = 6, ///<  6: bottom field, top field, bottom field repeated, in that order
+    SEI_PIC_STRUCT_FRAME_DOUBLING    = 7, ///<  7: %frame doubling
+    SEI_PIC_STRUCT_FRAME_TRIPLING    = 8  ///<  8: %frame tripling
+} SEI_PicStructType;
+
+/**
  * Sequence parameter set
  */
 typedef struct SPS{
@@ -150,6 +165,12 @@
     int scaling_matrix_present;
     uint8_t scaling_matrix4[6][16];
     uint8_t scaling_matrix8[2][64];
+    int nal_hrd_parameters_present_flag;
+    int vcl_hrd_parameters_present_flag;
+    int pic_struct_present_flag;
+    int time_offset_length;
+    int cpb_removal_delay_length;      ///< cpb_removal_delay_length_minus1 + 1
+    int dpb_output_delay_length;       ///< dpb_output_delay_length_minus1 + 1
 }SPS;
 
 /**
@@ -460,6 +481,11 @@
     int mb_xy;
 
     uint32_t svq3_watermark_key;
+
+    /**
+     * pic_struct in picture timing SEI message
+     */
+    SEI_PicStructType sei_pic_struct;
 }H264Context;
 
 #endif /* AVCODEC_H264_H */
--- a/h264data.h	Tue Nov 04 06:54:42 2008 +0000
+++ b/h264data.h	Tue Nov 04 18:31:48 2008 +0000
@@ -1296,4 +1296,8 @@
     }
 };
 
+static const uint8_t sei_num_clock_ts_table[9]={
+    1,  1,  1,  2,  2,  3,  3,  2,  3
+};
+
 #endif /* AVCODEC_H264DATA_H */