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