compatibility fix for new GST_DEBUG stuff.
[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   FlacEnc *flacenc;
329
330   flacenc = GST_FLACENC (gst_pad_get_parent (pad));
331
332   if (!GST_CAPS_IS_FIXED (caps))
333     return GST_PAD_LINK_DELAYED;
334
335   gst_caps_get_int (caps, "channels", &flacenc->channels);
336   gst_caps_get_int (caps, "depth", &flacenc->depth);
337   gst_caps_get_int (caps, "rate", &flacenc->sample_rate);
338   
339   FLAC__seekable_stream_encoder_set_bits_per_sample (flacenc->encoder, 
340                                             flacenc->depth);
341   FLAC__seekable_stream_encoder_set_sample_rate (flacenc->encoder, 
342                                         flacenc->sample_rate);
343   FLAC__seekable_stream_encoder_set_channels (flacenc->encoder, 
344                                      flacenc->channels);
345
346   flacenc->negotiated = TRUE;
347
348   return GST_PAD_LINK_OK;
349 }
350
351 static gboolean
352 gst_flacenc_update_quality (FlacEnc *flacenc, gint quality)
353 {
354   flacenc->quality = quality;
355
356 #define DO_UPDATE(name, val, str)                               \
357   G_STMT_START {                                                \
358     if (FLAC__seekable_stream_encoder_get_##name (flacenc->encoder) !=  \
359         flacenc_params[quality].val) {                          \
360       FLAC__seekable_stream_encoder_set_##name (flacenc->encoder,       \
361           flacenc_params[quality].val);                         \
362       g_object_notify (G_OBJECT (flacenc), str);                \
363     }                                                           \
364   } G_STMT_END
365
366   g_object_freeze_notify (G_OBJECT (flacenc));
367
368   DO_UPDATE (do_mid_side_stereo,           mid_side,                     "mid_side_stereo");
369   DO_UPDATE (loose_mid_side_stereo,        loose_mid_side,               "loose_mid_side");
370   DO_UPDATE (blocksize,                    blocksize,                    "blocksize");
371   DO_UPDATE (max_lpc_order,                max_lpc_order,                "max_lpc_order");
372   DO_UPDATE (qlp_coeff_precision,          qlp_coeff_precision,          "qlp_coeff_precision");
373   DO_UPDATE (do_qlp_coeff_prec_search,     qlp_coeff_prec_search,        "qlp_coeff_prec_search");
374   DO_UPDATE (do_escape_coding,             escape_coding,                "escape_coding");
375   DO_UPDATE (do_exhaustive_model_search,   exhaustive_model_search,      "exhaustive_model_search");
376   DO_UPDATE (min_residual_partition_order, min_residual_partition_order, "min_residual_partition_order");
377   DO_UPDATE (max_residual_partition_order, max_residual_partition_order, "max_residual_partition_order");
378   DO_UPDATE (rice_parameter_search_dist,   rice_parameter_search_dist,   "rice_parameter_search_dist");
379
380 #undef DO_UPDATE
381
382   g_object_thaw_notify (G_OBJECT (flacenc));
383
384   return TRUE;
385 }
386
387 static FLAC__SeekableStreamEncoderSeekStatus
388 gst_flacenc_seek_callback (const FLAC__SeekableStreamEncoder *encoder,
389                            FLAC__uint64 absolute_byte_offset,
390                            void *client_data)
391 {
392 FlacEnc *flacenc;
393 GstEvent *event;
394
395   flacenc = GST_FLACENC (client_data);
396
397   if (flacenc->stopped) 
398     return FLAC__STREAM_ENCODER_OK;
399
400   event = gst_event_new_seek ((GstSeekType)(int)(GST_FORMAT_BYTES | GST_SEEK_METHOD_SET), absolute_byte_offset); 
401
402   if (event)
403     gst_pad_push (flacenc->srcpad, GST_BUFFER (event));
404  
405   return  FLAC__STREAM_ENCODER_OK;
406 }
407
408 static FLAC__StreamEncoderWriteStatus 
409 gst_flacenc_write_callback (const FLAC__SeekableStreamEncoder *encoder, 
410                             const FLAC__byte buffer[], unsigned bytes, 
411                             unsigned samples, unsigned current_frame, 
412                             void *client_data)
413 {
414   FlacEnc *flacenc;
415   GstBuffer *outbuf;
416   
417   flacenc = GST_FLACENC (client_data);
418
419   if (flacenc->stopped) 
420     return FLAC__STREAM_ENCODER_OK;
421
422   outbuf = gst_buffer_new_and_alloc (bytes);
423
424   memcpy (GST_BUFFER_DATA (outbuf), buffer, bytes);
425
426   if (flacenc->first) {
427     flacenc->first_buf = outbuf;
428     gst_buffer_ref (outbuf);
429     flacenc->first = FALSE;
430   }
431
432   gst_pad_push (flacenc->srcpad, outbuf);
433
434   return FLAC__STREAM_ENCODER_OK;
435 }
436
437 static void
438 gst_flacenc_set_metadata (FlacEnc *flacenc, GstCaps *caps)
439 {
440   guint indice;
441   guint comments;
442   const gchar *meta_types[] = { "TITLE", "VERSION", "ALBUM", "TRACKNUMBER",
443                                 "ARTIST", "PERFORMER", "COPYRIGHT", "LICENSE",
444                                 "ORGANISATION", "DESCRIPTION", "GENRE", "DATE",
445                                 "LOCATION", "CONTACT", "ISRC", NULL };
446
447   g_return_if_fail (flacenc != NULL);
448
449   flacenc->meta = g_malloc (sizeof (FLAC__StreamMetadata **));
450
451   flacenc->meta[0] = FLAC__metadata_object_new (FLAC__METADATA_TYPE_VORBIS_COMMENT);
452   
453   for ( indice = 0, comments=0; meta_types[indice] != NULL; indice++) {
454     if (gst_caps_has_property(caps, meta_types[indice])) {
455       const gchar *entry;
456       gchar *data;
457       FLAC__StreamMetadata_VorbisComment_Entry commment_entry;
458       
459       gst_caps_get_string(caps, (gchar *)meta_types[indice], &entry);
460
461       if (!strcmp (entry, ""))
462         continue;
463    
464       data = g_strdup_printf("%s=%s", meta_types[indice], entry);
465       commment_entry.length = GUINT32_TO_LE (strlen(entry) + strlen(meta_types[indice]) + 1);
466       commment_entry.entry  =  g_convert (data, commment_entry.length, "UTF8", "ISO-8859-1", NULL, NULL, NULL);
467
468       FLAC__metadata_object_vorbiscomment_insert_comment (flacenc->meta[0], comments++, commment_entry, TRUE);
469     }
470   }
471
472   FLAC__seekable_stream_encoder_set_metadata(flacenc->encoder, flacenc->meta, 1);
473 }
474
475
476
477 static void
478 gst_flacenc_chain (GstPad *pad, GstBuffer *buf)
479 {
480   FlacEnc *flacenc;
481   FLAC__int32 *data;
482   gulong insize;
483   gint samples, depth;
484   gulong i;
485   FLAC__bool res;
486
487   g_return_if_fail(buf != NULL);
488
489   flacenc = GST_FLACENC (gst_pad_get_parent (pad));
490
491   if (GST_IS_EVENT (buf)) {
492     GstEvent *event = GST_EVENT (buf);
493
494     switch (GST_EVENT_TYPE (event)) {
495       case GST_EVENT_EOS:
496         FLAC__seekable_stream_encoder_finish(flacenc->encoder);
497       default:
498         gst_pad_event_default (pad, event);
499         break;
500     }
501     return;
502   }
503
504   if (!flacenc->negotiated) {
505     gst_element_error (GST_ELEMENT (flacenc),
506                     "format not negotiated");
507     return;
508   }
509
510   depth = flacenc->depth;
511
512   insize = GST_BUFFER_SIZE (buf);
513   samples = insize / ((depth+7)>>3);
514
515   if (FLAC__seekable_stream_encoder_get_state (flacenc->encoder) == 
516                   FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED) 
517   {
518     FLAC__SeekableStreamEncoderState state;
519
520     gst_flacenc_set_metadata (flacenc, flacenc->metadata);
521     state = FLAC__seekable_stream_encoder_init (flacenc->encoder);
522     if (state != FLAC__STREAM_ENCODER_OK) {
523       gst_element_error (GST_ELEMENT (flacenc),
524                          "could not initialize encoder (wrong parameters?)");
525       return;
526     }
527   }
528
529   /* we keep a pointer in the flacenc struct because we are freeing the data
530    * after a push opreration that might never return */
531   data = flacenc->data = g_malloc (samples * sizeof (FLAC__int32));
532     
533   if (depth == 8) {
534     gint8 *indata = (gint8 *) GST_BUFFER_DATA (buf);
535     
536
537     for (i=0; i<samples; i++) {
538       data[i] = (FLAC__int32) *indata++;
539     }
540   }
541   else if (depth == 16) {
542     gint16 *indata = (gint16 *) GST_BUFFER_DATA (buf);
543
544     for (i=0; i<samples; i++) {
545       data[i] = (FLAC__int32) *indata++;
546     }
547   }
548
549   gst_buffer_unref(buf);
550
551   res = FLAC__seekable_stream_encoder_process_interleaved (flacenc->encoder, 
552                               (const FLAC__int32 *) data, samples / flacenc->channels);
553
554   g_free (flacenc->data);
555   flacenc->data = NULL;
556
557   if (!res) {
558     gst_element_error (GST_ELEMENT (flacenc),
559                          "encoding error");
560   }
561 }
562
563 static void
564 gst_flacenc_set_property (GObject *object, guint prop_id,
565                           const GValue *value, GParamSpec *pspec)
566 {
567   FlacEnc *this;
568   
569   this = (FlacEnc *)object;
570   switch (prop_id) {
571     case ARG_QUALITY:
572       gst_flacenc_update_quality (this, g_value_get_enum (value));
573       break;
574     case ARG_STREAMABLE_SUBSET:
575       FLAC__seekable_stream_encoder_set_streamable_subset (this->encoder, 
576                            g_value_get_boolean (value));
577       break;
578     case ARG_MID_SIDE_STEREO:
579       FLAC__seekable_stream_encoder_set_do_mid_side_stereo (this->encoder, 
580                            g_value_get_boolean (value));
581       break;
582     case ARG_LOOSE_MID_SIDE_STEREO:
583       FLAC__seekable_stream_encoder_set_loose_mid_side_stereo (this->encoder, 
584                            g_value_get_boolean (value));
585       break;
586     case ARG_BLOCKSIZE:
587       FLAC__seekable_stream_encoder_set_blocksize (this->encoder, 
588                            g_value_get_uint (value));
589       break;
590     case ARG_MAX_LPC_ORDER:
591       FLAC__seekable_stream_encoder_set_max_lpc_order (this->encoder, 
592                            g_value_get_uint (value));
593       break;
594     case ARG_QLP_COEFF_PRECISION:
595       FLAC__seekable_stream_encoder_set_qlp_coeff_precision (this->encoder, 
596                            g_value_get_uint (value));
597       break;
598     case ARG_QLP_COEFF_PREC_SEARCH:
599       FLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search (this->encoder, 
600                            g_value_get_boolean (value));
601       break;
602     case ARG_ESCAPE_CODING:
603       FLAC__seekable_stream_encoder_set_do_escape_coding (this->encoder, 
604                            g_value_get_boolean (value));
605       break;
606     case ARG_EXHAUSTIVE_MODEL_SEARCH:
607       FLAC__seekable_stream_encoder_set_do_exhaustive_model_search (this->encoder, 
608                            g_value_get_boolean (value));
609       break;
610     case ARG_MIN_RESIDUAL_PARTITION_ORDER:
611       FLAC__seekable_stream_encoder_set_min_residual_partition_order (this->encoder, 
612                            g_value_get_uint (value));
613       break;
614     case ARG_MAX_RESIDUAL_PARTITION_ORDER:
615       FLAC__seekable_stream_encoder_set_max_residual_partition_order (this->encoder, 
616                            g_value_get_uint (value));
617       break;
618     case ARG_RICE_PARAMETER_SEARCH_DIST:
619       FLAC__seekable_stream_encoder_set_rice_parameter_search_dist (this->encoder, 
620                                                  g_value_get_uint (value));
621       break;
622     default:
623       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
624       return;
625   }
626 }
627
628 static void
629 gst_flacenc_get_property (GObject *object, guint prop_id, 
630                           GValue *value, GParamSpec *pspec)
631 {
632   FlacEnc *this;
633   
634   this = (FlacEnc *)object;
635   
636   switch (prop_id) {
637     case ARG_QUALITY:
638       g_value_set_enum (value, this->quality);
639       break;
640     case ARG_STREAMABLE_SUBSET:
641       g_value_set_boolean (value, 
642               FLAC__seekable_stream_encoder_get_streamable_subset (this->encoder));
643       break;
644     case ARG_MID_SIDE_STEREO:
645       g_value_set_boolean (value, 
646               FLAC__seekable_stream_encoder_get_do_mid_side_stereo (this->encoder));
647       break;
648     case ARG_LOOSE_MID_SIDE_STEREO:
649       g_value_set_boolean (value, 
650               FLAC__seekable_stream_encoder_get_loose_mid_side_stereo (this->encoder));
651       break;
652     case ARG_BLOCKSIZE:
653       g_value_set_uint (value, 
654               FLAC__seekable_stream_encoder_get_blocksize (this->encoder));
655       break;
656     case ARG_MAX_LPC_ORDER:
657       g_value_set_uint (value, 
658               FLAC__seekable_stream_encoder_get_max_lpc_order (this->encoder));
659       break;
660     case ARG_QLP_COEFF_PRECISION:
661       g_value_set_uint (value, 
662               FLAC__seekable_stream_encoder_get_qlp_coeff_precision (this->encoder));
663       break;
664     case ARG_QLP_COEFF_PREC_SEARCH:
665       g_value_set_boolean (value, 
666               FLAC__seekable_stream_encoder_get_do_qlp_coeff_prec_search (this->encoder));
667       break;
668     case ARG_ESCAPE_CODING:
669       g_value_set_boolean (value, 
670               FLAC__seekable_stream_encoder_get_do_escape_coding (this->encoder));
671       break;
672     case ARG_EXHAUSTIVE_MODEL_SEARCH:
673       g_value_set_boolean (value, 
674               FLAC__seekable_stream_encoder_get_do_exhaustive_model_search (this->encoder));
675       break;
676     case ARG_MIN_RESIDUAL_PARTITION_ORDER:
677       g_value_set_uint (value, 
678               FLAC__seekable_stream_encoder_get_min_residual_partition_order (this->encoder));
679       break;
680     case ARG_MAX_RESIDUAL_PARTITION_ORDER:
681       g_value_set_uint (value, 
682               FLAC__seekable_stream_encoder_get_max_residual_partition_order (this->encoder));
683       break;
684     case ARG_RICE_PARAMETER_SEARCH_DIST:
685       g_value_set_uint (value, 
686               FLAC__seekable_stream_encoder_get_rice_parameter_search_dist (this->encoder));
687       break;
688     default:
689       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
690       break;
691   }
692 }
693
694 static GstElementStateReturn
695 gst_flacenc_change_state (GstElement *element)
696 {
697   FlacEnc *flacenc = GST_FLACENC (element);
698
699   switch (GST_STATE_TRANSITION (element)) {
700     case GST_STATE_NULL_TO_READY:
701     case GST_STATE_READY_TO_PAUSED:
702       flacenc->first = TRUE;
703       flacenc->stopped = FALSE;
704       break;
705     case GST_STATE_PAUSED_TO_PLAYING:
706     case GST_STATE_PLAYING_TO_PAUSED:
707       break;
708     case GST_STATE_PAUSED_TO_READY:
709       if (FLAC__seekable_stream_encoder_get_state (flacenc->encoder) != 
710                         FLAC__STREAM_ENCODER_UNINITIALIZED) {
711         flacenc->stopped = TRUE;
712         FLAC__seekable_stream_encoder_finish (flacenc->encoder);
713       }
714       flacenc->negotiated = FALSE;
715       if (flacenc->first_buf)
716         gst_buffer_unref (flacenc->first_buf);
717       flacenc->first_buf = NULL;
718       g_free (flacenc->data);
719       flacenc->data = NULL;
720       FLAC__metadata_object_delete (flacenc->meta[0]);
721       g_free (flacenc->meta);
722       break;
723     case GST_STATE_READY_TO_NULL:
724     default:
725       break;
726   }
727
728   if (GST_ELEMENT_CLASS (parent_class)->change_state)
729     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
730
731   return GST_STATE_SUCCESS;
732 }