basevideodecoder: improve glitch resilience
authorMark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
Fri, 1 Apr 2011 16:00:11 +0000 (18:00 +0200)
committerMark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
Mon, 16 May 2011 18:32:24 +0000 (20:32 +0200)
Provide a replacement for GST_ELEMENT_ERROR to avoid aborting at the first
atom out of place, while on the other hand not failing indefinitely.

gst-libs/gst/video/gstbasevideodecoder.c
gst-libs/gst/video/gstbasevideodecoder.h

index 88cfe9e..00160d2 100644 (file)
@@ -318,6 +318,7 @@ gst_base_video_decoder_flush (GstBaseVideoDecoder * dec, gboolean hard)
     gst_segment_init (&GST_BASE_VIDEO_CODEC (dec)->segment,
         GST_FORMAT_UNDEFINED);
     gst_base_video_decoder_clear_queues (dec);
+    dec->error_count = 0;
   }
   /* and get (re)set for the sequel */
   gst_base_video_decoder_reset (dec, FALSE);
@@ -887,6 +888,7 @@ gst_base_video_decoder_reset (GstBaseVideoDecoder * base_video_decoder,
     gst_segment_init (&GST_BASE_VIDEO_CODEC (base_video_decoder)->segment,
         GST_FORMAT_UNDEFINED);
     gst_base_video_decoder_clear_queues (base_video_decoder);
+    base_video_decoder->error_count = 0;
   }
 
   GST_BASE_VIDEO_CODEC (base_video_decoder)->discont = TRUE;
@@ -1482,6 +1484,10 @@ gst_base_video_decoder_finish_frame (GstBaseVideoDecoder * base_video_decoder,
     }
   }
 
+  /* we got data, so note things are looking up again */
+  if (G_UNLIKELY (base_video_decoder->error_count))
+    base_video_decoder->error_count--;
+
   if (GST_BASE_VIDEO_CODEC (base_video_decoder)->segment.rate < 0.0) {
     GST_LOG_OBJECT (base_video_decoder, "queued buffer");
     base_video_decoder->queued =
@@ -1950,3 +1956,23 @@ gst_base_video_decoder_class_set_capture_pattern (GstBaseVideoDecoderClass *
   base_video_decoder_class->capture_mask = mask;
   base_video_decoder_class->capture_pattern = pattern;
 }
+
+GstFlowReturn
+_gst_base_video_decoder_error (GstBaseVideoDecoder * 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->error_count += weight;
+  GST_BASE_VIDEO_CODEC (dec)->discont = TRUE;
+  if (dec->max_errors < dec->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;
+  }
+}
index afad140..235dcb1 100644 (file)
@@ -65,10 +65,49 @@ G_BEGIN_DECLS
  **/
 #define GST_BASE_VIDEO_DECODER_FLOW_NEED_DATA GST_FLOW_CUSTOM_SUCCESS
 
-
 typedef struct _GstBaseVideoDecoder GstBaseVideoDecoder;
 typedef struct _GstBaseVideoDecoderClass GstBaseVideoDecoderClass;
 
+
+/* do not use this one, use macro below */
+GstFlowReturn _gst_base_video_decoder_error (GstBaseVideoDecoder *dec, gint weight,
+                                             GQuark domain, gint code,
+                                             gchar *txt, gchar *debug,
+                                             const gchar *file, const gchar *function,
+                                             gint line);
+
+/**
+ * GST_BASE_VIDEO_DECODER_ERROR:
+ * @el:     the base video 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;                           \
+  GstBaseVideoDecoder *dec = GST_BASE_VIDEO_DECODER (el);                   \
+  ret = _gst_base_video_decoder_error (dec, w, GST_ ## domain ## _ERROR,    \
+      GST_ ## domain ## _ERROR_ ## code, __txt, __dbg, __FILE__,            \
+      GST_FUNCTION, __LINE__);                                              \
+} G_STMT_END
+
+
 /**
  * GstBaseVideoDecoder:
  *
@@ -82,6 +121,7 @@ struct _GstBaseVideoDecoder
   gboolean          sink_clipping;
   gboolean          do_byte_time;
   gboolean          packetized;
+  gint              max_errors;
 
   /* parse tracking */
   /* input data */
@@ -113,6 +153,7 @@ struct _GstBaseVideoDecoder
 
   /* last outgoing ts */
   GstClockTime      last_timestamp;
+  gint              error_count;
 
   /* reverse playback */
   /* collect input */