diff --git a/ChangeLog b/ChangeLog index 86e80b0cf2..b3146dc2ed 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,32 @@ +2004-05-10 Wim Taymans + + * ext/vorbis/Makefile.am: + * ext/vorbis/README: + * ext/vorbis/oggvorbisenc.c: (gst_oggvorbisenc_get_formats), + (oggvorbisenc_get_type), (vorbis_caps_factory), (raw_caps_factory), + (gst_oggvorbisenc_base_init), (gst_oggvorbisenc_class_init), + (gst_oggvorbisenc_sinkconnect), (gst_oggvorbisenc_convert_src), + (gst_oggvorbisenc_convert_sink), + (gst_oggvorbisenc_get_query_types), (gst_oggvorbisenc_src_query), + (gst_oggvorbisenc_init), (gst_oggvorbisenc_get_tag_value), + (gst_oggvorbisenc_metadata_set1), (gst_oggvorbisenc_set_metadata), + (get_constraints_string), (update_start_message), + (gst_oggvorbisenc_setup), (gst_oggvorbisenc_write_page), + (gst_oggvorbisenc_chain), (gst_oggvorbisenc_get_property), + (gst_oggvorbisenc_set_property), (gst_oggvorbisenc_change_state): + * ext/vorbis/oggvorbisenc.h: + * ext/vorbis/vorbis.c: (plugin_init): + * ext/vorbis/vorbisenc.c: (vorbis_caps_factory), + (raw_caps_factory), (gst_vorbisenc_class_init), + (gst_vorbisenc_init), (gst_vorbisenc_setup), + (gst_vorbisenc_push_packet), (gst_vorbisenc_chain), + (gst_vorbisenc_get_property), (gst_vorbisenc_set_property): + * ext/vorbis/vorbisenc.h: + Added a raw vorbis encoder to be used with the oggmuxer. + We still need the old encoder for some gnome applications, + read the README to find out how that works. + The raw encoder is called "rawvorbisenc" until 0.9. + 2004-05-10 Wim Taymans * ext/ogg/gstogg.c: (plugin_init): diff --git a/ext/vorbis/Makefile.am b/ext/vorbis/Makefile.am index 9ee00279c0..e248bdfd16 100644 --- a/ext/vorbis/Makefile.am +++ b/ext/vorbis/Makefile.am @@ -1,10 +1,10 @@ plugin_LTLIBRARIES = libgstvorbis.la -libgstvorbis_la_SOURCES = vorbis.c vorbisdec.c vorbisenc.c +libgstvorbis_la_SOURCES = vorbis.c vorbisdec.c vorbisenc.c oggvorbisenc.c libgstvorbis_la_CFLAGS = $(GST_CFLAGS) $(VORBIS_CFLAGS) ## AM_PATH_VORBIS also sets VORBISENC_LIBS libgstvorbis_la_LIBADD = $(VORBIS_LIBS) $(VORBISENC_LIBS) $(VORBISFILE_LIBS) libgstvorbis_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -noinst_HEADERS = vorbisenc.h vorbisdec.h +noinst_HEADERS = vorbisenc.h vorbisdec.h oggvorbisenc.h diff --git a/ext/vorbis/README b/ext/vorbis/README new file mode 100644 index 0000000000..6b3151011a --- /dev/null +++ b/ext/vorbis/README @@ -0,0 +1,16 @@ +oggvorbisenc : encodes to vorbis inside an ogg stream. This is not the + GStreamer way of doing things and should be removed for + 0.9. It is still called "vorbisenc" for backward compatibility + reasons. It also takes integer audio as input. +vorbisenc : Encodes to a raw vorbis stream and should be used together + with an ogg muxer such as "oggmux" it is called "rawvorbisenc". + It also takes raw float samples as input. + +TODO for 0.9: + +- remove oggvorbisenc.c and oggvorbisenc.h +- remove references to oggvorbisenc.[ch] in the Makefile and in vorbis.c +- remove the element vorbisenc. +- rename the element rawvorbisenc to vorbisenc. + + diff --git a/ext/vorbis/oggvorbisenc.c b/ext/vorbis/oggvorbisenc.c new file mode 100644 index 0000000000..1e95c13aa9 --- /dev/null +++ b/ext/vorbis/oggvorbisenc.c @@ -0,0 +1,992 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include +#include +#include + +#include +#include +#include "oggvorbisenc.h" + +static GstPadTemplate *gst_oggvorbisenc_src_template, + *gst_oggvorbisenc_sink_template; + +/* elementfactory information */ +GstElementDetails oggvorbisenc_details = { + "Ogg Vorbis encoder", + "Codec/Encoder/Audio", + "Encodes audio in OGG Vorbis format", + "Monty , " "Wim Taymans ", +}; + +/* OggVorbisEnc signals and args */ +enum +{ + /* FILL ME */ + LAST_SIGNAL +}; + +enum +{ + ARG_0, + ARG_MAX_BITRATE, + ARG_BITRATE, + ARG_MIN_BITRATE, + ARG_QUALITY, + ARG_SERIAL, + ARG_MANAGED, + ARG_LAST_MESSAGE, +}; + +static const GstFormat * +gst_oggvorbisenc_get_formats (GstPad * pad) +{ + static const GstFormat src_formats[] = { + GST_FORMAT_BYTES, + GST_FORMAT_TIME, + 0 + }; + static const GstFormat sink_formats[] = { + GST_FORMAT_BYTES, + GST_FORMAT_DEFAULT, + GST_FORMAT_TIME, + 0 + }; + + return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats); +} + +#define MAX_BITRATE_DEFAULT -1 +#define BITRATE_DEFAULT -1 +#define MIN_BITRATE_DEFAULT -1 +#define QUALITY_DEFAULT 0.3 + +static void gst_oggvorbisenc_base_init (gpointer g_class); +static void gst_oggvorbisenc_class_init (OggVorbisEncClass * klass); +static void gst_oggvorbisenc_init (OggVorbisEnc * vorbisenc); + +static void gst_oggvorbisenc_chain (GstPad * pad, GstData * _data); +static gboolean gst_oggvorbisenc_setup (OggVorbisEnc * vorbisenc); + +static void gst_oggvorbisenc_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static void gst_oggvorbisenc_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static GstElementStateReturn gst_oggvorbisenc_change_state (GstElement * + element); + +static GstElementClass *parent_class = NULL; + +/*static guint gst_oggvorbisenc_signals[LAST_SIGNAL] = { 0 }; */ + +GType +oggvorbisenc_get_type (void) +{ + static GType oggvorbisenc_type = 0; + + if (!oggvorbisenc_type) { + static const GTypeInfo oggvorbisenc_info = { + sizeof (OggVorbisEncClass), + gst_oggvorbisenc_base_init, + NULL, + (GClassInitFunc) gst_oggvorbisenc_class_init, + NULL, + NULL, + sizeof (OggVorbisEnc), + 0, + (GInstanceInitFunc) gst_oggvorbisenc_init, + }; + static const GInterfaceInfo tag_setter_info = { + NULL, + NULL, + NULL + }; + + oggvorbisenc_type = + g_type_register_static (GST_TYPE_ELEMENT, "OggVorbisEnc", + &oggvorbisenc_info, 0); + + g_type_add_interface_static (oggvorbisenc_type, GST_TYPE_TAG_SETTER, + &tag_setter_info); + } + return oggvorbisenc_type; +} + +static GstCaps * +vorbis_caps_factory (void) +{ + return gst_caps_new_simple ("application/ogg", NULL); +} + +static GstCaps * +raw_caps_factory (void) +{ + return + gst_caps_new_simple ("audio/x-raw-int", + "endianness", G_TYPE_INT, G_BYTE_ORDER, + "signed", G_TYPE_BOOLEAN, TRUE, + "width", G_TYPE_INT, 16, + "depth", G_TYPE_INT, 16, + "rate", GST_TYPE_INT_RANGE, 11025, 48000, + "channels", GST_TYPE_INT_RANGE, 1, 2, NULL); +} + +static void +gst_oggvorbisenc_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + GstCaps *raw_caps, *vorbis_caps; + + raw_caps = raw_caps_factory (); + vorbis_caps = vorbis_caps_factory (); + + gst_oggvorbisenc_sink_template = gst_pad_template_new ("sink", GST_PAD_SINK, + GST_PAD_ALWAYS, raw_caps); + gst_oggvorbisenc_src_template = gst_pad_template_new ("src", GST_PAD_SRC, + GST_PAD_ALWAYS, vorbis_caps); + gst_element_class_add_pad_template (element_class, + gst_oggvorbisenc_sink_template); + gst_element_class_add_pad_template (element_class, + gst_oggvorbisenc_src_template); + gst_element_class_set_details (element_class, &oggvorbisenc_details); +} + +static void +gst_oggvorbisenc_class_init (OggVorbisEncClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MAX_BITRATE, + g_param_spec_int ("max_bitrate", "Max bitrate", + " Specify a minimum bitrate (in bps). Useful for encoding for a fixed-size channel", + -1, G_MAXINT, MAX_BITRATE_DEFAULT, G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE, + g_param_spec_int ("bitrate", "Bitrate", "Choose a bitrate to encode at. " + "Attempt to encode at a bitrate averaging this. Takes an argument in kbps.", + -1, G_MAXINT, BITRATE_DEFAULT, G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MIN_BITRATE, + g_param_spec_int ("min_bitrate", "Min bitrate", + "Specify a maximum bitrate in bps. Useful for streaming applications.", + -1, G_MAXINT, MIN_BITRATE_DEFAULT, G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QUALITY, + g_param_spec_float ("quality", "Quality", + "Specify quality instead of specifying a particular bitrate.", + 0.0, 1.0, QUALITY_DEFAULT, G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SERIAL, + g_param_spec_int ("serial", "Serial", + "Specify a serial number for the stream. (-1 is random)", -1, + G_MAXINT, -1, G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MANAGED, + g_param_spec_boolean ("managed", "Managed", + "Enable bitrate management engine", FALSE, G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE, + g_param_spec_string ("last-message", "last-message", + "The last status message", NULL, G_PARAM_READABLE)); + + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + + gobject_class->set_property = gst_oggvorbisenc_set_property; + gobject_class->get_property = gst_oggvorbisenc_get_property; + + gstelement_class->change_state = gst_oggvorbisenc_change_state; +} + +static GstPadLinkReturn +gst_oggvorbisenc_sinkconnect (GstPad * pad, const GstCaps * caps) +{ + OggVorbisEnc *vorbisenc; + GstStructure *structure; + + vorbisenc = GST_OGGVORBISENC (gst_pad_get_parent (pad)); + + structure = gst_caps_get_structure (caps, 0); + gst_structure_get_int (structure, "channels", &vorbisenc->channels); + gst_structure_get_int (structure, "rate", &vorbisenc->frequency); + + gst_oggvorbisenc_setup (vorbisenc); + + if (vorbisenc->setup) + return GST_PAD_LINK_OK; + + return GST_PAD_LINK_REFUSED; +} + +static gboolean +gst_oggvorbisenc_convert_src (GstPad * pad, GstFormat src_format, + gint64 src_value, GstFormat * dest_format, gint64 * dest_value) +{ + gboolean res = TRUE; + OggVorbisEnc *vorbisenc; + gint64 avg; + + vorbisenc = GST_OGGVORBISENC (gst_pad_get_parent (pad)); + + if (vorbisenc->samples_in == 0 || + vorbisenc->bytes_out == 0 || vorbisenc->frequency == 0) + return FALSE; + + avg = (vorbisenc->bytes_out * vorbisenc->frequency) / (vorbisenc->samples_in); + + switch (src_format) { + case GST_FORMAT_BYTES: + switch (*dest_format) { + case GST_FORMAT_TIME: + *dest_value = src_value * GST_SECOND / avg; + break; + default: + res = FALSE; + } + break; + case GST_FORMAT_TIME: + switch (*dest_format) { + case GST_FORMAT_BYTES: + *dest_value = src_value * avg / GST_SECOND; + break; + default: + res = FALSE; + } + break; + default: + res = FALSE; + } + return res; +} + +static gboolean +gst_oggvorbisenc_convert_sink (GstPad * pad, GstFormat src_format, + gint64 src_value, GstFormat * dest_format, gint64 * dest_value) +{ + gboolean res = TRUE; + guint scale = 1; + gint bytes_per_sample; + OggVorbisEnc *vorbisenc; + + vorbisenc = GST_OGGVORBISENC (gst_pad_get_parent (pad)); + + bytes_per_sample = vorbisenc->channels * 2; + + switch (src_format) { + case GST_FORMAT_BYTES: + switch (*dest_format) { + case GST_FORMAT_DEFAULT: + if (bytes_per_sample == 0) + return FALSE; + *dest_value = src_value / bytes_per_sample; + break; + case GST_FORMAT_TIME: + { + gint byterate = bytes_per_sample * vorbisenc->frequency; + + if (byterate == 0) + return FALSE; + *dest_value = src_value * GST_SECOND / byterate; + break; + } + default: + res = FALSE; + } + break; + case GST_FORMAT_DEFAULT: + switch (*dest_format) { + case GST_FORMAT_BYTES: + *dest_value = src_value * bytes_per_sample; + break; + case GST_FORMAT_TIME: + if (vorbisenc->frequency == 0) + return FALSE; + *dest_value = src_value * GST_SECOND / vorbisenc->frequency; + break; + default: + res = FALSE; + } + break; + case GST_FORMAT_TIME: + switch (*dest_format) { + case GST_FORMAT_BYTES: + scale = bytes_per_sample; + /* fallthrough */ + case GST_FORMAT_DEFAULT: + *dest_value = src_value * scale * vorbisenc->frequency / GST_SECOND; + break; + default: + res = FALSE; + } + break; + default: + res = FALSE; + } + return res; +} + +static const GstQueryType * +gst_oggvorbisenc_get_query_types (GstPad * pad) +{ + static const GstQueryType gst_oggvorbisenc_src_query_types[] = { + GST_QUERY_TOTAL, + GST_QUERY_POSITION, + 0 + }; + + return gst_oggvorbisenc_src_query_types; +} + +static gboolean +gst_oggvorbisenc_src_query (GstPad * pad, GstQueryType type, + GstFormat * format, gint64 * value) +{ + gboolean res = TRUE; + OggVorbisEnc *vorbisenc; + + vorbisenc = GST_OGGVORBISENC (gst_pad_get_parent (pad)); + + switch (type) { + case GST_QUERY_TOTAL: + { + switch (*format) { + case GST_FORMAT_BYTES: + case GST_FORMAT_TIME: + { + gint64 peer_value; + const GstFormat *peer_formats; + + res = FALSE; + + peer_formats = + gst_pad_get_formats (GST_PAD_PEER (vorbisenc->sinkpad)); + + while (peer_formats && *peer_formats && !res) { + + GstFormat peer_format = *peer_formats; + + /* do the probe */ + if (gst_pad_query (GST_PAD_PEER (vorbisenc->sinkpad), + GST_QUERY_TOTAL, &peer_format, &peer_value)) { + GstFormat conv_format; + + /* convert to TIME */ + conv_format = GST_FORMAT_TIME; + res = gst_pad_convert (vorbisenc->sinkpad, + peer_format, peer_value, &conv_format, value); + /* and to final format */ + res &= gst_pad_convert (pad, + GST_FORMAT_TIME, *value, format, value); + } + peer_formats++; + } + break; + } + default: + res = FALSE; + break; + } + break; + } + case GST_QUERY_POSITION: + switch (*format) { + default: + { + /* we only know about our samples, convert to requested format */ + res = gst_pad_convert (pad, + GST_FORMAT_BYTES, vorbisenc->bytes_out, format, value); + break; + } + } + break; + default: + res = FALSE; + break; + } + return res; +} + +static void +gst_oggvorbisenc_init (OggVorbisEnc * vorbisenc) +{ + vorbisenc->sinkpad = + gst_pad_new_from_template (gst_oggvorbisenc_sink_template, "sink"); + gst_element_add_pad (GST_ELEMENT (vorbisenc), vorbisenc->sinkpad); + gst_pad_set_chain_function (vorbisenc->sinkpad, gst_oggvorbisenc_chain); + gst_pad_set_link_function (vorbisenc->sinkpad, gst_oggvorbisenc_sinkconnect); + gst_pad_set_convert_function (vorbisenc->sinkpad, + GST_DEBUG_FUNCPTR (gst_oggvorbisenc_convert_sink)); + gst_pad_set_formats_function (vorbisenc->sinkpad, + GST_DEBUG_FUNCPTR (gst_oggvorbisenc_get_formats)); + + vorbisenc->srcpad = + gst_pad_new_from_template (gst_oggvorbisenc_src_template, "src"); + gst_pad_set_query_function (vorbisenc->srcpad, + GST_DEBUG_FUNCPTR (gst_oggvorbisenc_src_query)); + gst_pad_set_query_type_function (vorbisenc->srcpad, + GST_DEBUG_FUNCPTR (gst_oggvorbisenc_get_query_types)); + gst_pad_set_convert_function (vorbisenc->srcpad, + GST_DEBUG_FUNCPTR (gst_oggvorbisenc_convert_src)); + gst_pad_set_formats_function (vorbisenc->srcpad, + GST_DEBUG_FUNCPTR (gst_oggvorbisenc_get_formats)); + gst_element_add_pad (GST_ELEMENT (vorbisenc), vorbisenc->srcpad); + + vorbisenc->channels = -1; + vorbisenc->frequency = -1; + + vorbisenc->managed = FALSE; + vorbisenc->max_bitrate = MAX_BITRATE_DEFAULT; + vorbisenc->bitrate = BITRATE_DEFAULT; + vorbisenc->min_bitrate = MIN_BITRATE_DEFAULT; + vorbisenc->quality = QUALITY_DEFAULT; + vorbisenc->quality_set = FALSE; + vorbisenc->serial = -1; + vorbisenc->last_message = NULL; + + vorbisenc->setup = FALSE; + vorbisenc->eos = FALSE; + vorbisenc->header_sent = FALSE; + + vorbisenc->tags = gst_tag_list_new (); + + /* we're chained and we can deal with events */ + GST_FLAG_SET (vorbisenc, GST_ELEMENT_EVENT_AWARE); +} + + +static gchar * +gst_oggvorbisenc_get_tag_value (const GstTagList * list, const gchar * tag, + int index) +{ + gchar *vorbisvalue = NULL; + + if (tag == NULL) { + return NULL; + } + + /* get tag name right */ + if ((strcmp (tag, GST_TAG_TRACK_NUMBER) == 0) + || (strcmp (tag, GST_TAG_ALBUM_VOLUME_NUMBER) == 0) + || (strcmp (tag, GST_TAG_TRACK_COUNT) == 0) + || (strcmp (tag, GST_TAG_ALBUM_VOLUME_COUNT) == 0)) { + guint track_no; + + g_assert (gst_tag_list_get_uint_index (list, tag, index, &track_no)); + vorbisvalue = g_strdup_printf ("%u", track_no); + } else if (strcmp (tag, GST_TAG_DATE) == 0) { + /* FIXME: how are dates represented in vorbis files? */ + GDate *date; + guint u; + + g_assert (gst_tag_list_get_uint_index (list, tag, index, &u)); + date = g_date_new_julian (u); + vorbisvalue = + g_strdup_printf ("%04d-%02d-%02d", (gint) g_date_get_year (date), + (gint) g_date_get_month (date), (gint) g_date_get_day (date)); + g_date_free (date); + } else if (gst_tag_get_type (tag) == G_TYPE_STRING) { + g_assert (gst_tag_list_get_string_index (list, tag, index, &vorbisvalue)); + } + + return vorbisvalue; +} + +static void +gst_oggvorbisenc_metadata_set1 (const GstTagList * list, const gchar * tag, + gpointer vorbisenc) +{ + const gchar *vorbistag = NULL; + gchar *vorbisvalue = NULL; + guint i, count; + OggVorbisEnc *enc = GST_OGGVORBISENC (vorbisenc); + + vorbistag = gst_tag_to_vorbis_tag (tag); + if (vorbistag == NULL) { + return; + } + + count = gst_tag_list_get_tag_size (list, tag); + for (i = 0; i < count; i++) { + vorbisvalue = gst_oggvorbisenc_get_tag_value (list, tag, i); + + if (vorbisvalue != NULL) { + vorbis_comment_add_tag (&enc->vc, g_strdup (vorbistag), vorbisvalue); + } + } +} + +static void +gst_oggvorbisenc_set_metadata (OggVorbisEnc * vorbisenc) +{ + GstTagList *copy; + const GstTagList *user_tags; + + user_tags = gst_tag_setter_get_list (GST_TAG_SETTER (vorbisenc)); + if (!(vorbisenc->tags || user_tags)) + return; + + copy = + gst_tag_list_merge (user_tags, vorbisenc->tags, + gst_tag_setter_get_merge_mode (GST_TAG_SETTER (vorbisenc))); + vorbis_comment_init (&vorbisenc->vc); + gst_tag_list_foreach (copy, gst_oggvorbisenc_metadata_set1, vorbisenc); + gst_tag_list_free (copy); +} + +static gchar * +get_constraints_string (OggVorbisEnc * vorbisenc) +{ + gint min = vorbisenc->min_bitrate; + gint max = vorbisenc->max_bitrate; + gchar *result; + + if (min > 0 && max > 0) + result = g_strdup_printf ("(min %d bps, max %d bps)", min, max); + else if (min > 0) + result = g_strdup_printf ("(min %d bps, no max)", min); + else if (max > 0) + result = g_strdup_printf ("(no min, max %d bps)", max); + else + result = g_strdup_printf ("(no min or max)"); + + return result; +} + +static void +update_start_message (OggVorbisEnc * vorbisenc) +{ + gchar *constraints; + + g_free (vorbisenc->last_message); + + if (vorbisenc->bitrate > 0) { + if (vorbisenc->managed) { + constraints = get_constraints_string (vorbisenc); + vorbisenc->last_message = + g_strdup_printf ("encoding at average bitrate %d bps %s", + vorbisenc->bitrate, constraints); + g_free (constraints); + } else { + vorbisenc->last_message = + g_strdup_printf + ("encoding at approximate bitrate %d bps (VBR encoding enabled)", + vorbisenc->bitrate); + } + } else { + if (vorbisenc->quality_set) { + if (vorbisenc->managed) { + constraints = get_constraints_string (vorbisenc); + vorbisenc->last_message = + g_strdup_printf + ("encoding at quality level %2.2f using constrained VBR %s", + vorbisenc->quality, constraints); + g_free (constraints); + } else { + vorbisenc->last_message = + g_strdup_printf ("encoding at quality level %2.2f", + vorbisenc->quality); + } + } else { + constraints = get_constraints_string (vorbisenc); + vorbisenc->last_message = + g_strdup_printf ("encoding using bitrate management %s", constraints); + g_free (constraints); + } + } + + g_object_notify (G_OBJECT (vorbisenc), "last_message"); +} + +static gboolean +gst_oggvorbisenc_setup (OggVorbisEnc * vorbisenc) +{ + gint serial; + + if (vorbisenc->bitrate < 0 && vorbisenc->min_bitrate < 0 + && vorbisenc->max_bitrate < 0) { + vorbisenc->quality_set = TRUE; + } + + update_start_message (vorbisenc); + + /* choose an encoding mode */ + /* (mode 0: 44kHz stereo uncoupled, roughly 128kbps VBR) */ + vorbis_info_init (&vorbisenc->vi); + + if (vorbisenc->quality_set) { + if (vorbis_encode_setup_vbr (&vorbisenc->vi, + vorbisenc->channels, vorbisenc->frequency, vorbisenc->quality)) { + g_warning + ("vorbisenc: initialisation failed: invalid parameters for quality"); + vorbis_info_clear (&vorbisenc->vi); + return FALSE; + } + + /* do we have optional hard quality restrictions? */ + if (vorbisenc->max_bitrate > 0 || vorbisenc->min_bitrate > 0) { + struct ovectl_ratemanage_arg ai; + + vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_GET, &ai); + + /* the bitrates are in kHz */ + ai.bitrate_hard_min = vorbisenc->min_bitrate / 1000; + ai.bitrate_hard_max = vorbisenc->max_bitrate / 1000; + ai.management_active = 1; + + vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_SET, &ai); + } + } else { + if (vorbis_encode_setup_managed (&vorbisenc->vi, + vorbisenc->channels, + vorbisenc->frequency, + vorbisenc->max_bitrate > 0 ? vorbisenc->max_bitrate : -1, + vorbisenc->bitrate, + vorbisenc->min_bitrate > 0 ? vorbisenc->min_bitrate : -1)) { + g_warning + ("vorbisenc: initialisation failed: invalid parameters for bitrate\n"); + vorbis_info_clear (&vorbisenc->vi); + return FALSE; + } + } + + if (vorbisenc->managed && vorbisenc->bitrate < 0) { + vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_AVG, NULL); + } else if (!vorbisenc->managed) { + /* Turn off management entirely (if it was turned on). */ + vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_SET, NULL); + } + vorbis_encode_setup_init (&vorbisenc->vi); + + /* set up the analysis state and auxiliary encoding storage */ + vorbis_analysis_init (&vorbisenc->vd, &vorbisenc->vi); + vorbis_block_init (&vorbisenc->vd, &vorbisenc->vb); + + /* set up our packet->stream encoder */ + /* pick a random serial number; that way we can more likely build + chained streams just by concatenation */ + if (vorbisenc->serial < 0) { + srand (time (NULL)); + serial = rand (); + } else { + serial = vorbisenc->serial; + } + + ogg_stream_init (&vorbisenc->os, serial); + + vorbisenc->setup = TRUE; + + return TRUE; +} + +static void +gst_oggvorbisenc_write_page (OggVorbisEnc * vorbisenc, ogg_page * page) +{ + GstBuffer *outbuf; + + outbuf = gst_buffer_new_and_alloc (page->header_len + page->body_len); + + memcpy (GST_BUFFER_DATA (outbuf), page->header, page->header_len); + memcpy (GST_BUFFER_DATA (outbuf) + page->header_len, + page->body, page->body_len); + + GST_DEBUG ("vorbisenc: encoded buffer of %d bytes", GST_BUFFER_SIZE (outbuf)); + + vorbisenc->bytes_out += GST_BUFFER_SIZE (outbuf); + + if (GST_PAD_IS_USABLE (vorbisenc->srcpad)) { + gst_pad_push (vorbisenc->srcpad, GST_DATA (outbuf)); + } else { + gst_buffer_unref (outbuf); + } +} + +static void +gst_oggvorbisenc_chain (GstPad * pad, GstData * _data) +{ + GstBuffer *buf = GST_BUFFER (_data); + OggVorbisEnc *vorbisenc; + + g_return_if_fail (pad != NULL); + g_return_if_fail (GST_IS_PAD (pad)); + g_return_if_fail (buf != NULL); + + vorbisenc = GST_OGGVORBISENC (gst_pad_get_parent (pad)); + + if (GST_IS_EVENT (buf)) { + GstEvent *event = GST_EVENT (buf); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_EOS: + /* end of file. this can be done implicitly in the mainline, + but it's easier to see here in non-clever fashion. + Tell the library we're at end of stream so that it can handle + the last frame and mark end of stream in the output properly */ + vorbis_analysis_wrote (&vorbisenc->vd, 0); + gst_event_unref (event); + break; + case GST_EVENT_TAG: + if (vorbisenc->tags) { + gst_tag_list_insert (vorbisenc->tags, gst_event_tag_get_list (event), + gst_tag_setter_get_merge_mode (GST_TAG_SETTER (vorbisenc))); + } else { + g_assert_not_reached (); + } + gst_pad_event_default (pad, event); + return; + default: + gst_pad_event_default (pad, event); + return; + } + } else { + gint16 *data; + gulong size; + gulong i, j; + float **buffer; + + if (!vorbisenc->setup) { + gst_buffer_unref (buf); + GST_ELEMENT_ERROR (vorbisenc, CORE, NEGOTIATION, (NULL), + ("encoder not initialized (input is not audio?)")); + return; + } + + if (!vorbisenc->header_sent) { + gint result; + + /* Vorbis streams begin with three headers; the initial header (with + most of the codec setup parameters) which is mandated by the Ogg + bitstream spec. The second header holds any comment fields. The + third header holds the bitstream codebook. We merely need to + make the headers, then pass them to libvorbis one at a time; + libvorbis handles the additional Ogg bitstream constraints */ + ogg_packet header; + ogg_packet header_comm; + ogg_packet header_code; + + gst_oggvorbisenc_set_metadata (vorbisenc); + vorbis_analysis_headerout (&vorbisenc->vd, &vorbisenc->vc, &header, + &header_comm, &header_code); + ogg_stream_packetin (&vorbisenc->os, &header); /* automatically placed in its own page */ + ogg_stream_packetin (&vorbisenc->os, &header_comm); + ogg_stream_packetin (&vorbisenc->os, &header_code); + + while ((result = ogg_stream_flush (&vorbisenc->os, &vorbisenc->og))) { + gst_oggvorbisenc_write_page (vorbisenc, &vorbisenc->og); + } + vorbisenc->header_sent = TRUE; + } + + /* data to encode */ + data = (gint16 *) GST_BUFFER_DATA (buf); + size = GST_BUFFER_SIZE (buf) / (vorbisenc->channels * 2); + + /* expose the buffer to submit data */ + buffer = vorbis_analysis_buffer (&vorbisenc->vd, size); + + /* uninterleave samples */ + for (i = 0; i < size; i++) { + for (j = 0; j < vorbisenc->channels; j++) { + buffer[j][i] = data[i * vorbisenc->channels + j] / 32768.f; + } + } + + /* tell the library how much we actually submitted */ + vorbis_analysis_wrote (&vorbisenc->vd, size); + + vorbisenc->samples_in += size; + + gst_buffer_unref (buf); + } + + /* vorbis does some data preanalysis, then divvies up blocks for + more involved (potentially parallel) processing. Get a single + block for encoding now */ + while (vorbis_analysis_blockout (&vorbisenc->vd, &vorbisenc->vb) == 1) { + + /* analysis */ + vorbis_analysis (&vorbisenc->vb, NULL); + vorbis_bitrate_addblock (&vorbisenc->vb); + + while (vorbis_bitrate_flushpacket (&vorbisenc->vd, &vorbisenc->op)) { + + /* weld the packet into the bitstream */ + ogg_stream_packetin (&vorbisenc->os, &vorbisenc->op); + + /* write out pages (if any) */ + while (!vorbisenc->eos) { + int result = ogg_stream_pageout (&vorbisenc->os, &vorbisenc->og); + + if (result == 0) + break; + + gst_oggvorbisenc_write_page (vorbisenc, &vorbisenc->og); + + /* this could be set above, but for illustrative purposes, I do + it here (to show that vorbis does know where the stream ends) */ + if (ogg_page_eos (&vorbisenc->og)) { + vorbisenc->eos = 1; + } + } + } + } + + if (vorbisenc->eos) { + /* clean up and exit. vorbis_info_clear() must be called last */ + ogg_stream_clear (&vorbisenc->os); + vorbis_block_clear (&vorbisenc->vb); + vorbis_dsp_clear (&vorbisenc->vd); + vorbis_info_clear (&vorbisenc->vi); + gst_pad_push (vorbisenc->srcpad, GST_DATA (gst_event_new (GST_EVENT_EOS))); + gst_element_set_eos (GST_ELEMENT (vorbisenc)); + } +} + +static void +gst_oggvorbisenc_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + OggVorbisEnc *vorbisenc; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail (GST_IS_OGGVORBISENC (object)); + + vorbisenc = GST_OGGVORBISENC (object); + + switch (prop_id) { + case ARG_MAX_BITRATE: + g_value_set_int (value, vorbisenc->max_bitrate); + break; + case ARG_BITRATE: + g_value_set_int (value, vorbisenc->bitrate); + break; + case ARG_MIN_BITRATE: + g_value_set_int (value, vorbisenc->min_bitrate); + break; + case ARG_QUALITY: + g_value_set_float (value, vorbisenc->quality); + break; + case ARG_SERIAL: + g_value_set_int (value, vorbisenc->serial); + break; + case ARG_MANAGED: + g_value_set_boolean (value, vorbisenc->managed); + break; + case ARG_LAST_MESSAGE: + g_value_set_string (value, vorbisenc->last_message); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_oggvorbisenc_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + OggVorbisEnc *vorbisenc; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail (GST_IS_OGGVORBISENC (object)); + + vorbisenc = GST_OGGVORBISENC (object); + + switch (prop_id) { + case ARG_MAX_BITRATE: + { + gboolean old_value = vorbisenc->managed; + + vorbisenc->max_bitrate = g_value_get_int (value); + if (vorbisenc->min_bitrate > 0 && vorbisenc->max_bitrate > 0) + vorbisenc->managed = TRUE; + else + vorbisenc->managed = FALSE; + + if (old_value != vorbisenc->managed) + g_object_notify (object, "managed"); + break; + } + case ARG_BITRATE: + vorbisenc->bitrate = g_value_get_int (value); + break; + case ARG_MIN_BITRATE: + { + gboolean old_value = vorbisenc->managed; + + vorbisenc->min_bitrate = g_value_get_int (value); + if (vorbisenc->min_bitrate > 0 && vorbisenc->max_bitrate > 0) + vorbisenc->managed = TRUE; + else + vorbisenc->managed = FALSE; + + if (old_value != vorbisenc->managed) + g_object_notify (object, "managed"); + break; + } + case ARG_QUALITY: + vorbisenc->quality = g_value_get_float (value); + if (vorbisenc->quality >= 0.0) + vorbisenc->quality_set = TRUE; + else + vorbisenc->quality_set = FALSE; + break; + case ARG_SERIAL: + vorbisenc->serial = g_value_get_int (value); + break; + case ARG_MANAGED: + vorbisenc->managed = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstElementStateReturn +gst_oggvorbisenc_change_state (GstElement * element) +{ + OggVorbisEnc *vorbisenc = GST_OGGVORBISENC (element); + + switch (GST_STATE_TRANSITION (element)) { + case GST_STATE_NULL_TO_READY: + case GST_STATE_READY_TO_PAUSED: + vorbisenc->eos = FALSE; + break; + case GST_STATE_PAUSED_TO_PLAYING: + case GST_STATE_PLAYING_TO_PAUSED: + break; + case GST_STATE_PAUSED_TO_READY: + vorbisenc->setup = FALSE; + vorbisenc->header_sent = FALSE; + gst_tag_list_free (vorbisenc->tags); + vorbisenc->tags = gst_tag_list_new (); + break; + case GST_STATE_READY_TO_NULL: + default: + break; + } + + if (GST_ELEMENT_CLASS (parent_class)->change_state) + return GST_ELEMENT_CLASS (parent_class)->change_state (element); + + return GST_STATE_SUCCESS; +} diff --git a/ext/vorbis/oggvorbisenc.h b/ext/vorbis/oggvorbisenc.h new file mode 100644 index 0000000000..850fafad7d --- /dev/null +++ b/ext/vorbis/oggvorbisenc.h @@ -0,0 +1,100 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef __OGGVORBISENC_H__ +#define __OGGVORBISENC_H__ + + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define GST_TYPE_OGGVORBISENC \ + (oggvorbisenc_get_type()) +#define GST_OGGVORBISENC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OGGVORBISENC,OggVorbisEnc)) +#define GST_OGGVORBISENC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OGGVORBISENC,OggVorbisEncClass)) +#define GST_IS_OGGVORBISENC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OGGVORBISENC)) +#define GST_IS_OGGVORBISENC_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OGGVORBISENC)) + +typedef struct _OggVorbisEnc OggVorbisEnc; +typedef struct _OggVorbisEncClass OggVorbisEncClass; + +struct _OggVorbisEnc { + GstElement element; + + GstPad *sinkpad, + *srcpad; + + ogg_stream_state os; /* take physical pages, weld into a logical + stream of packets */ + ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */ + ogg_packet op; /* one raw packet of data for decode */ + + vorbis_info vi; /* struct that stores all the static vorbis bitstream + settings */ + vorbis_comment vc; /* struct that stores all the user comments */ + + vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */ + vorbis_block vb; /* local working space for packet->PCM decode */ + + gboolean eos; + + gboolean managed; + gint bitrate; + gint min_bitrate; + gint max_bitrate; + gfloat quality; + gboolean quality_set; + gint serial; + + gint channels; + gint frequency; + + guint64 samples_in; + guint64 bytes_out; + + GstTagList * tags; + + gboolean setup; + gboolean header_sent; + gchar *last_message; +}; + +struct _OggVorbisEncClass { + GstElementClass parent_class; +}; + +GType oggvorbisenc_get_type(void); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __OGGVORBISENC_H__ */ diff --git a/ext/vorbis/vorbis.c b/ext/vorbis/vorbis.c index 2369d26f27..237d6dd3a9 100644 --- a/ext/vorbis/vorbis.c +++ b/ext/vorbis/vorbis.c @@ -22,6 +22,7 @@ #endif #include "vorbisenc.h" +#include "oggvorbisenc.h" #include "vorbisdec.h" GST_DEBUG_CATEGORY (vorbisdec_debug); @@ -36,6 +37,10 @@ plugin_init (GstPlugin * plugin) return FALSE; if (!gst_element_register (plugin, "vorbisenc", GST_RANK_NONE, + GST_TYPE_OGGVORBISENC)) + return FALSE; + + if (!gst_element_register (plugin, "rawvorbisenc", GST_RANK_NONE, GST_TYPE_VORBISENC)) return FALSE; diff --git a/ext/vorbis/vorbisenc.c b/ext/vorbis/vorbisenc.c index 50cafb599c..5239f69759 100644 --- a/ext/vorbis/vorbisenc.c +++ b/ext/vorbis/vorbisenc.c @@ -37,7 +37,7 @@ GstElementDetails vorbisenc_details = { "Ogg Vorbis encoder", "Codec/Encoder/Audio", "Encodes audio in OGG Vorbis format", - "Monty , " "Wim Taymans ", + "Monty , " "Wim Taymans ", }; /* VorbisEnc signals and args */ @@ -54,7 +54,6 @@ enum ARG_BITRATE, ARG_MIN_BITRATE, ARG_QUALITY, - ARG_SERIAL, ARG_MANAGED, ARG_LAST_MESSAGE, }; @@ -135,18 +134,16 @@ vorbisenc_get_type (void) static GstCaps * vorbis_caps_factory (void) { - return gst_caps_new_simple ("application/ogg", NULL); + return gst_caps_new_simple ("audio/x-vorbis", NULL); } static GstCaps * raw_caps_factory (void) { return - gst_caps_new_simple ("audio/x-raw-int", + gst_caps_new_simple ("audio/x-raw-float", "endianness", G_TYPE_INT, G_BYTE_ORDER, - "signed", G_TYPE_BOOLEAN, TRUE, - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, + "width", G_TYPE_INT, 32, "rate", GST_TYPE_INT_RANGE, 11025, 48000, "channels", GST_TYPE_INT_RANGE, 1, 2, NULL); } @@ -196,10 +193,6 @@ gst_vorbisenc_class_init (VorbisEncClass * klass) g_param_spec_float ("quality", "Quality", "Specify quality instead of specifying a particular bitrate.", 0.0, 1.0, QUALITY_DEFAULT, G_PARAM_READWRITE)); - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SERIAL, - g_param_spec_int ("serial", "Serial", - "Specify a serial number for the stream. (-1 is random)", -1, - G_MAXINT, -1, G_PARAM_READWRITE)); g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MANAGED, g_param_spec_boolean ("managed", "Managed", "Enable bitrate management engine", FALSE, G_PARAM_READWRITE)); @@ -457,7 +450,6 @@ gst_vorbisenc_init (VorbisEnc * vorbisenc) vorbisenc->min_bitrate = MIN_BITRATE_DEFAULT; vorbisenc->quality = QUALITY_DEFAULT; vorbisenc->quality_set = FALSE; - vorbisenc->serial = -1; vorbisenc->last_message = NULL; vorbisenc->setup = FALSE; @@ -617,8 +609,6 @@ update_start_message (VorbisEnc * vorbisenc) static gboolean gst_vorbisenc_setup (VorbisEnc * vorbisenc) { - gint serial; - if (vorbisenc->bitrate < 0 && vorbisenc->min_bitrate < 0 && vorbisenc->max_bitrate < 0) { vorbisenc->quality_set = TRUE; @@ -678,33 +668,22 @@ gst_vorbisenc_setup (VorbisEnc * vorbisenc) vorbis_analysis_init (&vorbisenc->vd, &vorbisenc->vi); vorbis_block_init (&vorbisenc->vd, &vorbisenc->vb); - /* set up our packet->stream encoder */ - /* pick a random serial number; that way we can more likely build - chained streams just by concatenation */ - if (vorbisenc->serial < 0) { - srand (time (NULL)); - serial = rand (); - } else { - serial = vorbisenc->serial; - } - - ogg_stream_init (&vorbisenc->os, serial); - vorbisenc->setup = TRUE; return TRUE; } static void -gst_vorbisenc_write_page (VorbisEnc * vorbisenc, ogg_page * page) +gst_vorbisenc_push_packet (VorbisEnc * vorbisenc, ogg_packet * packet) { GstBuffer *outbuf; - outbuf = gst_buffer_new_and_alloc (page->header_len + page->body_len); - - memcpy (GST_BUFFER_DATA (outbuf), page->header, page->header_len); - memcpy (GST_BUFFER_DATA (outbuf) + page->header_len, - page->body, page->body_len); + outbuf = gst_buffer_new_and_alloc (packet->bytes); + memcpy (GST_BUFFER_DATA (outbuf), packet->packet, packet->bytes); + GST_BUFFER_OFFSET (outbuf) = vorbisenc->bytes_out; + GST_BUFFER_OFFSET_END (outbuf) = packet->granulepos; + GST_BUFFER_TIMESTAMP (outbuf) = + vorbis_granule_time (&vorbisenc->vd, packet->granulepos) * GST_SECOND; GST_DEBUG ("vorbisenc: encoded buffer of %d bytes", GST_BUFFER_SIZE (outbuf)); @@ -739,6 +718,7 @@ gst_vorbisenc_chain (GstPad * pad, GstData * _data) Tell the library we're at end of stream so that it can handle the last frame and mark end of stream in the output properly */ vorbis_analysis_wrote (&vorbisenc->vd, 0); + vorbisenc->eos = TRUE; gst_event_unref (event); break; case GST_EVENT_TAG: @@ -755,7 +735,7 @@ gst_vorbisenc_chain (GstPad * pad, GstData * _data) return; } } else { - gint16 *data; + gfloat *data; gulong size; gulong i, j; float **buffer; @@ -768,7 +748,7 @@ gst_vorbisenc_chain (GstPad * pad, GstData * _data) } if (!vorbisenc->header_sent) { - gint result; + //gint result; /* Vorbis streams begin with three headers; the initial header (with most of the codec setup parameters) which is mandated by the Ogg @@ -783,19 +763,16 @@ gst_vorbisenc_chain (GstPad * pad, GstData * _data) gst_vorbisenc_set_metadata (vorbisenc); vorbis_analysis_headerout (&vorbisenc->vd, &vorbisenc->vc, &header, &header_comm, &header_code); - ogg_stream_packetin (&vorbisenc->os, &header); /* automatically placed in its own page */ - ogg_stream_packetin (&vorbisenc->os, &header_comm); - ogg_stream_packetin (&vorbisenc->os, &header_code); + gst_vorbisenc_push_packet (vorbisenc, &header); + gst_vorbisenc_push_packet (vorbisenc, &header_comm); + gst_vorbisenc_push_packet (vorbisenc, &header_code); - while ((result = ogg_stream_flush (&vorbisenc->os, &vorbisenc->og))) { - gst_vorbisenc_write_page (vorbisenc, &vorbisenc->og); - } vorbisenc->header_sent = TRUE; } /* data to encode */ - data = (gint16 *) GST_BUFFER_DATA (buf); - size = GST_BUFFER_SIZE (buf) / (vorbisenc->channels * 2); + data = (gfloat *) GST_BUFFER_DATA (buf); + size = GST_BUFFER_SIZE (buf) / (vorbisenc->channels * sizeof (float)); /* expose the buffer to submit data */ buffer = vorbis_analysis_buffer (&vorbisenc->vd, size); @@ -803,7 +780,7 @@ gst_vorbisenc_chain (GstPad * pad, GstData * _data) /* uninterleave samples */ for (i = 0; i < size; i++) { for (j = 0; j < vorbisenc->channels; j++) { - buffer[j][i] = data[i * vorbisenc->channels + j] / 32768.f; + buffer[j][i] = *data++; } } @@ -815,41 +792,23 @@ gst_vorbisenc_chain (GstPad * pad, GstData * _data) gst_buffer_unref (buf); } - /* vorbis does some data preanalysis, then divvies up blocks for + /* vorbis does some data preanalysis, then divides up blocks for more involved (potentially parallel) processing. Get a single block for encoding now */ while (vorbis_analysis_blockout (&vorbisenc->vd, &vorbisenc->vb) == 1) { + ogg_packet op; /* analysis */ vorbis_analysis (&vorbisenc->vb, NULL); vorbis_bitrate_addblock (&vorbisenc->vb); - while (vorbis_bitrate_flushpacket (&vorbisenc->vd, &vorbisenc->op)) { - - /* weld the packet into the bitstream */ - ogg_stream_packetin (&vorbisenc->os, &vorbisenc->op); - - /* write out pages (if any) */ - while (!vorbisenc->eos) { - int result = ogg_stream_pageout (&vorbisenc->os, &vorbisenc->og); - - if (result == 0) - break; - - gst_vorbisenc_write_page (vorbisenc, &vorbisenc->og); - - /* this could be set above, but for illustrative purposes, I do - it here (to show that vorbis does know where the stream ends) */ - if (ogg_page_eos (&vorbisenc->og)) { - vorbisenc->eos = 1; - } - } + while (vorbis_bitrate_flushpacket (&vorbisenc->vd, &op)) { + gst_vorbisenc_push_packet (vorbisenc, &op); } } if (vorbisenc->eos) { /* clean up and exit. vorbis_info_clear() must be called last */ - ogg_stream_clear (&vorbisenc->os); vorbis_block_clear (&vorbisenc->vb); vorbis_dsp_clear (&vorbisenc->vd); vorbis_info_clear (&vorbisenc->vi); @@ -882,9 +841,6 @@ gst_vorbisenc_get_property (GObject * object, guint prop_id, GValue * value, case ARG_QUALITY: g_value_set_float (value, vorbisenc->quality); break; - case ARG_SERIAL: - g_value_set_int (value, vorbisenc->serial); - break; case ARG_MANAGED: g_value_set_boolean (value, vorbisenc->managed); break; @@ -947,9 +903,6 @@ gst_vorbisenc_set_property (GObject * object, guint prop_id, else vorbisenc->quality_set = FALSE; break; - case ARG_SERIAL: - vorbisenc->serial = g_value_get_int (value); - break; case ARG_MANAGED: vorbisenc->managed = g_value_get_boolean (value); break; diff --git a/ext/vorbis/vorbisenc.h b/ext/vorbis/vorbisenc.h index 72932c7567..c81b14261a 100644 --- a/ext/vorbis/vorbisenc.h +++ b/ext/vorbis/vorbisenc.h @@ -50,11 +50,6 @@ struct _VorbisEnc { GstPad *sinkpad, *srcpad; - ogg_stream_state os; /* take physical pages, weld into a logical - stream of packets */ - ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */ - ogg_packet op; /* one raw packet of data for decode */ - vorbis_info vi; /* struct that stores all the static vorbis bitstream settings */ vorbis_comment vc; /* struct that stores all the user comments */ @@ -70,7 +65,6 @@ struct _VorbisEnc { gint max_bitrate; gfloat quality; gboolean quality_set; - gint serial; gint channels; gint frequency;