mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 20:21:24 +00:00
a03f3df626
Change the way streams are woken up to download more data. Instead of checking the level on tracks that are being output as data is dequeued, calculate a 'wakeup time' at which it should download more data, and wake up the stream when the global output position crosses that threshold. For efficiency, compute the earliest wakeup time for all streams and store it on the period, so the output loop can quickly check only a single value to decide if something needs waking up. Does the same buffering as the previous method, but ensures that as we approach the end of one period, the next period continues incrementally downloading data so that it is fully buffered when the period starts. Fixes issues with multi-period VOD content where download of the second period resumes only after the first period is completely drained. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3055>
800 lines
25 KiB
C
800 lines
25 KiB
C
/* GStreamer
|
|
*
|
|
* Copyright (C) 2014 Samsung Electronics. All rights reserved.
|
|
* Author: Thiago Santos <thiagoss@osg.samsung.com>
|
|
*
|
|
* Copyright (C) 2021-2022 Centricular Ltd
|
|
* Author: Edward Hervey <edward@centricular.com>
|
|
* Author: Jan Schmidt <jan@centricular.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#ifndef _GST_ADAPTIVE_DEMUX_H_
|
|
#define _GST_ADAPTIVE_DEMUX_H_
|
|
|
|
#include <gst/gst.h>
|
|
#include <gst/base/gstqueuearray.h>
|
|
#include <gst/app/gstappsrc.h>
|
|
#include "downloadhelper.h"
|
|
#include "downloadrequest.h"
|
|
|
|
#include "gstadaptivedemuxutils.h"
|
|
|
|
G_BEGIN_DECLS
|
|
|
|
#define GST_TYPE_ADAPTIVE_DEMUX \
|
|
(gst_adaptive_demux_ng_get_type())
|
|
#define GST_ADAPTIVE_DEMUX(obj) \
|
|
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ADAPTIVE_DEMUX,GstAdaptiveDemux))
|
|
#define GST_ADAPTIVE_DEMUX_CLASS(klass) \
|
|
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ADAPTIVE_DEMUX,GstAdaptiveDemuxClass))
|
|
#define GST_ADAPTIVE_DEMUX_GET_CLASS(obj) \
|
|
(G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_ADAPTIVE_DEMUX,GstAdaptiveDemuxClass))
|
|
#define GST_IS_ADAPTIVE_DEMUX(obj) \
|
|
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ADAPTIVE_DEMUX))
|
|
#define GST_IS_ADAPTIVE_DEMUX_CLASS(obj) \
|
|
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ADAPTIVE_DEMUX))
|
|
#define GST_ADAPTIVE_DEMUX_CAST(obj) ((GstAdaptiveDemux *)obj)
|
|
|
|
#define GST_TYPE_ADAPTIVE_DEMUX2_STREAM \
|
|
(gst_adaptive_demux2_stream_get_type())
|
|
#define GST_ADAPTIVE_DEMUX2_STREAM(obj) \
|
|
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ADAPTIVE_DEMUX2_STREAM,GstAdaptiveDemux2Stream))
|
|
#define GST_ADAPTIVE_DEMUX2_STREAM_CAST(obj) ((GstAdaptiveDemux2Stream *)obj)
|
|
|
|
typedef struct _GstAdaptiveDemux2Stream GstAdaptiveDemux2Stream;
|
|
typedef GstObjectClass GstAdaptiveDemux2StreamClass;
|
|
|
|
|
|
/**
|
|
* GST_ADAPTIVE_DEMUX_SINK_NAME:
|
|
*
|
|
* The name of the templates for the sink pad.
|
|
*/
|
|
#define GST_ADAPTIVE_DEMUX_SINK_NAME "sink"
|
|
|
|
/**
|
|
* GST_ADAPTIVE_DEMUX_SINK_PAD:
|
|
* @obj: a #GstAdaptiveDemux
|
|
*
|
|
* Gives the pointer to the sink #GstPad object of the element.
|
|
*/
|
|
#define GST_ADAPTIVE_DEMUX_SINK_PAD(obj) (((GstAdaptiveDemux *) (obj))->sinkpad)
|
|
|
|
#define GST_ADAPTIVE_DEMUX_IN_TRICKMODE_KEY_UNITS(obj) ((((GstAdaptiveDemux*)(obj))->segment.flags & GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS) == GST_SEGMENT_FLAG_TRICKMODE_KEY_UNITS)
|
|
|
|
#define GST_ADAPTIVE_DEMUX2_STREAM_NEED_HEADER(obj) (((GstAdaptiveDemux2Stream *) (obj))->need_header)
|
|
|
|
/**
|
|
* GST_ADAPTIVE_DEMUX_STATISTICS_MESSAGE_NAME:
|
|
*
|
|
* Name of the ELEMENT type messages posted by dashdemux with statistics.
|
|
*
|
|
* Since: 1.6
|
|
*/
|
|
#define GST_ADAPTIVE_DEMUX_STATISTICS_MESSAGE_NAME "adaptive-streaming-statistics"
|
|
|
|
#define GST_ELEMENT_ERROR_FROM_ERROR(el, msg, err) G_STMT_START { \
|
|
gchar *__dbg = g_strdup_printf ("%s: %s", msg, err->message); \
|
|
GST_WARNING_OBJECT (el, "error: %s", __dbg); \
|
|
gst_element_message_full (GST_ELEMENT(el), GST_MESSAGE_ERROR, \
|
|
err->domain, err->code, \
|
|
NULL, __dbg, __FILE__, GST_FUNCTION, __LINE__); \
|
|
g_clear_error (&err); \
|
|
} G_STMT_END
|
|
|
|
/* DEPRECATED */
|
|
#define GST_ADAPTIVE_DEMUX_FLOW_END_OF_FRAGMENT GST_FLOW_CUSTOM_SUCCESS_1
|
|
|
|
/* Current fragment download should be aborted and restarted. The parent class
|
|
* will call ::update_fragment_info() again to get the updated information.
|
|
*/
|
|
#define GST_ADAPTIVE_DEMUX_FLOW_RESTART_FRAGMENT GST_FLOW_CUSTOM_SUCCESS_2
|
|
|
|
/* The live stream has lost synchronization and the demuxer needs to be resetted */
|
|
#define GST_ADAPTIVE_DEMUX_FLOW_LOST_SYNC GST_FLOW_CUSTOM_SUCCESS_2 + 1
|
|
|
|
typedef enum _GstAdaptiveDemux2StreamState GstAdaptiveDemux2StreamState;
|
|
|
|
typedef struct _GstAdaptiveDemux2StreamFragment GstAdaptiveDemux2StreamFragment;
|
|
typedef struct _GstAdaptiveDemuxTrack GstAdaptiveDemuxTrack;
|
|
typedef struct _GstAdaptiveDemuxPeriod GstAdaptiveDemuxPeriod;
|
|
typedef struct _GstAdaptiveDemux GstAdaptiveDemux;
|
|
typedef struct _GstAdaptiveDemuxClass GstAdaptiveDemuxClass;
|
|
typedef struct _GstAdaptiveDemuxPrivate GstAdaptiveDemuxPrivate;
|
|
|
|
struct _GstAdaptiveDemux2StreamFragment
|
|
{
|
|
/* The period-local stream time for the given fragment. */
|
|
GstClockTimeDiff stream_time;
|
|
GstClockTime duration;
|
|
|
|
gchar *uri;
|
|
gint64 range_start;
|
|
gint64 range_end;
|
|
|
|
/* when chunked downloading is used, may be be updated need_another_chunk() */
|
|
gint chunk_size;
|
|
|
|
/* when headers are needed */
|
|
gchar *header_uri;
|
|
gint64 header_range_start;
|
|
gint64 header_range_end;
|
|
|
|
/* when index is needed */
|
|
gchar *index_uri;
|
|
gint64 index_range_start;
|
|
gint64 index_range_end;
|
|
|
|
gboolean finished;
|
|
};
|
|
|
|
struct _GstAdaptiveDemuxTrack
|
|
{
|
|
gint ref_count;
|
|
|
|
/* Demux */
|
|
GstAdaptiveDemux *demux;
|
|
|
|
/* Stream type */
|
|
GstStreamType type;
|
|
|
|
/* Stream flags */
|
|
GstStreamFlags flags;
|
|
|
|
/* Unique identifier */
|
|
gchar *stream_id;
|
|
|
|
/* Period number this track belongs
|
|
* to (MAXINT if not assigned to a period yet)
|
|
*/
|
|
guint period_num;
|
|
|
|
/* Unique identifier of the internal stream produced
|
|
* by parsebin for the Stream this track comes from */
|
|
gchar *upstream_stream_id;
|
|
|
|
/* Generic *elementary stream* caps */
|
|
GstCaps *generic_caps;
|
|
|
|
/* Generic metadata */
|
|
GstTagList *tags;
|
|
|
|
/* The stream object */
|
|
GstStream *stream_object;
|
|
|
|
/* If TRUE, this track should be filled */
|
|
gboolean selected;
|
|
|
|
/* If TRUE, this track is currently being outputted */
|
|
gboolean active;
|
|
|
|
/* If TRUE, it is no longer selected but still being outputted. */
|
|
gboolean draining;
|
|
|
|
/* FIXME : Replace by actual track element */
|
|
GstElement *element;
|
|
|
|
/* The level at which 100% buffering is achieved */
|
|
GstClockTime buffering_threshold;
|
|
|
|
/* The sinkpad receives parsed elementary stream */
|
|
GstPad *sinkpad;
|
|
|
|
/* The pending parsebin source pad (used in case streams from parsebin get updated) (ref taken) */
|
|
GstPad *pending_srcpad;
|
|
|
|
/* Data storage */
|
|
GstQueueArray *queue;
|
|
|
|
/* Sticky event storage for this track */
|
|
GstEventStore sticky_events;
|
|
|
|
/* ============== */
|
|
/* Input tracking */
|
|
|
|
/* The track received EOS */
|
|
gboolean eos;
|
|
|
|
/* Input segment and time (in running time) */
|
|
GstSegment input_segment;
|
|
GstClockTimeDiff input_time;
|
|
GstClockTimeDiff lowest_input_time;
|
|
guint64 input_segment_seqnum;
|
|
|
|
/* ================= */
|
|
/* Contents tracking */
|
|
|
|
/* Current level of queue in bytes and time */
|
|
guint64 level_bytes;
|
|
GstClockTime level_time;
|
|
|
|
/* =============== */
|
|
/* Output tracking */
|
|
|
|
/* Is the output thread waiting for data on this track ? */
|
|
gboolean waiting_add;
|
|
|
|
/* If TRUE, the next pending GstSegment running time should be updated to the
|
|
* time stored in update_next_segment_run_ts */
|
|
gboolean update_next_segment;
|
|
|
|
/* Output segment and time (in running time) */
|
|
GstSegment output_segment;
|
|
GstClockTimeDiff output_time;
|
|
|
|
/* Track position and duration for emitting gap
|
|
* events */
|
|
GstClockTime gap_position;
|
|
GstClockTime gap_duration;
|
|
|
|
/* Next running time position pending in queue */
|
|
GstClockTimeDiff next_position;
|
|
|
|
/* If the next output buffer should be marked discont */
|
|
gboolean output_discont;
|
|
};
|
|
|
|
enum _GstAdaptiveDemux2StreamState {
|
|
GST_ADAPTIVE_DEMUX2_STREAM_STATE_STOPPED, /* Stream was stopped */
|
|
GST_ADAPTIVE_DEMUX2_STREAM_STATE_RESTART, /* Stream stopped but needs restart logic */
|
|
GST_ADAPTIVE_DEMUX2_STREAM_STATE_START_FRAGMENT,
|
|
GST_ADAPTIVE_DEMUX2_STREAM_STATE_WAITING_LIVE,
|
|
GST_ADAPTIVE_DEMUX2_STREAM_STATE_WAITING_OUTPUT_SPACE,
|
|
GST_ADAPTIVE_DEMUX2_STREAM_STATE_WAITING_MANIFEST_UPDATE,
|
|
GST_ADAPTIVE_DEMUX2_STREAM_STATE_DOWNLOADING,
|
|
GST_ADAPTIVE_DEMUX2_STREAM_STATE_EOS,
|
|
GST_ADAPTIVE_DEMUX2_STREAM_STATE_ERRORED
|
|
};
|
|
|
|
struct _GstAdaptiveDemux2Stream
|
|
{
|
|
GstObject object;
|
|
|
|
/* FIXME : transition to gstobject->parent */
|
|
GstAdaptiveDemux *demux;
|
|
|
|
/* The period to which the stream belongs, set when adding the stream to the
|
|
* demuxer */
|
|
GstAdaptiveDemuxPeriod *period;
|
|
|
|
/* The tracks this stream targets */
|
|
GList *tracks;
|
|
|
|
/* The internal parsebin, forward data to track */
|
|
GstElement *parsebin;
|
|
GstPad *parsebin_sink;
|
|
|
|
gulong pad_added_id, pad_removed_id;
|
|
|
|
GstSegment parse_segment;
|
|
|
|
/* TRUE if the current stream GstSegment should be sent downstream */
|
|
gboolean send_segment;
|
|
/* TRUE if the stream GstSegment requires recalculation (from demuxer
|
|
segment) */
|
|
gboolean compute_segment;
|
|
/* first_and_live applies to compute_segment */
|
|
gboolean first_and_live;
|
|
|
|
/* When restarting, what is the target position (in demux segment) to
|
|
* begin at */
|
|
GstClockTime start_position;
|
|
|
|
/* Track the current position (in demux segment) of the current fragment */
|
|
GstClockTime current_position;
|
|
|
|
GstCaps *pending_caps;
|
|
GstTagList *pending_tags;
|
|
|
|
GList *pending_events;
|
|
|
|
GstFlowReturn last_ret;
|
|
GError *last_error;
|
|
|
|
gboolean discont;
|
|
|
|
/* download tooling */
|
|
gboolean need_header;
|
|
gboolean need_index;
|
|
|
|
gboolean downloading_header;
|
|
gboolean downloading_index;
|
|
|
|
/* persistent, reused download request for fragment data */
|
|
DownloadRequest *download_request;
|
|
|
|
GstAdaptiveDemux2StreamState state;
|
|
guint pending_cb_id;
|
|
gboolean download_active;
|
|
/* The (global output) time at which this stream should be woken
|
|
* to download more input */
|
|
GstClockTimeDiff next_input_wakeup_time;
|
|
|
|
guint last_status_code;
|
|
|
|
gboolean pending_tracks; /* if we need to discover tracks dynamically for this stream */
|
|
gboolean download_finished;
|
|
gboolean cancelled;
|
|
gboolean replaced; /* replaced in a bitrate switch (used with cancelled) */
|
|
|
|
gboolean starting_fragment;
|
|
gboolean first_fragment_buffer;
|
|
gint64 download_start_time;
|
|
gint64 download_total_bytes;
|
|
gint64 download_end_offset;
|
|
guint64 current_download_rate;
|
|
|
|
/* bitrate of the previous fragment (pre-queue2) */
|
|
guint64 last_bitrate;
|
|
|
|
/* Total last download time, from request to completion */
|
|
GstClockTime last_download_time;
|
|
|
|
/* Average for the last fragments */
|
|
guint64 moving_bitrate;
|
|
guint moving_index;
|
|
guint64 *fragment_bitrates;
|
|
|
|
GstAdaptiveDemux2StreamFragment fragment;
|
|
|
|
guint download_error_count;
|
|
|
|
/* Last collection provided by parsebin */
|
|
GstStreamCollection *stream_collection;
|
|
|
|
/* OR'd set of stream types in this stream */
|
|
GstStreamType stream_type;
|
|
};
|
|
|
|
/**
|
|
* GstAdaptiveDemuxPeriod:
|
|
*
|
|
* The opaque #GstAdaptiveDemuxPeriod data structure. */
|
|
struct _GstAdaptiveDemuxPeriod
|
|
{
|
|
gint ref_count;
|
|
|
|
GstAdaptiveDemux *demux;
|
|
|
|
/* TRUE if the streams of this period were prepared and can be started */
|
|
gboolean prepared;
|
|
|
|
|
|
/* TRUE if there is another period after this one */
|
|
gboolean has_next_period;
|
|
|
|
/* An increasing unique identifier for the period.
|
|
*
|
|
* Note: unrelated to dash period id (which can be identical across
|
|
* periods) */
|
|
guint period_num;
|
|
|
|
/* The list of GstAdaptiveDemux2Stream (ref hold) */
|
|
GList *streams;
|
|
|
|
/* Current collection */
|
|
GstStreamCollection *collection;
|
|
|
|
/* List of available GstAdaptiveDemuxTrack (ref hold) */
|
|
GList *tracks;
|
|
|
|
/* Whether tracks were changed and need re-matching against outputs */
|
|
gboolean tracks_changed;
|
|
|
|
/* The time at which to wake up input streams for more
|
|
* data - the earliest of all waiting input stream thresholds,
|
|
* or GST_CLOCK_STIME_NONE if noone is waiting */
|
|
GstClockTimeDiff next_input_wakeup_time;
|
|
};
|
|
|
|
/**
|
|
* GstAdaptiveDemux:
|
|
*
|
|
* The opaque #GstAdaptiveDemux data structure.
|
|
*/
|
|
struct _GstAdaptiveDemux
|
|
{
|
|
/*< private >*/
|
|
GstBin bin;
|
|
|
|
gint running;
|
|
|
|
/*< protected >*/
|
|
GstPad *sinkpad;
|
|
|
|
DownloadHelper *download_helper;
|
|
|
|
/* Protected by TRACKS_LOCK */
|
|
/* Period used for output */
|
|
GstAdaptiveDemuxPeriod *output_period;
|
|
|
|
/* Period used for input */
|
|
GstAdaptiveDemuxPeriod *input_period;
|
|
|
|
GstSegment segment;
|
|
gdouble instant_rate_multiplier; /* 1.0 by default, or from instant-rate seek */
|
|
|
|
gchar *manifest_uri;
|
|
gchar *manifest_base_uri;
|
|
|
|
/* Properties */
|
|
gfloat bandwidth_target_ratio; /* ratio of the available bitrate to use */
|
|
guint connection_speed; /* Available / bandwidth to use set by the application */
|
|
guint min_bitrate; /* Minimum bitrate to choose */
|
|
guint max_bitrate; /* Maximum bitrate to choose */
|
|
|
|
guint current_download_rate; /* Current estimate of download bitrate */
|
|
|
|
/* Buffering levels */
|
|
GstClockTime max_buffering_time;
|
|
GstClockTime buffering_high_watermark_time;
|
|
GstClockTime buffering_low_watermark_time;
|
|
gdouble buffering_high_watermark_fragments;
|
|
gdouble buffering_low_watermark_fragments;
|
|
|
|
/* video/audio buffer level as minimum of the appropriate streams */
|
|
GstClockTime current_level_time_video;
|
|
GstClockTime current_level_time_audio;
|
|
|
|
gboolean have_group_id;
|
|
guint group_id;
|
|
|
|
guint next_stream_id;
|
|
|
|
/* Realtime clock */
|
|
GstAdaptiveDemuxClock *realtime_clock;
|
|
|
|
/* < private > */
|
|
GstAdaptiveDemuxPrivate *priv;
|
|
};
|
|
|
|
/**
|
|
* GstAdaptiveDemuxClass:
|
|
*
|
|
*/
|
|
struct _GstAdaptiveDemuxClass
|
|
{
|
|
/*< private >*/
|
|
GstBinClass bin_class;
|
|
|
|
/*< public >*/
|
|
|
|
/**
|
|
* process_manifest: Parse the manifest
|
|
* @demux: #GstAdaptiveDemux
|
|
* @manifest: the manifest to be parsed
|
|
*
|
|
* Parse the manifest and add the created streams using
|
|
* gst_adaptive_demux2_stream_new()
|
|
*
|
|
* Returns: %TRUE if successful
|
|
*/
|
|
gboolean (*process_manifest) (GstAdaptiveDemux * demux, GstBuffer * manifest);
|
|
|
|
/**
|
|
* get_manifest_update_interval:
|
|
* @demux: #GstAdaptiveDemux
|
|
*
|
|
* Used during live streaming, the subclass should return the interval
|
|
* between successive manifest updates
|
|
*
|
|
* Returns: the update interval in microseconds
|
|
*/
|
|
gint64 (*get_manifest_update_interval) (GstAdaptiveDemux * demux);
|
|
|
|
/**
|
|
* update_manifest:
|
|
* @demux: #GstAdaptiveDemux
|
|
*
|
|
* During live streaming, this will be called for the subclass to update its
|
|
* manifest with the new version. By default it fetches the manifest URI
|
|
* and passes it to GstAdaptiveDemux::update_manifest_data().
|
|
*
|
|
* Returns: #GST_FLOW_OK is all succeeded, #GST_FLOW_EOS if the stream ended
|
|
* or #GST_FLOW_ERROR if an error happened
|
|
*/
|
|
GstFlowReturn (*update_manifest) (GstAdaptiveDemux * demux);
|
|
|
|
/**
|
|
* update_manifest_data:
|
|
* @demux: #GstAdaptiveDemux
|
|
* @buf: Downloaded manifest data
|
|
*
|
|
* During live streaming, this will be called for the subclass to update its
|
|
* manifest with the new version
|
|
*
|
|
* Returns: #GST_FLOW_OK is all succeeded, #GST_FLOW_EOS if the stream ended
|
|
* or #GST_FLOW_ERROR if an error happened
|
|
*/
|
|
GstFlowReturn (*update_manifest_data) (GstAdaptiveDemux * demux, GstBuffer * buf);
|
|
|
|
gboolean (*is_live) (GstAdaptiveDemux * demux);
|
|
GstClockTime (*get_duration) (GstAdaptiveDemux * demux);
|
|
|
|
/**
|
|
* reset:
|
|
* @demux: #GstAdaptiveDemux
|
|
*
|
|
* Reset the internal state of the subclass, getting ready to restart with
|
|
* a new stream afterwards
|
|
*/
|
|
void (*reset) (GstAdaptiveDemux * demux);
|
|
|
|
/**
|
|
* seek:
|
|
* @demux: #GstAdaptiveDemux
|
|
* @seek: a seek #GstEvent
|
|
*
|
|
* The demuxer should seek on all its streams to the specified position
|
|
* in the seek event
|
|
*
|
|
* Returns: %TRUE if successful
|
|
*/
|
|
gboolean (*seek) (GstAdaptiveDemux * demux, GstEvent * seek);
|
|
|
|
/**
|
|
* has_next_period:
|
|
* @demux: #GstAdaptiveDemux
|
|
*
|
|
* Checks if there is a next period following the current one.
|
|
* DASH can have multiple medias chained in its manifest, when one finishes
|
|
* this function is called to verify if there is a new period to be played
|
|
* in sequence.
|
|
*
|
|
* Returns: %TRUE if there is another period
|
|
*/
|
|
gboolean (*has_next_period) (GstAdaptiveDemux * demux);
|
|
/**
|
|
* advance_period:
|
|
* @demux: #GstAdaptiveDemux
|
|
*
|
|
* Advances the manifest to the next period. New streams should be created
|
|
* using gst_adaptive_demux2_stream_new().
|
|
*/
|
|
void (*advance_period) (GstAdaptiveDemux * demux);
|
|
|
|
GstFlowReturn (*stream_seek) (GstAdaptiveDemux2Stream * stream,
|
|
gboolean forward,
|
|
GstSeekFlags flags,
|
|
GstClockTimeDiff target_ts,
|
|
GstClockTimeDiff * final_ts);
|
|
gboolean (*stream_has_next_fragment) (GstAdaptiveDemux2Stream * stream);
|
|
GstFlowReturn (*stream_advance_fragment) (GstAdaptiveDemux2Stream * stream);
|
|
|
|
/**
|
|
* stream_can_start:
|
|
* @demux: The #GstAdaptiveDemux
|
|
* @stream: a #GstAdaptiveDemux2Stream
|
|
*
|
|
* Called before starting a @stream. sub-classes can return %FALSE if more
|
|
* information is required before it can be started. Sub-classes will have to
|
|
* call gst_adaptive_demux2_stream_start() when the stream should be started.
|
|
*/
|
|
gboolean (*stream_can_start) (GstAdaptiveDemux *demux,
|
|
GstAdaptiveDemux2Stream *stream);
|
|
|
|
/**
|
|
* stream_update_tracks:
|
|
* @demux: The #GstAdaptiveDemux
|
|
* @stream: A #GstAdaptiveDemux2Stream
|
|
*
|
|
* Called whenever the base class collected a @collection on a @stream which has
|
|
* pending tracks to be created. Subclasses should override this if they
|
|
* create streams without tracks.
|
|
*
|
|
* * create the various tracks by analyzing the @stream stream_collection
|
|
* * Set the track upstream_stream_id to the corresponding stream_id from the collection
|
|
*/
|
|
void (*stream_update_tracks) (GstAdaptiveDemux *demux,
|
|
GstAdaptiveDemux2Stream *stream);
|
|
/**
|
|
* need_another_chunk:
|
|
* @stream: #GstAdaptiveDemux2Stream
|
|
*
|
|
* If chunked downloading is used (chunk_size != 0) this is called once a
|
|
* chunk is finished to decide whether more has to be downloaded or not.
|
|
* May update chunk_size to a different value
|
|
*/
|
|
gboolean (*need_another_chunk) (GstAdaptiveDemux2Stream * stream);
|
|
|
|
/**
|
|
* stream_update_fragment_info:
|
|
* @stream: #GstAdaptiveDemux2Stream
|
|
*
|
|
* Requests the stream to set the information about the current fragment to its
|
|
* current fragment struct
|
|
*
|
|
* Returns: #GST_FLOW_OK in success, #GST_FLOW_ERROR on error and #GST_FLOW_EOS
|
|
* if there is no fragment.
|
|
*/
|
|
GstFlowReturn (*stream_update_fragment_info) (GstAdaptiveDemux2Stream * stream);
|
|
/**
|
|
* stream_select_bitrate:
|
|
* @stream: #GstAdaptiveDemux2Stream
|
|
* @bitrate: the bitrate to select (in bytes per second)
|
|
*
|
|
* The stream should try to select the bitrate that is the greater, but not
|
|
* greater than the requested bitrate. If it needs a codec change it should
|
|
* create the new stream using gst_adaptive_demux2_stream_new(). If it only
|
|
* needs a caps change it should set the new caps using
|
|
* gst_adaptive_demux2_stream_set_caps().
|
|
*
|
|
* Returns: %TRUE if the stream changed bitrate, %FALSE otherwise
|
|
*/
|
|
gboolean (*stream_select_bitrate) (GstAdaptiveDemux2Stream * stream, guint64 bitrate);
|
|
/**
|
|
* stream_get_fragment_waiting_time:
|
|
* @stream: #GstAdaptiveDemux2Stream
|
|
*
|
|
* For live streams, requests how much time should be waited before starting
|
|
* to download the fragment. This is useful to avoid downloading a fragment that
|
|
* isn't available yet.
|
|
*
|
|
* Returns: The waiting time in as a #GstClockTime
|
|
*/
|
|
GstClockTime (*stream_get_fragment_waiting_time) (GstAdaptiveDemux2Stream * stream);
|
|
|
|
/**
|
|
* start_fragment:
|
|
* @demux: #GstAdaptiveDemux
|
|
* @stream: #GstAdaptiveDemux2Stream
|
|
*
|
|
* Notifies the subclass that the given stream is starting the download
|
|
* of a new fragment. Can be used to reset/init internal state that is
|
|
* needed before each fragment, like decryption engines.
|
|
*
|
|
* Returns: %TRUE if successful.
|
|
*/
|
|
gboolean (*start_fragment) (GstAdaptiveDemux * demux, GstAdaptiveDemux2Stream * stream);
|
|
/**
|
|
* finish_fragment:
|
|
* @demux: #GstAdaptiveDemux
|
|
* @stream: #GstAdaptiveDemux2Stream
|
|
*
|
|
* Notifies the subclass that a fragment download was finished.
|
|
* It can be used to cleanup internal state after a fragment and
|
|
* also push any pending data before moving to the next fragment.
|
|
*/
|
|
GstFlowReturn (*finish_fragment) (GstAdaptiveDemux * demux, GstAdaptiveDemux2Stream * stream);
|
|
/**
|
|
* data_received:
|
|
* @demux: #GstAdaptiveDemux
|
|
* @stream: #GstAdaptiveDemux2Stream
|
|
* @buffer: #GstBuffer
|
|
*
|
|
* Notifies the subclass that a fragment chunk was downloaded. The subclass
|
|
* can look at the data and modify/push data as desired.
|
|
*
|
|
* Returns: #GST_FLOW_OK if successful, #GST_FLOW_ERROR in case of error.
|
|
*/
|
|
GstFlowReturn (*data_received) (GstAdaptiveDemux * demux, GstAdaptiveDemux2Stream * stream, GstBuffer * buffer);
|
|
|
|
/**
|
|
* get_live_seek_range:
|
|
* @demux: #GstAdaptiveDemux
|
|
* @start: pointer to put the start position allowed to seek to
|
|
* @stop: pointer to put the stop position allowed to seek to
|
|
*
|
|
* Gets the allowed seek start and stop positions for the current live stream
|
|
*
|
|
* Return: %TRUE if successful
|
|
*/
|
|
gboolean (*get_live_seek_range) (GstAdaptiveDemux * demux, gint64 * start, gint64 * stop);
|
|
|
|
/**
|
|
* get_presentation_offset:
|
|
* @demux: #GstAdaptiveDemux
|
|
* @stream: #GstAdaptiveDemux2Stream
|
|
*
|
|
* Gets the delay to apply to @stream.
|
|
*
|
|
* Return: a #GstClockTime representing the (positive) time offset to apply to
|
|
* @stream.
|
|
*/
|
|
GstClockTime (*get_presentation_offset) (GstAdaptiveDemux *demux, GstAdaptiveDemux2Stream *stream);
|
|
|
|
/**
|
|
* get_period_start_time:
|
|
* @demux: #GstAdaptiveDemux
|
|
*
|
|
* Gets the start time of the current period. Timestamps are resetting to 0
|
|
* after each period but we have to maintain a continuous stream and running
|
|
* time so need to know the start time of the current period.
|
|
*
|
|
* Return: a #GstClockTime representing the start time of the currently
|
|
* selected period.
|
|
*/
|
|
GstClockTime (*get_period_start_time) (GstAdaptiveDemux *demux);
|
|
|
|
/**
|
|
* requires_periodical_playlist_update:
|
|
* @demux: #GstAdaptiveDemux
|
|
*
|
|
* Some adaptive streaming protocols allow the client to download
|
|
* the playlist once and build up the fragment list based on the
|
|
* current fragment metadata. For those protocols the demuxer
|
|
* doesn't need to periodically refresh the playlist. This vfunc
|
|
* is relevant only for live playback scenarios.
|
|
*
|
|
* Return: %TRUE if the playlist needs to be refreshed periodically by the demuxer.
|
|
*/
|
|
gboolean (*requires_periodical_playlist_update) (GstAdaptiveDemux * demux);
|
|
};
|
|
|
|
GType gst_adaptive_demux_ng_get_type (void);
|
|
|
|
GType gst_adaptive_demux2_stream_get_type (void);
|
|
|
|
gboolean gst_adaptive_demux2_add_stream (GstAdaptiveDemux *demux,
|
|
GstAdaptiveDemux2Stream *stream);
|
|
|
|
gboolean gst_adaptive_demux2_stream_add_track (GstAdaptiveDemux2Stream *stream,
|
|
GstAdaptiveDemuxTrack *track);
|
|
|
|
GstAdaptiveDemuxTrack *gst_adaptive_demux_track_new (GstAdaptiveDemux *demux,
|
|
GstStreamType type,
|
|
GstStreamFlags flags,
|
|
gchar *stream_id,
|
|
GstCaps *caps,
|
|
GstTagList *tags);
|
|
GstAdaptiveDemuxTrack *gst_adaptive_demux_track_ref (GstAdaptiveDemuxTrack *track);
|
|
void gst_adaptive_demux_track_unref (GstAdaptiveDemuxTrack *track);
|
|
|
|
|
|
void gst_adaptive_demux2_stream_set_caps (GstAdaptiveDemux2Stream * stream,
|
|
GstCaps * caps);
|
|
|
|
void gst_adaptive_demux2_stream_set_tags (GstAdaptiveDemux2Stream * stream,
|
|
GstTagList * tags);
|
|
|
|
void gst_adaptive_demux2_stream_fragment_clear (GstAdaptiveDemux2StreamFragment * f);
|
|
|
|
GstFlowReturn gst_adaptive_demux2_stream_push_buffer (GstAdaptiveDemux2Stream * stream,
|
|
GstBuffer * buffer);
|
|
|
|
GstFlowReturn gst_adaptive_demux2_stream_advance_fragment (GstAdaptiveDemux * demux,
|
|
GstAdaptiveDemux2Stream * stream,
|
|
GstClockTime duration);
|
|
|
|
gboolean gst_adaptive_demux_start_new_period (GstAdaptiveDemux * demux);
|
|
|
|
void
|
|
gst_adaptive_demux2_stream_start (GstAdaptiveDemux2Stream * stream);
|
|
|
|
void gst_adaptive_demux2_stream_queue_event (GstAdaptiveDemux2Stream * stream,
|
|
GstEvent * event);
|
|
|
|
gboolean gst_adaptive_demux2_stream_is_selected (GstAdaptiveDemux2Stream *stream);
|
|
gboolean gst_adaptive_demux2_stream_is_running (GstAdaptiveDemux2Stream * stream);
|
|
|
|
GstClockTime gst_adaptive_demux2_get_monotonic_time (GstAdaptiveDemux * demux);
|
|
|
|
GDateTime *gst_adaptive_demux2_get_client_now_utc (GstAdaptiveDemux * demux);
|
|
|
|
gboolean gst_adaptive_demux2_is_running (GstAdaptiveDemux * demux);
|
|
|
|
GstClockTime gst_adaptive_demux2_get_qos_earliest_time (GstAdaptiveDemux *demux);
|
|
|
|
GstCaps * gst_codec_utils_caps_from_iso_rfc6831 (gchar * codec);
|
|
|
|
gdouble gst_adaptive_demux_play_rate (GstAdaptiveDemux *demux);
|
|
|
|
G_END_DECLS
|
|
|
|
#endif
|
|
|