hlsdemux: parse cue related tag for AD 22/257522/1 accepted/tizen/unified/20210428.092142 submit/tizen/20210427.071055 submit/tizen/20210428.054922
authorEunhye Choi <eunhae1.choi@samsung.com>
Mon, 26 Apr 2021 10:36:07 +0000 (19:36 +0900)
committerEunhye Choi <eunhae1.choi@samsung.com>
Tue, 27 Apr 2021 06:38:19 +0000 (15:38 +0900)
- parse cue-out, cue-in, cue-out-cont hls tag
  to get AD information

Change-Id: I9b9e4ec3e370418b8cf1310d0aed7afc4cffb79f

ext/hls/gsthlsdemux.c
ext/hls/m3u8.c
ext/hls/m3u8.h
packaging/gst-plugins-bad.spec

index 62f632f..49d640f 100644 (file)
@@ -757,6 +757,17 @@ gst_hls_demux_process_manifest (GstAdaptiveDemux * demux, GstBuffer * buf)
   }
 #endif
 
+#ifdef TIZEN_FEATURE_AD
+  if (variant) {
+    GST_DEBUG_OBJECT (hlsdemux, "post AD info");
+    gst_element_post_message (GST_ELEMENT_CAST (hlsdemux),
+        gst_message_new_element (GST_OBJECT_CAST (hlsdemux),
+            gst_structure_new ("adaptive-ad-info",
+                "ad-info", G_TYPE_POINTER,
+                variant->m3u8->ad_info, NULL)));
+  }
+#endif
+
   /* get the selected media playlist (unless the inital list was one already) */
   if (!hlsdemux->master->is_simple) {
     GError *err = NULL;
index 2ce8281..3830d46 100644 (file)
@@ -52,6 +52,9 @@ gst_m3u8_new (void)
   m3u8->sequence_position = 0;
   m3u8->highest_sequence_number = -1;
   m3u8->duration = GST_CLOCK_TIME_NONE;
+#ifdef TIZEN_FEATURE_AD
+  m3u8->ad_info = g_new0 (GstM3U8AdInfo, 1);
+#endif
 
   g_mutex_init (&m3u8->lock);
   m3u8->ref_count = 1;
@@ -89,6 +92,28 @@ gst_m3u8_set_uri (GstM3U8 * m3u8, const gchar * uri, const gchar * base_uri,
   GST_M3U8_UNLOCK (m3u8);
 }
 
+#ifdef TIZEN_FEATURE_AD
+static GstM3U8Cue *
+gst_m3u8_cue_info_new (GstClockTime start_time, GstClockTime duration)
+{
+  GstM3U8Cue *ad;
+
+  ad = g_new0 (GstM3U8Cue, 1);
+  ad->start_time = start_time;
+  ad->end_time = 0;
+  ad->duration = duration;
+
+  return ad;
+}
+
+void
+gst_m3u8_cue_cont_free (GstM3U8CueOutCont * self)
+{
+  g_return_if_fail (self != NULL);
+  g_free (self->cont_data);
+}
+#endif
+
 GstM3U8 *
 gst_m3u8_ref (GstM3U8 * m3u8)
 {
@@ -111,6 +136,14 @@ gst_m3u8_unref (GstM3U8 * self)
     g_list_foreach (self->files, (GFunc) gst_m3u8_media_file_unref, NULL);
     g_list_free (self->files);
 
+#ifdef TIZEN_FEATURE_AD
+    if (self->ad_info) {
+      g_list_free (self->ad_info->cue);
+      g_list_free_full(self->ad_info->cue_cont, (GFunc) gst_m3u8_cue_cont_free);
+      g_free (self->ad_info);
+    }
+#endif
+
     g_free (self->last_data);
     g_mutex_clear (&self->lock);
     g_free (self);
@@ -462,6 +495,9 @@ gst_m3u8_update (GstM3U8 * self, gchar * data)
   gint64 mediasequence;
   GList *previous_files = NULL;
   gboolean have_mediasequence = FALSE;
+#ifdef TIZEN_FEATURE_AD
+  GstClockTime timestamp = 0;
+#endif
 
   g_return_val_if_fail (self != NULL, FALSE);
   g_return_val_if_fail (data != NULL, FALSE);
@@ -559,7 +595,9 @@ gst_m3u8_update (GstM3U8 * self, gchar * data)
         }
 
         file->discont = discontinuity;
-
+#ifdef TIZEN_FEATURE_AD
+        timestamp += duration;
+#endif
         duration = 0;
         title = NULL;
         discontinuity = FALSE;
@@ -676,7 +714,79 @@ gst_m3u8_update (GstM3U8 * self, gchar * data)
         } else {
           goto next_line;
         }
-      } else {
+      }
+#ifdef TIZEN_FEATURE_AD
+      else if (g_str_has_prefix (data_ext_x, "CUE-OUT:")) {
+        GstM3U8Cue *cue;
+        gdouble fval;
+
+        GST_LOG ("cue out: %" GST_TIME_FORMAT ", %s", GST_TIME_ARGS (timestamp), data);
+
+        data = data + strlen ("#EXT-X-CUE-OUT:");
+        if (!data) {
+          GST_WARNING ("There is no CUE-OUT duration");
+          goto next_line;
+        }
+
+        if (g_str_has_prefix (data, "DURATION="))
+          data = data + strlen ("DURATION=");
+
+        if (!double_from_string (data, &data, &fval)) {
+          GST_WARNING ("Can't read CUE-OUT duration");
+          goto next_line;
+        }
+
+        duration = fval * (gdouble) GST_SECOND;
+
+        cue = gst_m3u8_cue_info_new (timestamp, duration);
+        GST_LOG ("cue out start %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT
+                      , GST_TIME_ARGS (cue->start_time), GST_TIME_ARGS (cue->duration));
+        self->ad_info->cue = g_list_append (self->ad_info->cue, cue);
+        duration = 0;
+      } else if (g_str_has_prefix (data_ext_x, "CUE-IN")) {
+        GList *cue;
+        GstM3U8Cue *cue_data;
+
+        GST_LOG ("cue in: %" GST_TIME_FORMAT ", %s", GST_TIME_ARGS (timestamp), data);
+
+        cue = g_list_last (self->ad_info->cue);
+        if (!cue || !(cue->data)) {
+          GST_WARNING ("there is no valid data");
+          goto next_line;
+        }
+
+        cue_data = cue->data;
+        GST_LOG ("start %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT,
+                GST_TIME_ARGS (cue_data->start_time), GST_TIME_ARGS (cue_data->duration));
+
+        if (cue_data->end_time != 0) {
+          GST_WARNING ("cue syntax err, skip this tag.");
+          goto next_line;
+        }
+
+        cue_data->end_time = timestamp;
+
+        GST_LOG ("cue start %" GST_TIME_FORMAT ", end %" GST_TIME_FORMAT " dur %" GST_TIME_FORMAT,
+                 GST_TIME_ARGS (cue_data->start_time), GST_TIME_ARGS (cue_data->end_time),
+                 GST_TIME_ARGS (cue_data->duration));
+      } else if (g_str_has_prefix (data_ext_x, "CUE-OUT-CONT:")) {
+        GstM3U8CueOutCont *cont = g_new0 (GstM3U8CueOutCont, 1);
+
+        GST_LOG ("cue cont: %" GST_TIME_FORMAT ", %s", GST_TIME_ARGS (timestamp), data);
+
+        data = data + strlen ("#EXT-X-CUE-OUT-CONT:");
+        if (!data) {
+          GST_WARNING ("there is no valid data");
+          g_free (cont);
+          goto next_line;
+        }
+
+        cont->timestamp = timestamp;
+        cont->cont_data = g_strdup (data);
+        self->ad_info->cue_cont = g_list_append (self->ad_info->cue_cont, cont);
+      }
+#endif
+      else {
         GST_LOG ("Ignored line: %s", data);
       }
     } else {
index 0d74f7d..5e3d58f 100644 (file)
@@ -34,6 +34,11 @@ typedef struct _GstHLSMedia GstHLSMedia;
 typedef struct _GstM3U8Client GstM3U8Client;
 typedef struct _GstHLSVariantStream GstHLSVariantStream;
 typedef struct _GstHLSMasterPlaylist GstHLSMasterPlaylist;
+#ifdef TIZEN_FEATURE_AD
+typedef struct _GstM3U8AdInfo GstM3U8AdInfo;
+typedef struct _GstM3U8Cue GstM3U8Cue;
+typedef struct _GstM3U8CueOutCont GstM3U8CueOutCont;
+#endif
 
 #define GST_M3U8(m) ((GstM3U8*)m)
 #define GST_M3U8_MEDIA_FILE(f) ((GstM3U8MediaFile*)f)
@@ -64,6 +69,9 @@ struct _GstM3U8
   gboolean allowcache;          /* last EXT-X-ALLOWCACHE */
 
   GList *files;
+#ifdef TIZEN_FEATURE_AD
+  GstM3U8AdInfo *ad_info;
+#endif
 
   /* state */
   GList *current_file;
@@ -101,6 +109,29 @@ struct _GstM3U8MediaFile
   gint ref_count;               /* ATOMIC */
 };
 
+#ifdef TIZEN_FEATURE_AD
+
+struct _GstM3U8Cue
+{
+  GstClockTime start_time;      /* EXT-X-CUE-OUT */
+  GstClockTime end_time;        /* EXT-X-CUE-IN */
+  GstClockTime duration;        /* from EXT-X-CUE-OUT */
+};
+
+struct _GstM3U8CueOutCont
+{
+  GstClockTime timestamp;
+  gchar *cont_data;             /* EXT-X-CUE-OUT-CONT */
+};
+
+struct _GstM3U8AdInfo
+{
+  GList *cue;                   /* GstM3U8Cue */
+  GList *cue_cont;              /* GstM3U8CueOutCont */
+};
+
+#endif
+
 GstM3U8MediaFile * gst_m3u8_media_file_ref   (GstM3U8MediaFile * mfile);
 
 void               gst_m3u8_media_file_unref (GstM3U8MediaFile * mfile);
index 4cc62d5..a8bad35 100644 (file)
@@ -4,7 +4,7 @@
 
 Name:           gst-plugins-bad
 Version:        1.16.2
-Release:        9
+Release:        10
 Summary:        GStreamer Streaming-Media Framework Plug-Ins
 License:        LGPL-2.0+
 Group:          Multimedia/Framework
@@ -84,7 +84,7 @@ export CFLAGS+=" -Wall -g -fPIC\
   -DTIZEN_FEATURE_OALSINK_MODIFICATION\
   -DTIZEN_FEATURE_MPEGDEMUX_MODIFICATION\
   -DTIZEN_FEATURE_H264PARSE_MODIFICATION\
-  -DTIZEN_FEATURE_UPSTREAM\
+  -DTIZEN_FEATURE_AD\
   -D__TIZEN__\
   -fstack-protector-strong\
   -Wl,-z,relro\