From ddcea02d481cc7049634b9cf966a591fa0eee492 Mon Sep 17 00:00:00 2001 From: Eunhye Choi Date: Mon, 26 Apr 2021 19:36:07 +0900 Subject: [PATCH] hlsdemux: parse cue related tag for AD - parse cue-out, cue-in, cue-out-cont hls tag to get AD information Change-Id: I9b9e4ec3e370418b8cf1310d0aed7afc4cffb79f --- ext/hls/gsthlsdemux.c | 11 ++++ ext/hls/m3u8.c | 114 ++++++++++++++++++++++++++++++++++++++++- ext/hls/m3u8.h | 31 +++++++++++ packaging/gst-plugins-bad.spec | 4 +- 4 files changed, 156 insertions(+), 4 deletions(-) diff --git a/ext/hls/gsthlsdemux.c b/ext/hls/gsthlsdemux.c index 62f632f..49d640f 100644 --- a/ext/hls/gsthlsdemux.c +++ b/ext/hls/gsthlsdemux.c @@ -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; diff --git a/ext/hls/m3u8.c b/ext/hls/m3u8.c index 2ce8281..3830d46 100644 --- a/ext/hls/m3u8.c +++ b/ext/hls/m3u8.c @@ -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 { diff --git a/ext/hls/m3u8.h b/ext/hls/m3u8.h index 0d74f7d..5e3d58f 100644 --- a/ext/hls/m3u8.h +++ b/ext/hls/m3u8.h @@ -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); diff --git a/packaging/gst-plugins-bad.spec b/packaging/gst-plugins-bad.spec index 4cc62d5..a8bad35 100644 --- a/packaging/gst-plugins-bad.spec +++ b/packaging/gst-plugins-bad.spec @@ -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\ -- 2.7.4