change NULL to (NULL) for GST_ELEMENT_ERROR
[platform/upstream/gst-plugins-base.git] / ext / vorbis / vorbisenc.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  *
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.
8  *
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.
13  *
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.
18  */
19
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 #include <stdlib.h>
25 #include <string.h>
26 #include <time.h>
27 #include <vorbis/vorbisenc.h>
28
29 #include <gst/gsttaginterface.h>
30 #include "vorbisenc.h"
31
32 static GstPadTemplate *gst_vorbisenc_src_template, *gst_vorbisenc_sink_template;
33
34 /* elementfactory information */
35 GstElementDetails vorbisenc_details = {
36   "Ogg Vorbis encoder",
37   "Codec/Encoder/Audio",
38   "Encodes audio in OGG Vorbis format",
39   "Monty <monty@xiph.org>, "
40   "Wim Taymans <wim.taymans@chello.be>",
41 };
42
43 /* VorbisEnc signals and args */
44 enum
45 {
46   /* FILL ME */
47   LAST_SIGNAL
48 };
49
50 enum
51 {
52   ARG_0,
53   ARG_MAX_BITRATE,
54   ARG_BITRATE,
55   ARG_MIN_BITRATE,
56   ARG_QUALITY,
57   ARG_SERIAL,
58   ARG_MANAGED,
59   ARG_LAST_MESSAGE,
60 };
61
62 static const GstFormat*
63 gst_vorbisenc_get_formats (GstPad *pad)
64 {
65   static const GstFormat src_formats[] = {
66     GST_FORMAT_BYTES,
67     GST_FORMAT_TIME,
68     0
69   };
70   static const GstFormat sink_formats[] = {
71     GST_FORMAT_BYTES,
72     GST_FORMAT_DEFAULT,
73     GST_FORMAT_TIME, 
74     0
75   };
76               
77   return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats);
78
79
80 #define MAX_BITRATE_DEFAULT     -1
81 #define BITRATE_DEFAULT         -1
82 #define MIN_BITRATE_DEFAULT     -1
83 #define QUALITY_DEFAULT         0.3
84
85 static void             gst_vorbisenc_base_init         (gpointer g_class);
86 static void             gst_vorbisenc_class_init        (VorbisEncClass *klass);
87 static void             gst_vorbisenc_init              (VorbisEnc *vorbisenc);
88
89 static void             gst_vorbisenc_chain             (GstPad *pad, GstData *_data);
90 static gboolean         gst_vorbisenc_setup             (VorbisEnc *vorbisenc);
91
92 static void             gst_vorbisenc_get_property      (GObject *object, guint prop_id, 
93                                                          GValue *value, GParamSpec *pspec);
94 static void             gst_vorbisenc_set_property      (GObject *object, guint prop_id, 
95                                                          const GValue *value, GParamSpec *pspec);
96 static GstElementStateReturn
97                         gst_vorbisenc_change_state      (GstElement *element);
98
99 static GstElementClass *parent_class = NULL;
100 /*static guint gst_vorbisenc_signals[LAST_SIGNAL] = { 0 }; */
101
102 GType
103 vorbisenc_get_type (void)
104 {
105   static GType vorbisenc_type = 0;
106
107   if (!vorbisenc_type) {
108     static const GTypeInfo vorbisenc_info = {
109       sizeof (VorbisEncClass), 
110       gst_vorbisenc_base_init,
111       NULL,
112       (GClassInitFunc) gst_vorbisenc_class_init,
113       NULL,
114       NULL,
115       sizeof (VorbisEnc),
116       0,
117       (GInstanceInitFunc) gst_vorbisenc_init,
118     };
119     static const GInterfaceInfo tag_setter_info = {
120       NULL,
121       NULL,
122       NULL
123     };
124     
125     vorbisenc_type = g_type_register_static (GST_TYPE_ELEMENT, "VorbisEnc", &vorbisenc_info, 0);
126     
127     g_type_add_interface_static (vorbisenc_type, GST_TYPE_TAG_SETTER, &tag_setter_info);
128   }
129   return vorbisenc_type;
130 }
131
132 static GstCaps*
133 vorbis_caps_factory (void)
134 {
135   return gst_caps_new_simple ("application/ogg", NULL);
136 }
137
138 static GstCaps*
139 raw_caps_factory (void)
140 {
141   return
142    gst_caps_new_simple ("audio/x-raw-int",
143        "endianness",    G_TYPE_INT, G_BYTE_ORDER,
144        "signed",        G_TYPE_BOOLEAN, TRUE,
145        "width",         G_TYPE_INT, 16,
146        "depth",         G_TYPE_INT, 16,
147        "rate",          GST_TYPE_INT_RANGE, 11025, 48000,
148        "channels",      GST_TYPE_INT_RANGE, 1, 2,
149        NULL);
150 }
151
152 static void
153 gst_vorbisenc_base_init (gpointer g_class)
154 {
155   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
156   GstCaps *raw_caps, *vorbis_caps;
157
158   raw_caps = raw_caps_factory ();
159   vorbis_caps = vorbis_caps_factory ();
160
161   gst_vorbisenc_sink_template = gst_pad_template_new ("sink", GST_PAD_SINK, 
162                                                       GST_PAD_ALWAYS, 
163                                                       raw_caps);
164   gst_vorbisenc_src_template = gst_pad_template_new ("src", GST_PAD_SRC, 
165                                                      GST_PAD_ALWAYS, 
166                                                      vorbis_caps);
167   gst_element_class_add_pad_template (element_class, gst_vorbisenc_sink_template);
168   gst_element_class_add_pad_template (element_class, gst_vorbisenc_src_template);
169   gst_element_class_set_details (element_class, &vorbisenc_details);
170 }
171
172 static void
173 gst_vorbisenc_class_init (VorbisEncClass * klass)
174 {
175   GObjectClass *gobject_class;
176   GstElementClass *gstelement_class;
177
178   gobject_class = (GObjectClass *) klass;
179   gstelement_class = (GstElementClass *) klass;
180
181   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MAX_BITRATE, 
182     g_param_spec_int ("max_bitrate", "Max bitrate", 
183             " Specify a minimum bitrate (in bps). Useful for encoding for a fixed-size channel", 
184             -1, G_MAXINT, MAX_BITRATE_DEFAULT, G_PARAM_READWRITE));
185   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE, 
186     g_param_spec_int ("bitrate", "Bitrate", "Choose a bitrate to encode at. "
187             "Attempt to encode at a bitrate averaging this. Takes an argument in kbps.", 
188             -1, G_MAXINT, BITRATE_DEFAULT, G_PARAM_READWRITE));
189   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MIN_BITRATE, 
190     g_param_spec_int ("min_bitrate", "Min bitrate", 
191             "Specify a maximum bitrate in bps. Useful for streaming applications.",
192             -1, G_MAXINT, MIN_BITRATE_DEFAULT, G_PARAM_READWRITE));
193   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QUALITY, 
194     g_param_spec_float ("quality", "Quality", 
195             "Specify quality instead of specifying a particular bitrate.",
196             0.0, 1.0, QUALITY_DEFAULT, G_PARAM_READWRITE));
197   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SERIAL, 
198     g_param_spec_int ("serial", "Serial", "Specify a serial number for the stream. (-1 is random)",
199             -1, G_MAXINT, -1, G_PARAM_READWRITE));
200   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MANAGED, 
201     g_param_spec_boolean ("managed", "Managed", "Enable bitrate management engine",
202             FALSE, G_PARAM_READWRITE));
203   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
204     g_param_spec_string ("last-message", "last-message", "The last status message",
205             NULL, G_PARAM_READABLE));
206
207   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
208
209   gobject_class->set_property = gst_vorbisenc_set_property;
210   gobject_class->get_property = gst_vorbisenc_get_property;
211
212   gstelement_class->change_state = gst_vorbisenc_change_state;
213 }
214
215 static GstPadLinkReturn
216 gst_vorbisenc_sinkconnect (GstPad * pad, const GstCaps * caps)
217 {
218   VorbisEnc *vorbisenc;
219   GstStructure *structure;
220
221   vorbisenc = GST_VORBISENC (gst_pad_get_parent (pad));
222
223   structure = gst_caps_get_structure (caps, 0);
224   gst_structure_get_int  (structure, "channels", &vorbisenc->channels);
225   gst_structure_get_int  (structure, "rate",     &vorbisenc->frequency);
226
227   gst_vorbisenc_setup (vorbisenc);
228
229   if (vorbisenc->setup)
230     return GST_PAD_LINK_OK;
231
232   return GST_PAD_LINK_REFUSED;
233 }
234
235 static gboolean
236 gst_vorbisenc_convert_src (GstPad *pad, GstFormat src_format, gint64 src_value, 
237                       GstFormat *dest_format, gint64 *dest_value)
238 {
239   gboolean res = TRUE;
240   VorbisEnc *vorbisenc;
241   gint64 avg;
242
243   vorbisenc = GST_VORBISENC (gst_pad_get_parent (pad));
244
245   if (vorbisenc->samples_in == 0 || 
246       vorbisenc->bytes_out == 0 || 
247       vorbisenc->frequency == 0)
248     return FALSE;
249
250   avg = (vorbisenc->bytes_out * vorbisenc->frequency)/
251                   (vorbisenc->samples_in);
252
253   switch (src_format) {
254     case GST_FORMAT_BYTES:
255       switch (*dest_format) {
256         case GST_FORMAT_TIME:
257           *dest_value = src_value * GST_SECOND / avg;
258           break;
259         default:
260           res = FALSE;
261       }
262       break;
263     case GST_FORMAT_TIME:
264       switch (*dest_format) {
265         case GST_FORMAT_BYTES:
266           *dest_value = src_value * avg / GST_SECOND;
267           break;
268         default:
269           res = FALSE;
270       }
271       break;
272     default:
273       res = FALSE;
274   }
275   return res;
276 }
277
278 static gboolean
279 gst_vorbisenc_convert_sink (GstPad *pad, GstFormat src_format, gint64 src_value, 
280                      GstFormat *dest_format, gint64 *dest_value)
281 {
282   gboolean res = TRUE;
283   guint scale = 1;
284   gint bytes_per_sample;
285   VorbisEnc *vorbisenc;
286
287   vorbisenc = GST_VORBISENC (gst_pad_get_parent (pad));
288   
289   bytes_per_sample = vorbisenc->channels * 2;
290   
291   switch (src_format) {
292     case GST_FORMAT_BYTES:
293       switch (*dest_format) {
294         case GST_FORMAT_DEFAULT:
295           if (bytes_per_sample == 0)
296             return FALSE;
297           *dest_value = src_value / bytes_per_sample;
298           break;
299         case GST_FORMAT_TIME:
300         {
301           gint byterate = bytes_per_sample * vorbisenc->frequency;
302
303           if (byterate == 0)
304             return FALSE;
305           *dest_value = src_value * GST_SECOND / byterate;
306           break;
307         }
308         default:
309           res = FALSE;
310       }
311       break;
312     case GST_FORMAT_DEFAULT:
313       switch (*dest_format) {
314         case GST_FORMAT_BYTES:
315           *dest_value = src_value * bytes_per_sample;
316           break;
317         case GST_FORMAT_TIME:
318           if (vorbisenc->frequency == 0)
319             return FALSE;
320           *dest_value = src_value * GST_SECOND / vorbisenc->frequency;
321           break;
322         default:
323           res = FALSE;
324       }
325       break;
326     case GST_FORMAT_TIME:
327       switch (*dest_format) {
328         case GST_FORMAT_BYTES:
329           scale = bytes_per_sample;
330           /* fallthrough */
331         case GST_FORMAT_DEFAULT:
332           *dest_value = src_value * scale * vorbisenc->frequency / GST_SECOND;
333           break;
334         default:
335           res = FALSE;
336       }
337       break;
338     default:
339       res = FALSE;
340   }
341   return res;
342 }
343
344 static const GstQueryType*
345 gst_vorbisenc_get_query_types (GstPad *pad)
346 {
347   static const GstQueryType gst_vorbisenc_src_query_types[] = {
348     GST_QUERY_TOTAL,
349     GST_QUERY_POSITION,
350     0
351   };
352   return gst_vorbisenc_src_query_types;
353 }
354
355 static gboolean
356 gst_vorbisenc_src_query (GstPad *pad, GstQueryType type,
357                    GstFormat *format, gint64 *value)
358 {
359   gboolean res = TRUE;
360   VorbisEnc *vorbisenc;
361  
362   vorbisenc = GST_VORBISENC (gst_pad_get_parent (pad));
363
364   switch (type) {
365     case GST_QUERY_TOTAL:
366     {
367       switch (*format) {
368         case GST_FORMAT_BYTES:
369         case GST_FORMAT_TIME:
370         {
371           gint64 peer_value;
372           const GstFormat *peer_formats;
373
374           res = FALSE;
375
376           peer_formats = gst_pad_get_formats (GST_PAD_PEER (vorbisenc->sinkpad));
377
378           while (peer_formats && *peer_formats && !res) {
379
380             GstFormat peer_format = *peer_formats;
381
382             /* do the probe */
383             if (gst_pad_query (GST_PAD_PEER (vorbisenc->sinkpad), GST_QUERY_TOTAL,
384                                &peer_format, &peer_value)) 
385             {
386               GstFormat conv_format;
387               /* convert to TIME */
388               conv_format = GST_FORMAT_TIME;
389               res = gst_pad_convert (vorbisenc->sinkpad,
390                                 peer_format, peer_value,
391                                 &conv_format, value);
392               /* and to final format */
393               res &= gst_pad_convert (pad,
394                         GST_FORMAT_TIME, *value,
395                         format, value);
396             }
397             peer_formats++;
398           }
399           break;
400         }
401         default:
402           res = FALSE;
403           break;
404       }
405       break;
406     }
407     case GST_QUERY_POSITION:
408       switch (*format) {
409         default:
410         {
411           /* we only know about our samples, convert to requested format */
412           res = gst_pad_convert (pad,
413                           GST_FORMAT_BYTES, vorbisenc->bytes_out,
414                           format, value);
415           break;
416         }
417       }
418       break;
419     default:
420       res = FALSE;
421       break;
422   }
423   return res;
424 }
425
426 static void
427 gst_vorbisenc_init (VorbisEnc * vorbisenc)
428 {
429   vorbisenc->sinkpad = gst_pad_new_from_template (gst_vorbisenc_sink_template, "sink");
430   gst_element_add_pad (GST_ELEMENT (vorbisenc), vorbisenc->sinkpad);
431   gst_pad_set_chain_function (vorbisenc->sinkpad, gst_vorbisenc_chain);
432   gst_pad_set_link_function (vorbisenc->sinkpad, gst_vorbisenc_sinkconnect);
433   gst_pad_set_convert_function (vorbisenc->sinkpad, GST_DEBUG_FUNCPTR (gst_vorbisenc_convert_sink));
434   gst_pad_set_formats_function (vorbisenc->sinkpad, GST_DEBUG_FUNCPTR (gst_vorbisenc_get_formats));
435
436   vorbisenc->srcpad = gst_pad_new_from_template (gst_vorbisenc_src_template, "src");
437   gst_pad_set_query_function (vorbisenc->srcpad, GST_DEBUG_FUNCPTR (gst_vorbisenc_src_query));
438   gst_pad_set_query_type_function (vorbisenc->srcpad, GST_DEBUG_FUNCPTR (gst_vorbisenc_get_query_types));
439   gst_pad_set_convert_function (vorbisenc->srcpad, GST_DEBUG_FUNCPTR (gst_vorbisenc_convert_src));
440   gst_pad_set_formats_function (vorbisenc->srcpad, GST_DEBUG_FUNCPTR (gst_vorbisenc_get_formats));
441   gst_element_add_pad (GST_ELEMENT (vorbisenc), vorbisenc->srcpad);
442
443   vorbisenc->channels = -1;
444   vorbisenc->frequency = -1;
445
446   vorbisenc->managed = FALSE;
447   vorbisenc->max_bitrate = MAX_BITRATE_DEFAULT;
448   vorbisenc->bitrate = BITRATE_DEFAULT;
449   vorbisenc->min_bitrate = MIN_BITRATE_DEFAULT;
450   vorbisenc->quality = QUALITY_DEFAULT;
451   vorbisenc->quality_set = FALSE;
452   vorbisenc->serial = -1;
453   vorbisenc->last_message = NULL;
454   
455   vorbisenc->setup = FALSE;
456   vorbisenc->eos = FALSE;
457   vorbisenc->header_sent = FALSE;
458
459   vorbisenc->tags = gst_tag_list_new ();
460   
461   /* we're chained and we can deal with events */
462   GST_FLAG_SET (vorbisenc, GST_ELEMENT_EVENT_AWARE);
463 }
464
465 static void
466 gst_vorbisenc_metadata_set1 (const GstTagList *list, const gchar *tag, gpointer vorbisenc)
467 {
468   gchar *vorbistag = NULL;
469   gchar *vorbisvalue = NULL;
470   guint i, count;
471   VorbisEnc *enc = GST_VORBISENC (vorbisenc);
472
473   count = gst_tag_list_get_tag_size (list, tag);
474   for (i = 0; i < count; i++) {
475     /* get tag name right */
476     if (strcmp (tag, GST_TAG_TITLE) == 0) {
477       vorbistag = g_strdup ("TITLE");
478       g_assert (gst_tag_list_get_string_index (list, tag, i, &vorbisvalue));
479     } else if (strcmp (tag, GST_TAG_VERSION) == 0) {
480       vorbistag = g_strdup ("VERSION");
481       g_assert (gst_tag_list_get_string_index (list, tag, i, &vorbisvalue));
482     } else if (strcmp (tag, GST_TAG_ALBUM) == 0) {
483       vorbistag = g_strdup ("ALBUM");
484       g_assert (gst_tag_list_get_string_index (list, tag, i, &vorbisvalue));
485     } else if (strcmp (tag, GST_TAG_TRACK_NUMBER) == 0) {
486       guint track_no;
487       vorbistag = g_strdup ("TRACKNUMBER");
488       g_assert (gst_tag_list_get_uint_index (list, tag, i, &track_no));
489       vorbisvalue = g_strdup_printf ("%u", track_no);
490     } else if (strcmp (tag, GST_TAG_ARTIST) == 0) {
491       vorbistag = g_strdup ("ARTIST");
492       g_assert (gst_tag_list_get_string_index (list, tag, i, &vorbisvalue));
493     } else if (strcmp (tag, GST_TAG_PERFORMER) == 0) {
494       vorbistag = g_strdup ("PERFORMER");
495       g_assert (gst_tag_list_get_string_index (list, tag, i, &vorbisvalue));
496     } else if (strcmp (tag, GST_TAG_COPYRIGHT) == 0) {
497       vorbistag = g_strdup ("COPYRIGHT");
498       g_assert (gst_tag_list_get_string_index (list, tag, i, &vorbisvalue));
499     } else if (strcmp (tag, GST_TAG_LICENSE) == 0) {
500       vorbistag = g_strdup ("LICENSE");
501       g_assert (gst_tag_list_get_string_index (list, tag, i, &vorbisvalue));
502     } else if (strcmp (tag, GST_TAG_ORGANIZATION) == 0) {
503       vorbistag = g_strdup ("ORGANIZATION");
504       g_assert (gst_tag_list_get_string_index (list, tag, i, &vorbisvalue));
505     } else if (strcmp (tag, GST_TAG_DESCRIPTION) == 0) {
506       vorbistag = g_strdup ("DESCRIPTION");
507       g_assert (gst_tag_list_get_string_index (list, tag, i, &vorbisvalue));
508     } else if (strcmp (tag, GST_TAG_GENRE) == 0) {
509       vorbistag = g_strdup ("GENRE");
510       g_assert (gst_tag_list_get_string_index (list, tag, i, &vorbisvalue));
511     } else if (strcmp (tag, GST_TAG_DATE) == 0) {
512       /* FIXME: how are dates represented in vorbis files? */
513       GDate *date;
514       guint u;
515       
516       vorbistag = g_strdup ("DATE");
517       g_assert (gst_tag_list_get_uint_index (list, tag, i, &u));
518       date = g_date_new_julian (u);
519       vorbisvalue = g_strdup_printf ("%04d-%02d-%02d", (gint) g_date_get_year (date),
520                                    (gint) g_date_get_month (date), (gint) g_date_get_day (date));
521       g_date_free (date);
522     /* NOTE: GST_TAG_LOCATION != vorbis' location
523     } else if (strcmp (tag, PLACE) == 0) {
524       vorbistag = g_strdup ("LOCATION");
525       g_assert (gst_tag_list_get_string_index (list, tag, i, &vorbisvalue));
526     */
527     } else if (strcmp (tag, GST_TAG_CONTACT) == 0) {
528       vorbistag = g_strdup ("CONTACT");
529       g_assert (gst_tag_list_get_string_index (list, tag, i, &vorbisvalue));
530     } else if (strcmp (tag, GST_TAG_ISRC) == 0) {
531       vorbistag = g_strdup ("ISRC");
532       g_assert (gst_tag_list_get_string_index (list, tag, i, &vorbisvalue));
533     } else {
534       vorbistag = g_ascii_strup (tag, -1);
535       if (gst_tag_get_type (tag) == G_TYPE_STRING) {
536         g_assert (gst_tag_list_get_string_index (list, tag, i, &vorbisvalue));
537       } else {
538         const GValue *value = gst_tag_list_get_value_index (list, tag, i);
539         vorbisvalue = g_strdup_value_contents (value);
540       }
541     }
542   }
543
544   vorbis_comment_add_tag (&enc->vc, vorbistag, vorbisvalue);
545 }
546 static void 
547 gst_vorbisenc_set_metadata (VorbisEnc *vorbisenc)
548 {
549   GstTagList *copy; 
550   const GstTagList *user_tags;
551   
552   user_tags = gst_tag_setter_get_list (GST_TAG_SETTER (vorbisenc));
553   if (!(vorbisenc->tags || user_tags))
554     return;
555
556   copy = gst_tag_list_merge (user_tags, vorbisenc->tags, gst_tag_setter_get_merge_mode (GST_TAG_SETTER (vorbisenc)));
557   vorbis_comment_init (&vorbisenc->vc);
558   gst_tag_list_foreach (copy, gst_vorbisenc_metadata_set1, vorbisenc);
559   gst_tag_list_free (copy);
560 }
561
562 static gchar*
563 get_constraints_string (VorbisEnc *vorbisenc)
564 {
565   gint min = vorbisenc->min_bitrate;
566   gint max = vorbisenc->max_bitrate;
567   gchar *result;
568
569   if (min > 0 && max > 0)
570     result = g_strdup_printf ("(min %d bps, max %d bps)", min,max);
571   else if (min > 0)
572     result = g_strdup_printf ("(min %d bps, no max)", min);
573   else if (max > 0)
574     result = g_strdup_printf ("(no min, max %d bps)", max);
575   else
576     result = g_strdup_printf ("(no min or max)");
577
578   return result;
579 }
580
581 static void
582 update_start_message (VorbisEnc *vorbisenc) 
583 {
584   gchar *constraints;
585
586   g_free (vorbisenc->last_message);
587
588   if (vorbisenc->bitrate > 0) {
589     if (vorbisenc->managed) {
590       constraints = get_constraints_string (vorbisenc);
591       vorbisenc->last_message = 
592               g_strdup_printf ("encoding at average bitrate %d bps %s", 
593                                vorbisenc->bitrate, constraints);
594       g_free (constraints);
595     }
596     else {
597       vorbisenc->last_message = 
598               g_strdup_printf ("encoding at approximate bitrate %d bps (VBR encoding enabled)", 
599                                vorbisenc->bitrate);
600     }
601   }
602   else {
603     if (vorbisenc->quality_set) {
604       if (vorbisenc->managed) {
605         constraints = get_constraints_string (vorbisenc);
606         vorbisenc->last_message = 
607               g_strdup_printf ("encoding at quality level %2.2f using constrained VBR %s", 
608                                vorbisenc->quality, constraints);
609         g_free (constraints);
610       }
611       else {
612         vorbisenc->last_message = 
613               g_strdup_printf ("encoding at quality level %2.2f", 
614                                vorbisenc->quality);
615       }
616     }
617     else {
618       constraints = get_constraints_string (vorbisenc);
619       vorbisenc->last_message = 
620               g_strdup_printf ("encoding using bitrate management %s", 
621                                constraints);
622       g_free (constraints);
623     }
624   }
625
626   g_object_notify (G_OBJECT (vorbisenc), "last_message");
627 }
628
629 static gboolean
630 gst_vorbisenc_setup (VorbisEnc *vorbisenc)
631 {
632   gint serial;
633
634   if (vorbisenc->bitrate < 0 && vorbisenc->min_bitrate < 0 && vorbisenc->max_bitrate < 0) {
635     vorbisenc->quality_set = TRUE;
636   }
637
638   update_start_message (vorbisenc);
639   
640   /* choose an encoding mode */
641   /* (mode 0: 44kHz stereo uncoupled, roughly 128kbps VBR) */
642   vorbis_info_init (&vorbisenc->vi);
643
644   if(vorbisenc->quality_set){
645     if (vorbis_encode_setup_vbr (&vorbisenc->vi, 
646                                  vorbisenc->channels, 
647                                  vorbisenc->frequency, 
648                                  vorbisenc->quality)) 
649     {
650        g_warning ("vorbisenc: initialisation failed: invalid parameters for quality");
651        vorbis_info_clear(&vorbisenc->vi);
652        return FALSE;
653     }
654
655     /* do we have optional hard quality restrictions? */
656     if(vorbisenc->max_bitrate > 0 || vorbisenc->min_bitrate > 0){
657       struct ovectl_ratemanage_arg ai;
658       vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_GET, &ai);
659
660       /* the bitrates are in kHz */
661       ai.bitrate_hard_min = vorbisenc->min_bitrate / 1000;
662       ai.bitrate_hard_max = vorbisenc->max_bitrate / 1000;
663       ai.management_active = 1;
664
665       vorbis_encode_ctl (&vorbisenc->vi, OV_ECTL_RATEMANAGE_SET, &ai);
666     }
667   } 
668   else {
669     if (vorbis_encode_setup_managed (&vorbisenc->vi, 
670                                      vorbisenc->channels, 
671                                      vorbisenc->frequency,
672                                      vorbisenc->max_bitrate > 0 ? vorbisenc->max_bitrate : -1,
673                                      vorbisenc->bitrate,
674                                      vorbisenc->min_bitrate > 0 ? vorbisenc->min_bitrate : -1))
675     {
676       g_warning("vorbisenc: initialisation failed: invalid parameters for bitrate\n");
677       vorbis_info_clear(&vorbisenc->vi);
678       return FALSE;
679     }
680   }
681
682   if(vorbisenc->managed && vorbisenc->bitrate < 0) {
683     vorbis_encode_ctl(&vorbisenc->vi, OV_ECTL_RATEMANAGE_AVG, NULL);
684   }
685   else if(!vorbisenc->managed) {
686     /* Turn off management entirely (if it was turned on). */
687     vorbis_encode_ctl(&vorbisenc->vi, OV_ECTL_RATEMANAGE_SET, NULL);
688   }
689   vorbis_encode_setup_init(&vorbisenc->vi);
690
691   /* set up the analysis state and auxiliary encoding storage */
692   vorbis_analysis_init (&vorbisenc->vd, &vorbisenc->vi);
693   vorbis_block_init (&vorbisenc->vd, &vorbisenc->vb);
694
695   /* set up our packet->stream encoder */
696   /* pick a random serial number; that way we can more likely build
697      chained streams just by concatenation */
698   if (vorbisenc->serial < 0) {
699     srand (time (NULL));
700     serial = rand ();
701   }
702   else {
703     serial = vorbisenc->serial;
704   }
705
706   ogg_stream_init (&vorbisenc->os, serial);
707
708   vorbisenc->setup = TRUE;
709
710   return TRUE;
711 }
712
713 static void
714 gst_vorbisenc_write_page (VorbisEnc *vorbisenc, ogg_page *page)
715 {
716   GstBuffer *outbuf;
717
718   outbuf = gst_buffer_new_and_alloc (page->header_len + 
719                                      page->body_len);
720
721   memcpy (GST_BUFFER_DATA (outbuf), page->header, 
722                                     page->header_len);
723   memcpy (GST_BUFFER_DATA (outbuf) + page->header_len, 
724                                      page->body,
725                                      page->body_len);
726
727   GST_DEBUG ("vorbisenc: encoded buffer of %d bytes", 
728                         GST_BUFFER_SIZE (outbuf));
729
730   vorbisenc->bytes_out += GST_BUFFER_SIZE (outbuf);
731
732   if (GST_PAD_IS_USABLE (vorbisenc->srcpad)) {
733     gst_pad_push (vorbisenc->srcpad, GST_DATA (outbuf));
734   }
735   else {
736     gst_buffer_unref (outbuf);
737   }
738 }
739
740 static void
741 gst_vorbisenc_chain (GstPad * pad, GstData *_data)
742 {
743   GstBuffer *buf = GST_BUFFER (_data);
744   VorbisEnc *vorbisenc;
745
746   g_return_if_fail (pad != NULL);
747   g_return_if_fail (GST_IS_PAD (pad));
748   g_return_if_fail (buf != NULL);
749
750   vorbisenc = GST_VORBISENC (gst_pad_get_parent (pad));
751
752   if (GST_IS_EVENT (buf)) {
753     GstEvent *event = GST_EVENT (buf);
754
755     switch (GST_EVENT_TYPE (event)) {
756       case GST_EVENT_EOS:
757         /* end of file.  this can be done implicitly in the mainline,
758            but it's easier to see here in non-clever fashion.
759            Tell the library we're at end of stream so that it can handle
760            the last frame and mark end of stream in the output properly */
761         vorbis_analysis_wrote (&vorbisenc->vd, 0);
762         gst_event_unref (event);
763         break;
764       case GST_EVENT_TAG:
765         if (vorbisenc->tags) {
766           gst_tag_list_merge (vorbisenc->tags, gst_event_tag_get_list (event), 
767                   gst_tag_setter_get_merge_mode (GST_TAG_SETTER (vorbisenc)));
768         } else {
769           g_assert_not_reached ();
770         }
771         gst_pad_event_default (pad, event);
772         return;
773       default:
774         gst_pad_event_default (pad, event);
775         return;
776     }
777   }
778   else {
779     gint16 *data;
780     gulong size;
781     gulong i, j;
782     float **buffer;
783
784     if (!vorbisenc->setup) {
785       gst_buffer_unref (buf);
786       GST_ELEMENT_ERROR (vorbisenc, CORE, NEGOTIATION, (NULL), ("encoder not initialized (input is not audio?)"));
787       return;
788     }
789
790     if (!vorbisenc->header_sent) {
791       gint result;
792       /* Vorbis streams begin with three headers; the initial header (with
793          most of the codec setup parameters) which is mandated by the Ogg
794          bitstream spec.  The second header holds any comment fields.  The
795          third header holds the bitstream codebook.  We merely need to
796          make the headers, then pass them to libvorbis one at a time;
797          libvorbis handles the additional Ogg bitstream constraints */
798       ogg_packet header;
799       ogg_packet header_comm;
800       ogg_packet header_code;
801
802       gst_vorbisenc_set_metadata (vorbisenc);
803       vorbis_analysis_headerout (&vorbisenc->vd, &vorbisenc->vc, &header, &header_comm, &header_code);
804       ogg_stream_packetin (&vorbisenc->os, &header); /* automatically placed in its own page */
805       ogg_stream_packetin (&vorbisenc->os, &header_comm);
806       ogg_stream_packetin (&vorbisenc->os, &header_code);
807
808       while ((result = ogg_stream_flush(&vorbisenc->os, &vorbisenc->og))) {
809         gst_vorbisenc_write_page (vorbisenc, &vorbisenc->og);
810       }
811       vorbisenc->header_sent = TRUE;
812     }
813   
814     /* data to encode */
815     data = (gint16 *) GST_BUFFER_DATA (buf);
816     size = GST_BUFFER_SIZE (buf) / (vorbisenc->channels * 2);
817
818     /* expose the buffer to submit data */
819     buffer = vorbis_analysis_buffer (&vorbisenc->vd, size);
820
821     /* uninterleave samples */
822     for (i = 0; i < size; i++) {
823       for (j = 0; j < vorbisenc->channels; j++) {
824         buffer[j][i] = data[i * vorbisenc->channels + j] / 32768.f;
825       }
826     }
827
828     /* tell the library how much we actually submitted */
829     vorbis_analysis_wrote (&vorbisenc->vd, size);
830
831     vorbisenc->samples_in += size;
832
833     gst_buffer_unref (buf);
834   }
835
836   /* vorbis does some data preanalysis, then divvies up blocks for
837      more involved (potentially parallel) processing.  Get a single
838      block for encoding now */
839   while (vorbis_analysis_blockout (&vorbisenc->vd, &vorbisenc->vb) == 1) {
840
841     /* analysis */
842     vorbis_analysis (&vorbisenc->vb, NULL);
843     vorbis_bitrate_addblock(&vorbisenc->vb);
844     
845     while (vorbis_bitrate_flushpacket (&vorbisenc->vd, &vorbisenc->op)) {
846
847       /* weld the packet into the bitstream */
848       ogg_stream_packetin (&vorbisenc->os, &vorbisenc->op);
849
850       /* write out pages (if any) */
851       while (!vorbisenc->eos) {
852         int result = ogg_stream_pageout (&vorbisenc->os, &vorbisenc->og);
853
854         if (result == 0)
855           break;
856
857         gst_vorbisenc_write_page (vorbisenc, &vorbisenc->og);
858
859         /* this could be set above, but for illustrative purposes, I do
860            it here (to show that vorbis does know where the stream ends) */
861         if (ogg_page_eos (&vorbisenc->og)) {
862           vorbisenc->eos = 1;
863         }
864       }
865     }
866   }
867
868   if (vorbisenc->eos) {
869     /* clean up and exit.  vorbis_info_clear() must be called last */
870     ogg_stream_clear (&vorbisenc->os);
871     vorbis_block_clear (&vorbisenc->vb);
872     vorbis_dsp_clear (&vorbisenc->vd);
873     vorbis_info_clear (&vorbisenc->vi);
874     gst_pad_push (vorbisenc->srcpad, GST_DATA (gst_event_new (GST_EVENT_EOS)));
875     gst_element_set_eos (GST_ELEMENT (vorbisenc));
876   }
877 }
878
879 static void
880 gst_vorbisenc_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec)
881 {
882   VorbisEnc *vorbisenc;
883
884   /* it's not null if we got it, but it might not be ours */
885   g_return_if_fail (GST_IS_VORBISENC (object));
886
887   vorbisenc = GST_VORBISENC (object);
888
889   switch (prop_id) {
890     case ARG_MAX_BITRATE:
891       g_value_set_int (value, vorbisenc->max_bitrate);
892       break;
893     case ARG_BITRATE:
894       g_value_set_int (value, vorbisenc->bitrate);
895       break;
896     case ARG_MIN_BITRATE:
897       g_value_set_int (value, vorbisenc->min_bitrate);
898       break;
899     case ARG_QUALITY:
900       g_value_set_float (value, vorbisenc->quality);
901       break;
902     case ARG_SERIAL:
903       g_value_set_int (value, vorbisenc->serial);
904       break;
905     case ARG_MANAGED:
906       g_value_set_boolean (value, vorbisenc->managed);
907       break;
908     case ARG_LAST_MESSAGE:
909       g_value_set_string (value, vorbisenc->last_message);
910       break;
911     default:
912       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
913       break;
914   }
915 }
916
917 static void
918 gst_vorbisenc_set_property (GObject * object, guint prop_id, const GValue * value,
919                             GParamSpec * pspec)
920 {
921   VorbisEnc *vorbisenc;
922
923   /* it's not null if we got it, but it might not be ours */
924   g_return_if_fail (GST_IS_VORBISENC (object));
925
926   vorbisenc = GST_VORBISENC (object);
927
928   switch (prop_id) {
929     case ARG_MAX_BITRATE:
930     {
931       gboolean old_value = vorbisenc->managed;
932
933       vorbisenc->max_bitrate = g_value_get_int (value);
934       if (vorbisenc->min_bitrate > 0 && vorbisenc->max_bitrate > 0)
935         vorbisenc->managed = TRUE;
936       else
937         vorbisenc->managed = FALSE;
938
939       if (old_value != vorbisenc->managed)
940         g_object_notify (object, "managed");
941       break;
942     }
943     case ARG_BITRATE:
944       vorbisenc->bitrate = g_value_get_int (value);
945       break;
946     case ARG_MIN_BITRATE:
947     {
948       gboolean old_value = vorbisenc->managed;
949
950       vorbisenc->min_bitrate = g_value_get_int (value);
951       if (vorbisenc->min_bitrate > 0 && vorbisenc->max_bitrate > 0)
952         vorbisenc->managed = TRUE;
953       else
954         vorbisenc->managed = FALSE;
955
956       if (old_value != vorbisenc->managed)
957         g_object_notify (object, "managed");
958       break;
959     }
960     case ARG_QUALITY:
961       vorbisenc->quality = g_value_get_float (value);
962       if (vorbisenc->quality >= 0.0)
963         vorbisenc->quality_set = TRUE;
964       else
965         vorbisenc->quality_set = FALSE;
966       break;
967     case ARG_SERIAL:
968       vorbisenc->serial = g_value_get_int (value);
969       break;
970     case ARG_MANAGED:
971       vorbisenc->managed = g_value_get_boolean (value);
972       break;
973     default:
974       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
975       break;
976   }
977 }
978
979 static GstElementStateReturn
980 gst_vorbisenc_change_state (GstElement *element)
981 {
982   VorbisEnc *vorbisenc = GST_VORBISENC (element);
983     
984   switch (GST_STATE_TRANSITION (element)) {
985     case GST_STATE_NULL_TO_READY:
986     case GST_STATE_READY_TO_PAUSED:
987       vorbisenc->eos = FALSE;
988       break;
989     case GST_STATE_PAUSED_TO_PLAYING:
990     case GST_STATE_PLAYING_TO_PAUSED:
991       break;
992     case GST_STATE_PAUSED_TO_READY:
993       vorbisenc->setup = FALSE;
994       vorbisenc->header_sent = FALSE;
995       gst_tag_list_free (vorbisenc->tags);
996       vorbisenc->tags = gst_tag_list_new ();
997       break;
998     case GST_STATE_READY_TO_NULL:
999     default:
1000       break;
1001   }
1002
1003   if (GST_ELEMENT_CLASS (parent_class)->change_state)
1004     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
1005
1006   return GST_STATE_SUCCESS;
1007 }
1008