From d2ddf5eba5bcb848cef150a2aa0cdcfef7010354 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Tue, 30 May 2006 13:22:58 +0000 Subject: [PATCH] ext/vorbis/vorbisenc.*: Multi-channel caps negotiation, so we can do proper multichannel vorbis encoding, negotiated ... Original commit message from CVS: * ext/vorbis/vorbisenc.c: (raw_caps_factory), (gst_vorbis_enc_class_init), (gst_vorbis_enc_dispose), (gst_vorbis_enc_generate_sink_caps), (gst_vorbis_enc_sink_getcaps), (gst_vorbis_enc_init), (gst_vorbis_enc_buffer_from_header_packet), (gst_vorbis_enc_chain), (gst_vorbis_enc_change_state): * ext/vorbis/vorbisenc.h: Multi-channel caps negotiation, so we can do proper multichannel vorbis encoding, negotiated through audioconvert. --- ChangeLog | 11 ++++ ext/vorbis/vorbisenc.c | 131 ++++++++++++++++++++++++++++++++++++++--- ext/vorbis/vorbisenc.h | 3 + 3 files changed, 138 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index bcd61b4ce7..01c444b424 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2006-05-30 Michael Smith + + * ext/vorbis/vorbisenc.c: (raw_caps_factory), + (gst_vorbis_enc_class_init), (gst_vorbis_enc_dispose), + (gst_vorbis_enc_generate_sink_caps), (gst_vorbis_enc_sink_getcaps), + (gst_vorbis_enc_init), (gst_vorbis_enc_buffer_from_header_packet), + (gst_vorbis_enc_chain), (gst_vorbis_enc_change_state): + * ext/vorbis/vorbisenc.h: + Multi-channel caps negotiation, so we can do proper multichannel + vorbis encoding, negotiated through audioconvert. + 2006-05-30 Wim Taymans * tests/check/elements/adder.c: (test_event_message_received), diff --git a/ext/vorbis/vorbisenc.c b/ext/vorbis/vorbisenc.c index c5cc86a830..de74f83fc3 100644 --- a/ext/vorbis/vorbisenc.c +++ b/ext/vorbis/vorbisenc.c @@ -58,6 +58,7 @@ #include #include +#include #include "vorbisenc.h" GST_DEBUG_CATEGORY_EXTERN (vorbisenc_debug); @@ -120,6 +121,7 @@ static gboolean gst_vorbis_enc_sink_event (GstPad * pad, GstEvent * event); static GstFlowReturn gst_vorbis_enc_chain (GstPad * pad, GstBuffer * buffer); static gboolean gst_vorbis_enc_setup (GstVorbisEnc * vorbisenc); +static void gst_vorbis_enc_dispose (GObject * object); static void gst_vorbis_enc_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); static void gst_vorbis_enc_set_property (GObject * object, guint prop_id, @@ -149,12 +151,12 @@ vorbis_caps_factory (void) static GstCaps * raw_caps_factory (void) { - /* lowest sample rate is in vorbis/lib/modes/setup_8.h, 8000 Hz - * highest sample rate is in vorbis/lib/modes/setup_44.h, 50000 Hz */ + /* lowest, highest sample rates come from vorbis/lib/modes/setup_X.h: + * 1-200000 Hz */ return gst_caps_new_simple ("audio/x-raw-float", - "rate", GST_TYPE_INT_RANGE, 8000, 50000, - "channels", GST_TYPE_INT_RANGE, 1, 2, + "rate", GST_TYPE_INT_RANGE, 1, 200000, + "channels", GST_TYPE_INT_RANGE, 1, 256, "endianness", G_TYPE_INT, G_BYTE_ORDER, "width", G_TYPE_INT, 32, NULL); } @@ -189,6 +191,7 @@ gst_vorbis_enc_class_init (GstVorbisEncClass * klass) gobject_class->set_property = gst_vorbis_enc_set_property; gobject_class->get_property = gst_vorbis_enc_get_property; + gobject_class->dispose = gst_vorbis_enc_dispose; g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MAX_BITRATE, g_param_spec_int ("max-bitrate", "Maximum Bitrate", @@ -221,6 +224,113 @@ gst_vorbis_enc_class_init (GstVorbisEncClass * klass) GST_DEBUG_FUNCPTR (gst_vorbis_enc_change_state); } +static void +gst_vorbis_enc_dispose (GObject * object) +{ + GstVorbisEnc *vorbisenc = GST_VORBISENC (object); + + if (vorbisenc->sinkcaps) { + gst_caps_unref (vorbisenc->sinkcaps); + vorbisenc->sinkcaps = NULL; + } + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static GstAudioChannelPosition vorbischannelpositions[][6] = { + { /* Mono */ + GST_AUDIO_CHANNEL_POSITION_FRONT_MONO}, + { /* Stereo */ + GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, + GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, + { /* Stereo + Centre */ + GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, + GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, + GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, + { /* Quadraphonic */ + GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, + GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, + GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, + GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, + }, + { /* Stereo + Centre + rear stereo */ + GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, + GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, + GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, + GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, + GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, + }, + { /* Full 5.1 Surround */ + GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, + GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, + GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, + GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, + GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, + GST_AUDIO_CHANNEL_POSITION_LFE, + }, +}; +static GstCaps * +gst_vorbis_enc_generate_sink_caps (void) +{ + GstCaps *caps = gst_caps_new_empty (); + int i, c; + + gst_caps_append_structure (caps, gst_structure_new ("audio/x-raw-float", + "rate", GST_TYPE_INT_RANGE, 1, 200000, + "channels", G_TYPE_INT, 1, + "endianness", G_TYPE_INT, G_BYTE_ORDER, "width", G_TYPE_INT, 32, + NULL)); + + gst_caps_append_structure (caps, gst_structure_new ("audio/x-raw-float", + "rate", GST_TYPE_INT_RANGE, 1, 200000, + "channels", G_TYPE_INT, 2, + "endianness", G_TYPE_INT, G_BYTE_ORDER, "width", G_TYPE_INT, 32, + NULL)); + + for (i = 3; i <= 6; i++) { + GValue chanpos = { 0 }; + GValue pos = { 0 }; + GstStructure *structure; + + g_value_init (&chanpos, GST_TYPE_ARRAY); + g_value_init (&pos, GST_TYPE_AUDIO_CHANNEL_POSITION); + + for (c = 0; c < i; c++) { + g_value_set_enum (&pos, vorbischannelpositions[i - 1][c]); + gst_value_array_append_value (&chanpos, &pos); + } + g_value_unset (&pos); + + structure = gst_structure_new ("audio/x-raw-float", + "rate", GST_TYPE_INT_RANGE, 1, 200000, + "channels", G_TYPE_INT, i, + "endianness", G_TYPE_INT, G_BYTE_ORDER, "width", G_TYPE_INT, 32, NULL); + gst_structure_set_value (structure, "channel-positions", &chanpos); + g_value_unset (&chanpos); + + gst_caps_append_structure (caps, structure); + } + + gst_caps_append_structure (caps, gst_structure_new ("audio/x-raw-float", + "rate", GST_TYPE_INT_RANGE, 1, 200000, + "channels", GST_TYPE_INT_RANGE, 7, 256, + "endianness", G_TYPE_INT, G_BYTE_ORDER, "width", G_TYPE_INT, 32, + NULL)); + + return caps; +} + +static GstCaps * +gst_vorbis_enc_sink_getcaps (GstPad * pad) +{ + GstVorbisEnc *vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad)); + + if (vorbisenc->sinkcaps == NULL) + vorbisenc->sinkcaps = gst_vorbis_enc_generate_sink_caps (); + + return gst_caps_ref (vorbisenc->sinkcaps); +} + static gboolean gst_vorbis_enc_sink_setcaps (GstPad * pad, GstCaps * caps) { @@ -488,6 +598,8 @@ gst_vorbis_enc_init (GstVorbisEnc * vorbisenc, GstVorbisEncClass * klass) GST_DEBUG_FUNCPTR (gst_vorbis_enc_chain)); gst_pad_set_setcaps_function (vorbisenc->sinkpad, GST_DEBUG_FUNCPTR (gst_vorbis_enc_sink_setcaps)); + gst_pad_set_getcaps_function (vorbisenc->sinkpad, + GST_DEBUG_FUNCPTR (gst_vorbis_enc_sink_getcaps)); gst_pad_set_query_function (vorbisenc->sinkpad, GST_DEBUG_FUNCPTR (gst_vorbis_enc_sink_query)); gst_element_add_pad (GST_ELEMENT (vorbisenc), vorbisenc->sinkpad); @@ -807,6 +919,8 @@ gst_vorbis_enc_buffer_from_header_packet (GstVorbisEnc * vorbisenc, GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE; GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE; + gst_buffer_set_caps (outbuf, vorbisenc->srccaps); + GST_DEBUG ("created header packet buffer, %d bytes", GST_BUFFER_SIZE (outbuf)); return outbuf; @@ -958,7 +1072,8 @@ gst_vorbis_enc_chain (GstPad * pad, GstBuffer * buffer) buf3 = gst_vorbis_enc_buffer_from_header_packet (vorbisenc, &header_code); /* mark and put on caps */ - caps = gst_pad_get_caps (vorbisenc->srcpad); + vorbisenc->srccaps = gst_caps_new_simple ("audio/x-vorbis", NULL); + caps = vorbisenc->srccaps; caps = gst_vorbis_enc_set_header_on_caps (caps, buf1, buf2, buf3); /* negotiate with these caps */ @@ -969,8 +1084,6 @@ gst_vorbis_enc_chain (GstPad * pad, GstBuffer * buffer) gst_buffer_set_caps (buf2, caps); gst_buffer_set_caps (buf3, caps); - gst_caps_unref (caps); - /* push out buffers */ if ((ret = gst_vorbis_enc_push_buffer (vorbisenc, buf1)) != GST_FLOW_OK) goto failed_header_push; @@ -1210,6 +1323,10 @@ gst_vorbis_enc_change_state (GstElement * element, GstStateChange transition) vorbis_info_clear (&vorbisenc->vi); g_free (vorbisenc->last_message); vorbisenc->last_message = NULL; + if (vorbisenc->srccaps) { + gst_caps_unref (vorbisenc->srccaps); + vorbisenc->srccaps = NULL; + } break; case GST_STATE_CHANGE_READY_TO_NULL: gst_tag_list_free (vorbisenc->tags); diff --git a/ext/vorbis/vorbisenc.h b/ext/vorbis/vorbisenc.h index 0cf8b2b56b..40f009ef68 100644 --- a/ext/vorbis/vorbisenc.h +++ b/ext/vorbis/vorbisenc.h @@ -53,6 +53,9 @@ struct _GstVorbisEnc { GstPad *sinkpad; GstPad *srcpad; + GstCaps *srccaps; + GstCaps *sinkcaps; + vorbis_info vi; /* struct that stores all the static vorbis bitstream settings */ vorbis_comment vc; /* struct that stores all the user comments */