3 * Copyright (C) 2014 Samsung Electronics. All rights reserved.
4 * Author: Thiago Santos <thiagoss@osg.samsung.com>
5 * Copyright (C) 2021-2022 Jan Schmidt <jan@centricular.com>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
28 #include <gst/pbutils/pbutils.h>
30 #include "gstadaptivedemuxutils.h"
32 GST_DEBUG_CATEGORY_EXTERN (adaptivedemux2_debug);
33 #define GST_CAT_DEFAULT adaptivedemux2_debug
35 struct _GstAdaptiveDemuxClock
40 GstClockTimeDiff clock_offset; /* offset between realtime_clock and UTC */
43 struct _GstAdaptiveDemuxLoop
49 GRecMutex context_lock;
53 GMainContext *context;
59 GstAdaptiveDemuxClock *
60 gst_adaptive_demux_clock_new (void)
62 GstAdaptiveDemuxClock *clock = g_slice_new (GstAdaptiveDemuxClock);
63 GstClockType clock_type = GST_CLOCK_TYPE_OTHER;
64 GObjectClass *gobject_class;
66 g_atomic_int_set (&clock->ref_count, 1);
68 clock->gst_clock = gst_system_clock_obtain ();
69 g_assert (clock->gst_clock != NULL);
71 gobject_class = G_OBJECT_GET_CLASS (clock->gst_clock);
72 if (g_object_class_find_property (gobject_class, "clock-type")) {
73 g_object_get (clock->gst_clock, "clock-type", &clock_type, NULL);
75 GST_WARNING ("System clock does not have clock-type property");
78 if (clock_type == GST_CLOCK_TYPE_REALTIME) {
79 clock->clock_offset = 0;
83 utc_now = g_date_time_new_now_utc ();
84 gst_adaptive_demux_clock_set_utc_time (clock, utc_now);
85 g_date_time_unref (utc_now);
91 GstAdaptiveDemuxClock *
92 gst_adaptive_demux_clock_ref (GstAdaptiveDemuxClock * clock)
94 g_return_val_if_fail (clock != NULL, NULL);
95 g_atomic_int_inc (&clock->ref_count);
100 gst_adaptive_demux_clock_unref (GstAdaptiveDemuxClock * clock)
102 g_return_if_fail (clock != NULL);
103 if (g_atomic_int_dec_and_test (&clock->ref_count)) {
104 gst_object_unref (clock->gst_clock);
105 g_slice_free (GstAdaptiveDemuxClock, clock);
110 gst_adaptive_demux_clock_get_time (GstAdaptiveDemuxClock * clock)
112 g_return_val_if_fail (clock != NULL, GST_CLOCK_TIME_NONE);
113 return gst_clock_get_time (clock->gst_clock);
117 gst_adaptive_demux_clock_get_now_utc (GstAdaptiveDemuxClock * clock)
119 GstClockTime rtc_now;
120 GDateTime *unix_datetime;
121 GDateTime *result_datetime;
122 gint64 utc_now_in_us;
124 rtc_now = gst_clock_get_time (clock->gst_clock);
125 utc_now_in_us = clock->clock_offset + GST_TIME_AS_USECONDS (rtc_now);
127 g_date_time_new_from_unix_utc (utc_now_in_us / G_TIME_SPAN_SECOND);
129 g_date_time_add (unix_datetime, utc_now_in_us % G_TIME_SPAN_SECOND);
130 g_date_time_unref (unix_datetime);
131 return result_datetime;
135 gst_adaptive_demux_clock_set_utc_time (GstAdaptiveDemuxClock * clock,
138 GstClockTime rtc_now = gst_clock_get_time (clock->gst_clock);
139 GstClockTimeDiff clock_offset;
142 g_date_time_to_unix (utc_now) * G_TIME_SPAN_SECOND +
143 g_date_time_get_microsecond (utc_now) - GST_TIME_AS_USECONDS (rtc_now);
145 GST_INFO ("Changing UTC clock offset to %" GST_STIME_FORMAT
146 " was %" GST_STIME_FORMAT, GST_STIME_ARGS (clock_offset),
147 GST_STIME_ARGS (clock->clock_offset));
149 clock->clock_offset = clock_offset;
152 GstAdaptiveDemuxLoop *
153 gst_adaptive_demux_loop_new (void)
155 GstAdaptiveDemuxLoop *loop = g_slice_new0 (GstAdaptiveDemuxLoop);
156 g_atomic_int_set (&loop->ref_count, 1);
158 g_mutex_init (&loop->lock);
159 g_rec_mutex_init (&loop->context_lock);
160 g_cond_init (&loop->cond);
162 loop->stopped = TRUE;
163 loop->paused = FALSE;
168 GstAdaptiveDemuxLoop *
169 gst_adaptive_demux_loop_ref (GstAdaptiveDemuxLoop * loop)
171 g_return_val_if_fail (loop != NULL, NULL);
172 g_atomic_int_inc (&loop->ref_count);
177 gst_adaptive_demux_loop_unref (GstAdaptiveDemuxLoop * loop)
179 g_return_if_fail (loop != NULL);
180 if (g_atomic_int_dec_and_test (&loop->ref_count)) {
181 gst_adaptive_demux_loop_stop (loop, TRUE);
183 g_mutex_clear (&loop->lock);
184 g_rec_mutex_clear (&loop->context_lock);
185 g_cond_clear (&loop->cond);
187 g_slice_free (GstAdaptiveDemuxLoop, loop);
192 _gst_adaptive_demux_loop_thread (GstAdaptiveDemuxLoop * loop)
194 g_mutex_lock (&loop->lock);
196 loop->loop = g_main_loop_new (loop->context, FALSE);
198 while (!loop->stopped) {
199 g_mutex_unlock (&loop->lock);
201 g_rec_mutex_lock (&loop->context_lock);
203 g_main_context_push_thread_default (loop->context);
204 g_main_loop_run (loop->loop);
205 g_main_context_pop_thread_default (loop->context);
207 g_rec_mutex_unlock (&loop->context_lock);
209 g_mutex_lock (&loop->lock);
211 g_cond_wait (&loop->cond, &loop->lock);
214 g_main_loop_unref (loop->loop);
217 g_cond_broadcast (&loop->cond);
218 g_mutex_unlock (&loop->lock);
220 g_main_context_unref (loop->context);
221 loop->context = NULL;
223 gst_adaptive_demux_loop_unref (loop);
229 gst_adaptive_demux_loop_start (GstAdaptiveDemuxLoop * loop)
231 g_mutex_lock (&loop->lock);
232 if (loop->thread != NULL)
233 goto done; /* Already running */
235 loop->stopped = FALSE;
236 loop->context = g_main_context_new ();
239 g_thread_new ("AdaptiveDemux",
240 (GThreadFunc) _gst_adaptive_demux_loop_thread,
241 gst_adaptive_demux_loop_ref (loop));
244 g_mutex_unlock (&loop->lock);
248 do_quit_cb (GstAdaptiveDemuxLoop * loop)
250 g_main_loop_quit (loop->loop);
251 return G_SOURCE_REMOVE;
255 gst_adaptive_demux_loop_stop (GstAdaptiveDemuxLoop * loop, gboolean wait)
257 g_mutex_lock (&loop->lock);
259 if (!loop->stopped) {
260 loop->stopped = TRUE;
262 GSource *s = g_idle_source_new ();
263 g_source_set_callback (s, (GSourceFunc) do_quit_cb,
264 gst_adaptive_demux_loop_ref (loop),
265 (GDestroyNotify) gst_adaptive_demux_loop_unref);
266 g_source_attach (s, loop->context);
270 while (loop->loop != NULL)
271 g_cond_wait (&loop->cond, &loop->lock);
274 if (loop->thread != NULL) {
275 g_thread_unref (loop->thread);
280 g_mutex_unlock (&loop->lock);
284 gst_adaptive_demux_loop_pause_and_lock (GstAdaptiveDemuxLoop * loop)
286 /* Try and acquire the context lock directly. This will succeed
287 * if called when the loop is not running, and we can avoid
288 * adding an unnecessary extra idle source to quit the loop. */
289 if (!g_rec_mutex_trylock (&loop->context_lock)) {
290 g_mutex_lock (&loop->lock);
293 g_mutex_unlock (&loop->lock);
300 GSource *s = g_idle_source_new ();
301 g_source_set_callback (s, (GSourceFunc) do_quit_cb,
302 gst_adaptive_demux_loop_ref (loop),
303 (GDestroyNotify) gst_adaptive_demux_loop_unref);
304 g_source_attach (s, loop->context);
308 g_mutex_unlock (&loop->lock);
310 g_rec_mutex_lock (&loop->context_lock);
312 g_main_context_push_thread_default (loop->context);
318 gst_adaptive_demux_loop_unlock_and_unpause (GstAdaptiveDemuxLoop * loop)
320 g_main_context_pop_thread_default (loop->context);
321 g_rec_mutex_unlock (&loop->context_lock);
323 g_mutex_lock (&loop->lock);
324 loop->paused = FALSE;
327 g_mutex_unlock (&loop->lock);
331 /* Wake up the loop to run again */
332 g_cond_broadcast (&loop->cond);
333 g_mutex_unlock (&loop->lock);
339 gst_adaptive_demux_loop_call (GstAdaptiveDemuxLoop * loop, GSourceFunc func,
340 gpointer data, GDestroyNotify notify)
344 g_mutex_lock (&loop->lock);
346 GSource *s = g_idle_source_new ();
347 g_source_set_callback (s, func, data, notify);
348 ret = g_source_attach (s, loop->context);
350 } else if (notify != NULL) {
354 g_mutex_unlock (&loop->lock);
360 gst_adaptive_demux_loop_call_delayed (GstAdaptiveDemuxLoop * loop,
361 GstClockTime delay, GSourceFunc func, gpointer data, GDestroyNotify notify)
365 g_mutex_lock (&loop->lock);
367 GSource *s = g_timeout_source_new (GST_TIME_AS_MSECONDS (delay));
368 g_source_set_callback (s, func, data, notify);
369 ret = g_source_attach (s, loop->context);
371 } else if (notify != NULL) {
375 g_mutex_unlock (&loop->lock);
381 gst_adaptive_demux_loop_cancel_call (GstAdaptiveDemuxLoop * loop, guint cb_id)
385 g_mutex_lock (&loop->lock);
386 s = g_main_context_find_source_by_id (loop->context, cb_id);
388 g_source_destroy (s);
389 g_mutex_unlock (&loop->lock);
392 struct Rfc5322TimeZone
399 Parse an RFC5322 (section 3.3) date-time from the Date: field in the
401 See https://tools.ietf.org/html/rfc5322#section-3.3
404 gst_adaptive_demux_util_parse_http_head_date (const gchar * http_date)
406 static const gchar *months[] = { NULL, "Jan", "Feb", "Mar", "Apr",
407 "May", "Jun", "Jul", "Aug",
408 "Sep", "Oct", "Nov", "Dec", NULL
410 static const struct Rfc5322TimeZone timezones[] = {
427 gint year = -1, month = -1, day = -1, hour = -1, minute = -1, second = -1;
431 gboolean parsed_tz = FALSE;
433 g_return_val_if_fail (http_date != NULL, NULL);
435 /* skip optional text version of day of the week */
436 pos = strchr (http_date, ',');
443 sscanf (pos, "%02d %3s %04d %02d:%02d:%02d %5s", &day, monthstr, &year,
444 &hour, &minute, &second, zone);
450 for (i = 1; months[i]; ++i) {
451 if (g_ascii_strncasecmp (months[i], monthstr, strlen (months[i])) == 0) {
456 for (i = 0; timezones[i].name && !parsed_tz; ++i) {
457 if (g_ascii_strncasecmp (timezones[i].name, z,
458 strlen (timezones[i].name)) == 0) {
459 tzoffset = timezones[i].tzoffset;
465 gboolean neg = FALSE;
466 /* check if it is in the form +-HHMM */
467 if (*z == '+' || *z == '-') {
470 else if (*z == '-') {
474 ret = sscanf (z, "%02d%02d", &hh, &mm);
477 tzoffset += mm / 60.0;
479 tzoffset = -tzoffset;
484 /* Accept year in both 2 digit or 4 digit format */
489 if (month < 1 || !parsed_tz)
492 return gst_date_time_new (tzoffset, year, month, day, hour, minute, second);
502 gst_event_store_init (GstEventStore * store)
504 store->events = g_array_sized_new (FALSE, TRUE, sizeof (PadEvent), 16);
505 store->events_pending = FALSE;
509 gst_event_store_flush (GstEventStore * store)
512 GArray *events = store->events;
515 for (i = 0; i < len; i++) {
516 PadEvent *ev = &g_array_index (events, PadEvent, i);
517 GstEvent *event = ev->event;
521 gst_event_unref (event);
523 g_array_set_size (events, 0);
525 store->events_pending = FALSE;
529 gst_event_store_deinit (GstEventStore * store)
531 gst_event_store_flush (store);
532 g_array_free (store->events, TRUE);
536 gst_event_store_insert_event (GstEventStore * store, GstEvent * event,
543 gboolean insert = TRUE;
545 type = GST_EVENT_TYPE (event);
547 if (type & GST_EVENT_TYPE_STICKY_MULTI)
548 name_id = gst_structure_get_name_id (gst_event_get_structure (event));
550 events = store->events;
553 for (i = 0; i < len; i++) {
554 PadEvent *ev = &g_array_index (events, PadEvent, i);
556 if (ev->event == NULL)
559 if (type == GST_EVENT_TYPE (ev->event)) {
560 /* matching types, check matching name if needed */
561 if (name_id && !gst_event_has_name_id (ev->event, name_id))
564 /* overwrite if different */
565 if (gst_event_replace (&ev->event, event)) {
566 ev->delivered = delivered;
567 /* If the event was not delivered, mark that we have a pending
568 * undelivered event */
570 store->events_pending = TRUE;
577 if (type < GST_EVENT_TYPE (ev->event) || (type != GST_EVENT_TYPE (ev->event)
578 && GST_EVENT_TYPE (ev->event) == GST_EVENT_EOS)) {
579 /* STREAM_START, CAPS and SEGMENT must be delivered in this order. By
580 * storing the sticky ordered we can check that this is respected. */
581 if (G_UNLIKELY (GST_EVENT_TYPE (ev->event) <= GST_EVENT_SEGMENT
582 || GST_EVENT_TYPE (ev->event) == GST_EVENT_EOS))
584 ":%s:<store %p> Sticky event misordering, got '%s' before '%s'",
586 gst_event_type_get_name (GST_EVENT_TYPE (ev->event)),
587 gst_event_type_get_name (type));
593 ev.event = gst_event_ref (event);
594 ev.delivered = delivered;
595 g_array_insert_val (events, i, ev);
597 /* If the event was not delivered, mark that we have a pending
598 * undelivered event */
600 store->events_pending = TRUE;
601 GST_LOG ("store %p stored sticky event %s", store,
602 GST_EVENT_TYPE_NAME (event));
606 /* Find the first non-pending event and return a ref to it, owned by the caller */
608 gst_event_store_get_next_pending (GstEventStore * store)
613 if (!store->events_pending)
616 events = store->events;
618 for (i = 0; i < len; i++) {
619 PadEvent *ev = &g_array_index (events, PadEvent, i);
621 if (ev->event == NULL || ev->delivered)
624 /* Found an undelivered event, return it. The caller will mark it
625 * as delivered once it has done so successfully by calling
626 * gst_event_store_mark_delivered() */
627 return gst_event_ref (ev->event);
630 store->events_pending = FALSE;
635 gst_event_store_mark_delivered (GstEventStore * store, GstEvent * event)
637 gboolean events_pending = FALSE;
641 events = store->events;
643 for (i = 0; i < len; i++) {
644 PadEvent *ev = &g_array_index (events, PadEvent, i);
646 if (ev->event == NULL)
649 /* Check if there are any pending events other than
650 * the passed one, so we can update the events_pending
652 if (ev->event != event && !ev->delivered) {
653 events_pending = TRUE;
657 ev->delivered = TRUE;
660 store->events_pending = events_pending;
664 gst_event_store_mark_all_undelivered (GstEventStore * store)
666 gboolean events_pending = FALSE;
670 events = store->events;
672 for (i = 0; i < len; i++) {
673 PadEvent *ev = &g_array_index (events, PadEvent, i);
675 if (ev->event == NULL)
678 ev->delivered = FALSE;
679 events_pending = TRUE;
682 /* Only set the flag if there was at least
683 * one sticky event in the store */
684 store->events_pending = events_pending;