3 * Copyright (C) 2014 Samsung Electronics. All rights reserved.
4 * Author: Thiago Santos <thiagoss@osg.samsung.com>
6 * Copyright (C) 2021-2022 Centricular Ltd
7 * Author: Edward Hervey <edward@centricular.com>
8 * Author: Jan Schmidt <jan@centricular.com>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
20 * You should have received a copy of the GNU Library General Public
21 * License along with this library; if not, write to the
22 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
30 #include "gstadaptivedemux-stream.h"
31 #include "gstadaptivedemux-private.h"
33 #include <glib/gi18n-lib.h>
34 #include <gst/app/gstappsrc.h>
36 GST_DEBUG_CATEGORY_EXTERN (adaptivedemux2_debug);
37 #define GST_CAT_DEFAULT adaptivedemux2_debug
39 static void gst_adaptive_demux2_stream_finalize (GObject * object);
40 static void gst_adaptive_demux2_stream_error (GstAdaptiveDemux2Stream * stream);
42 gst_adaptive_demux2_stream_data_received_default (GstAdaptiveDemux2Stream *
43 stream, GstBuffer * buffer);
45 gst_adaptive_demux2_stream_finish_fragment_default (GstAdaptiveDemux2Stream *
49 gst_adaptive_demux2_stream_update_current_bitrate (GstAdaptiveDemux2Stream *
51 static void gst_adaptive_demux2_stream_update_track_ids (GstAdaptiveDemux2Stream
54 #define gst_adaptive_demux2_stream_parent_class parent_class
55 G_DEFINE_ABSTRACT_TYPE (GstAdaptiveDemux2Stream, gst_adaptive_demux2_stream,
59 gst_adaptive_demux2_stream_class_init (GstAdaptiveDemux2StreamClass * klass)
61 GObjectClass *gobject_class = (GObjectClass *) klass;
63 gobject_class->finalize = gst_adaptive_demux2_stream_finalize;
65 klass->data_received = gst_adaptive_demux2_stream_data_received_default;
66 klass->finish_fragment = gst_adaptive_demux2_stream_finish_fragment_default;
69 static GType tsdemux_type = 0;
72 gst_adaptive_demux2_stream_init (GstAdaptiveDemux2Stream * stream)
74 stream->download_request = download_request_new ();
75 stream->state = GST_ADAPTIVE_DEMUX2_STREAM_STATE_STOPPED;
76 stream->last_ret = GST_FLOW_OK;
77 stream->next_input_wakeup_time = GST_CLOCK_STIME_NONE;
79 stream->fragment_bitrates =
80 g_malloc0 (sizeof (guint64) * NUM_LOOKBACK_FRAGMENTS);
82 stream->start_position = stream->current_position = GST_CLOCK_TIME_NONE;
84 gst_segment_init (&stream->parse_segment, GST_FORMAT_TIME);
87 /* must be called with manifest_lock taken.
88 * It will temporarily drop the manifest_lock in order to join the task.
89 * It will join only the old_streams (the demux->streams are joined by
90 * gst_adaptive_demux_stop_tasks before gst_adaptive_demux2_stream_free is
94 gst_adaptive_demux2_stream_finalize (GObject * object)
96 GstAdaptiveDemux2Stream *stream = (GstAdaptiveDemux2Stream *) object;
98 GST_LOG_OBJECT (object, "Finalizing");
100 if (stream->download_request)
101 download_request_unref (stream->download_request);
103 g_clear_error (&stream->last_error);
105 gst_adaptive_demux2_stream_fragment_clear (&stream->fragment);
107 if (stream->pending_events) {
108 g_list_free_full (stream->pending_events, (GDestroyNotify) gst_event_unref);
109 stream->pending_events = NULL;
112 if (stream->parsebin_sink) {
113 gst_object_unref (stream->parsebin_sink);
114 stream->parsebin_sink = NULL;
117 if (stream->pad_added_id)
118 g_signal_handler_disconnect (stream->parsebin, stream->pad_added_id);
119 if (stream->pad_removed_id)
120 g_signal_handler_disconnect (stream->parsebin, stream->pad_removed_id);
122 if (stream->parsebin != NULL) {
123 GST_LOG_OBJECT (stream, "Removing parsebin");
124 gst_bin_remove (GST_BIN_CAST (stream->demux), stream->parsebin);
125 gst_element_set_state (stream->parsebin, GST_STATE_NULL);
126 gst_object_unref (stream->parsebin);
127 stream->parsebin = NULL;
130 g_free (stream->fragment_bitrates);
132 g_list_free_full (stream->tracks,
133 (GDestroyNotify) gst_adaptive_demux_track_unref);
135 if (stream->pending_caps)
136 gst_caps_unref (stream->pending_caps);
138 gst_clear_tag_list (&stream->pending_tags);
139 g_clear_pointer (&stream->stream_collection, gst_object_unref);
141 G_OBJECT_CLASS (parent_class)->finalize (object);
145 * gst_adaptive_demux2_stream_add_track:
146 * @stream: A #GstAdaptiveDemux2Stream
147 * @track: (transfer none): A #GstAdaptiveDemuxTrack to assign to the @stream
149 * This function is called when a subclass knows of a target @track that this
150 * @stream can provide.
153 gst_adaptive_demux2_stream_add_track (GstAdaptiveDemux2Stream * stream,
154 GstAdaptiveDemuxTrack * track)
156 g_return_val_if_fail (track != NULL, FALSE);
158 GST_DEBUG_OBJECT (stream->demux, "stream:%p track:%s", stream,
160 if (g_list_find (stream->tracks, track)) {
161 GST_DEBUG_OBJECT (stream->demux,
162 "track '%s' already handled by this stream", track->stream_id);
166 if (stream->demux->buffering_low_watermark_time)
167 track->buffering_threshold = stream->demux->buffering_low_watermark_time;
168 else if (GST_CLOCK_TIME_IS_VALID (stream->recommended_buffering_threshold))
169 track->buffering_threshold =
170 MIN (10 * GST_SECOND, stream->recommended_buffering_threshold);
172 /* Using a starting default, can be overriden later in
173 * ::update_stream_info() */
174 GST_DEBUG_OBJECT (stream,
175 "Setting default 10s buffering threshold on new track");
176 track->buffering_threshold = 10 * GST_SECOND;
180 g_list_append (stream->tracks, gst_adaptive_demux_track_ref (track));
182 g_assert (stream->period);
183 gst_adaptive_demux_period_add_track (stream->period, track);
189 gst_adaptive_demux2_stream_next_download (GstAdaptiveDemux2Stream * stream);
191 gst_adaptive_demux2_stream_load_a_fragment (GstAdaptiveDemux2Stream * stream);
193 gst_adaptive_demux2_stream_handle_playlist_eos (GstAdaptiveDemux2Stream *
196 gst_adaptive_demux2_stream_begin_download_uri (GstAdaptiveDemux * demux,
197 GstAdaptiveDemux2Stream * stream, const gchar * uri, gint64 start,
200 #ifndef GST_DISABLE_GST_DEBUG
202 uritype (GstAdaptiveDemux2Stream * s)
204 if (s->downloading_header)
206 if (s->downloading_index)
212 /* Schedules another chunked download (returns TRUE) or FALSE if no more chunks */
214 schedule_another_chunk (GstAdaptiveDemux2Stream * stream)
216 GstAdaptiveDemux *demux = stream->demux;
217 DownloadRequest *request = stream->download_request;
220 gchar *uri = request->uri;
221 gint64 range_start = request->range_start;
222 gint64 range_end = request->range_end;
227 return FALSE; /* This was a request to the end, no more to load */
229 /* The size of the request that just completed: */
230 chunk_size = range_end + 1 - range_start;
232 if (request->content_received < chunk_size)
233 return FALSE; /* Short read - we're done */
235 /* Accumulate the data we just fetched, to figure out the next
236 * request start position and update the target chunk size from
237 * the updated stream fragment info */
238 range_start += chunk_size;
239 range_end = stream->fragment.range_end;
240 chunk_size = stream->fragment.chunk_size;
243 return FALSE; /* Sub-class doesn't want another chunk */
245 /* HTTP ranges are inclusive for the end */
246 if (chunk_size != -1) {
247 chunk_end = range_start + chunk_size - 1;
248 if (range_end != -1 && range_end < chunk_end)
249 chunk_end = range_end;
251 chunk_end = range_end;
254 GST_DEBUG_OBJECT (stream,
255 "Starting next chunk %s %" G_GINT64_FORMAT "-%" G_GINT64_FORMAT
256 " chunk_size %" G_GINT64_FORMAT, uri, range_start, chunk_end, chunk_size);
259 gst_adaptive_demux2_stream_begin_download_uri (demux, stream, uri,
260 range_start, chunk_end);
261 if (ret != GST_FLOW_OK) {
262 GST_DEBUG_OBJECT (stream,
263 "Stopping stream due to begin download failure - ret %s",
264 gst_flow_get_name (ret));
265 gst_adaptive_demux2_stream_stop (stream);
273 drain_inactive_tracks (GstAdaptiveDemux2Stream * stream)
276 GstAdaptiveDemux *demux = stream->demux;
279 for (iter = stream->tracks; iter; iter = iter->next) {
280 GstAdaptiveDemuxTrack *track = (GstAdaptiveDemuxTrack *) iter->data;
281 if (!track->selected) {
282 gst_adaptive_demux_track_drain_to (track,
283 demux->priv->global_output_position);
287 TRACKS_UNLOCK (demux);
290 /* Called to complete a download, either due to failure or completion
291 * Should set up the next download if necessary */
293 gst_adaptive_demux2_stream_finish_download (GstAdaptiveDemux2Stream *
294 stream, GstFlowReturn ret, GError * err)
296 GstAdaptiveDemux2StreamClass *klass =
297 GST_ADAPTIVE_DEMUX2_STREAM_GET_CLASS (stream);
299 GST_DEBUG_OBJECT (stream,
300 "%s download finish: %d %s - err: %p", uritype (stream), ret,
301 gst_flow_get_name (ret), err);
303 stream->download_finished = TRUE;
305 /* finish_fragment might call gst_adaptive_demux2_stream_advance_fragment,
306 * which can look at the last_ret - so make sure it's stored before calling that.
307 * Also, for not-linked or other errors passed in that are going to make
308 * this stream stop, we'll need to store it */
309 stream->last_ret = ret;
312 g_clear_error (&stream->last_error);
313 stream->last_error = g_error_copy (err);
316 /* For actual errors, stop now, no need to call finish_fragment and get
317 * confused if it returns a non-error status, but if EOS was passed in,
318 * continue and check whether finish_fragment() says we've finished
319 * the whole manifest or just this fragment */
320 if (ret < 0 && ret != GST_FLOW_EOS) {
321 GST_INFO_OBJECT (stream,
322 "Stopping stream due to error ret %s", gst_flow_get_name (ret));
323 gst_adaptive_demux2_stream_stop (stream);
327 /* Handle all the possible flow returns here: */
328 if (ret == GST_ADAPTIVE_DEMUX_FLOW_LOST_SYNC) {
329 /* We lost sync, seek back to live and return */
330 GST_WARNING_OBJECT (stream, "Lost sync when downloading");
331 gst_adaptive_demux_handle_lost_sync (stream->demux);
333 } else if (ret == GST_ADAPTIVE_DEMUX_FLOW_END_OF_FRAGMENT) {
334 /* The sub-class wants to stop the fragment immediately */
335 stream->fragment.finished = TRUE;
336 ret = klass->finish_fragment (stream);
338 GST_DEBUG_OBJECT (stream, "finish_fragment ret %d %s", ret,
339 gst_flow_get_name (ret));
340 } else if (ret == GST_ADAPTIVE_DEMUX_FLOW_RESTART_FRAGMENT) {
341 GST_DEBUG_OBJECT (stream, "Restarting download as requested");
342 /* Just mark the fragment as finished */
343 stream->fragment.finished = TRUE;
345 } else if (!klass->need_another_chunk || stream->fragment.chunk_size == -1
346 || !klass->need_another_chunk (stream)
347 || stream->fragment.chunk_size == 0) {
348 stream->fragment.finished = TRUE;
349 ret = klass->finish_fragment (stream);
351 GST_DEBUG_OBJECT (stream, "finish_fragment ret %d %s", ret,
352 gst_flow_get_name (ret));
353 } else if (stream->fragment.chunk_size != 0
354 && schedule_another_chunk (stream)) {
355 /* Another download has already begun, no need to queue anything below */
359 /* For HLS, we might be enqueueing data into tracks that aren't
360 * selected. Drain those ones out */
361 drain_inactive_tracks (stream);
363 /* Now that we've called finish_fragment we can clear these flags the
364 * sub-class might have checked */
365 if (stream->downloading_header) {
366 stream->need_header = FALSE;
367 stream->downloading_header = FALSE;
368 } else if (stream->downloading_index) {
369 stream->need_index = FALSE;
370 stream->downloading_index = FALSE;
371 /* Restart the fragment again now that header + index were loaded
372 * so that get_fragment_info() will be called again */
373 stream->state = GST_ADAPTIVE_DEMUX2_STREAM_STATE_START_FRAGMENT;
375 /* Finishing a fragment data download. Try for another */
376 stream->state = GST_ADAPTIVE_DEMUX2_STREAM_STATE_START_FRAGMENT;
379 /* if GST_FLOW_EOS was passed in that means this download is finished,
380 * but it's the result returned from finish_fragment() we really care
381 * about, as that tells us if the manifest has run out of fragments
383 if (ret == GST_FLOW_EOS) {
384 stream->last_ret = ret;
386 gst_adaptive_demux2_stream_handle_playlist_eos (stream);
390 /* Now finally, if ret is anything other than success, we should stop this
393 GST_DEBUG_OBJECT (stream,
394 "Stopping stream due to finish fragment ret %s",
395 gst_flow_get_name (ret));
396 gst_adaptive_demux2_stream_stop (stream);
400 /* Clear the last_ret marker before starting a fresh download */
401 stream->last_ret = GST_FLOW_OK;
403 GST_LOG_OBJECT (stream, "Scheduling next_download() call");
404 stream->pending_cb_id =
405 gst_adaptive_demux_loop_call (stream->demux->priv->scheduler_task,
406 (GSourceFunc) gst_adaptive_demux2_stream_next_download,
407 gst_object_ref (stream), (GDestroyNotify) gst_object_unref);
410 /* Must be called from the scheduler context */
412 gst_adaptive_demux2_stream_parse_error (GstAdaptiveDemux2Stream * stream,
415 GstAdaptiveDemux *demux = stream->demux;
417 if (stream->state != GST_ADAPTIVE_DEMUX2_STREAM_STATE_DOWNLOADING)
420 downloadhelper_cancel_request (demux->download_helper,
421 stream->download_request);
423 /* cancellation is async, so recycle our download request to avoid races */
424 download_request_unref (stream->download_request);
425 stream->download_request = download_request_new ();
427 gst_adaptive_demux2_stream_finish_download (stream, GST_FLOW_CUSTOM_ERROR,
432 gst_adaptive_demux2_stream_prepare_segment (GstAdaptiveDemux2Stream * stream,
433 gboolean first_and_live)
435 GstAdaptiveDemux *demux = stream->demux;
436 GstClockTime period_start = gst_adaptive_demux_get_period_start_time (demux);
437 GstClockTime offset =
438 gst_adaptive_demux2_stream_get_presentation_offset (stream);
440 /* FIXME: Add a helper function to retrieve the demuxer segment
441 * using the SEGMENT_LOCK */
442 stream->parse_segment = demux->segment;
444 /* The demuxer segment is just built from seek events, but for each stream
445 * we have to adjust segments according to the current period and the
446 * stream specific presentation time offset.
448 * For each period, buffer timestamps start again from 0. Additionally the
449 * buffer timestamps are shifted by the stream specific presentation time
450 * offset, so the first buffer timestamp of a period is 0 + presentation
451 * time offset. If the stream contains timestamps itself, this is also
452 * supposed to be the presentation time stored inside the stream.
454 * The stream time over periods is supposed to be continuous, that is the
455 * buffer timestamp 0 + presentation time offset should map to the start
456 * time of the current period.
459 * The adjustment of the stream segments as such works the following.
461 * If the demuxer segment start is bigger than the period start, this
462 * means that we have to drop some media at the beginning of the current
463 * period, e.g. because a seek into the middle of the period has
464 * happened. The amount of media to drop is the difference between the
465 * period start and the demuxer segment start, and as each period starts
466 * again from 0, this difference is going to be the actual stream's
467 * segment start. As all timestamps of the stream are shifted by the
468 * presentation time offset, we will also have to move the segment start
471 * Likewise, the demuxer segment stop value is adjusted in the same
474 * Now the running time and stream time at the stream's segment start has
475 * to be the one that is stored inside the demuxer's segment, which means
476 * that segment.base and segment.time have to be copied over (done just
480 * If the demuxer segment start is smaller than the period start time,
481 * this means that the whole period is inside the segment. As each period
482 * starts timestamps from 0, and additionally timestamps are shifted by
483 * the presentation time offset, the stream's first timestamp (and as such
484 * the stream's segment start) has to be the presentation time offset.
485 * The stream time at the segment start is supposed to be the stream time
486 * of the period start according to the demuxer segment, so the stream
487 * segment's time would be set to that. The same goes for the stream
488 * segment's base, which is supposed to be the running time of the period
489 * start according to the demuxer's segment.
491 * The same logic applies for negative rates with the segment stop and
492 * the period stop time (which gets clamped).
495 * For the first case where not the complete period is inside the segment,
496 * the segment time and base as calculated by the second case would be
499 GST_DEBUG_OBJECT (stream, "Using demux segment %" GST_SEGMENT_FORMAT,
500 &stream->parse_segment);
502 GST_DEBUG_OBJECT (demux,
503 "period_start: %" GST_TIME_FORMAT " offset: %" GST_TIME_FORMAT,
504 GST_TIME_ARGS (period_start), GST_TIME_ARGS (offset));
506 * Since stream->parse_segment is initially a copy of demux->segment,
507 * only the values that need updating are modified below. */
508 if (first_and_live) {
509 /* If first and live, demuxer did seek to the current position already */
510 stream->parse_segment.start = demux->segment.start - period_start + offset;
511 if (GST_CLOCK_TIME_IS_VALID (demux->segment.stop))
512 stream->parse_segment.stop = demux->segment.stop - period_start + offset;
513 /* FIXME : Do we need to handle negative rates for this ? */
514 stream->parse_segment.position = stream->parse_segment.start;
515 } else if (demux->segment.start > period_start) {
516 /* seek within a period */
517 stream->parse_segment.start = demux->segment.start - period_start + offset;
518 if (GST_CLOCK_TIME_IS_VALID (demux->segment.stop))
519 stream->parse_segment.stop = demux->segment.stop - period_start + offset;
520 if (stream->parse_segment.rate >= 0)
521 stream->parse_segment.position = offset;
523 stream->parse_segment.position = stream->parse_segment.stop;
525 stream->parse_segment.start = offset;
526 if (GST_CLOCK_TIME_IS_VALID (demux->segment.stop))
527 stream->parse_segment.stop = demux->segment.stop - period_start + offset;
528 if (stream->parse_segment.rate >= 0) {
529 stream->parse_segment.position = offset;
530 stream->parse_segment.base =
531 gst_segment_to_running_time (&demux->segment, GST_FORMAT_TIME,
534 stream->parse_segment.position = stream->parse_segment.stop;
535 stream->parse_segment.base =
536 gst_segment_to_running_time (&demux->segment, GST_FORMAT_TIME,
537 period_start + demux->segment.stop - demux->segment.start);
539 stream->parse_segment.time =
540 gst_segment_to_stream_time (&demux->segment, GST_FORMAT_TIME,
544 stream->send_segment = TRUE;
546 GST_DEBUG_OBJECT (stream, "Prepared segment %" GST_SEGMENT_FORMAT,
547 &stream->parse_segment);
550 /* Segment lock hold */
552 update_buffer_pts_and_demux_position_locked (GstAdaptiveDemux * demux,
553 GstAdaptiveDemux2Stream * stream, GstBuffer * buffer)
555 GstClockTimeDiff pos;
557 GST_DEBUG_OBJECT (stream, "stream->fragment.stream_time %" GST_STIME_FORMAT,
558 GST_STIME_ARGS (stream->fragment.stream_time));
560 pos = stream->fragment.stream_time;
562 if (GST_CLOCK_STIME_IS_VALID (pos)) {
563 GstClockTime offset =
564 gst_adaptive_demux2_stream_get_presentation_offset (stream);
569 GST_WARNING_OBJECT (stream, "Clamping segment and buffer position to 0");
573 GST_BUFFER_PTS (buffer) = pos;
575 GST_BUFFER_PTS (buffer) = GST_CLOCK_TIME_NONE;
578 GST_DEBUG_OBJECT (stream, "Buffer/stream position is now: %" GST_TIME_FORMAT,
579 GST_TIME_ARGS (GST_BUFFER_PTS (buffer)));
582 /* Must be called from the scheduler context */
584 gst_adaptive_demux2_stream_push_buffer (GstAdaptiveDemux2Stream * stream,
587 GstAdaptiveDemux *demux = stream->demux;
588 GstFlowReturn ret = GST_FLOW_OK;
589 gboolean discont = FALSE;
591 GstEvent *pending_caps = NULL, *pending_segment = NULL, *pending_tags =
592 NULL, *stream_start = NULL, *buffer_gap = NULL;
593 GList *pending_events = NULL;
595 if (stream->compute_segment) {
596 gst_adaptive_demux2_stream_prepare_segment (stream, stream->first_and_live);
597 stream->compute_segment = FALSE;
598 stream->first_and_live = FALSE;
601 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DROPPABLE)) {
602 GST_DEBUG_OBJECT (stream, "Creating gap event for droppable buffer");
604 gst_event_new_gap (GST_BUFFER_PTS (buffer),
605 GST_BUFFER_DURATION (buffer));
608 if (stream->first_fragment_buffer) {
609 GST_ADAPTIVE_DEMUX_SEGMENT_LOCK (demux);
610 if (demux->segment.rate < 0)
611 /* Set DISCONT flag for every first buffer in reverse playback mode
612 * as each fragment for its own has to be reversed */
614 update_buffer_pts_and_demux_position_locked (demux, stream, buffer);
615 GST_ADAPTIVE_DEMUX_SEGMENT_UNLOCK (demux);
617 GST_LOG_OBJECT (stream, "Handling initial buffer %" GST_PTR_FORMAT, buffer);
619 /* Do we need to inject STREAM_START and SEGMENT events ?
621 * This can happen when a stream is restarted, and also when switching to a
622 * variant which needs a header (in which case downloading_header will be
625 if (G_UNLIKELY (stream->send_segment || stream->downloading_header)) {
626 GST_ADAPTIVE_DEMUX_SEGMENT_LOCK (demux);
627 pending_segment = gst_event_new_segment (&stream->parse_segment);
628 gst_event_set_seqnum (pending_segment, demux->priv->segment_seqnum);
629 stream->send_segment = FALSE;
630 GST_DEBUG_OBJECT (stream, "Sending %" GST_PTR_FORMAT, pending_segment);
631 GST_ADAPTIVE_DEMUX_SEGMENT_UNLOCK (demux);
632 stream_start = gst_event_new_stream_start ("bogus");
633 if (demux->have_group_id)
634 gst_event_set_group_id (stream_start, demux->group_id);
637 GST_BUFFER_PTS (buffer) = GST_CLOCK_TIME_NONE;
639 stream->first_fragment_buffer = FALSE;
641 if (stream->discont) {
643 stream->discont = FALSE;
647 GST_DEBUG_OBJECT (stream, "Marking fragment as discontinuous");
648 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
650 GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DISCONT);
653 GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
654 GST_BUFFER_DTS (buffer) = GST_CLOCK_TIME_NONE;
655 if (G_UNLIKELY (stream->pending_caps)) {
656 pending_caps = gst_event_new_caps (stream->pending_caps);
657 gst_caps_unref (stream->pending_caps);
658 stream->pending_caps = NULL;
661 if (G_UNLIKELY (stream->pending_tags)) {
662 GstTagList *tags = stream->pending_tags;
664 stream->pending_tags = NULL;
667 pending_tags = gst_event_new_tag (tags);
669 if (G_UNLIKELY (stream->pending_events)) {
670 pending_events = stream->pending_events;
671 stream->pending_events = NULL;
674 /* Do not push events or buffers holding the manifest lock */
675 if (G_UNLIKELY (stream_start)) {
676 GST_DEBUG_OBJECT (stream,
677 "Setting stream start: %" GST_PTR_FORMAT, stream_start);
678 gst_pad_send_event (stream->parsebin_sink, stream_start);
680 if (G_UNLIKELY (pending_caps)) {
681 GST_DEBUG_OBJECT (stream,
682 "Setting pending caps: %" GST_PTR_FORMAT, pending_caps);
683 gst_pad_send_event (stream->parsebin_sink, pending_caps);
685 if (G_UNLIKELY (pending_segment)) {
686 GST_DEBUG_OBJECT (stream,
687 "Sending pending seg: %" GST_PTR_FORMAT, pending_segment);
688 gst_pad_send_event (stream->parsebin_sink, pending_segment);
690 if (G_UNLIKELY (pending_tags)) {
691 GST_DEBUG_OBJECT (stream,
692 "Sending pending tags: %" GST_PTR_FORMAT, pending_tags);
693 gst_pad_send_event (stream->parsebin_sink, pending_tags);
695 while (pending_events != NULL) {
696 GstEvent *event = pending_events->data;
698 GST_DEBUG_OBJECT (stream, "Sending pending event: %" GST_PTR_FORMAT, event);
699 if (!gst_pad_send_event (stream->parsebin_sink, event))
700 GST_ERROR_OBJECT (stream, "Failed to send pending event");
702 pending_events = g_list_delete_link (pending_events, pending_events);
705 GST_DEBUG_OBJECT (stream,
706 "About to push buffer of size %" G_GSIZE_FORMAT " offset %"
707 G_GUINT64_FORMAT, gst_buffer_get_size (buffer),
708 GST_BUFFER_OFFSET (buffer));
710 ret = gst_pad_chain (stream->parsebin_sink, buffer);
713 GST_DEBUG_OBJECT (stream, "Sending %" GST_PTR_FORMAT, buffer_gap);
714 gst_pad_send_event (stream->parsebin_sink, buffer_gap);
717 if (G_UNLIKELY (stream->state == GST_ADAPTIVE_DEMUX2_STREAM_STATE_STOPPED)) {
718 GST_LOG_OBJECT (demux, "Stream was cancelled");
719 return GST_FLOW_FLUSHING;
722 GST_LOG_OBJECT (stream, "Push result: %d %s", ret, gst_flow_get_name (ret));
728 gst_adaptive_demux2_stream_parse_buffer (GstAdaptiveDemux2Stream * stream,
731 GstAdaptiveDemux *demux = stream->demux;
732 GstAdaptiveDemux2StreamClass *klass =
733 GST_ADAPTIVE_DEMUX2_STREAM_GET_CLASS (stream);
734 GstFlowReturn ret = GST_FLOW_OK;
736 /* do not make any changes if the stream is cancelled */
737 if (G_UNLIKELY (stream->state == GST_ADAPTIVE_DEMUX2_STREAM_STATE_STOPPED)) {
738 GST_DEBUG_OBJECT (stream, "Stream was stopped. Aborting");
739 gst_buffer_unref (buffer);
740 return GST_FLOW_FLUSHING;
743 /* starting_fragment is set to TRUE at the beginning of
744 * _stream_download_fragment()
745 * /!\ If there is a header/index being downloaded, then this will
746 * be TRUE for the first one ... but FALSE for the remaining ones,
747 * including the *actual* fragment ! */
748 if (stream->starting_fragment) {
749 stream->starting_fragment = FALSE;
750 if (klass->start_fragment != NULL && !klass->start_fragment (stream))
751 return GST_FLOW_ERROR;
754 stream->download_total_bytes += gst_buffer_get_size (buffer);
756 GST_TRACE_OBJECT (stream,
757 "Received %s buffer of size %" G_GSIZE_FORMAT, uritype (stream),
758 gst_buffer_get_size (buffer));
760 ret = klass->data_received (stream, buffer);
762 if (ret != GST_FLOW_OK) {
763 GST_DEBUG_OBJECT (stream, "data_received returned %s",
764 gst_flow_get_name (ret));
766 if (ret == GST_FLOW_FLUSHING) {
767 /* do not make any changes if the stream is cancelled */
768 if (stream->state == GST_ADAPTIVE_DEMUX2_STREAM_STATE_STOPPED) {
769 GST_DEBUG_OBJECT (stream, "Stream was stopped. Aborting");
774 if (ret < GST_FLOW_EOS) {
775 GstEvent *eos = gst_event_new_eos ();
776 GST_ELEMENT_FLOW_ERROR (demux, ret);
778 GST_DEBUG_OBJECT (stream, "Pushing EOS to parser");
780 /* TODO push this on all pads */
781 gst_event_set_seqnum (eos, demux->priv->segment_seqnum);
782 gst_pad_send_event (stream->parsebin_sink, eos);
783 ret = GST_FLOW_ERROR;
785 stream->state = GST_ADAPTIVE_DEMUX2_STREAM_STATE_ERRORED;
792 /* Calculate the low and high download buffering watermarks
793 * in time as MAX (low-watermark-time, low-watermark-fragments) and
794 * MIN (high-watermark-time, high-watermark-fragments) respectively
797 calculate_track_thresholds (GstAdaptiveDemux * demux,
798 GstAdaptiveDemux2Stream * stream,
799 GstClockTime fragment_duration, GstClockTime * low_threshold,
800 GstClockTime * high_threshold)
802 GST_OBJECT_LOCK (demux);
803 *low_threshold = demux->buffering_low_watermark_fragments * fragment_duration;
804 if (*low_threshold == 0 ||
805 (demux->buffering_low_watermark_time != 0
806 && demux->buffering_low_watermark_time > *low_threshold)) {
807 *low_threshold = demux->buffering_low_watermark_time;
810 if (*low_threshold == 0) {
811 /* This implies both low level properties were 0, the default is 10s unless
812 * the subclass has specified a recommended buffering threshold */
813 *low_threshold = 10 * GST_SECOND;
814 if (GST_CLOCK_TIME_IS_VALID (stream->recommended_buffering_threshold))
816 MIN (stream->recommended_buffering_threshold, *low_threshold);
820 demux->buffering_high_watermark_fragments * fragment_duration;
821 if (*high_threshold == 0 || (demux->buffering_high_watermark_time != 0
822 && demux->buffering_high_watermark_time < *high_threshold)) {
823 *high_threshold = demux->buffering_high_watermark_time;
826 /* Make sure the low and high thresholds are less than the maximum buffering
828 if (*high_threshold == 0 ||
829 (demux->max_buffering_time != 0
830 && demux->max_buffering_time < *high_threshold)) {
831 *high_threshold = demux->max_buffering_time;
834 if (*low_threshold == 0 ||
835 (demux->max_buffering_time != 0
836 && demux->max_buffering_time < *low_threshold)) {
837 *low_threshold = demux->max_buffering_time;
840 /* Make sure the high threshold is higher than (or equal to) the low threshold.
841 * It's OK if they are the same, as the minimum download is 1 fragment */
842 if (*high_threshold == 0 ||
843 (*low_threshold != 0 && *low_threshold > *high_threshold)) {
844 *high_threshold = *low_threshold;
847 GST_OBJECT_UNLOCK (demux);
850 #define ABSDIFF(a,b) ((a) < (b) ? (b) - (a) : (a) - (b))
852 gst_adaptive_demux2_stream_wait_for_output_space (GstAdaptiveDemux * demux,
853 GstAdaptiveDemux2Stream * stream, GstClockTime fragment_duration)
855 gboolean need_to_wait = TRUE;
856 gboolean have_any_tracks = FALSE;
857 gboolean have_active_tracks = FALSE;
858 gboolean have_filled_inactive = FALSE;
859 gboolean update_buffering = FALSE;
861 GstClockTime low_threshold = 0, high_threshold = 0;
864 calculate_track_thresholds (demux, stream, fragment_duration,
865 &low_threshold, &high_threshold);
866 GST_DEBUG_OBJECT (stream,
867 "Thresholds low:%" GST_TIME_FORMAT " high:%" GST_TIME_FORMAT
868 " recommended:%" GST_TIME_FORMAT, GST_TIME_ARGS (low_threshold),
869 GST_TIME_ARGS (high_threshold),
870 GST_TIME_ARGS (stream->recommended_buffering_threshold));
872 /* If there are no tracks at all, don't wait. If there are no active
873 * tracks, keep filling until at least one track is full. If there
874 * are active tracks, require that they are all full */
876 for (iter = stream->tracks; iter; iter = iter->next) {
877 GstAdaptiveDemuxTrack *track = (GstAdaptiveDemuxTrack *) iter->data;
879 /* Update the buffering threshold if it changed by more than a second */
880 if (ABSDIFF (low_threshold, track->buffering_threshold) > GST_SECOND) {
881 GST_DEBUG_OBJECT (stream, "Updating threshold");
882 /* The buffering threshold for this track changed, make sure to
883 * re-check buffering status */
884 update_buffering = TRUE;
885 track->buffering_threshold = low_threshold;
888 have_any_tracks = TRUE;
890 have_active_tracks = TRUE;
892 if (track->level_time < high_threshold) {
894 need_to_wait = FALSE;
895 GST_DEBUG_OBJECT (stream,
896 "track %s has level %" GST_TIME_FORMAT
897 " - needs more data (target %" GST_TIME_FORMAT
898 ") (fragment duration %" GST_TIME_FORMAT ")",
899 track->stream_id, GST_TIME_ARGS (track->level_time),
900 GST_TIME_ARGS (high_threshold), GST_TIME_ARGS (fragment_duration));
903 } else if (!track->active) { /* track is over threshold and inactive */
904 have_filled_inactive = TRUE;
907 GST_DEBUG_OBJECT (stream,
908 "track %s active (%d) has level %" GST_TIME_FORMAT,
909 track->stream_id, track->active, GST_TIME_ARGS (track->level_time));
912 /* If there are no tracks, don't wait (we might need data to create them),
913 * or if there are active tracks that need more data to hit the threshold,
914 * don't wait. Otherwise it means all active tracks are full and we should wait */
915 if (!have_any_tracks) {
916 GST_DEBUG_OBJECT (stream, "no tracks created yet - not waiting");
917 need_to_wait = FALSE;
918 } else if (!have_active_tracks && !have_filled_inactive) {
919 GST_DEBUG_OBJECT (stream,
920 "have only inactive tracks that need more data - not waiting");
921 need_to_wait = FALSE;
925 stream->next_input_wakeup_time = GST_CLOCK_STIME_NONE;
927 for (iter = stream->tracks; iter; iter = iter->next) {
928 GstAdaptiveDemuxTrack *track = (GstAdaptiveDemuxTrack *) iter->data;
930 GST_DEBUG_OBJECT (stream,
931 "Waiting for queued data on track %s to drop below %"
932 GST_TIME_FORMAT " (fragment duration %" GST_TIME_FORMAT ")",
933 track->stream_id, GST_TIME_ARGS (high_threshold),
934 GST_TIME_ARGS (fragment_duration));
936 /* we want to get woken up when the global output position reaches
937 * a point where the input is closer than "high_threshold" to needing
938 * output, so we can put more data in */
939 GstClockTimeDiff wakeup_time = track->input_time - high_threshold;
941 if (stream->next_input_wakeup_time == GST_CLOCK_STIME_NONE ||
942 wakeup_time < stream->next_input_wakeup_time) {
943 stream->next_input_wakeup_time = wakeup_time;
945 GST_DEBUG_OBJECT (stream,
946 "Track %s level %" GST_TIME_FORMAT ". Input at position %"
947 GST_TIME_FORMAT " next wakeup should be %" GST_TIME_FORMAT " now %"
948 GST_TIME_FORMAT, track->stream_id,
949 GST_TIME_ARGS (track->level_time),
950 GST_TIME_ARGS (track->input_time), GST_TIME_ARGS (wakeup_time),
951 GST_TIME_ARGS (demux->priv->global_output_position));
955 if (stream->next_input_wakeup_time != GST_CLOCK_TIME_NONE) {
956 GST_DEBUG_OBJECT (stream,
957 "Next input wakeup time is now %" GST_TIME_FORMAT,
958 GST_TIME_ARGS (stream->next_input_wakeup_time));
960 /* If this stream needs waking up sooner than any other current one,
961 * update the period wakeup time, which is what the output loop
963 GstAdaptiveDemuxPeriod *period = stream->period;
964 if (period->next_input_wakeup_time == GST_CLOCK_STIME_NONE ||
965 period->next_input_wakeup_time > stream->next_input_wakeup_time) {
966 period->next_input_wakeup_time = stream->next_input_wakeup_time;
971 if (update_buffering) {
972 demux_update_buffering_locked (demux);
973 demux_post_buffering_locked (demux);
976 TRACKS_UNLOCK (demux);
981 static GstAdaptiveDemuxTrack *
982 match_parsebin_to_track (GstAdaptiveDemux2Stream * stream, GstPad * pad)
985 GstAdaptiveDemuxTrack *found_track = NULL, *first_matched_track = NULL;
986 gint num_possible_tracks = 0;
987 GstStream *gst_stream;
988 const gchar *internal_stream_id;
989 GstStreamType stream_type;
991 gst_stream = gst_pad_get_stream (pad);
993 /* FIXME: Edward: Added assertion because I don't see in what cases we would
994 * end up with a pad from parsebin which wouldn't have an associated
996 g_assert (gst_stream);
998 internal_stream_id = gst_stream_get_stream_id (gst_stream);
999 stream_type = gst_stream_get_stream_type (gst_stream);
1001 GST_DEBUG_OBJECT (pad,
1002 "Trying to match pad from parsebin with internal streamid %s and caps %"
1003 GST_PTR_FORMAT, GST_STR_NULL (internal_stream_id),
1004 gst_stream_get_caps (gst_stream));
1006 /* Try to match directly by the track's pending upstream_stream_id */
1007 for (tmp = stream->tracks; tmp; tmp = tmp->next) {
1008 GstAdaptiveDemuxTrack *track = (GstAdaptiveDemuxTrack *) tmp->data;
1010 if (stream_type != GST_STREAM_TYPE_UNKNOWN && track->type != stream_type)
1013 GST_DEBUG_OBJECT (pad, "track upstream_stream_id: %s",
1014 track->upstream_stream_id);
1016 if (first_matched_track == NULL)
1017 first_matched_track = track;
1018 num_possible_tracks++;
1020 /* If this track has a desired upstream stream id, match on it */
1021 if (track->upstream_stream_id == NULL ||
1022 g_strcmp0 (track->upstream_stream_id, internal_stream_id)) {
1023 /* This is not the track for this pad */
1027 /* Remove pending upstream id (we have matched it for the pending
1029 g_free (track->upstream_stream_id);
1030 track->upstream_stream_id = NULL;
1031 found_track = track;
1035 if (found_track == NULL) {
1036 /* If we arrive here, it means the stream is switching pads after
1037 * the stream has already started running */
1038 /* No track is currently waiting for this particular stream id -
1039 * try and match an existing linked track. If there's only 1 possible,
1041 if (num_possible_tracks == 1 && first_matched_track != NULL) {
1042 GST_LOG_OBJECT (pad, "Only one possible track to link to");
1043 found_track = first_matched_track;
1047 if (found_track == NULL) {
1048 /* TODO: There are multiple possible tracks, need to match based
1049 * on language code and caps. Have you found a stream like this? */
1050 GST_FIXME_OBJECT (pad, "Need to match track based on caps and language");
1053 if (found_track != NULL) {
1054 if (!gst_pad_is_linked (found_track->sinkpad)) {
1055 GST_LOG_OBJECT (pad, "Linking to track pad %" GST_PTR_FORMAT,
1056 found_track->sinkpad);
1058 if (gst_pad_link (pad, found_track->sinkpad) != GST_PAD_LINK_OK) {
1059 GST_ERROR_OBJECT (pad, "Couldn't connect to track sinkpad");
1060 /* FIXME : Do something if we can't link ? */
1063 /* Store pad as pending link */
1064 GST_LOG_OBJECT (pad,
1065 "Remembering pad to be linked when current pad is unlinked");
1066 g_assert (found_track->pending_srcpad == NULL);
1067 found_track->pending_srcpad = gst_object_ref (pad);
1072 gst_object_unref (gst_stream);
1078 parsebin_pad_removed_cb (GstElement * parsebin, GstPad * pad,
1079 GstAdaptiveDemux2Stream * stream)
1082 GST_DEBUG_OBJECT (stream, "pad %s:%s", GST_DEBUG_PAD_NAME (pad));
1084 /* Remove from pending source pad */
1085 TRACKS_LOCK (stream->demux);
1086 for (iter = stream->tracks; iter; iter = iter->next) {
1087 GstAdaptiveDemuxTrack *track = iter->data;
1088 if (track->pending_srcpad == pad) {
1089 gst_object_unref (track->pending_srcpad);
1090 track->pending_srcpad = NULL;
1094 TRACKS_UNLOCK (stream->demux);
1098 parsebin_pad_added_cb (GstElement * parsebin, GstPad * pad,
1099 GstAdaptiveDemux2Stream * stream)
1101 if (!GST_PAD_IS_SRC (pad))
1104 GST_DEBUG_OBJECT (stream, "pad %s:%s", GST_DEBUG_PAD_NAME (pad));
1106 if (!match_parsebin_to_track (stream, pad))
1107 GST_WARNING_OBJECT (pad, "Found no track to handle pad");
1109 GST_DEBUG_OBJECT (stream->demux, "Done linking");
1113 parsebin_deep_element_added_cb (GstBin * parsebin, GstBin * unused,
1114 GstElement * element, GstAdaptiveDemux * demux)
1116 if (G_OBJECT_TYPE (element) == tsdemux_type) {
1117 GST_DEBUG_OBJECT (demux, "Overriding tsdemux ignore-pcr to TRUE");
1118 g_object_set (element, "ignore-pcr", TRUE, NULL);
1122 /* must be called with manifest_lock taken */
1124 gst_adaptive_demux2_stream_create_parser (GstAdaptiveDemux2Stream * stream)
1126 GstAdaptiveDemux *demux = stream->demux;
1128 if (stream->parsebin == NULL) {
1131 GST_DEBUG_OBJECT (demux, "Setting up new parsing source");
1133 /* Workaround to detect if tsdemux is being used */
1134 if (tsdemux_type == 0) {
1135 GstElement *element = gst_element_factory_make ("tsdemux", NULL);
1137 tsdemux_type = G_OBJECT_TYPE (element);
1138 gst_object_unref (element);
1142 stream->parsebin = gst_element_factory_make ("parsebin", NULL);
1144 g_signal_connect (stream->parsebin, "deep-element-added",
1145 (GCallback) parsebin_deep_element_added_cb, demux);
1146 gst_bin_add (GST_BIN_CAST (demux), gst_object_ref (stream->parsebin));
1147 stream->parsebin_sink =
1148 gst_element_get_static_pad (stream->parsebin, "sink");
1149 stream->pad_added_id = g_signal_connect (stream->parsebin, "pad-added",
1150 G_CALLBACK (parsebin_pad_added_cb), stream);
1151 stream->pad_removed_id = g_signal_connect (stream->parsebin, "pad-removed",
1152 G_CALLBACK (parsebin_pad_removed_cb), stream);
1154 event = gst_event_new_stream_start ("bogus");
1155 if (demux->have_group_id)
1156 gst_event_set_group_id (event, demux->group_id);
1158 gst_pad_send_event (stream->parsebin_sink, event);
1160 /* Not sure if these need to be outside the manifest lock: */
1161 gst_element_sync_state_with_parent (stream->parsebin);
1162 stream->last_status_code = 200; /* default to OK */
1168 on_download_cancellation (DownloadRequest * request, DownloadRequestState state,
1169 GstAdaptiveDemux2Stream * stream)
1174 on_download_error (DownloadRequest * request, DownloadRequestState state,
1175 GstAdaptiveDemux2Stream * stream)
1177 GstAdaptiveDemux *demux = stream->demux;
1178 guint last_status_code = request->status_code;
1181 if (stream->state != GST_ADAPTIVE_DEMUX2_STREAM_STATE_DOWNLOADING) {
1182 GST_DEBUG_OBJECT (stream, "Stream state changed to %d. Aborting",
1187 stream->download_active = FALSE;
1188 stream->last_status_code = last_status_code;
1190 GST_DEBUG_OBJECT (stream,
1191 "Download finished with error, request state %d http status %u, dc %d",
1192 request->state, last_status_code, stream->download_error_count);
1194 live = gst_adaptive_demux_is_live (demux);
1195 if (((last_status_code / 100 == 4 && live)
1196 || last_status_code / 100 == 5)) {
1198 /* if current position is before available start, switch to next */
1199 if (!gst_adaptive_demux2_stream_has_next_fragment (stream))
1203 gint64 range_start, range_stop;
1205 if (!gst_adaptive_demux_get_live_seek_range (demux, &range_start,
1209 if (demux->segment.position < range_start) {
1212 GST_DEBUG_OBJECT (stream, "Retrying once with next segment");
1213 gst_adaptive_demux2_stream_finish_download (stream, GST_FLOW_EOS, NULL);
1215 GST_DEBUG_OBJECT (demux, "Calling update_fragment_info");
1217 ret = gst_adaptive_demux2_stream_update_fragment_info (stream);
1218 GST_DEBUG_OBJECT (stream, "update_fragment_info ret: %s",
1219 gst_flow_get_name (ret));
1221 if (ret == GST_FLOW_OK)
1224 } else if (demux->segment.position > range_stop) {
1225 /* wait a bit to be in range, we don't have any locks at that point */
1226 GstClockTime wait_time =
1227 gst_adaptive_demux2_stream_get_fragment_waiting_time (stream);
1228 if (wait_time > 0) {
1229 GST_DEBUG_OBJECT (stream,
1230 "Download waiting for %" GST_TIME_FORMAT,
1231 GST_TIME_ARGS (wait_time));
1232 g_assert (stream->pending_cb_id == 0);
1233 GST_LOG_OBJECT (stream, "Scheduling delayed load_a_fragment() call");
1234 stream->pending_cb_id =
1235 gst_adaptive_demux_loop_call_delayed (demux->priv->scheduler_task,
1237 (GSourceFunc) gst_adaptive_demux2_stream_load_a_fragment,
1238 gst_object_ref (stream), (GDestroyNotify) gst_object_unref);
1244 if (stream->download_error_count >= MAX_DOWNLOAD_ERROR_COUNT) {
1245 /* looks like there is no way of knowing when a live stream has ended
1246 * Have to assume we are falling behind and cause a manifest reload */
1247 GST_DEBUG_OBJECT (stream, "Converting error of live stream to EOS");
1248 gst_adaptive_demux2_stream_handle_playlist_eos (stream);
1251 } else if (!gst_adaptive_demux2_stream_has_next_fragment (stream)) {
1252 /* If this is the last fragment, consider failures EOS and not actual
1253 * errors. Due to rounding errors in the durations, the last fragment
1254 * might not actually exist */
1255 GST_DEBUG_OBJECT (stream, "Converting error for last fragment to EOS");
1256 gst_adaptive_demux2_stream_handle_playlist_eos (stream);
1259 /* retry same segment */
1260 if (++stream->download_error_count > MAX_DOWNLOAD_ERROR_COUNT) {
1261 gst_adaptive_demux2_stream_error (stream);
1268 /* wait a short time in case the server needs a bit to recover */
1269 GST_LOG_OBJECT (stream,
1270 "Scheduling delayed load_a_fragment() call to retry in 10 milliseconds");
1271 g_assert (stream->pending_cb_id == 0);
1272 stream->pending_cb_id = gst_adaptive_demux_loop_call_delayed (demux->priv->scheduler_task, 10 * GST_MSECOND, /* Retry in 10 ms */
1273 (GSourceFunc) gst_adaptive_demux2_stream_load_a_fragment,
1274 gst_object_ref (stream), (GDestroyNotify) gst_object_unref);
1278 update_stream_bitrate (GstAdaptiveDemux2Stream * stream,
1279 DownloadRequest * request)
1281 GstClockTimeDiff last_download_duration;
1282 guint64 fragment_bytes_downloaded = request->content_received;
1284 /* The stream last_download time tracks the full download time for now */
1285 stream->last_download_time =
1286 GST_CLOCK_DIFF (request->download_request_time,
1287 request->download_end_time);
1289 /* Here we only track the time the data took to arrive and ignore request delay, so we can estimate bitrate */
1290 last_download_duration =
1291 GST_CLOCK_DIFF (request->download_start_time, request->download_end_time);
1293 /* If the entire response arrived in the first buffer
1294 * though, include the request time to get a valid
1295 * bitrate estimate */
1296 if (last_download_duration < 2 * stream->last_download_time)
1297 last_download_duration = stream->last_download_time;
1299 if (last_download_duration > 0) {
1300 stream->last_bitrate =
1301 gst_util_uint64_scale (fragment_bytes_downloaded,
1302 8 * GST_SECOND, last_download_duration);
1304 GST_DEBUG_OBJECT (stream,
1305 "Updated stream bitrate. %" G_GUINT64_FORMAT
1306 " bytes. download time %" GST_TIME_FORMAT " bitrate %"
1307 G_GUINT64_FORMAT " bps", fragment_bytes_downloaded,
1308 GST_TIME_ARGS (last_download_duration), stream->last_bitrate);
1313 on_download_progress (DownloadRequest * request, DownloadRequestState state,
1314 GstAdaptiveDemux2Stream * stream)
1316 GstAdaptiveDemux *demux = stream->demux;
1317 GstBuffer *buffer = download_request_take_buffer (request);
1322 GST_DEBUG_OBJECT (stream,
1323 "Handling buffer of %" G_GSIZE_FORMAT
1324 " bytes of ongoing download progress - %" G_GUINT64_FORMAT " / %"
1325 G_GUINT64_FORMAT " bytes", gst_buffer_get_size (buffer),
1326 request->content_received, request->content_length);
1328 /* Drop the request lock when parsing data. FIXME: Check and comment why this is needed */
1329 download_request_unlock (request);
1330 ret = gst_adaptive_demux2_stream_parse_buffer (stream, buffer);
1331 download_request_lock (request);
1333 if (stream->state != GST_ADAPTIVE_DEMUX2_STREAM_STATE_DOWNLOADING)
1336 if (ret != GST_FLOW_OK) {
1337 GST_DEBUG_OBJECT (stream,
1338 "Buffer parsing returned: %d %s. Aborting download", ret,
1339 gst_flow_get_name (ret));
1341 if (!stream->downloading_header && !stream->downloading_index)
1342 update_stream_bitrate (stream, request);
1344 downloadhelper_cancel_request (demux->download_helper, request);
1346 /* cancellation is async, so recycle our download request to avoid races */
1347 download_request_unref (stream->download_request);
1348 stream->download_request = download_request_new ();
1350 gst_adaptive_demux2_stream_finish_download (stream, ret, NULL);
1356 on_download_complete (DownloadRequest * request, DownloadRequestState state,
1357 GstAdaptiveDemux2Stream * stream)
1359 GstFlowReturn ret = GST_FLOW_OK;
1362 stream->download_active = FALSE;
1364 if (stream->state != GST_ADAPTIVE_DEMUX2_STREAM_STATE_DOWNLOADING) {
1365 GST_DEBUG_OBJECT (stream, "Stream state changed to %d. Aborting",
1370 GST_DEBUG_OBJECT (stream,
1371 "Stream %p %s download for %s is complete with state %d",
1372 stream, uritype (stream), request->uri, request->state);
1374 /* Update bitrate for fragment downloads */
1375 if (!stream->downloading_header && !stream->downloading_index)
1376 update_stream_bitrate (stream, request);
1378 buffer = download_request_take_buffer (request);
1380 ret = gst_adaptive_demux2_stream_parse_buffer (stream, buffer);
1382 GST_DEBUG_OBJECT (stream,
1383 "%s download finished: %s ret %d %s. Stream state %d", uritype (stream),
1384 request->uri, ret, gst_flow_get_name (ret), stream->state);
1386 if (stream->state != GST_ADAPTIVE_DEMUX2_STREAM_STATE_DOWNLOADING)
1389 g_assert (stream->pending_cb_id == 0);
1390 gst_adaptive_demux2_stream_finish_download (stream, ret, NULL);
1393 /* must be called from the scheduler context
1395 * Will submit the request only, which will complete asynchronously
1397 static GstFlowReturn
1398 gst_adaptive_demux2_stream_begin_download_uri (GstAdaptiveDemux * demux,
1399 GstAdaptiveDemux2Stream * stream, const gchar * uri, gint64 start,
1402 DownloadRequest *request = stream->download_request;
1404 GST_DEBUG_OBJECT (demux,
1405 "Downloading %s uri: %s, range:%" G_GINT64_FORMAT " - %" G_GINT64_FORMAT,
1406 uritype (stream), uri, start, end);
1408 if (!gst_adaptive_demux2_stream_create_parser (stream))
1409 return GST_FLOW_ERROR;
1411 /* Configure our download request */
1412 download_request_set_uri (request, uri, start, end);
1414 if (stream->downloading_header || stream->downloading_index) {
1415 download_request_set_callbacks (request,
1416 (DownloadRequestEventCallback) on_download_complete,
1417 (DownloadRequestEventCallback) on_download_error,
1418 (DownloadRequestEventCallback) on_download_cancellation,
1419 (DownloadRequestEventCallback) NULL, stream);
1421 download_request_set_callbacks (request,
1422 (DownloadRequestEventCallback) on_download_complete,
1423 (DownloadRequestEventCallback) on_download_error,
1424 (DownloadRequestEventCallback) on_download_cancellation,
1425 (DownloadRequestEventCallback) on_download_progress, stream);
1428 if (!downloadhelper_submit_request (demux->download_helper,
1429 demux->manifest_uri, DOWNLOAD_FLAG_NONE, request, NULL))
1430 return GST_FLOW_ERROR;
1432 stream->download_active = TRUE;
1437 /* must be called from the scheduler context */
1438 static GstFlowReturn
1439 gst_adaptive_demux2_stream_download_fragment (GstAdaptiveDemux2Stream * stream)
1441 GstAdaptiveDemux *demux = stream->demux;
1442 GstAdaptiveDemux2StreamClass *klass =
1443 GST_ADAPTIVE_DEMUX2_STREAM_GET_CLASS (stream);
1447 /* THERE ARE THREE DIFFERENT VARIABLES FOR THE "BEGINNING" OF A FRAGMENT ! */
1448 if (stream->starting_fragment) {
1449 GST_DEBUG_OBJECT (stream, "Downloading %s%s%s",
1450 stream->fragment.uri ? "FRAGMENT " : "",
1451 stream->need_header && stream->fragment.header_uri ? "HEADER " : "",
1452 stream->need_index && stream->fragment.index_uri ? "INDEX" : "");
1454 if (stream->fragment.uri == NULL && stream->fragment.header_uri == NULL &&
1455 stream->fragment.index_uri == NULL)
1458 stream->first_fragment_buffer = TRUE;
1459 stream->state = GST_ADAPTIVE_DEMUX2_STREAM_STATE_DOWNLOADING;
1462 if (stream->need_header && stream->fragment.header_uri != NULL) {
1464 /* Set the need_index flag when we start the header if we'll also need the index */
1465 stream->need_index = (stream->fragment.index_uri != NULL);
1467 GST_DEBUG_OBJECT (stream, "Fetching header %s %" G_GINT64_FORMAT "-%"
1468 G_GINT64_FORMAT, stream->fragment.header_uri,
1469 stream->fragment.header_range_start, stream->fragment.header_range_end);
1471 stream->downloading_header = TRUE;
1473 return gst_adaptive_demux2_stream_begin_download_uri (demux, stream,
1474 stream->fragment.header_uri, stream->fragment.header_range_start,
1475 stream->fragment.header_range_end);
1478 /* check if we have an index */
1479 if (stream->need_index && stream->fragment.index_uri != NULL) {
1480 GST_DEBUG_OBJECT (stream,
1481 "Fetching index %s %" G_GINT64_FORMAT "-%" G_GINT64_FORMAT,
1482 stream->fragment.index_uri,
1483 stream->fragment.index_range_start, stream->fragment.index_range_end);
1485 stream->downloading_index = TRUE;
1487 return gst_adaptive_demux2_stream_begin_download_uri (demux, stream,
1488 stream->fragment.index_uri, stream->fragment.index_range_start,
1489 stream->fragment.index_range_end);
1492 url = stream->fragment.uri;
1493 GST_DEBUG_OBJECT (stream, "Got url '%s' for stream %p", url, stream);
1497 /* Download the actual fragment, either in chunks or in one go */
1498 stream->first_fragment_buffer = TRUE;
1500 if (klass->need_another_chunk && klass->need_another_chunk (stream)
1501 && stream->fragment.chunk_size != 0) {
1502 /* Handle chunk downloading */
1503 gint64 range_start = stream->fragment.range_start;
1504 gint64 range_end = stream->fragment.range_end;
1505 gint chunk_size = stream->fragment.chunk_size;
1508 /* HTTP ranges are inclusive for the end */
1509 if (chunk_size != -1) {
1510 chunk_end = range_start + chunk_size - 1;
1511 if (range_end != -1 && range_end < chunk_end)
1512 chunk_end = range_end;
1514 chunk_end = range_end;
1517 GST_DEBUG_OBJECT (stream,
1518 "Starting chunked download %s %" G_GINT64_FORMAT "-%" G_GINT64_FORMAT,
1519 url, range_start, chunk_end);
1520 return gst_adaptive_demux2_stream_begin_download_uri (demux, stream, url,
1521 range_start, chunk_end);
1524 /* regular single chunk download */
1525 stream->fragment.chunk_size = 0;
1527 return gst_adaptive_demux2_stream_begin_download_uri (demux, stream, url,
1528 stream->fragment.range_start, stream->fragment.range_end);
1532 GST_ELEMENT_ERROR (demux, STREAM, DEMUX,
1533 (_("Failed to get fragment URL.")),
1534 ("An error happened when getting fragment URL"));
1535 return GST_FLOW_ERROR;
1540 gst_adaptive_demux2_stream_push_event (GstAdaptiveDemux2Stream * stream,
1543 gboolean ret = TRUE;
1546 /* If there's a parsebin, push the event through it */
1547 if (stream->parsebin_sink != NULL) {
1548 pad = gst_object_ref (stream->parsebin_sink);
1549 GST_DEBUG_OBJECT (pad, "Pushing event %" GST_PTR_FORMAT, event);
1550 ret = gst_pad_send_event (pad, gst_event_ref (event));
1551 gst_object_unref (pad);
1554 /* If the event is EOS, ensure that all tracks are EOS. This catches
1555 * the case where the parsebin hasn't parsed anything yet (we switched
1556 * to a never before used track right near EOS, or it didn't parse enough
1557 * to create pads and be able to send EOS through to the tracks.
1559 * We don't need to care about any other events
1561 if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
1564 for (iter = stream->tracks; iter; iter = iter->next) {
1565 GstAdaptiveDemuxTrack *track = (GstAdaptiveDemuxTrack *) iter->data;
1566 ret &= gst_pad_send_event (track->sinkpad, gst_event_ref (event));
1570 gst_event_unref (event);
1575 gst_adaptive_demux2_stream_error (GstAdaptiveDemux2Stream * stream)
1577 GstAdaptiveDemux *demux = stream->demux;
1579 GstStructure *details;
1581 details = gst_structure_new_empty ("details");
1582 gst_structure_set (details, "http-status-code", G_TYPE_UINT,
1583 stream->last_status_code, NULL);
1585 stream->state = GST_ADAPTIVE_DEMUX2_STREAM_STATE_ERRORED;
1587 if (stream->last_error) {
1588 gchar *debug = g_strdup_printf ("Error on stream %s",
1589 GST_OBJECT_NAME (stream));
1591 gst_message_new_error_with_details (GST_OBJECT_CAST (demux),
1592 stream->last_error, debug, details);
1593 GST_ERROR_OBJECT (stream, "Download error: %s",
1594 stream->last_error->message);
1597 GError *err = g_error_new (GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_NOT_FOUND,
1598 _("Couldn't download fragments"));
1600 gst_message_new_error_with_details (GST_OBJECT_CAST (demux), err,
1601 "Fragment downloading has failed consecutive times", details);
1603 GST_ERROR_OBJECT (stream,
1604 "Download error: Couldn't download fragments, too many failures");
1607 gst_element_post_message (GST_ELEMENT_CAST (demux), msg);
1610 /* Called when a stream reaches the end of a playback segment */
1612 gst_adaptive_demux2_stream_end_of_manifest (GstAdaptiveDemux2Stream * stream)
1614 GstAdaptiveDemux *demux = stream->demux;
1615 GstFlowReturn combined =
1616 gst_adaptive_demux_period_combine_stream_flows (demux->input_period);
1618 GST_DEBUG_OBJECT (stream, "Combined flow %s", gst_flow_get_name (combined));
1620 if (gst_adaptive_demux_has_next_period (demux)) {
1621 if (combined == GST_FLOW_EOS) {
1622 GST_DEBUG_OBJECT (stream, "Next period available, advancing");
1623 gst_adaptive_demux_advance_period (demux);
1625 /* Ensure the 'has_next_period' flag is set on the period before
1626 * pushing EOS to the stream, so that the output loop knows not
1627 * to actually output the event */
1628 GST_DEBUG_OBJECT (stream, "Marking current period has a next one");
1629 demux->input_period->has_next_period = TRUE;
1633 if (demux->priv->outputs) {
1634 GstEvent *eos = gst_event_new_eos ();
1636 GST_DEBUG_OBJECT (stream, "Stream is EOS. Stopping.");
1637 stream->state = GST_ADAPTIVE_DEMUX2_STREAM_STATE_EOS;
1639 gst_event_set_seqnum (eos, stream->demux->priv->segment_seqnum);
1640 gst_adaptive_demux2_stream_push_event (stream, eos);
1642 GST_ERROR_OBJECT (demux, "Can't push EOS on non-exposed pad");
1643 gst_adaptive_demux2_stream_error (stream);
1648 gst_adaptive_demux2_stream_reload_manifest_cb (GstAdaptiveDemux2Stream * stream)
1650 GstAdaptiveDemux *demux = stream->demux;
1652 gboolean is_live = gst_adaptive_demux_is_live (demux);
1654 stream->pending_cb_id = 0;
1656 /* Refetch the playlist now after we waited */
1657 /* FIXME: Make this manifest update async and handle it on completion */
1658 if (!is_live && gst_adaptive_demux_update_manifest (demux) == GST_FLOW_OK) {
1659 GST_DEBUG_OBJECT (demux, "Updated the playlist");
1662 /* We were called here from a timeout, so if the load function wants to loop
1663 * again, schedule an immediate callback but return G_SOURCE_REMOVE either
1665 while (gst_adaptive_demux2_stream_next_download (stream));
1667 return G_SOURCE_REMOVE;
1671 gst_adaptive_demux2_stream_on_output_space_available_cb (GstAdaptiveDemux2Stream
1674 /* If the state already moved on, the stream was stopped, or another track
1675 * already woke up and needed data */
1676 if (stream->state != GST_ADAPTIVE_DEMUX2_STREAM_STATE_WAITING_OUTPUT_SPACE)
1677 return G_SOURCE_REMOVE;
1679 GstAdaptiveDemux *demux = stream->demux;
1680 TRACKS_LOCK (demux);
1683 for (iter = stream->tracks; iter; iter = iter->next) {
1684 GstAdaptiveDemuxTrack *track = (GstAdaptiveDemuxTrack *) iter->data;
1686 /* We need to recompute the track's level_time value, as the
1687 * global output position may have advanced and reduced the
1688 * value, even without anything being dequeued yet */
1689 gst_adaptive_demux_track_update_level_locked (track);
1691 GST_DEBUG_OBJECT (stream, "track %s woken level %" GST_TIME_FORMAT
1692 " input position %" GST_TIME_FORMAT " at %" GST_TIME_FORMAT,
1693 track->stream_id, GST_TIME_ARGS (track->level_time),
1694 GST_TIME_ARGS (track->input_time),
1695 GST_TIME_ARGS (demux->priv->global_output_position));
1697 TRACKS_UNLOCK (demux);
1699 while (gst_adaptive_demux2_stream_load_a_fragment (stream));
1701 return G_SOURCE_REMOVE;
1705 gst_adaptive_demux2_stream_on_output_space_available (GstAdaptiveDemux2Stream *
1708 GstAdaptiveDemux *demux = stream->demux;
1710 stream->next_input_wakeup_time = GST_CLOCK_STIME_NONE;
1712 GST_LOG_OBJECT (stream, "Scheduling output_space_available() call");
1714 gst_adaptive_demux_loop_call (demux->priv->scheduler_task,
1715 (GSourceFunc) gst_adaptive_demux2_stream_on_output_space_available_cb,
1716 gst_object_ref (stream), (GDestroyNotify) gst_object_unref);
1720 gst_adaptive_demux2_stream_on_manifest_update (GstAdaptiveDemux2Stream * stream)
1722 GstAdaptiveDemux *demux = stream->demux;
1724 if (stream->state != GST_ADAPTIVE_DEMUX2_STREAM_STATE_WAITING_MANIFEST_UPDATE)
1727 g_assert (stream->pending_cb_id == 0);
1729 GST_LOG_OBJECT (stream, "Scheduling load_a_fragment() call");
1730 stream->pending_cb_id =
1731 gst_adaptive_demux_loop_call (demux->priv->scheduler_task,
1732 (GSourceFunc) gst_adaptive_demux2_stream_load_a_fragment,
1733 gst_object_ref (stream), (GDestroyNotify) gst_object_unref);
1737 gst_adaptive_demux2_stream_handle_playlist_eos (GstAdaptiveDemux2Stream *
1740 GstAdaptiveDemux *demux = stream->demux;
1742 if (gst_adaptive_demux_is_live (demux) && (demux->segment.rate == 1.0
1743 || gst_adaptive_demux2_stream_in_live_seek_range (demux, stream))) {
1745 if (!gst_adaptive_demux_has_next_period (demux)) {
1746 /* Wait only if we can ensure current manifest has been expired.
1747 * The meaning "we have next period" *WITH* EOS is that, current
1748 * period has been ended but we can continue to the next period */
1749 GST_DEBUG_OBJECT (stream,
1750 "Live playlist EOS - waiting for manifest update");
1751 stream->state = GST_ADAPTIVE_DEMUX2_STREAM_STATE_WAITING_MANIFEST_UPDATE;
1752 /* Clear the stream last_ret EOS state, since we're not actually EOS */
1753 if (stream->last_ret == GST_FLOW_EOS)
1754 stream->last_ret = GST_FLOW_OK;
1755 gst_adaptive_demux2_stream_wants_manifest_update (demux);
1760 gst_adaptive_demux2_stream_end_of_manifest (stream);
1764 gst_adaptive_demux2_stream_load_a_fragment (GstAdaptiveDemux2Stream * stream)
1766 GstAdaptiveDemux *demux = stream->demux;
1767 gboolean live = gst_adaptive_demux_is_live (demux);
1768 GstFlowReturn ret = GST_FLOW_OK;
1770 stream->pending_cb_id = 0;
1772 GST_LOG_OBJECT (stream, "entering, state = %d.", stream->state);
1774 switch (stream->state) {
1775 case GST_ADAPTIVE_DEMUX2_STREAM_STATE_RESTART:
1776 case GST_ADAPTIVE_DEMUX2_STREAM_STATE_START_FRAGMENT:
1777 case GST_ADAPTIVE_DEMUX2_STREAM_STATE_WAITING_LIVE:
1778 case GST_ADAPTIVE_DEMUX2_STREAM_STATE_WAITING_OUTPUT_SPACE:
1779 case GST_ADAPTIVE_DEMUX2_STREAM_STATE_WAITING_MANIFEST_UPDATE:
1780 /* Get information about the fragment to download */
1781 GST_DEBUG_OBJECT (demux, "Calling update_fragment_info");
1782 ret = gst_adaptive_demux2_stream_update_fragment_info (stream);
1783 GST_DEBUG_OBJECT (stream,
1784 "Fragment info update result: %d %s", ret, gst_flow_get_name (ret));
1786 if (ret == GST_FLOW_OK)
1787 stream->starting_fragment = TRUE;
1789 case GST_ADAPTIVE_DEMUX2_STREAM_STATE_DOWNLOADING:
1791 case GST_ADAPTIVE_DEMUX2_STREAM_STATE_EOS:
1792 GST_ERROR_OBJECT (stream,
1793 "Unexpected stream state EOS. The stream should not be running now.");
1795 case GST_ADAPTIVE_DEMUX2_STREAM_STATE_STOPPED:
1796 /* The stream was stopped. Just finish up */
1799 GST_ERROR_OBJECT (stream, "Unexpected stream state %d", stream->state);
1800 g_assert_not_reached ();
1804 if (ret == GST_FLOW_OK) {
1805 /* Wait for room in the output tracks */
1806 if (gst_adaptive_demux2_stream_wait_for_output_space (demux, stream,
1807 stream->fragment.duration)) {
1808 stream->state = GST_ADAPTIVE_DEMUX2_STREAM_STATE_WAITING_OUTPUT_SPACE;
1813 if (ret == GST_FLOW_OK) {
1814 /* wait for live fragments to be available */
1816 GstClockTime wait_time =
1817 gst_adaptive_demux2_stream_get_fragment_waiting_time (stream);
1818 if (wait_time > 0) {
1819 GST_DEBUG_OBJECT (stream,
1820 "Download waiting for %" GST_TIME_FORMAT,
1821 GST_TIME_ARGS (wait_time));
1823 stream->state = GST_ADAPTIVE_DEMUX2_STREAM_STATE_WAITING_LIVE;
1825 GST_LOG_OBJECT (stream, "Scheduling delayed load_a_fragment() call");
1826 g_assert (stream->pending_cb_id == 0);
1827 stream->pending_cb_id =
1828 gst_adaptive_demux_loop_call_delayed (demux->priv->scheduler_task,
1829 wait_time, (GSourceFunc) gst_adaptive_demux2_stream_load_a_fragment,
1830 gst_object_ref (stream), (GDestroyNotify) gst_object_unref);
1835 if (gst_adaptive_demux2_stream_download_fragment (stream) != GST_FLOW_OK) {
1836 GST_ERROR_OBJECT (demux,
1837 "Failed to begin fragment download for stream %p", stream);
1842 /* Cast to int avoids a compiler warning that
1843 * GST_ADAPTIVE_DEMUX_FLOW_LOST_SYNC is not in the GstFlowReturn enum */
1844 switch ((int) ret) {
1846 break; /* all is good, let's go */
1848 GST_DEBUG_OBJECT (stream, "EOS, checking to stop download loop");
1849 stream->last_ret = ret;
1850 gst_adaptive_demux2_stream_handle_playlist_eos (stream);
1852 case GST_ADAPTIVE_DEMUX_FLOW_LOST_SYNC:
1853 GST_DEBUG_OBJECT (stream, "Lost sync, asking reset to current position");
1854 stream->state = GST_ADAPTIVE_DEMUX2_STREAM_STATE_STOPPED;
1855 gst_adaptive_demux_handle_lost_sync (demux);
1857 case GST_FLOW_NOT_LINKED:
1859 stream->state = GST_ADAPTIVE_DEMUX2_STREAM_STATE_EOS;
1861 if (gst_adaptive_demux_period_combine_stream_flows (demux->input_period)
1862 == GST_FLOW_NOT_LINKED) {
1863 GST_ELEMENT_FLOW_ERROR (demux, ret);
1868 case GST_FLOW_FLUSHING:
1869 /* Flushing is normal, the target track might have been unselected */
1870 GST_DEBUG_OBJECT (stream, "Got flushing return. Stopping callback.");
1873 if (ret <= GST_FLOW_ERROR) {
1874 GST_WARNING_OBJECT (demux, "Error while downloading fragment");
1875 if (++stream->download_error_count > MAX_DOWNLOAD_ERROR_COUNT) {
1876 gst_adaptive_demux2_stream_error (stream);
1880 g_clear_error (&stream->last_error);
1882 /* First try to update the playlist for non-live playlists
1883 * in case the URIs have changed in the meantime. But only
1884 * try it the first time, after that we're going to wait a
1885 * a bit to not flood the server */
1886 if (stream->download_error_count == 1
1887 && !gst_adaptive_demux_is_live (demux)) {
1888 /* TODO hlsdemux had more options to this function (boolean and err) */
1889 if (gst_adaptive_demux_update_manifest (demux) == GST_FLOW_OK) {
1890 /* Retry immediately, the playlist actually has changed */
1891 GST_DEBUG_OBJECT (demux, "Updated the playlist");
1896 /* Wait half the fragment duration before retrying */
1897 GST_LOG_OBJECT (stream, "Scheduling delayed reload_manifest_cb() call");
1898 g_assert (stream->pending_cb_id == 0);
1899 stream->pending_cb_id =
1900 gst_adaptive_demux_loop_call_delayed (demux->priv->scheduler_task,
1901 stream->fragment.duration / 2,
1902 (GSourceFunc) gst_adaptive_demux2_stream_reload_manifest_cb,
1903 gst_object_ref (stream), (GDestroyNotify) gst_object_unref);
1913 gst_adaptive_demux2_stream_next_download (GstAdaptiveDemux2Stream * stream)
1915 GstAdaptiveDemux *demux = stream->demux;
1916 gboolean end_of_manifest = FALSE;
1918 GST_LOG_OBJECT (stream, "Looking for next download");
1920 /* Restarting download, figure out new position
1921 * FIXME : Move this to a separate function ? */
1922 if (G_UNLIKELY (stream->state == GST_ADAPTIVE_DEMUX2_STREAM_STATE_RESTART)) {
1923 GstClockTimeDiff stream_time = 0;
1925 GST_DEBUG_OBJECT (stream, "Activating stream after restart");
1927 if (stream->parsebin_sink != NULL) {
1928 /* If the parsebin already exists, we need to clear it out (if it doesn't,
1929 * this is the first time we've used this stream, so it's all good) */
1930 gst_adaptive_demux2_stream_push_event (stream,
1931 gst_event_new_flush_start ());
1932 gst_adaptive_demux2_stream_push_event (stream,
1933 gst_event_new_flush_stop (FALSE));
1936 GST_ADAPTIVE_DEMUX_SEGMENT_LOCK (demux);
1937 stream_time = stream->start_position;
1939 GST_DEBUG_OBJECT (stream, "Restarting stream at "
1940 "stream position %" GST_STIME_FORMAT, GST_STIME_ARGS (stream_time));
1942 if (GST_CLOCK_STIME_IS_VALID (stream_time)) {
1943 /* TODO check return */
1944 gst_adaptive_demux2_stream_seek (stream, demux->segment.rate >= 0,
1945 0, stream_time, &stream_time);
1946 stream->current_position = stream->start_position;
1948 GST_DEBUG_OBJECT (stream,
1949 "stream_time after restart seek: %" GST_STIME_FORMAT
1950 " position %" GST_STIME_FORMAT, GST_STIME_ARGS (stream_time),
1951 GST_STIME_ARGS (stream->current_position));
1954 /* Trigger (re)computation of the parsebin input segment */
1955 stream->compute_segment = TRUE;
1957 GST_ADAPTIVE_DEMUX_SEGMENT_UNLOCK (demux);
1959 stream->discont = TRUE;
1960 stream->need_header = TRUE;
1961 stream->state = GST_ADAPTIVE_DEMUX2_STREAM_STATE_START_FRAGMENT;
1964 /* Check if we're done with our segment */
1965 GST_ADAPTIVE_DEMUX_SEGMENT_LOCK (demux);
1966 if (demux->segment.rate > 0) {
1967 if (GST_CLOCK_TIME_IS_VALID (demux->segment.stop)
1968 && stream->current_position >= demux->segment.stop) {
1969 end_of_manifest = TRUE;
1972 if (GST_CLOCK_TIME_IS_VALID (demux->segment.start)
1973 && stream->current_position <= demux->segment.start) {
1974 end_of_manifest = TRUE;
1977 GST_ADAPTIVE_DEMUX_SEGMENT_UNLOCK (demux);
1979 if (end_of_manifest) {
1980 gst_adaptive_demux2_stream_end_of_manifest (stream);
1983 return gst_adaptive_demux2_stream_load_a_fragment (stream);
1987 gst_adaptive_demux2_stream_can_start (GstAdaptiveDemux2Stream * stream)
1989 GstAdaptiveDemux2StreamClass *klass =
1990 GST_ADAPTIVE_DEMUX2_STREAM_GET_CLASS (stream);
1992 if (!klass->can_start)
1994 return klass->can_start (stream);
1998 * gst_adaptive_demux2_stream_start:
1999 * @stream: a #GstAdaptiveDemux2Stream
2001 * Start the given @stream. Should be called by subclasses that previously
2002 * returned %FALSE in `GstAdaptiveDemux::stream_can_start()`
2005 gst_adaptive_demux2_stream_start (GstAdaptiveDemux2Stream * stream)
2007 GstAdaptiveDemux *demux;
2009 g_return_if_fail (stream && stream->demux);
2011 demux = stream->demux;
2013 if (stream->pending_cb_id != 0 || stream->download_active) {
2014 /* There is already something active / pending on this stream */
2015 GST_LOG_OBJECT (stream, "Stream already running");
2019 /* Some streams require a delayed start, i.e. they need more information
2020 * before they can actually be started */
2021 if (!gst_adaptive_demux2_stream_can_start (stream)) {
2022 GST_LOG_OBJECT (stream, "Stream will be started asynchronously");
2026 if (stream->state == GST_ADAPTIVE_DEMUX2_STREAM_STATE_EOS) {
2027 GST_LOG_OBJECT (stream, "Stream is EOS already");
2031 if (stream->state == GST_ADAPTIVE_DEMUX2_STREAM_STATE_STOPPED ||
2032 stream->state == GST_ADAPTIVE_DEMUX2_STREAM_STATE_RESTART) {
2033 GST_LOG_OBJECT (stream, "Activating stream. Current state %d",
2035 stream->last_ret = GST_FLOW_OK;
2037 if (stream->state == GST_ADAPTIVE_DEMUX2_STREAM_STATE_STOPPED)
2038 stream->state = GST_ADAPTIVE_DEMUX2_STREAM_STATE_START_FRAGMENT;
2041 GST_LOG_OBJECT (stream, "Scheduling next_download() call");
2042 stream->pending_cb_id =
2043 gst_adaptive_demux_loop_call (demux->priv->scheduler_task,
2044 (GSourceFunc) gst_adaptive_demux2_stream_next_download,
2045 gst_object_ref (stream), (GDestroyNotify) gst_object_unref);
2049 gst_adaptive_demux2_stream_stop (GstAdaptiveDemux2Stream * stream)
2051 GstAdaptiveDemux *demux = stream->demux;
2053 GST_DEBUG_OBJECT (stream, "Stopping stream (from state %d)", stream->state);
2054 stream->state = GST_ADAPTIVE_DEMUX2_STREAM_STATE_STOPPED;
2056 if (stream->pending_cb_id != 0) {
2057 gst_adaptive_demux_loop_cancel_call (demux->priv->scheduler_task,
2058 stream->pending_cb_id);
2059 stream->pending_cb_id = 0;
2062 /* Cancel and drop the existing download request */
2063 downloadhelper_cancel_request (demux->download_helper,
2064 stream->download_request);
2065 download_request_unref (stream->download_request);
2066 stream->downloading_header = stream->downloading_index = FALSE;
2067 stream->download_request = download_request_new ();
2068 stream->download_active = FALSE;
2070 stream->next_input_wakeup_time = GST_CLOCK_STIME_NONE;
2074 gst_adaptive_demux2_stream_is_running (GstAdaptiveDemux2Stream * stream)
2076 if (stream->state == GST_ADAPTIVE_DEMUX2_STREAM_STATE_STOPPED)
2078 if (stream->state == GST_ADAPTIVE_DEMUX2_STREAM_STATE_RESTART)
2080 if (stream->state == GST_ADAPTIVE_DEMUX2_STREAM_STATE_EOS)
2086 gst_adaptive_demux2_stream_is_selected_locked (GstAdaptiveDemux2Stream * stream)
2090 for (tmp = stream->tracks; tmp; tmp = tmp->next) {
2091 GstAdaptiveDemuxTrack *track = tmp->data;
2092 if (track->selected)
2100 * gst_adaptive_demux2_stream_is_selected:
2101 * @stream: A #GstAdaptiveDemux2Stream
2103 * Returns: %TRUE if any of the tracks targetted by @stream is selected
2106 gst_adaptive_demux2_stream_is_selected (GstAdaptiveDemux2Stream * stream)
2110 g_return_val_if_fail (stream && stream->demux, FALSE);
2112 TRACKS_LOCK (stream->demux);
2113 ret = gst_adaptive_demux2_stream_is_selected_locked (stream);
2114 TRACKS_UNLOCK (stream->demux);
2119 /* Called from the scheduler task */
2121 gst_adaptive_demux2_stream_get_presentation_offset (GstAdaptiveDemux2Stream *
2124 GstAdaptiveDemux2StreamClass *klass =
2125 GST_ADAPTIVE_DEMUX2_STREAM_GET_CLASS (stream);
2127 if (klass->get_presentation_offset == NULL)
2130 return klass->get_presentation_offset (stream);
2134 gst_adaptive_demux2_stream_update_fragment_info (GstAdaptiveDemux2Stream *
2137 GstAdaptiveDemux2StreamClass *klass =
2138 GST_ADAPTIVE_DEMUX2_STREAM_GET_CLASS (stream);
2141 g_return_val_if_fail (klass->update_fragment_info != NULL, GST_FLOW_ERROR);
2143 /* Make sure the sub-class will update bitrate, or else
2145 stream->fragment.finished = FALSE;
2147 GST_LOG_OBJECT (stream, "position %" GST_TIME_FORMAT,
2148 GST_TIME_ARGS (stream->current_position));
2150 ret = klass->update_fragment_info (stream);
2152 GST_LOG_OBJECT (stream, "ret:%s uri:%s",
2153 gst_flow_get_name (ret), stream->fragment.uri);
2154 if (ret == GST_FLOW_OK) {
2155 GST_LOG_OBJECT (stream,
2156 "stream_time %" GST_STIME_FORMAT " duration:%" GST_TIME_FORMAT,
2157 GST_STIME_ARGS (stream->fragment.stream_time),
2158 GST_TIME_ARGS (stream->fragment.duration));
2159 GST_LOG_OBJECT (stream,
2160 "range start:%" G_GINT64_FORMAT " end:%" G_GINT64_FORMAT,
2161 stream->fragment.range_start, stream->fragment.range_end);
2167 static GstFlowReturn
2168 gst_adaptive_demux2_stream_data_received_default (GstAdaptiveDemux2Stream *
2169 stream, GstBuffer * buffer)
2171 return gst_adaptive_demux2_stream_push_buffer (stream, buffer);
2174 static GstFlowReturn
2175 gst_adaptive_demux2_stream_finish_fragment_default (GstAdaptiveDemux2Stream *
2178 /* No need to advance, this isn't a real fragment */
2179 if (G_UNLIKELY (stream->downloading_header || stream->downloading_index))
2182 return gst_adaptive_demux2_stream_advance_fragment (stream,
2183 stream->fragment.duration);
2186 /* must be called from the scheduler */
2188 gst_adaptive_demux2_stream_has_next_fragment (GstAdaptiveDemux2Stream * stream)
2190 GstAdaptiveDemux2StreamClass *klass =
2191 GST_ADAPTIVE_DEMUX2_STREAM_GET_CLASS (stream);
2192 gboolean ret = TRUE;
2194 if (klass->has_next_fragment)
2195 ret = klass->has_next_fragment (stream);
2200 /* must be called from the scheduler */
2202 gst_adaptive_demux2_stream_seek (GstAdaptiveDemux2Stream * stream,
2203 gboolean forward, GstSeekFlags flags,
2204 GstClockTimeDiff ts, GstClockTimeDiff * final_ts)
2206 GstAdaptiveDemux2StreamClass *klass =
2207 GST_ADAPTIVE_DEMUX2_STREAM_GET_CLASS (stream);
2209 if (klass->stream_seek)
2210 return klass->stream_seek (stream, forward, flags, ts, final_ts);
2211 return GST_FLOW_ERROR;
2215 gst_adaptive_demux2_stream_select_bitrate (GstAdaptiveDemux *
2216 demux, GstAdaptiveDemux2Stream * stream, guint64 bitrate)
2218 GstAdaptiveDemux2StreamClass *klass =
2219 GST_ADAPTIVE_DEMUX2_STREAM_GET_CLASS (stream);
2221 if (klass->select_bitrate)
2222 return klass->select_bitrate (stream, bitrate);
2227 gst_adaptive_demux2_stream_get_fragment_waiting_time (GstAdaptiveDemux2Stream *
2230 GstAdaptiveDemux2StreamClass *klass =
2231 GST_ADAPTIVE_DEMUX2_STREAM_GET_CLASS (stream);
2233 if (klass->get_fragment_waiting_time)
2234 return klass->get_fragment_waiting_time (stream);
2238 /* must be called from the scheduler */
2239 /* Called from: the ::finish_fragment() handlers when an *actual* fragment is
2242 * @duration: Is the duration of the advancement starting from
2243 * stream->current_position which might not be the fragment duration after a
2247 gst_adaptive_demux2_stream_advance_fragment (GstAdaptiveDemux2Stream * stream,
2248 GstClockTime duration)
2250 if (stream->last_ret != GST_FLOW_OK)
2251 return stream->last_ret;
2253 GstAdaptiveDemux2StreamClass *klass =
2254 GST_ADAPTIVE_DEMUX2_STREAM_GET_CLASS (stream);
2255 GstAdaptiveDemux *demux = stream->demux;
2256 GstFlowReturn ret = GST_FLOW_OK;
2258 g_assert (klass->advance_fragment != NULL);
2260 GST_LOG_OBJECT (stream,
2261 "stream_time %" GST_STIME_FORMAT " duration:%" GST_TIME_FORMAT,
2262 GST_STIME_ARGS (stream->fragment.stream_time), GST_TIME_ARGS (duration));
2264 stream->download_error_count = 0;
2265 g_clear_error (&stream->last_error);
2268 /* FIXME - url has no indication of byte ranges for subsegments */
2269 /* FIXME: Reenable statistics sending? */
2270 gst_element_post_message (GST_ELEMENT_CAST (demux),
2271 gst_message_new_element (GST_OBJECT_CAST (demux),
2272 gst_structure_new (GST_ADAPTIVE_DEMUX_STATISTICS_MESSAGE_NAME,
2273 "manifest-uri", G_TYPE_STRING,
2274 demux->manifest_uri, "uri", G_TYPE_STRING,
2275 stream->fragment.uri, "fragment-start-time",
2276 GST_TYPE_CLOCK_TIME, stream->download_start_time,
2277 "fragment-stop-time", GST_TYPE_CLOCK_TIME,
2278 gst_util_get_timestamp (), "fragment-size", G_TYPE_UINT64,
2279 stream->download_total_bytes, "fragment-download-time",
2280 GST_TYPE_CLOCK_TIME, stream->last_download_time, NULL)));
2283 /* Don't update to the end of the segment if in reverse playback */
2284 GST_ADAPTIVE_DEMUX_SEGMENT_LOCK (demux);
2285 if (GST_CLOCK_TIME_IS_VALID (duration) && demux->segment.rate > 0) {
2286 stream->parse_segment.position += duration;
2287 stream->current_position += duration;
2289 GST_DEBUG_OBJECT (stream,
2290 "stream position now %" GST_TIME_FORMAT,
2291 GST_TIME_ARGS (stream->current_position));
2293 GST_ADAPTIVE_DEMUX_SEGMENT_UNLOCK (demux);
2295 /* When advancing with a non 1.0 rate on live streams, we need to check
2296 * the live seeking range again to make sure we can still advance to
2298 if (demux->segment.rate != 1.0 && gst_adaptive_demux_is_live (demux)) {
2299 if (!gst_adaptive_demux2_stream_in_live_seek_range (demux, stream))
2302 ret = klass->advance_fragment (stream);
2303 } else if (gst_adaptive_demux_is_live (demux)
2304 || gst_adaptive_demux2_stream_has_next_fragment (stream)) {
2305 ret = klass->advance_fragment (stream);
2310 stream->download_start_time =
2311 GST_TIME_AS_USECONDS (gst_adaptive_demux2_get_monotonic_time (demux));
2313 /* Always check if we need to switch bitrate on OK, or when live
2314 * (it's normal to have EOS on advancing in live when we hit the
2315 * end of the manifest) */
2316 if (ret == GST_FLOW_OK || gst_adaptive_demux_is_live (demux)) {
2317 GST_DEBUG_OBJECT (stream, "checking if stream requires bitrate change");
2318 if (gst_adaptive_demux2_stream_select_bitrate (demux, stream,
2319 gst_adaptive_demux2_stream_update_current_bitrate (stream))) {
2320 GST_DEBUG_OBJECT (stream, "Bitrate changed. Returning FLOW_SWITCH");
2321 stream->need_header = TRUE;
2322 ret = (GstFlowReturn) GST_ADAPTIVE_DEMUX_FLOW_SWITCH;
2326 stream->last_ret = ret;
2327 return stream->last_ret;
2330 /* TRACKS_LOCK held */
2331 static GstAdaptiveDemuxTrack *
2332 gst_adaptive_demux2_stream_find_track_of_type (GstAdaptiveDemux2Stream * stream,
2333 GstStreamType stream_type)
2337 for (iter = stream->tracks; iter; iter = iter->next) {
2338 GstAdaptiveDemuxTrack *track = iter->data;
2340 if (track->type == stream_type)
2347 /* TRACKS lock held */
2349 gst_adaptive_demux2_stream_update_track_ids (GstAdaptiveDemux2Stream * stream)
2353 GST_DEBUG_OBJECT (stream, "Updating track information from collection");
2355 for (i = 0; i < gst_stream_collection_get_size (stream->stream_collection);
2357 GstStream *gst_stream =
2358 gst_stream_collection_get_stream (stream->stream_collection, i);
2359 GstStreamType stream_type = gst_stream_get_stream_type (gst_stream);
2360 GstAdaptiveDemuxTrack *track;
2362 if (stream_type == GST_STREAM_TYPE_UNKNOWN)
2364 track = gst_adaptive_demux2_stream_find_track_of_type (stream, stream_type);
2366 GST_DEBUG_OBJECT (stream,
2367 "We don't have an existing track to handle stream %" GST_PTR_FORMAT,
2372 if (track->upstream_stream_id)
2373 g_free (track->upstream_stream_id);
2374 track->upstream_stream_id =
2375 g_strdup (gst_stream_get_stream_id (gst_stream));
2381 tags_have_language_info (GstTagList * tags)
2383 const gchar *language = NULL;
2388 if (gst_tag_list_peek_string_index (tags, GST_TAG_LANGUAGE_CODE, 0,
2391 if (gst_tag_list_peek_string_index (tags, GST_TAG_LANGUAGE_NAME, 0,
2399 can_handle_collection (GstAdaptiveDemux2Stream * stream,
2400 GstStreamCollection * collection)
2403 guint nb_audio, nb_video, nb_text;
2404 gboolean have_audio_languages = TRUE;
2405 gboolean have_text_languages = TRUE;
2407 nb_audio = nb_video = nb_text = 0;
2409 for (i = 0; i < gst_stream_collection_get_size (collection); i++) {
2410 GstStream *gst_stream = gst_stream_collection_get_stream (collection, i);
2411 GstTagList *tags = gst_stream_get_tags (gst_stream);
2413 GST_DEBUG_OBJECT (stream,
2414 "Internal collection stream #%d %" GST_PTR_FORMAT, i, gst_stream);
2415 switch (gst_stream_get_stream_type (gst_stream)) {
2416 case GST_STREAM_TYPE_AUDIO:
2417 have_audio_languages &= tags_have_language_info (tags);
2420 case GST_STREAM_TYPE_VIDEO:
2423 case GST_STREAM_TYPE_TEXT:
2424 have_text_languages &= tags_have_language_info (tags);
2431 gst_tag_list_unref (tags);
2434 /* Check that we either have at most 1 of each track type, or that
2435 * we have language tags for each to tell which is which */
2437 (nb_audio > 1 && !have_audio_languages) ||
2438 (nb_text > 1 && !have_text_languages)) {
2440 ("Collection can't be handled (nb_audio:%d, nb_video:%d, nb_text:%d)",
2441 nb_audio, nb_video, nb_text);
2448 /* Called from the demuxer when it receives a GstStreamCollection on the bus
2449 * for this stream. */
2450 /* TRACKS lock held */
2452 gst_adaptive_demux2_stream_handle_collection (GstAdaptiveDemux2Stream * stream,
2453 GstStreamCollection * collection, gboolean * had_pending_tracks)
2455 g_assert (had_pending_tracks != NULL);
2457 /* Check whether the collection is "sane" or not.
2459 * In the context of adaptive streaming, we can only handle multiplexed
2460 * content where the output sub-streams can be matched reliably to the various
2461 * tracks. That is, only a single stream of each type, or if there are
2462 * multiple audio/subtitle tracks, they can be differentiated by language
2463 * (and possibly in the future by codec).
2465 if (!can_handle_collection (stream, collection)) {
2469 /* Store the collection on the stream */
2470 gst_object_replace ((GstObject **) & stream->stream_collection,
2471 (GstObject *) collection);
2473 /* If stream is marked as having pending_tracks, ask the subclass to
2474 * handle that and create the tracks now */
2475 if (stream->pending_tracks) {
2476 GstAdaptiveDemux2StreamClass *klass =
2477 GST_ADAPTIVE_DEMUX2_STREAM_GET_CLASS (stream);
2478 g_assert (klass->create_tracks);
2479 klass->create_tracks (stream);
2480 stream->pending_tracks = FALSE;
2481 *had_pending_tracks = TRUE;
2483 g_assert (stream->tracks);
2485 /* Now we should have assigned tracks, match them to the
2486 * collection and update the pending upstream stream_id
2487 * for each of them based on the collection information. */
2488 gst_adaptive_demux2_stream_update_track_ids (stream);
2495 _update_average_bitrate (GstAdaptiveDemux2Stream * stream, guint64 new_bitrate)
2497 gint index = stream->moving_index % NUM_LOOKBACK_FRAGMENTS;
2499 stream->moving_bitrate -= stream->fragment_bitrates[index];
2500 stream->fragment_bitrates[index] = new_bitrate;
2501 stream->moving_bitrate += new_bitrate;
2503 stream->moving_index += 1;
2505 if (stream->moving_index > NUM_LOOKBACK_FRAGMENTS)
2506 return stream->moving_bitrate / NUM_LOOKBACK_FRAGMENTS;
2507 return stream->moving_bitrate / stream->moving_index;
2511 gst_adaptive_demux2_stream_update_current_bitrate (GstAdaptiveDemux2Stream *
2514 guint64 average_bitrate;
2515 guint64 fragment_bitrate;
2516 guint connection_speed, min_bitrate, max_bitrate, target_download_rate;
2518 fragment_bitrate = stream->last_bitrate;
2519 GST_DEBUG_OBJECT (stream, "Download bitrate is : %" G_GUINT64_FORMAT " bps",
2522 average_bitrate = _update_average_bitrate (stream, fragment_bitrate);
2524 GST_INFO_OBJECT (stream,
2525 "last fragment bitrate was %" G_GUINT64_FORMAT, fragment_bitrate);
2526 GST_INFO_OBJECT (stream,
2527 "Last %u fragments average bitrate is %" G_GUINT64_FORMAT,
2528 NUM_LOOKBACK_FRAGMENTS, average_bitrate);
2530 /* Conservative approach, make sure we don't upgrade too fast */
2531 stream->current_download_rate = MIN (average_bitrate, fragment_bitrate);
2533 /* For the video stream, update the demuxer reported download
2534 * rate. FIXME: Move all bandwidth estimation to the
2535 * download helper and make it the demuxer's responsibility
2536 * to select the right set of things to download within
2538 GstAdaptiveDemux *demux = stream->demux;
2539 GST_OBJECT_LOCK (demux);
2541 /* If this is stream containing our video, update the overall demuxer
2542 * reported bitrate and notify, to give the application a
2543 * chance to choose a new connection-bitrate */
2544 if ((stream->stream_type & GST_STREAM_TYPE_VIDEO) != 0) {
2545 demux->current_download_rate = stream->current_download_rate;
2546 GST_OBJECT_UNLOCK (demux);
2547 g_object_notify (G_OBJECT (demux), "current-bandwidth");
2548 GST_OBJECT_LOCK (demux);
2551 connection_speed = demux->connection_speed;
2552 min_bitrate = demux->min_bitrate;
2553 max_bitrate = demux->max_bitrate;
2554 GST_OBJECT_UNLOCK (demux);
2556 if (connection_speed) {
2557 GST_LOG_OBJECT (stream, "connection-speed is set to %u kbps, using it",
2558 connection_speed / 1000);
2559 return connection_speed;
2562 /* No explicit connection_speed, so choose the new variant to use as a
2563 * fraction of the measured download rate */
2564 target_download_rate =
2565 CLAMP (stream->current_download_rate, 0,
2566 G_MAXUINT) * demux->bandwidth_target_ratio;
2568 GST_DEBUG_OBJECT (stream, "Bitrate after target ratio limit (%0.2f): %u",
2569 demux->bandwidth_target_ratio, target_download_rate);
2572 /* Debugging code, modulate the bitrate every few fragments */
2574 static guint ctr = 0;
2576 GST_INFO_OBJECT (stream, "Halving reported bitrate for debugging");
2577 target_download_rate /= 2;
2583 if (min_bitrate > 0 && target_download_rate < min_bitrate) {
2584 target_download_rate = min_bitrate;
2585 GST_LOG_OBJECT (stream, "Bitrate adjusted due to min-bitrate : %u bits/s",
2589 if (max_bitrate > 0 && target_download_rate > max_bitrate) {
2590 target_download_rate = max_bitrate;
2591 GST_LOG_OBJECT (stream, "Bitrate adjusted due to max-bitrate : %u bits/s",
2595 GST_DEBUG_OBJECT (stream, "Returning target download rate of %u bps",
2596 target_download_rate);
2598 return target_download_rate;
2602 gst_adaptive_demux2_stream_fragment_clear (GstAdaptiveDemux2StreamFragment * f)
2609 g_free (f->header_uri);
2610 f->header_uri = NULL;
2611 f->header_range_start = 0;
2612 f->header_range_end = -1;
2614 g_free (f->index_uri);
2615 f->index_uri = NULL;
2616 f->index_range_start = 0;
2617 f->index_range_end = -1;
2619 f->stream_time = GST_CLOCK_STIME_NONE;
2620 f->duration = GST_CLOCK_TIME_NONE;
2621 f->finished = FALSE;