adaptivedemux: add adaptivedemux base class

https://bugzilla.gnome.org/show_bug.cgi?id=735848
This commit is contained in:
Thiago Santos 2014-11-21 20:42:09 -03:00
parent 83d9353d58
commit 9ec9f3f119
5 changed files with 2701 additions and 2 deletions

View file

@ -3237,6 +3237,7 @@ gst/yadif/Makefile
gst/compositor/Makefile
gst-libs/Makefile
gst-libs/gst/Makefile
gst-libs/gst/adaptivedemux/Makefile
gst-libs/gst/basecamerabinsrc/Makefile
gst-libs/gst/gl/Makefile
gst-libs/gst/gl/android/Makefile

View file

@ -10,9 +10,9 @@ if USE_WAYLAND
WAYLAND_DIR=wayland
endif
SUBDIRS = interfaces basecamerabinsrc codecparsers \
SUBDIRS = adaptivedemux interfaces basecamerabinsrc codecparsers \
insertbin uridownloader mpegts base video $(GL_DIR) $(WAYLAND_DIR)
noinst_HEADERS = gst-i18n-plugin.h gettext.h glib-compat-private.h
DIST_SUBDIRS = interfaces gl basecamerabinsrc codecparsers \
DIST_SUBDIRS = adaptivedemux interfaces gl basecamerabinsrc codecparsers \
insertbin uridownloader mpegts wayland base video

View file

@ -0,0 +1,35 @@
lib_LTLIBRARIES = libgstadaptivedemux-@GST_API_VERSION@.la
CLEANFILES = $(BUILT_SOURCES)
libgstadaptivedemux_@GST_API_VERSION@_la_SOURCES = \
gstadaptivedemux.c
libgstadaptivedemux_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/adaptivedemux
noinst_HEADERS = gstadaptivedemux.h
libgstadaptivedemux_@GST_API_VERSION@_la_CFLAGS = \
$(GST_PLUGINS_BAD_CFLAGS) \
$(GST_PLUGINS_BASE_CFLAGS) \
-DGST_USE_UNSTABLE_API \
$(GST_CFLAGS)
libgstadaptivedemux_@GST_API_VERSION@_la_LIBADD = \
-lgstapp-$(GST_API_VERSION) $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(GST_LIBS)
libgstadaptivedemux_@GST_API_VERSION@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS)
Android.mk: Makefile.am
androgenizer -:PROJECT libgstadaptivedemux -:STATIC libgstadaptivedemux-@GST_API_VERSION@ \
-:TAGS eng debug \
-:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
-:SOURCES $(libgstadaptivedemux_@GST_API_VERSION@_la_SOURCES) \
-:CFLAGS $(DEFS) $(libgstadaptivedemux_@GST_API_VERSION@_la_CFLAGS) \
-:LDFLAGS $(libgstadaptivedemux_@GST_API_VERSION@_la_LDFLAGS) \
$(libgstadaptivedemux_@GST_API_VERSION@_la_LIBADD) \
-ldl \
-:HEADER_TARGET gstreamer-@GST_API_VERSION@/gst/adaptivedemux \
-:HEADERS $(libgstadaptivedemuxinclude_HEADERS) \
-:PASSTHROUGH LOCAL_ARM_MODE:=arm \
> $@

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,372 @@
/* GStreamer
*
* Copyright (C) 2014 Samsung Electronics. All rights reserved.
* Author: Thiago Santos <thiagoss@osg.samsung.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/gstadapter.h>
G_BEGIN_DECLS
#define GST_TYPE_ADAPTIVE_DEMUX \
(gst_adaptive_demux_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_ADAPTIVE_DEMUX_STREAM_CAST(obj) ((GstAdaptiveDemuxStream *)obj)
/**
* 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_STREAM_PAD(obj) (((GstAdaptiveDemuxStream *) (obj))->pad)
#define GST_ADAPTIVE_DEMUX_STREAM_NEED_HEADER(obj) (((GstAdaptiveDemuxStream *) (obj))->need_header)
#define STATISTICS_MESSAGE_NAME "adaptive-streaming-statistics"
#define GST_MANIFEST_GET_LOCK(d) (&(GST_ADAPTIVE_DEMUX_CAST(d)->manifest_lock))
#define GST_MANIFEST_LOCK(d) (g_mutex_lock (GST_MANIFEST_GET_LOCK (d)))
#define GST_MANIFEST_UNLOCK(d) (g_mutex_unlock (GST_MANIFEST_GET_LOCK (d)))
#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
typedef struct _GstAdaptiveDemuxStreamFragment GstAdaptiveDemuxStreamFragment;
typedef struct _GstAdaptiveDemuxStream GstAdaptiveDemuxStream;
typedef struct _GstAdaptiveDemux GstAdaptiveDemux;
typedef struct _GstAdaptiveDemuxClass GstAdaptiveDemuxClass;
typedef struct _GstAdaptiveDemuxPrivate GstAdaptiveDemuxPrivate;
struct _GstAdaptiveDemuxStreamFragment
{
GstClockTime timestamp;
GstClockTime duration;
gchar *uri;
gint64 range_start;
gint64 range_end;
/* 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;
};
struct _GstAdaptiveDemuxStream
{
GstPad *pad;
GstAdaptiveDemux *demux;
GstSegment segment;
GstCaps *pending_caps;
GstEvent *pending_segment;
GstTagList *pending_tags;
gboolean need_header;
GstFlowReturn last_ret;
GError *last_error;
GstTask *download_task;
GRecMutex download_lock;
gboolean restart_download;
gboolean discont;
/* download tooling */
GstElement *src;
GstPad *src_srcpad;
GMutex fragment_download_lock;
GCond fragment_download_cond;
gboolean download_finished;
gboolean starting_fragment;
gboolean first_fragment_buffer;
gint64 download_start_time;
gint64 download_total_time;
gint64 download_total_bytes;
gint current_download_rate;
GstAdaptiveDemuxStreamFragment fragment;
guint download_error_count;
/* TODO check if used */
gboolean eos;
};
/**
* GstAdaptiveDemux:
*
* The opaque #GstAdaptiveDemux data structure.
*/
struct _GstAdaptiveDemux
{
/*< private >*/
GstBin bin;
gsize stream_struct_size;
/*< protected >*/
GstPad *sinkpad;
GstAdaptiveDemuxPrivate *priv;
GList *streams;
GList *next_streams;
GstSegment segment;
gboolean cancelled;
GMutex manifest_lock;
GCond manifest_cond;
gchar *manifest_uri;
gchar *manifest_base_uri;
gboolean have_group_id;
guint group_id;
};
/**
* 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_demux_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
* @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) (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_demux_stream_new().
*/
void (*advance_period) (GstAdaptiveDemux * demux);
void (*stream_free) (GstAdaptiveDemuxStream * stream);
GstFlowReturn (*stream_seek) (GstAdaptiveDemuxStream * stream, GstClockTime ts);
gboolean (*stream_has_next_fragment) (GstAdaptiveDemuxStream * stream);
GstFlowReturn (*stream_advance_fragment) (GstAdaptiveDemuxStream * stream);
/**
* stream_update_fragment_info:
* @stream: #GstAdaptiveDemuxStream
*
* 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) (GstAdaptiveDemuxStream * stream);
/**
* stream_select_bitrate:
* @stream: #GstAdaptiveDemuxStream
* @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_demux_stream_new(). If it only
* needs a caps change it should set the new caps using
* gst_adaptive_demux_stream_set_caps().
*
* Returns: #TRUE if the stream changed bitrate, #FALSE otherwise
*/
gboolean (*stream_select_bitrate) (GstAdaptiveDemuxStream * stream, guint64 bitrate);
/**
* stream_get_fragment_waiting_time:
* @stream: #GstAdaptiveDemuxStream
*
* 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 microsseconds
*/
gint64 (*stream_get_fragment_waiting_time) (GstAdaptiveDemuxStream * stream);
/**
* start_fragment:
* @demux: #GstAdaptiveDemux
* @stream: #GstAdaptiveDemuxStream
*
* 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, GstAdaptiveDemuxStream * stream);
/**
* finish_fragment:
* @demux: #GstAdaptiveDemux
* @stream: #GstAdaptiveDemuxStream
* @buffer: Pointer to store and pending data that should be pushed.
*
* Notifies the subclass that a fragment download was finished.
* It can be used to cleanup internal state after a fragment and also
* provides a pointer for the subclass to return some pending data
* that should be pushed before starting the next fragment. This
* covers the use case of finishing the decryption of the last chunk
* of an encrypted fragment.
*/
void (*finish_fragment) (GstAdaptiveDemux * demux, GstAdaptiveDemuxStream * stream, GstBuffer ** buffer);
/**
* chunk_received:
* @demux: #GstAdaptiveDemux
* @stream: #GstAdaptiveDemuxStream
* @buffer: Pointer containing the received chunk, also used to return modified data
*
* Notifies the subclass that a fragment chunk was downloaded. The subclass can
* modify the buffer and return a new one if needed. Used for decryption.
*
* Returns: #GST_FLOW_OK if successful, #GST_FLOW_ERROR in case of error.
*/
GstFlowReturn (*chunk_received) (GstAdaptiveDemux * demux, GstAdaptiveDemuxStream * stream, GstBuffer ** buffer);
};
GType gst_adaptive_demux_get_type (void);
void gst_adaptive_demux_set_stream_struct_size (GstAdaptiveDemux * demux,
gsize struct_size);
GstAdaptiveDemuxStream *gst_adaptive_demux_stream_new (GstAdaptiveDemux * demux,
GstPad * pad);
void gst_adaptive_demux_stream_set_caps (GstAdaptiveDemuxStream * stream,
GstCaps * caps);
void gst_adaptive_demux_stream_set_tags (GstAdaptiveDemuxStream * stream,
GstTagList * tags);
void gst_adaptive_demux_stream_fragment_clear (GstAdaptiveDemuxStreamFragment * f);
G_END_DECLS
#endif