From a256fa7c7346232c8a850e46ac7876e0b481b67c Mon Sep 17 00:00:00 2001 From: Eunhye Choi Date: Wed, 19 Feb 2025 16:03:48 +0900 Subject: [PATCH] hldemux: parse cue tag to post ad info [Version] 1.24.11-5 parse EXT-T-CUE-OUT, EXT-T-CUE-IN, EXT-T-CUE-OUT-CONT tags to post msg about ad info Change-Id: I79c0c5d164040dfa1d7d619fe66af9b22304ac85 --- packaging/gstreamer.spec | 2 +- .../ext/adaptivedemux2/hls/gsthlsdemux.c | 29 +++-- .../ext/adaptivedemux2/hls/m3u8.c | 100 ++++++++++++++++++ .../ext/adaptivedemux2/hls/m3u8.h | 30 ++++++ subprojects/gst-plugins-good/meson.build | 1 + 5 files changed, 155 insertions(+), 7 deletions(-) diff --git a/packaging/gstreamer.spec b/packaging/gstreamer.spec index 615f6bbb61..cd7c2750cb 100644 --- a/packaging/gstreamer.spec +++ b/packaging/gstreamer.spec @@ -60,7 +60,7 @@ Name: %{_name} Version: 1.24.11 -Release: 4 +Release: 5 Summary: Streaming-Media Framework Runtime License: LGPL-2.0+ Group: Multimedia/Framework diff --git a/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux.c b/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux.c index 113ea625d7..f4d5dea0d3 100644 --- a/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux.c +++ b/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/gsthlsdemux.c @@ -781,6 +781,23 @@ gst_hls_demux_process_initial_manifest (GstAdaptiveDemux * demux, * is available to the baseclass at the start */ gst_hls_demux_update_manifest (demux); +#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, hlsdemux->main_playlist->ad_info, NULL))); + + GST_DEBUG_OBJECT (hlsdemux, "post current bandwidth info : %d", + variant->bandwidth); + gst_element_post_message (GST_ELEMENT_CAST (hlsdemux), + gst_message_new_element (GST_OBJECT_CAST (hlsdemux), + gst_structure_new (GST_ADAPTIVE_DEMUX_STATISTICS_MESSAGE_NAME, + "bitrate", G_TYPE_INT, variant->bandwidth, NULL))); + } +#endif + return TRUE; } @@ -1074,12 +1091,12 @@ gst_hls_demux_update_manifest (GstAdaptiveDemux * demux) gst_hls_media_playlist_ref (hlsdemux->main_stream->playlist); #ifdef TIZEN_FEATURE_POST_VARIANT_INFO - GST_DEBUG_OBJECT (hlsdemux, "post variant info message"); - gst_element_post_message (GST_ELEMENT_CAST (hlsdemux), - gst_message_new_element (GST_OBJECT_CAST (hlsdemux), - gst_structure_new (GST_ADAPTIVE_DEMUX_VARIANT_MESSAGE_NAME, - "video-variant-info", G_TYPE_POINTER, - hlsdemux->master->variant_info, NULL))); + GST_DEBUG_OBJECT (hlsdemux, "post variant info message"); + gst_element_post_message (GST_ELEMENT_CAST (hlsdemux), + gst_message_new_element (GST_OBJECT_CAST (hlsdemux), + gst_structure_new (GST_ADAPTIVE_DEMUX_VARIANT_MESSAGE_NAME, + "video-variant-info", G_TYPE_POINTER, + hlsdemux->master->variant_info, NULL))); #endif return GST_FLOW_OK; diff --git a/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/m3u8.c b/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/m3u8.c index 8a69f46baa..fe9118f6c2 100644 --- a/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/m3u8.c +++ b/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/m3u8.c @@ -47,6 +47,28 @@ static void gst_m3u8_media_segment_fill_partial_stream_times (GstM3U8MediaSegment * segment); +#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 + GstHLSMediaPlaylist * gst_hls_media_playlist_ref (GstHLSMediaPlaylist * m3u8) { @@ -73,6 +95,14 @@ gst_hls_media_playlist_unref (GstHLSMediaPlaylist * self) if (self->removed_date_ranges != NULL) g_strfreev (self->removed_date_ranges); +#ifdef TIZEN_FEATURE_AD + if (self->ad_info) { + g_list_free (self->ad_info->cue); + g_list_free_full(self->ad_info->cue_cont, (GDestroyNotify) gst_m3u8_cue_cont_free); + g_free (self->ad_info); + } +#endif + g_free (self->last_data); g_mutex_clear (&self->lock); g_free (self); @@ -438,6 +468,10 @@ gst_hls_media_playlist_new (const gchar * uri, const gchar * base_uri) m3u8->hold_back = GST_CLOCK_TIME_NONE; m3u8->part_hold_back = 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; @@ -834,6 +868,9 @@ gst_hls_media_playlist_parse (gchar * data, GstM3U8MediaSegment *previous = NULL; GPtrArray *partial_segments = NULL; gboolean is_gap = FALSE; +#ifdef TIZEN_FEATURE_AD + GstClockTime timestamp = 0; +#endif GST_LOG ("playlist ts: %" GST_TIMEP_FORMAT, &playlist_ts); GST_LOG ("uri: %s", uri); @@ -935,6 +972,10 @@ gst_hls_media_playlist_parse (gchar * data, if (last_init_file) file->init_file = gst_m3u8_init_file_ref (last_init_file); +#ifdef TIZEN_FEATURE_AD + timestamp += duration; +#endif + file->partial_segments = partial_segments; partial_segments = NULL; @@ -1162,6 +1203,65 @@ gst_hls_media_playlist_parse (gchar * data, /* Increment the current MSN by the number * of segments that were removed */ mediasequence += self->skipped_segments; +#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 (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 error, 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:"); + 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); } diff --git a/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/m3u8.h b/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/m3u8.h index 9216fc04b2..662271378e 100644 --- a/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/m3u8.h +++ b/subprojects/gst-plugins-good/ext/adaptivedemux2/hls/m3u8.h @@ -48,6 +48,11 @@ typedef struct _GstHLSRenditionStream GstHLSRenditionStream; 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_HLS_MEDIA_PLAYLIST(m) ((GstHLSMediaPlaylist*)m) #define GST_M3U8_MEDIA_SEGMENT(f) ((GstM3U8MediaSegment*)f) @@ -152,6 +157,10 @@ struct _GstHLSMediaPlaylist gint num_removed_date_ranges; gchar **removed_date_ranges; +#ifdef TIZEN_FEATURE_AD + GstM3U8AdInfo *ad_info; +#endif + /*< private > */ GMutex lock; @@ -268,6 +277,27 @@ struct _GstM3U8InitFile guint 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 + GstM3U8InitFile *gst_m3u8_init_file_ref (GstM3U8InitFile * ifile); void gst_m3u8_init_file_unref (GstM3U8InitFile * ifile); gboolean gst_m3u8_init_file_equal (const GstM3U8InitFile * ifile1, const GstM3U8InitFile *ifile2); diff --git a/subprojects/gst-plugins-good/meson.build b/subprojects/gst-plugins-good/meson.build index db7e1d849c..1a6b6c3a46 100644 --- a/subprojects/gst-plugins-good/meson.build +++ b/subprojects/gst-plugins-good/meson.build @@ -477,6 +477,7 @@ cdata.set('TIZEN_FEATURE_GST_MUX_ENHANCEMENT', true) cdata.set('TIZEN_FEATURE_V4L2_DISABLE_COLORIMETRY', true) cdata.set('TIZEN_FEATURE_POST_VARIANT_INFO', true) cdata.set('TIZEN_FEATURE_ADAPTIVE_VARIANT_LIMIT', true) +cdata.set('TIZEN_FEATURE_AD', true) cdata.set('TIZEN_FEATURE_BUG_FIX', true) cdata.set('TIZEN_FEATURE_V4L2_ENCODER_SET_MAX_LEVEL', true) cdata.set('TIZEN_FEATURE_RTPH264PAY_MODIFICATION', true) -- 2.34.1