Merge remote-tracking branch 'origin/master' into 0.11-premerge

Conflicts:
	docs/libs/Makefile.am
	ext/kate/gstkatetiger.c
	ext/opus/gstopusdec.c
	ext/xvid/gstxvidenc.c
	gst-libs/gst/basecamerabinsrc/Makefile.am
	gst-libs/gst/basecamerabinsrc/gstbasecamerasrc.c
	gst-libs/gst/basecamerabinsrc/gstbasecamerasrc.h
	gst-libs/gst/video/gstbasevideocodec.c
	gst-libs/gst/video/gstbasevideocodec.h
	gst-libs/gst/video/gstbasevideodecoder.c
	gst-libs/gst/video/gstbasevideoencoder.c
	gst/asfmux/gstasfmux.c
	gst/audiovisualizers/gstwavescope.c
	gst/camerabin2/gstcamerabin2.c
	gst/debugutils/gstcompare.c
	gst/frei0r/gstfrei0rmixer.c
	gst/mpegpsmux/mpegpsmux.c
	gst/mpegtsmux/mpegtsmux.c
	gst/mxf/mxfmux.c
	gst/videomeasure/gstvideomeasure_ssim.c
	gst/videoparsers/gsth264parse.c
	gst/videoparsers/gstmpeg4videoparse.c
This commit is contained in:
Edward Hervey 2011-12-30 11:41:17 +01:00
commit d5b34263cd
9 changed files with 373 additions and 72 deletions

View file

@ -1,6 +1,6 @@
plugin_LTLIBRARIES = libgstopus.la
libgstopus_la_SOURCES = gstopus.c gstopusdec.c gstopusenc.c gstopusparse.c gstopusheader.c gstopuscommon.c
libgstopus_la_SOURCES = gstopus.c gstopusdec.c gstopusenc.c gstopusparse.c gstopusheader.c gstopuscommon.c gstrtpopuspay.c gstrtpopusdepay.c
libgstopus_la_CFLAGS = \
-DGST_USE_UNSTABLE_API \
$(GST_PLUGINS_BASE_CFLAGS) \
@ -9,10 +9,11 @@ libgstopus_la_CFLAGS = \
libgstopus_la_LIBADD = \
-lgstaudio-$(GST_MAJORMINOR) \
$(GST_PLUGINS_BASE_LIBS) -lgsttag-$(GST_MAJORMINOR) \
-lgstrtp-@GST_MAJORMINOR@ \
$(GST_BASE_LIBS) \
$(GST_LIBS) \
$(OPUS_LIBS)
libgstopus_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(LIBM)
libgstopus_la_LIBTOOLFLAGS = --tag=disable-static
noinst_HEADERS = gstopusenc.h gstopusdec.h gstopusparse.h gstopusheader.h gstopuscommon.h
noinst_HEADERS = gstopusenc.h gstopusdec.h gstopusparse.h gstopusheader.h gstopuscommon.h gstrtpopuspay.h gstrtpopusdepay.h

View file

@ -25,6 +25,9 @@
#include "gstopusenc.h"
#include "gstopusparse.h"
#include "gstrtpopuspay.h"
#include "gstrtpopusdepay.h"
#include <gst/tag/tag.h>
static gboolean
@ -43,6 +46,14 @@ plugin_init (GstPlugin * plugin)
GST_TYPE_OPUS_PARSE))
return FALSE;
if (!gst_element_register (plugin, "rtpopusdepay", GST_RANK_NONE,
GST_TYPE_RTP_OPUS_DEPAY))
return FALSE;
if (!gst_element_register (plugin, "rtpopuspay", GST_RANK_NONE,
GST_TYPE_RTP_OPUS_PAY))
return FALSE;
gst_tag_register_musicbrainz_tags ();
return TRUE;

View file

@ -17,6 +17,8 @@
* Boston, MA 02111-1307, USA.
*/
#include <stdio.h>
#include <string.h>
#include "gstopuscommon.h"
/* http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-800004.3.9 */
@ -86,3 +88,19 @@ const char *gst_opus_channel_names[] = {
"side right",
"none"
};
void
gst_opus_common_log_channel_mapping_table (GstElement * element,
GstDebugCategory * category, const char *msg, int n_channels,
const guint8 * table)
{
char s[8 + 256 * 4] = "[ "; /* enough for 256 times "255 " at most */
int n;
for (n = 0; n < n_channels; ++n) {
size_t len = strlen (s);
snprintf (s + len, sizeof (s) - len, "%d ", table[n]);
}
strcat (s, "]");
GST_CAT_LEVEL_LOG (category, GST_LEVEL_INFO, element, "%s: %s", msg, s);
}

View file

@ -28,6 +28,9 @@ G_BEGIN_DECLS
extern const GstAudioChannelPosition gst_opus_channel_positions[][8];
extern const char *gst_opus_channel_names[];
extern void gst_opus_common_log_channel_mapping_table (GstElement *element,
GstDebugCategory * category, const char *msg,
int n_channels, const guint8 *table);
G_END_DECLS

View file

@ -38,12 +38,11 @@
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#include "config.h"
#endif
#include <math.h>
#include <string.h>
#include <gst/tag/tag.h>
#include "gstopusheader.h"
#include "gstopuscommon.h"
#include "gstopusdec.h"
@ -57,7 +56,7 @@ GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-raw, "
"format = (string) { " GST_AUDIO_NE (S16) " }, "
"rate = (int) { 8000, 12000, 16000, 24000, 48000 }, "
"rate = (int) { 48000, 24000, 16000, 12000, 8000 }, "
"channels = (int) [ 1, 8 ] ")
);
@ -207,12 +206,32 @@ 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)
{
GstCaps *caps = gst_pad_get_allowed_caps (GST_AUDIO_DECODER_SRC_PAD (dec));
GstStructure *s;
caps = gst_caps_make_writable (caps);
gst_caps_truncate (caps);
s = gst_caps_get_structure (caps, 0);
gst_structure_fixate_field_nearest_int (s, "rate", 48000);
gst_structure_get_int (s, "rate", &dec->sample_rate);
gst_structure_fixate_field_nearest_int (s, "channels", dec->n_channels);
gst_structure_get_int (s, "channels", &dec->n_channels);
GST_INFO_OBJECT (dec, "Negotiated %d channels, %d Hz", dec->n_channels,
dec->sample_rate);
return caps;
}
static GstFlowReturn
gst_opus_dec_parse_header (GstOpusDec * dec, GstBuffer * buf)
{
const guint8 *data;
GstCaps *caps;
GstStructure *s;
const GstAudioChannelPosition *pos = NULL;
g_return_val_if_fail (gst_opus_header_is_id_header (buf), GST_FLOW_ERROR);
@ -277,16 +296,7 @@ gst_opus_dec_parse_header (GstOpusDec * dec, GstBuffer * buf)
}
}
/* negotiate width with downstream */
caps = gst_pad_get_allowed_caps (GST_AUDIO_DECODER_SRC_PAD (dec));
s = gst_caps_get_structure (caps, 0);
gst_structure_fixate_field_nearest_int (s, "rate", 48000);
gst_structure_get_int (s, "rate", &dec->sample_rate);
gst_structure_fixate_field_nearest_int (s, "channels", dec->n_channels);
gst_structure_get_int (s, "channels", &dec->n_channels);
GST_INFO_OBJECT (dec, "Negotiated %d channels, %d Hz", dec->n_channels,
dec->sample_rate);
caps = gst_opus_dec_negotiate (dec);
if (pos) {
GST_DEBUG_OBJECT (dec, "Setting channel positions on caps");
@ -327,11 +337,36 @@ opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buffer)
GstBuffer *buf;
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_DEBUG_OBJECT (dec, "Creating decoder with %d channels, %d Hz",
dec->n_channels, dec->sample_rate);
dec->state = opus_multistream_decoder_create (dec->sample_rate,
dec->n_channels, dec->n_streams, dec->n_stereo_streams,
dec->channel_mapping, &err);
#ifndef GST_DISABLE_DEBUG
gst_opus_common_log_channel_mapping_table (GST_ELEMENT (dec), opusdec_debug,
"Mapping table", dec->n_channels, dec->channel_mapping);
#endif
GST_DEBUG_OBJECT (dec, "%d streams, %d stereo", dec->n_streams,
dec->n_stereo_streams);
dec->state =
opus_multistream_decoder_create (dec->sample_rate, dec->n_channels,
dec->n_streams, dec->n_stereo_streams, dec->channel_mapping, &err);
if (!dec->state || err != OPUS_OK)
goto creation_failed;
}
@ -411,12 +446,12 @@ opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buffer)
GST_INFO_OBJECT (dec,
"Skipping %u samples (%u at 48000 Hz, %u left to skip)", skip,
scaled_skip, dec->pre_skip);
}
if (gst_buffer_get_size (outbuf) == 0) {
gst_buffer_unref (outbuf);
outbuf = NULL;
}
}
/* Apply gain */
/* Would be better off leaving this to a volume element, as this is

View file

@ -161,6 +161,8 @@ static void gst_opus_enc_finalize (GObject * object);
static gboolean gst_opus_enc_sink_event (GstAudioEncoder * benc,
GstEvent * event);
static GstCaps *gst_opus_enc_sink_getcaps (GstAudioEncoder * benc,
GstCaps * filter);
static gboolean gst_opus_enc_setup (GstOpusEnc * enc);
static void gst_opus_enc_get_property (GObject * object, guint prop_id,
@ -211,6 +213,7 @@ gst_opus_enc_class_init (GstOpusEncClass * klass)
base_class->set_format = GST_DEBUG_FUNCPTR (gst_opus_enc_set_format);
base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_opus_enc_handle_frame);
base_class->event = GST_DEBUG_FUNCPTR (gst_opus_enc_sink_event);
base_class->getcaps = GST_DEBUG_FUNCPTR (gst_opus_enc_sink_getcaps);
g_object_class_install_property (gobject_class, PROP_AUDIO,
g_param_spec_boolean ("audio", "Audio or voice",
@ -401,7 +404,50 @@ gst_opus_enc_get_frame_samples (GstOpusEnc * enc)
}
static void
gst_opus_enc_setup_channel_mapping (GstOpusEnc * enc, const GstAudioInfo * info)
gst_opus_enc_setup_trivial_mapping (GstOpusEnc * enc, guint8 mapping[256])
{
int n;
for (n = 0; n < 255; ++n)
mapping[n] = n;
}
static int
gst_opus_enc_find_channel_position (GstOpusEnc * enc, const GstAudioInfo * info,
GstAudioChannelPosition position)
{
int n;
for (n = 0; n < enc->n_channels; ++n) {
if (GST_AUDIO_INFO_POSITION (info, n) == position) {
return n;
}
}
return -1;
}
static int
gst_opus_enc_find_channel_position_in_vorbis_order (GstOpusEnc * enc,
GstAudioChannelPosition position)
{
int c;
for (c = 0; c < enc->n_channels; ++c) {
if (gst_opus_channel_positions[enc->n_channels - 1][c] == position) {
GST_INFO_OBJECT (enc,
"Channel position %s maps to index %d in Vorbis order",
gst_opus_channel_names[position], c);
return c;
}
}
GST_WARNING_OBJECT (enc,
"Channel position %s is not representable in Vorbis order",
gst_opus_channel_names[position]);
return -1;
}
static void
gst_opus_enc_setup_channel_mappings (GstOpusEnc * enc,
const GstAudioInfo * info)
{
#define MAPS(idx,pos) (GST_AUDIO_INFO_POSITION (info, (idx)) == GST_AUDIO_CHANNEL_POSITION_##pos)
@ -411,14 +457,15 @@ gst_opus_enc_setup_channel_mapping (GstOpusEnc * enc, const GstAudioInfo * info)
enc->n_channels);
/* Start by setting up a default trivial mapping */
for (n = 0; n < 255; ++n)
enc->channel_mapping[n] = n;
enc->n_stereo_streams = 0;
gst_opus_enc_setup_trivial_mapping (enc, enc->encoding_channel_mapping);
gst_opus_enc_setup_trivial_mapping (enc, enc->decoding_channel_mapping);
/* For one channel, use the basic RTP mapping */
if (enc->n_channels == 1) {
GST_INFO_OBJECT (enc, "Mono, trivial RTP mapping");
enc->channel_mapping_family = 0;
enc->channel_mapping[0] = 0;
/* implicit mapping for family 0 */
return;
}
@ -428,9 +475,11 @@ gst_opus_enc_setup_channel_mapping (GstOpusEnc * enc, const GstAudioInfo * info)
if (MAPS (0, FRONT_LEFT) && MAPS (1, FRONT_RIGHT)) {
GST_INFO_OBJECT (enc, "Stereo, canonical mapping");
enc->channel_mapping_family = 0;
enc->n_stereo_streams = 1;
/* The channel mapping is implicit for family 0, that's why we do not
attempt to create one for right/left - this will be mapped to the
Vorbis mapping below. */
return;
} else {
GST_DEBUG_OBJECT (enc, "Stereo, but not canonical mapping, continuing");
}
@ -438,42 +487,115 @@ gst_opus_enc_setup_channel_mapping (GstOpusEnc * enc, const GstAudioInfo * info)
/* For channels between 1 and 8, we use the Vorbis mapping if we can
find a permutation that matches it. Mono will have been taken care
of earlier, but this code also handles it. */
of earlier, but this code also handles it. Same for left/right stereo.
There are two mappings. One maps the input channels to an ordering
which has the natural pairs first so they can benefit from the Opus
stereo channel coupling, and the other maps this ordering to the
Vorbis ordering. */
if (enc->n_channels >= 1 && enc->n_channels <= 8) {
GST_DEBUG_OBJECT (enc,
"In range for the Vorbis mapping, checking channel positions");
for (n = 0; n < enc->n_channels; ++n) {
GstAudioChannelPosition pos = GST_AUDIO_INFO_POSITION (info, n);
int c;
int c0, c1, c0v, c1v;
int mapped;
gboolean positions_done[256];
static const GstAudioChannelPosition pairs[][2] = {
{GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT},
{GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT},
{GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER},
{GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER},
{GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT},
};
size_t pair;
GST_DEBUG_OBJECT (enc, "Channel %d has position %d (%s)", n, pos,
gst_opus_channel_names[pos]);
for (c = 0; c < enc->n_channels; ++c) {
if (gst_opus_channel_positions[enc->n_channels - 1][c] == pos) {
GST_DEBUG_OBJECT (enc, "Found in Vorbis mapping as channel %d", c);
break;
}
}
if (c == enc->n_channels) {
/* We did not find that position, so use undefined */
GST_DEBUG_OBJECT (enc,
"In range for the Vorbis mapping, building channel mapping tables");
enc->n_stereo_streams = 0;
mapped = 0;
for (n = 0; n < 256; ++n)
positions_done[n] = FALSE;
/* First, find any natural pairs, and move them to the front */
for (pair = 0; pair < G_N_ELEMENTS (pairs); ++pair) {
GstAudioChannelPosition p0 = pairs[pair][0];
GstAudioChannelPosition p1 = pairs[pair][1];
c0 = gst_opus_enc_find_channel_position (enc, info, p0);
c1 = gst_opus_enc_find_channel_position (enc, info, p1);
if (c0 >= 0 && c1 >= 0) {
/* We found a natural pair */
GST_DEBUG_OBJECT (enc, "Natural pair '%s/%s' found at %d %d",
gst_opus_channel_names[p0], gst_opus_channel_names[p1], c0, c1);
/* Find where they map in Vorbis order */
c0v = gst_opus_enc_find_channel_position_in_vorbis_order (enc, p0);
c1v = gst_opus_enc_find_channel_position_in_vorbis_order (enc, p1);
if (c0v < 0 || c1v < 0) {
GST_WARNING_OBJECT (enc,
"Position %d (%s) not found in Vorbis mapping, using unknown mapping",
pos, gst_opus_channel_positions[pos]);
"Cannot map channel positions to Vorbis order, using unknown mapping");
enc->channel_mapping_family = 255;
enc->n_stereo_streams = 0;
return;
}
GST_DEBUG_OBJECT (enc, "Mapping output channel %d to %d (%s)", c, n,
gst_opus_channel_names[pos]);
enc->channel_mapping[c] = n;
enc->encoding_channel_mapping[mapped] = c0;
enc->encoding_channel_mapping[mapped + 1] = c1;
enc->decoding_channel_mapping[c0v] = mapped;
enc->decoding_channel_mapping[c1v] = mapped + 1;
enc->n_stereo_streams++;
mapped += 2;
positions_done[p0] = positions_done[p1] = TRUE;
}
GST_INFO_OBJECT (enc, "Permutation found, using Vorbis mapping");
}
/* Now add all other input channels as mono streams */
for (n = 0; n < enc->n_channels; ++n) {
GstAudioChannelPosition position = GST_AUDIO_INFO_POSITION (info, n);
/* if we already mapped it while searching for pairs, nothing else
needs to be done */
if (!positions_done[position]) {
int cv;
GST_DEBUG_OBJECT (enc, "Channel position %s is not mapped yet, adding",
gst_opus_channel_names[position]);
cv = gst_opus_enc_find_channel_position_in_vorbis_order (enc, position);
if (cv < 0) {
GST_WARNING_OBJECT (enc,
"Cannot map channel positions to Vorbis order, using unknown mapping");
enc->channel_mapping_family = 255;
enc->n_stereo_streams = 0;
return;
}
enc->encoding_channel_mapping[mapped] = n;
enc->decoding_channel_mapping[cv] = mapped;
mapped++;
}
}
#ifndef GST_DISABLE_DEBUG
GST_INFO_OBJECT (enc,
"Mapping tables built: %d channels, %d stereo streams", enc->n_channels,
enc->n_stereo_streams);
gst_opus_common_log_channel_mapping_table (GST_ELEMENT (enc), opusenc_debug,
"Encoding mapping table", enc->n_channels,
enc->encoding_channel_mapping);
gst_opus_common_log_channel_mapping_table (GST_ELEMENT (enc), opusenc_debug,
"Decoding mapping table", enc->n_channels,
enc->decoding_channel_mapping);
#endif
enc->channel_mapping_family = 1;
return;
}
/* For other cases, we use undefined, with the default trivial mapping */
/* More than 8 channels, if future mappings are added for those */
/* For other cases, we use undefined, with the default trivial mapping
and all mono streams */
GST_WARNING_OBJECT (enc, "Unknown mapping");
enc->channel_mapping_family = 255;
enc->n_stereo_streams = 0;
#undef MAPS
}
@ -489,7 +611,7 @@ gst_opus_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
enc->n_channels = GST_AUDIO_INFO_CHANNELS (info);
enc->sample_rate = GST_AUDIO_INFO_RATE (info);
gst_opus_enc_setup_channel_mapping (enc, info);
gst_opus_enc_setup_channel_mappings (enc, info);
GST_DEBUG_OBJECT (benc, "Setup with %d channels, %d Hz", enc->n_channels,
enc->sample_rate);
@ -514,17 +636,24 @@ gst_opus_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
static gboolean
gst_opus_enc_setup (GstOpusEnc * enc)
{
int error = OPUS_OK, n;
guint8 trivial_mapping[256];
int error = OPUS_OK;
GST_DEBUG_OBJECT (enc, "setup");
#ifndef GST_DISABLE_DEBUG
GST_DEBUG_OBJECT (enc,
"setup: %d Hz, %d channels, %d stereo streams, family %d",
enc->sample_rate, enc->n_channels, enc->n_stereo_streams,
enc->channel_mapping_family);
GST_INFO_OBJECT (enc, "Mapping tables built: %d channels, %d stereo streams",
enc->n_channels, enc->n_stereo_streams);
gst_opus_common_log_channel_mapping_table (GST_ELEMENT (enc), opusenc_debug,
"Encoding mapping table", enc->n_channels, enc->encoding_channel_mapping);
gst_opus_common_log_channel_mapping_table (GST_ELEMENT (enc), opusenc_debug,
"Decoding mapping table", enc->n_channels, enc->decoding_channel_mapping);
#endif
for (n = 0; n < 256; ++n)
trivial_mapping[n] = n;
enc->state =
opus_multistream_encoder_create (enc->sample_rate, enc->n_channels,
enc->n_channels, 0, trivial_mapping,
enc->state = opus_multistream_encoder_create (enc->sample_rate,
enc->n_channels, enc->n_channels - enc->n_stereo_streams,
enc->n_stereo_streams, enc->encoding_channel_mapping,
enc->audio_or_voip ? OPUS_APPLICATION_AUDIO : OPUS_APPLICATION_VOIP,
&error);
if (!enc->state || error != OPUS_OK)
@ -580,6 +709,75 @@ gst_opus_enc_sink_event (GstAudioEncoder * benc, GstEvent * event)
return FALSE;
}
static GstCaps *
gst_opus_enc_sink_getcaps (GstAudioEncoder * benc, GstCaps * filter)
{
GstOpusEnc *enc;
GstCaps *caps;
GstCaps *peercaps = NULL;
GstCaps *intersect = NULL;
guint i;
gboolean allow_multistream;
enc = GST_OPUS_ENC (benc);
GST_DEBUG_OBJECT (enc, "sink getcaps");
peercaps = gst_pad_peer_query_caps (GST_AUDIO_ENCODER_SRC_PAD (benc), filter);
if (!peercaps) {
GST_DEBUG_OBJECT (benc, "No peercaps, returning template sink caps");
return
gst_caps_copy (gst_pad_get_pad_template_caps
(GST_AUDIO_ENCODER_SINK_PAD (benc)));
}
intersect = gst_caps_intersect (peercaps,
gst_pad_get_pad_template_caps (GST_AUDIO_ENCODER_SRC_PAD (benc)));
gst_caps_unref (peercaps);
if (gst_caps_is_empty (intersect))
return intersect;
allow_multistream = FALSE;
for (i = 0; i < gst_caps_get_size (intersect); i++) {
GstStructure *s = gst_caps_get_structure (intersect, i);
gboolean multistream;
if (gst_structure_get_boolean (s, "multistream", &multistream)) {
if (multistream) {
allow_multistream = TRUE;
}
} else {
allow_multistream = TRUE;
}
}
gst_caps_unref (intersect);
caps =
gst_caps_copy (gst_pad_get_pad_template_caps (GST_AUDIO_ENCODER_SINK_PAD
(benc)));
if (!allow_multistream) {
GValue range = { 0 };
g_value_init (&range, GST_TYPE_INT_RANGE);
gst_value_set_int_range (&range, 1, 2);
for (i = 0; i < gst_caps_get_size (caps); i++) {
GstStructure *s = gst_caps_get_structure (caps, i);
gst_structure_set_value (s, "channels", &range);
}
g_value_unset (&range);
}
if (filter) {
GstCaps *tmp = gst_caps_intersect_full (caps, filter,
GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (caps);
caps = tmp;
}
GST_DEBUG_OBJECT (enc, "Returning caps: %" GST_PTR_FORMAT, caps);
return caps;
}
static GstFlowReturn
gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buf)
{
@ -684,7 +882,8 @@ gst_opus_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
enc->headers = NULL;
gst_opus_header_create_caps (&caps, &enc->headers, enc->n_channels,
enc->sample_rate, enc->channel_mapping_family, enc->channel_mapping,
enc->n_stereo_streams, enc->sample_rate, enc->channel_mapping_family,
enc->decoding_channel_mapping,
gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc)));

View file

@ -79,7 +79,9 @@ struct _GstOpusEnc {
GstTagList *tags;
guint8 channel_mapping_family;
guint8 channel_mapping[256];
guint8 encoding_channel_mapping[256];
guint8 decoding_channel_mapping[256];
guint8 n_stereo_streams;
};
struct _GstOpusEncClass {

View file

@ -27,12 +27,17 @@
#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;
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 */
@ -44,8 +49,8 @@ gst_opus_enc_create_id_buffer (gint nchannels, gint sample_rate,
gst_byte_writer_put_uint16_le (&bw, 0); /* output gain */
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_uint8 (&bw, nchannels - n_stereo_streams);
gst_byte_writer_put_uint8 (&bw, n_stereo_streams);
gst_byte_writer_put_data (&bw, channel_mapping, nchannels);
}
@ -145,11 +150,38 @@ void
gst_opus_header_create_caps_from_headers (GstCaps ** caps, GSList ** headers,
GstBuffer * buf1, GstBuffer * buf2)
{
int n_streams, family;
gboolean multistream;
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);
/* 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 (size >= 20)
n_streams = data[19];
else {
g_warning ("family > 0 but header buffer size < 20");
gst_buffer_unmap (buf1, data, size);
return;
}
}
gst_buffer_unmap (buf1, data, size);
/* 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 +190,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 +207,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);

View file

@ -28,7 +28,7 @@ G_BEGIN_DECLS
extern void gst_opus_header_create_caps_from_headers (GstCaps **caps, GSList **headers,
GstBuffer *id_header, GstBuffer *comment_header);
extern void gst_opus_header_create_caps (GstCaps **caps, GSList **headers,
gint nchannels, gint sample_rate,
gint nchannels, gint n_stereo_streams, gint sample_rate,
guint8 channel_mapping_family, const guint8 *channel_mapping,
const GstTagList *tags);
extern gboolean gst_opus_header_is_header (GstBuffer * buf,