hlsdemux: handle errors from internal source

Set up a message handling function to catch errors from the internal
source and store the last return code to identify error situations
when returning from a fragment download.

Also moves the duration increase to after the download when we
know if it was successful or not
This commit is contained in:
Thiago Santos 2014-04-29 15:19:51 -03:00
parent f16560c520
commit 4431388cab
2 changed files with 65 additions and 8 deletions

View file

@ -83,6 +83,8 @@ static void gst_hls_demux_dispose (GObject * obj);
static GstStateChangeReturn static GstStateChangeReturn
gst_hls_demux_change_state (GstElement * element, GstStateChange transition); gst_hls_demux_change_state (GstElement * element, GstStateChange transition);
static void gst_hls_demux_handle_message (GstBin * bin, GstMessage * msg);
/* GstHLSDemux */ /* GstHLSDemux */
static GstFlowReturn gst_hls_demux_chain (GstPad * pad, GstObject * parent, static GstFlowReturn gst_hls_demux_chain (GstPad * pad, GstObject * parent,
GstBuffer * buf); GstBuffer * buf);
@ -157,9 +159,11 @@ gst_hls_demux_class_init (GstHLSDemuxClass * klass)
{ {
GObjectClass *gobject_class; GObjectClass *gobject_class;
GstElementClass *element_class; GstElementClass *element_class;
GstBinClass *bin_class;
gobject_class = (GObjectClass *) klass; gobject_class = (GObjectClass *) klass;
element_class = (GstElementClass *) klass; element_class = (GstElementClass *) klass;
bin_class = (GstBinClass *) klass;
gobject_class->set_property = gst_hls_demux_set_property; gobject_class->set_property = gst_hls_demux_set_property;
gobject_class->get_property = gst_hls_demux_get_property; gobject_class->get_property = gst_hls_demux_get_property;
@ -200,6 +204,8 @@ gst_hls_demux_class_init (GstHLSDemuxClass * klass)
"Marc-Andre Lureau <marcandre.lureau@gmail.com>\n" "Marc-Andre Lureau <marcandre.lureau@gmail.com>\n"
"Andoni Morales Alastruey <ylatuya@gmail.com>"); "Andoni Morales Alastruey <ylatuya@gmail.com>");
bin_class->handle_message = gst_hls_demux_handle_message;
GST_DEBUG_CATEGORY_INIT (gst_hls_demux_debug, "hlsdemux", 0, GST_DEBUG_CATEGORY_INIT (gst_hls_demux_debug, "hlsdemux", 0,
"hlsdemux element"); "hlsdemux element");
} }
@ -327,6 +333,41 @@ gst_hls_demux_change_state (GstElement * element, GstStateChange transition)
return ret; return ret;
} }
static void
gst_hls_demux_handle_message (GstBin * bin, GstMessage * msg)
{
GstHLSDemux *demux = GST_HLS_DEMUX_CAST (bin);
switch (GST_MESSAGE_TYPE (msg)) {
case GST_MESSAGE_ERROR:{
GError *err = NULL;
gchar *debug = NULL;
gst_message_parse_error (msg, &err, &debug);
GST_WARNING_OBJECT (demux, "Source posted error: %d:%d %s (%s)",
err->domain, err->code, err->message, debug);
/* error, but ask to retry */
g_mutex_lock (&demux->fragment_download_lock);
demux->last_ret = GST_FLOW_CUSTOM_ERROR;
g_cond_signal (&demux->fragment_download_cond);
g_mutex_unlock (&demux->fragment_download_lock);
g_error_free (err);
g_free (debug);
gst_message_unref (msg);
msg = NULL;
}
break;
default:
break;
}
if (msg)
GST_BIN_CLASS (parent_class)->handle_message (bin, msg);
}
static gboolean static gboolean
gst_hls_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event) gst_hls_demux_src_event (GstPad * pad, GstObject * parent, GstEvent * event)
{ {
@ -790,6 +831,7 @@ _src_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
("decryption failed %s", err->message)); ("decryption failed %s", err->message));
g_error_free (err); g_error_free (err);
demux->last_ret = GST_FLOW_ERROR;
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
} }
@ -824,6 +866,7 @@ _src_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
GST_ELEMENT_ERROR (demux, STREAM, TYPE_NOT_FOUND, GST_ELEMENT_ERROR (demux, STREAM, TYPE_NOT_FOUND,
("Could not determine type of stream"), (NULL)); ("Could not determine type of stream"), (NULL));
gst_buffer_unref (buffer); gst_buffer_unref (buffer);
demux->last_ret = GST_FLOW_NOT_NEGOTIATED;
return GST_FLOW_NOT_NEGOTIATED; return GST_FLOW_NOT_NEGOTIATED;
} }
@ -848,10 +891,6 @@ _src_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
demux->starting_fragment = FALSE; demux->starting_fragment = FALSE;
demux->segment.position = GST_BUFFER_TIMESTAMP (buffer); demux->segment.position = GST_BUFFER_TIMESTAMP (buffer);
#if 0
if (demux->segment.rate > 0)
demux->segment.position += GST_BUFFER_DURATION (buf);
#endif
if (demux->need_segment) { if (demux->need_segment) {
/* And send a newsegment */ /* And send a newsegment */
@ -882,12 +921,14 @@ _src_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
} }
/* avoid having the source handle the same error again */ /* avoid having the source handle the same error again */
demux->last_ret = ret;
ret = GST_FLOW_OK; ret = GST_FLOW_OK;
return ret; return ret;
key_failed: key_failed:
/* TODO ERROR here */ /* TODO ERROR here */
demux->last_ret = GST_FLOW_ERROR;
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
} }
@ -924,9 +965,11 @@ _src_event (GstPad * pad, GstObject * parent, GstEvent * event)
demux->pending_buffer = NULL; demux->pending_buffer = NULL;
} }
if (demux->segment.rate > 0) GST_DEBUG_OBJECT (demux, "Fragment download finished");
demux->segment.position += demux->current_duration;
g_mutex_lock (&demux->fragment_download_lock);
g_cond_signal (&demux->fragment_download_cond); g_cond_signal (&demux->fragment_download_cond);
g_mutex_unlock (&demux->fragment_download_lock);
break; break;
default: default:
break; break;
@ -1849,9 +1892,20 @@ gst_hls_demux_get_next_fragment (GstHLSDemux * demux,
/* wait for the fragment to be completely downloaded */ /* wait for the fragment to be completely downloaded */
g_cond_wait (&demux->fragment_download_cond, &demux->fragment_download_lock); g_cond_wait (&demux->fragment_download_cond, &demux->fragment_download_lock);
gst_element_set_state (demux->src, GST_STATE_READY);
g_mutex_unlock (&demux->fragment_download_lock); g_mutex_unlock (&demux->fragment_download_lock);
if (demux->last_ret != GST_FLOW_OK) {
gst_element_set_state (demux->src, GST_STATE_NULL);
*err = g_error_new (GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED,
"Failed to download fragment");
} else {
gst_element_set_state (demux->src, GST_STATE_READY);
if (demux->segment.rate > 0)
demux->segment.position += demux->current_duration;
}
if (demux->last_ret != GST_FLOW_OK)
return FALSE;
return TRUE; return TRUE;
} }

View file

@ -49,6 +49,8 @@ G_BEGIN_DECLS
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_HLS_DEMUX)) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_HLS_DEMUX))
#define GST_HLS_DEMUX_GET_CLASS(obj) \ #define GST_HLS_DEMUX_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_HLS_DEMUX,GstHLSDemuxClass)) (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_HLS_DEMUX,GstHLSDemuxClass))
#define GST_HLS_DEMUX_CAST(obj) \
((GstHLSDemux *)obj)
typedef struct _GstHLSDemux GstHLSDemux; typedef struct _GstHLSDemux GstHLSDemux;
typedef struct _GstHLSDemuxClass GstHLSDemuxClass; typedef struct _GstHLSDemuxClass GstHLSDemuxClass;
@ -121,6 +123,7 @@ struct _GstHLSDemux
gint64 download_start_time; gint64 download_start_time;
gint64 download_total_time; gint64 download_total_time;
gint64 download_total_bytes; gint64 download_total_bytes;
GstFlowReturn last_ret;
/* decryption tooling */ /* decryption tooling */
#ifdef HAVE_NETTLE #ifdef HAVE_NETTLE