$OpenBSD: patch-ext_ffmpeg_gstffmpegdec_c,v 1.7 2015/11/21 10:57:25 ajacoutot Exp $

From upstream:
- Don't flush buffers on DISCONT.
- Report latency if B-frames are present.
- Give the (E)AC3/DTS decoders a rank of marginal.
- Only set get_buffer() function for video.
- Only slice-threading.

Also:
From a3b0ae22d76522d0a79f5d946872c0260dd1e3b2 Mon Sep 17 00:00:00 2001
From: Wim Taymans <wim.taymans@collabora.co.uk>
Date: Tue, 10 Jul 2012 14:10:14 +0000
Subject: avdec: ignore AAC errors instead of erroring out

Set the mp3 decoder to a rank of PRIMARY.

--- ext/ffmpeg/gstffmpegdec.c.orig	Wed Nov  2 14:04:05 2011
+++ ext/ffmpeg/gstffmpegdec.c	Sat Nov 21 11:32:54 2015
@@ -477,36 +477,44 @@ static gboolean
 gst_ffmpegdec_query (GstPad * pad, GstQuery * query)
 {
   GstFFMpegDec *ffmpegdec;
-  GstPad *peer;
-  gboolean res;
+  gboolean res = FALSE;
 
   ffmpegdec = (GstFFMpegDec *) gst_pad_get_parent (pad);
 
-  res = FALSE;
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_LATENCY:
+    {
+      GST_DEBUG_OBJECT (ffmpegdec, "latency query %d",
+          ffmpegdec->context->has_b_frames);
+      if ((res = gst_pad_peer_query (ffmpegdec->sinkpad, query))) {
+        if (ffmpegdec->context->has_b_frames) {
+          gboolean live;
+          GstClockTime min_lat, max_lat, our_lat;
 
-  if ((peer = gst_pad_get_peer (ffmpegdec->sinkpad))) {
-    /* just forward to peer */
-    res = gst_pad_query (peer, query);
-    gst_object_unref (peer);
+          gst_query_parse_latency (query, &live, &min_lat, &max_lat);
+          if (ffmpegdec->format.video.fps_n > 0)
+            our_lat =
+                gst_util_uint64_scale_int (ffmpegdec->context->has_b_frames *
+                GST_SECOND, ffmpegdec->format.video.fps_d,
+                ffmpegdec->format.video.fps_n);
+          else
+            our_lat =
+                gst_util_uint64_scale_int (ffmpegdec->context->has_b_frames *
+                GST_SECOND, 1, 25);
+          if (min_lat != -1)
+            min_lat += our_lat;
+          if (max_lat != -1)
+            max_lat += our_lat;
+          gst_query_set_latency (query, live, min_lat, max_lat);
+        }
+      }
+    }
+      break;
+    default:
+      res = gst_pad_query_default (pad, query);
+      break;
   }
-#if 0
-  {
-    GstFormat bfmt;
 
-    bfmt = GST_FORMAT_BYTES;
-
-    /* ok, do bitrate calc... */
-    if ((type != GST_QUERY_POSITION && type != GST_QUERY_TOTAL) ||
-        *fmt != GST_FORMAT_TIME || ffmpegdec->context->bit_rate == 0 ||
-        !gst_pad_query (peer, type, &bfmt, value))
-      return FALSE;
-
-    if (ffmpegdec->pcache && type == GST_QUERY_POSITION)
-      *value -= GST_BUFFER_SIZE (ffmpegdec->pcache);
-    *value *= GST_SECOND / ffmpegdec->context->bit_rate;
-  }
-#endif
-
   gst_object_unref (ffmpegdec);
 
   return res;
@@ -758,9 +766,11 @@ gst_ffmpegdec_setcaps (GstPad * pad, GstCaps * caps)
   }
 
   /* set buffer functions */
-  ffmpegdec->context->get_buffer = gst_ffmpegdec_get_buffer;
-  ffmpegdec->context->release_buffer = gst_ffmpegdec_release_buffer;
-  ffmpegdec->context->draw_horiz_band = NULL;
+  if (oclass->in_plugin->type == AVMEDIA_TYPE_VIDEO) {
+    ffmpegdec->context->get_buffer = gst_ffmpegdec_get_buffer;
+    ffmpegdec->context->release_buffer = gst_ffmpegdec_release_buffer;
+    ffmpegdec->context->draw_horiz_band = NULL;
+  }
 
   /* default is to let format decide if it needs a parser */
   ffmpegdec->turnoff_parser = FALSE;
@@ -879,6 +889,8 @@ gst_ffmpegdec_setcaps (GstPad * pad, GstCaps * caps)
   else
     ffmpegdec->context->thread_count = ffmpegdec->max_threads;
 
+  ffmpegdec->context->thread_type = FF_THREAD_SLICE;
+
   /* open codec - we don't select an output pix_fmt yet,
    * simply because we don't know! We only get it
    * during playback... */
@@ -1546,6 +1558,9 @@ check_keyframe (GstFFMpegDec * ffmpegdec)
   if (!ffmpegdec->has_b_frames && ffmpegdec->picture->pict_type == FF_B_TYPE) {
     GST_DEBUG_OBJECT (ffmpegdec, "we have B frames");
     ffmpegdec->has_b_frames = TRUE;
+    /* Emit latency message to recalculate it */
+    gst_element_post_message (GST_ELEMENT_CAST (ffmpegdec),
+        gst_message_new_latency (GST_OBJECT_CAST (ffmpegdec)));
   }
 
   is_itype = (ffmpegdec->picture->pict_type == FF_I_TYPE);
@@ -1821,7 +1836,7 @@ gst_ffmpegdec_video_frame (GstFFMpegDec * ffmpegdec,
       GstStructure *s = gst_caps_get_structure (GST_BUFFER_CAPS (buffer), 0);
       gboolean interlaced;
       gboolean found = gst_structure_get_boolean (s, "interlaced", &interlaced);
-      if (!found || (!!interlaced != !!ffmpegdec->format.video.interlaced)) {
+      if (!found || (! !interlaced != ! !ffmpegdec->format.video.interlaced)) {
         GST_DEBUG_OBJECT (ffmpegdec,
             "Buffer interlacing does not match pad, updating");
         buffer = gst_buffer_make_metadata_writable (buffer);
@@ -2205,15 +2220,6 @@ gst_ffmpegdec_audio_frame (GstFFMpegDec * ffmpegdec,
     *outbuf = NULL;
   }
 
-  /* If we don't error out after the first failed read with the AAC decoder,
-   * we must *not* carry on pushing data, else we'll cause segfaults... */
-  if (len == -1 && (in_plugin->id == CODEC_ID_AAC
-          || in_plugin->id == CODEC_ID_AAC_LATM)) {
-    GST_ELEMENT_ERROR (ffmpegdec, STREAM, DECODE, (NULL),
-        ("Decoding of AAC stream by FFMPEG failed."));
-    *ret = GST_FLOW_ERROR;
-  }
-
 beach:
   GST_DEBUG_OBJECT (ffmpegdec, "return flow %d, out %p, len %d",
       *ret, *outbuf, len);
@@ -2542,15 +2548,15 @@ gst_ffmpegdec_chain (GstPad * pad, GstBuffer * inbuf)
   discont = GST_BUFFER_IS_DISCONT (inbuf);
 
   /* The discont flags marks a buffer that is not continuous with the previous
-   * buffer. This means we need to clear whatever data we currently have. We
-   * currently also wait for a new keyframe, which might be suboptimal in the
-   * case of a network error, better show the errors than to drop all data.. */
+   * buffer. This means we need to clear whatever data we currently have. We let
+   * ffmpeg continue with the data that it has. We currently drain the old
+   * frames that might be inside the decoder and we clear any partial data in
+   * the pcache, we might be able to remove the drain and flush too. */
   if (G_UNLIKELY (discont)) {
     GST_DEBUG_OBJECT (ffmpegdec, "received DISCONT");
     /* drain what we have queued */
     gst_ffmpegdec_drain (ffmpegdec);
     gst_ffmpegdec_flush_pcache (ffmpegdec);
-    avcodec_flush_buffers (ffmpegdec->context);
     ffmpegdec->discont = TRUE;
     gst_ffmpegdec_reset_ts (ffmpegdec);
   }
@@ -3030,6 +3036,7 @@ gst_ffmpegdec_register (GstPlugin * plugin)
       case CODEC_ID_RV30:
       case CODEC_ID_RV40:
       case CODEC_ID_COOK:
+      case CODEC_ID_MP3:
         rank = GST_RANK_PRIMARY;
         break;
         /* DVVIDEO: we have a good dv decoder, fast on both ppc as well as x86.
@@ -3041,17 +3048,6 @@ gst_ffmpegdec_register (GstPlugin * plugin)
       case CODEC_ID_DVVIDEO:
       case CODEC_ID_SIPR:
         rank = GST_RANK_SECONDARY;
-        break;
-      case CODEC_ID_MP3:
-        rank = GST_RANK_NONE;
-        break;
-        /* TEMPORARILY DISABLING AC3/EAC3/DTS for 0.10.12 release
-         * due to downmixing failure.
-         * See Bug #608892 for more details */
-      case CODEC_ID_EAC3:
-      case CODEC_ID_AC3:
-      case CODEC_ID_DTS:
-        rank = GST_RANK_NONE;
         break;
       default:
         rank = GST_RANK_MARGINAL;
