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 #include "gstvorbiscommon.h"
59 GST_DEBUG_CATEGORY_EXTERN (vorbisenc_debug);
60 #define GST_CAT_DEFAULT vorbisenc_debug
62 static GstStaticPadTemplate vorbis_enc_sink_factory =
63 GST_STATIC_PAD_TEMPLATE ("sink",
66 GST_STATIC_CAPS ("audio/x-raw, "
67 "format = (string) " GST_AUDIO_NE (F32) ", "
68 "rate = (int) [ 1, 200000 ], " "channels = (int) [ 1, 256 ]")
71 static GstStaticPadTemplate vorbis_enc_src_factory =
72 GST_STATIC_PAD_TEMPLATE ("src",
75 GST_STATIC_CAPS ("audio/x-vorbis")
89 static GstFlowReturn gst_vorbis_enc_output_buffers (GstVorbisEnc * vorbisenc);
92 #define MAX_BITRATE_DEFAULT -1
93 #define BITRATE_DEFAULT -1
94 #define MIN_BITRATE_DEFAULT -1
95 #define QUALITY_DEFAULT 0.3
96 #define LOWEST_BITRATE 6000 /* lowest allowed for a 8 kHz stream */
97 #define HIGHEST_BITRATE 250001 /* highest allowed for a 44 kHz stream */
99 static gboolean gst_vorbis_enc_start (GstAudioEncoder * enc);
100 static gboolean gst_vorbis_enc_stop (GstAudioEncoder * enc);
101 static gboolean gst_vorbis_enc_set_format (GstAudioEncoder * enc,
102 GstAudioInfo * info);
103 static GstFlowReturn gst_vorbis_enc_handle_frame (GstAudioEncoder * enc,
105 static GstCaps *gst_vorbis_enc_getcaps (GstAudioEncoder * enc,
107 static gboolean gst_vorbis_enc_sink_event (GstAudioEncoder * enc,
109 static GstFlowReturn gst_vorbis_enc_pre_push (GstAudioEncoder * enc,
110 GstBuffer ** buffer);
112 static gboolean gst_vorbis_enc_setup (GstVorbisEnc * vorbisenc);
114 static void gst_vorbis_enc_dispose (GObject * object);
115 static void gst_vorbis_enc_get_property (GObject * object, guint prop_id,
116 GValue * value, GParamSpec * pspec);
117 static void gst_vorbis_enc_set_property (GObject * object, guint prop_id,
118 const GValue * value, GParamSpec * pspec);
120 #define gst_vorbis_enc_parent_class parent_class
121 G_DEFINE_TYPE_WITH_CODE (GstVorbisEnc, gst_vorbis_enc,
122 GST_TYPE_AUDIO_ENCODER, G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL));
125 gst_vorbis_enc_class_init (GstVorbisEncClass * klass)
127 GObjectClass *gobject_class;
128 GstElementClass *gstelement_class;
129 GstAudioEncoderClass *base_class;
131 gobject_class = (GObjectClass *) klass;
132 gstelement_class = (GstElementClass *) klass;
133 base_class = (GstAudioEncoderClass *) (klass);
135 gobject_class->set_property = gst_vorbis_enc_set_property;
136 gobject_class->get_property = gst_vorbis_enc_get_property;
137 gobject_class->dispose = gst_vorbis_enc_dispose;
139 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MAX_BITRATE,
140 g_param_spec_int ("max-bitrate", "Maximum Bitrate",
141 "Specify a maximum bitrate (in bps). Useful for streaming "
142 "applications. (-1 == disabled)",
143 -1, HIGHEST_BITRATE, MAX_BITRATE_DEFAULT,
144 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
145 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE,
146 g_param_spec_int ("bitrate", "Target Bitrate",
147 "Attempt to encode at a bitrate averaging this (in bps). "
148 "This uses the bitrate management engine, and is not recommended for most users. "
149 "Quality is a better alternative. (-1 == disabled)", -1,
150 HIGHEST_BITRATE, BITRATE_DEFAULT,
151 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
152 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MIN_BITRATE,
153 g_param_spec_int ("min-bitrate", "Minimum Bitrate",
154 "Specify a minimum bitrate (in bps). Useful for encoding for a "
155 "fixed-size channel. (-1 == disabled)", -1, HIGHEST_BITRATE,
156 MIN_BITRATE_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
157 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QUALITY,
158 g_param_spec_float ("quality", "Quality",
159 "Specify quality instead of specifying a particular bitrate.", -0.1,
160 1.0, QUALITY_DEFAULT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
161 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MANAGED,
162 g_param_spec_boolean ("managed", "Managed",
163 "Enable bitrate management engine", FALSE,
164 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
165 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
166 g_param_spec_string ("last-message", "last-message",
167 "The last status message", NULL,
168 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
170 gst_element_class_add_pad_template (gstelement_class,
171 gst_static_pad_template_get (&vorbis_enc_src_factory));
172 gst_element_class_add_pad_template (gstelement_class,
173 gst_static_pad_template_get (&vorbis_enc_sink_factory));
175 gst_element_class_set_details_simple (gstelement_class,
176 "Vorbis audio encoder", "Codec/Encoder/Audio",
177 "Encodes audio in Vorbis format",
178 "Monty <monty@xiph.org>, " "Wim Taymans <wim@fluendo.com>");
180 base_class->start = GST_DEBUG_FUNCPTR (gst_vorbis_enc_start);
181 base_class->stop = GST_DEBUG_FUNCPTR (gst_vorbis_enc_stop);
182 base_class->set_format = GST_DEBUG_FUNCPTR (gst_vorbis_enc_set_format);
183 base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_vorbis_enc_handle_frame);
184 base_class->getcaps = GST_DEBUG_FUNCPTR (gst_vorbis_enc_getcaps);
185 base_class->event = GST_DEBUG_FUNCPTR (gst_vorbis_enc_sink_event);
186 base_class->pre_push = GST_DEBUG_FUNCPTR (gst_vorbis_enc_pre_push);
190 gst_vorbis_enc_init (GstVorbisEnc * vorbisenc)
192 GstAudioEncoder *enc = GST_AUDIO_ENCODER (vorbisenc);
194 vorbisenc->channels = -1;
195 vorbisenc->frequency = -1;
197 vorbisenc->managed = FALSE;
198 vorbisenc->max_bitrate = MAX_BITRATE_DEFAULT;
199 vorbisenc->bitrate = BITRATE_DEFAULT;
200 vorbisenc->min_bitrate = MIN_BITRATE_DEFAULT;
201 vorbisenc->quality = QUALITY_DEFAULT;
202 vorbisenc->quality_set = FALSE;
203 vorbisenc->last_message = NULL;
205 /* arrange granulepos marking (and required perfect ts) */
206 gst_audio_encoder_set_mark_granule (enc, TRUE);
207 gst_audio_encoder_set_perfect_timestamp (enc, TRUE);
211 gst_vorbis_enc_dispose (GObject * object)
213 GstVorbisEnc *vorbisenc = GST_VORBISENC (object);
215 if (vorbisenc->sinkcaps) {
216 gst_caps_unref (vorbisenc->sinkcaps);
217 vorbisenc->sinkcaps = NULL;
220 G_OBJECT_CLASS (parent_class)->dispose (object);
224 gst_vorbis_enc_start (GstAudioEncoder * enc)
226 GstVorbisEnc *vorbisenc = GST_VORBISENC (enc);
228 GST_DEBUG_OBJECT (enc, "start");
229 vorbisenc->tags = gst_tag_list_new ();
230 vorbisenc->header_sent = FALSE;
236 gst_vorbis_enc_stop (GstAudioEncoder * enc)
238 GstVorbisEnc *vorbisenc = GST_VORBISENC (enc);
240 GST_DEBUG_OBJECT (enc, "stop");
241 vorbis_block_clear (&vorbisenc->vb);
242 vorbis_dsp_clear (&vorbisenc->vd);
243 vorbis_info_clear (&vorbisenc->vi);
244 g_free (vorbisenc->last_message);
245 vorbisenc->last_message = NULL;
246 gst_tag_list_free (vorbisenc->tags);
247 vorbisenc->tags = NULL;
248 g_slist_foreach (vorbisenc->headers, (GFunc) gst_buffer_unref, NULL);
249 vorbisenc->headers = NULL;
255 gst_vorbis_enc_generate_sink_caps (void)
257 GstCaps *caps = gst_caps_new_empty ();
260 gst_caps_append_structure (caps, gst_structure_new ("audio/x-raw",
261 "format", G_TYPE_STRING, GST_AUDIO_NE (F32),
262 "rate", GST_TYPE_INT_RANGE, 1, 200000,
263 "channels", G_TYPE_INT, 1, NULL));
265 gst_caps_append_structure (caps, gst_structure_new ("audio/x-raw",
266 "format", G_TYPE_STRING, GST_AUDIO_NE (F32),
267 "rate", GST_TYPE_INT_RANGE, 1, 200000,
268 "channels", G_TYPE_INT, 2, NULL));
270 for (i = 3; i <= 8; i++) {
271 GValue chanpos = { 0 };
273 GstStructure *structure;
275 g_value_init (&chanpos, GST_TYPE_ARRAY);
276 g_value_init (&pos, GST_TYPE_AUDIO_CHANNEL_POSITION);
278 for (c = 0; c < i; c++) {
279 g_value_set_enum (&pos, gst_vorbis_channel_positions[i - 1][c]);
280 gst_value_array_append_value (&chanpos, &pos);
282 g_value_unset (&pos);
284 structure = gst_structure_new ("audio/x-raw",
285 "format", G_TYPE_STRING, GST_AUDIO_NE (F32),
286 "rate", GST_TYPE_INT_RANGE, 1, 200000, "channels", G_TYPE_INT, i, NULL);
287 gst_structure_set_value (structure, "channel-positions", &chanpos);
288 g_value_unset (&chanpos);
290 gst_caps_append_structure (caps, structure);
293 gst_caps_append_structure (caps, gst_structure_new ("audio/x-raw",
294 "format", G_TYPE_STRING, GST_AUDIO_NE (F32),
295 "rate", GST_TYPE_INT_RANGE, 1, 200000,
296 "channels", GST_TYPE_INT_RANGE, 9, 256, NULL));
302 gst_vorbis_enc_getcaps (GstAudioEncoder * enc, GstCaps * filter)
304 GstVorbisEnc *vorbisenc = GST_VORBISENC (enc);
306 if (vorbisenc->sinkcaps == NULL)
307 vorbisenc->sinkcaps = gst_vorbis_enc_generate_sink_caps ();
309 return gst_audio_encoder_proxy_getcaps (enc, vorbisenc->sinkcaps);
313 gst_vorbis_enc_get_latency (GstVorbisEnc * vorbisenc)
315 /* FIXME, this probably depends on the bitrate and other setting but for now
316 * we return this value, which was obtained by totally unscientific
318 return 58 * GST_MSECOND;
322 gst_vorbis_enc_set_format (GstAudioEncoder * enc, GstAudioInfo * info)
324 GstVorbisEnc *vorbisenc;
326 vorbisenc = GST_VORBISENC (enc);
328 vorbisenc->channels = GST_AUDIO_INFO_CHANNELS (info);
329 vorbisenc->frequency = GST_AUDIO_INFO_RATE (info);
331 /* if re-configured, we were drained and cleared already */
332 if (!gst_vorbis_enc_setup (vorbisenc))
335 /* feedback to base class */
336 gst_audio_encoder_set_latency (enc,
337 gst_vorbis_enc_get_latency (vorbisenc),
338 gst_vorbis_enc_get_latency (vorbisenc));
344 gst_vorbis_enc_metadata_set1 (const GstTagList * list, const gchar * tag,
347 GstVorbisEnc *enc = GST_VORBISENC (vorbisenc);
350 vc_list = gst_tag_to_vorbis_comments (list, tag);
352 for (l = vc_list; l != NULL; l = l->next) {
353 const gchar *vc_string = (const gchar *) l->data;
354 gchar *key = NULL, *val = NULL;
356 GST_LOG_OBJECT (vorbisenc, "vorbis comment: %s", vc_string);
357 if (gst_tag_parse_extended_comment (vc_string, &key, NULL, &val, TRUE)) {
358 vorbis_comment_add_tag (&enc->vc, key, val);
364 g_list_foreach (vc_list, (GFunc) g_free, NULL);
365 g_list_free (vc_list);
369 gst_vorbis_enc_set_metadata (GstVorbisEnc * enc)
371 GstTagList *merged_tags;
372 const GstTagList *user_tags;
374 vorbis_comment_init (&enc->vc);
376 user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
378 GST_DEBUG_OBJECT (enc, "upstream tags = %" GST_PTR_FORMAT, enc->tags);
379 GST_DEBUG_OBJECT (enc, "user-set tags = %" GST_PTR_FORMAT, user_tags);
381 /* gst_tag_list_merge() will handle NULL for either or both lists fine */
382 merged_tags = gst_tag_list_merge (user_tags, enc->tags,
383 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (enc)));
386 GST_DEBUG_OBJECT (enc, "merged tags = %" GST_PTR_FORMAT, merged_tags);
387 gst_tag_list_foreach (merged_tags, gst_vorbis_enc_metadata_set1, enc);
388 gst_tag_list_free (merged_tags);
393 get_constraints_string (GstVorbisEnc * vorbisenc)
395 gint min = vorbisenc->min_bitrate;
396 gint max = vorbisenc->max_bitrate;
399 if (min > 0 && max > 0)
400 result = g_strdup_printf ("(min %d bps, max %d bps)", min, max);
402 result = g_strdup_printf ("(min %d bps, no max)", min);
404 result = g_strdup_printf ("(no min, max %d bps)", max);
406 result = g_strdup_printf ("(no min or max)");
412 update_start_message (GstVorbisEnc * vorbisenc)
416 g_free (vorbisenc->last_message);
418 if (vorbisenc->bitrate > 0) {
419 if (vorbisenc->managed) {
420 constraints = get_constraints_string (vorbisenc);
421 vorbisenc->last_message =
422 g_strdup_printf ("encoding at average bitrate %d bps %s",
423 vorbisenc->bitrate, constraints);
424 g_free (constraints);
426 vorbisenc->last_message =
428 ("encoding at approximate bitrate %d bps (VBR encoding enabled)",
432 if (vorbisenc->quality_set) {
433 if (vorbisenc->managed) {
434 constraints = get_constraints_string (vorbisenc);
435 vorbisenc->last_message =
437 ("encoding at quality level %2.2f using constrained VBR %s",
438 vorbisenc->quality, constraints);
439 g_free (constraints);
441 vorbisenc->last_message =
442 g_strdup_printf ("encoding at quality level %2.2f",
446 constraints = get_constraints_string (vorbisenc);
447 vorbisenc->last_message =
448 g_strdup_printf ("encoding using bitrate management %s", constraints);
449 g_free (constraints);
453 g_object_notify (G_OBJECT (vorbisenc), "last_message");
457 gst_vorbis_enc_setup (GstVorbisEnc * vorbisenc)
460 GST_LOG_OBJECT (vorbisenc, "setup");
462 if (vorbisenc->bitrate < 0 && vorbisenc->min_bitrate < 0
463 && vorbisenc->max_bitrate < 0) {
464 vorbisenc->quality_set = TRUE;
467 update_start_message (vorbisenc);
469 /* choose an encoding mode */
470 /* (mode 0: 44kHz stereo uncoupled, roughly 128kbps VBR) */
471 vorbis_info_init (&vorbisenc->vi);
473 if (vorbisenc->quality_set) {
474 if (vorbis_encode_setup_vbr (&vorbisenc->vi,
475 vorbisenc->channels, vorbisenc->frequency,
476 vorbisenc->quality) != 0) {
477 GST_ERROR_OBJECT (vorbisenc,
478 "vorbisenc: initialisation failed: invalid parameters for quality");
479 vorbis_info_clear (&vorbisenc->vi);
483 /* do we have optional hard quality restrictions? */
484 if (vorbisenc->max_bitrate > 0 || vorbisenc->min_bitrate > 0) {
485 struct ovectl_ratemanage_arg ai;
487 vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_GET, &ai);
489 ai.bitrate_hard_min = vorbisenc->min_bitrate;
490 ai.bitrate_hard_max = vorbisenc->max_bitrate;
491 ai.management_active = 1;
493 vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_SET, &ai);
496 long min_bitrate, max_bitrate;
498 min_bitrate = vorbisenc->min_bitrate > 0 ? vorbisenc->min_bitrate : -1;
499 max_bitrate = vorbisenc->max_bitrate > 0 ? vorbisenc->max_bitrate : -1;
501 if (vorbis_encode_setup_managed (&vorbisenc->vi,
503 vorbisenc->frequency,
504 max_bitrate, vorbisenc->bitrate, min_bitrate) != 0) {
505 GST_ERROR_OBJECT (vorbisenc,
506 "vorbis_encode_setup_managed "
507 "(c %d, rate %d, max br %ld, br %d, min br %ld) failed",
508 vorbisenc->channels, vorbisenc->frequency, max_bitrate,
509 vorbisenc->bitrate, min_bitrate);
510 vorbis_info_clear (&vorbisenc->vi);
515 if (vorbisenc->managed && vorbisenc->bitrate < 0) {
516 vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_AVG, NULL);
517 } else if (!vorbisenc->managed) {
518 /* Turn off management entirely (if it was turned on). */
519 vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_SET, NULL);
521 vorbis_encode_setup_init (&vorbisenc->vi);
523 /* set up the analysis state and auxiliary encoding storage */
524 vorbis_analysis_init (&vorbisenc->vd, &vorbisenc->vi);
525 vorbis_block_init (&vorbisenc->vd, &vorbisenc->vb);
527 /* samples == granulepos start at 0 again */
528 vorbisenc->samples_out = 0;
530 /* fresh encoder available */
531 vorbisenc->setup = TRUE;
537 gst_vorbis_enc_clear (GstVorbisEnc * vorbisenc)
539 GstFlowReturn ret = GST_FLOW_OK;
541 if (vorbisenc->setup) {
542 vorbis_analysis_wrote (&vorbisenc->vd, 0);
543 ret = gst_vorbis_enc_output_buffers (vorbisenc);
545 /* marked EOS to encoder, recreate if needed */
546 vorbisenc->setup = FALSE;
549 /* clean up and exit. vorbis_info_clear() must be called last */
550 vorbis_block_clear (&vorbisenc->vb);
551 vorbis_dsp_clear (&vorbisenc->vd);
552 vorbis_info_clear (&vorbisenc->vi);
558 gst_vorbis_enc_buffer_from_header_packet (GstVorbisEnc * vorbisenc,
563 outbuf = gst_buffer_new_and_alloc (packet->bytes);
564 gst_buffer_fill (outbuf, 0, packet->packet, packet->bytes);
565 GST_BUFFER_OFFSET (outbuf) = vorbisenc->bytes_out;
566 GST_BUFFER_OFFSET_END (outbuf) = 0;
567 GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
568 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
570 GST_DEBUG ("created header packet buffer, %d bytes",
571 gst_buffer_get_size (outbuf));
576 gst_vorbis_enc_sink_event (GstAudioEncoder * enc, GstEvent * event)
578 GstVorbisEnc *vorbisenc;
580 vorbisenc = GST_VORBISENC (enc);
582 switch (GST_EVENT_TYPE (event)) {
584 if (vorbisenc->tags) {
587 gst_event_parse_tag (event, &list);
588 gst_tag_list_insert (vorbisenc->tags, list,
589 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (vorbisenc)));
591 g_assert_not_reached ();
599 /* we only peeked, let base class handle it */
603 /* push out the buffer and do internal bookkeeping */
605 gst_vorbis_enc_push_header (GstVorbisEnc * vorbisenc, GstBuffer * buffer)
607 GST_DEBUG_OBJECT (vorbisenc,
608 "Pushing buffer with GP %" G_GINT64_FORMAT ", ts %" GST_TIME_FORMAT,
609 GST_BUFFER_OFFSET_END (buffer),
610 GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
611 return gst_pad_push (GST_AUDIO_ENCODER_SRC_PAD (vorbisenc), buffer);
615 * (really really) FIXME: move into core (dixit tpm)
618 * _gst_caps_set_buffer_array:
620 * @field: field in caps to set
621 * @buf: header buffers
623 * Adds given buffers to an array of buffers set as the given @field
624 * on the given @caps. List of buffer arguments must be NULL-terminated.
626 * Returns: input caps with a streamheader field added, or NULL if some error
629 _gst_caps_set_buffer_array (GstCaps * caps, const gchar * field,
630 GstBuffer * buf, ...)
632 GstStructure *structure = NULL;
634 GValue array = { 0 };
635 GValue value = { 0 };
637 g_return_val_if_fail (caps != NULL, NULL);
638 g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
639 g_return_val_if_fail (field != NULL, NULL);
641 caps = gst_caps_make_writable (caps);
642 structure = gst_caps_get_structure (caps, 0);
644 g_value_init (&array, GST_TYPE_ARRAY);
647 /* put buffers in a fixed list */
649 g_assert (gst_buffer_is_writable (buf));
652 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
654 g_value_init (&value, GST_TYPE_BUFFER);
655 buf = gst_buffer_copy (buf);
656 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
657 gst_value_set_buffer (&value, buf);
658 gst_buffer_unref (buf);
659 gst_value_array_append_value (&array, &value);
660 g_value_unset (&value);
662 buf = va_arg (va, GstBuffer *);
665 gst_structure_set_value (structure, field, &array);
666 g_value_unset (&array);
672 gst_vorbis_enc_handle_frame (GstAudioEncoder * enc, GstBuffer * buffer)
674 GstVorbisEnc *vorbisenc;
675 GstFlowReturn ret = GST_FLOW_OK;
680 float **vorbis_buffer;
681 GstBuffer *buf1, *buf2, *buf3;
683 vorbisenc = GST_VORBISENC (enc);
685 if (G_UNLIKELY (!vorbisenc->setup)) {
687 GST_DEBUG_OBJECT (vorbisenc, "forcing setup");
688 /* should not fail, as setup before same way */
689 if (!gst_vorbis_enc_setup (vorbisenc))
690 return GST_FLOW_ERROR;
693 GST_LOG_OBJECT (vorbisenc, "already drained");
698 if (!vorbisenc->header_sent) {
699 /* Vorbis streams begin with three headers; the initial header (with
700 most of the codec setup parameters) which is mandated by the Ogg
701 bitstream spec. The second header holds any comment fields. The
702 third header holds the bitstream codebook. We merely need to
703 make the headers, then pass them to libvorbis one at a time;
704 libvorbis handles the additional Ogg bitstream constraints */
706 ogg_packet header_comm;
707 ogg_packet header_code;
710 GST_DEBUG_OBJECT (vorbisenc, "creating and sending header packets");
711 gst_vorbis_enc_set_metadata (vorbisenc);
712 vorbis_analysis_headerout (&vorbisenc->vd, &vorbisenc->vc, &header,
713 &header_comm, &header_code);
714 vorbis_comment_clear (&vorbisenc->vc);
716 /* create header buffers */
717 buf1 = gst_vorbis_enc_buffer_from_header_packet (vorbisenc, &header);
718 buf2 = gst_vorbis_enc_buffer_from_header_packet (vorbisenc, &header_comm);
719 buf3 = gst_vorbis_enc_buffer_from_header_packet (vorbisenc, &header_code);
721 /* mark and put on caps */
722 caps = gst_caps_new_simple ("audio/x-vorbis", NULL);
723 caps = _gst_caps_set_buffer_array (caps, "streamheader",
724 buf1, buf2, buf3, NULL);
726 /* negotiate with these caps */
727 GST_DEBUG_OBJECT (vorbisenc, "here are the caps: %" GST_PTR_FORMAT, caps);
728 gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (vorbisenc), caps);
729 gst_caps_unref (caps);
731 /* store buffers for later pre_push sending */
732 g_slist_foreach (vorbisenc->headers, (GFunc) gst_buffer_unref, NULL);
733 vorbisenc->headers = NULL;
734 GST_DEBUG_OBJECT (vorbisenc, "storing header buffers");
735 vorbisenc->headers = g_slist_prepend (vorbisenc->headers, buf3);
736 vorbisenc->headers = g_slist_prepend (vorbisenc->headers, buf2);
737 vorbisenc->headers = g_slist_prepend (vorbisenc->headers, buf1);
739 vorbisenc->header_sent = TRUE;
743 return gst_vorbis_enc_clear (vorbisenc);
745 data = gst_buffer_map (buffer, &bsize, NULL, GST_MAP_WRITE);
748 size = bsize / (vorbisenc->channels * sizeof (float));
752 /* expose the buffer to submit data */
753 vorbis_buffer = vorbis_analysis_buffer (&vorbisenc->vd, size);
755 /* deinterleave samples, write the buffer data */
756 for (i = 0; i < size; i++) {
757 for (j = 0; j < vorbisenc->channels; j++) {
758 vorbis_buffer[j][i] = *ptr++;
762 /* tell the library how much we actually submitted */
763 vorbis_analysis_wrote (&vorbisenc->vd, size);
764 gst_buffer_unmap (buffer, data, bsize);
766 GST_LOG_OBJECT (vorbisenc, "wrote %lu samples to vorbis", size);
768 vorbisenc->samples_in += size;
770 ret = gst_vorbis_enc_output_buffers (vorbisenc);
776 gst_vorbis_enc_output_buffers (GstVorbisEnc * vorbisenc)
780 /* vorbis does some data preanalysis, then divides up blocks for
781 more involved (potentially parallel) processing. Get a single
782 block for encoding now */
783 while (vorbis_analysis_blockout (&vorbisenc->vd, &vorbisenc->vb) == 1) {
786 GST_LOG_OBJECT (vorbisenc, "analysed to a block");
789 vorbis_analysis (&vorbisenc->vb, NULL);
790 vorbis_bitrate_addblock (&vorbisenc->vb);
792 while (vorbis_bitrate_flushpacket (&vorbisenc->vd, &op)) {
795 GST_LOG_OBJECT (vorbisenc, "pushing out a data packet");
796 buf = gst_buffer_new_and_alloc (op.bytes);
797 gst_buffer_fill (buf, 0, op.packet, op.bytes);
798 /* tracking granulepos should tell us samples accounted for */
800 gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER
801 (vorbisenc), buf, op.granulepos - vorbisenc->samples_out);
802 vorbisenc->samples_out = op.granulepos;
804 if (ret != GST_FLOW_OK)
813 gst_vorbis_enc_pre_push (GstAudioEncoder * enc, GstBuffer ** buffer)
815 GstVorbisEnc *vorbisenc;
816 GstFlowReturn ret = GST_FLOW_OK;
818 vorbisenc = GST_VORBISENC (enc);
820 /* FIXME 0.11 ? get rid of this special ogg stuff and have it
821 * put and use 'codec data' in caps like anything else,
822 * with all the usual out-of-band advantage etc */
823 if (G_UNLIKELY (vorbisenc->headers)) {
824 GSList *header = vorbisenc->headers;
826 /* try to push all of these, if we lose one, might as well lose all */
828 if (ret == GST_FLOW_OK)
829 ret = gst_vorbis_enc_push_header (vorbisenc, header->data);
831 gst_vorbis_enc_push_header (vorbisenc, header->data);
832 header = g_slist_next (header);
835 g_slist_free (vorbisenc->headers);
836 vorbisenc->headers = NULL;
843 gst_vorbis_enc_get_property (GObject * object, guint prop_id, GValue * value,
846 GstVorbisEnc *vorbisenc;
848 g_return_if_fail (GST_IS_VORBISENC (object));
850 vorbisenc = GST_VORBISENC (object);
853 case ARG_MAX_BITRATE:
854 g_value_set_int (value, vorbisenc->max_bitrate);
857 g_value_set_int (value, vorbisenc->bitrate);
859 case ARG_MIN_BITRATE:
860 g_value_set_int (value, vorbisenc->min_bitrate);
863 g_value_set_float (value, vorbisenc->quality);
866 g_value_set_boolean (value, vorbisenc->managed);
868 case ARG_LAST_MESSAGE:
869 g_value_set_string (value, vorbisenc->last_message);
872 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
878 gst_vorbis_enc_set_property (GObject * object, guint prop_id,
879 const GValue * value, GParamSpec * pspec)
881 GstVorbisEnc *vorbisenc;
883 g_return_if_fail (GST_IS_VORBISENC (object));
885 vorbisenc = GST_VORBISENC (object);
888 case ARG_MAX_BITRATE:
890 gboolean old_value = vorbisenc->managed;
892 vorbisenc->max_bitrate = g_value_get_int (value);
893 if (vorbisenc->max_bitrate >= 0
894 && vorbisenc->max_bitrate < LOWEST_BITRATE) {
895 g_warning ("Lowest allowed bitrate is %d", LOWEST_BITRATE);
896 vorbisenc->max_bitrate = LOWEST_BITRATE;
898 if (vorbisenc->min_bitrate > 0 && vorbisenc->max_bitrate > 0)
899 vorbisenc->managed = TRUE;
901 vorbisenc->managed = FALSE;
903 if (old_value != vorbisenc->managed)
904 g_object_notify (object, "managed");
908 vorbisenc->bitrate = g_value_get_int (value);
909 if (vorbisenc->bitrate >= 0 && vorbisenc->bitrate < LOWEST_BITRATE) {
910 g_warning ("Lowest allowed bitrate is %d", LOWEST_BITRATE);
911 vorbisenc->bitrate = LOWEST_BITRATE;
914 case ARG_MIN_BITRATE:
916 gboolean old_value = vorbisenc->managed;
918 vorbisenc->min_bitrate = g_value_get_int (value);
919 if (vorbisenc->min_bitrate >= 0
920 && vorbisenc->min_bitrate < LOWEST_BITRATE) {
921 g_warning ("Lowest allowed bitrate is %d", LOWEST_BITRATE);
922 vorbisenc->min_bitrate = LOWEST_BITRATE;
924 if (vorbisenc->min_bitrate > 0 && vorbisenc->max_bitrate > 0)
925 vorbisenc->managed = TRUE;
927 vorbisenc->managed = FALSE;
929 if (old_value != vorbisenc->managed)
930 g_object_notify (object, "managed");
934 vorbisenc->quality = g_value_get_float (value);
935 if (vorbisenc->quality >= 0.0)
936 vorbisenc->quality_set = TRUE;
938 vorbisenc->quality_set = FALSE;
941 vorbisenc->managed = g_value_get_boolean (value);
944 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);