Commit 229a15b3 authored by Thiago Santos's avatar Thiago Santos

adaptivedemux: refactor chunk downloading flow

Add more power to the chunk_received function (renamed to data_received)
and also to the fragment_finish function.

The data_received function must parse/decrypt the data if necessary and
also push it using the new push_buffer function that is exposed now. The
default implementation gets data from the stream adapter (all available)
and pushes it.

The fragment_finish function must also advance the fragment. The default
implementation only advances the fragment.

This allows the subsegment handling in dashdemux to continuously download
the same file from the server instead of stopping at every subsegment
boundary and starting a new request
parent 15d51c1f
......@@ -200,7 +200,7 @@ static GstFlowReturn gst_dash_demux_stream_seek (GstAdaptiveDemuxStream *
stream, GstClockTime ts);
static GstFlowReturn
gst_dash_demux_stream_advance_fragment (GstAdaptiveDemuxStream * stream);
static void
static gboolean
gst_dash_demux_stream_advance_subfragment (GstAdaptiveDemuxStream * stream);
static gboolean gst_dash_demux_stream_select_bitrate (GstAdaptiveDemuxStream *
stream, guint64 bitrate);
......@@ -213,8 +213,11 @@ gst_dash_demux_stream_get_fragment_waiting_time (GstAdaptiveDemuxStream *
stream);
static void gst_dash_demux_advance_period (GstAdaptiveDemux * demux);
static gboolean gst_dash_demux_has_next_period (GstAdaptiveDemux * demux);
static GstFlowReturn gst_dash_demux_chunk_received (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream, GstBuffer ** chunk);
static GstFlowReturn gst_dash_demux_data_received (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream);
static GstFlowReturn
gst_dash_demux_stream_fragment_finished (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream);
/* GstDashDemux */
static gboolean gst_dash_demux_setup_all_streams (GstDashDemux * demux);
......@@ -600,7 +603,8 @@ gst_dash_demux_process_manifest (GstAdaptiveDemux * demux, GstBuffer * buf)
if (gst_mpd_client_has_isoff_ondemand_profile (dashdemux->client)) {
klass = GST_ADAPTIVE_DEMUX_GET_CLASS (dashdemux);
klass->chunk_received = gst_dash_demux_chunk_received;
klass->data_received = gst_dash_demux_data_received;
klass->finish_fragment = gst_dash_demux_stream_fragment_finished;
}
if (gst_mpd_client_setup_media_presentation (dashdemux->client)) {
......@@ -882,7 +886,7 @@ gst_dash_demux_stream_seek (GstAdaptiveDemuxStream * stream, GstClockTime ts)
return GST_FLOW_OK;
}
static void
static gboolean
gst_dash_demux_stream_advance_subfragment (GstAdaptiveDemuxStream * stream)
{
GstDashDemuxStream *dashstream = (GstDashDemuxStream *) stream;
......@@ -905,6 +909,7 @@ gst_dash_demux_stream_advance_subfragment (GstAdaptiveDemuxStream * stream)
if (!fragment_finished) {
dashstream->sidx_current_remaining = sidx->entries[sidx->entry_index].size;
}
return !fragment_finished;
}
static GstFlowReturn
......@@ -914,17 +919,8 @@ gst_dash_demux_stream_advance_fragment (GstAdaptiveDemuxStream * stream)
GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (stream->demux);
if (gst_mpd_client_has_isoff_ondemand_profile (dashdemux->client)) {
GstSidxBox *sidx = SIDX (dashstream);
if (stream->demux->segment.rate > 0.0) {
if (sidx->entry_index < sidx->entries_count) {
return GST_FLOW_OK;
}
} else {
if (sidx->entry_index >= 0) {
return GST_FLOW_OK;
}
}
if (gst_dash_demux_stream_advance_subfragment (stream))
return GST_FLOW_OK;
}
return gst_mpd_client_advance_segment (dashdemux->client,
......@@ -986,22 +982,14 @@ gst_dash_demux_stream_select_bitrate (GstAdaptiveDemuxStream * stream,
if (gst_mpd_client_has_isoff_ondemand_profile (demux->client)) {
/* a new subsegment is going to start, cleanup any pending data from the
* previous one */
/* store our current position to change to the same one in a different
* representation if needed */
dashstream->sidx_index = SIDX (dashstream)->entry_index;
if (dashstream->pending_buffer) {
gst_buffer_unref (dashstream->pending_buffer);
dashstream->pending_buffer = NULL;
}
if (ret) {
/* TODO cache indexes to avoid re-downloading and parsing */
/* if we switched, we need a new index */
gst_isoff_sidx_parser_clear (&dashstream->sidx_parser);
gst_isoff_sidx_parser_init (&dashstream->sidx_parser);
} else {
dashstream->sidx_current_remaining =
SIDX_ENTRY (dashstream, dashstream->sidx_index)->size;
}
}
......@@ -1071,11 +1059,6 @@ gst_dash_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek)
gst_isoff_sidx_parser_clear (&dashstream->sidx_parser);
gst_isoff_sidx_parser_init (&dashstream->sidx_parser);
}
if (dashstream->pending_buffer) {
gst_buffer_unref (dashstream->pending_buffer);
dashstream->pending_buffer = NULL;
}
gst_dash_demux_stream_seek (iter->data, target_pos);
}
return TRUE;
......@@ -1247,88 +1230,112 @@ gst_dash_demux_advance_period (GstAdaptiveDemux * demux)
}
static GstBuffer *
_gst_buffer_split (GstBuffer ** buffer, gint offset, gsize size)
_gst_buffer_split (GstBuffer * buffer, gint offset, gsize size)
{
GstBuffer *newbuf = gst_buffer_copy_region (*buffer,
GstBuffer *newbuf = gst_buffer_copy_region (buffer,
GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_META
| GST_BUFFER_COPY_MEMORY, offset, size - offset);
gst_buffer_resize (*buffer, 0, offset);
gst_buffer_resize (buffer, 0, offset);
return newbuf;
}
static GstFlowReturn
gst_dash_demux_chunk_received (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream, GstBuffer ** chunk)
gst_dash_demux_stream_fragment_finished (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream)
{
GstDashDemuxStream *dash_stream = (GstDashDemuxStream *) stream;
GstFlowReturn ret = GST_FLOW_OK;
GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (demux);
if (*chunk == NULL) {
if (dash_stream->pending_buffer) {
*chunk = dash_stream->pending_buffer;
dash_stream->pending_buffer = NULL;
}
if (gst_mpd_client_has_isoff_ondemand_profile (dashdemux->client)) {
/* fragment is advanced on data_received when byte limits are reached */
return GST_FLOW_OK;
} else {
return gst_adaptive_demux_stream_advance_fragment (demux, stream,
stream->fragment.duration);
}
}
if (dash_stream->pending_buffer) {
*chunk = gst_buffer_append (dash_stream->pending_buffer, *chunk);
dash_stream->pending_buffer = NULL;
}
static GstFlowReturn
gst_dash_demux_data_received (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream)
{
GstDashDemuxStream *dash_stream = (GstDashDemuxStream *) stream;
GstFlowReturn ret = GST_FLOW_OK;
GstBuffer *buffer;
gsize available;
if (stream->downloading_index
&& dash_stream->sidx_parser.status != GST_ISOFF_SIDX_PARSER_FINISHED) {
if (stream->downloading_index) {
GstIsoffParserResult res;
guint consumed;
res =
gst_isoff_sidx_parser_add_buffer (&dash_stream->sidx_parser, *chunk,
&consumed);
available = gst_adapter_available (stream->adapter);
buffer = gst_adapter_take_buffer (stream->adapter, available);
if (res == GST_ISOFF_PARSER_ERROR) {
} else if (res == GST_ISOFF_PARSER_UNEXPECTED) {
/* this is not a 'sidx' index, just skip it and continue playback */
} else {
/* when finished, prepare for real data streaming */
if (dash_stream->sidx_parser.status == GST_ISOFF_SIDX_PARSER_FINISHED) {
if (GST_CLOCK_TIME_IS_VALID (dash_stream->pending_seek_ts)) {
gst_dash_demux_stream_sidx_seek (dash_stream,
dash_stream->pending_seek_ts);
dash_stream->pending_seek_ts = GST_CLOCK_TIME_NONE;
} else {
SIDX (dash_stream)->entry_index = dash_stream->sidx_index;
if (dash_stream->sidx_parser.status != GST_ISOFF_SIDX_PARSER_FINISHED) {
res =
gst_isoff_sidx_parser_add_buffer (&dash_stream->sidx_parser, buffer,
&consumed);
if (res == GST_ISOFF_PARSER_ERROR) {
} else if (res == GST_ISOFF_PARSER_UNEXPECTED) {
/* this is not a 'sidx' index, just skip it and continue playback */
} else {
/* when finished, prepare for real data streaming */
if (dash_stream->sidx_parser.status == GST_ISOFF_SIDX_PARSER_FINISHED) {
if (GST_CLOCK_TIME_IS_VALID (dash_stream->pending_seek_ts)) {
gst_dash_demux_stream_sidx_seek (dash_stream,
dash_stream->pending_seek_ts);
dash_stream->pending_seek_ts = GST_CLOCK_TIME_NONE;
} else {
SIDX (dash_stream)->entry_index = dash_stream->sidx_index;
}
dash_stream->sidx_current_remaining =
SIDX_CURRENT_ENTRY (dash_stream)->size;
} else if (consumed < available) {
GstBuffer *pending;
/* we still need to keep some data around for the next parsing round
* so just push what was already processed by the parser */
pending = _gst_buffer_split (buffer, consumed, -1);
gst_adapter_push (stream->adapter, pending);
}
dash_stream->sidx_current_remaining =
SIDX_CURRENT_ENTRY (dash_stream)->size;
} else if (consumed < gst_buffer_get_size (*chunk)) {
dash_stream->pending_buffer = _gst_buffer_split (chunk, consumed, -1);
}
}
}
ret = gst_adaptive_demux_stream_push_buffer (stream, buffer);
} else if (dash_stream->sidx_parser.status == GST_ISOFF_SIDX_PARSER_FINISHED) {
/* check our position in subsegments */
if (!stream->downloading_index
&& dash_stream->sidx_parser.status == GST_ISOFF_SIDX_PARSER_FINISHED) {
gsize size = gst_buffer_get_size (*chunk);
GST_LOG_OBJECT (stream->pad,
"Received buffer of size: %" G_GSIZE_FORMAT
" - remaining in subsegment: %" G_GSIZE_FORMAT, size,
dash_stream->sidx_current_remaining);
if (size < dash_stream->sidx_current_remaining) {
dash_stream->sidx_current_remaining -= size;
} else if (size >= dash_stream->sidx_current_remaining) {
if (size > dash_stream->sidx_current_remaining) {
dash_stream->pending_buffer =
_gst_buffer_split (chunk, dash_stream->sidx_current_remaining,
size);
}
while (ret == GST_FLOW_OK
&& ((available = gst_adapter_available (stream->adapter)) > 0)) {
gboolean advance = FALSE;
gst_dash_demux_stream_advance_subfragment (stream);
ret = (GstFlowReturn) GST_ADAPTIVE_DEMUX_FLOW_SUBSEGMENT_END;
if (available < dash_stream->sidx_current_remaining) {
buffer = gst_adapter_take_buffer (stream->adapter, available);
dash_stream->sidx_current_remaining -= available;
} else {
buffer =
gst_adapter_take_buffer (stream->adapter,
dash_stream->sidx_current_remaining);
dash_stream->sidx_current_remaining = 0;
advance = TRUE;
}
ret = gst_adaptive_demux_stream_push_buffer (stream, buffer);
if (advance) {
GstFlowReturn new_ret;
new_ret =
gst_adaptive_demux_stream_advance_fragment (demux, stream,
SIDX_CURRENT_ENTRY (dash_stream)->duration);
/* only overwrite if it was OK before */
if (ret == GST_FLOW_OK)
ret = new_ret;
}
}
} else {
/* this should be the main header, just push it all */
ret =
gst_adaptive_demux_stream_push_buffer (stream,
gst_adapter_take_buffer (stream->adapter,
gst_adapter_available (stream->adapter)));
}
return ret;
......@@ -1340,6 +1347,4 @@ gst_dash_demux_stream_free (GstAdaptiveDemuxStream * stream)
GstDashDemuxStream *dash_stream = (GstDashDemuxStream *) stream;
gst_isoff_sidx_parser_clear (&dash_stream->sidx_parser);
if (dash_stream->pending_buffer)
gst_buffer_unref (dash_stream->pending_buffer);
}
......@@ -65,8 +65,6 @@ struct _GstDashDemuxStream
GstMediaFragmentInfo current_fragment;
GstBuffer *pending_buffer;
/* index parsing */
GstSidxParser sidx_parser;
gsize sidx_current_remaining;
......
......@@ -111,10 +111,10 @@ static gboolean gst_hls_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek);
static gboolean
gst_hls_demux_start_fragment (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream);
static void gst_hls_demux_finish_fragment (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream, GstBuffer ** buffer);
static GstFlowReturn gst_hls_demux_chunk_received (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream, GstBuffer ** chunk);
static GstFlowReturn gst_hls_demux_finish_fragment (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream);
static GstFlowReturn gst_hls_demux_data_received (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream);
static gboolean gst_hls_demux_stream_has_next_fragment (GstAdaptiveDemuxStream *
stream);
static GstFlowReturn gst_hls_demux_advance_fragment (GstAdaptiveDemuxStream *
......@@ -216,7 +216,7 @@ gst_hls_demux_class_init (GstHLSDemuxClass * klass)
adaptivedemux_class->start_fragment = gst_hls_demux_start_fragment;
adaptivedemux_class->finish_fragment = gst_hls_demux_finish_fragment;
adaptivedemux_class->chunk_received = gst_hls_demux_chunk_received;
adaptivedemux_class->data_received = gst_hls_demux_data_received;
GST_DEBUG_CATEGORY_INIT (gst_hls_demux_debug, "hlsdemux", 0,
"hlsdemux element");
......@@ -289,9 +289,6 @@ gst_hls_demux_change_state (GstElement * element, GstStateChange transition)
gst_hls_demux_reset (GST_ADAPTIVE_DEMUX_CAST (demux));
gst_uri_downloader_reset (demux->downloader);
break;
case GST_STATE_CHANGE_NULL_TO_READY:
demux->adapter = gst_adapter_new ();
break;
default:
break;
}
......@@ -302,10 +299,6 @@ gst_hls_demux_change_state (GstElement * element, GstStateChange transition)
case GST_STATE_CHANGE_PAUSED_TO_READY:
gst_hls_demux_reset (GST_ADAPTIVE_DEMUX_CAST (demux));
break;
case GST_STATE_CHANGE_READY_TO_NULL:
gst_object_unref (demux->adapter);
demux->adapter = NULL;
break;
default:
break;
}
......@@ -364,11 +357,6 @@ gst_hls_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek)
/* properly cleanup pending decryption status */
if (flags & GST_SEEK_FLAG_FLUSH) {
if (hlsdemux->adapter)
gst_adapter_clear (hlsdemux->adapter);
if (hlsdemux->pending_buffer)
gst_buffer_unref (hlsdemux->pending_buffer);
hlsdemux->pending_buffer = NULL;
gst_hls_demux_decrypt_end (hlsdemux);
}
......@@ -593,9 +581,9 @@ key_failed:
return FALSE;
}
static void
static GstFlowReturn
gst_hls_demux_finish_fragment (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream, GstBuffer ** buffer)
GstAdaptiveDemuxStream * stream)
{
GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
......@@ -605,8 +593,8 @@ gst_hls_demux_finish_fragment (GstAdaptiveDemux * demux,
/* ideally this should be empty, but this eos might have been
* caused by an error on the source element */
GST_DEBUG_OBJECT (demux, "Data still on the adapter when EOS was received"
": %" G_GSIZE_FORMAT, gst_adapter_available (hlsdemux->adapter));
gst_adapter_clear (hlsdemux->adapter);
": %" G_GSIZE_FORMAT, gst_adapter_available (stream->adapter));
gst_adapter_clear (stream->adapter);
/* pending buffer is only used for encrypted streams */
if (stream->last_ret == GST_FLOW_OK) {
......@@ -621,40 +609,41 @@ gst_hls_demux_finish_fragment (GstAdaptiveDemux * demux,
gst_buffer_resize (hlsdemux->pending_buffer, 0, unpadded_size);
*buffer = hlsdemux->pending_buffer;
hlsdemux->pending_buffer = NULL;
gst_adaptive_demux_stream_push_buffer (stream, hlsdemux->pending_buffer);
}
} else {
if (hlsdemux->pending_buffer)
gst_buffer_unref (hlsdemux->pending_buffer);
hlsdemux->pending_buffer = NULL;
}
return gst_adaptive_demux_stream_advance_fragment (demux, stream,
stream->fragment.duration);
}
static GstFlowReturn
gst_hls_demux_chunk_received (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream, GstBuffer ** chunk)
gst_hls_demux_data_received (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream)
{
GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (demux);
GstBuffer *buffer = *chunk;
gsize available;
GstBuffer *buffer = NULL;
available = gst_adapter_available (stream->adapter);
/* Is it encrypted? */
if (hlsdemux->current_key) {
GError *err = NULL;
GstBuffer *tmp_buffer;
gsize available;
gst_adapter_push (hlsdemux->adapter, buffer);
*chunk = NULL;
/* must be a multiple of 16 */
available = gst_adapter_available (hlsdemux->adapter) & (~0xF);
available = available & (~0xF);
if (available == 0) {
return GST_FLOW_OK;
}
buffer = gst_adapter_take_buffer (hlsdemux->adapter, available);
buffer = gst_adapter_take_buffer (stream->adapter, available);
buffer = gst_hls_demux_decrypt_fragment (hlsdemux, buffer, &err);
if (buffer == NULL) {
GST_ELEMENT_ERROR (demux, STREAM, DECODE, ("Failed to decrypt buffer"),
......@@ -665,14 +654,15 @@ gst_hls_demux_chunk_received (GstAdaptiveDemux * demux,
tmp_buffer = hlsdemux->pending_buffer;
hlsdemux->pending_buffer = buffer;
*chunk = tmp_buffer;
} else if (hlsdemux->pending_buffer) {
*chunk = gst_buffer_append (hlsdemux->pending_buffer, buffer);
hlsdemux->pending_buffer = NULL;
buffer = tmp_buffer;
} else {
buffer = gst_adapter_take_buffer (stream->adapter, available);
if (hlsdemux->pending_buffer) {
buffer = gst_buffer_append (hlsdemux->pending_buffer, buffer);
hlsdemux->pending_buffer = NULL;
}
}
buffer = *chunk;
if (G_UNLIKELY (hlsdemux->do_typefind && buffer != NULL)) {
GstCaps *caps = NULL;
GstMapInfo info;
......@@ -697,6 +687,7 @@ gst_hls_demux_chunk_received (GstAdaptiveDemux * demux,
if (buffer_size > (2 * 1024 * 1024)) {
GST_ELEMENT_ERROR (hlsdemux, STREAM, TYPE_NOT_FOUND,
("Could not determine type of stream"), (NULL));
gst_buffer_unref (buffer);
return GST_FLOW_NOT_NEGOTIATED;
} else {
if (hlsdemux->pending_buffer)
......@@ -704,7 +695,6 @@ gst_hls_demux_chunk_received (GstAdaptiveDemux * demux,
gst_buffer_append (buffer, hlsdemux->pending_buffer);
else
hlsdemux->pending_buffer = buffer;
*chunk = NULL;
return GST_FLOW_OK;
}
}
......@@ -722,6 +712,9 @@ gst_hls_demux_chunk_received (GstAdaptiveDemux * demux,
hlsdemux->do_typefind = FALSE;
}
if (buffer) {
return gst_adaptive_demux_stream_push_buffer (stream, buffer);
}
return GST_FLOW_OK;
}
......@@ -842,8 +835,6 @@ gst_hls_demux_reset (GstAdaptiveDemux * ademux)
demux->client = gst_m3u8_client_new ("", NULL);
demux->srcpad_counter = 0;
if (demux->adapter)
gst_adapter_clear (demux->adapter);
if (demux->pending_buffer)
gst_buffer_unref (demux->pending_buffer);
demux->pending_buffer = NULL;
......
......@@ -25,7 +25,6 @@
#define __GST_HLS_DEMUX_H__
#include <gst/gst.h>
#include <gst/base/gstadapter.h>
#include "m3u8.h"
#include "gstfragmented.h"
#include <gst/uridownloader/gsturidownloader.h>
......@@ -96,7 +95,6 @@ struct _GstHLSDemux
#endif
gchar *current_key;
guint8 *current_iv;
GstAdapter *adapter; /* used to accumulate 16 bytes multiple chunks */
GstBuffer *pending_buffer; /* decryption scenario:
* the last buffer can only be pushed when
* resized, so need to store and wait for
......
......@@ -87,6 +87,11 @@ GST_DEBUG_CATEGORY (adaptivedemux_debug);
#define MAX_DOWNLOAD_ERROR_COUNT 3
#define DEFAULT_FAILED_COUNT 3
enum GstAdaptiveDemuxFlowReturn
{
GST_ADAPTIVE_DEMUX_FLOW_SWITCH = GST_FLOW_CUSTOM_SUCCESS_2 + 1
};
struct _GstAdaptiveDemuxPrivate
{
GstAdapter *input_adapter;
......@@ -141,9 +146,6 @@ static GstFlowReturn gst_adaptive_demux_stream_seek (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream, GstClockTime ts);
static gboolean gst_adaptive_demux_stream_has_next_fragment (GstAdaptiveDemux *
demux, GstAdaptiveDemuxStream * stream);
static GstFlowReturn
gst_adaptive_demux_stream_advance_fragment (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream);
static gboolean gst_adaptive_demux_stream_select_bitrate (GstAdaptiveDemux *
demux, GstAdaptiveDemuxStream * stream, guint64 bitrate);
static GstFlowReturn
......@@ -171,6 +173,12 @@ static GstFlowReturn gst_adaptive_demux_combine_flows (GstAdaptiveDemux *
static void
gst_adaptive_demux_stream_fragment_download_finish (GstAdaptiveDemuxStream *
stream, GstFlowReturn ret, GError * err);
static GstFlowReturn
gst_adaptive_demux_stream_data_received_default (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream);
static GstFlowReturn
gst_adaptive_demux_stream_finish_fragment_default (GstAdaptiveDemux * demux,
GstAdaptiveDemuxStream * stream);
/* we can't use G_DEFINE_ABSTRACT_TYPE because we need the klass in the _init
......@@ -223,6 +231,9 @@ gst_adaptive_demux_class_init (GstAdaptiveDemuxClass * klass)
gstelement_class->change_state = gst_adaptive_demux_change_state;
gstbin_class->handle_message = gst_adaptive_demux_handle_message;
klass->data_received = gst_adaptive_demux_stream_data_received_default;
klass->finish_fragment = gst_adaptive_demux_stream_finish_fragment_default;
}
static void
......@@ -251,7 +262,6 @@ gst_adaptive_demux_init (GstAdaptiveDemux * demux,
g_cond_init (&demux->priv->updates_timed_cond);
g_cond_init (&demux->manifest_cond);
g_mutex_init (&demux->manifest_lock);
pad_template =
......@@ -299,8 +309,6 @@ gst_adaptive_demux_change_state (GstElement * element,
case GST_STATE_CHANGE_PAUSED_TO_READY:
gst_adaptive_demux_reset (demux);
break;
case GST_STATE_CHANGE_READY_TO_NULL:
break;
default:
break;
}
......@@ -704,6 +712,7 @@ gst_adaptive_demux_stream_new (GstAdaptiveDemux * demux, GstPad * pad)
gst_segment_init (&stream->segment, GST_FORMAT_TIME);
g_cond_init (&stream->fragment_download_cond);
g_mutex_init (&stream->fragment_download_lock);
stream->adapter = gst_adapter_new ();
demux->next_streams = g_list_append (demux->next_streams, stream);
......@@ -763,6 +772,9 @@ gst_adaptive_demux_stream_free (GstAdaptiveDemuxStream * stream)
}
if (stream->pending_caps)
gst_caps_unref (stream->pending_caps);
g_object_unref (stream->adapter);
g_free (stream);
}
......@@ -1110,6 +1122,7 @@ gst_adaptive_demux_stop_tasks (GstAdaptiveDemux * demux)
gst_task_join (stream->download_task);
stream->download_error_count = 0;
stream->need_header = TRUE;
gst_adapter_clear (stream->adapter);
}
gst_task_join (demux->priv->updates_task);
}
......@@ -1167,6 +1180,9 @@ gst_adaptive_demux_stream_update_current_bitrate (GstAdaptiveDemuxStream *
if (bitrate > G_MAXINT)
bitrate = G_MAXINT;
stream->current_download_rate = bitrate;
GST_DEBUG_OBJECT (stream->pad, "Bitrate: %" G_GUINT64_FORMAT
" (bytes: %" G_GINT64_FORMAT " / %" G_GINT64_FORMAT " microsecs",
bitrate, stream->download_total_bytes, stream->download_total_time);
return bitrate;
}
......@@ -1202,54 +1218,13 @@ gst_adaptive_demux_combine_flows (GstAdaptiveDemux * demux)
return GST_FLOW_OK;
}
static GstFlowReturn
_src_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
GstFlowReturn
gst_adaptive_demux_stream_push_buffer (GstAdaptiveDemuxStream * stream,
GstBuffer * buffer)
{
GstPad *srcpad = (GstPad *) parent;
GstAdaptiveDemuxStream *stream = gst_pad_get_element_private (srcpad);
GstAdaptiveDemux *demux = stream->demux;
GstAdaptiveDemuxClass *klass = GST_ADAPTIVE_DEMUX_GET_CLASS (demux);
GstFlowReturn ret = GST_FLOW_OK;
gboolean discont = FALSE;
gboolean subsegment_end = FALSE;
if (stream->starting_fragment) {
stream->starting_fragment = FALSE;
if (klass->start_fragment) {
klass->start_fragment (demux, stream);
}
GST_BUFFER_PTS (buffer) = stream->fragment.timestamp;
GST_LOG_OBJECT (stream->pad, "set fragment pts=%" GST_TIME_FORMAT,
GST_TIME_ARGS (GST_BUFFER_PTS (buffer)));
if (GST_BUFFER_PTS_IS_VALID (buffer))
stream->segment.position = GST_BUFFER_PTS (buffer);
} else {
GST_BUFFER_PTS (buffer) = GST_CLOCK_TIME_NONE;
}
/* The subclass might need to decrypt or modify the buffer somehow