2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * SECTION:element-vorbisenc
22 * @see_also: vorbisdec, oggmux
24 * This element encodes raw float audio into a Vorbis stream.
25 * <ulink url="http://www.vorbis.com/">Vorbis</ulink> is a royalty-free
26 * audio codec maintained by the <ulink url="http://www.xiph.org/">Xiph.org
30 * <title>Example pipelines</title>
32 * gst-launch -v audiotestsrc wave=sine num-buffers=100 ! audioconvert ! vorbisenc ! oggmux ! filesink location=sine.ogg
33 * ]| Encode a test sine signal to Ogg/Vorbis. Note that the resulting file
34 * will be really small because a sine signal compresses very well.
36 * gst-launch -v alsasrc ! audioconvert ! vorbisenc ! oggmux ! filesink location=alsasrc.ogg
37 * ]| Record from a sound card using ALSA and encode to Ogg/Vorbis.
40 * Last reviewed on 2006-03-01 (0.10.4)
49 #include <vorbis/vorbisenc.h>
51 #include <gst/gsttagsetter.h>
52 #include <gst/tag/tag.h>
53 #include <gst/audio/multichannel.h>
54 #include <gst/audio/audio.h>
55 #include "gstvorbisenc.h"
57 GST_DEBUG_CATEGORY_EXTERN (vorbisenc_debug);
58 #define GST_CAT_DEFAULT vorbisenc_debug
60 static GstStaticPadTemplate vorbis_enc_sink_factory =
61 GST_STATIC_PAD_TEMPLATE ("sink",
64 GST_STATIC_CAPS ("audio/x-raw-float, "
65 "rate = (int) [ 1, 200000 ], "
66 "channels = (int) [ 1, 256 ], " "endianness = (int) BYTE_ORDER, "
70 static GstStaticPadTemplate vorbis_enc_src_factory =
71 GST_STATIC_PAD_TEMPLATE ("src",
74 GST_STATIC_CAPS ("audio/x-vorbis")
78 /* elementfactory information */
79 static const GstElementDetails vorbisenc_details =
80 GST_ELEMENT_DETAILS ("Vorbis audio encoder",
81 "Codec/Encoder/Audio",
82 "Encodes audio in Vorbis format",
83 "Monty <monty@xiph.org>, " "Wim Taymans <wim@fluendo.com>");
96 static GstFlowReturn gst_vorbis_enc_output_buffers (GstVorbisEnc * vorbisenc);
98 /* this function takes into account the granulepos_offset and the subgranule
101 granulepos_to_timestamp_offset (GstVorbisEnc * vorbisenc,
102 ogg_int64_t granulepos)
105 return gst_util_uint64_scale ((guint64) granulepos
106 + vorbisenc->granulepos_offset, GST_SECOND, vorbisenc->frequency)
107 + vorbisenc->subgranule_offset;
108 return GST_CLOCK_TIME_NONE;
111 /* this function does a straight granulepos -> timestamp conversion */
113 granulepos_to_timestamp (GstVorbisEnc * vorbisenc, ogg_int64_t granulepos)
116 return gst_util_uint64_scale ((guint64) granulepos,
117 GST_SECOND, vorbisenc->frequency);
118 return GST_CLOCK_TIME_NONE;
121 #define MAX_BITRATE_DEFAULT -1
122 #define BITRATE_DEFAULT -1
123 #define MIN_BITRATE_DEFAULT -1
124 #define QUALITY_DEFAULT 0.3
125 #define LOWEST_BITRATE 6000 /* lowest allowed for a 8 kHz stream */
126 #define HIGHEST_BITRATE 250001 /* highest allowed for a 44 kHz stream */
128 static gboolean gst_vorbis_enc_sink_event (GstPad * pad, GstEvent * event);
129 static GstFlowReturn gst_vorbis_enc_chain (GstPad * pad, GstBuffer * buffer);
130 static gboolean gst_vorbis_enc_setup (GstVorbisEnc * vorbisenc);
132 static void gst_vorbis_enc_dispose (GObject * object);
133 static void gst_vorbis_enc_get_property (GObject * object, guint prop_id,
134 GValue * value, GParamSpec * pspec);
135 static void gst_vorbis_enc_set_property (GObject * object, guint prop_id,
136 const GValue * value, GParamSpec * pspec);
137 static GstStateChangeReturn gst_vorbis_enc_change_state (GstElement * element,
138 GstStateChange transition);
139 static void gst_vorbis_enc_add_interfaces (GType vorbisenc_type);
141 GST_BOILERPLATE_FULL (GstVorbisEnc, gst_vorbis_enc, GstElement,
142 GST_TYPE_ELEMENT, gst_vorbis_enc_add_interfaces);
145 gst_vorbis_enc_add_interfaces (GType vorbisenc_type)
147 static const GInterfaceInfo tag_setter_info = { NULL, NULL, NULL };
148 static const GInterfaceInfo preset_info = { NULL, NULL, NULL };
150 g_type_add_interface_static (vorbisenc_type, GST_TYPE_TAG_SETTER,
152 g_type_add_interface_static (vorbisenc_type, GST_TYPE_PRESET, &preset_info);
156 gst_vorbis_enc_base_init (gpointer g_class)
158 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
159 GstPadTemplate *src_template, *sink_template;
162 src_template = gst_static_pad_template_get (&vorbis_enc_src_factory);
163 gst_element_class_add_pad_template (element_class, src_template);
165 sink_template = gst_static_pad_template_get (&vorbis_enc_sink_factory);
166 gst_element_class_add_pad_template (element_class, sink_template);
167 gst_element_class_set_details (element_class, &vorbisenc_details);
171 gst_vorbis_enc_class_init (GstVorbisEncClass * klass)
173 GObjectClass *gobject_class;
174 GstElementClass *gstelement_class;
176 gobject_class = (GObjectClass *) klass;
177 gstelement_class = (GstElementClass *) klass;
179 gobject_class->set_property = gst_vorbis_enc_set_property;
180 gobject_class->get_property = gst_vorbis_enc_get_property;
181 gobject_class->dispose = gst_vorbis_enc_dispose;
183 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MAX_BITRATE,
184 g_param_spec_int ("max-bitrate", "Maximum Bitrate",
185 "Specify a maximum bitrate (in bps). Useful for streaming "
186 "applications. (-1 == disabled)",
187 -1, HIGHEST_BITRATE, MAX_BITRATE_DEFAULT,
188 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
189 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE,
190 g_param_spec_int ("bitrate", "Target Bitrate",
191 "Attempt to encode at a bitrate averaging this (in bps). "
192 "This uses the bitrate management engine, and is not recommended for most users. "
193 "Quality is a better alternative. (-1 == disabled)", -1,
194 HIGHEST_BITRATE, BITRATE_DEFAULT,
195 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
196 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MIN_BITRATE,
197 g_param_spec_int ("min-bitrate", "Minimum Bitrate",
198 "Specify a minimum bitrate (in bps). Useful for encoding for a "
199 "fixed-size channel. (-1 == disabled)", -1, HIGHEST_BITRATE,
200 MIN_BITRATE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
201 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QUALITY,
202 g_param_spec_float ("quality", "Quality",
203 "Specify quality instead of specifying a particular bitrate.", -0.1,
204 1.0, QUALITY_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
205 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MANAGED,
206 g_param_spec_boolean ("managed", "Managed",
207 "Enable bitrate management engine", FALSE,
208 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
209 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
210 g_param_spec_string ("last-message", "last-message",
211 "The last status message", NULL,
212 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
214 gstelement_class->change_state =
215 GST_DEBUG_FUNCPTR (gst_vorbis_enc_change_state);
219 gst_vorbis_enc_dispose (GObject * object)
221 GstVorbisEnc *vorbisenc = GST_VORBISENC (object);
223 if (vorbisenc->sinkcaps) {
224 gst_caps_unref (vorbisenc->sinkcaps);
225 vorbisenc->sinkcaps = NULL;
228 G_OBJECT_CLASS (parent_class)->dispose (object);
231 static const GstAudioChannelPosition vorbischannelpositions[][8] = {
233 GST_AUDIO_CHANNEL_POSITION_FRONT_MONO},
235 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
236 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT},
237 { /* Stereo + Centre */
238 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
239 GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
240 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT},
242 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
243 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
244 GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
245 GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
247 { /* Stereo + Centre + rear stereo */
248 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
249 GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
250 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
251 GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
252 GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
254 { /* Full 5.1 Surround */
255 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
256 GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
257 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
258 GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
259 GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
260 GST_AUDIO_CHANNEL_POSITION_LFE,
262 { /* Not defined by spec, GStreamer default */
263 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
264 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
265 GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
266 GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
267 GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
268 GST_AUDIO_CHANNEL_POSITION_LFE,
269 GST_AUDIO_CHANNEL_POSITION_REAR_CENTER,
271 { /* Not defined by spec, GStreamer default */
272 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
273 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
274 GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
275 GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
276 GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
277 GST_AUDIO_CHANNEL_POSITION_LFE,
278 GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
279 GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
284 gst_vorbis_enc_generate_sink_caps (void)
286 GstCaps *caps = gst_caps_new_empty ();
289 gst_caps_append_structure (caps, gst_structure_new ("audio/x-raw-float",
290 "rate", GST_TYPE_INT_RANGE, 1, 200000,
291 "channels", G_TYPE_INT, 1,
292 "endianness", G_TYPE_INT, G_BYTE_ORDER, "width", G_TYPE_INT, 32,
295 gst_caps_append_structure (caps, gst_structure_new ("audio/x-raw-float",
296 "rate", GST_TYPE_INT_RANGE, 1, 200000,
297 "channels", G_TYPE_INT, 2,
298 "endianness", G_TYPE_INT, G_BYTE_ORDER, "width", G_TYPE_INT, 32,
301 for (i = 3; i <= 8; i++) {
302 GValue chanpos = { 0 };
304 GstStructure *structure;
306 g_value_init (&chanpos, GST_TYPE_ARRAY);
307 g_value_init (&pos, GST_TYPE_AUDIO_CHANNEL_POSITION);
309 for (c = 0; c < i; c++) {
310 g_value_set_enum (&pos, vorbischannelpositions[i - 1][c]);
311 gst_value_array_append_value (&chanpos, &pos);
313 g_value_unset (&pos);
315 structure = gst_structure_new ("audio/x-raw-float",
316 "rate", GST_TYPE_INT_RANGE, 1, 200000,
317 "channels", G_TYPE_INT, i,
318 "endianness", G_TYPE_INT, G_BYTE_ORDER, "width", G_TYPE_INT, 32, NULL);
319 gst_structure_set_value (structure, "channel-positions", &chanpos);
320 g_value_unset (&chanpos);
322 gst_caps_append_structure (caps, structure);
325 gst_caps_append_structure (caps, gst_structure_new ("audio/x-raw-float",
326 "rate", GST_TYPE_INT_RANGE, 1, 200000,
327 "channels", GST_TYPE_INT_RANGE, 9, 256,
328 "endianness", G_TYPE_INT, G_BYTE_ORDER, "width", G_TYPE_INT, 32,
335 gst_vorbis_enc_sink_getcaps (GstPad * pad)
337 GstVorbisEnc *vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad));
339 if (vorbisenc->sinkcaps == NULL)
340 vorbisenc->sinkcaps = gst_vorbis_enc_generate_sink_caps ();
342 return gst_caps_ref (vorbisenc->sinkcaps);
346 gst_vorbis_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
348 GstVorbisEnc *vorbisenc;
349 GstStructure *structure;
351 vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad));
352 vorbisenc->setup = FALSE;
354 structure = gst_caps_get_structure (caps, 0);
355 gst_structure_get_int (structure, "channels", &vorbisenc->channels);
356 gst_structure_get_int (structure, "rate", &vorbisenc->frequency);
358 gst_vorbis_enc_setup (vorbisenc);
360 if (vorbisenc->setup)
367 gst_vorbis_enc_convert_src (GstPad * pad, GstFormat src_format,
368 gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
371 GstVorbisEnc *vorbisenc;
374 vorbisenc = GST_VORBISENC (gst_pad_get_parent (pad));
376 if (vorbisenc->samples_in == 0 ||
377 vorbisenc->bytes_out == 0 || vorbisenc->frequency == 0) {
378 gst_object_unref (vorbisenc);
382 avg = (vorbisenc->bytes_out * vorbisenc->frequency) / (vorbisenc->samples_in);
384 switch (src_format) {
385 case GST_FORMAT_BYTES:
386 switch (*dest_format) {
387 case GST_FORMAT_TIME:
388 *dest_value = gst_util_uint64_scale_int (src_value, GST_SECOND, avg);
394 case GST_FORMAT_TIME:
395 switch (*dest_format) {
396 case GST_FORMAT_BYTES:
397 *dest_value = gst_util_uint64_scale_int (src_value, avg, GST_SECOND);
406 gst_object_unref (vorbisenc);
411 gst_vorbis_enc_convert_sink (GstPad * pad, GstFormat src_format,
412 gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
416 gint bytes_per_sample;
417 GstVorbisEnc *vorbisenc;
419 vorbisenc = GST_VORBISENC (gst_pad_get_parent (pad));
421 bytes_per_sample = vorbisenc->channels * 2;
423 switch (src_format) {
424 case GST_FORMAT_BYTES:
425 switch (*dest_format) {
426 case GST_FORMAT_DEFAULT:
427 if (bytes_per_sample == 0)
429 *dest_value = src_value / bytes_per_sample;
431 case GST_FORMAT_TIME:
433 gint byterate = bytes_per_sample * vorbisenc->frequency;
438 gst_util_uint64_scale_int (src_value, GST_SECOND, byterate);
445 case GST_FORMAT_DEFAULT:
446 switch (*dest_format) {
447 case GST_FORMAT_BYTES:
448 *dest_value = src_value * bytes_per_sample;
450 case GST_FORMAT_TIME:
451 if (vorbisenc->frequency == 0)
454 gst_util_uint64_scale_int (src_value, GST_SECOND,
455 vorbisenc->frequency);
461 case GST_FORMAT_TIME:
462 switch (*dest_format) {
463 case GST_FORMAT_BYTES:
464 scale = bytes_per_sample;
466 case GST_FORMAT_DEFAULT:
468 gst_util_uint64_scale_int (src_value,
469 scale * vorbisenc->frequency, GST_SECOND);
478 gst_object_unref (vorbisenc);
483 gst_vorbis_enc_get_latency (GstVorbisEnc * vorbisenc)
485 /* FIXME, this probably depends on the bitrate and other setting but for now
486 * we return this value, which was obtained by totally unscientific
488 return 58 * GST_MSECOND;
491 static const GstQueryType *
492 gst_vorbis_enc_get_query_types (GstPad * pad)
494 static const GstQueryType gst_vorbis_enc_src_query_types[] = {
501 return gst_vorbis_enc_src_query_types;
505 gst_vorbis_enc_src_query (GstPad * pad, GstQuery * query)
508 GstVorbisEnc *vorbisenc;
511 vorbisenc = GST_VORBISENC (gst_pad_get_parent (pad));
512 peerpad = gst_pad_get_peer (GST_PAD (vorbisenc->sinkpad));
514 switch (GST_QUERY_TYPE (query)) {
515 case GST_QUERY_POSITION:
517 GstFormat fmt, req_fmt;
520 gst_query_parse_position (query, &req_fmt, NULL);
521 if ((res = gst_pad_query_position (peerpad, &req_fmt, &val))) {
522 gst_query_set_position (query, req_fmt, val);
526 fmt = GST_FORMAT_TIME;
527 if (!(res = gst_pad_query_position (peerpad, &fmt, &pos)))
530 if ((res = gst_pad_query_convert (peerpad, fmt, pos, &req_fmt, &val))) {
531 gst_query_set_position (query, req_fmt, val);
535 case GST_QUERY_DURATION:
537 GstFormat fmt, req_fmt;
540 gst_query_parse_duration (query, &req_fmt, NULL);
541 if ((res = gst_pad_query_duration (peerpad, &req_fmt, &val))) {
542 gst_query_set_duration (query, req_fmt, val);
546 fmt = GST_FORMAT_TIME;
547 if (!(res = gst_pad_query_duration (peerpad, &fmt, &dur)))
550 if ((res = gst_pad_query_convert (peerpad, fmt, dur, &req_fmt, &val))) {
551 gst_query_set_duration (query, req_fmt, val);
555 case GST_QUERY_CONVERT:
557 GstFormat src_fmt, dest_fmt;
558 gint64 src_val, dest_val;
560 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
562 gst_vorbis_enc_convert_src (pad, src_fmt, src_val, &dest_fmt,
565 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
568 case GST_QUERY_LATENCY:
571 GstClockTime min_latency, max_latency;
574 if ((res = gst_pad_query (peerpad, query))) {
575 gst_query_parse_latency (query, &live, &min_latency, &max_latency);
577 latency = gst_vorbis_enc_get_latency (vorbisenc);
579 /* add our latency */
580 min_latency += latency;
581 if (max_latency != -1)
582 max_latency += latency;
584 gst_query_set_latency (query, live, min_latency, max_latency);
589 res = gst_pad_query (peerpad, query);
594 gst_object_unref (peerpad);
595 gst_object_unref (vorbisenc);
600 gst_vorbis_enc_sink_query (GstPad * pad, GstQuery * query)
603 GstVorbisEnc *vorbisenc;
605 vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad));
607 switch (GST_QUERY_TYPE (query)) {
608 case GST_QUERY_CONVERT:
610 GstFormat src_fmt, dest_fmt;
611 gint64 src_val, dest_val;
613 gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
615 gst_vorbis_enc_convert_sink (pad, src_fmt, src_val, &dest_fmt,
618 gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
622 res = gst_pad_query_default (pad, query);
631 gst_vorbis_enc_init (GstVorbisEnc * vorbisenc, GstVorbisEncClass * klass)
634 gst_pad_new_from_static_template (&vorbis_enc_sink_factory, "sink");
635 gst_pad_set_event_function (vorbisenc->sinkpad,
636 GST_DEBUG_FUNCPTR (gst_vorbis_enc_sink_event));
637 gst_pad_set_chain_function (vorbisenc->sinkpad,
638 GST_DEBUG_FUNCPTR (gst_vorbis_enc_chain));
639 gst_pad_set_setcaps_function (vorbisenc->sinkpad,
640 GST_DEBUG_FUNCPTR (gst_vorbis_enc_sink_setcaps));
641 gst_pad_set_getcaps_function (vorbisenc->sinkpad,
642 GST_DEBUG_FUNCPTR (gst_vorbis_enc_sink_getcaps));
643 gst_pad_set_query_function (vorbisenc->sinkpad,
644 GST_DEBUG_FUNCPTR (gst_vorbis_enc_sink_query));
645 gst_element_add_pad (GST_ELEMENT (vorbisenc), vorbisenc->sinkpad);
648 gst_pad_new_from_static_template (&vorbis_enc_src_factory, "src");
649 gst_pad_set_query_function (vorbisenc->srcpad,
650 GST_DEBUG_FUNCPTR (gst_vorbis_enc_src_query));
651 gst_pad_set_query_type_function (vorbisenc->srcpad,
652 GST_DEBUG_FUNCPTR (gst_vorbis_enc_get_query_types));
653 gst_element_add_pad (GST_ELEMENT (vorbisenc), vorbisenc->srcpad);
655 vorbisenc->channels = -1;
656 vorbisenc->frequency = -1;
658 vorbisenc->managed = FALSE;
659 vorbisenc->max_bitrate = MAX_BITRATE_DEFAULT;
660 vorbisenc->bitrate = BITRATE_DEFAULT;
661 vorbisenc->min_bitrate = MIN_BITRATE_DEFAULT;
662 vorbisenc->quality = QUALITY_DEFAULT;
663 vorbisenc->quality_set = FALSE;
664 vorbisenc->last_message = NULL;
668 gst_vorbis_enc_metadata_set1 (const GstTagList * list, const gchar * tag,
671 GstVorbisEnc *enc = GST_VORBISENC (vorbisenc);
674 vc_list = gst_tag_to_vorbis_comments (list, tag);
676 for (l = vc_list; l != NULL; l = l->next) {
677 const gchar *vc_string = (const gchar *) l->data;
678 gchar *key = NULL, *val = NULL;
680 GST_LOG_OBJECT (vorbisenc, "vorbis comment: %s", vc_string);
681 if (gst_tag_parse_extended_comment (vc_string, &key, NULL, &val, TRUE)) {
682 vorbis_comment_add_tag (&enc->vc, key, val);
688 g_list_foreach (vc_list, (GFunc) g_free, NULL);
689 g_list_free (vc_list);
693 gst_vorbis_enc_set_metadata (GstVorbisEnc * enc)
695 GstTagList *merged_tags;
696 const GstTagList *user_tags;
698 vorbis_comment_init (&enc->vc);
700 user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
702 GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
703 GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
705 /* gst_tag_list_merge() will handle NULL for either or both lists fine */
706 merged_tags = gst_tag_list_merge (user_tags, enc->tags,
707 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
710 GST_DEBUG_OBJECT (enc, "merged tags = %" GST_PTR_FORMAT, merged_tags);
711 gst_tag_list_foreach (merged_tags, gst_vorbis_enc_metadata_set1, enc);
712 gst_tag_list_free (merged_tags);
717 get_constraints_string (GstVorbisEnc * vorbisenc)
719 gint min = vorbisenc->min_bitrate;
720 gint max = vorbisenc->max_bitrate;
723 if (min > 0 && max > 0)
724 result = g_strdup_printf ("(min %d bps, max %d bps)", min, max);
726 result = g_strdup_printf ("(min %d bps, no max)", min);
728 result = g_strdup_printf ("(no min, max %d bps)", max);
730 result = g_strdup_printf ("(no min or max)");
736 update_start_message (GstVorbisEnc * vorbisenc)
740 g_free (vorbisenc->last_message);
742 if (vorbisenc->bitrate > 0) {
743 if (vorbisenc->managed) {
744 constraints = get_constraints_string (vorbisenc);
745 vorbisenc->last_message =
746 g_strdup_printf ("encoding at average bitrate %d bps %s",
747 vorbisenc->bitrate, constraints);
748 g_free (constraints);
750 vorbisenc->last_message =
752 ("encoding at approximate bitrate %d bps (VBR encoding enabled)",
756 if (vorbisenc->quality_set) {
757 if (vorbisenc->managed) {
758 constraints = get_constraints_string (vorbisenc);
759 vorbisenc->last_message =
761 ("encoding at quality level %2.2f using constrained VBR %s",
762 vorbisenc->quality, constraints);
763 g_free (constraints);
765 vorbisenc->last_message =
766 g_strdup_printf ("encoding at quality level %2.2f",
770 constraints = get_constraints_string (vorbisenc);
771 vorbisenc->last_message =
772 g_strdup_printf ("encoding using bitrate management %s", constraints);
773 g_free (constraints);
777 g_object_notify (G_OBJECT (vorbisenc), "last_message");
781 gst_vorbis_enc_setup (GstVorbisEnc * vorbisenc)
783 vorbisenc->setup = FALSE;
785 if (vorbisenc->bitrate < 0 && vorbisenc->min_bitrate < 0
786 && vorbisenc->max_bitrate < 0) {
787 vorbisenc->quality_set = TRUE;
790 update_start_message (vorbisenc);
792 /* choose an encoding mode */
793 /* (mode 0: 44kHz stereo uncoupled, roughly 128kbps VBR) */
794 vorbis_info_init (&vorbisenc->vi);
796 if (vorbisenc->quality_set) {
797 if (vorbis_encode_setup_vbr (&vorbisenc->vi,
798 vorbisenc->channels, vorbisenc->frequency,
799 vorbisenc->quality) != 0) {
800 GST_ERROR_OBJECT (vorbisenc,
801 "vorbisenc: initialisation failed: invalid parameters for quality");
802 vorbis_info_clear (&vorbisenc->vi);
806 /* do we have optional hard quality restrictions? */
807 if (vorbisenc->max_bitrate > 0 || vorbisenc->min_bitrate > 0) {
808 struct ovectl_ratemanage_arg ai;
810 vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_GET, &ai);
812 ai.bitrate_hard_min = vorbisenc->min_bitrate;
813 ai.bitrate_hard_max = vorbisenc->max_bitrate;
814 ai.management_active = 1;
816 vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_SET, &ai);
819 long min_bitrate, max_bitrate;
821 min_bitrate = vorbisenc->min_bitrate > 0 ? vorbisenc->min_bitrate : -1;
822 max_bitrate = vorbisenc->max_bitrate > 0 ? vorbisenc->max_bitrate : -1;
824 if (vorbis_encode_setup_managed (&vorbisenc->vi,
826 vorbisenc->frequency,
827 max_bitrate, vorbisenc->bitrate, min_bitrate) != 0) {
828 GST_ERROR_OBJECT (vorbisenc,
829 "vorbis_encode_setup_managed "
830 "(c %d, rate %d, max br %ld, br %d, min br %ld) failed",
831 vorbisenc->channels, vorbisenc->frequency, max_bitrate,
832 vorbisenc->bitrate, min_bitrate);
833 vorbis_info_clear (&vorbisenc->vi);
838 if (vorbisenc->managed && vorbisenc->bitrate < 0) {
839 vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_AVG, NULL);
840 } else if (!vorbisenc->managed) {
841 /* Turn off management entirely (if it was turned on). */
842 vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_SET, NULL);
844 vorbis_encode_setup_init (&vorbisenc->vi);
846 /* set up the analysis state and auxiliary encoding storage */
847 vorbis_analysis_init (&vorbisenc->vd, &vorbisenc->vi);
848 vorbis_block_init (&vorbisenc->vd, &vorbisenc->vb);
850 vorbisenc->next_ts = 0;
852 vorbisenc->setup = TRUE;
858 gst_vorbis_enc_clear (GstVorbisEnc * vorbisenc)
860 GstFlowReturn ret = GST_FLOW_OK;
862 if (vorbisenc->setup) {
863 vorbis_analysis_wrote (&vorbisenc->vd, 0);
864 ret = gst_vorbis_enc_output_buffers (vorbisenc);
866 vorbisenc->setup = FALSE;
869 /* clean up and exit. vorbis_info_clear() must be called last */
870 vorbis_block_clear (&vorbisenc->vb);
871 vorbis_dsp_clear (&vorbisenc->vd);
872 vorbis_info_clear (&vorbisenc->vi);
874 vorbisenc->header_sent = FALSE;
879 /* prepare a buffer for transmission by passing data through libvorbis */
881 gst_vorbis_enc_buffer_from_packet (GstVorbisEnc * vorbisenc,
886 outbuf = gst_buffer_new_and_alloc (packet->bytes);
887 memcpy (GST_BUFFER_DATA (outbuf), packet->packet, packet->bytes);
888 /* see ext/ogg/README; OFFSET_END takes "our" granulepos, OFFSET its
889 * time representation */
890 GST_BUFFER_OFFSET_END (outbuf) = packet->granulepos +
891 vorbisenc->granulepos_offset;
892 GST_BUFFER_OFFSET (outbuf) = granulepos_to_timestamp (vorbisenc,
893 GST_BUFFER_OFFSET_END (outbuf));
894 GST_BUFFER_TIMESTAMP (outbuf) = vorbisenc->next_ts;
896 /* update the next timestamp, taking granulepos_offset and subgranule offset
899 granulepos_to_timestamp_offset (vorbisenc, packet->granulepos) +
900 vorbisenc->initial_ts;
901 GST_BUFFER_DURATION (outbuf) =
902 vorbisenc->next_ts - GST_BUFFER_TIMESTAMP (outbuf);
904 if (vorbisenc->next_discont) {
905 GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
906 vorbisenc->next_discont = FALSE;
909 gst_buffer_set_caps (outbuf, vorbisenc->srccaps);
911 GST_LOG_OBJECT (vorbisenc, "encoded buffer of %d bytes",
912 GST_BUFFER_SIZE (outbuf));
916 /* the same as above, but different logic for setting timestamp and granulepos
919 gst_vorbis_enc_buffer_from_header_packet (GstVorbisEnc * vorbisenc,
924 outbuf = gst_buffer_new_and_alloc (packet->bytes);
925 memcpy (GST_BUFFER_DATA (outbuf), packet->packet, packet->bytes);
926 GST_BUFFER_OFFSET (outbuf) = vorbisenc->bytes_out;
927 GST_BUFFER_OFFSET_END (outbuf) = 0;
928 GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
929 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
931 gst_buffer_set_caps (outbuf, vorbisenc->srccaps);
933 GST_DEBUG ("created header packet buffer, %d bytes",
934 GST_BUFFER_SIZE (outbuf));
938 /* push out the buffer and do internal bookkeeping */
940 gst_vorbis_enc_push_buffer (GstVorbisEnc * vorbisenc, GstBuffer * buffer)
942 vorbisenc->bytes_out += GST_BUFFER_SIZE (buffer);
944 GST_DEBUG_OBJECT (vorbisenc, "Pushing buffer with GP %lld, ts %lld",
945 GST_BUFFER_OFFSET_END (buffer), GST_BUFFER_TIMESTAMP (buffer));
946 return gst_pad_push (vorbisenc->srcpad, buffer);
950 gst_vorbis_enc_push_packet (GstVorbisEnc * vorbisenc, ogg_packet * packet)
954 outbuf = gst_vorbis_enc_buffer_from_packet (vorbisenc, packet);
955 return gst_vorbis_enc_push_buffer (vorbisenc, outbuf);
958 /* Set a copy of these buffers as 'streamheader' on the caps.
959 * We need a copy to avoid these buffers ending up with (indirect) refs on
963 gst_vorbis_enc_set_header_on_caps (GstCaps * caps, GstBuffer * buf1,
964 GstBuffer * buf2, GstBuffer * buf3)
967 GstStructure *structure;
968 GValue array = { 0 };
969 GValue value = { 0 };
971 caps = gst_caps_make_writable (caps);
972 structure = gst_caps_get_structure (caps, 0);
975 GST_BUFFER_FLAG_SET (buf1, GST_BUFFER_FLAG_IN_CAPS);
976 GST_BUFFER_FLAG_SET (buf2, GST_BUFFER_FLAG_IN_CAPS);
977 GST_BUFFER_FLAG_SET (buf3, GST_BUFFER_FLAG_IN_CAPS);
979 /* put buffers in a fixed list */
980 g_value_init (&array, GST_TYPE_ARRAY);
981 g_value_init (&value, GST_TYPE_BUFFER);
982 buf = gst_buffer_copy (buf1);
983 gst_value_set_buffer (&value, buf);
984 gst_buffer_unref (buf);
985 gst_value_array_append_value (&array, &value);
986 g_value_unset (&value);
987 g_value_init (&value, GST_TYPE_BUFFER);
988 buf = gst_buffer_copy (buf2);
989 gst_value_set_buffer (&value, buf);
990 gst_buffer_unref (buf);
991 gst_value_array_append_value (&array, &value);
992 g_value_unset (&value);
993 g_value_init (&value, GST_TYPE_BUFFER);
994 buf = gst_buffer_copy (buf3);
995 gst_value_set_buffer (&value, buf);
996 gst_buffer_unref (buf);
997 gst_value_array_append_value (&array, &value);
998 gst_structure_set_value (structure, "streamheader", &array);
999 g_value_unset (&value);
1000 g_value_unset (&array);
1006 gst_vorbis_enc_sink_event (GstPad * pad, GstEvent * event)
1008 gboolean res = TRUE;
1009 GstVorbisEnc *vorbisenc;
1011 vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad));
1013 switch (GST_EVENT_TYPE (event)) {
1015 /* Tell the library we're at end of stream so that it can handle
1016 * the last frame and mark end of stream in the output properly */
1017 GST_DEBUG_OBJECT (vorbisenc, "EOS, clearing state and sending event on");
1018 gst_vorbis_enc_clear (vorbisenc);
1020 res = gst_pad_push_event (vorbisenc->srcpad, event);
1023 if (vorbisenc->tags) {
1026 gst_event_parse_tag (event, &list);
1027 gst_tag_list_insert (vorbisenc->tags, list,
1028 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (vorbisenc)));
1030 g_assert_not_reached ();
1032 res = gst_pad_push_event (vorbisenc->srcpad, event);
1034 case GST_EVENT_NEWSEGMENT:
1037 gdouble rate, applied_rate;
1039 gint64 start, stop, position;
1041 gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
1042 &format, &start, &stop, &position);
1043 if (format == GST_FORMAT_TIME) {
1044 gst_segment_set_newsegment (&vorbisenc->segment, update, rate, format,
1045 start, stop, position);
1046 if (vorbisenc->initial_ts == GST_CLOCK_TIME_NONE) {
1047 GST_DEBUG_OBJECT (vorbisenc, "Initial segment %" GST_SEGMENT_FORMAT,
1048 &vorbisenc->segment);
1049 vorbisenc->initial_ts = start;
1055 res = gst_pad_push_event (vorbisenc->srcpad, event);
1062 gst_vorbis_enc_buffer_check_discontinuous (GstVorbisEnc * vorbisenc,
1063 GstClockTime timestamp, GstClockTime duration)
1065 gboolean ret = FALSE;
1067 if (timestamp != GST_CLOCK_TIME_NONE &&
1068 vorbisenc->expected_ts != GST_CLOCK_TIME_NONE &&
1069 timestamp + duration != vorbisenc->expected_ts) {
1070 /* It turns out that a lot of elements don't generate perfect streams due
1071 * to rounding errors. So, we permit small errors (< 1/2 a sample) without
1072 * causing a discont.
1074 int halfsample = GST_SECOND / vorbisenc->frequency / 2;
1076 if ((GstClockTimeDiff) (timestamp - vorbisenc->expected_ts) > halfsample) {
1077 GST_DEBUG_OBJECT (vorbisenc, "Expected TS %" GST_TIME_FORMAT
1078 ", buffer TS %" GST_TIME_FORMAT,
1079 GST_TIME_ARGS (vorbisenc->expected_ts), GST_TIME_ARGS (timestamp));
1084 if (timestamp != GST_CLOCK_TIME_NONE && duration != GST_CLOCK_TIME_NONE) {
1085 vorbisenc->expected_ts = timestamp + duration;
1087 vorbisenc->expected_ts = GST_CLOCK_TIME_NONE;
1092 static GstFlowReturn
1093 gst_vorbis_enc_chain (GstPad * pad, GstBuffer * buffer)
1095 GstVorbisEnc *vorbisenc;
1096 GstFlowReturn ret = GST_FLOW_OK;
1100 float **vorbis_buffer;
1101 GstBuffer *buf1, *buf2, *buf3;
1102 gboolean first = FALSE;
1103 GstClockTime timestamp = GST_CLOCK_TIME_NONE;
1104 GstClockTime running_time = GST_CLOCK_TIME_NONE;
1106 vorbisenc = GST_VORBISENC (GST_PAD_PARENT (pad));
1108 if (!vorbisenc->setup)
1111 buffer = gst_audio_buffer_clip (buffer, &vorbisenc->segment,
1112 vorbisenc->frequency, 4 * vorbisenc->channels);
1113 if (buffer == NULL) {
1114 GST_DEBUG_OBJECT (vorbisenc, "Dropping buffer, out of segment");
1118 gst_segment_to_running_time (&vorbisenc->segment, GST_FORMAT_TIME,
1119 GST_BUFFER_TIMESTAMP (buffer));
1120 timestamp = running_time + vorbisenc->initial_ts;
1121 GST_DEBUG_OBJECT (vorbisenc, "Initial ts is %" GST_TIME_FORMAT,
1122 GST_TIME_ARGS (vorbisenc->initial_ts));
1123 if (!vorbisenc->header_sent) {
1124 /* Vorbis streams begin with three headers; the initial header (with
1125 most of the codec setup parameters) which is mandated by the Ogg
1126 bitstream spec. The second header holds any comment fields. The
1127 third header holds the bitstream codebook. We merely need to
1128 make the headers, then pass them to libvorbis one at a time;
1129 libvorbis handles the additional Ogg bitstream constraints */
1131 ogg_packet header_comm;
1132 ogg_packet header_code;
1135 /* first, make sure header buffers get timestamp == 0 */
1136 vorbisenc->next_ts = 0;
1137 vorbisenc->granulepos_offset = 0;
1138 vorbisenc->subgranule_offset = 0;
1140 GST_DEBUG_OBJECT (vorbisenc, "creating and sending header packets");
1141 gst_vorbis_enc_set_metadata (vorbisenc);
1142 vorbis_analysis_headerout (&vorbisenc->vd, &vorbisenc->vc, &header,
1143 &header_comm, &header_code);
1144 vorbis_comment_clear (&vorbisenc->vc);
1146 /* create header buffers */
1147 buf1 = gst_vorbis_enc_buffer_from_header_packet (vorbisenc, &header);
1148 buf2 = gst_vorbis_enc_buffer_from_header_packet (vorbisenc, &header_comm);
1149 buf3 = gst_vorbis_enc_buffer_from_header_packet (vorbisenc, &header_code);
1151 /* mark and put on caps */
1152 vorbisenc->srccaps = gst_caps_new_simple ("audio/x-vorbis", NULL);
1153 caps = vorbisenc->srccaps;
1154 caps = gst_vorbis_enc_set_header_on_caps (caps, buf1, buf2, buf3);
1156 /* negotiate with these caps */
1157 GST_DEBUG ("here are the caps: %" GST_PTR_FORMAT, caps);
1158 gst_pad_set_caps (vorbisenc->srcpad, caps);
1160 gst_buffer_set_caps (buf1, caps);
1161 gst_buffer_set_caps (buf2, caps);
1162 gst_buffer_set_caps (buf3, caps);
1164 /* push out buffers */
1165 /* push_buffer takes the reference even for failure */
1166 if ((ret = gst_vorbis_enc_push_buffer (vorbisenc, buf1)) != GST_FLOW_OK)
1167 goto failed_header_push;
1168 if ((ret = gst_vorbis_enc_push_buffer (vorbisenc, buf2)) != GST_FLOW_OK) {
1170 goto failed_header_push;
1172 if ((ret = gst_vorbis_enc_push_buffer (vorbisenc, buf3)) != GST_FLOW_OK) {
1174 goto failed_header_push;
1177 /* now adjust starting granulepos accordingly if the buffer's timestamp is
1179 vorbisenc->next_ts = timestamp;
1180 vorbisenc->expected_ts = timestamp;
1181 vorbisenc->granulepos_offset = gst_util_uint64_scale
1182 (running_time, vorbisenc->frequency, GST_SECOND);
1183 vorbisenc->subgranule_offset = 0;
1184 vorbisenc->subgranule_offset =
1185 (vorbisenc->next_ts - vorbisenc->initial_ts) -
1186 granulepos_to_timestamp_offset (vorbisenc, 0);
1188 vorbisenc->header_sent = TRUE;
1192 if (vorbisenc->expected_ts != GST_CLOCK_TIME_NONE &&
1193 timestamp < vorbisenc->expected_ts) {
1194 guint64 diff = vorbisenc->expected_ts - timestamp;
1197 GST_WARNING_OBJECT (vorbisenc, "Buffer is older than previous "
1198 "timestamp + duration (%" GST_TIME_FORMAT "< %" GST_TIME_FORMAT
1199 "), cannot handle. Clipping buffer.",
1200 GST_TIME_ARGS (timestamp), GST_TIME_ARGS (vorbisenc->expected_ts));
1203 GST_CLOCK_TIME_TO_FRAMES (diff,
1204 vorbisenc->frequency) * vorbisenc->channels * sizeof (gfloat);
1205 if (diff_bytes >= GST_BUFFER_SIZE (buffer)) {
1206 gst_buffer_unref (buffer);
1209 buffer = gst_buffer_make_metadata_writable (buffer);
1210 GST_BUFFER_DATA (buffer) += diff_bytes;
1211 GST_BUFFER_SIZE (buffer) -= diff_bytes;
1213 GST_BUFFER_TIMESTAMP (buffer) += diff;
1214 if (GST_BUFFER_DURATION_IS_VALID (buffer))
1215 GST_BUFFER_DURATION (buffer) -= diff;
1218 if (gst_vorbis_enc_buffer_check_discontinuous (vorbisenc, timestamp,
1219 GST_BUFFER_DURATION (buffer)) && !first) {
1220 GST_WARNING_OBJECT (vorbisenc,
1221 "Buffer is discontinuous, flushing encoder "
1222 "and restarting (Discont from %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT
1223 ")", GST_TIME_ARGS (vorbisenc->next_ts), GST_TIME_ARGS (timestamp));
1224 /* Re-initialise encoder (there's unfortunately no API to flush it) */
1225 if ((ret = gst_vorbis_enc_clear (vorbisenc)) != GST_FLOW_OK)
1227 if (!gst_vorbis_enc_setup (vorbisenc))
1228 return GST_FLOW_ERROR; /* Should be impossible, we can only get here if
1229 we successfully initialised earlier */
1231 /* Now, set our granulepos offset appropriately. */
1232 vorbisenc->next_ts = timestamp;
1233 /* We need to round to the nearest whole number of samples, not just do
1234 * a truncating division here */
1235 vorbisenc->granulepos_offset = gst_util_uint64_scale
1236 (running_time + GST_SECOND / vorbisenc->frequency / 2
1237 - vorbisenc->subgranule_offset, vorbisenc->frequency, GST_SECOND);
1239 vorbisenc->header_sent = TRUE;
1241 /* And our next output buffer must have DISCONT set on it */
1242 vorbisenc->next_discont = TRUE;
1245 /* Sending zero samples to libvorbis marks EOS, so we mustn't do that */
1246 if (GST_BUFFER_SIZE (buffer) == 0) {
1247 gst_buffer_unref (buffer);
1251 /* data to encode */
1252 data = (gfloat *) GST_BUFFER_DATA (buffer);
1253 size = GST_BUFFER_SIZE (buffer) / (vorbisenc->channels * sizeof (float));
1255 /* expose the buffer to submit data */
1256 vorbis_buffer = vorbis_analysis_buffer (&vorbisenc->vd, size);
1258 /* deinterleave samples, write the buffer data */
1259 for (i = 0; i < size; i++) {
1260 for (j = 0; j < vorbisenc->channels; j++) {
1261 vorbis_buffer[j][i] = *data++;
1265 /* tell the library how much we actually submitted */
1266 vorbis_analysis_wrote (&vorbisenc->vd, size);
1268 GST_LOG_OBJECT (vorbisenc, "wrote %lu samples to vorbis", size);
1270 vorbisenc->samples_in += size;
1272 gst_buffer_unref (buffer);
1274 ret = gst_vorbis_enc_output_buffers (vorbisenc);
1281 gst_buffer_unref (buffer);
1282 GST_ELEMENT_ERROR (vorbisenc, CORE, NEGOTIATION, (NULL),
1283 ("encoder not initialized (input is not audio?)"));
1284 return GST_FLOW_UNEXPECTED;
1288 GST_WARNING_OBJECT (vorbisenc, "Failed to push headers");
1289 /* buf1 is always already unreffed */
1291 gst_buffer_unref (buf2);
1293 gst_buffer_unref (buf3);
1294 gst_buffer_unref (buffer);
1299 static GstFlowReturn
1300 gst_vorbis_enc_output_buffers (GstVorbisEnc * vorbisenc)
1304 /* vorbis does some data preanalysis, then divides up blocks for
1305 more involved (potentially parallel) processing. Get a single
1306 block for encoding now */
1307 while (vorbis_analysis_blockout (&vorbisenc->vd, &vorbisenc->vb) == 1) {
1310 GST_LOG_OBJECT (vorbisenc, "analysed to a block");
1313 vorbis_analysis (&vorbisenc->vb, NULL);
1314 vorbis_bitrate_addblock (&vorbisenc->vb);
1316 while (vorbis_bitrate_flushpacket (&vorbisenc->vd, &op)) {
1317 GST_LOG_OBJECT (vorbisenc, "pushing out a data packet");
1318 ret = gst_vorbis_enc_push_packet (vorbisenc, &op);
1320 if (ret != GST_FLOW_OK)
1329 gst_vorbis_enc_get_property (GObject * object, guint prop_id, GValue * value,
1332 GstVorbisEnc *vorbisenc;
1334 g_return_if_fail (GST_IS_VORBISENC (object));
1336 vorbisenc = GST_VORBISENC (object);
1339 case ARG_MAX_BITRATE:
1340 g_value_set_int (value, vorbisenc->max_bitrate);
1343 g_value_set_int (value, vorbisenc->bitrate);
1345 case ARG_MIN_BITRATE:
1346 g_value_set_int (value, vorbisenc->min_bitrate);
1349 g_value_set_float (value, vorbisenc->quality);
1352 g_value_set_boolean (value, vorbisenc->managed);
1354 case ARG_LAST_MESSAGE:
1355 g_value_set_string (value, vorbisenc->last_message);
1358 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1364 gst_vorbis_enc_set_property (GObject * object, guint prop_id,
1365 const GValue * value, GParamSpec * pspec)
1367 GstVorbisEnc *vorbisenc;
1369 g_return_if_fail (GST_IS_VORBISENC (object));
1371 vorbisenc = GST_VORBISENC (object);
1374 case ARG_MAX_BITRATE:
1376 gboolean old_value = vorbisenc->managed;
1378 vorbisenc->max_bitrate = g_value_get_int (value);
1379 if (vorbisenc->max_bitrate >= 0
1380 && vorbisenc->max_bitrate < LOWEST_BITRATE) {
1381 g_warning ("Lowest allowed bitrate is %d", LOWEST_BITRATE);
1382 vorbisenc->max_bitrate = LOWEST_BITRATE;
1384 if (vorbisenc->min_bitrate > 0 && vorbisenc->max_bitrate > 0)
1385 vorbisenc->managed = TRUE;
1387 vorbisenc->managed = FALSE;
1389 if (old_value != vorbisenc->managed)
1390 g_object_notify (object, "managed");
1394 vorbisenc->bitrate = g_value_get_int (value);
1395 if (vorbisenc->bitrate >= 0 && vorbisenc->bitrate < LOWEST_BITRATE) {
1396 g_warning ("Lowest allowed bitrate is %d", LOWEST_BITRATE);
1397 vorbisenc->bitrate = LOWEST_BITRATE;
1400 case ARG_MIN_BITRATE:
1402 gboolean old_value = vorbisenc->managed;
1404 vorbisenc->min_bitrate = g_value_get_int (value);
1405 if (vorbisenc->min_bitrate >= 0
1406 && vorbisenc->min_bitrate < LOWEST_BITRATE) {
1407 g_warning ("Lowest allowed bitrate is %d", LOWEST_BITRATE);
1408 vorbisenc->min_bitrate = LOWEST_BITRATE;
1410 if (vorbisenc->min_bitrate > 0 && vorbisenc->max_bitrate > 0)
1411 vorbisenc->managed = TRUE;
1413 vorbisenc->managed = FALSE;
1415 if (old_value != vorbisenc->managed)
1416 g_object_notify (object, "managed");
1420 vorbisenc->quality = g_value_get_float (value);
1421 if (vorbisenc->quality >= 0.0)
1422 vorbisenc->quality_set = TRUE;
1424 vorbisenc->quality_set = FALSE;
1427 vorbisenc->managed = g_value_get_boolean (value);
1430 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1435 static GstStateChangeReturn
1436 gst_vorbis_enc_change_state (GstElement * element, GstStateChange transition)
1438 GstVorbisEnc *vorbisenc = GST_VORBISENC (element);
1439 GstStateChangeReturn res;
1442 switch (transition) {
1443 case GST_STATE_CHANGE_NULL_TO_READY:
1444 vorbisenc->tags = gst_tag_list_new ();
1446 case GST_STATE_CHANGE_READY_TO_PAUSED:
1447 vorbisenc->setup = FALSE;
1448 vorbisenc->next_discont = FALSE;
1449 vorbisenc->header_sent = FALSE;
1450 gst_segment_init (&vorbisenc->segment, GST_FORMAT_TIME);
1451 vorbisenc->initial_ts = GST_CLOCK_TIME_NONE;
1453 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1459 res = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1461 switch (transition) {
1462 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1464 case GST_STATE_CHANGE_PAUSED_TO_READY:
1465 vorbis_block_clear (&vorbisenc->vb);
1466 vorbis_dsp_clear (&vorbisenc->vd);
1467 vorbis_info_clear (&vorbisenc->vi);
1468 g_free (vorbisenc->last_message);
1469 vorbisenc->last_message = NULL;
1470 if (vorbisenc->srccaps) {
1471 gst_caps_unref (vorbisenc->srccaps);
1472 vorbisenc->srccaps = NULL;
1475 case GST_STATE_CHANGE_READY_TO_NULL:
1476 gst_tag_list_free (vorbisenc->tags);
1477 vorbisenc->tags = NULL;