h264parse: forward time codes
authorMathieu Duponchelle <mathieu@centricular.com>
Thu, 28 Mar 2019 21:02:02 +0000 (22:02 +0100)
committerMathieu Duponchelle <mduponchelle1@gmail.com>
Mon, 1 Apr 2019 10:02:33 +0000 (10:02 +0000)
This transforms time codes from the timing SEI into
GstVideoTimeCodeMeta

gst-libs/gst/codecparsers/gsth264parser.h
gst/videoparsers/gsth264parse.c
gst/videoparsers/gsth264parse.h

index 1914470..671b5e5 100644 (file)
@@ -307,6 +307,21 @@ typedef enum
   GST_H264_S_SI_SLICE = 9
 } GstH264SliceType;
 
+/**
+ * GstH264CtType
+ *
+ * Mapping of ct_type to source picture scan
+ *
+ * Since: 1.16
+ */
+
+typedef enum
+{
+  GST_H264_CT_TYPE_PROGRESSIVE = 0,
+  GST_H264_CT_TYPE_INTERLACED = 1,
+  GST_H264_CT_TYPE_UNKNOWN = 2,
+} GstCtType;
+
 typedef struct _GstH264NalParser              GstH264NalParser;
 
 typedef struct _GstH264NalUnit                GstH264NalUnit;
index fe50033..3654516 100644 (file)
@@ -539,14 +539,30 @@ gst_h264_parse_process_sei (GstH264Parse * h264parse, GstH264NalUnit * nalu)
     sei = g_array_index (messages, GstH264SEIMessage, i);
     switch (sei.payloadType) {
       case GST_H264_SEI_PIC_TIMING:
+      {
+        guint j;
         h264parse->sei_pic_struct_pres_flag =
             sei.payload.pic_timing.pic_struct_present_flag;
         h264parse->sei_cpb_removal_delay =
             sei.payload.pic_timing.cpb_removal_delay;
-        if (h264parse->sei_pic_struct_pres_flag)
+        if (h264parse->sei_pic_struct_pres_flag) {
           h264parse->sei_pic_struct = sei.payload.pic_timing.pic_struct;
+        }
+
+        h264parse->num_clock_timestamp = 0;
+
+        for (j = 0; j < 3; j++) {
+          if (sei.payload.pic_timing.clock_timestamp_flag[j]) {
+            memcpy (&h264parse->
+                clock_timestamp[h264parse->num_clock_timestamp++],
+                &sei.payload.pic_timing.clock_timestamp[j],
+                sizeof (GstH264ClockTimestamp));
+          }
+        }
+
         GST_LOG_OBJECT (h264parse, "pic timing updated");
         break;
+      }
       case GST_H264_SEI_BUF_PERIOD:
         if (h264parse->ts_trn_nb == GST_CLOCK_TIME_NONE ||
             h264parse->dts == GST_CLOCK_TIME_NONE)
@@ -1894,15 +1910,20 @@ gst_h264_parse_update_src_caps (GstH264Parse * h264parse, GstCaps * caps)
           "height", G_TYPE_INT, height, NULL);
 
       /* upstream overrides */
-      if (s && gst_structure_has_field (s, "framerate"))
+      if (s && gst_structure_has_field (s, "framerate")) {
         gst_structure_get_fraction (s, "framerate", &fps_num, &fps_den);
+      }
 
       /* but not necessarily or reliably this */
       if (fps_den > 0) {
+        GstStructure *s2;
         gst_caps_set_simple (caps, "framerate",
             GST_TYPE_FRACTION, fps_num, fps_den, NULL);
-        gst_base_parse_set_frame_rate (GST_BASE_PARSE (h264parse),
-            fps_num, fps_den, 0, 0);
+        s2 = gst_caps_get_structure (caps, 0);
+        gst_structure_get_fraction (s2, "framerate", &h264parse->parsed_fps_n,
+            &h264parse->parsed_fps_d);
+        gst_base_parse_set_frame_rate (GST_BASE_PARSE (h264parse), fps_num,
+            fps_den, 0, 0);
         if (fps_num > 0) {
           latency = gst_util_uint64_scale (GST_SECOND, fps_den, fps_num);
           gst_base_parse_set_latency (GST_BASE_PARSE (h264parse), latency,
@@ -2550,6 +2571,68 @@ gst_h264_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
   }
 #endif
 
+  {
+    guint i = 0;
+
+    for (i = 0; i < h264parse->num_clock_timestamp; i++) {
+      GstH264ClockTimestamp *tim = &h264parse->clock_timestamp[i];
+      GstVideoTimeCodeFlags flags = 0;
+      gint field_count = -1;
+
+      /* Table D-1 */
+      switch (h264parse->sei_pic_struct) {
+        case GST_H264_SEI_PIC_STRUCT_FRAME:
+        case GST_H264_SEI_PIC_STRUCT_TOP_FIELD:
+        case GST_H264_SEI_PIC_STRUCT_BOTTOM_FIELD:
+          field_count = h264parse->sei_pic_struct;
+          break;
+        case GST_H264_SEI_PIC_STRUCT_TOP_BOTTOM:
+          field_count = i + 1;
+          break;
+        case GST_H264_SEI_PIC_STRUCT_BOTTOM_TOP:
+          field_count = 2 - i;
+          break;
+        case GST_H264_SEI_PIC_STRUCT_TOP_BOTTOM_TOP:
+          field_count = i % 2 ? 2 : 1;
+          break;
+        case GST_H264_SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM:
+          field_count = i % 2 ? 1 : 2;
+          break;
+        case GST_H264_SEI_PIC_STRUCT_FRAME_DOUBLING:
+        case GST_H264_SEI_PIC_STRUCT_FRAME_TRIPLING:
+          field_count = 0;
+          break;
+      }
+
+      if (field_count == -1) {
+        GST_WARNING_OBJECT (parse,
+            "failed to determine field count for timecode");
+        field_count = 0;
+      }
+
+      /* dropping of the two lowest (value 0 and 1) n_frames
+       * counts when seconds_value is equal to 0 and
+       * minutes_value is not an integer multiple of 10 */
+      if (tim->counting_type == 4)
+        flags |= GST_VIDEO_TIME_CODE_FLAGS_DROP_FRAME;
+
+      if (tim->ct_type == GST_H264_CT_TYPE_INTERLACED)
+        flags |= GST_VIDEO_TIME_CODE_FLAGS_INTERLACED;
+
+      gst_buffer_add_video_time_code_meta_full (buffer,
+          h264parse->parsed_fps_n,
+          h264parse->parsed_fps_d,
+          NULL,
+          flags,
+          tim->hours_flag ? tim->hours_value : 0,
+          tim->minutes_flag ? tim->minutes_value : 0,
+          tim->seconds_flag ? tim->seconds_value : 0,
+          tim->n_frames, field_count);
+    }
+
+    h264parse->num_clock_timestamp = 0;
+  }
+
   gst_h264_parse_reset_frame (h264parse);
 
   return GST_FLOW_OK;
index 61a996d..3d4d8e2 100644 (file)
@@ -59,6 +59,7 @@ struct _GstH264Parse
   gint fps_num, fps_den;
   gint upstream_par_n, upstream_par_d;
   gint parsed_par_n, parsed_par_d;
+  gint parsed_fps_n, parsed_fps_d;
   /* current codec_data in output caps, if any */
   GstBuffer *codec_data;
   /* input codec_data, if any */
@@ -95,6 +96,10 @@ struct _GstH264Parse
   GstBuffer *sps_nals[GST_H264_MAX_SPS_COUNT];
   GstBuffer *pps_nals[GST_H264_MAX_PPS_COUNT];
 
+  /* collected SEI timestamps */
+  guint num_clock_timestamp;
+  GstH264ClockTimestamp clock_timestamp[3];
+
   /* Infos we need to keep track of */
   guint32 sei_cpb_removal_delay;
   guint8 sei_pic_struct;