h265parse: add support for SEI registered user data
authorAaron Boxer <aaron.boxer@collabora.com>
Wed, 8 May 2019 15:06:40 +0000 (11:06 -0400)
committerAaron Boxer <aaron.boxer@collabora.com>
Mon, 26 Aug 2019 22:14:17 +0000 (18:14 -0400)
gst-libs/gst/codecparsers/gsth265parser.c
gst-libs/gst/codecparsers/gsth265parser.h
gst/videoparsers/gsth265parse.c
gst/videoparsers/gsth265parse.h

index df8e99d..f0bd108 100644 (file)
@@ -1132,6 +1132,53 @@ error:
   return GST_H265_PARSER_ERROR;
 }
 
+
+static GstH265ParserResult
+gst_h265_parser_parse_registered_user_data (GstH265Parser * parser,
+    GstH265RegisteredUserData * rud, NalReader * nr, guint payload_size)
+{
+  guint8 *data = NULL;
+  guint i;
+
+  rud->data = NULL;
+  rud->size = 0;
+
+  if (payload_size < 2)
+    return GST_H265_PARSER_ERROR;
+
+  READ_UINT8 (nr, rud->country_code, 8);
+  --payload_size;
+
+  if (rud->country_code == 0xFF) {
+    READ_UINT8 (nr, rud->country_code_extension, 8);
+    --payload_size;
+  } else {
+    rud->country_code_extension = 0;
+  }
+
+  if (payload_size < 8)
+    return GST_H265_PARSER_ERROR;
+
+  data = g_malloc (payload_size);
+  for (i = 0; i < payload_size / 8; ++i) {
+    READ_UINT8 (nr, data[i], 8);
+  }
+
+  GST_MEMDUMP ("SEI user data", data, payload_size / 8);
+
+  rud->data = data;
+  rud->size = payload_size;
+  return GST_H265_PARSER_OK;
+
+error:
+  {
+    GST_WARNING ("error parsing \"Registered User Data\"");
+    g_free (data);
+    return GST_H265_PARSER_ERROR;
+  }
+}
+
+
 static GstH265ParserResult
 gst_h265_parser_parse_time_code (GstH265Parser * parser,
     GstH265TimeCode * tc, NalReader * nr)
@@ -2472,6 +2519,10 @@ gst_h265_parser_parse_sei_message (GstH265Parser * parser,
         res = gst_h265_parser_parse_pic_timing (parser,
             &sei->payload.pic_timing, nr);
         break;
+      case GST_H265_SEI_REGISTERED_USER_DATA:
+        res = gst_h265_parser_parse_registered_user_data (parser,
+            &sei->payload.registered_user_data, nr, payloadSizeBytes);
+        break;
       case GST_H265_SEI_RECOVERY_POINT:
         res = gst_h265_parser_parse_recovery_point (parser,
             &sei->payload.recovery_point, nr);
index dab28eb..27b529b 100644 (file)
@@ -271,6 +271,7 @@ typedef enum
  * GstH265SEIPayloadType:
  * @GST_H265_SEI_BUF_PERIOD: Buffering Period SEI Message
  * @GST_H265_SEI_PIC_TIMING: Picture Timing SEI Message
+ * @GST_H265_SEI_REGISTERED_USER_DATA: Registered user data (D.2.5)
  * @GST_H265_SEI_RECOVERY_POINT: Recovery Point SEI Message (D.3.8)
  * @GST_H265_SEI_TIME_CODE: Time code SEI message (D.2.27) (Since: 1.16)
  * @GST_H265_SEI_MASTERING_DISPLAY_COLOUR_VOLUME: Mastering display colour volume information SEI message (D.2.28) (Since: 1.18)
@@ -283,6 +284,7 @@ typedef enum
 {
   GST_H265_SEI_BUF_PERIOD = 0,
   GST_H265_SEI_PIC_TIMING = 1,
+  GST_H265_SEI_REGISTERED_USER_DATA = 4,
   GST_H265_SEI_RECOVERY_POINT = 6,
   GST_H265_SEI_TIME_CODE = 136,
   GST_H265_SEI_MASTERING_DISPLAY_COLOUR_VOLUME = 137,
@@ -373,6 +375,7 @@ typedef struct _GstH265ShortTermRefPicSet       GstH265ShortTermRefPicSet;
 typedef struct _GstH265SliceHdr                 GstH265SliceHdr;
 
 typedef struct _GstH265PicTiming                GstH265PicTiming;
+typedef struct _GstH265RegisteredUserData      GstH265RegisteredUserData;
 typedef struct _GstH265BufferingPeriod          GstH265BufferingPeriod;
 typedef struct _GstH265RecoveryPoint            GstH265RecoveryPoint;
 typedef struct _GstH265TimeCode                 GstH265TimeCode;
@@ -1226,6 +1229,15 @@ struct _GstH265RecoveryPoint
   guint8 broken_link_flag;
 };
 
+struct _GstH265RegisteredUserData
+{
+  guint8 country_code;
+  guint8 country_code_extension;
+  const guint8 *data;
+  guint size;
+};
+
+
 /**
  * GstH265TimeCode:
  * The time code SEI message provides time code information similar to that
@@ -1297,6 +1309,7 @@ struct _GstH265SEIMessage
   union {
     GstH265BufferingPeriod buffering_period;
     GstH265PicTiming pic_timing;
+    GstH265RegisteredUserData registered_user_data;
     GstH265RecoveryPoint recovery_point;
     GstH265TimeCode time_code;
     GstH265MasteringDisplayColourVolume mastering_display_colour_volume;
index 909955c..75c2567 100644 (file)
@@ -114,6 +114,9 @@ static GstCaps *gst_h265_parse_get_caps (GstBaseParse * parse,
 static gboolean gst_h265_parse_event (GstBaseParse * parse, GstEvent * event);
 static gboolean gst_h265_parse_src_event (GstBaseParse * parse,
     GstEvent * event);
+static void
+gst_h265_parse_process_sei_user_data (GstH265Parse * h265parse,
+    GstH265RegisteredUserData * rud);
 
 static void
 gst_h265_parse_class_init (GstH265ParseClass * klass)
@@ -570,6 +573,10 @@ gst_h265_parse_process_sei (GstH265Parse * h265parse, GstH265NalUnit * nalu)
       case GST_H265_SEI_PIC_TIMING:
         h265parse->sei_pic_struct = sei.payload.pic_timing.pic_struct;
         break;
+      case GST_H265_SEI_REGISTERED_USER_DATA:
+        gst_h265_parse_process_sei_user_data (h265parse,
+            &sei.payload.registered_user_data);
+        break;
       case GST_H265_SEI_BUF_PERIOD:
         /* FIXME */
         break;
@@ -672,6 +679,39 @@ gst_h265_parse_process_sei (GstH265Parse * h265parse, GstH265NalUnit * nalu)
   g_array_free (messages, TRUE);
 }
 
+static void
+gst_h265_parse_process_sei_user_data (GstH265Parse * h265parse,
+    GstH265RegisteredUserData * rud)
+{
+  guint16 provider_code;
+  GstByteReader br;
+  GstVideoParseUtilsField field = GST_VIDEO_PARSE_UTILS_FIELD_1;
+
+  /* only US country code is currently supported */
+  switch (rud->country_code) {
+    case ITU_T_T35_COUNTRY_CODE_US:
+      break;
+    default:
+      GST_LOG_OBJECT (h265parse, "Unsupported country code %d",
+          rud->country_code);
+      return;
+  }
+
+  if (rud->data == NULL || rud->size < 2)
+    return;
+
+  gst_byte_reader_init (&br, rud->data, rud->size);
+
+  provider_code = gst_byte_reader_get_uint16_be_unchecked (&br);
+
+  if (h265parse->sei_pic_struct ==
+      (guint8) GST_H265_SEI_PIC_STRUCT_BOTTOM_FIELD)
+    field = GST_VIDEO_PARSE_UTILS_FIELD_1;
+  gst_video_parse_user_data ((GstElement *) h265parse, &h265parse->user_data,
+      &br, field, provider_code);
+
+}
+
 /* caller guarantees 2 bytes of nal payload */
 static gboolean
 gst_h265_parse_process_nal (GstH265Parse * h265parse, GstH265NalUnit * nalu)
@@ -2565,6 +2605,7 @@ gst_h265_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
   GstH265Parse *h265parse;
   GstBuffer *buffer;
   GstEvent *event;
+  GstBuffer *parse_buffer = NULL;
 
   h265parse = GST_H265_PARSE (parse);
 
@@ -2671,9 +2712,9 @@ gst_h265_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
     guint i = 0;
 
     for (i = 0; i < h265parse->time_code.num_clock_ts; i++) {
-      GstVideoTimeCodeFlags flags = 0;
       gint field_count = -1;
       guint n_frames;
+      GstVideoTimeCodeFlags flags = 0;
 
       if (!h265parse->time_code.clock_timestamp_flag[i])
         break;
@@ -2742,6 +2783,22 @@ gst_h265_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
     }
   }
 
+  if (frame->out_buffer) {
+    parse_buffer = frame->out_buffer =
+        gst_buffer_make_writable (frame->out_buffer);
+  } else {
+    parse_buffer = frame->buffer = gst_buffer_make_writable (frame->buffer);
+  }
+
+  if (h265parse->sei_pic_struct != GST_H265_SEI_PIC_STRUCT_FRAME) {
+    GST_BUFFER_FLAG_SET (parse_buffer, GST_VIDEO_BUFFER_FLAG_INTERLACED);
+    if (h265parse->sei_pic_struct == GST_H265_SEI_PIC_STRUCT_TOP_FIELD)
+      GST_BUFFER_FLAG_SET (parse_buffer, GST_VIDEO_BUFFER_FLAG_TFF);
+  }
+
+  gst_video_push_user_data ((GstElement *) h265parse, &h265parse->user_data,
+      parse_buffer);
+
   gst_h265_parse_reset_frame (h265parse);
 
   return GST_FLOW_OK;
index 0af1528..40f0682 100644 (file)
@@ -25,6 +25,7 @@
 #include <gst/base/gstbaseparse.h>
 #include <gst/codecparsers/gsth265parser.h>
 #include <gst/video/video.h>
+#include "gstvideoparseutils.h"
 
 G_BEGIN_DECLS
 
@@ -108,6 +109,8 @@ struct _GstH265Parse
   /* AU state */
   gboolean picture_start;
 
+  GstVideoParseUserData user_data;
+
   /* props */
   gint interval;