opusdec: fix 120 ms buffers being wrongly emitted
authorVincent Penquerc'h <vincent.penquerch@collabora.co.uk>
Fri, 4 Nov 2016 16:41:05 +0000 (16:41 +0000)
committerVincent Penquerc'h <vincent.penquerch@collabora.co.uk>
Fri, 4 Nov 2016 16:59:26 +0000 (16:59 +0000)
Using the max 120 ms buffer size to ensure we have enough space
for decoded data meant that Opus could actually return 120 ms'
worth of data.

https://bugzilla.gnome.org/show_bug.cgi?id=771723

ext/opus/gstopusdec.c

index 304e6bf8a2d499072a18165a850a599bff0fdeec..46d66630005d744ba1dc3efebb6d5a5695726d0e 100644 (file)
@@ -590,11 +590,11 @@ opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buffer)
         " num frame samples: %d new leftover: %" GST_TIME_FORMAT,
         GST_TIME_ARGS (aligned_missing_duration), samples,
         GST_TIME_ARGS (dec->leftover_plc_duration));
+  } else {
+    /* use maximum size (120 ms) as the number of returned samples is
+       not constant over the stream. */
+    samples = 120 * dec->sample_rate / 1000;
   }
-
-  /* use maximum size (120 ms) as the number of returned samples is
-     not constant over the stream. */
-  samples = 120 * dec->sample_rate / 1000;
   packet_size = samples * dec->n_channels * 2;
 
   outbuf =
@@ -610,23 +610,44 @@ opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buffer)
   gst_buffer_map (outbuf, &omap, GST_MAP_WRITE);
   out_data = (gint16 *) omap.data;
 
-  if (dec->use_inband_fec) {
-    if (gst_buffer_get_size (dec->last_buffer) > 0) {
-      /* normal delayed decode */
-      GST_LOG_OBJECT (dec, "FEC enabled, decoding last delayed buffer");
-      n = opus_multistream_decode (dec->state, data, size, out_data, samples,
-          0);
+  do {
+    if (dec->use_inband_fec) {
+      if (gst_buffer_get_size (dec->last_buffer) > 0) {
+        /* normal delayed decode */
+        GST_LOG_OBJECT (dec, "FEC enabled, decoding last delayed buffer");
+        n = opus_multistream_decode (dec->state, data, size, out_data, samples,
+            0);
+      } else {
+        /* FEC reconstruction decode */
+        GST_LOG_OBJECT (dec, "FEC enabled, reconstructing last buffer");
+        n = opus_multistream_decode (dec->state, data, size, out_data, samples,
+            1);
+      }
     } else {
-      /* FEC reconstruction decode */
-      GST_LOG_OBJECT (dec, "FEC enabled, reconstructing last buffer");
+      /* normal decode */
+      GST_LOG_OBJECT (dec, "FEC disabled, decoding buffer");
       n = opus_multistream_decode (dec->state, data, size, out_data, samples,
-          1);
+          0);
     }
-  } else {
-    /* normal decode */
-    GST_LOG_OBJECT (dec, "FEC disabled, decoding buffer");
-    n = opus_multistream_decode (dec->state, data, size, out_data, samples, 0);
-  }
+    if (n == OPUS_BUFFER_TOO_SMALL) {
+      /* if too small, add 2.5 milliseconds and try again, up to the
+       * Opus max size of 120 milliseconds */
+      if (samples >= 120 * dec->sample_rate / 1000)
+        break;
+      samples += 25 * dec->sample_rate / 10000;
+      packet_size = samples * dec->n_channels * 2;
+      gst_buffer_unmap (outbuf, &omap);
+      gst_buffer_unref (outbuf);
+      outbuf =
+          gst_audio_decoder_allocate_output_buffer (GST_AUDIO_DECODER (dec),
+          packet_size);
+      if (!outbuf) {
+        goto buffer_failed;
+      }
+      gst_buffer_map (outbuf, &omap, GST_MAP_WRITE);
+      out_data = (gint16 *) omap.data;
+    }
+  } while (n == OPUS_BUFFER_TOO_SMALL);
   gst_buffer_unmap (outbuf, &omap);
   if (data != NULL)
     gst_buffer_unmap (buf, &map);
@@ -641,6 +662,8 @@ opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buffer)
   }
   GST_DEBUG_OBJECT (dec, "decoded %d samples", n);
   gst_buffer_set_size (outbuf, n * 2 * dec->n_channels);
+  GST_BUFFER_DURATION (outbuf) = samples * GST_SECOND / dec->sample_rate;
+  samples = n;
 
   cmeta = gst_buffer_get_audio_clipping_meta (buf);