opusdec: allow negotiation of rate/channels with downstream
authorVincent Penquerc'h <vincent.penquerch@collabora.co.uk>
Wed, 16 Nov 2011 13:26:35 +0000 (13:26 +0000)
committerVincent Penquerc'h <vincent.penquerch@collabora.co.uk>
Wed, 16 Nov 2011 13:43:36 +0000 (13:43 +0000)
Since an opus stream may be decoded to any (sensible) rate,
and either stereo or mono, we try to accomodate downstream.

ext/opus/gstopusdec.c

index d3528c8..5af3784 100644 (file)
@@ -121,8 +121,8 @@ gst_opus_dec_reset (GstOpusDec * dec)
 static void
 gst_opus_dec_init (GstOpusDec * dec)
 {
-  dec->sample_rate = 48000;
-  dec->n_channels = 2;
+  dec->sample_rate = 0;
+  dec->n_channels = 0;
 
   gst_opus_dec_reset (dec);
 }
@@ -162,6 +162,46 @@ gst_opus_dec_parse_comments (GstOpusDec * dec, GstBuffer * buf)
   return GST_FLOW_OK;
 }
 
+static void
+gst_opus_dec_setup_from_peer_caps (GstOpusDec * dec)
+{
+  GstPad *srcpad, *peer;
+  GstStructure *s;
+  GstCaps *caps, *template_caps, *peer_caps;
+
+  srcpad = GST_AUDIO_DECODER_SRC_PAD (dec);
+  peer = gst_pad_get_peer (srcpad);
+
+  if (peer) {
+    template_caps = gst_pad_get_pad_template_caps (srcpad);
+    peer_caps = gst_pad_get_caps (peer, NULL);
+    GST_DEBUG_OBJECT (dec, "Peer caps: %" GST_PTR_FORMAT, peer_caps);
+    caps = gst_caps_intersect (template_caps, peer_caps);
+    gst_caps_fixate (caps);
+    GST_DEBUG_OBJECT (dec, "Fixated caps: %" GST_PTR_FORMAT, caps);
+
+    s = gst_caps_get_structure (caps, 0);
+    if (!gst_structure_get_int (s, "channels", &dec->n_channels)) {
+      dec->n_channels = 2;
+      GST_WARNING_OBJECT (dec, "Failed to get channels, using default %d",
+          dec->n_channels);
+    } else {
+      GST_DEBUG_OBJECT (dec, "Got channels %d", dec->n_channels);
+    }
+    if (!gst_structure_get_int (s, "rate", &dec->sample_rate)) {
+      dec->sample_rate = 48000;
+      GST_WARNING_OBJECT (dec, "Failed to get rate, using default %d",
+          dec->sample_rate);
+    } else {
+      GST_DEBUG_OBJECT (dec, "Got sample rate %d", dec->sample_rate);
+    }
+
+    gst_audio_decoder_set_outcaps (GST_AUDIO_DECODER (dec), caps);
+  } else {
+    GST_WARNING_OBJECT (dec, "Failed to get src pad peer");
+  }
+}
+
 static GstFlowReturn
 opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buf,
     GstClockTime timestamp, GstClockTime duration)
@@ -176,25 +216,11 @@ opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buf,
   unsigned int packet_size;
 
   if (dec->state == NULL) {
-    GstCaps *caps;
+    gst_opus_dec_setup_from_peer_caps (dec);
 
     dec->state = opus_decoder_create (dec->sample_rate, dec->n_channels, &err);
     if (!dec->state || err != OPUS_OK)
       goto creation_failed;
-
-    /* set caps */
-    caps = gst_caps_new_simple ("audio/x-raw",
-        "format", G_TYPE_STRING, "S16LE",
-        "rate", G_TYPE_INT, dec->sample_rate,
-        "channels", G_TYPE_INT, dec->n_channels, NULL);
-
-    GST_DEBUG_OBJECT (dec, "rate=%d channels=%d",
-        dec->sample_rate, dec->n_channels);
-
-    if (!gst_pad_set_caps (GST_AUDIO_DECODER_SRC_PAD (dec), caps))
-      GST_ERROR ("nego failure");
-
-    gst_caps_unref (caps);
   }
 
   if (buf) {
@@ -302,13 +328,6 @@ gst_opus_dec_set_format (GstAudioDecoder * bdec, GstCaps * caps)
     }
   }
 
-  caps = gst_caps_new_simple ("audio/x-raw",
-      "format", G_TYPE_STRING, "S16LE",
-      "rate", G_TYPE_INT, dec->sample_rate,
-      "channels", G_TYPE_INT, dec->n_channels, NULL);
-  gst_audio_decoder_set_outcaps (GST_AUDIO_DECODER (dec), caps);
-  gst_caps_unref (caps);
-
 done:
   return ret;
 }