diff --git a/gst-libs/gst/audio/gstbaseaudiodecoder.c b/gst-libs/gst/audio/gstbaseaudiodecoder.c index 5ebe655815..d36099780e 100644 --- a/gst-libs/gst/audio/gstbaseaudiodecoder.c +++ b/gst-libs/gst/audio/gstbaseaudiodecoder.c @@ -215,6 +215,8 @@ struct _GstBaseAudioDecoderPrivate guint64 samples_out; /* bytes flushed during parsing */ guint sync_flush; + /* error count */ + gint error_count; /* codec id tag */ GstTagList *taglist; @@ -386,6 +388,7 @@ gst_base_audio_decoder_reset (GstBaseAudioDecoder * dec, gboolean full) dec->priv->bytes_in = 0; dec->priv->samples_out = 0; dec->priv->agg = -1; + dec->priv->error_count = 0; gst_base_audio_decoder_clear_queues (dec); g_free (dec->ctx->state.channel_pos); @@ -786,6 +789,10 @@ gst_base_audio_decoder_finish_frame (GstBaseAudioDecoder * dec, GstBuffer * buf, } priv->samples += samples; priv->samples_out += samples; + + /* we got data, so note things are looking up */ + if (G_UNLIKELY (dec->priv->error_count)) + dec->priv->error_count--; } return gst_base_audio_decoder_output (dec, buf); @@ -985,6 +992,7 @@ gst_base_audio_decoder_flush (GstBaseAudioDecoder * dec, gboolean hard) ret = gst_base_audio_decoder_drain (dec); } else { gst_segment_init (&dec->segment, GST_FORMAT_TIME); + dec->priv->error_count = 0; } /* only bother subclass with flushing if known it is already alive * and kicking out stuff */ @@ -1844,3 +1852,23 @@ stop_failed: return GST_STATE_CHANGE_FAILURE; } } + +GstFlowReturn +_gst_base_audio_decoder_error (GstBaseAudioDecoder * dec, gint weight, + GQuark domain, gint code, gchar * txt, gchar * dbg, const gchar * file, + const gchar * function, gint line) +{ + if (txt) + GST_WARNING_OBJECT (dec, "error: %s", txt); + if (dbg) + GST_WARNING_OBJECT (dec, "error: %s", dbg); + dec->priv->error_count += weight; + dec->priv->discont = TRUE; + if (dec->ctx->max_errors < dec->priv->error_count) { + gst_element_message_full (GST_ELEMENT (dec), GST_MESSAGE_ERROR, + domain, code, txt, dbg, file, function, line); + return GST_FLOW_ERROR; + } else { + return GST_FLOW_OK; + } +} diff --git a/gst-libs/gst/audio/gstbaseaudiodecoder.h b/gst-libs/gst/audio/gstbaseaudiodecoder.h index 4db0ffd78b..c257caaf56 100644 --- a/gst-libs/gst/audio/gstbaseaudiodecoder.h +++ b/gst-libs/gst/audio/gstbaseaudiodecoder.h @@ -83,6 +83,44 @@ typedef struct _GstBaseAudioDecoderClass GstBaseAudioDecoderClass; typedef struct _GstBaseAudioDecoderPrivate GstBaseAudioDecoderPrivate; typedef struct _GstBaseAudioDecoderContext GstBaseAudioDecoderContext; +/* do not use this one, use macro below */ +GstFlowReturn _gst_base_audio_decoder_error (GstBaseAudioDecoder *dec, gint weight, + GQuark domain, gint code, + gchar *txt, gchar *debug, + const gchar *file, const gchar *function, + gint line); + +/** + * GST_BASE_AUDIO_DECODER_ERROR: + * @el: the base audio decoder element that generates the error + * @weight: element defined weight of the error, added to error count + * @domain: like CORE, LIBRARY, RESOURCE or STREAM (see #gstreamer-GstGError) + * @code: error code defined for that domain (see #gstreamer-GstGError) + * @text: the message to display (format string and args enclosed in + * parentheses) + * @debug: debugging information for the message (format string and args + * enclosed in parentheses) + * @ret: variable to receive return value + * + * Utility function that audio decoder elements can use in case they encountered + * a data processing error that may be fatal for the current "data unit" but + * need not prevent subsequent decoding. Such errors are counted and if there + * are too many, as configured in the context's max_errors, the pipeline will + * post an error message and the application will be requested to stop further + * media processing. Otherwise, it is considered a "glitch" and only a warning + * is logged. In either case, @ret is set to the proper value to + * return to upstream/caller (indicating either GST_FLOW_ERROR or GST_FLOW_OK). + */ +#define GST_BASE_AUDIO_DECODER_ERROR(el, w, domain, code, text, debug, ret) \ +G_STMT_START { \ + gchar *__txt = _gst_element_error_printf text; \ + gchar *__dbg = _gst_element_error_printf debug; \ + GstBaseAudioDecoder *dec = GST_BASE_AUDIO_DECODER (el); \ + ret = _gst_base_audio_decoder_error (dec, w, GST_ ## domain ## _ERROR, \ + GST_ ## domain ## _ERROR_ ## code, __txt, __dbg, __FILE__, \ + GST_FUNCTION, __LINE__); \ +} G_STMT_END + /** * GstBaseAudioDecoderContext: * @state: a #GstAudioState describing input audio format @@ -111,6 +149,7 @@ struct _GstBaseAudioDecoderContext { /* output */ gboolean do_plc; gboolean do_byte_time; + gint max_errors; /* MT-protected (with LOCK) */ GstClockTime min_latency; GstClockTime max_latency;