#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;
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);
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);
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;
/* 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);
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];
beach:
if (data)
- gst_buffer_unmap (buf, data, size);
+ gst_buffer_unmap (buf, &map);
return ret;
}