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