opus: bump written version from 0 to 0x01
[platform/upstream/gstreamer.git] / ext / opus / gstopusheader.c
index a46c5d6..36cb4ec 100644 (file)
 #include "gstopusheader.h"
 
 static GstBuffer *
-gst_opus_enc_create_id_buffer (gint nchannels, gint sample_rate,
-    guint8 channel_mapping_family, const guint8 * channel_mapping)
+gst_opus_enc_create_id_buffer (gint nchannels, gint n_stereo_streams,
+    gint sample_rate, guint8 channel_mapping_family,
+    const guint8 * channel_mapping)
 {
   GstBuffer *buffer;
   GstByteWriter bw;
+  gboolean hdl = TRUE;
+
+  g_return_val_if_fail (nchannels > 0 && nchannels < 256, NULL);
+  g_return_val_if_fail (n_stereo_streams >= 0, NULL);
+  g_return_val_if_fail (n_stereo_streams <= nchannels - n_stereo_streams, NULL);
 
   gst_byte_writer_init (&bw);
 
   /* See http://wiki.xiph.org/OggOpus */
-  gst_byte_writer_put_data (&bw, (const guint8 *) "OpusHead", 8);
-  gst_byte_writer_put_uint8 (&bw, 0);   /* version number */
-  gst_byte_writer_put_uint8 (&bw, nchannels);
-  gst_byte_writer_put_uint16_le (&bw, 0);       /* pre-skip */
-  gst_byte_writer_put_uint32_le (&bw, sample_rate);
-  gst_byte_writer_put_uint16_le (&bw, 0);       /* output gain */
-  gst_byte_writer_put_uint8 (&bw, channel_mapping_family);
+  hdl &= gst_byte_writer_put_data (&bw, (const guint8 *) "OpusHead", 8);
+  hdl &= gst_byte_writer_put_uint8 (&bw, 0x01); /* version number */
+  hdl &= gst_byte_writer_put_uint8 (&bw, nchannels);
+  hdl &= gst_byte_writer_put_uint16_le (&bw, 0);        /* pre-skip */
+  hdl &= gst_byte_writer_put_uint32_le (&bw, sample_rate);
+  hdl &= gst_byte_writer_put_uint16_le (&bw, 0);        /* output gain */
+  hdl &= gst_byte_writer_put_uint8 (&bw, channel_mapping_family);
   if (channel_mapping_family > 0) {
-    gst_byte_writer_put_uint8 (&bw, nchannels);
-    gst_byte_writer_put_uint8 (&bw, 0);
-    gst_byte_writer_put_data (&bw, channel_mapping, nchannels);
+    hdl &= gst_byte_writer_put_uint8 (&bw, nchannels - n_stereo_streams);
+    hdl &= gst_byte_writer_put_uint8 (&bw, n_stereo_streams);
+    hdl &= gst_byte_writer_put_data (&bw, channel_mapping, nchannels);
   }
 
+  if (!hdl)
+    GST_WARNING ("Error creating header");
+
   buffer = gst_byte_writer_reset_and_get_buffer (&bw);
 
   GST_BUFFER_OFFSET (buffer) = 0;
@@ -122,11 +131,11 @@ _gst_caps_set_buffer_array (GstCaps * caps, const gchar * field,
     g_assert (gst_buffer_is_writable (buf));
 
     /* mark buffer */
-    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
+    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
 
     g_value_init (&value, GST_TYPE_BUFFER);
     buf = gst_buffer_copy (buf);
-    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
+    GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
     gst_value_set_buffer (&value, buf);
     gst_buffer_unref (buf);
     gst_value_array_append_value (&array, &value);
@@ -145,11 +154,39 @@ void
 gst_opus_header_create_caps_from_headers (GstCaps ** caps, GSList ** headers,
     GstBuffer * buf1, GstBuffer * buf2)
 {
+  int n_streams, family;
+  gboolean multistream;
+  GstMapInfo map;
+  guint8 *data;
+
   g_return_if_fail (caps);
   g_return_if_fail (headers && !*headers);
+  g_return_if_fail (gst_buffer_get_size (buf1) >= 19);
+
+  gst_buffer_map (buf1, &map, GST_MAP_READ);
+  data = map.data;
+
+  /* work out the number of streams */
+  family = data[18];
+  if (family == 0) {
+    n_streams = 1;
+  } else {
+    /* only included in the header for family > 0 */
+    if (map.size >= 20)
+      n_streams = data[19];
+    else {
+      g_warning ("family > 0 but header buffer size < 20");
+      gst_buffer_unmap (buf1, &map);
+      return;
+    }
+  }
+
+  gst_buffer_unmap (buf1, &map);
 
   /* mark and put on caps */
-  *caps = gst_caps_from_string ("audio/x-opus");
+  multistream = n_streams > 1;
+  *caps = gst_caps_new_simple ("audio/x-opus",
+      "multistream", G_TYPE_BOOLEAN, multistream, NULL);
   *caps = _gst_caps_set_buffer_array (*caps, "streamheader", buf1, buf2, NULL);
 
   *headers = g_slist_prepend (*headers, buf2);
@@ -158,7 +195,7 @@ gst_opus_header_create_caps_from_headers (GstCaps ** caps, GSList ** headers,
 
 void
 gst_opus_header_create_caps (GstCaps ** caps, GSList ** headers, gint nchannels,
-    gint sample_rate, guint8 channel_mapping_family,
+    gint n_stereo_streams, gint sample_rate, guint8 channel_mapping_family,
     const guint8 * channel_mapping, const GstTagList * tags)
 {
   GstBuffer *buf1, *buf2;
@@ -175,7 +212,7 @@ gst_opus_header_create_caps (GstCaps ** caps, GSList ** headers, gint nchannels,
 
   /* create header buffers */
   buf1 =
-      gst_opus_enc_create_id_buffer (nchannels, sample_rate,
+      gst_opus_enc_create_id_buffer (nchannels, n_stereo_streams, sample_rate,
       channel_mapping_family, channel_mapping);
   buf2 = gst_opus_enc_create_metadata_buffer (tags);
 
@@ -196,13 +233,16 @@ gst_opus_header_is_id_header (GstBuffer * buf)
   guint8 *data = NULL;
   guint8 channels, channel_mapping_family, n_streams, n_stereo_streams;
   gboolean ret = FALSE;
+  GstMapInfo map;
 
   if (size < 19)
     goto beach;
   if (!gst_opus_header_is_header (buf, "OpusHead", 8))
     goto beach;
 
-  data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
+  gst_buffer_map (buf, &map, GST_MAP_READ);
+  data = map.data;
+  size = map.size;
 
   channels = data[9];
 
@@ -231,7 +271,7 @@ gst_opus_header_is_id_header (GstBuffer * buf)
 
 beach:
   if (data)
-    gst_buffer_unmap (buf, data, size);
+    gst_buffer_unmap (buf, &map);
   return ret;
 }