Add support for flac >= 1.1.3 which changed the API. Fixes bug #385887.
[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 /* FIXME:
21  *  - we assume timestamps start from 0 and that we get a perfect stream; we
22  *    don't handle non-zero starts and mid-stream discontinuities, esp. not if
23  *    we're muxing into ogg
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include <gstflacenc.h>
33 #include <gst/audio/audio.h>
34 #include <gst/tag/tag.h>
35 #include <gst/gsttagsetter.h>
36
37
38 static const GstElementDetails flacenc_details =
39 GST_ELEMENT_DETAILS ("FLAC audio encoder",
40     "Codec/Encoder/Audio",
41     "Encodes audio with the FLAC lossless audio encoder",
42     "Wim Taymans <wim.taymans@chello.be>");
43
44 #define FLAC_SINK_CAPS \
45   "audio/x-raw-int, "               \
46   "endianness = (int) BYTE_ORDER, " \
47   "signed = (boolean) TRUE, "       \
48   "width = (int) 16, "              \
49   "depth = (int) 16, "              \
50   "rate = (int) [ 8000, 48000 ], " \
51   "channels = (int) [ 1, 2 ]"
52
53 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
54     GST_PAD_SRC,
55     GST_PAD_ALWAYS,
56     GST_STATIC_CAPS ("audio/x-flac")
57     );
58
59 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
60     GST_PAD_SINK,
61     GST_PAD_ALWAYS,
62     GST_STATIC_CAPS (FLAC_SINK_CAPS)
63     );
64
65 enum
66 {
67   PROP_0,
68   PROP_QUALITY,
69   PROP_STREAMABLE_SUBSET,
70   PROP_MID_SIDE_STEREO,
71   PROP_LOOSE_MID_SIDE_STEREO,
72   PROP_BLOCKSIZE,
73   PROP_MAX_LPC_ORDER,
74   PROP_QLP_COEFF_PRECISION,
75   PROP_QLP_COEFF_PREC_SEARCH,
76   PROP_ESCAPE_CODING,
77   PROP_EXHAUSTIVE_MODEL_SEARCH,
78   PROP_MIN_RESIDUAL_PARTITION_ORDER,
79   PROP_MAX_RESIDUAL_PARTITION_ORDER,
80   PROP_RICE_PARAMETER_SEARCH_DIST
81 };
82
83 GST_DEBUG_CATEGORY_STATIC (flacenc_debug);
84 #define GST_CAT_DEFAULT flacenc_debug
85
86
87 #define _do_init(type)                                                          \
88   G_STMT_START{                                                                 \
89     static const GInterfaceInfo tag_setter_info = {                             \
90       NULL,                                                                     \
91       NULL,                                                                     \
92       NULL                                                                      \
93     };                                                                          \
94     g_type_add_interface_static (type, GST_TYPE_TAG_SETTER,                     \
95                                  &tag_setter_info);                             \
96   }G_STMT_END
97
98 GST_BOILERPLATE_FULL (GstFlacEnc, gst_flac_enc, GstElement, GST_TYPE_ELEMENT,
99     _do_init);
100
101 static void gst_flac_enc_finalize (GObject * object);
102
103 static gboolean gst_flac_enc_sink_setcaps (GstPad * pad, GstCaps * caps);
104 static gboolean gst_flac_enc_sink_event (GstPad * pad, GstEvent * event);
105 static GstFlowReturn gst_flac_enc_chain (GstPad * pad, GstBuffer * buffer);
106
107 static gboolean gst_flac_enc_update_quality (GstFlacEnc * flacenc,
108     gint quality);
109 static void gst_flac_enc_set_property (GObject * object, guint prop_id,
110     const GValue * value, GParamSpec * pspec);
111 static void gst_flac_enc_get_property (GObject * object, guint prop_id,
112     GValue * value, GParamSpec * pspec);
113 static GstStateChangeReturn gst_flac_enc_change_state (GstElement * element,
114     GstStateChange transition);
115
116 #ifdef LEGACY_FLAC
117 static FLAC__StreamEncoderWriteStatus
118 gst_flac_enc_write_callback (const FLAC__SeekableStreamEncoder * encoder,
119     const FLAC__byte buffer[], unsigned bytes,
120     unsigned samples, unsigned current_frame, void *client_data);
121 static FLAC__SeekableStreamEncoderSeekStatus
122 gst_flac_enc_seek_callback (const FLAC__SeekableStreamEncoder * encoder,
123     FLAC__uint64 absolute_byte_offset, void *client_data);
124 static FLAC__SeekableStreamEncoderTellStatus
125 gst_flac_enc_tell_callback (const FLAC__SeekableStreamEncoder * encoder,
126     FLAC__uint64 * absolute_byte_offset, void *client_data);
127 #else
128 static FLAC__StreamEncoderWriteStatus
129 gst_flac_enc_write_callback (const FLAC__StreamEncoder * encoder,
130     const FLAC__byte buffer[], size_t bytes,
131     unsigned samples, unsigned current_frame, void *client_data);
132 static FLAC__StreamEncoderSeekStatus
133 gst_flac_enc_seek_callback (const FLAC__StreamEncoder * encoder,
134     FLAC__uint64 absolute_byte_offset, void *client_data);
135 static FLAC__StreamEncoderTellStatus
136 gst_flac_enc_tell_callback (const FLAC__StreamEncoder * encoder,
137     FLAC__uint64 * absolute_byte_offset, void *client_data);
138 #endif
139
140 typedef struct
141 {
142   gboolean exhaustive_model_search;
143   gboolean escape_coding;
144   gboolean mid_side;
145   gboolean loose_mid_side;
146   guint qlp_coeff_precision;
147   gboolean qlp_coeff_prec_search;
148   guint min_residual_partition_order;
149   guint max_residual_partition_order;
150   guint rice_parameter_search_dist;
151   guint max_lpc_order;
152   guint blocksize;
153 }
154 GstFlacEncParams;
155
156 static const GstFlacEncParams flacenc_params[] = {
157   {FALSE, FALSE, FALSE, FALSE, 0, FALSE, 2, 2, 0, 0, 1152},
158   {FALSE, FALSE, TRUE, TRUE, 0, FALSE, 2, 2, 0, 0, 1152},
159   {FALSE, FALSE, TRUE, FALSE, 0, FALSE, 0, 3, 0, 0, 1152},
160   {FALSE, FALSE, FALSE, FALSE, 0, FALSE, 3, 3, 0, 6, 4608},
161   {FALSE, FALSE, TRUE, TRUE, 0, FALSE, 3, 3, 0, 8, 4608},
162   {FALSE, FALSE, TRUE, FALSE, 0, FALSE, 3, 3, 0, 8, 4608},
163   {FALSE, FALSE, TRUE, FALSE, 0, FALSE, 0, 4, 0, 8, 4608},
164   {TRUE, FALSE, TRUE, FALSE, 0, FALSE, 0, 6, 0, 8, 4608},
165   {TRUE, FALSE, TRUE, FALSE, 0, FALSE, 0, 6, 0, 12, 4608},
166   {TRUE, TRUE, TRUE, FALSE, 0, FALSE, 0, 16, 0, 32, 4608},
167 };
168
169 #define DEFAULT_QUALITY 5
170
171 #define GST_TYPE_FLAC_ENC_QUALITY (gst_flac_enc_quality_get_type ())
172 GType
173 gst_flac_enc_quality_get_type (void)
174 {
175   static GType qtype = 0;
176
177   if (qtype == 0) {
178     static const GEnumValue values[] = {
179       {0, "0 - Fastest compression", "0"},
180       {1, "1", "1"},
181       {2, "2", "2"},
182       {3, "3", "3"},
183       {4, "4", "4"},
184       {5, "5 - Default", "5"},
185       {6, "6", "6"},
186       {7, "7", "7"},
187       {8, "8 - Highest compression", "8"},
188       {9, "9 - Insane", "9"},
189       {0, NULL, NULL}
190     };
191
192     qtype = g_enum_register_static ("GstFlacEncQuality", values);
193   }
194   return qtype;
195 }
196
197 static void
198 gst_flac_enc_base_init (gpointer g_class)
199 {
200   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
201
202   gst_element_class_add_pad_template (element_class,
203       gst_static_pad_template_get (&src_factory));
204   gst_element_class_add_pad_template (element_class,
205       gst_static_pad_template_get (&sink_factory));
206
207   gst_element_class_set_details (element_class, &flacenc_details);
208
209   GST_DEBUG_CATEGORY_INIT (flacenc_debug, "flacenc", 0,
210       "Flac encoding element");
211 }
212
213 static void
214 gst_flac_enc_class_init (GstFlacEncClass * klass)
215 {
216   GObjectClass *gobject_class;
217   GstElementClass *gstelement_class;
218
219   gobject_class = (GObjectClass *) klass;
220   gstelement_class = (GstElementClass *) klass;
221
222   gobject_class->set_property = gst_flac_enc_set_property;
223   gobject_class->get_property = gst_flac_enc_get_property;
224   gobject_class->finalize = gst_flac_enc_finalize;
225
226   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QUALITY,
227       g_param_spec_enum ("quality",
228           "Quality",
229           "Speed versus compression tradeoff",
230           GST_TYPE_FLAC_ENC_QUALITY, DEFAULT_QUALITY, G_PARAM_READWRITE));
231   g_object_class_install_property (G_OBJECT_CLASS (klass),
232       PROP_STREAMABLE_SUBSET, g_param_spec_boolean ("streamable_subset",
233           "Streamable subset",
234           "true to limit encoder to generating a Subset stream, else false",
235           TRUE, G_PARAM_READWRITE));
236   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MID_SIDE_STEREO,
237       g_param_spec_boolean ("mid_side_stereo", "Do mid side stereo",
238           "Do mid side stereo (only for stereo input)",
239           flacenc_params[DEFAULT_QUALITY].mid_side, G_PARAM_READWRITE));
240   g_object_class_install_property (G_OBJECT_CLASS (klass),
241       PROP_LOOSE_MID_SIDE_STEREO, g_param_spec_boolean ("loose_mid_side_stereo",
242           "Loose mid side stereo", "Loose mid side stereo",
243           flacenc_params[DEFAULT_QUALITY].loose_mid_side, G_PARAM_READWRITE));
244   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BLOCKSIZE,
245       g_param_spec_uint ("blocksize", "Blocksize", "Blocksize in samples",
246           FLAC__MIN_BLOCK_SIZE, FLAC__MAX_BLOCK_SIZE,
247           flacenc_params[DEFAULT_QUALITY].blocksize, G_PARAM_READWRITE));
248   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MAX_LPC_ORDER,
249       g_param_spec_uint ("max_lpc_order", "Max LPC order",
250           "Max LPC order; 0 => use only fixed predictors", 0,
251           FLAC__MAX_LPC_ORDER, flacenc_params[DEFAULT_QUALITY].max_lpc_order,
252           G_PARAM_READWRITE));
253   g_object_class_install_property (G_OBJECT_CLASS (klass),
254       PROP_QLP_COEFF_PRECISION, g_param_spec_uint ("qlp_coeff_precision",
255           "QLP coefficients precision",
256           "Precision in bits of quantized linear-predictor coefficients; 0 = automatic",
257           0, 32, flacenc_params[DEFAULT_QUALITY].qlp_coeff_precision,
258           G_PARAM_READWRITE));
259   g_object_class_install_property (G_OBJECT_CLASS (klass),
260       PROP_QLP_COEFF_PREC_SEARCH, g_param_spec_boolean ("qlp_coeff_prec_search",
261           "Do QLP coefficients precision search",
262           "false = use qlp_coeff_precision, "
263           "true = search around qlp_coeff_precision, take best",
264           flacenc_params[DEFAULT_QUALITY].qlp_coeff_prec_search,
265           G_PARAM_READWRITE));
266   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ESCAPE_CODING,
267       g_param_spec_boolean ("escape_coding", "Do Escape coding",
268           "search for escape codes in the entropy coding stage "
269           "for slightly better compression",
270           flacenc_params[DEFAULT_QUALITY].escape_coding, G_PARAM_READWRITE));
271   g_object_class_install_property (G_OBJECT_CLASS (klass),
272       PROP_EXHAUSTIVE_MODEL_SEARCH,
273       g_param_spec_boolean ("exhaustive_model_search",
274           "Do exhaustive model search",
275           "do exhaustive search of LP coefficient quantization (expensive!)",
276           flacenc_params[DEFAULT_QUALITY].exhaustive_model_search,
277           G_PARAM_READWRITE));
278   g_object_class_install_property (G_OBJECT_CLASS (klass),
279       PROP_MIN_RESIDUAL_PARTITION_ORDER,
280       g_param_spec_uint ("min_residual_partition_order",
281           "Min residual partition order",
282           "Min residual partition order (above 4 doesn't usually help much)", 0,
283           16, flacenc_params[DEFAULT_QUALITY].min_residual_partition_order,
284           G_PARAM_READWRITE));
285   g_object_class_install_property (G_OBJECT_CLASS (klass),
286       PROP_MAX_RESIDUAL_PARTITION_ORDER,
287       g_param_spec_uint ("max_residual_partition_order",
288           "Max residual partition order",
289           "Max residual partition order (above 4 doesn't usually help much)", 0,
290           16, flacenc_params[DEFAULT_QUALITY].max_residual_partition_order,
291           G_PARAM_READWRITE));
292   g_object_class_install_property (G_OBJECT_CLASS (klass),
293       PROP_RICE_PARAMETER_SEARCH_DIST,
294       g_param_spec_uint ("rice_parameter_search_dist",
295           "rice_parameter_search_dist",
296           "0 = try only calc'd parameter k; else try all [k-dist..k+dist] "
297           "parameters, use best", 0, FLAC__MAX_RICE_PARTITION_ORDER,
298           flacenc_params[DEFAULT_QUALITY].rice_parameter_search_dist,
299           G_PARAM_READWRITE));
300
301   gstelement_class->change_state = gst_flac_enc_change_state;
302 }
303
304 static void
305 gst_flac_enc_init (GstFlacEnc * flacenc, GstFlacEncClass * klass)
306 {
307   GstElementClass *eclass = GST_ELEMENT_CLASS (klass);
308
309   flacenc->sinkpad =
310       gst_pad_new_from_template (gst_element_class_get_pad_template (eclass,
311           "sink"), "sink");
312   gst_element_add_pad (GST_ELEMENT (flacenc), flacenc->sinkpad);
313   gst_pad_set_chain_function (flacenc->sinkpad, gst_flac_enc_chain);
314   gst_pad_set_event_function (flacenc->sinkpad, gst_flac_enc_sink_event);
315   gst_pad_set_setcaps_function (flacenc->sinkpad, gst_flac_enc_sink_setcaps);
316
317   flacenc->srcpad =
318       gst_pad_new_from_template (gst_element_class_get_pad_template (eclass,
319           "src"), "src");
320   gst_pad_use_fixed_caps (flacenc->srcpad);
321   gst_element_add_pad (GST_ELEMENT (flacenc), flacenc->srcpad);
322
323 #ifdef LEGACY_FLAC
324   flacenc->encoder = FLAC__seekable_stream_encoder_new ();
325 #else
326   flacenc->encoder = FLAC__stream_encoder_new ();
327 #endif
328
329   flacenc->offset = 0;
330   flacenc->samples_written = 0;
331   gst_flac_enc_update_quality (flacenc, DEFAULT_QUALITY);
332   flacenc->tags = gst_tag_list_new ();
333   flacenc->got_headers = FALSE;
334   flacenc->headers = NULL;
335 }
336
337 static void
338 gst_flac_enc_finalize (GObject * object)
339 {
340   GstFlacEnc *flacenc = GST_FLAC_ENC (object);
341
342   gst_tag_list_free (flacenc->tags);
343 #ifdef LEGACY_FLAC
344   FLAC__seekable_stream_encoder_delete (flacenc->encoder);
345 #else
346   FLAC__stream_encoder_delete (flacenc->encoder);
347 #endif
348
349   G_OBJECT_CLASS (parent_class)->finalize (object);
350 }
351
352 static void
353 add_one_tag (const GstTagList * list, const gchar * tag, gpointer user_data)
354 {
355   GList *comments;
356   GList *it;
357   GstFlacEnc *flacenc = GST_FLAC_ENC (user_data);
358
359   comments = gst_tag_to_vorbis_comments (list, tag);
360   for (it = comments; it != NULL; it = it->next) {
361     FLAC__StreamMetadata_VorbisComment_Entry commment_entry;
362
363     commment_entry.length = strlen (it->data);
364     commment_entry.entry = it->data;
365     FLAC__metadata_object_vorbiscomment_insert_comment (flacenc->meta[0],
366         flacenc->meta[0]->data.vorbis_comment.num_comments,
367         commment_entry, TRUE);
368     g_free (it->data);
369   }
370   g_list_free (comments);
371 }
372
373 static void
374 gst_flac_enc_set_metadata (GstFlacEnc * flacenc)
375 {
376   const GstTagList *user_tags;
377   GstTagList *copy;
378
379   g_return_if_fail (flacenc != NULL);
380   user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (flacenc));
381   if ((flacenc->tags == NULL) && (user_tags == NULL)) {
382     return;
383   }
384   copy = gst_tag_list_merge (user_tags, flacenc->tags,
385       gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (flacenc)));
386   flacenc->meta = g_malloc (sizeof (FLAC__StreamMetadata **));
387
388   flacenc->meta[0] =
389       FLAC__metadata_object_new (FLAC__METADATA_TYPE_VORBIS_COMMENT);
390   gst_tag_list_foreach (copy, add_one_tag, flacenc);
391
392 #ifdef LEGACY_FLAC
393   if (FLAC__seekable_stream_encoder_set_metadata (flacenc->encoder,
394           flacenc->meta, 1) != true)
395 #else
396   if (FLAC__stream_encoder_set_metadata (flacenc->encoder,
397           flacenc->meta, 1) != true)
398 #endif
399     g_warning ("Dude, i'm already initialized!");
400   gst_tag_list_free (copy);
401 }
402
403 static gboolean
404 gst_flac_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
405 {
406   GstFlacEnc *flacenc;
407   GstStructure *structure;
408
409 #ifdef LEGACY_FLAC
410   FLAC__SeekableStreamEncoderState state;
411 #else
412   FLAC__StreamEncoderInitStatus init_status;
413 #endif
414   gint depth, chans, rate, width;
415
416   flacenc = GST_FLAC_ENC (gst_pad_get_parent (pad));
417
418 #ifdef LEGACY_FLAC
419   if (FLAC__seekable_stream_encoder_get_state (flacenc->encoder) !=
420       FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
421 #else
422   if (FLAC__stream_encoder_get_state (flacenc->encoder) !=
423       FLAC__STREAM_ENCODER_UNINITIALIZED)
424 #endif
425
426     goto encoder_already_initialized;
427
428   structure = gst_caps_get_structure (caps, 0);
429
430   if (!gst_structure_get_int (structure, "channels", &chans) ||
431       !gst_structure_get_int (structure, "width", &width) ||
432       !gst_structure_get_int (structure, "depth", &depth) ||
433       !gst_structure_get_int (structure, "rate", &rate)) {
434     GST_DEBUG_OBJECT (flacenc, "incomplete caps: %" GST_PTR_FORMAT, caps);
435     return FALSE;
436   }
437
438   flacenc->channels = chans;
439   flacenc->depth = depth;
440   flacenc->sample_rate = rate;
441
442   caps = gst_caps_new_simple ("audio/x-flac",
443       "channels", G_TYPE_INT, flacenc->channels,
444       "rate", G_TYPE_INT, flacenc->sample_rate, NULL);
445
446   if (!gst_pad_set_caps (flacenc->srcpad, caps))
447     goto setting_src_caps_failed;
448
449   gst_caps_unref (caps);
450
451 #ifdef LEGACY_FLAC
452   FLAC__seekable_stream_encoder_set_bits_per_sample (flacenc->encoder,
453       flacenc->depth);
454   FLAC__seekable_stream_encoder_set_sample_rate (flacenc->encoder,
455       flacenc->sample_rate);
456   FLAC__seekable_stream_encoder_set_channels (flacenc->encoder,
457       flacenc->channels);
458
459   FLAC__seekable_stream_encoder_set_write_callback (flacenc->encoder,
460       gst_flac_enc_write_callback);
461   FLAC__seekable_stream_encoder_set_seek_callback (flacenc->encoder,
462       gst_flac_enc_seek_callback);
463   FLAC__seekable_stream_encoder_set_tell_callback (flacenc->encoder,
464       gst_flac_enc_tell_callback);
465
466   FLAC__seekable_stream_encoder_set_client_data (flacenc->encoder, flacenc);
467 #else
468   FLAC__stream_encoder_set_bits_per_sample (flacenc->encoder, flacenc->depth);
469   FLAC__stream_encoder_set_sample_rate (flacenc->encoder, flacenc->sample_rate);
470   FLAC__stream_encoder_set_channels (flacenc->encoder, flacenc->channels);
471 #endif
472
473   gst_flac_enc_set_metadata (flacenc);
474
475 #ifdef LEGACY_FLAC
476   state = FLAC__seekable_stream_encoder_init (flacenc->encoder);
477   if (state != FLAC__STREAM_ENCODER_OK)
478     goto failed_to_initialize;
479 #else
480   init_status = FLAC__stream_encoder_init_stream (flacenc->encoder,
481       gst_flac_enc_write_callback, gst_flac_enc_seek_callback,
482       gst_flac_enc_tell_callback, NULL, flacenc);
483   if (init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK)
484     goto failed_to_initialize;
485 #endif
486
487   gst_object_unref (flacenc);
488
489   return TRUE;
490
491 encoder_already_initialized:
492   {
493     g_warning ("flac already initialized -- fixme allow this");
494     gst_object_unref (flacenc);
495     return FALSE;
496   }
497 setting_src_caps_failed:
498   {
499     GST_DEBUG_OBJECT (flacenc,
500         "Couldn't set caps on source pad: %" GST_PTR_FORMAT, caps);
501     gst_caps_unref (caps);
502     gst_object_unref (flacenc);
503     return FALSE;
504   }
505 failed_to_initialize:
506   {
507     GST_ELEMENT_ERROR (flacenc, LIBRARY, INIT, (NULL),
508         ("could not initialize encoder (wrong parameters?)"));
509     gst_object_unref (flacenc);
510     return FALSE;
511   }
512 }
513
514 static gboolean
515 gst_flac_enc_update_quality (GstFlacEnc * flacenc, gint quality)
516 {
517   flacenc->quality = quality;
518
519 #ifdef LEGACY_FLAC
520 #define DO_UPDATE(name, val, str)                                               \
521   G_STMT_START {                                                                \
522     if (FLAC__seekable_stream_encoder_get_##name (flacenc->encoder) !=          \
523         flacenc_params[quality].val) {                                          \
524       FLAC__seekable_stream_encoder_set_##name (flacenc->encoder,               \
525           flacenc_params[quality].val);                                         \
526       g_object_notify (G_OBJECT (flacenc), str);                                \
527     }                                                                           \
528   } G_STMT_END
529
530 #else
531 #define DO_UPDATE(name, val, str)                                               \
532   G_STMT_START {                                                                \
533     if (FLAC__stream_encoder_get_##name (flacenc->encoder) !=                   \
534         flacenc_params[quality].val) {                                          \
535       FLAC__stream_encoder_set_##name (flacenc->encoder,                        \
536           flacenc_params[quality].val);                                         \
537       g_object_notify (G_OBJECT (flacenc), str);                                \
538     }                                                                           \
539   } G_STMT_END
540
541 #endif
542
543   g_object_freeze_notify (G_OBJECT (flacenc));
544
545   if (flacenc->channels == 2) {
546     DO_UPDATE (do_mid_side_stereo, mid_side, "mid_side_stereo");
547     DO_UPDATE (loose_mid_side_stereo, loose_mid_side, "loose_mid_side");
548   }
549
550   DO_UPDATE (blocksize, blocksize, "blocksize");
551   DO_UPDATE (max_lpc_order, max_lpc_order, "max_lpc_order");
552   DO_UPDATE (qlp_coeff_precision, qlp_coeff_precision, "qlp_coeff_precision");
553   DO_UPDATE (do_qlp_coeff_prec_search, qlp_coeff_prec_search,
554       "qlp_coeff_prec_search");
555   DO_UPDATE (do_escape_coding, escape_coding, "escape_coding");
556   DO_UPDATE (do_exhaustive_model_search, exhaustive_model_search,
557       "exhaustive_model_search");
558   DO_UPDATE (min_residual_partition_order, min_residual_partition_order,
559       "min_residual_partition_order");
560   DO_UPDATE (max_residual_partition_order, max_residual_partition_order,
561       "max_residual_partition_order");
562   DO_UPDATE (rice_parameter_search_dist, rice_parameter_search_dist,
563       "rice_parameter_search_dist");
564
565 #undef DO_UPDATE
566
567   g_object_thaw_notify (G_OBJECT (flacenc));
568
569   return TRUE;
570 }
571
572 #ifdef LEGACY_FLAC
573 static FLAC__SeekableStreamEncoderSeekStatus
574 gst_flac_enc_seek_callback (const FLAC__SeekableStreamEncoder * encoder,
575     FLAC__uint64 absolute_byte_offset, void *client_data)
576 #else
577 static FLAC__StreamEncoderSeekStatus
578 gst_flac_enc_seek_callback (const FLAC__StreamEncoder * encoder,
579     FLAC__uint64 absolute_byte_offset, void *client_data)
580 #endif
581 {
582   GstFlacEnc *flacenc;
583   GstEvent *event;
584   GstPad *peerpad;
585
586   flacenc = GST_FLAC_ENC (client_data);
587
588   if (flacenc->stopped)
589 #ifdef LEGACY_FLAC
590     return FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK;
591 #else
592     return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
593 #endif
594   event = gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_BYTES,
595       absolute_byte_offset, GST_BUFFER_OFFSET_NONE, 0);
596
597   if ((peerpad = gst_pad_get_peer (flacenc->srcpad))) {
598     gboolean ret = gst_pad_send_event (peerpad, event);
599
600     gst_object_unref (peerpad);
601
602     if (ret) {
603       GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " %s", absolute_byte_offset,
604           "succeeded");
605     } else {
606       GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " %s", absolute_byte_offset,
607           "failed");
608     }
609   } else {
610     GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " failed (no peer pad)",
611         absolute_byte_offset);
612   }
613
614   flacenc->offset = absolute_byte_offset;
615 #ifdef LEGACY_FLAC
616   return FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK;
617 #else
618   return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
619 #endif
620 }
621
622 static void
623 notgst_value_array_append_buffer (GValue * array_val, GstBuffer * buf)
624 {
625   GValue value = { 0, };
626
627   g_value_init (&value, GST_TYPE_BUFFER);
628   /* copy buffer to avoid problems with circular refcounts */
629   buf = gst_buffer_copy (buf);
630   /* again, for good measure */
631   GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
632   gst_value_set_buffer (&value, buf);
633   gst_buffer_unref (buf);
634   gst_value_array_append_value (array_val, &value);
635   g_value_unset (&value);
636 }
637
638 #define HDR_TYPE_STREAMINFO     0
639 #define HDR_TYPE_VORBISCOMMENT  4
640
641 static void
642 gst_flac_enc_process_stream_headers (GstFlacEnc * enc)
643 {
644   GstBuffer *vorbiscomment = NULL;
645   GstBuffer *streaminfo = NULL;
646   GstBuffer *marker = NULL;
647   GValue array = { 0, };
648   GstCaps *caps;
649   GList *l;
650
651   caps = gst_caps_new_simple ("audio/x-flac",
652       "channels", G_TYPE_INT, enc->channels,
653       "rate", G_TYPE_INT, enc->sample_rate, NULL);
654
655   for (l = enc->headers; l != NULL; l = l->next) {
656     const guint8 *data;
657     guint size;
658
659     /* mark buffers so oggmux will ignore them if it already muxed the
660      * header buffers from the streamheaders field in the caps */
661     l->data = gst_buffer_make_metadata_writable (GST_BUFFER (l->data));
662     GST_BUFFER_FLAG_SET (GST_BUFFER (l->data), GST_BUFFER_FLAG_IN_CAPS);
663
664     data = GST_BUFFER_DATA (GST_BUFFER_CAST (l->data));
665     size = GST_BUFFER_SIZE (GST_BUFFER_CAST (l->data));
666
667     /* find initial 4-byte marker which we need to skip later on */
668     if (size == 4 && memcmp (data, "fLaC", 4) == 0) {
669       marker = GST_BUFFER_CAST (l->data);
670     } else if (size > 1 && (data[0] & 0x7f) == HDR_TYPE_STREAMINFO) {
671       streaminfo = GST_BUFFER_CAST (l->data);
672     } else if (size > 1 && (data[0] & 0x7f) == HDR_TYPE_VORBISCOMMENT) {
673       vorbiscomment = GST_BUFFER_CAST (l->data);
674     }
675   }
676
677   if (marker == NULL || streaminfo == NULL || vorbiscomment == NULL) {
678     GST_WARNING_OBJECT (enc, "missing header %p %p %p, muxing into container "
679         "formats may be broken", marker, streaminfo, vorbiscomment);
680     goto push_headers;
681   }
682
683   g_value_init (&array, GST_TYPE_ARRAY);
684
685   /* add marker including STREAMINFO header */
686   {
687     GstBuffer *buf;
688     guint16 num;
689
690     /* minus one for the marker that is merged with streaminfo here */
691     num = g_list_length (enc->headers) - 1;
692
693     buf = gst_buffer_new_and_alloc (13 + GST_BUFFER_SIZE (streaminfo));
694     GST_BUFFER_DATA (buf)[0] = 0x7f;
695     memcpy (GST_BUFFER_DATA (buf) + 1, "FLAC", 4);
696     GST_BUFFER_DATA (buf)[5] = 0x01;    /* mapping version major */
697     GST_BUFFER_DATA (buf)[6] = 0x00;    /* mapping version minor */
698     GST_BUFFER_DATA (buf)[7] = (num & 0xFF00) >> 8;
699     GST_BUFFER_DATA (buf)[8] = (num & 0x00FF) >> 0;
700     memcpy (GST_BUFFER_DATA (buf) + 9, "fLaC", 4);
701     memcpy (GST_BUFFER_DATA (buf) + 13, GST_BUFFER_DATA (streaminfo),
702         GST_BUFFER_SIZE (streaminfo));
703     notgst_value_array_append_buffer (&array, buf);
704     gst_buffer_unref (buf);
705   }
706
707   /* add VORBISCOMMENT header */
708   notgst_value_array_append_buffer (&array, vorbiscomment);
709
710   /* add other headers, if there are any */
711   for (l = enc->headers; l != NULL; l = l->next) {
712     if (GST_BUFFER_CAST (l->data) != marker &&
713         GST_BUFFER_CAST (l->data) != streaminfo &&
714         GST_BUFFER_CAST (l->data) != vorbiscomment) {
715       notgst_value_array_append_buffer (&array, GST_BUFFER_CAST (l->data));
716     }
717   }
718
719   gst_structure_set_value (gst_caps_get_structure (caps, 0),
720       "streamheader", &array);
721   g_value_unset (&array);
722
723 push_headers:
724
725   gst_pad_set_caps (enc->srcpad, caps);
726
727   /* push header buffers; update caps, so when we push the first buffer the
728    * negotiated caps will change to caps that include the streamheader field */
729   for (l = enc->headers; l != NULL; l = l->next) {
730     GstBuffer *buf;
731
732     buf = GST_BUFFER (l->data);
733     gst_buffer_set_caps (buf, caps);
734     GST_LOG ("Pushing header buffer, size %u bytes", GST_BUFFER_SIZE (buf));
735     (void) gst_pad_push (enc->srcpad, buf);
736     l->data = NULL;
737   }
738   g_list_free (enc->headers);
739   enc->headers = NULL;
740
741   gst_caps_unref (caps);
742 }
743
744 #ifdef LEGACY_FLAC
745 static FLAC__StreamEncoderWriteStatus
746 gst_flac_enc_write_callback (const FLAC__SeekableStreamEncoder * encoder,
747     const FLAC__byte buffer[], unsigned bytes,
748     unsigned samples, unsigned current_frame, void *client_data)
749 #else
750 static FLAC__StreamEncoderWriteStatus
751 gst_flac_enc_write_callback (const FLAC__StreamEncoder * encoder,
752     const FLAC__byte buffer[], size_t bytes,
753     unsigned samples, unsigned current_frame, void *client_data)
754 #endif
755 {
756   GstFlowReturn ret = GST_FLOW_OK;
757   GstFlacEnc *flacenc;
758   GstBuffer *outbuf;
759
760   flacenc = GST_FLAC_ENC (client_data);
761
762   if (flacenc->stopped)
763     return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
764
765   outbuf = gst_buffer_new_and_alloc (bytes);
766   memcpy (GST_BUFFER_DATA (outbuf), buffer, bytes);
767
768   if (samples > 0 && flacenc->samples_written != (guint64) - 1) {
769     guint64 granulepos;
770
771     GST_BUFFER_TIMESTAMP (outbuf) =
772         GST_FRAMES_TO_CLOCK_TIME (flacenc->samples_written,
773         flacenc->sample_rate);
774     GST_BUFFER_DURATION (outbuf) =
775         GST_FRAMES_TO_CLOCK_TIME (samples, flacenc->sample_rate);
776     /* offset_end = granulepos for ogg muxer */
777     granulepos = flacenc->samples_written + samples;
778     GST_BUFFER_OFFSET_END (outbuf) = granulepos;
779     /* offset = timestamp corresponding to granulepos for ogg muxer
780      * (see vorbisenc for a much more elaborate version of this) */
781     GST_BUFFER_OFFSET (outbuf) =
782         GST_FRAMES_TO_CLOCK_TIME (granulepos, flacenc->sample_rate);
783   } else {
784     GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
785     GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
786   }
787
788   /* we assume libflac passes us stuff neatly framed */
789   if (!flacenc->got_headers) {
790     if (samples == 0) {
791       GST_DEBUG_OBJECT (flacenc, "Got header, queueing (%u bytes)", bytes);
792       flacenc->headers = g_list_append (flacenc->headers, outbuf);
793       /* note: it's important that we increase our byte offset */
794       goto out;
795     } else {
796       GST_INFO_OBJECT (flacenc, "Non-header packet, we have all headers now");
797       gst_flac_enc_process_stream_headers (flacenc);
798       flacenc->got_headers = TRUE;
799     }
800   }
801
802   GST_LOG ("Pushing buffer: ts=%" GST_TIME_FORMAT ", samples=%u, size=%u, "
803       "pos=%" G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
804       samples, bytes, flacenc->offset);
805
806   gst_buffer_set_caps (outbuf, GST_PAD_CAPS (flacenc->srcpad));
807   ret = gst_pad_push (flacenc->srcpad, outbuf);
808
809 out:
810
811   flacenc->offset += bytes;
812   flacenc->samples_written += samples;
813
814   if (GST_FLOW_IS_FATAL (ret))
815     return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
816
817   return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
818 }
819
820 #ifdef LEGACY_FLAC
821 static FLAC__SeekableStreamEncoderTellStatus
822 gst_flac_enc_tell_callback (const FLAC__SeekableStreamEncoder * encoder,
823     FLAC__uint64 * absolute_byte_offset, void *client_data)
824 #else
825 static FLAC__StreamEncoderTellStatus
826 gst_flac_enc_tell_callback (const FLAC__StreamEncoder * encoder,
827     FLAC__uint64 * absolute_byte_offset, void *client_data)
828 #endif
829 {
830   GstFlacEnc *flacenc = GST_FLAC_ENC (client_data);
831
832   *absolute_byte_offset = flacenc->offset;
833
834 #ifdef LEGACY_FLAC
835   return FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK;
836 #else
837   return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
838 #endif
839 }
840
841 static gboolean
842 gst_flac_enc_sink_event (GstPad * pad, GstEvent * event)
843 {
844   GstFlacEnc *flacenc;
845   GstTagList *taglist;
846   gboolean ret = TRUE;
847
848   flacenc = GST_FLAC_ENC (gst_pad_get_parent (pad));
849
850   GST_DEBUG ("Received %s event on sinkpad", GST_EVENT_TYPE_NAME (event));
851
852   switch (GST_EVENT_TYPE (event)) {
853     case GST_EVENT_NEWSEGMENT:{
854       GstFormat format;
855       gint64 start, stream_time;
856
857       if (flacenc->offset == 0) {
858         gst_event_parse_new_segment (event, NULL, NULL, &format, &start, NULL,
859             &stream_time);
860       } else {
861         start = -1;
862       }
863       if (start != 0) {
864         if (flacenc->offset > 0)
865           GST_DEBUG ("Not handling mid-stream newsegment event");
866         else
867           GST_DEBUG ("Not handling newsegment event with non-zero start");
868       } else {
869         GstEvent *e = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES,
870             0, -1, 0);
871
872         ret = gst_pad_push_event (flacenc->srcpad, e);
873       }
874       if (stream_time != 0) {
875         GST_DEBUG ("Not handling non-zero stream time");
876       }
877       gst_event_unref (event);
878       /* don't push it downstream, we'll generate our own via seek to 0 */
879       break;
880     }
881     case GST_EVENT_EOS:
882 #ifdef LEGACY_FLAC
883       FLAC__seekable_stream_encoder_finish (flacenc->encoder);
884 #else
885       FLAC__stream_encoder_finish (flacenc->encoder);
886 #endif
887       ret = gst_pad_event_default (pad, event);
888       break;
889     case GST_EVENT_TAG:
890       if (flacenc->tags) {
891         gst_event_parse_tag (event, &taglist);
892         gst_tag_list_insert (flacenc->tags, taglist, GST_TAG_MERGE_REPLACE);
893       } else {
894         g_assert_not_reached ();
895       }
896       ret = gst_pad_event_default (pad, event);
897       break;
898     default:
899       ret = gst_pad_event_default (pad, event);
900       break;
901   }
902
903   gst_object_unref (flacenc);
904
905   return ret;
906 }
907
908 static GstFlowReturn
909 gst_flac_enc_chain (GstPad * pad, GstBuffer * buffer)
910 {
911   GstFlacEnc *flacenc;
912   FLAC__int32 *data;
913   gulong insize;
914   gint samples, depth;
915   gulong i;
916   FLAC__bool res;
917
918   flacenc = GST_FLAC_ENC (GST_PAD_PARENT (pad));
919
920   /* make sure setcaps has been called and the encoder is set up */
921   if (G_UNLIKELY (flacenc->depth == 0))
922     return GST_FLOW_NOT_NEGOTIATED;
923
924   depth = flacenc->depth;
925
926   insize = GST_BUFFER_SIZE (buffer);
927   samples = insize / ((depth + 7) >> 3);
928
929   data = g_malloc (samples * sizeof (FLAC__int32));
930
931   if (depth == 8) {
932     gint8 *indata = (gint8 *) GST_BUFFER_DATA (buffer);
933
934     for (i = 0; i < samples; i++)
935       data[i] = (FLAC__int32) indata[i];
936   } else if (depth == 16) {
937     gint16 *indata = (gint16 *) GST_BUFFER_DATA (buffer);
938
939     for (i = 0; i < samples; i++)
940       data[i] = (FLAC__int32) indata[i];
941   } else {
942     g_assert_not_reached ();
943   }
944
945   gst_buffer_unref (buffer);
946
947 #ifdef LEGACY_FLAC
948   res = FLAC__seekable_stream_encoder_process_interleaved (flacenc->encoder,
949       (const FLAC__int32 *) data, samples / flacenc->channels);
950 #else
951   res = FLAC__stream_encoder_process_interleaved (flacenc->encoder,
952       (const FLAC__int32 *) data, samples / flacenc->channels);
953 #endif
954
955   g_free (data);
956
957   if (res)
958     return GST_FLOW_OK;
959   else
960     return GST_FLOW_ERROR;
961 }
962
963 static void
964 gst_flac_enc_set_property (GObject * object, guint prop_id,
965     const GValue * value, GParamSpec * pspec)
966 {
967   GstFlacEnc *this = GST_FLAC_ENC (object);
968
969   GST_OBJECT_LOCK (this);
970
971   switch (prop_id) {
972     case PROP_QUALITY:
973       gst_flac_enc_update_quality (this, g_value_get_enum (value));
974       break;
975     case PROP_STREAMABLE_SUBSET:
976 #ifdef LEGACY_FLAC
977       FLAC__seekable_stream_encoder_set_streamable_subset (this->encoder,
978           g_value_get_boolean (value));
979 #else
980       FLAC__stream_encoder_set_streamable_subset (this->encoder,
981           g_value_get_boolean (value));
982 #endif
983       break;
984     case PROP_MID_SIDE_STEREO:
985 #ifdef LEGACY_FLAC
986       FLAC__seekable_stream_encoder_set_do_mid_side_stereo (this->encoder,
987           g_value_get_boolean (value));
988 #else
989       FLAC__stream_encoder_set_do_mid_side_stereo (this->encoder,
990           g_value_get_boolean (value));
991 #endif
992       break;
993     case PROP_LOOSE_MID_SIDE_STEREO:
994 #ifdef LEGACY_FLAC
995       FLAC__seekable_stream_encoder_set_loose_mid_side_stereo (this->encoder,
996           g_value_get_boolean (value));
997 #else
998       FLAC__stream_encoder_set_loose_mid_side_stereo (this->encoder,
999           g_value_get_boolean (value));
1000 #endif
1001       break;
1002     case PROP_BLOCKSIZE:
1003 #ifdef LEGACY_FLAC
1004       FLAC__seekable_stream_encoder_set_blocksize (this->encoder,
1005           g_value_get_uint (value));
1006 #else
1007       FLAC__stream_encoder_set_blocksize (this->encoder,
1008           g_value_get_uint (value));
1009 #endif
1010       break;
1011     case PROP_MAX_LPC_ORDER:
1012 #ifdef LEGACY_FLAC
1013       FLAC__seekable_stream_encoder_set_max_lpc_order (this->encoder,
1014           g_value_get_uint (value));
1015 #else
1016       FLAC__stream_encoder_set_max_lpc_order (this->encoder,
1017           g_value_get_uint (value));
1018 #endif
1019       break;
1020     case PROP_QLP_COEFF_PRECISION:
1021 #ifdef LEGACY_FLAC
1022       FLAC__seekable_stream_encoder_set_qlp_coeff_precision (this->encoder,
1023           g_value_get_uint (value));
1024 #else
1025       FLAC__stream_encoder_set_qlp_coeff_precision (this->encoder,
1026           g_value_get_uint (value));
1027 #endif
1028       break;
1029     case PROP_QLP_COEFF_PREC_SEARCH:
1030 #ifdef LEGACY_FLAC
1031       FLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search (this->encoder,
1032           g_value_get_boolean (value));
1033 #else
1034       FLAC__stream_encoder_set_do_qlp_coeff_prec_search (this->encoder,
1035           g_value_get_boolean (value));
1036 #endif
1037       break;
1038     case PROP_ESCAPE_CODING:
1039 #ifdef LEGACY_FLAC
1040       FLAC__seekable_stream_encoder_set_do_escape_coding (this->encoder,
1041           g_value_get_boolean (value));
1042 #else
1043       FLAC__stream_encoder_set_do_escape_coding (this->encoder,
1044           g_value_get_boolean (value));
1045 #endif
1046       break;
1047     case PROP_EXHAUSTIVE_MODEL_SEARCH:
1048 #ifdef LEGACY_FLAC
1049       FLAC__seekable_stream_encoder_set_do_exhaustive_model_search (this->
1050           encoder, g_value_get_boolean (value));
1051 #else
1052       FLAC__stream_encoder_set_do_exhaustive_model_search (this->
1053           encoder, g_value_get_boolean (value));
1054 #endif
1055       break;
1056     case PROP_MIN_RESIDUAL_PARTITION_ORDER:
1057 #ifdef LEGACY_FLAC
1058       FLAC__seekable_stream_encoder_set_min_residual_partition_order (this->
1059           encoder, g_value_get_uint (value));
1060 #else
1061       FLAC__stream_encoder_set_min_residual_partition_order (this->
1062           encoder, g_value_get_uint (value));
1063 #endif
1064       break;
1065     case PROP_MAX_RESIDUAL_PARTITION_ORDER:
1066 #ifdef LEGACY_FLAC
1067       FLAC__seekable_stream_encoder_set_max_residual_partition_order (this->
1068           encoder, g_value_get_uint (value));
1069 #else
1070       FLAC__stream_encoder_set_max_residual_partition_order (this->
1071           encoder, g_value_get_uint (value));
1072 #endif
1073       break;
1074     case PROP_RICE_PARAMETER_SEARCH_DIST:
1075 #ifdef LEGACY_FLAC
1076       FLAC__seekable_stream_encoder_set_rice_parameter_search_dist (this->
1077           encoder, g_value_get_uint (value));
1078 #else
1079       FLAC__stream_encoder_set_rice_parameter_search_dist (this->
1080           encoder, g_value_get_uint (value));
1081 #endif
1082       break;
1083     default:
1084       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1085       break;
1086   }
1087
1088   GST_OBJECT_UNLOCK (this);
1089 }
1090
1091 static void
1092 gst_flac_enc_get_property (GObject * object, guint prop_id,
1093     GValue * value, GParamSpec * pspec)
1094 {
1095   GstFlacEnc *this = GST_FLAC_ENC (object);
1096
1097   GST_OBJECT_LOCK (this);
1098
1099   switch (prop_id) {
1100     case PROP_QUALITY:
1101       g_value_set_enum (value, this->quality);
1102       break;
1103     case PROP_STREAMABLE_SUBSET:
1104 #ifdef LEGACY_FLAC
1105       g_value_set_boolean (value,
1106           FLAC__seekable_stream_encoder_get_streamable_subset (this->encoder));
1107 #else
1108       g_value_set_boolean (value,
1109           FLAC__stream_encoder_get_streamable_subset (this->encoder));
1110 #endif
1111       break;
1112     case PROP_MID_SIDE_STEREO:
1113 #ifdef LEGACY_FLAC
1114       g_value_set_boolean (value,
1115           FLAC__seekable_stream_encoder_get_do_mid_side_stereo (this->encoder));
1116 #else
1117       g_value_set_boolean (value,
1118           FLAC__stream_encoder_get_do_mid_side_stereo (this->encoder));
1119 #endif
1120       break;
1121     case PROP_LOOSE_MID_SIDE_STEREO:
1122 #ifdef LEGACY_FLAC
1123       g_value_set_boolean (value,
1124           FLAC__seekable_stream_encoder_get_loose_mid_side_stereo (this->
1125               encoder));
1126 #else
1127       g_value_set_boolean (value,
1128           FLAC__stream_encoder_get_loose_mid_side_stereo (this->encoder));
1129 #endif
1130       break;
1131     case PROP_BLOCKSIZE:
1132 #ifdef LEGACY_FLAC
1133       g_value_set_uint (value,
1134           FLAC__seekable_stream_encoder_get_blocksize (this->encoder));
1135 #else
1136       g_value_set_uint (value,
1137           FLAC__stream_encoder_get_blocksize (this->encoder));
1138 #endif
1139       break;
1140     case PROP_MAX_LPC_ORDER:
1141 #ifdef LEGACY_FLAC
1142       g_value_set_uint (value,
1143           FLAC__seekable_stream_encoder_get_max_lpc_order (this->encoder));
1144 #else
1145       g_value_set_uint (value,
1146           FLAC__stream_encoder_get_max_lpc_order (this->encoder));
1147 #endif
1148       break;
1149     case PROP_QLP_COEFF_PRECISION:
1150 #ifdef LEGACY_FLAC
1151       g_value_set_uint (value,
1152           FLAC__seekable_stream_encoder_get_qlp_coeff_precision (this->
1153               encoder));
1154 #else
1155       g_value_set_uint (value,
1156           FLAC__stream_encoder_get_qlp_coeff_precision (this->encoder));
1157 #endif
1158       break;
1159     case PROP_QLP_COEFF_PREC_SEARCH:
1160 #ifdef LEGACY_FLAC
1161       g_value_set_boolean (value,
1162           FLAC__seekable_stream_encoder_get_do_qlp_coeff_prec_search (this->
1163               encoder));
1164 #else
1165       g_value_set_boolean (value,
1166           FLAC__stream_encoder_get_do_qlp_coeff_prec_search (this->encoder));
1167 #endif
1168       break;
1169     case PROP_ESCAPE_CODING:
1170 #ifdef LEGACY_FLAC
1171       g_value_set_boolean (value,
1172           FLAC__seekable_stream_encoder_get_do_escape_coding (this->encoder));
1173 #else
1174       g_value_set_boolean (value,
1175           FLAC__stream_encoder_get_do_escape_coding (this->encoder));
1176 #endif
1177       break;
1178     case PROP_EXHAUSTIVE_MODEL_SEARCH:
1179 #ifdef LEGACY_FLAC
1180       g_value_set_boolean (value,
1181           FLAC__seekable_stream_encoder_get_do_exhaustive_model_search (this->
1182               encoder));
1183 #else
1184       g_value_set_boolean (value,
1185           FLAC__stream_encoder_get_do_exhaustive_model_search (this->encoder));
1186 #endif
1187       break;
1188     case PROP_MIN_RESIDUAL_PARTITION_ORDER:
1189 #ifdef LEGACY_FLAC
1190       g_value_set_uint (value,
1191           FLAC__seekable_stream_encoder_get_min_residual_partition_order (this->
1192               encoder));
1193 #else
1194       g_value_set_uint (value,
1195           FLAC__stream_encoder_get_min_residual_partition_order (this->
1196               encoder));
1197 #endif
1198       break;
1199     case PROP_MAX_RESIDUAL_PARTITION_ORDER:
1200 #ifdef LEGACY_FLAC
1201       g_value_set_uint (value,
1202           FLAC__seekable_stream_encoder_get_max_residual_partition_order (this->
1203               encoder));
1204 #else
1205       g_value_set_uint (value,
1206           FLAC__stream_encoder_get_max_residual_partition_order (this->
1207               encoder));
1208 #endif
1209       break;
1210     case PROP_RICE_PARAMETER_SEARCH_DIST:
1211 #ifdef LEGACY_FLAC
1212       g_value_set_uint (value,
1213           FLAC__seekable_stream_encoder_get_rice_parameter_search_dist (this->
1214               encoder));
1215 #else
1216       g_value_set_uint (value,
1217           FLAC__stream_encoder_get_rice_parameter_search_dist (this->encoder));
1218 #endif
1219       break;
1220     default:
1221       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1222       break;
1223   }
1224
1225   GST_OBJECT_UNLOCK (this);
1226 }
1227
1228 static GstStateChangeReturn
1229 gst_flac_enc_change_state (GstElement * element, GstStateChange transition)
1230 {
1231   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1232   GstFlacEnc *flacenc = GST_FLAC_ENC (element);
1233
1234   switch (transition) {
1235     case GST_STATE_CHANGE_NULL_TO_READY:
1236     case GST_STATE_CHANGE_READY_TO_PAUSED:
1237       flacenc->stopped = FALSE;
1238       break;
1239     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1240     default:
1241       break;
1242   }
1243
1244   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1245
1246   switch (transition) {
1247     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1248       break;
1249     case GST_STATE_CHANGE_PAUSED_TO_READY:
1250 #ifdef LEGACY_FLAC
1251       if (FLAC__seekable_stream_encoder_get_state (flacenc->encoder) !=
1252           FLAC__STREAM_ENCODER_UNINITIALIZED) {
1253         flacenc->stopped = TRUE;
1254         FLAC__seekable_stream_encoder_finish (flacenc->encoder);
1255       }
1256 #else
1257       if (FLAC__stream_encoder_get_state (flacenc->encoder) !=
1258           FLAC__STREAM_ENCODER_UNINITIALIZED) {
1259         flacenc->stopped = TRUE;
1260         FLAC__stream_encoder_finish (flacenc->encoder);
1261       }
1262 #endif
1263       flacenc->offset = 0;
1264       flacenc->samples_written = 0;
1265       flacenc->channels = 0;
1266       flacenc->depth = 0;
1267       flacenc->sample_rate = 0;
1268       if (flacenc->meta) {
1269         FLAC__metadata_object_delete (flacenc->meta[0]);
1270         g_free (flacenc->meta);
1271         flacenc->meta = NULL;
1272       }
1273       g_list_foreach (flacenc->headers, (GFunc) gst_mini_object_unref, NULL);
1274       g_list_free (flacenc->headers);
1275       flacenc->headers = NULL;
1276       flacenc->got_headers = FALSE;
1277       break;
1278     case GST_STATE_CHANGE_READY_TO_NULL:
1279     default:
1280       break;
1281   }
1282
1283   return ret;
1284 }