flacdec: improve error handling and resilience
authorMark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
Fri, 16 Mar 2012 17:23:29 +0000 (18:23 +0100)
committerMark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
Mon, 19 Mar 2012 11:02:42 +0000 (12:02 +0100)
... by noting that one occurred in the first place, and then appropriately
ignoring some transient ones.

ext/flac/gstflacdec.c
ext/flac/gstflacdec.h

index 10f8916..19a866c 100644 (file)
@@ -542,6 +542,26 @@ gst_flac_dec_scan_for_last_block (GstFlacDec * flacdec, gint64 * samples)
   }
 }
 
+static gboolean
+gst_flac_dec_handle_decoder_error (GstFlacDec * dec, gboolean msg)
+{
+  gboolean ret;
+
+  dec->error_count++;
+  if (dec->error_count > 10) {
+    if (msg)
+      GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), (NULL));
+    dec->last_flow = GST_FLOW_ERROR;
+    ret = TRUE;
+  } else {
+    GST_DEBUG_OBJECT (dec, "ignoring error for now at count %d",
+        dec->error_count);
+    ret = FALSE;
+  }
+
+  return ret;
+}
+
 static void
 gst_flac_extract_picture_buffer (GstFlacDec * dec,
     const FLAC__StreamMetadata * metadata)
@@ -672,8 +692,8 @@ gst_flac_dec_error_cb (const FLAC__StreamDecoder * d,
       break;
   }
 
-  GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("%s (%d)", error, status));
-  dec->last_flow = GST_FLOW_ERROR;
+  if (gst_flac_dec_handle_decoder_error (dec, FALSE))
+    GST_ELEMENT_ERROR (dec, STREAM, DECODE, (NULL), ("%s (%d)", error, status));
 }
 
 static FLAC__StreamDecoderSeekStatus
@@ -1023,6 +1043,9 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame,
     g_assert_not_reached ();
   }
 
+  if (flacdec->error_count)
+    flacdec->error_count--;
+
   if (!flacdec->seeking) {
     GST_DEBUG_OBJECT (flacdec, "pushing %d samples at offset %" G_GINT64_FORMAT
         " (%" GST_TIME_FORMAT " + %" GST_TIME_FORMAT ")",
@@ -1503,6 +1526,15 @@ gst_flac_dec_chain (GstPad * pad, GstBuffer * buf)
     if (!FLAC__stream_decoder_process_single (dec->decoder)) {
       GST_DEBUG_OBJECT (dec, "process_single failed");
     }
+
+    if (FLAC__stream_decoder_get_state (dec->decoder) ==
+        FLAC__STREAM_DECODER_ABORTED) {
+      GST_WARNING_OBJECT (dec, "Read callback caused internal abort");
+      /* allow recovery */
+      gst_adapter_clear (dec->adapter);
+      FLAC__stream_decoder_flush (dec->decoder);
+      gst_flac_dec_handle_decoder_error (dec, TRUE);
+    }
   } else {
     GST_DEBUG_OBJECT (dec, "don't have all headers yet");
   }
@@ -2154,6 +2186,7 @@ gst_flac_dec_change_state (GstElement * element, GstStateChange transition)
       flacdec->width = 0;
       flacdec->sample_rate = 0;
       gst_segment_init (&flacdec->segment, GST_FORMAT_DEFAULT);
+      flacdec->error_count = 0;
       break;
     default:
       break;
index 835bdbd..f3882a2 100644 (file)
@@ -88,6 +88,8 @@ struct _GstFlacDec {
   guint16        max_blocksize;
 
   gint64         cur_granulepos; /* only used in framed mode (flac-in-ogg) */
+
+  gint           error_count;
 };
 
 struct _GstFlacDecClass {