Apply patch from jesimon@libertysurf.fr (Jeremy SIMON) in #122368.
[platform/upstream/gst-plugins-good.git] / ext / flac / gstflacenc.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
27 #include <gstflacenc.h>
28 #include <gst/tags/gsttagediting.h>
29 #include <gst/gsttaginterface.h>
30 #include "flac_compat.h"
31
32 static GstPadTemplate *src_template, *sink_template;
33
34 /* elementfactory information */
35 GstElementDetails flacenc_details = {
36   "FLAC encoder",
37   "Codec/Encoder/Audio",
38   "Encodes audio with the FLAC lossless audio encoder",
39   "Wim Taymans <wim.taymans@chello.be>",
40 };
41
42 /* FlacEnc signals and args */
43 enum {
44   /* FILL ME */
45   LAST_SIGNAL
46 };
47
48 enum {
49   ARG_0,
50   ARG_QUALITY,
51   ARG_STREAMABLE_SUBSET,
52   ARG_MID_SIDE_STEREO,
53   ARG_LOOSE_MID_SIDE_STEREO,
54   ARG_BLOCKSIZE,
55   ARG_MAX_LPC_ORDER,
56   ARG_QLP_COEFF_PRECISION,
57   ARG_QLP_COEFF_PREC_SEARCH,
58   ARG_ESCAPE_CODING,
59   ARG_EXHAUSTIVE_MODEL_SEARCH,
60   ARG_MIN_RESIDUAL_PARTITION_ORDER,
61   ARG_MAX_RESIDUAL_PARTITION_ORDER,
62   ARG_RICE_PARAMETER_SEARCH_DIST,
63 };
64
65 static void             gst_flacenc_base_init           (gpointer g_class);
66 static void             gst_flacenc_init                (FlacEnc *flacenc);
67 static void             gst_flacenc_class_init          (FlacEncClass *klass);
68 static void             gst_flacenc_dispose             (GObject *object);
69
70 static GstPadLinkReturn
71                         gst_flacenc_sinkconnect         (GstPad *pad, GstCaps *caps);
72 static void             gst_flacenc_chain               (GstPad *pad, GstData *_data);
73
74 static gboolean         gst_flacenc_update_quality      (FlacEnc *flacenc, gint quality);
75 static void             gst_flacenc_set_property        (GObject *object, guint prop_id, 
76                                                          const GValue *value, GParamSpec *pspec);
77 static void             gst_flacenc_get_property        (GObject *object, guint prop_id,
78                                                          GValue *value, GParamSpec *pspec);
79 static GstElementStateReturn
80                         gst_flacenc_change_state        (GstElement *element);
81
82 static FLAC__StreamEncoderWriteStatus 
83                         gst_flacenc_write_callback      (const FLAC__SeekableStreamEncoder *encoder, 
84                                                          const FLAC__byte buffer[], unsigned bytes, 
85                                                          unsigned samples, unsigned current_frame, 
86                                                          void *client_data);
87 static FLAC__SeekableStreamEncoderSeekStatus
88                         gst_flacenc_seek_callback       (const FLAC__SeekableStreamEncoder *encoder,
89                                                          FLAC__uint64 absolute_byte_offset,
90                                                          void *client_data);
91
92 static GstElementClass *parent_class = NULL;
93 /*static guint gst_flacenc_signals[LAST_SIGNAL] = { 0 }; */
94
95 GType
96 flacenc_get_type (void)
97 {
98   static GType flacenc_type = 0;
99
100   if (!flacenc_type) {
101     static const GTypeInfo flacenc_info = {
102       sizeof(FlacEncClass),
103       gst_flacenc_base_init,
104       NULL,
105       (GClassInitFunc)gst_flacenc_class_init,
106       NULL,
107       NULL,
108       sizeof(FlacEnc),
109       0,
110       (GInstanceInitFunc)gst_flacenc_init,
111     };
112
113     static const GInterfaceInfo tag_setter_info = {
114       NULL,
115       NULL,
116       NULL
117     };
118
119     flacenc_type = g_type_register_static (GST_TYPE_ELEMENT, "FlacEnc", &flacenc_info, 0);
120     g_type_add_interface_static (flacenc_type, GST_TYPE_TAG_SETTER, &tag_setter_info);
121   }
122   return flacenc_type;
123 }
124
125 typedef struct {
126   gboolean      exhaustive_model_search;
127   gboolean      escape_coding;
128   gboolean      mid_side;
129   gboolean      loose_mid_side;
130   guint         qlp_coeff_precision;
131   gboolean      qlp_coeff_prec_search;
132   guint         min_residual_partition_order;
133   guint         max_residual_partition_order;
134   guint         rice_parameter_search_dist;
135   guint         max_lpc_order;
136   guint         blocksize;
137 } FlacEncParams;
138
139 static const FlacEncParams flacenc_params[] = 
140 {
141   { FALSE, FALSE, FALSE, FALSE, 0, FALSE, 2, 2,  0, 0,  1152 },
142   { FALSE, FALSE, TRUE,  TRUE,  0, FALSE, 2, 2,  0, 0,  1152 },
143   { FALSE, FALSE, TRUE,  FALSE, 0, FALSE, 0, 3,  0, 0,  1152 },
144   { FALSE, FALSE, FALSE, FALSE, 0, FALSE, 3, 3,  0, 6,  4608 },
145   { FALSE, FALSE, TRUE,  TRUE,  0, FALSE, 3, 3,  0, 8,  4608 },
146   { FALSE, FALSE, TRUE,  FALSE, 0, FALSE, 3, 3,  0, 8,  4608 },
147   { FALSE, FALSE, TRUE,  FALSE, 0, FALSE, 0, 4,  0, 8,  4608 },
148   { TRUE,  FALSE, TRUE,  FALSE, 0, FALSE, 0, 6,  0, 8,  4608 },
149   { TRUE,  FALSE, TRUE,  FALSE, 0, FALSE, 0, 6,  0, 12, 4608 },
150   { TRUE,  TRUE,  TRUE,  FALSE, 0, FALSE, 0, 16, 0, 32, 4608 },
151 };
152
153 #define DEFAULT_QUALITY 5
154
155 #define GST_TYPE_FLACENC_QUALITY (gst_flacenc_quality_get_type ())
156 GType
157 gst_flacenc_quality_get_type (void)
158 {
159   static GType qtype = 0;
160   if (qtype == 0) {
161     static const GEnumValue values[] = {
162       { 0, "0", "0 - Fastest compression" },
163       { 1, "1", "1" },
164       { 2, "2", "2" },
165       { 3, "3", "3" },
166       { 4, "4", "4" },
167       { 5, "5", "5 - Default" },
168       { 6, "6", "6" },
169       { 7, "7", "7" },
170       { 8, "8", "8 - Highest compression " },
171       { 9, "9", "9 - Insane" },
172       { 0, NULL, NULL }
173     };
174     qtype = g_enum_register_static ("FlacEncQuality", values);
175   }
176   return qtype;
177 }
178
179 static GstCaps*
180 flac_caps_factory (void)
181 {
182   return
183    gst_caps_new (
184         "flac_flac",
185         "application/x-flac",
186         /* gst_props_new (
187             "rate",             GST_PROPS_INT_RANGE (11025, 48000),
188             "channels",         GST_PROPS_INT_RANGE (1, 2),
189             NULL) */NULL);
190 }
191
192 static GstCaps*
193 raw_caps_factory (void)
194 {
195   return
196    gst_caps_new (
197         "flac_raw",
198         "audio/x-raw-int",
199         gst_props_new (
200             "endianness",       GST_PROPS_INT (G_BYTE_ORDER),
201             "signed",           GST_PROPS_BOOLEAN (TRUE),
202             "width",            GST_PROPS_INT (16),
203             "depth",            GST_PROPS_INT (16),
204             "rate",             GST_PROPS_INT_RANGE (11025, 48000),
205             "channels",         GST_PROPS_INT_RANGE (1, 2),
206             NULL));
207 }
208
209 static void
210 gst_flacenc_base_init (gpointer g_class)
211 {
212   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
213   GstCaps *raw_caps, *flac_caps;
214
215   raw_caps = raw_caps_factory ();
216   flac_caps = flac_caps_factory ();
217   
218   sink_template = gst_pad_template_new ("sink", GST_PAD_SINK, 
219                                         GST_PAD_ALWAYS, 
220                                         raw_caps, NULL);
221   src_template = gst_pad_template_new ("src", GST_PAD_SRC, 
222                                        GST_PAD_ALWAYS, 
223                                        flac_caps, NULL);
224   gst_element_class_add_pad_template (element_class, sink_template);
225   gst_element_class_add_pad_template (element_class, src_template);
226   gst_element_class_set_details (element_class, &flacenc_details);
227 }
228
229 static void
230 gst_flacenc_class_init (FlacEncClass *klass)
231 {
232   GObjectClass *gobject_class;
233   GstElementClass *gstelement_class;
234
235   gobject_class = (GObjectClass*)klass;
236   gstelement_class = (GstElementClass*)klass;
237
238   parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
239   
240   /* we have no properties atm so this is a bit silly */
241   gobject_class->set_property = gst_flacenc_set_property;
242   gobject_class->get_property = gst_flacenc_get_property;
243   gobject_class->dispose      = gst_flacenc_dispose;
244
245   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QUALITY,
246     g_param_spec_enum ("quality", 
247                        "Quality", 
248                        "Speed versus compression tradeoff",
249                        GST_TYPE_FLACENC_QUALITY, DEFAULT_QUALITY, G_PARAM_READWRITE));
250   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_STREAMABLE_SUBSET,
251     g_param_spec_boolean ("streamable_subset", 
252                           "Streamable subset", 
253                           "true to limit encoder to generating a Subset stream, else false",
254                           TRUE, G_PARAM_READWRITE));
255   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MID_SIDE_STEREO,
256     g_param_spec_boolean ("mid_side_stereo", 
257                           "Do mid side stereo", 
258                           "Do mid side stereo (only for stereo input)", 
259                           flacenc_params[DEFAULT_QUALITY].mid_side, G_PARAM_READWRITE));
260   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOOSE_MID_SIDE_STEREO,
261     g_param_spec_boolean ("loose_mid_side_stereo", 
262                           "Loose mid side stereo", 
263                           "Loose mid side stereo", 
264                           flacenc_params[DEFAULT_QUALITY].loose_mid_side, G_PARAM_READWRITE));
265   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BLOCKSIZE,
266     g_param_spec_uint ("blocksize", 
267                        "Blocksize", 
268                        "Blocksize in samples",
269                        FLAC__MIN_BLOCK_SIZE, FLAC__MAX_BLOCK_SIZE, 
270                        flacenc_params[DEFAULT_QUALITY].blocksize, G_PARAM_READWRITE));
271   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MAX_LPC_ORDER,
272     g_param_spec_uint ("max_lpc_order", 
273                        "Max LPC order", 
274                        "Max LPC order; 0 => use only fixed predictors",
275                        0, FLAC__MAX_LPC_ORDER,
276                        flacenc_params[DEFAULT_QUALITY].max_lpc_order, G_PARAM_READWRITE));
277   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QLP_COEFF_PRECISION,
278     g_param_spec_uint ("qlp_coeff_precision", 
279                        "QLP coefficients precision", 
280                        "Precision in bits of quantized linear-predictor coefficients; 0 = automatic",
281                        0, 32, 
282                        flacenc_params[DEFAULT_QUALITY].qlp_coeff_precision, G_PARAM_READWRITE));
283   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QLP_COEFF_PREC_SEARCH,
284     g_param_spec_boolean ("qlp_coeff_prec_search", 
285                           "Do QLP coefficients precision search", 
286                           "false = use qlp_coeff_precision, "
287                             "true = search around qlp_coeff_precision, take best", 
288                           flacenc_params[DEFAULT_QUALITY].qlp_coeff_prec_search, G_PARAM_READWRITE));
289   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ESCAPE_CODING,
290     g_param_spec_boolean ("escape_coding", 
291                           "Do Escape coding", 
292                           "search for escape codes in the entropy coding stage "
293                             "for slightly better compression", 
294                           flacenc_params[DEFAULT_QUALITY].escape_coding, G_PARAM_READWRITE));
295   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_EXHAUSTIVE_MODEL_SEARCH,
296     g_param_spec_boolean ("exhaustive_model_search", 
297                           "Do exhaustive model search", 
298                           "do exhaustive search of LP coefficient quantization (expensive!)",
299                           flacenc_params[DEFAULT_QUALITY].exhaustive_model_search, G_PARAM_READWRITE));
300   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MIN_RESIDUAL_PARTITION_ORDER,
301     g_param_spec_uint ("min_residual_partition_order", 
302                        "Min residual partition order", 
303                        "Min residual partition order (above 4 doesn't usually help much)",
304                        0, 16, 
305                        flacenc_params[DEFAULT_QUALITY].min_residual_partition_order, G_PARAM_READWRITE));
306   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MAX_RESIDUAL_PARTITION_ORDER,
307     g_param_spec_uint ("max_residual_partition_order", 
308                        "Max residual partition order", 
309                        "Max residual partition order (above 4 doesn't usually help much)",
310                        0, 16, 
311                        flacenc_params[DEFAULT_QUALITY].max_residual_partition_order, G_PARAM_READWRITE));
312   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_RICE_PARAMETER_SEARCH_DIST,
313     g_param_spec_uint ("rice_parameter_search_dist", 
314                        "rice_parameter_search_dist", 
315                        "0 = try only calc'd parameter k; else try all [k-dist..k+dist] "
316                          "parameters, use best",
317                        0, FLAC__MAX_RICE_PARTITION_ORDER, 
318                        flacenc_params[DEFAULT_QUALITY].rice_parameter_search_dist, G_PARAM_READWRITE));
319
320   gstelement_class->change_state = gst_flacenc_change_state;
321 }
322
323 static void
324 gst_flacenc_init (FlacEnc *flacenc)
325 {
326   flacenc->sinkpad = gst_pad_new_from_template (sink_template, "sink");
327   gst_element_add_pad(GST_ELEMENT(flacenc),flacenc->sinkpad);
328   gst_pad_set_chain_function(flacenc->sinkpad,gst_flacenc_chain);
329   gst_pad_set_link_function (flacenc->sinkpad, gst_flacenc_sinkconnect);
330
331   flacenc->srcpad = gst_pad_new_from_template (src_template, "src");
332   gst_element_add_pad(GST_ELEMENT(flacenc),flacenc->srcpad);
333
334   GST_FLAG_SET (flacenc, GST_ELEMENT_EVENT_AWARE);
335
336   flacenc->encoder = FLAC__seekable_stream_encoder_new();
337
338   flacenc->negotiated = FALSE;
339   flacenc->first = TRUE;
340   flacenc->first_buf = NULL;
341   flacenc->data = NULL;
342   gst_flacenc_update_quality (flacenc, DEFAULT_QUALITY);
343   flacenc->tags = gst_tag_list_new ();
344 }
345
346 static void
347 gst_flacenc_dispose (GObject *object)
348 {
349   FlacEnc *flacenc = GST_FLACENC (object);
350
351   FLAC__seekable_stream_encoder_delete (flacenc->encoder);
352   
353   G_OBJECT_CLASS (parent_class)->dispose (object);
354 }
355
356 static GstPadLinkReturn
357 gst_flacenc_sinkconnect (GstPad *pad, GstCaps *caps)
358 {
359   GstPadLinkReturn ret;
360   FlacEnc *flacenc;
361
362   flacenc = GST_FLACENC (gst_pad_get_parent (pad));
363
364   if (!GST_CAPS_IS_FIXED (caps))
365     return GST_PAD_LINK_DELAYED;
366
367   gst_caps_get_int (caps, "channels", &flacenc->channels);
368   gst_caps_get_int (caps, "depth", &flacenc->depth);
369   gst_caps_get_int (caps, "rate", &flacenc->sample_rate);
370   
371   caps = GST_CAPS_NEW ("flacenc_srccaps",
372                        "application/x-flac",
373                          "channels", GST_PROPS_INT (flacenc->channels),
374                          "rate", GST_PROPS_INT (flacenc->sample_rate));
375   ret = gst_pad_try_set_caps (flacenc->srcpad, caps);
376   if (ret <= 0) {
377     return ret;
378   }
379
380   FLAC__seekable_stream_encoder_set_bits_per_sample (flacenc->encoder, 
381                                             flacenc->depth);
382   FLAC__seekable_stream_encoder_set_sample_rate (flacenc->encoder, 
383                                         flacenc->sample_rate);
384   FLAC__seekable_stream_encoder_set_channels (flacenc->encoder, 
385                                      flacenc->channels);
386
387   flacenc->negotiated = TRUE;
388
389   return ret;
390 }
391
392 static gboolean
393 gst_flacenc_update_quality (FlacEnc *flacenc, gint quality)
394 {
395   flacenc->quality = quality;
396
397 #define DO_UPDATE(name, val, str)                               \
398   G_STMT_START {                                                \
399     if (FLAC__seekable_stream_encoder_get_##name (flacenc->encoder) !=  \
400         flacenc_params[quality].val) {                          \
401       FLAC__seekable_stream_encoder_set_##name (flacenc->encoder,       \
402           flacenc_params[quality].val);                         \
403       g_object_notify (G_OBJECT (flacenc), str);                \
404     }                                                           \
405   } G_STMT_END
406
407   g_object_freeze_notify (G_OBJECT (flacenc));
408
409   DO_UPDATE (do_mid_side_stereo,           mid_side,                     "mid_side_stereo");
410   DO_UPDATE (loose_mid_side_stereo,        loose_mid_side,               "loose_mid_side");
411   DO_UPDATE (blocksize,                    blocksize,                    "blocksize");
412   DO_UPDATE (max_lpc_order,                max_lpc_order,                "max_lpc_order");
413   DO_UPDATE (qlp_coeff_precision,          qlp_coeff_precision,          "qlp_coeff_precision");
414   DO_UPDATE (do_qlp_coeff_prec_search,     qlp_coeff_prec_search,        "qlp_coeff_prec_search");
415   DO_UPDATE (do_escape_coding,             escape_coding,                "escape_coding");
416   DO_UPDATE (do_exhaustive_model_search,   exhaustive_model_search,      "exhaustive_model_search");
417   DO_UPDATE (min_residual_partition_order, min_residual_partition_order, "min_residual_partition_order");
418   DO_UPDATE (max_residual_partition_order, max_residual_partition_order, "max_residual_partition_order");
419   DO_UPDATE (rice_parameter_search_dist,   rice_parameter_search_dist,   "rice_parameter_search_dist");
420
421 #undef DO_UPDATE
422
423   g_object_thaw_notify (G_OBJECT (flacenc));
424
425   return TRUE;
426 }
427
428 static FLAC__SeekableStreamEncoderSeekStatus
429 gst_flacenc_seek_callback (const FLAC__SeekableStreamEncoder *encoder,
430                            FLAC__uint64 absolute_byte_offset,
431                            void *client_data)
432 {
433 FlacEnc *flacenc;
434 GstEvent *event;
435
436   flacenc = GST_FLACENC (client_data);
437
438   if (flacenc->stopped) 
439     return FLAC__STREAM_ENCODER_OK;
440
441   event = gst_event_new_seek ((GstSeekType)(int)(GST_FORMAT_BYTES | GST_SEEK_METHOD_SET), absolute_byte_offset); 
442
443   if (event)
444     gst_pad_push (flacenc->srcpad, GST_DATA (event));
445  
446   return  FLAC__STREAM_ENCODER_OK;
447 }
448
449 static FLAC__StreamEncoderWriteStatus 
450 gst_flacenc_write_callback (const FLAC__SeekableStreamEncoder *encoder, 
451                             const FLAC__byte buffer[], unsigned bytes, 
452                             unsigned samples, unsigned current_frame, 
453                             void *client_data)
454 {
455   FlacEnc *flacenc;
456   GstBuffer *outbuf;
457   
458   flacenc = GST_FLACENC (client_data);
459
460   if (flacenc->stopped) 
461     return FLAC__STREAM_ENCODER_OK;
462
463   outbuf = gst_buffer_new_and_alloc (bytes);
464
465   memcpy (GST_BUFFER_DATA (outbuf), buffer, bytes);
466
467   if (flacenc->first) {
468     flacenc->first_buf = outbuf;
469     gst_buffer_ref (outbuf);
470     flacenc->first = FALSE;
471   }
472
473   gst_pad_push (flacenc->srcpad, GST_DATA (outbuf));
474
475   return FLAC__STREAM_ENCODER_OK;
476 }
477
478 void  add_one_tag (const GstTagList *list, 
479                    const gchar *tag, 
480                    gpointer user_data)
481 {
482       GList *comments;
483       GList *it;
484       FlacEnc *flacenc = GST_FLACENC (user_data);
485
486       comments = gst_tag_to_vorbis_comments (list, tag);
487       for (it = comments; it != NULL; it = it->next) {
488               FLAC__StreamMetadata_VorbisComment_Entry commment_entry;
489               commment_entry.length = GUINT32_TO_LE (strlen(it->data) + 1);
490               commment_entry.entry  =  it->data;
491               FLAC__metadata_object_vorbiscomment_insert_comment (flacenc->meta[0], 
492                                                                   flacenc->meta[0]->data.vorbis_comment.num_comments, 
493                                                                   commment_entry, 
494                                                                   TRUE);
495               g_free (it->data);
496       }
497       g_list_free (comments);
498 }
499
500 static void
501 gst_flacenc_set_metadata (FlacEnc *flacenc)
502 {
503   const GstTagList *user_tags;
504   GstTagList *copy;
505
506   g_return_if_fail (flacenc != NULL);
507   user_tags = gst_tag_setter_get_list (GST_TAG_SETTER (flacenc));
508   if ((flacenc->tags == NULL) && (user_tags == NULL)) {
509     return;
510   }
511   copy = gst_tag_list_merge (user_tags, flacenc->tags, 
512                              gst_tag_setter_get_merge_mode (GST_TAG_SETTER (flacenc)));
513   flacenc->meta = g_malloc (sizeof (FLAC__StreamMetadata **));
514
515   flacenc->meta[0] = FLAC__metadata_object_new (FLAC__METADATA_TYPE_VORBIS_COMMENT);
516   gst_tag_list_foreach ((GstTagList*)copy, add_one_tag, flacenc);
517
518   FLAC__seekable_stream_encoder_set_metadata(flacenc->encoder, flacenc->meta, 1);
519   gst_tag_list_free (copy);
520 }
521
522
523 static void
524 gst_flacenc_chain (GstPad *pad, GstData *_data)
525 {
526   GstBuffer *buf = GST_BUFFER (_data);
527   FlacEnc *flacenc;
528   FLAC__int32 *data;
529   gulong insize;
530   gint samples, depth;
531   gulong i;
532   FLAC__bool res;
533
534   g_return_if_fail(buf != NULL);
535
536   flacenc = GST_FLACENC (gst_pad_get_parent (pad));
537
538   if (GST_IS_EVENT (buf)) {
539     GstEvent *event = GST_EVENT (buf);
540
541     switch (GST_EVENT_TYPE (event)) {
542       case GST_EVENT_EOS:
543         FLAC__seekable_stream_encoder_finish(flacenc->encoder);
544         break;
545       case GST_EVENT_TAG:
546         if (flacenc->tags) {
547           gst_tag_list_merge (flacenc->tags, gst_event_tag_get_list (event), 
548                   gst_tag_setter_get_merge_mode (GST_TAG_SETTER (flacenc)));
549         } else {
550           g_assert_not_reached ();
551         }
552         break;
553       default:
554         break;
555     }
556     gst_pad_event_default (pad, event);
557     return;
558   }
559
560   if (!flacenc->negotiated) {
561     gst_element_error (GST_ELEMENT (flacenc),
562                     "format not negotiated");
563     return;
564   }
565
566   depth = flacenc->depth;
567
568   insize = GST_BUFFER_SIZE (buf);
569   samples = insize / ((depth+7)>>3);
570
571   if (FLAC__seekable_stream_encoder_get_state (flacenc->encoder) == 
572                   FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) 
573   {
574     FLAC__SeekableStreamEncoderState state;
575
576     FLAC__seekable_stream_encoder_set_write_callback (flacenc->encoder, 
577                                           gst_flacenc_write_callback);
578     FLAC__seekable_stream_encoder_set_seek_callback (flacenc->encoder, 
579                                           gst_flacenc_seek_callback);
580                                           
581     FLAC__seekable_stream_encoder_set_client_data (flacenc->encoder, 
582                                           flacenc);
583                   
584     gst_flacenc_set_metadata (flacenc);
585     state = FLAC__seekable_stream_encoder_init (flacenc->encoder);
586     if (state != FLAC__STREAM_ENCODER_OK) {
587       gst_element_error (GST_ELEMENT (flacenc),
588                          "could not initialize encoder (wrong parameters?)");
589       return;
590     }
591   }
592
593   /* we keep a pointer in the flacenc struct because we are freeing the data
594    * after a push opreration that might never return */
595   data = flacenc->data = g_malloc (samples * sizeof (FLAC__int32));
596     
597   if (depth == 8) {
598     gint8 *indata = (gint8 *) GST_BUFFER_DATA (buf);
599     
600
601     for (i=0; i<samples; i++) {
602       data[i] = (FLAC__int32) *indata++;
603     }
604   }
605   else if (depth == 16) {
606     gint16 *indata = (gint16 *) GST_BUFFER_DATA (buf);
607
608     for (i=0; i<samples; i++) {
609       data[i] = (FLAC__int32) *indata++;
610     }
611   }
612
613   gst_buffer_unref(buf);
614
615   res = FLAC__seekable_stream_encoder_process_interleaved (flacenc->encoder, 
616                               (const FLAC__int32 *) data, samples / flacenc->channels);
617
618   g_free (flacenc->data);
619   flacenc->data = NULL;
620
621   if (!res) {
622     gst_element_error (GST_ELEMENT (flacenc),
623                          "encoding error");
624   }
625 }
626
627 static void
628 gst_flacenc_set_property (GObject *object, guint prop_id,
629                           const GValue *value, GParamSpec *pspec)
630 {
631   FlacEnc *this;
632   
633   this = (FlacEnc *)object;
634   switch (prop_id) {
635     case ARG_QUALITY:
636       gst_flacenc_update_quality (this, g_value_get_enum (value));
637       break;
638     case ARG_STREAMABLE_SUBSET:
639       FLAC__seekable_stream_encoder_set_streamable_subset (this->encoder, 
640                            g_value_get_boolean (value));
641       break;
642     case ARG_MID_SIDE_STEREO:
643       FLAC__seekable_stream_encoder_set_do_mid_side_stereo (this->encoder, 
644                            g_value_get_boolean (value));
645       break;
646     case ARG_LOOSE_MID_SIDE_STEREO:
647       FLAC__seekable_stream_encoder_set_loose_mid_side_stereo (this->encoder, 
648                            g_value_get_boolean (value));
649       break;
650     case ARG_BLOCKSIZE:
651       FLAC__seekable_stream_encoder_set_blocksize (this->encoder, 
652                            g_value_get_uint (value));
653       break;
654     case ARG_MAX_LPC_ORDER:
655       FLAC__seekable_stream_encoder_set_max_lpc_order (this->encoder, 
656                            g_value_get_uint (value));
657       break;
658     case ARG_QLP_COEFF_PRECISION:
659       FLAC__seekable_stream_encoder_set_qlp_coeff_precision (this->encoder, 
660                            g_value_get_uint (value));
661       break;
662     case ARG_QLP_COEFF_PREC_SEARCH:
663       FLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search (this->encoder, 
664                            g_value_get_boolean (value));
665       break;
666     case ARG_ESCAPE_CODING:
667       FLAC__seekable_stream_encoder_set_do_escape_coding (this->encoder, 
668                            g_value_get_boolean (value));
669       break;
670     case ARG_EXHAUSTIVE_MODEL_SEARCH:
671       FLAC__seekable_stream_encoder_set_do_exhaustive_model_search (this->encoder, 
672                            g_value_get_boolean (value));
673       break;
674     case ARG_MIN_RESIDUAL_PARTITION_ORDER:
675       FLAC__seekable_stream_encoder_set_min_residual_partition_order (this->encoder, 
676                            g_value_get_uint (value));
677       break;
678     case ARG_MAX_RESIDUAL_PARTITION_ORDER:
679       FLAC__seekable_stream_encoder_set_max_residual_partition_order (this->encoder, 
680                            g_value_get_uint (value));
681       break;
682     case ARG_RICE_PARAMETER_SEARCH_DIST:
683       FLAC__seekable_stream_encoder_set_rice_parameter_search_dist (this->encoder, 
684                                                  g_value_get_uint (value));
685       break;
686     default:
687       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
688       return;
689   }
690 }
691
692 static void
693 gst_flacenc_get_property (GObject *object, guint prop_id, 
694                           GValue *value, GParamSpec *pspec)
695 {
696   FlacEnc *this;
697   
698   this = (FlacEnc *)object;
699   
700   switch (prop_id) {
701     case ARG_QUALITY:
702       g_value_set_enum (value, this->quality);
703       break;
704     case ARG_STREAMABLE_SUBSET:
705       g_value_set_boolean (value, 
706               FLAC__seekable_stream_encoder_get_streamable_subset (this->encoder));
707       break;
708     case ARG_MID_SIDE_STEREO:
709       g_value_set_boolean (value, 
710               FLAC__seekable_stream_encoder_get_do_mid_side_stereo (this->encoder));
711       break;
712     case ARG_LOOSE_MID_SIDE_STEREO:
713       g_value_set_boolean (value, 
714               FLAC__seekable_stream_encoder_get_loose_mid_side_stereo (this->encoder));
715       break;
716     case ARG_BLOCKSIZE:
717       g_value_set_uint (value, 
718               FLAC__seekable_stream_encoder_get_blocksize (this->encoder));
719       break;
720     case ARG_MAX_LPC_ORDER:
721       g_value_set_uint (value, 
722               FLAC__seekable_stream_encoder_get_max_lpc_order (this->encoder));
723       break;
724     case ARG_QLP_COEFF_PRECISION:
725       g_value_set_uint (value, 
726               FLAC__seekable_stream_encoder_get_qlp_coeff_precision (this->encoder));
727       break;
728     case ARG_QLP_COEFF_PREC_SEARCH:
729       g_value_set_boolean (value, 
730               FLAC__seekable_stream_encoder_get_do_qlp_coeff_prec_search (this->encoder));
731       break;
732     case ARG_ESCAPE_CODING:
733       g_value_set_boolean (value, 
734               FLAC__seekable_stream_encoder_get_do_escape_coding (this->encoder));
735       break;
736     case ARG_EXHAUSTIVE_MODEL_SEARCH:
737       g_value_set_boolean (value, 
738               FLAC__seekable_stream_encoder_get_do_exhaustive_model_search (this->encoder));
739       break;
740     case ARG_MIN_RESIDUAL_PARTITION_ORDER:
741       g_value_set_uint (value, 
742               FLAC__seekable_stream_encoder_get_min_residual_partition_order (this->encoder));
743       break;
744     case ARG_MAX_RESIDUAL_PARTITION_ORDER:
745       g_value_set_uint (value, 
746               FLAC__seekable_stream_encoder_get_max_residual_partition_order (this->encoder));
747       break;
748     case ARG_RICE_PARAMETER_SEARCH_DIST:
749       g_value_set_uint (value, 
750               FLAC__seekable_stream_encoder_get_rice_parameter_search_dist (this->encoder));
751       break;
752     default:
753       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
754       break;
755   }
756 }
757
758 static GstElementStateReturn
759 gst_flacenc_change_state (GstElement *element)
760 {
761   FlacEnc *flacenc = GST_FLACENC (element);
762
763   switch (GST_STATE_TRANSITION (element)) {
764     case GST_STATE_NULL_TO_READY:
765     case GST_STATE_READY_TO_PAUSED:
766       flacenc->first = TRUE;
767       flacenc->stopped = FALSE;
768       break;
769     case GST_STATE_PAUSED_TO_PLAYING:
770     case GST_STATE_PLAYING_TO_PAUSED:
771       break;
772     case GST_STATE_PAUSED_TO_READY:
773       if (FLAC__seekable_stream_encoder_get_state (flacenc->encoder) != 
774                         FLAC__STREAM_ENCODER_UNINITIALIZED) {
775         flacenc->stopped = TRUE;
776         FLAC__seekable_stream_encoder_finish (flacenc->encoder);
777       }
778       flacenc->negotiated = FALSE;
779       if (flacenc->first_buf)
780         gst_buffer_unref (flacenc->first_buf);
781       flacenc->first_buf = NULL;
782       g_free (flacenc->data);
783       flacenc->data = NULL;
784       if (flacenc->meta) {
785         FLAC__metadata_object_delete (flacenc->meta[0]);
786         g_free (flacenc->meta);
787         flacenc->meta = NULL;
788       }
789       break;
790     case GST_STATE_READY_TO_NULL:
791     default:
792       break;
793   }
794
795   if (GST_ELEMENT_CLASS (parent_class)->change_state)
796     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
797
798   return GST_STATE_SUCCESS;
799 }