Fix tiny caps error in lame caps - mpegversion(1) was missing
[platform/upstream/gst-plugins-good.git] / ext / lame / gstlame.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 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 #include "string.h"
24 #include "gstlame.h"
25
26 /* elementfactory information */
27 static GstElementDetails gst_lame_details = 
28 {
29   "L.A.M.E. mp3 encoder",
30   "Codec/Audio/Encoder",
31   "LGPL",
32   "High-quality free MP3 encoder",
33   VERSION,
34   "Erik Walthinsen <omega@cse.ogi.edu>",
35   "(C) 2000",
36 };
37
38 GST_PAD_TEMPLATE_FACTORY (gst_lame_sink_factory,
39   "sink",
40   GST_PAD_SINK,
41   GST_PAD_ALWAYS,
42   GST_CAPS_NEW (
43     "gstlame_sink",
44     "audio/x-raw-int",
45       "endianness", GST_PROPS_INT (G_BYTE_ORDER),
46       "signed",     GST_PROPS_BOOLEAN (TRUE),
47       "width",      GST_PROPS_INT (16),
48       "depth",      GST_PROPS_INT (16),
49       "rate",       GST_PROPS_LIST (
50                       GST_PROPS_INT (8000), 
51                       GST_PROPS_INT (11025), 
52                       GST_PROPS_INT (12000), 
53                       GST_PROPS_INT (16000), 
54                       GST_PROPS_INT (22050),
55                       GST_PROPS_INT (24000),
56                       GST_PROPS_INT (32000),
57                       GST_PROPS_INT (44100),
58                       GST_PROPS_INT (48000)
59                     ),
60       "channels",   GST_PROPS_INT_RANGE (1, 2)
61   )
62 )
63
64 GST_PAD_TEMPLATE_FACTORY (gst_lame_src_factory,
65   "src",
66   GST_PAD_SRC,
67   GST_PAD_ALWAYS,
68   GST_CAPS_NEW (
69     "gstlame_src",
70     "audio/mpeg",
71       "mpegversion", GST_PROPS_INT (1),
72       "layer",      GST_PROPS_INT (3),
73       "rate",       GST_PROPS_LIST (
74                       GST_PROPS_INT (8000), 
75                       GST_PROPS_INT (11025), 
76                       GST_PROPS_INT (12000), 
77                       GST_PROPS_INT (16000), 
78                       GST_PROPS_INT (22050),
79                       GST_PROPS_INT (24000),
80                       GST_PROPS_INT (32000),
81                       GST_PROPS_INT (44100),
82                       GST_PROPS_INT (48000)
83                     ),
84       "channels",   GST_PROPS_INT_RANGE (1, 2)
85   )
86 )
87
88 /********** Define useful types for non-programmatic interfaces **********/
89 #define GST_TYPE_LAME_MODE (gst_lame_mode_get_type())
90 static GType
91 gst_lame_mode_get_type (void)
92 {
93   static GType lame_mode_type = 0;
94   static GEnumValue lame_modes[] = {
95     { 0, "0", "Stereo" },
96     { 1, "1", "Joint-Stereo" },
97     { 2, "2", "Dual channel" },
98     { 3, "3", "Mono" },
99     { 4, "4", "Auto" },
100     { 0, NULL, NULL },
101   };
102   if (!lame_mode_type) {
103     lame_mode_type = g_enum_register_static ("GstLameMode", lame_modes);
104   }
105   return lame_mode_type;
106 }
107
108 #define GST_TYPE_LAME_QUALITY (gst_lame_quality_get_type())
109 static GType
110 gst_lame_quality_get_type (void)
111 {
112   static GType lame_quality_type = 0;
113   static GEnumValue lame_quality[] = {
114     { 0, "0", "0 - Best" },
115     { 1, "1", "1" },
116     { 2, "2", "2" },
117     { 3, "3", "3" },
118     { 4, "4", "4" },
119     { 5, "5", "5 - Default" },
120     { 6, "6", "6" },
121     { 7, "7", "7" },
122     { 8, "8", "8" },
123     { 9, "9", "9 - Worst" },
124     { 0, NULL, NULL },
125   };
126   if (!lame_quality_type) {
127     lame_quality_type = g_enum_register_static ("GstLameQuality", lame_quality);
128   }
129   return lame_quality_type;
130 }
131
132 #define GST_TYPE_LAME_PADDING (gst_lame_padding_get_type())
133 static GType
134 gst_lame_padding_get_type (void)
135 {
136   static GType lame_padding_type = 0;
137   static GEnumValue lame_padding[] = {
138     { 0, "0", "No Padding" },
139     { 1, "1", "Always Pad" },
140     { 2, "2", "Adjust Padding" },
141     { 0, NULL, NULL },
142   };
143   if (!lame_padding_type) {
144     lame_padding_type = g_enum_register_static ("GstLamePadding", lame_padding);
145   }
146   return lame_padding_type;
147 }
148
149 /********** Standard stuff for signals and arguments **********/
150 /* GstLame signals and args */
151 enum {
152   /* FILL_ME */
153   LAST_SIGNAL
154 };
155
156 enum {
157   ARG_0,
158   ARG_BITRATE,
159   ARG_COMPRESSION_RATIO,
160   ARG_QUALITY,
161   ARG_MODE,
162   ARG_FORCE_MS,
163   ARG_FREE_FORMAT,
164   ARG_COPYRIGHT,
165   ARG_ORIGINAL,
166   ARG_ERROR_PROTECTION,
167   ARG_PADDING_TYPE,
168   ARG_EXTENSION,
169   ARG_STRICT_ISO,
170   ARG_DISABLE_RESERVOIR,
171   ARG_VBR,
172   ARG_VBR_MEAN_BITRATE,
173   ARG_VBR_MIN_BITRATE,
174   ARG_VBR_MAX_BITRATE,
175   ARG_VBR_HARD_MIN,
176   ARG_LOWPASS_FREQ,
177   ARG_LOWPASS_WIDTH,
178   ARG_HIGHPASS_FREQ,
179   ARG_HIGHPASS_WIDTH,
180   ARG_ATH_ONLY,
181   ARG_ATH_SHORT,
182   ARG_NO_ATH,
183   ARG_ATH_LOWER,
184   ARG_CWLIMIT,
185   ARG_ALLOW_DIFF_SHORT,
186   ARG_NO_SHORT_BLOCKS,
187   ARG_EMPHASIS,
188   ARG_METADATA,
189 };
190
191
192 static void                     gst_lame_class_init     (GstLameClass *klass);
193 static void                     gst_lame_init           (GstLame *gst_lame);
194
195 static void                     gst_lame_set_property   (GObject *object, guint prop_id, 
196                                                          const GValue *value, GParamSpec *pspec);
197 static void                     gst_lame_get_property   (GObject *object, guint prop_id, 
198                                                          GValue *value, GParamSpec *pspec);
199 static void                     gst_lame_chain          (GstPad *pad, GstBuffer *buf);
200 static gboolean                 gst_lame_setup          (GstLame *lame);
201 static GstElementStateReturn    gst_lame_change_state   (GstElement *element);
202
203 static GstElementClass *parent_class = NULL;
204 /* static guint gst_lame_signals[LAST_SIGNAL] = { 0 }; */
205
206 GType
207 gst_lame_get_type (void)
208 {
209   static GType gst_lame_type = 0;
210
211   if (!gst_lame_type) {
212     static const GTypeInfo gst_lame_info = {
213       sizeof (GstLameClass),      
214       NULL,
215       NULL,
216       (GClassInitFunc) gst_lame_class_init,
217       NULL,
218       NULL,
219       sizeof(GstLame),
220       0,
221       (GInstanceInitFunc) gst_lame_init,
222     };
223     gst_lame_type = g_type_register_static (GST_TYPE_ELEMENT, "GstLame", &gst_lame_info, 0);
224   }
225   return gst_lame_type;
226 }
227
228 static void
229 gst_lame_class_init (GstLameClass *klass)
230 {
231   GObjectClass *gobject_class;
232   GstElementClass *gstelement_class;
233
234   gobject_class = (GObjectClass*)klass;
235   gstelement_class = (GstElementClass*)klass;
236
237   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
238
239   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BITRATE,
240     g_param_spec_int("bitrate", "Bitrate (kb/s)", "Bitrate in kbit/sec",
241                      8, 320, 128, G_PARAM_READWRITE)); 
242   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_COMPRESSION_RATIO,
243     g_param_spec_float ("compression_ratio", "Compression Ratio",
244                         "choose bitrate to achive selected compression ratio",
245                         1.0, 200.0, 11.0, G_PARAM_READWRITE));
246   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QUALITY,
247     g_param_spec_enum ("quality", "Quality", "Encoding Quality",
248                        GST_TYPE_LAME_QUALITY, 5, G_PARAM_READWRITE));
249   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MODE,
250     g_param_spec_enum ("mode", "Mode", "Encoding mode",
251                        GST_TYPE_LAME_MODE, 0, G_PARAM_READWRITE));
252   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FORCE_MS,
253     g_param_spec_boolean ("force_ms","Force ms","Force ms_stereo on all frames",
254                           TRUE, G_PARAM_READWRITE));
255   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FREE_FORMAT,
256     g_param_spec_boolean ("free_format","Free format","Produce a free format bitstream",
257                           TRUE, G_PARAM_READWRITE));
258   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_COPYRIGHT,
259     g_param_spec_boolean ("copyright","Copyright","Mark as copyright",
260                           TRUE, G_PARAM_READWRITE));
261   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_ORIGINAL,
262     g_param_spec_boolean("original", "Original", "Mark as non-original",
263                          TRUE, G_PARAM_READWRITE));
264   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ERROR_PROTECTION,
265     g_param_spec_boolean ("error_protection","Error protection",
266                           "Adds 16 bit checksum to every frame",
267                           TRUE, G_PARAM_READWRITE));
268   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PADDING_TYPE,
269     g_param_spec_enum ("padding_type", "Padding type", "Padding type",
270                        GST_TYPE_LAME_PADDING, 0, G_PARAM_READWRITE));
271   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_EXTENSION,
272     g_param_spec_boolean ("extension", "Extension", "Extension",
273                           TRUE, G_PARAM_READWRITE));
274   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_STRICT_ISO,
275     g_param_spec_boolean ("strict_iso", "Strict ISO",
276                           "Comply as much as possible to ISO MPEG spec",
277                           TRUE, G_PARAM_READWRITE));
278   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DISABLE_RESERVOIR,
279     g_param_spec_boolean ("disable_reservoir", "Disable reservoir", "Disable the bit reservoir",
280                           TRUE, G_PARAM_READWRITE));
281   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_VBR,
282     g_param_spec_boolean ("vbr", "VBR", "Use variable bitrate",
283                           TRUE, G_PARAM_READWRITE));
284   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_VBR_MEAN_BITRATE,
285     g_param_spec_int ("vbr_mean_bitrate", "VBR mean bitrate", "Specify mean bitrate",
286                       0, G_MAXINT, 0, G_PARAM_READWRITE));
287   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_VBR_MIN_BITRATE,
288     g_param_spec_int ("vbr_min_bitrate", "VBR min bitrate", "Specify min bitrate",
289                       0, G_MAXINT, 0, G_PARAM_READWRITE));
290   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_VBR_MAX_BITRATE,
291     g_param_spec_int ("vbr_max_bitrate", "VBR max bitrate", "Specify max bitrate",
292                       0, G_MAXINT, 0, G_PARAM_READWRITE));
293   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_VBR_HARD_MIN,
294     g_param_spec_int ("vbr_hard_min", "VBR hard min", "Specify hard min bitrate",
295                       0, G_MAXINT, 0, G_PARAM_READWRITE));
296   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOWPASS_FREQ,
297     g_param_spec_int ("lowpass_freq", "Lowpass freq", 
298                         "frequency(kHz), lowpass filter cutoff above freq",
299                         0, 50000, 0, G_PARAM_READWRITE));
300   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOWPASS_WIDTH,
301     g_param_spec_int ("lowpass_width", "Lowpass width", 
302                       "frequency(kHz) - default 15% of lowpass freq",
303                       0, G_MAXINT, 0, G_PARAM_READWRITE)); 
304   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HIGHPASS_FREQ,
305     g_param_spec_int ("highpass_freq", "Highpass freq", 
306                       "frequency(kHz), highpass filter cutoff below freq",
307                       0, 50000, 0, G_PARAM_READWRITE));
308   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HIGHPASS_WIDTH,
309     g_param_spec_int ("highpass_width", "Highpass width",
310                       "frequency(kHz) - default 15% of highpass freq",
311                       0, G_MAXINT, 0, G_PARAM_READWRITE));
312   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ATH_ONLY,
313     g_param_spec_boolean ("ath_only", "ATH only", 
314                           "Ignore GPSYCHO completely, use ATH only",
315                           TRUE, G_PARAM_READWRITE));
316   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ATH_SHORT,
317     g_param_spec_boolean ("ath_short", "ATH short", 
318                           "Ignore GPSYCHO for short blocks, use ATH only",
319                           TRUE, G_PARAM_READWRITE));
320   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NO_ATH,
321     g_param_spec_boolean ("no_ath", "No ath", "turns ATH down to a flat noise floor",
322                           TRUE, G_PARAM_READWRITE));
323   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ATH_LOWER,
324     g_param_spec_int ("ath_lower", "ATH lower", "lowers ATH by x dB",
325                       G_MININT, G_MAXINT, 0, G_PARAM_READWRITE));
326   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_CWLIMIT,
327     g_param_spec_int ("cwlimit", "Cwlimit", "Compute tonality up to freq (in kHz) default 8.8717",
328                       0, 50000, 0, G_PARAM_READWRITE));
329   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ALLOW_DIFF_SHORT,
330     g_param_spec_boolean ("allow_diff_short", "Allow diff short", "Allow diff short",
331                           TRUE, G_PARAM_READWRITE)); 
332   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NO_SHORT_BLOCKS,
333     g_param_spec_boolean ("no_short_blocks", "No short blocks", "Do not use short blocks",
334                           TRUE, G_PARAM_READWRITE));
335   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_EMPHASIS,
336     g_param_spec_boolean ("emphasis", "Emphasis", "Emphasis",
337                           TRUE, G_PARAM_READWRITE));
338
339   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_METADATA,
340     g_param_spec_boxed ("metadata", "Metadata", "Metadata to add to the stream,",
341             GST_TYPE_CAPS, G_PARAM_READWRITE));
342
343
344   gobject_class->set_property = gst_lame_set_property;
345   gobject_class->get_property = gst_lame_get_property;
346
347   gstelement_class->change_state = gst_lame_change_state;
348 }
349
350 static GstPadLinkReturn
351 gst_lame_sinkconnect (GstPad *pad, GstCaps *caps)
352 {
353   GstLame *lame;
354
355   lame = GST_LAME (gst_pad_get_parent (pad));
356
357   if (!GST_CAPS_IS_FIXED (caps)) {
358     GST_DEBUG ("caps on lame pad %s:%s not fixed, delayed",
359                GST_DEBUG_PAD_NAME (pad));
360     return GST_PAD_LINK_DELAYED;
361   }
362
363   gst_caps_get_int (caps, "rate", &lame->samplerate);
364   gst_caps_get_int (caps, "channels", &lame->num_channels);
365
366   if (!gst_lame_setup (lame)) {
367     gst_element_error (GST_ELEMENT (lame), 
368                        "could not initialize encoder (wrong parameters?)");
369     return GST_PAD_LINK_REFUSED;
370   }
371
372   caps = GST_CAPS_NEW ("lame_src_caps",
373                        "audio/mpeg",
374                          "mpegversion", GST_PROPS_INT (1),
375                          "layer",    GST_PROPS_INT (3),
376                          "channels", GST_PROPS_INT (lame->num_channels),
377                          "rate",     GST_PROPS_INT (lame->samplerate));
378
379   return gst_pad_try_set_caps (lame->srcpad, caps);
380 }
381
382 static void
383 gst_lame_init (GstLame *lame)
384 {
385   GST_DEBUG_OBJECT (lame, "starting initialization");
386
387   lame->sinkpad = gst_pad_new_from_template (GST_PAD_TEMPLATE_GET (gst_lame_sink_factory), "sink");
388   gst_element_add_pad (GST_ELEMENT (lame), lame->sinkpad);
389   gst_pad_set_chain_function (lame->sinkpad, gst_lame_chain);
390   gst_pad_set_link_function (lame->sinkpad, gst_lame_sinkconnect);
391
392   lame->srcpad = gst_pad_new_from_template (GST_PAD_TEMPLATE_GET (gst_lame_src_factory), "src");
393   gst_element_add_pad (GST_ELEMENT (lame), lame->srcpad);
394
395   GST_FLAG_SET (lame, GST_ELEMENT_EVENT_AWARE);
396
397   GST_DEBUG ("setting up lame encoder");
398   lame->lgf = lame_init ();
399
400   lame->samplerate = 44100;
401   lame->num_channels = 2;
402   lame->initialized = FALSE;
403
404   lame->bitrate = lame_get_brate (lame->lgf);
405   lame->compression_ratio = lame_get_compression_ratio (lame->lgf);
406   lame->quality = lame_get_quality (lame->lgf);
407   lame->mode = lame_get_mode (lame->lgf);
408   lame->force_ms = lame_get_force_ms (lame->lgf);
409   lame->free_format = lame_get_free_format (lame->lgf);
410   lame->copyright = lame_get_copyright (lame->lgf);
411   lame->original = lame_get_original (lame->lgf);
412   lame->error_protection = lame_get_error_protection (lame->lgf);
413   lame->padding_type = lame_get_padding_type (lame->lgf);
414   lame->extension = lame_get_extension (lame->lgf);
415   lame->strict_iso = lame_get_strict_ISO (lame->lgf);
416   lame->disable_reservoir = lame_get_disable_reservoir (lame->lgf);
417   lame->vbr = lame_get_VBR_q (lame->lgf);
418   lame->vbr_mean_bitrate = lame_get_VBR_mean_bitrate_kbps (lame->lgf);
419   lame->vbr_min_bitrate = lame_get_VBR_min_bitrate_kbps (lame->lgf);
420   lame->vbr_max_bitrate = lame_get_VBR_max_bitrate_kbps (lame->lgf);
421   lame->vbr_hard_min = lame_get_VBR_hard_min (lame->lgf);
422   lame->lowpass_freq = lame_get_lowpassfreq (lame->lgf);
423   lame->lowpass_width = lame_get_lowpasswidth (lame->lgf);
424   lame->highpass_freq = lame_get_highpassfreq (lame->lgf);
425   lame->highpass_width = lame_get_highpasswidth (lame->lgf);
426   lame->ath_only = lame_get_ATHonly (lame->lgf);
427   lame->ath_short = lame_get_ATHshort (lame->lgf);
428   lame->no_ath = lame_get_noATH (lame->lgf);
429   /*  lame->ath_type = lame_get_ATHtype (lame->lgf); */
430   lame->ath_lower = lame_get_ATHlower (lame->lgf);
431   lame->cwlimit = lame_get_cwlimit (lame->lgf);
432   lame->allow_diff_short = lame_get_allow_diff_short (lame->lgf);
433   lame->no_short_blocks = lame_get_no_short_blocks (lame->lgf);
434   lame->emphasis = lame_get_emphasis (lame->lgf);
435
436   lame->metadata = GST_CAPS_NEW (
437       "lame_metadata",
438       "application/x-gst-metadata",
439       "comment",     GST_PROPS_STRING ("Track encoded with GStreamer"),
440       "year",        GST_PROPS_STRING (""),
441       "tracknumber", GST_PROPS_STRING (""),
442       "title",       GST_PROPS_STRING (""),
443       "artist",      GST_PROPS_STRING (""),
444       "album",       GST_PROPS_STRING (""),
445       "genre",       GST_PROPS_STRING ("")
446   );
447
448   id3tag_init (lame->lgf);
449   
450   GST_DEBUG_OBJECT (lame, "done initializing");
451 }
452
453 static void
454 gst_lame_add_metadata (GstLame *lame, GstCaps *caps)
455 {
456   GList *props;
457   GstPropsEntry *prop;
458
459   if (caps == NULL)
460     return;
461
462   props = gst_caps_get_props (caps)->properties;
463   while (props) {
464     prop = (GstPropsEntry*)(props->data);
465     props = g_list_next(props);
466
467     if (gst_props_entry_get_props_type (prop) == GST_PROPS_STRING_TYPE) {
468       const gchar *name = gst_props_entry_get_name (prop);
469       const gchar *value;
470
471       gst_props_entry_get_string (prop, &value);
472
473       if (!value || strlen (value) == 0)
474         continue;
475
476       if (strcmp (name, "comment") == 0) {
477         id3tag_set_comment (lame->lgf, value);
478       } else if (strcmp (name, "date") == 0) {
479         id3tag_set_year (lame->lgf, value);
480       } else if (strcmp (name, "tracknumber") == 0) {
481         id3tag_set_track (lame->lgf, value);
482       } else if (strcmp (name, "title") == 0) {
483         id3tag_set_title (lame->lgf, value);
484       } else if (strcmp (name, "artist") == 0) {
485         id3tag_set_artist (lame->lgf, value);
486       } else if (strcmp (name, "album") == 0) {
487         id3tag_set_album (lame->lgf, value);
488       } else if (strcmp (name, "genre") == 0) {
489         id3tag_set_genre (lame->lgf, value);
490       }
491     }
492   }
493 }
494
495 static void
496 gst_lame_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
497 {
498   GstLame *lame;
499
500   /* it's not null if we got it, but it might not be ours */
501   g_return_if_fail (GST_IS_LAME (object));
502
503   lame = GST_LAME (object);
504
505   switch (prop_id) {
506     case ARG_BITRATE:
507       lame->bitrate = g_value_get_int (value);
508       break;
509     case ARG_COMPRESSION_RATIO:
510       lame->compression_ratio = g_value_get_float (value);
511       break;
512     case ARG_QUALITY:
513       lame->quality = g_value_get_enum (value);
514       break;
515     case ARG_MODE:
516       lame->mode = g_value_get_enum (value);
517       break;
518     case ARG_FORCE_MS:
519       lame->force_ms = g_value_get_boolean (value);
520       break;
521     case ARG_FREE_FORMAT:
522       lame->free_format = g_value_get_boolean (value);
523       break;
524     case ARG_COPYRIGHT:
525       lame->copyright = g_value_get_boolean (value);
526       break;
527     case ARG_ORIGINAL:
528       lame->original = g_value_get_boolean (value);
529       break;
530     case ARG_ERROR_PROTECTION:
531       lame->error_protection = g_value_get_boolean (value);
532       break;
533     case ARG_PADDING_TYPE:
534       lame->padding_type = g_value_get_int (value);
535       break;
536     case ARG_EXTENSION:
537       lame->extension = g_value_get_boolean (value);
538       break;
539     case ARG_STRICT_ISO:
540       lame->strict_iso = g_value_get_boolean (value);
541       break;
542     case ARG_DISABLE_RESERVOIR:
543       lame->disable_reservoir = g_value_get_boolean (value);
544       break;
545     case ARG_VBR:
546       lame->vbr = g_value_get_boolean (value);
547       break;
548     case ARG_VBR_MEAN_BITRATE:
549       lame->vbr_mean_bitrate = g_value_get_int (value);
550       break;
551     case ARG_VBR_MIN_BITRATE:
552       lame->vbr_min_bitrate = g_value_get_int (value);
553       break;
554     case ARG_VBR_MAX_BITRATE:
555       lame->vbr_max_bitrate = g_value_get_int (value);
556       break;
557     case ARG_VBR_HARD_MIN:
558       lame->vbr_hard_min = g_value_get_int (value);
559       break;
560     case ARG_LOWPASS_FREQ:
561       lame->lowpass_freq = g_value_get_int (value);
562       break;
563     case ARG_LOWPASS_WIDTH:
564       lame->lowpass_width = g_value_get_int (value);
565       break;
566     case ARG_HIGHPASS_FREQ:
567       lame->highpass_freq = g_value_get_int (value);
568       break;
569     case ARG_HIGHPASS_WIDTH:
570       lame->highpass_width = g_value_get_int (value);
571       break;
572     case ARG_ATH_ONLY:
573       lame->ath_only = g_value_get_boolean (value);
574       break;
575     case ARG_ATH_SHORT:
576       lame->ath_short = g_value_get_boolean (value);
577       break;
578     case ARG_NO_ATH:
579       lame->no_ath = g_value_get_boolean (value);
580       break;
581     case ARG_ATH_LOWER:
582       lame->ath_lower = g_value_get_int (value);
583       break;
584     case ARG_CWLIMIT:
585       lame->cwlimit = g_value_get_int (value);
586       break;
587     case ARG_ALLOW_DIFF_SHORT:
588       lame->allow_diff_short = g_value_get_boolean (value);
589       break;
590     case ARG_NO_SHORT_BLOCKS:
591       lame->no_short_blocks = g_value_get_boolean (value);
592       break;
593     case ARG_EMPHASIS:
594       lame->emphasis = g_value_get_boolean (value);
595       break;
596     case ARG_METADATA:
597       lame->metadata = g_value_get_boxed (value);
598       break;
599     default:
600       break;
601   }
602
603 }
604
605 static void
606 gst_lame_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
607 {
608   GstLame *lame;
609
610   /* it's not null if we got it, but it might not be ours */
611   g_return_if_fail (GST_IS_LAME (object));
612
613   lame = GST_LAME (object);
614
615   switch (prop_id) {
616     case ARG_BITRATE:
617       g_value_set_int (value, lame->bitrate);
618       break;
619     case ARG_COMPRESSION_RATIO:
620       g_value_set_float (value, lame->compression_ratio);
621       break;
622     case ARG_QUALITY:
623       g_value_set_enum (value, lame->quality);
624       break;
625     case ARG_MODE:
626       g_value_set_enum (value, lame->mode);
627       break;
628     case ARG_FORCE_MS:
629       g_value_set_boolean (value, lame->force_ms);
630       break;
631     case ARG_FREE_FORMAT:
632       g_value_set_boolean (value, lame->free_format);
633       break;
634     case ARG_COPYRIGHT:
635       g_value_set_boolean (value, lame->copyright);
636       break;
637     case ARG_ORIGINAL:
638       g_value_set_boolean (value, lame->original);
639       break;
640     case ARG_ERROR_PROTECTION:
641       g_value_set_boolean (value, lame->error_protection);
642       break;
643     case ARG_PADDING_TYPE:
644       g_value_set_enum (value, lame->padding_type);
645       break;
646     case ARG_EXTENSION:
647       g_value_set_boolean (value, lame->extension);
648       break;
649     case ARG_STRICT_ISO:
650       g_value_set_boolean (value, lame->strict_iso);
651       break;
652     case ARG_DISABLE_RESERVOIR:
653       g_value_set_boolean (value, lame->disable_reservoir);
654       break;
655     case ARG_VBR:
656       g_value_set_boolean (value, lame->vbr);
657       break;
658     case ARG_VBR_MEAN_BITRATE:
659       g_value_set_int (value, lame->vbr_mean_bitrate);
660       break;
661     case ARG_VBR_MIN_BITRATE:
662       g_value_set_int (value, lame->vbr_min_bitrate);
663       break;
664     case ARG_VBR_MAX_BITRATE:
665       g_value_set_int (value, lame->vbr_max_bitrate);
666       break;
667     case ARG_VBR_HARD_MIN:
668       g_value_set_int (value, lame->vbr_hard_min);
669       break;
670     case ARG_LOWPASS_FREQ:
671       g_value_set_int (value, lame->lowpass_freq);
672       break;
673     case ARG_LOWPASS_WIDTH:
674       g_value_set_int (value, lame->lowpass_width);
675       break;
676     case ARG_HIGHPASS_FREQ:
677       g_value_set_int (value, lame->highpass_freq);
678       break;
679     case ARG_HIGHPASS_WIDTH:
680       g_value_set_int (value, lame->highpass_width);
681       break;
682     case ARG_ATH_ONLY:
683       g_value_set_boolean (value, lame->ath_only);
684       break;
685     case ARG_ATH_SHORT:
686       g_value_set_boolean (value, lame->ath_short);
687       break;
688     case ARG_NO_ATH:
689       g_value_set_boolean (value, lame->no_ath);
690       break;
691     case ARG_ATH_LOWER:
692       g_value_set_int (value, lame->ath_lower);
693       break;
694     case ARG_CWLIMIT:
695       g_value_set_int (value, lame->cwlimit);
696       break;
697     case ARG_ALLOW_DIFF_SHORT:
698       g_value_set_boolean (value, lame->allow_diff_short);
699       break;
700     case ARG_NO_SHORT_BLOCKS:
701       g_value_set_boolean (value, lame->no_short_blocks);
702       break;
703     case ARG_EMPHASIS:
704       g_value_set_boolean (value, lame->emphasis);
705       break;
706     case ARG_METADATA:
707       g_value_set_static_boxed (value, lame->metadata);
708       break;
709     default:
710       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
711       break;
712   }
713 }
714
715 static void
716 gst_lame_chain (GstPad *pad, GstBuffer *buf)
717 {
718   GstLame *lame;
719   GstBuffer *outbuf;
720   gchar *mp3_data = NULL;
721   gint mp3_buffer_size, mp3_size = 0;
722   gboolean eos = FALSE;
723
724   lame = GST_LAME (gst_pad_get_parent (pad));
725
726   GST_DEBUG ("entered chain");
727
728   if (GST_IS_EVENT (buf)) {
729     switch (GST_EVENT_TYPE (buf)) {
730       case GST_EVENT_EOS:
731         eos = TRUE;
732       case GST_EVENT_FLUSH:
733         mp3_buffer_size = 7200;
734         mp3_data = g_malloc (mp3_buffer_size);
735
736         mp3_size = lame_encode_flush (lame->lgf, mp3_data, mp3_buffer_size);
737         gst_event_unref (GST_EVENT (buf));
738         break;  
739       default:
740         gst_pad_event_default (pad, GST_EVENT (buf));
741         break;
742     }
743   }
744   else {
745     gint64 duration;
746
747     if (!lame->initialized) {
748       gst_buffer_unref (buf);
749       gst_element_error (GST_ELEMENT (lame), "encoder not initialized (input is not audio?)");
750       return;
751     }
752
753     /* allocate space for output */
754     mp3_buffer_size = ((GST_BUFFER_SIZE(buf) / (2+lame->num_channels)) * 1.25) + 7200;
755     mp3_data = g_malloc (mp3_buffer_size);
756
757     if (lame->num_channels == 2) {
758       mp3_size = lame_encode_buffer_interleaved (lame->lgf, 
759                     (short int *) (GST_BUFFER_DATA (buf)),
760                     GST_BUFFER_SIZE (buf) / 4, 
761                     mp3_data, mp3_buffer_size);
762     }
763     else {
764       mp3_size = lame_encode_buffer (lame->lgf, 
765                     (short int *) (GST_BUFFER_DATA (buf)),
766                     (short int *) (GST_BUFFER_DATA (buf)),
767                     GST_BUFFER_SIZE (buf) / 2, 
768                     mp3_data, mp3_buffer_size);
769     }
770
771     GST_DEBUG (
772                "encoded %d bytes of audio to %d bytes of mp3", 
773                GST_BUFFER_SIZE (buf), mp3_size);
774
775     duration = (GST_SECOND * GST_BUFFER_SIZE (buf) /
776                 (2 * lame->samplerate * lame->num_channels));
777
778     if (GST_BUFFER_DURATION (buf) != GST_CLOCK_TIME_NONE &&
779         GST_BUFFER_DURATION (buf) != duration)
780       GST_DEBUG (
781                  "mad: incoming buffer had incorrect duration %lld, "
782                  "outgoing buffer will have correct duration %lld",
783                  GST_BUFFER_DURATION (buf), duration);
784
785     if (lame->last_ts == GST_CLOCK_TIME_NONE) {
786       lame->last_ts       = GST_BUFFER_TIMESTAMP (buf);
787       lame->last_offs     = GST_BUFFER_OFFSET (buf);
788       lame->last_duration = duration;
789     } else {
790       lame->last_duration += duration;
791     }
792
793     gst_buffer_unref (buf);
794   }
795   
796   if (mp3_size > 0) {
797     outbuf = gst_buffer_new ();
798     GST_BUFFER_DATA (outbuf)      = mp3_data;
799     GST_BUFFER_SIZE (outbuf)      = mp3_size;
800     GST_BUFFER_TIMESTAMP (outbuf) = lame->last_ts;
801     GST_BUFFER_OFFSET (outbuf)    = lame->last_offs;
802     GST_BUFFER_DURATION (outbuf)  = lame->last_duration;
803
804     gst_pad_push (lame->srcpad,outbuf);
805
806     lame->last_ts = GST_CLOCK_TIME_NONE;
807   }
808   else { 
809     g_free (mp3_data);
810   }
811
812   if (eos) {
813     gst_pad_push (lame->srcpad, GST_BUFFER (gst_event_new (GST_EVENT_EOS)));
814     gst_element_set_eos (GST_ELEMENT (lame));
815   }
816 }
817
818 /* transition to the READY state by configuring the gst_lame encoder */
819 static gboolean
820 gst_lame_setup (GstLame *lame)
821 {
822   GST_DEBUG_OBJECT (lame, "starting setup");
823
824   /* check if we're already initialized; if we are, we might want to check
825    * if this initialization is compatible with the previous one */
826   /* FIXME: do this */
827   if (lame->initialized)
828     g_warning ("already initialized");
829
830   /* copy the parameters over */
831   lame_set_in_samplerate (lame->lgf, lame->samplerate);
832
833   /* force mono encoding if we only have one channel */
834   if (lame->num_channels == 1) 
835     lame->mode = 3;
836
837   lame_set_brate (lame->lgf, lame->bitrate);
838   lame_set_compression_ratio (lame->lgf, lame->compression_ratio);
839   lame_set_quality (lame->lgf, lame->quality);
840   lame_set_mode (lame->lgf, lame->mode);
841   lame_set_force_ms (lame->lgf, lame->force_ms);
842   lame_set_free_format (lame->lgf, lame->free_format);
843   lame_set_copyright (lame->lgf, lame->copyright);
844   lame_set_original (lame->lgf, lame->original);
845   lame_set_error_protection (lame->lgf, lame->error_protection);
846   lame_set_padding_type (lame->lgf, lame->padding_type);
847   lame_set_extension (lame->lgf, lame->extension);
848   lame_set_strict_ISO (lame->lgf, lame->strict_iso);
849   lame_set_disable_reservoir (lame->lgf, lame->disable_reservoir);
850   lame_set_VBR_q (lame->lgf, lame->vbr);
851   lame_set_VBR_mean_bitrate_kbps (lame->lgf, lame->vbr_mean_bitrate);
852   lame_set_VBR_min_bitrate_kbps (lame->lgf, lame->vbr_min_bitrate);
853   lame_set_VBR_max_bitrate_kbps (lame->lgf, lame->vbr_max_bitrate);
854   lame_set_VBR_hard_min (lame->lgf, lame->vbr_hard_min);
855   lame_set_lowpassfreq (lame->lgf, lame->lowpass_freq);
856   lame_set_lowpasswidth (lame->lgf, lame->lowpass_width);
857   lame_set_highpassfreq (lame->lgf, lame->highpass_freq);
858   lame_set_highpasswidth (lame->lgf, lame->highpass_width);
859   lame_set_ATHonly (lame->lgf, lame->ath_only);
860   lame_set_ATHshort (lame->lgf, lame->ath_short);
861   lame_set_noATH (lame->lgf, lame->no_ath);
862   lame_set_ATHlower (lame->lgf, lame->ath_lower);
863   lame_set_cwlimit (lame->lgf, lame->cwlimit);
864   lame_set_allow_diff_short (lame->lgf, lame->allow_diff_short);
865   lame_set_no_short_blocks (lame->lgf, lame->no_short_blocks);
866   lame_set_emphasis (lame->lgf, lame->emphasis);
867
868   gst_lame_add_metadata (lame, lame->metadata);
869
870   /* initialize the lame encoder */
871   if (lame_init_params (lame->lgf) < 0) {
872     lame->initialized = FALSE;
873   }
874   else {
875     lame->initialized = TRUE;
876     /* FIXME: it would be nice to print out the mode here */
877     GST_INFO ( 
878               "lame encoder initialized (%d kbit/s, %d Hz, %d channels)", 
879               lame->bitrate, lame->samplerate, lame->num_channels);
880   }
881
882   GST_DEBUG_OBJECT (lame, "done with setup");
883
884   return lame->initialized;
885 }
886
887 static GstElementStateReturn
888 gst_lame_change_state (GstElement *element)
889 {
890   GstLame *lame;
891   
892   g_return_val_if_fail (GST_IS_LAME (element), GST_STATE_FAILURE);
893
894   lame = GST_LAME (element);
895
896   GST_DEBUG ("state pending %d", GST_STATE_PENDING (element));
897
898   switch (GST_STATE_TRANSITION (element)) {
899     case GST_STATE_READY_TO_PAUSED:
900       lame->last_ts = GST_CLOCK_TIME_NONE;
901       break;
902     case GST_STATE_READY_TO_NULL:
903       if (lame->initialized) {
904         lame_close (lame->lgf);
905         lame->initialized = FALSE;
906       }
907       break;
908     default:
909       break;
910   }
911
912   /* if we haven't failed already, give the parent class a chance to ;-) */
913   if (GST_ELEMENT_CLASS (parent_class)->change_state)
914     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
915
916   return GST_STATE_SUCCESS;
917 }
918
919 static gboolean
920 plugin_init (GModule *module, GstPlugin *plugin)
921 {
922   GstElementFactory *factory;
923
924   /* create an elementfactory for the gst_lame element */
925   factory = gst_element_factory_new ("lame", GST_TYPE_LAME,
926                                     &gst_lame_details);
927   g_return_val_if_fail (factory != NULL, FALSE);
928
929   /* register the source's padtemplate */
930   gst_element_factory_add_pad_template (factory, 
931                 GST_PAD_TEMPLATE_GET (gst_lame_src_factory));
932
933   /* register the sink's padtemplate */
934   gst_element_factory_add_pad_template (factory, 
935                 GST_PAD_TEMPLATE_GET (gst_lame_sink_factory));
936
937   /* and add the gst_lame element factory to the plugin */
938   gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
939
940   return TRUE;
941 }
942
943 GstPluginDesc plugin_desc = {
944   GST_VERSION_MAJOR,
945   GST_VERSION_MINOR,
946   "lame",
947   plugin_init
948 };