aboutsummaryrefslogtreecommitdiffstats
path: root/meta/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0001-mssdemux-improved-live-playback-support.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0001-mssdemux-improved-live-playback-support.patch')
-rw-r--r--meta/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0001-mssdemux-improved-live-playback-support.patch929
1 files changed, 0 insertions, 929 deletions
diff --git a/meta/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0001-mssdemux-improved-live-playback-support.patch b/meta/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0001-mssdemux-improved-live-playback-support.patch
deleted file mode 100644
index 4832c18e78..0000000000
--- a/meta/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad/0001-mssdemux-improved-live-playback-support.patch
+++ /dev/null
@@ -1,929 +0,0 @@
-From 73721ad4e9e2d32e1c8b6a3b4aaa98401530e58a Mon Sep 17 00:00:00 2001
-From: Philippe Normand <philn@igalia.com>
-Date: Tue, 29 Nov 2016 14:43:41 +0100
-Subject: [PATCH] mssdemux: improved live playback support
-
-When a MSS server hosts a live stream the fragments listed in the
-manifest usually don't have accurate timestamps and duration, except
-for the first fragment, which additionally stores timing information
-for the few upcoming fragments. In this scenario it is useless to
-periodically fetch and update the manifest and the fragments list can
-be incrementally built by parsing the first/current fragment.
-
-https://bugzilla.gnome.org/show_bug.cgi?id=755036
----
-Upstream-Status: Backport
-Signed-off-by: Khem Raj <raj.khem@gmail.com>
-
- ext/smoothstreaming/Makefile.am | 2 +
- ext/smoothstreaming/gstmssdemux.c | 60 ++++++
- ext/smoothstreaming/gstmssfragmentparser.c | 266 ++++++++++++++++++++++++++
- ext/smoothstreaming/gstmssfragmentparser.h | 84 ++++++++
- ext/smoothstreaming/gstmssmanifest.c | 158 ++++++++++++++-
- ext/smoothstreaming/gstmssmanifest.h | 7 +
- gst-libs/gst/adaptivedemux/gstadaptivedemux.c | 27 ++-
- gst-libs/gst/adaptivedemux/gstadaptivedemux.h | 14 ++
- 8 files changed, 606 insertions(+), 12 deletions(-)
- create mode 100644 ext/smoothstreaming/gstmssfragmentparser.c
- create mode 100644 ext/smoothstreaming/gstmssfragmentparser.h
-
-diff --git a/ext/smoothstreaming/Makefile.am b/ext/smoothstreaming/Makefile.am
-index 4faf9df9f..a5e1ad6ae 100644
---- a/ext/smoothstreaming/Makefile.am
-+++ b/ext/smoothstreaming/Makefile.am
-@@ -13,8 +13,10 @@ libgstsmoothstreaming_la_LIBADD = \
- libgstsmoothstreaming_la_LDFLAGS = ${GST_PLUGIN_LDFLAGS}
- libgstsmoothstreaming_la_SOURCES = gstsmoothstreaming-plugin.c \
- gstmssdemux.c \
-+ gstmssfragmentparser.c \
- gstmssmanifest.c
- libgstsmoothstreaming_la_LIBTOOLFLAGS = --tag=disable-static
-
- noinst_HEADERS = gstmssdemux.h \
-+ gstmssfragmentparser.h \
- gstmssmanifest.h
-diff --git a/ext/smoothstreaming/gstmssdemux.c b/ext/smoothstreaming/gstmssdemux.c
-index 12fb40497..120d9c22b 100644
---- a/ext/smoothstreaming/gstmssdemux.c
-+++ b/ext/smoothstreaming/gstmssdemux.c
-@@ -135,11 +135,18 @@ gst_mss_demux_stream_update_fragment_info (GstAdaptiveDemuxStream * stream);
- static gboolean gst_mss_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek);
- static gint64
- gst_mss_demux_get_manifest_update_interval (GstAdaptiveDemux * demux);
-+static gint64
-+gst_mss_demux_stream_get_fragment_waiting_time (GstAdaptiveDemuxStream *
-+ stream);
- static GstFlowReturn
- gst_mss_demux_update_manifest_data (GstAdaptiveDemux * demux,
- GstBuffer * buffer);
- static gboolean gst_mss_demux_get_live_seek_range (GstAdaptiveDemux * demux,
- gint64 * start, gint64 * stop);
-+static GstFlowReturn gst_mss_demux_data_received (GstAdaptiveDemux * demux,
-+ GstAdaptiveDemuxStream * stream, GstBuffer * buffer);
-+static gboolean
-+gst_mss_demux_requires_periodical_playlist_update (GstAdaptiveDemux * demux);
-
- static void
- gst_mss_demux_class_init (GstMssDemuxClass * klass)
-@@ -192,10 +199,15 @@ gst_mss_demux_class_init (GstMssDemuxClass * klass)
- gst_mss_demux_stream_select_bitrate;
- gstadaptivedemux_class->stream_update_fragment_info =
- gst_mss_demux_stream_update_fragment_info;
-+ gstadaptivedemux_class->stream_get_fragment_waiting_time =
-+ gst_mss_demux_stream_get_fragment_waiting_time;
- gstadaptivedemux_class->update_manifest_data =
- gst_mss_demux_update_manifest_data;
- gstadaptivedemux_class->get_live_seek_range =
- gst_mss_demux_get_live_seek_range;
-+ gstadaptivedemux_class->data_received = gst_mss_demux_data_received;
-+ gstadaptivedemux_class->requires_periodical_playlist_update =
-+ gst_mss_demux_requires_periodical_playlist_update;
-
- GST_DEBUG_CATEGORY_INIT (mssdemux_debug, "mssdemux", 0, "mssdemux plugin");
- }
-@@ -650,6 +662,13 @@ gst_mss_demux_get_manifest_update_interval (GstAdaptiveDemux * demux)
- return interval;
- }
-
-+static gint64
-+gst_mss_demux_stream_get_fragment_waiting_time (GstAdaptiveDemuxStream * stream)
-+{
-+ /* Wait a second for live streams so we don't try premature fragments downloading */
-+ return GST_SECOND;
-+}
-+
- static GstFlowReturn
- gst_mss_demux_update_manifest_data (GstAdaptiveDemux * demux,
- GstBuffer * buffer)
-@@ -670,3 +689,44 @@ gst_mss_demux_get_live_seek_range (GstAdaptiveDemux * demux, gint64 * start,
-
- return gst_mss_manifest_get_live_seek_range (mssdemux->manifest, start, stop);
- }
-+
-+static GstFlowReturn
-+gst_mss_demux_data_received (GstAdaptiveDemux * demux,
-+ GstAdaptiveDemuxStream * stream, GstBuffer * buffer)
-+{
-+ GstMssDemux *mssdemux = GST_MSS_DEMUX_CAST (demux);
-+ GstMssDemuxStream *mssstream = (GstMssDemuxStream *) stream;
-+ gsize available;
-+
-+ if (!gst_mss_manifest_is_live (mssdemux->manifest)) {
-+ return GST_ADAPTIVE_DEMUX_CLASS (parent_class)->data_received (demux,
-+ stream, buffer);
-+ }
-+
-+ if (gst_mss_stream_fragment_parsing_needed (mssstream->manifest_stream)) {
-+ gst_mss_manifest_live_adapter_push (mssstream->manifest_stream, buffer);
-+ available =
-+ gst_mss_manifest_live_adapter_available (mssstream->manifest_stream);
-+ // FIXME: try to reduce this minimal size.
-+ if (available < 4096) {
-+ return GST_FLOW_OK;
-+ } else {
-+ GST_LOG_OBJECT (stream->pad, "enough data, parsing fragment.");
-+ buffer =
-+ gst_mss_manifest_live_adapter_take_buffer (mssstream->manifest_stream,
-+ available);
-+ gst_mss_stream_parse_fragment (mssstream->manifest_stream, buffer);
-+ }
-+ }
-+
-+ return GST_ADAPTIVE_DEMUX_CLASS (parent_class)->data_received (demux, stream,
-+ buffer);
-+}
-+
-+static gboolean
-+gst_mss_demux_requires_periodical_playlist_update (GstAdaptiveDemux * demux)
-+{
-+ GstMssDemux *mssdemux = GST_MSS_DEMUX_CAST (demux);
-+
-+ return (!gst_mss_manifest_is_live (mssdemux->manifest));
-+}
-diff --git a/ext/smoothstreaming/gstmssfragmentparser.c b/ext/smoothstreaming/gstmssfragmentparser.c
-new file mode 100644
-index 000000000..b554d4f31
---- /dev/null
-+++ b/ext/smoothstreaming/gstmssfragmentparser.c
-@@ -0,0 +1,266 @@
-+/*
-+ * Microsoft Smooth-Streaming fragment parsing library
-+ *
-+ * gstmssfragmentparser.h
-+ *
-+ * Copyright (C) 2016 Igalia S.L
-+ * Copyright (C) 2016 Metrological
-+ * Author: Philippe Normand <philn@igalia.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.1 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 (COPYING); if not, write to the
-+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-+ * Boston, MA 02111-1307, USA.
-+ */
-+
-+#include "gstmssfragmentparser.h"
-+#include <gst/base/gstbytereader.h>
-+#include <string.h>
-+
-+GST_DEBUG_CATEGORY_EXTERN (mssdemux_debug);
-+#define GST_CAT_DEFAULT mssdemux_debug
-+
-+void
-+gst_mss_fragment_parser_init (GstMssFragmentParser * parser)
-+{
-+ parser->status = GST_MSS_FRAGMENT_HEADER_PARSER_INIT;
-+ parser->tfrf.entries_count = 0;
-+}
-+
-+void
-+gst_mss_fragment_parser_clear (GstMssFragmentParser * parser)
-+{
-+ parser->tfrf.entries_count = 0;
-+ if (parser->tfrf.entries) {
-+ g_free (parser->tfrf.entries);
-+ parser->tfrf.entries = 0;
-+ }
-+}
-+
-+static gboolean
-+_parse_tfrf_box (GstMssFragmentParser * parser, GstByteReader * reader)
-+{
-+ guint8 version;
-+ guint32 flags = 0;
-+ guint8 fragment_count = 0;
-+ guint8 index = 0;
-+
-+ if (!gst_byte_reader_get_uint8 (reader, &version)) {
-+ GST_ERROR ("Error getting box's version field");
-+ return FALSE;
-+ }
-+
-+ if (!gst_byte_reader_get_uint24_be (reader, &flags)) {
-+ GST_ERROR ("Error getting box's flags field");
-+ return FALSE;
-+ }
-+
-+ gst_byte_reader_get_uint8 (reader, &fragment_count);
-+ parser->tfrf.entries_count = fragment_count;
-+ parser->tfrf.entries =
-+ g_malloc (sizeof (GstTfrfBoxEntry) * parser->tfrf.entries_count);
-+ for (index = 0; index < fragment_count; index++) {
-+ guint64 absolute_time = 0;
-+ guint64 absolute_duration = 0;
-+ if (version & 0x01) {
-+ gst_byte_reader_get_uint64_be (reader, &absolute_time);
-+ gst_byte_reader_get_uint64_be (reader, &absolute_duration);
-+ } else {
-+ guint32 time = 0;
-+ guint32 duration = 0;
-+ gst_byte_reader_get_uint32_be (reader, &time);
-+ gst_byte_reader_get_uint32_be (reader, &duration);
-+ time = ~time;
-+ duration = ~duration;
-+ absolute_time = ~time;
-+ absolute_duration = ~duration;
-+ }
-+ parser->tfrf.entries[index].time = absolute_time;
-+ parser->tfrf.entries[index].duration = absolute_duration;
-+ }
-+
-+ GST_LOG ("tfrf box parsed");
-+ return TRUE;
-+}
-+
-+static gboolean
-+_parse_tfxd_box (GstMssFragmentParser * parser, GstByteReader * reader)
-+{
-+ guint8 version;
-+ guint32 flags = 0;
-+ guint64 absolute_time = 0;
-+ guint64 absolute_duration = 0;
-+
-+ if (!gst_byte_reader_get_uint8 (reader, &version)) {
-+ GST_ERROR ("Error getting box's version field");
-+ return FALSE;
-+ }
-+
-+ if (!gst_byte_reader_get_uint24_be (reader, &flags)) {
-+ GST_ERROR ("Error getting box's flags field");
-+ return FALSE;
-+ }
-+
-+ if (version & 0x01) {
-+ gst_byte_reader_get_uint64_be (reader, &absolute_time);
-+ gst_byte_reader_get_uint64_be (reader, &absolute_duration);
-+ } else {
-+ guint32 time = 0;
-+ guint32 duration = 0;
-+ gst_byte_reader_get_uint32_be (reader, &time);
-+ gst_byte_reader_get_uint32_be (reader, &duration);
-+ time = ~time;
-+ duration = ~duration;
-+ absolute_time = ~time;
-+ absolute_duration = ~duration;
-+ }
-+
-+ parser->tfxd.time = absolute_time;
-+ parser->tfxd.duration = absolute_duration;
-+ GST_LOG ("tfxd box parsed");
-+ return TRUE;
-+}
-+
-+gboolean
-+gst_mss_fragment_parser_add_buffer (GstMssFragmentParser * parser,
-+ GstBuffer * buffer)
-+{
-+ GstByteReader reader;
-+ GstMapInfo info;
-+ guint32 size;
-+ guint32 fourcc;
-+ const guint8 *uuid;
-+ gboolean error = FALSE;
-+ gboolean mdat_box_found = FALSE;
-+
-+ static const guint8 tfrf_uuid[] = {
-+ 0xd4, 0x80, 0x7e, 0xf2, 0xca, 0x39, 0x46, 0x95,
-+ 0x8e, 0x54, 0x26, 0xcb, 0x9e, 0x46, 0xa7, 0x9f
-+ };
-+
-+ static const guint8 tfxd_uuid[] = {
-+ 0x6d, 0x1d, 0x9b, 0x05, 0x42, 0xd5, 0x44, 0xe6,
-+ 0x80, 0xe2, 0x14, 0x1d, 0xaf, 0xf7, 0x57, 0xb2
-+ };
-+
-+ static const guint8 piff_uuid[] = {
-+ 0xa2, 0x39, 0x4f, 0x52, 0x5a, 0x9b, 0x4f, 0x14,
-+ 0xa2, 0x44, 0x6c, 0x42, 0x7c, 0x64, 0x8d, 0xf4
-+ };
-+
-+ if (!gst_buffer_map (buffer, &info, GST_MAP_READ)) {
-+ return FALSE;
-+ }
-+
-+ gst_byte_reader_init (&reader, info.data, info.size);
-+ GST_TRACE ("Total buffer size: %u", gst_byte_reader_get_size (&reader));
-+
-+ size = gst_byte_reader_get_uint32_be_unchecked (&reader);
-+ fourcc = gst_byte_reader_get_uint32_le_unchecked (&reader);
-+ if (fourcc == GST_MSS_FRAGMENT_FOURCC_MOOF) {
-+ GST_TRACE ("moof box found");
-+ size = gst_byte_reader_get_uint32_be_unchecked (&reader);
-+ fourcc = gst_byte_reader_get_uint32_le_unchecked (&reader);
-+ if (fourcc == GST_MSS_FRAGMENT_FOURCC_MFHD) {
-+ gst_byte_reader_skip_unchecked (&reader, size - 8);
-+
-+ size = gst_byte_reader_get_uint32_be_unchecked (&reader);
-+ fourcc = gst_byte_reader_get_uint32_le_unchecked (&reader);
-+ if (fourcc == GST_MSS_FRAGMENT_FOURCC_TRAF) {
-+ size = gst_byte_reader_get_uint32_be_unchecked (&reader);
-+ fourcc = gst_byte_reader_get_uint32_le_unchecked (&reader);
-+ if (fourcc == GST_MSS_FRAGMENT_FOURCC_TFHD) {
-+ gst_byte_reader_skip_unchecked (&reader, size - 8);
-+
-+ size = gst_byte_reader_get_uint32_be_unchecked (&reader);
-+ fourcc = gst_byte_reader_get_uint32_le_unchecked (&reader);
-+ if (fourcc == GST_MSS_FRAGMENT_FOURCC_TRUN) {
-+ GST_TRACE ("trun box found, size: %" G_GUINT32_FORMAT, size);
-+ if (!gst_byte_reader_skip (&reader, size - 8)) {
-+ GST_WARNING ("Failed to skip trun box, enough data?");
-+ error = TRUE;
-+ goto beach;
-+ }
-+ }
-+ }
-+ }
-+ }
-+ }
-+
-+ while (!mdat_box_found) {
-+ GST_TRACE ("remaining data: %u", gst_byte_reader_get_remaining (&reader));
-+ if (!gst_byte_reader_get_uint32_be (&reader, &size)) {
-+ GST_WARNING ("Failed to get box size, enough data?");
-+ error = TRUE;
-+ break;
-+ }
-+
-+ GST_TRACE ("box size: %" G_GUINT32_FORMAT, size);
-+ if (!gst_byte_reader_get_uint32_le (&reader, &fourcc)) {
-+ GST_WARNING ("Failed to get fourcc, enough data?");
-+ error = TRUE;
-+ break;
-+ }
-+
-+ if (fourcc == GST_MSS_FRAGMENT_FOURCC_MDAT) {
-+ GST_LOG ("mdat box found");
-+ mdat_box_found = TRUE;
-+ break;
-+ }
-+
-+ if (fourcc != GST_MSS_FRAGMENT_FOURCC_UUID) {
-+ GST_ERROR ("invalid UUID fourcc: %" GST_FOURCC_FORMAT,
-+ GST_FOURCC_ARGS (fourcc));
-+ error = TRUE;
-+ break;
-+ }
-+
-+ if (!gst_byte_reader_peek_data (&reader, 16, &uuid)) {
-+ GST_ERROR ("not enough data in UUID box");
-+ error = TRUE;
-+ break;
-+ }
-+
-+ if (memcmp (uuid, piff_uuid, 16) == 0) {
-+ gst_byte_reader_skip_unchecked (&reader, size - 8);
-+ GST_LOG ("piff box detected");
-+ }
-+
-+ if (memcmp (uuid, tfrf_uuid, 16) == 0) {
-+ gst_byte_reader_get_data (&reader, 16, &uuid);
-+ if (!_parse_tfrf_box (parser, &reader)) {
-+ GST_ERROR ("txrf box parsing error");
-+ error = TRUE;
-+ break;
-+ }
-+ }
-+
-+ if (memcmp (uuid, tfxd_uuid, 16) == 0) {
-+ gst_byte_reader_get_data (&reader, 16, &uuid);
-+ if (!_parse_tfxd_box (parser, &reader)) {
-+ GST_ERROR ("tfrf box parsing error");
-+ error = TRUE;
-+ break;
-+ }
-+ }
-+ }
-+
-+beach:
-+
-+ if (!error)
-+ parser->status = GST_MSS_FRAGMENT_HEADER_PARSER_FINISHED;
-+
-+ GST_LOG ("Fragment parsing successful: %s", error ? "no" : "yes");
-+ gst_buffer_unmap (buffer, &info);
-+ return !error;
-+}
-diff --git a/ext/smoothstreaming/gstmssfragmentparser.h b/ext/smoothstreaming/gstmssfragmentparser.h
-new file mode 100644
-index 000000000..cf4711865
---- /dev/null
-+++ b/ext/smoothstreaming/gstmssfragmentparser.h
-@@ -0,0 +1,84 @@
-+/*
-+ * Microsoft Smooth-Streaming fragment parsing library
-+ *
-+ * gstmssfragmentparser.h
-+ *
-+ * Copyright (C) 2016 Igalia S.L
-+ * Copyright (C) 2016 Metrological
-+ * Author: Philippe Normand <philn@igalia.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.1 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 (COPYING); if not, write to the
-+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-+ * Boston, MA 02111-1307, USA.
-+ */
-+
-+#ifndef __GST_MSS_FRAGMENT_PARSER_H__
-+#define __GST_MSS_FRAGMENT_PARSER_H__
-+
-+#include <gst/gst.h>
-+
-+G_BEGIN_DECLS
-+
-+#define GST_MSS_FRAGMENT_FOURCC_MOOF GST_MAKE_FOURCC('m','o','o','f')
-+#define GST_MSS_FRAGMENT_FOURCC_MFHD GST_MAKE_FOURCC('m','f','h','d')
-+#define GST_MSS_FRAGMENT_FOURCC_TRAF GST_MAKE_FOURCC('t','r','a','f')
-+#define GST_MSS_FRAGMENT_FOURCC_TFHD GST_MAKE_FOURCC('t','f','h','d')
-+#define GST_MSS_FRAGMENT_FOURCC_TRUN GST_MAKE_FOURCC('t','r','u','n')
-+#define GST_MSS_FRAGMENT_FOURCC_UUID GST_MAKE_FOURCC('u','u','i','d')
-+#define GST_MSS_FRAGMENT_FOURCC_MDAT GST_MAKE_FOURCC('m','d','a','t')
-+
-+typedef struct _GstTfxdBox
-+{
-+ guint8 version;
-+ guint32 flags;
-+
-+ guint64 time;
-+ guint64 duration;
-+} GstTfxdBox;
-+
-+typedef struct _GstTfrfBoxEntry
-+{
-+ guint64 time;
-+ guint64 duration;
-+} GstTfrfBoxEntry;
-+
-+typedef struct _GstTfrfBox
-+{
-+ guint8 version;
-+ guint32 flags;
-+
-+ gint entries_count;
-+ GstTfrfBoxEntry *entries;
-+} GstTfrfBox;
-+
-+typedef enum _GstFragmentHeaderParserStatus
-+{
-+ GST_MSS_FRAGMENT_HEADER_PARSER_INIT,
-+ GST_MSS_FRAGMENT_HEADER_PARSER_FINISHED
-+} GstFragmentHeaderParserStatus;
-+
-+typedef struct _GstMssFragmentParser
-+{
-+ GstFragmentHeaderParserStatus status;
-+ GstTfxdBox tfxd;
-+ GstTfrfBox tfrf;
-+} GstMssFragmentParser;
-+
-+void gst_mss_fragment_parser_init (GstMssFragmentParser * parser);
-+void gst_mss_fragment_parser_clear (GstMssFragmentParser * parser);
-+gboolean gst_mss_fragment_parser_add_buffer (GstMssFragmentParser * parser, GstBuffer * buf);
-+
-+G_END_DECLS
-+
-+#endif /* __GST_MSS_FRAGMENT_PARSER_H__ */
-diff --git a/ext/smoothstreaming/gstmssmanifest.c b/ext/smoothstreaming/gstmssmanifest.c
-index 144bbb42d..e1031ba55 100644
---- a/ext/smoothstreaming/gstmssmanifest.c
-+++ b/ext/smoothstreaming/gstmssmanifest.c
-@@ -1,5 +1,7 @@
- /* GStreamer
- * Copyright (C) 2012 Smart TV Alliance
-+ * Copyright (C) 2016 Igalia S.L
-+ * Copyright (C) 2016 Metrological
- * Author: Thiago Sousa Santos <thiago.sousa.santos@collabora.com>, Collabora Ltd.
- *
- * gstmssmanifest.c:
-@@ -31,6 +33,7 @@
- #include <gst/codecparsers/gsth264parser.h>
-
- #include "gstmssmanifest.h"
-+#include "gstmssfragmentparser.h"
-
- GST_DEBUG_CATEGORY_EXTERN (mssdemux_debug);
- #define GST_CAT_DEFAULT mssdemux_debug
-@@ -74,12 +77,17 @@ struct _GstMssStream
- gboolean active; /* if the stream is currently being used */
- gint selectedQualityIndex;
-
-+ gboolean has_live_fragments;
-+ GstAdapter *live_adapter;
-+
- GList *fragments;
- GList *qualities;
-
- gchar *url;
- gchar *lang;
-
-+ GstMssFragmentParser fragment_parser;
-+
- guint fragment_repetition_index;
- GList *current_fragment;
- GList *current_quality;
-@@ -96,6 +104,7 @@ struct _GstMssManifest
-
- gboolean is_live;
- gint64 dvr_window;
-+ guint64 look_ahead_fragment_count;
-
- GString *protection_system_id;
- gchar *protection_data;
-@@ -235,7 +244,8 @@ compare_bitrate (GstMssStreamQuality * a, GstMssStreamQuality * b)
- }
-
- static void
--_gst_mss_stream_init (GstMssStream * stream, xmlNodePtr node)
-+_gst_mss_stream_init (GstMssManifest * manifest, GstMssStream * stream,
-+ xmlNodePtr node)
- {
- xmlNodePtr iter;
- GstMssFragmentListBuilder builder;
-@@ -248,9 +258,21 @@ _gst_mss_stream_init (GstMssStream * stream, xmlNodePtr node)
- stream->url = (gchar *) xmlGetProp (node, (xmlChar *) MSS_PROP_URL);
- stream->lang = (gchar *) xmlGetProp (node, (xmlChar *) MSS_PROP_LANGUAGE);
-
-+ /* for live playback each fragment usually has timing
-+ * information for the few next look-ahead fragments so the
-+ * playlist can be built incrementally from the first fragment
-+ * of the manifest.
-+ */
-+
-+ GST_DEBUG ("Live stream: %s, look-ahead fragments: %" G_GUINT64_FORMAT,
-+ manifest->is_live ? "yes" : "no", manifest->look_ahead_fragment_count);
-+ stream->has_live_fragments = manifest->is_live
-+ && manifest->look_ahead_fragment_count;
-+
- for (iter = node->children; iter; iter = iter->next) {
- if (node_has_type (iter, MSS_NODE_STREAM_FRAGMENT)) {
-- gst_mss_fragment_list_builder_add (&builder, iter);
-+ if (!stream->has_live_fragments || !builder.fragments)
-+ gst_mss_fragment_list_builder_add (&builder, iter);
- } else if (node_has_type (iter, MSS_NODE_STREAM_QUALITY)) {
- GstMssStreamQuality *quality = gst_mss_stream_quality_new (iter);
- stream->qualities = g_list_prepend (stream->qualities, quality);
-@@ -259,17 +281,24 @@ _gst_mss_stream_init (GstMssStream * stream, xmlNodePtr node)
- }
- }
-
-- stream->fragments = g_list_reverse (builder.fragments);
-+ if (stream->has_live_fragments) {
-+ stream->live_adapter = gst_adapter_new ();
-+ }
-+
-+ if (builder.fragments) {
-+ stream->fragments = g_list_reverse (builder.fragments);
-+ stream->current_fragment = stream->fragments;
-+ }
-
- /* order them from smaller to bigger based on bitrates */
- stream->qualities =
- g_list_sort (stream->qualities, (GCompareFunc) compare_bitrate);
--
-- stream->current_fragment = stream->fragments;
- stream->current_quality = stream->qualities;
-
- stream->regex_bitrate = g_regex_new ("\\{[Bb]itrate\\}", 0, 0, NULL);
- stream->regex_position = g_regex_new ("\\{start[ _]time\\}", 0, 0, NULL);
-+
-+ gst_mss_fragment_parser_init (&stream->fragment_parser);
- }
-
-
-@@ -315,6 +344,7 @@ gst_mss_manifest_new (GstBuffer * data)
- xmlNodePtr nodeiter;
- gchar *live_str;
- GstMapInfo mapinfo;
-+ gchar *look_ahead_fragment_count_str;
-
- if (!gst_buffer_map (data, &mapinfo, GST_MAP_READ)) {
- return NULL;
-@@ -335,6 +365,7 @@ gst_mss_manifest_new (GstBuffer * data)
- /* the entire file is always available for non-live streams */
- if (!manifest->is_live) {
- manifest->dvr_window = 0;
-+ manifest->look_ahead_fragment_count = 0;
- } else {
- /* if 0, or non-existent, the length is infinite */
- gchar *dvr_window_str = (gchar *) xmlGetProp (root,
-@@ -346,6 +377,17 @@ gst_mss_manifest_new (GstBuffer * data)
- manifest->dvr_window = 0;
- }
- }
-+
-+ look_ahead_fragment_count_str =
-+ (gchar *) xmlGetProp (root, (xmlChar *) "LookAheadFragmentCount");
-+ if (look_ahead_fragment_count_str) {
-+ manifest->look_ahead_fragment_count =
-+ g_ascii_strtoull (look_ahead_fragment_count_str, NULL, 10);
-+ xmlFree (look_ahead_fragment_count_str);
-+ if (manifest->look_ahead_fragment_count <= 0) {
-+ manifest->look_ahead_fragment_count = 0;
-+ }
-+ }
- }
-
- for (nodeiter = root->children; nodeiter; nodeiter = nodeiter->next) {
-@@ -354,7 +396,7 @@ gst_mss_manifest_new (GstBuffer * data)
- GstMssStream *stream = g_new0 (GstMssStream, 1);
-
- manifest->streams = g_slist_append (manifest->streams, stream);
-- _gst_mss_stream_init (stream, nodeiter);
-+ _gst_mss_stream_init (manifest, stream, nodeiter);
- }
-
- if (nodeiter->type == XML_ELEMENT_NODE
-@@ -371,6 +413,11 @@ gst_mss_manifest_new (GstBuffer * data)
- static void
- gst_mss_stream_free (GstMssStream * stream)
- {
-+ if (stream->live_adapter) {
-+ gst_adapter_clear (stream->live_adapter);
-+ g_object_unref (stream->live_adapter);
-+ }
-+
- g_list_free_full (stream->fragments, g_free);
- g_list_free_full (stream->qualities,
- (GDestroyNotify) gst_mss_stream_quality_free);
-@@ -379,6 +426,7 @@ gst_mss_stream_free (GstMssStream * stream)
- g_regex_unref (stream->regex_position);
- g_regex_unref (stream->regex_bitrate);
- g_free (stream);
-+ gst_mss_fragment_parser_clear (&stream->fragment_parser);
- }
-
- void
-@@ -1079,6 +1127,9 @@ GstFlowReturn
- gst_mss_stream_advance_fragment (GstMssStream * stream)
- {
- GstMssStreamFragment *fragment;
-+ const gchar *stream_type_name =
-+ gst_mss_stream_type_name (gst_mss_stream_get_type (stream));
-+
- g_return_val_if_fail (stream->active, GST_FLOW_ERROR);
-
- if (stream->current_fragment == NULL)
-@@ -1086,14 +1137,20 @@ gst_mss_stream_advance_fragment (GstMssStream * stream)
-
- fragment = stream->current_fragment->data;
- stream->fragment_repetition_index++;
-- if (stream->fragment_repetition_index < fragment->repetitions) {
-- return GST_FLOW_OK;
-- }
-+ if (stream->fragment_repetition_index < fragment->repetitions)
-+ goto beach;
-
- stream->fragment_repetition_index = 0;
- stream->current_fragment = g_list_next (stream->current_fragment);
-+
-+ GST_DEBUG ("Advanced to fragment #%d on %s stream", fragment->number,
-+ stream_type_name);
- if (stream->current_fragment == NULL)
- return GST_FLOW_EOS;
-+
-+beach:
-+ gst_mss_fragment_parser_clear (&stream->fragment_parser);
-+ gst_mss_fragment_parser_init (&stream->fragment_parser);
- return GST_FLOW_OK;
- }
-
-@@ -1173,6 +1230,11 @@ gst_mss_stream_seek (GstMssStream * stream, gboolean forward,
- GST_DEBUG ("Stream %s seeking to %" G_GUINT64_FORMAT, stream->url, time);
- for (iter = stream->fragments; iter; iter = g_list_next (iter)) {
- fragment = iter->data;
-+ if (stream->has_live_fragments) {
-+ if (fragment->time + fragment->repetitions * fragment->duration > time)
-+ stream->current_fragment = iter;
-+ break;
-+ }
- if (fragment->time + fragment->repetitions * fragment->duration > time) {
- stream->current_fragment = iter;
- stream->fragment_repetition_index =
-@@ -1256,9 +1318,14 @@ static void
- gst_mss_stream_reload_fragments (GstMssStream * stream, xmlNodePtr streamIndex)
- {
- xmlNodePtr iter;
-- guint64 current_gst_time = gst_mss_stream_get_fragment_gst_timestamp (stream);
-+ guint64 current_gst_time;
- GstMssFragmentListBuilder builder;
-
-+ if (stream->has_live_fragments)
-+ return;
-+
-+ current_gst_time = gst_mss_stream_get_fragment_gst_timestamp (stream);
-+
- gst_mss_fragment_list_builder_init (&builder);
-
- GST_DEBUG ("Current position: %" GST_TIME_FORMAT,
-@@ -1514,3 +1581,74 @@ gst_mss_manifest_get_live_seek_range (GstMssManifest * manifest, gint64 * start,
-
- return ret;
- }
-+
-+void
-+gst_mss_manifest_live_adapter_push (GstMssStream * stream, GstBuffer * buffer)
-+{
-+ gst_adapter_push (stream->live_adapter, buffer);
-+}
-+
-+gsize
-+gst_mss_manifest_live_adapter_available (GstMssStream * stream)
-+{
-+ return gst_adapter_available (stream->live_adapter);
-+}
-+
-+GstBuffer *
-+gst_mss_manifest_live_adapter_take_buffer (GstMssStream * stream, gsize nbytes)
-+{
-+ return gst_adapter_take_buffer (stream->live_adapter, nbytes);
-+}
-+
-+gboolean
-+gst_mss_stream_fragment_parsing_needed (GstMssStream * stream)
-+{
-+ return stream->fragment_parser.status == GST_MSS_FRAGMENT_HEADER_PARSER_INIT;
-+}
-+
-+void
-+gst_mss_stream_parse_fragment (GstMssStream * stream, GstBuffer * buffer)
-+{
-+ GstMssStreamFragment *current_fragment = NULL;
-+ const gchar *stream_type_name;
-+ guint8 index;
-+
-+ if (!stream->has_live_fragments)
-+ return;
-+
-+ if (!gst_mss_fragment_parser_add_buffer (&stream->fragment_parser, buffer))
-+ return;
-+
-+ current_fragment = stream->current_fragment->data;
-+ current_fragment->time = stream->fragment_parser.tfxd.time;
-+ current_fragment->duration = stream->fragment_parser.tfxd.duration;
-+
-+ stream_type_name =
-+ gst_mss_stream_type_name (gst_mss_stream_get_type (stream));
-+
-+ for (index = 0; index < stream->fragment_parser.tfrf.entries_count; index++) {
-+ GList *l = g_list_last (stream->fragments);
-+ GstMssStreamFragment *last;
-+ GstMssStreamFragment *fragment;
-+
-+ if (l == NULL)
-+ break;
-+
-+ last = (GstMssStreamFragment *) l->data;
-+
-+ if (last->time == stream->fragment_parser.tfrf.entries[index].time)
-+ continue;
-+
-+ fragment = g_new (GstMssStreamFragment, 1);
-+ fragment->number = last->number + 1;
-+ fragment->repetitions = 1;
-+ fragment->time = stream->fragment_parser.tfrf.entries[index].time;
-+ fragment->duration = stream->fragment_parser.tfrf.entries[index].duration;
-+
-+ stream->fragments = g_list_append (stream->fragments, fragment);
-+ GST_LOG ("Adding fragment number: %u to %s stream, time: %" G_GUINT64_FORMAT
-+ ", duration: %" G_GUINT64_FORMAT ", repetitions: %u",
-+ fragment->number, stream_type_name,
-+ fragment->time, fragment->duration, fragment->repetitions);
-+ }
-+}
-diff --git a/ext/smoothstreaming/gstmssmanifest.h b/ext/smoothstreaming/gstmssmanifest.h
-index 6b7b1f971..03b066ae5 100644
---- a/ext/smoothstreaming/gstmssmanifest.h
-+++ b/ext/smoothstreaming/gstmssmanifest.h
-@@ -26,6 +26,7 @@
- #include <glib.h>
- #include <gio/gio.h>
- #include <gst/gst.h>
-+#include <gst/base/gstadapter.h>
-
- G_BEGIN_DECLS
-
-@@ -73,5 +74,11 @@ const gchar * gst_mss_stream_get_lang (GstMssStream * stream);
-
- const gchar * gst_mss_stream_type_name (GstMssStreamType streamtype);
-
-+void gst_mss_manifest_live_adapter_push(GstMssStream * stream, GstBuffer * buffer);
-+gsize gst_mss_manifest_live_adapter_available(GstMssStream * stream);
-+GstBuffer * gst_mss_manifest_live_adapter_take_buffer(GstMssStream * stream, gsize nbytes);
-+gboolean gst_mss_stream_fragment_parsing_needed(GstMssStream * stream);
-+void gst_mss_stream_parse_fragment(GstMssStream * stream, GstBuffer * buffer);
-+
- G_END_DECLS
- #endif /* __GST_MSS_MANIFEST_H__ */
-diff --git a/gst-libs/gst/adaptivedemux/gstadaptivedemux.c b/gst-libs/gst/adaptivedemux/gstadaptivedemux.c
-index 634e4f388..ddca726b6 100644
---- a/gst-libs/gst/adaptivedemux/gstadaptivedemux.c
-+++ b/gst-libs/gst/adaptivedemux/gstadaptivedemux.c
-@@ -291,6 +291,9 @@ gst_adaptive_demux_wait_until (GstClock * clock, GCond * cond, GMutex * mutex,
- GstClockTime end_time);
- static gboolean gst_adaptive_demux_clock_callback (GstClock * clock,
- GstClockTime time, GstClockID id, gpointer user_data);
-+static gboolean
-+gst_adaptive_demux_requires_periodical_playlist_update_default (GstAdaptiveDemux
-+ * demux);
-
- /* we can't use G_DEFINE_ABSTRACT_TYPE because we need the klass in the _init
- * method to get to the padtemplates */
-@@ -412,6 +415,9 @@ gst_adaptive_demux_class_init (GstAdaptiveDemuxClass * klass)
- klass->data_received = gst_adaptive_demux_stream_data_received_default;
- klass->finish_fragment = gst_adaptive_demux_stream_finish_fragment_default;
- klass->update_manifest = gst_adaptive_demux_update_manifest_default;
-+ klass->requires_periodical_playlist_update =
-+ gst_adaptive_demux_requires_periodical_playlist_update_default;
-+
- }
-
- static void
-@@ -686,7 +692,9 @@ gst_adaptive_demux_sink_event (GstPad * pad, GstObject * parent,
- demux->priv->stop_updates_task = FALSE;
- g_mutex_unlock (&demux->priv->updates_timed_lock);
- /* Task to periodically update the manifest */
-- gst_task_start (demux->priv->updates_task);
-+ if (demux_class->requires_periodical_playlist_update (demux)) {
-+ gst_task_start (demux->priv->updates_task);
-+ }
- }
- } else {
- /* no streams */
-@@ -2125,6 +2133,13 @@ gst_adaptive_demux_stream_data_received_default (GstAdaptiveDemux * demux,
- return gst_adaptive_demux_stream_push_buffer (stream, buffer);
- }
-
-+static gboolean
-+gst_adaptive_demux_requires_periodical_playlist_update_default (GstAdaptiveDemux
-+ * demux)
-+{
-+ return TRUE;
-+}
-+
- static GstFlowReturn
- _src_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
- {
-@@ -3338,7 +3353,15 @@ gst_adaptive_demux_stream_download_loop (GstAdaptiveDemuxStream * stream)
- GST_DEBUG_OBJECT (stream->pad, "EOS, checking to stop download loop");
- /* we push the EOS after releasing the object lock */
- if (gst_adaptive_demux_is_live (demux)) {
-- if (gst_adaptive_demux_stream_wait_manifest_update (demux, stream)) {
-+ GstAdaptiveDemuxClass *demux_class =
-+ GST_ADAPTIVE_DEMUX_GET_CLASS (demux);
-+
-+ /* this might be a fragment download error, refresh the manifest, just in case */
-+ if (!demux_class->requires_periodical_playlist_update (demux)) {
-+ ret = gst_adaptive_demux_update_manifest (demux);
-+ break;
-+ } else if (gst_adaptive_demux_stream_wait_manifest_update (demux,
-+ stream)) {
- goto end;
- }
- gst_task_stop (stream->download_task);
-diff --git a/gst-libs/gst/adaptivedemux/gstadaptivedemux.h b/gst-libs/gst/adaptivedemux/gstadaptivedemux.h
-index 780f4d93f..9a1a1b7d1 100644
---- a/gst-libs/gst/adaptivedemux/gstadaptivedemux.h
-+++ b/gst-libs/gst/adaptivedemux/gstadaptivedemux.h
-@@ -459,6 +459,20 @@ struct _GstAdaptiveDemuxClass
- * 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_get_type (void);
---
-2.11.0
-