From fa02111b7c1506c8ac67b04c64e552b74be3eea8 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Wed, 7 Mar 2012 17:14:29 +0100 Subject: [PATCH] opus: port to updated 0.11 --- ext/opus/gstopuscommon.c | 8 ++-- ext/opus/gstopuscommon.h | 2 +- ext/opus/gstopusdec.c | 102 +++++++++++++++++++++++++++-------------------- ext/opus/gstopusdec.h | 3 ++ ext/opus/gstopusenc.c | 25 ++++++------ ext/opus/gstopusheader.c | 22 +++++----- 6 files changed, 93 insertions(+), 69 deletions(-) diff --git a/ext/opus/gstopuscommon.c b/ext/opus/gstopuscommon.c index dbf585a..80414ad 100644 --- a/ext/opus/gstopuscommon.c +++ b/ext/opus/gstopuscommon.c @@ -25,7 +25,7 @@ /* copy of the same structure in the vorbis plugin */ const GstAudioChannelPosition gst_opus_channel_positions[][8] = { { /* Mono */ - GST_AUDIO_CHANNEL_POSITION_FRONT_MONO}, + GST_AUDIO_CHANNEL_POSITION_MONO}, { /* Stereo */ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, @@ -52,7 +52,7 @@ const GstAudioChannelPosition gst_opus_channel_positions[][8] = { GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, - GST_AUDIO_CHANNEL_POSITION_LFE, + GST_AUDIO_CHANNEL_POSITION_LFE1, }, { /* 6.1 Surround, in Vorbis spec since 2010-01-13 */ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, @@ -61,7 +61,7 @@ const GstAudioChannelPosition gst_opus_channel_positions[][8] = { GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT, GST_AUDIO_CHANNEL_POSITION_REAR_CENTER, - GST_AUDIO_CHANNEL_POSITION_LFE}, + GST_AUDIO_CHANNEL_POSITION_LFE1}, { /* 7.1 Surround, in Vorbis spec since 2010-01-13 */ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, @@ -70,7 +70,7 @@ const GstAudioChannelPosition gst_opus_channel_positions[][8] = { GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, - GST_AUDIO_CHANNEL_POSITION_LFE}, + GST_AUDIO_CHANNEL_POSITION_LFE1}, }; const char *gst_opus_channel_names[] = { diff --git a/ext/opus/gstopuscommon.h b/ext/opus/gstopuscommon.h index 1fba565..21c2733 100644 --- a/ext/opus/gstopuscommon.h +++ b/ext/opus/gstopuscommon.h @@ -22,7 +22,7 @@ #define __GST_OPUS_COMMON_H__ #include -#include +#include G_BEGIN_DECLS diff --git a/ext/opus/gstopusdec.c b/ext/opus/gstopusdec.c index 6766245..5c9b363 100644 --- a/ext/opus/gstopusdec.c +++ b/ext/opus/gstopusdec.c @@ -56,6 +56,7 @@ GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_ALWAYS, GST_STATIC_CAPS ("audio/x-raw, " "format = (string) { " GST_AUDIO_NE (S16) " }, " + "layout = (string) interleaved, " "rate = (int) { 48000, 24000, 16000, 12000, 8000 }, " "channels = (int) [ 1, 8 ] ") ); @@ -206,11 +207,12 @@ gst_opus_dec_get_r128_volume (gint16 r128_gain) return DB_TO_LINEAR (gst_opus_dec_get_r128_gain (r128_gain)); } -static GstCaps * -gst_opus_dec_negotiate (GstOpusDec * dec) +static void +gst_opus_dec_negotiate (GstOpusDec * dec, const GstAudioChannelPosition * pos) { GstCaps *caps = gst_pad_get_allowed_caps (GST_AUDIO_DECODER_SRC_PAD (dec)); GstStructure *s; + GstAudioInfo info; caps = gst_caps_make_writable (caps); gst_caps_truncate (caps); @@ -224,19 +226,41 @@ gst_opus_dec_negotiate (GstOpusDec * dec) GST_INFO_OBJECT (dec, "Negotiated %d channels, %d Hz", dec->n_channels, dec->sample_rate); - return caps; + /* pass valid order to audio info */ + if (pos) { + memcpy (dec->opus_pos, pos, sizeof (pos[0]) * dec->n_channels); + gst_audio_channel_positions_to_valid_order (dec->opus_pos, dec->n_channels); + } + + /* set up source format */ + gst_audio_info_init (&info); + gst_audio_info_set_format (&info, GST_AUDIO_FORMAT_S16, + dec->sample_rate, dec->n_channels, pos ? dec->opus_pos : NULL); + gst_audio_decoder_set_output_format (GST_AUDIO_DECODER (dec), &info); + + /* but we still need the opus order for later reordering */ + if (pos) { + memcpy (dec->opus_pos, pos, sizeof (pos[0]) * dec->n_channels); + gst_audio_channel_positions_to_valid_order (dec->opus_pos, dec->n_channels); + } else { + dec->opus_pos[0] = GST_AUDIO_CHANNEL_POSITION_INVALID; + } + + dec->info = info; } static GstFlowReturn gst_opus_dec_parse_header (GstOpusDec * dec, GstBuffer * buf) { const guint8 *data; - GstCaps *caps; - const GstAudioChannelPosition *pos = NULL; + GstAudioChannelPosition pos[64]; + const GstAudioChannelPosition *posn = NULL; + GstMapInfo map; g_return_val_if_fail (gst_opus_header_is_id_header (buf), GST_FLOW_ERROR); - data = gst_buffer_map (buf, NULL, NULL, GST_MAP_READ); + gst_buffer_map (buf, &map, GST_MAP_READ); + data = map.data; g_return_val_if_fail (dec->n_channels == 0 || dec->n_channels == data[9], GST_FLOW_ERROR); @@ -274,20 +298,18 @@ gst_opus_dec_parse_header (GstOpusDec * dec, GstBuffer * buf) case 6: case 7: case 8: - pos = gst_opus_channel_positions[dec->n_channels - 1]; + posn = gst_opus_channel_positions[dec->n_channels - 1]; break; default:{ gint i; - GstAudioChannelPosition *posn = - g_new (GstAudioChannelPosition, dec->n_channels); GST_ELEMENT_WARNING (GST_ELEMENT (dec), STREAM, DECODE, (NULL), ("Using NONE channel layout for more than 8 channels")); for (i = 0; i < dec->n_channels; i++) - posn[i] = GST_AUDIO_CHANNEL_POSITION_NONE; + pos[i] = GST_AUDIO_CHANNEL_POSITION_NONE; - pos = posn; + posn = pos; } } } else { @@ -296,22 +318,9 @@ gst_opus_dec_parse_header (GstOpusDec * dec, GstBuffer * buf) } } - caps = gst_opus_dec_negotiate (dec); - - if (pos) { - GST_DEBUG_OBJECT (dec, "Setting channel positions on caps"); - gst_audio_set_channel_positions (gst_caps_get_structure (caps, 0), pos); - } - - if (dec->n_channels > 8) { - g_free ((GstAudioChannelPosition *) pos); - } - - GST_INFO_OBJECT (dec, "Setting src caps to %" GST_PTR_FORMAT, caps); - gst_pad_set_caps (GST_AUDIO_DECODER_SRC_PAD (dec), caps); - gst_caps_unref (caps); + gst_opus_dec_negotiate (dec, posn); - gst_buffer_unmap (buf, (guint8 *) data, -1); + gst_buffer_unmap (buf, &map); return GST_FLOW_OK; } @@ -327,7 +336,7 @@ static GstFlowReturn opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buffer) { GstFlowReturn res = GST_FLOW_OK; - gsize size, out_size; + gsize size; guint8 *data; GstBuffer *outbuf; gint16 *out_data; @@ -335,24 +344,22 @@ opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buffer) int samples; unsigned int packet_size; GstBuffer *buf; + GstMapInfo map, omap; if (dec->state == NULL) { /* If we did not get any headers, default to 2 channels */ if (dec->n_channels == 0) { - GstCaps *caps; GST_INFO_OBJECT (dec, "No header, assuming single stream"); dec->n_channels = 2; dec->sample_rate = 48000; - caps = gst_opus_dec_negotiate (dec); - GST_INFO_OBJECT (dec, "Setting src caps to %" GST_PTR_FORMAT, caps); - gst_pad_set_caps (GST_AUDIO_DECODER_SRC_PAD (dec), caps); - gst_caps_unref (caps); /* default stereo mapping */ dec->channel_mapping_family = 0; dec->channel_mapping[0] = 0; dec->channel_mapping[1] = 1; dec->n_streams = 1; dec->n_stereo_streams = 1; + + gst_opus_dec_negotiate (dec, NULL); } GST_DEBUG_OBJECT (dec, "Creating decoder with %d channels, %d Hz", @@ -389,7 +396,9 @@ opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buffer) buf = dec->use_inband_fec && dec->last_buffer ? dec->last_buffer : buffer; if (buf) { - data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ); + gst_buffer_map (buf, &map, GST_MAP_READ); + data = map.data; + size = map.size; GST_DEBUG_OBJECT (dec, "Using buffer of size %u", size); } else { @@ -409,7 +418,8 @@ opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buffer) goto buffer_failed; } - out_data = (gint16 *) gst_buffer_map (outbuf, &out_size, NULL, GST_MAP_WRITE); + gst_buffer_map (outbuf, &omap, GST_MAP_WRITE); + out_data = (gint16 *) omap.data; if (dec->use_inband_fec) { if (dec->last_buffer) { @@ -425,8 +435,9 @@ opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buffer) /* normal decode */ n = opus_multistream_decode (dec->state, data, size, out_data, samples, 0); } - gst_buffer_unmap (buf, data, size); - gst_buffer_unmap (outbuf, out_data, out_size); + gst_buffer_unmap (outbuf, &omap); + if (buf) + gst_buffer_unmap (buf, &map); if (n < 0) { GST_ELEMENT_ERROR (dec, STREAM, DECODE, ("Decoding error: %d", n), (NULL)); @@ -451,6 +462,9 @@ opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buffer) if (gst_buffer_get_size (outbuf) == 0) { gst_buffer_unref (outbuf); outbuf = NULL; + } else if (dec->opus_pos[0] != GST_AUDIO_CHANNEL_POSITION_INVALID) { + gst_audio_buffer_reorder_channels (outbuf, GST_AUDIO_FORMAT_S16, + dec->n_channels, dec->opus_pos, dec->info.position); } /* Apply gain */ @@ -463,16 +477,18 @@ opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buffer) gsize rsize; unsigned int i, nsamples; double volume = dec->r128_gain_volume; - gint16 *samples = - (gint16 *) gst_buffer_map (outbuf, &rsize, NULL, GST_MAP_READWRITE); + gint16 *samples; + gst_buffer_map (outbuf, &omap, GST_MAP_READWRITE); + samples = (gint16 *) omap.data; + rsize = omap.size; GST_DEBUG_OBJECT (dec, "Applying gain: volume %f", volume); nsamples = rsize / 2; for (i = 0; i < nsamples; ++i) { int sample = (int) (samples[i] * volume + 0.5); samples[i] = sample < -32768 ? -32768 : sample > 32767 ? 32767 : sample; } - gst_buffer_unmap (outbuf, samples, rsize); + gst_buffer_unmap (outbuf, &omap); } res = gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (dec), outbuf, 1); @@ -542,8 +558,8 @@ static gboolean memcmp_buffers (GstBuffer * buf1, GstBuffer * buf2) { gsize size1, size2; - gpointer data1; gboolean res; + GstMapInfo map; size1 = gst_buffer_get_size (buf1); size2 = gst_buffer_get_size (buf2); @@ -551,9 +567,9 @@ memcmp_buffers (GstBuffer * buf1, GstBuffer * buf2) if (size1 != size2) return FALSE; - data1 = gst_buffer_map (buf1, NULL, NULL, GST_MAP_READ); - res = gst_buffer_memcmp (buf2, 0, data1, size1) == 0; - gst_buffer_unmap (buf1, data1, size1); + gst_buffer_map (buf1, &map, GST_MAP_READ); + res = gst_buffer_memcmp (buf2, 0, map.data, map.size) == 0; + gst_buffer_unmap (buf1, &map); return res; } diff --git a/ext/opus/gstopusdec.h b/ext/opus/gstopusdec.h index 3ccfa26..0bea2c0 100644 --- a/ext/opus/gstopusdec.h +++ b/ext/opus/gstopusdec.h @@ -56,6 +56,9 @@ struct _GstOpusDec { guint32 pre_skip; gint16 r128_gain; + GstAudioChannelPosition opus_pos[64]; + GstAudioInfo info; + guint8 n_streams; guint8 n_stereo_streams; guint8 channel_mapping_family; diff --git a/ext/opus/gstopusenc.c b/ext/opus/gstopusenc.c index c7053cd..9c10d1a 100644 --- a/ext/opus/gstopusenc.c +++ b/ext/opus/gstopusenc.c @@ -120,6 +120,7 @@ static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_ALWAYS, GST_STATIC_CAPS ("audio/x-raw, " "format = (string) " FORMAT_STR ", " + "layout = (string) interleaved, " "rate = (int) { 8000, 12000, 16000, 24000, 48000 }, " "channels = (int) [ 1, 2 ] ") ); @@ -725,7 +726,7 @@ gst_opus_enc_sink_getcaps (GstAudioEncoder * benc, GstCaps * filter) GST_DEBUG_OBJECT (enc, "sink getcaps"); - peercaps = gst_pad_peer_query_caps (GST_AUDIO_ENCODER_SRC_PAD (benc), filter); + peercaps = gst_pad_peer_query_caps (GST_AUDIO_ENCODER_SRC_PAD (benc), NULL); if (!peercaps) { GST_DEBUG_OBJECT (benc, "No peercaps, returning template sink caps"); return @@ -787,11 +788,14 @@ gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buf) gsize bsize, size; gsize bytes = enc->frame_samples * enc->n_channels * 2; gint ret = GST_FLOW_OK; + GstMapInfo map; g_mutex_lock (enc->property_lock); if (G_LIKELY (buf)) { - bdata = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ); + gst_buffer_map (buf, &map, GST_MAP_READ); + bdata = map.data; + bsize = map.size; if (G_UNLIKELY (bsize % bytes)) { GST_DEBUG_OBJECT (enc, "draining; adding silence samples"); @@ -799,8 +803,6 @@ gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buf) size = ((bsize / bytes) + 1) * bytes; mdata = g_malloc0 (size); memcpy (mdata, bdata, bsize); - gst_buffer_unmap (buf, bdata, bsize); - bdata = NULL; data = mdata; } else { data = bdata; @@ -813,9 +815,8 @@ gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buf) while (size) { gint encoded_size; - unsigned char *out_data; - gsize out_size; GstBuffer *outbuf; + GstMapInfo omap; outbuf = gst_buffer_new_and_alloc (enc->max_payload_size * enc->n_channels); if (!outbuf) @@ -824,11 +825,11 @@ gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buf) GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)", enc->frame_samples, (int) bytes); - out_data = gst_buffer_map (outbuf, &out_size, NULL, GST_MAP_WRITE); + gst_buffer_map (outbuf, &omap, GST_MAP_WRITE); encoded_size = opus_multistream_encode (enc->state, (const gint16 *) data, - enc->frame_samples, out_data, enc->max_payload_size * enc->n_channels); - gst_buffer_unmap (outbuf, out_data, out_size); + enc->frame_samples, omap.data, enc->max_payload_size * enc->n_channels); + gst_buffer_unmap (outbuf, &omap); if (encoded_size < 0) { GST_ERROR_OBJECT (enc, "Encoding failed: %d", encoded_size); @@ -837,7 +838,7 @@ gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buf) } else if (encoded_size > enc->max_payload_size) { GST_WARNING_OBJECT (enc, "Encoded size %d is higher than max payload size (%d bytes)", - out_size, enc->max_payload_size); + encoded_size, enc->max_payload_size); ret = GST_FLOW_ERROR; goto done; } @@ -859,7 +860,7 @@ gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buf) done: if (bdata) - gst_buffer_unmap (buf, bdata, bsize); + gst_buffer_unmap (buf, &map); g_mutex_unlock (enc->property_lock); if (mdata) @@ -893,7 +894,7 @@ gst_opus_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf) /* negotiate with these caps */ GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps); - gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc), caps); + gst_audio_encoder_set_output_format (benc, caps); gst_caps_unref (caps); enc->header_sent = TRUE; diff --git a/ext/opus/gstopusheader.c b/ext/opus/gstopusheader.c index 68826a5..2de891d 100644 --- a/ext/opus/gstopusheader.c +++ b/ext/opus/gstopusheader.c @@ -127,11 +127,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); @@ -152,14 +152,15 @@ gst_opus_header_create_caps_from_headers (GstCaps ** caps, GSList ** headers, { int n_streams, family; gboolean multistream; + GstMapInfo map; guint8 *data; - gsize size; g_return_if_fail (caps); g_return_if_fail (headers && !*headers); g_return_if_fail (gst_buffer_get_size (buf1) >= 19); - data = gst_buffer_map (buf1, &size, NULL, GST_MAP_READ); + gst_buffer_map (buf1, &map, GST_MAP_READ); + data = map.data; /* work out the number of streams */ family = data[18]; @@ -167,16 +168,16 @@ gst_opus_header_create_caps_from_headers (GstCaps ** caps, GSList ** headers, n_streams = 1; } else { /* only included in the header for family > 0 */ - if (size >= 20) + if (map.size >= 20) n_streams = data[19]; else { g_warning ("family > 0 but header buffer size < 20"); - gst_buffer_unmap (buf1, data, size); + gst_buffer_unmap (buf1, &map); return; } } - gst_buffer_unmap (buf1, data, size); + gst_buffer_unmap (buf1, &map); /* mark and put on caps */ multistream = n_streams > 1; @@ -228,13 +229,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]; @@ -263,7 +267,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; } -- 2.7.4