Merge branch 'master' into 0.11
[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   PROP_PADDING,
146   PROP_SEEKPOINTS
147 };
148
149 GST_DEBUG_CATEGORY_STATIC (flacenc_debug);
150 #define GST_CAT_DEFAULT flacenc_debug
151
152 #define gst_flac_enc_parent_class parent_class
153 G_DEFINE_TYPE_WITH_CODE (GstFlacEnc, gst_flac_enc, GST_TYPE_ELEMENT,
154     G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL);
155     G_IMPLEMENT_INTERFACE (GST_TYPE_PRESET, NULL));
156
157 static void gst_flac_enc_finalize (GObject * object);
158
159 static gboolean gst_flac_enc_sink_setcaps (GstPad * pad, GstCaps * caps);
160 static GstCaps *gst_flac_enc_sink_getcaps (GstPad * pad);
161 static gboolean gst_flac_enc_sink_event (GstPad * pad, GstEvent * event);
162 static GstFlowReturn gst_flac_enc_chain (GstPad * pad, GstBuffer * buffer);
163
164 static gboolean gst_flac_enc_update_quality (GstFlacEnc * flacenc,
165     gint quality);
166 static void gst_flac_enc_set_property (GObject * object, guint prop_id,
167     const GValue * value, GParamSpec * pspec);
168 static void gst_flac_enc_get_property (GObject * object, guint prop_id,
169     GValue * value, GParamSpec * pspec);
170 static GstStateChangeReturn gst_flac_enc_change_state (GstElement * element,
171     GstStateChange transition);
172
173 static FLAC__StreamEncoderWriteStatus
174 gst_flac_enc_write_callback (const FLAC__StreamEncoder * encoder,
175     const FLAC__byte buffer[], size_t bytes,
176     unsigned samples, unsigned current_frame, void *client_data);
177 static FLAC__StreamEncoderSeekStatus
178 gst_flac_enc_seek_callback (const FLAC__StreamEncoder * encoder,
179     FLAC__uint64 absolute_byte_offset, void *client_data);
180 static FLAC__StreamEncoderTellStatus
181 gst_flac_enc_tell_callback (const FLAC__StreamEncoder * encoder,
182     FLAC__uint64 * absolute_byte_offset, void *client_data);
183
184 typedef struct
185 {
186   gboolean exhaustive_model_search;
187   gboolean escape_coding;
188   gboolean mid_side;
189   gboolean loose_mid_side;
190   guint qlp_coeff_precision;
191   gboolean qlp_coeff_prec_search;
192   guint min_residual_partition_order;
193   guint max_residual_partition_order;
194   guint rice_parameter_search_dist;
195   guint max_lpc_order;
196   guint blocksize;
197 }
198 GstFlacEncParams;
199
200 static const GstFlacEncParams flacenc_params[] = {
201   {FALSE, FALSE, FALSE, FALSE, 0, FALSE, 2, 2, 0, 0, 1152},
202   {FALSE, FALSE, TRUE, TRUE, 0, FALSE, 2, 2, 0, 0, 1152},
203   {FALSE, FALSE, TRUE, FALSE, 0, FALSE, 0, 3, 0, 0, 1152},
204   {FALSE, FALSE, FALSE, FALSE, 0, FALSE, 3, 3, 0, 6, 4608},
205   {FALSE, FALSE, TRUE, TRUE, 0, FALSE, 3, 3, 0, 8, 4608},
206   {FALSE, FALSE, TRUE, FALSE, 0, FALSE, 3, 3, 0, 8, 4608},
207   {FALSE, FALSE, TRUE, FALSE, 0, FALSE, 0, 4, 0, 8, 4608},
208   {TRUE, FALSE, TRUE, FALSE, 0, FALSE, 0, 6, 0, 8, 4608},
209   {TRUE, FALSE, TRUE, FALSE, 0, FALSE, 0, 6, 0, 12, 4608},
210   {TRUE, TRUE, TRUE, FALSE, 0, FALSE, 0, 16, 0, 32, 4608},
211 };
212
213 #define DEFAULT_QUALITY 5
214 #define DEFAULT_PADDING 0
215 #define DEFAULT_SEEKPOINTS 0
216
217 #define GST_TYPE_FLAC_ENC_QUALITY (gst_flac_enc_quality_get_type ())
218 static GType
219 gst_flac_enc_quality_get_type (void)
220 {
221   static GType qtype = 0;
222
223   if (qtype == 0) {
224     static const GEnumValue values[] = {
225       {0, "0 - Fastest compression", "0"},
226       {1, "1", "1"},
227       {2, "2", "2"},
228       {3, "3", "3"},
229       {4, "4", "4"},
230       {5, "5 - Default", "5"},
231       {6, "6", "6"},
232       {7, "7", "7"},
233       {8, "8 - Highest compression", "8"},
234       {9, "9 - Insane", "9"},
235       {0, NULL, NULL}
236     };
237
238     qtype = g_enum_register_static ("GstFlacEncQuality", values);
239   }
240   return qtype;
241 }
242
243 static void
244 gst_flac_enc_class_init (GstFlacEncClass * klass)
245 {
246   GObjectClass *gobject_class;
247   GstElementClass *gstelement_class;
248
249   gobject_class = (GObjectClass *) klass;
250   gstelement_class = (GstElementClass *) klass;
251
252   GST_DEBUG_CATEGORY_INIT (flacenc_debug, "flacenc", 0,
253       "Flac encoding element");
254
255   gobject_class->set_property = gst_flac_enc_set_property;
256   gobject_class->get_property = gst_flac_enc_get_property;
257   gobject_class->finalize = gst_flac_enc_finalize;
258
259   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QUALITY,
260       g_param_spec_enum ("quality",
261           "Quality",
262           "Speed versus compression tradeoff",
263           GST_TYPE_FLAC_ENC_QUALITY, DEFAULT_QUALITY,
264           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
265   g_object_class_install_property (G_OBJECT_CLASS (klass),
266       PROP_STREAMABLE_SUBSET, g_param_spec_boolean ("streamable-subset",
267           "Streamable subset",
268           "true to limit encoder to generating a Subset stream, else false",
269           TRUE,
270           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
271   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MID_SIDE_STEREO,
272       g_param_spec_boolean ("mid-side-stereo", "Do mid side stereo",
273           "Do mid side stereo (only for stereo input)",
274           flacenc_params[DEFAULT_QUALITY].mid_side,
275           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
276   g_object_class_install_property (G_OBJECT_CLASS (klass),
277       PROP_LOOSE_MID_SIDE_STEREO, g_param_spec_boolean ("loose-mid-side-stereo",
278           "Loose mid side stereo", "Loose mid side stereo",
279           flacenc_params[DEFAULT_QUALITY].loose_mid_side,
280           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
281   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BLOCKSIZE,
282       g_param_spec_uint ("blocksize", "Blocksize", "Blocksize in samples",
283           FLAC__MIN_BLOCK_SIZE, FLAC__MAX_BLOCK_SIZE,
284           flacenc_params[DEFAULT_QUALITY].blocksize,
285           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
286   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MAX_LPC_ORDER,
287       g_param_spec_uint ("max-lpc-order", "Max LPC order",
288           "Max LPC order; 0 => use only fixed predictors", 0,
289           FLAC__MAX_LPC_ORDER, flacenc_params[DEFAULT_QUALITY].max_lpc_order,
290           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
291   g_object_class_install_property (G_OBJECT_CLASS (klass),
292       PROP_QLP_COEFF_PRECISION, g_param_spec_uint ("qlp-coeff-precision",
293           "QLP coefficients precision",
294           "Precision in bits of quantized linear-predictor coefficients; 0 = automatic",
295           0, 32, flacenc_params[DEFAULT_QUALITY].qlp_coeff_precision,
296           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
297   g_object_class_install_property (G_OBJECT_CLASS (klass),
298       PROP_QLP_COEFF_PREC_SEARCH, g_param_spec_boolean ("qlp-coeff-prec-search",
299           "Do QLP coefficients precision search",
300           "false = use qlp_coeff_precision, "
301           "true = search around qlp_coeff_precision, take best",
302           flacenc_params[DEFAULT_QUALITY].qlp_coeff_prec_search,
303           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
304   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ESCAPE_CODING,
305       g_param_spec_boolean ("escape-coding", "Do Escape coding",
306           "search for escape codes in the entropy coding stage "
307           "for slightly better compression",
308           flacenc_params[DEFAULT_QUALITY].escape_coding,
309           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
310   g_object_class_install_property (G_OBJECT_CLASS (klass),
311       PROP_EXHAUSTIVE_MODEL_SEARCH,
312       g_param_spec_boolean ("exhaustive-model-search",
313           "Do exhaustive model search",
314           "do exhaustive search of LP coefficient quantization (expensive!)",
315           flacenc_params[DEFAULT_QUALITY].exhaustive_model_search,
316           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
317   g_object_class_install_property (G_OBJECT_CLASS (klass),
318       PROP_MIN_RESIDUAL_PARTITION_ORDER,
319       g_param_spec_uint ("min-residual-partition-order",
320           "Min residual partition order",
321           "Min residual partition order (above 4 doesn't usually help much)", 0,
322           16, flacenc_params[DEFAULT_QUALITY].min_residual_partition_order,
323           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
324   g_object_class_install_property (G_OBJECT_CLASS (klass),
325       PROP_MAX_RESIDUAL_PARTITION_ORDER,
326       g_param_spec_uint ("max-residual-partition-order",
327           "Max residual partition order",
328           "Max residual partition order (above 4 doesn't usually help much)", 0,
329           16, flacenc_params[DEFAULT_QUALITY].max_residual_partition_order,
330           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
331   g_object_class_install_property (G_OBJECT_CLASS (klass),
332       PROP_RICE_PARAMETER_SEARCH_DIST,
333       g_param_spec_uint ("rice-parameter-search-dist",
334           "rice_parameter_search_dist",
335           "0 = try only calc'd parameter k; else try all [k-dist..k+dist] "
336           "parameters, use best", 0, FLAC__MAX_RICE_PARTITION_ORDER,
337           flacenc_params[DEFAULT_QUALITY].rice_parameter_search_dist,
338           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
339
340   /**
341    * GstFlacEnc:padding
342    *
343    * Write a PADDING block with this length in bytes
344    *
345    * Since: 0.10.16
346    **/
347   g_object_class_install_property (G_OBJECT_CLASS (klass),
348       PROP_PADDING,
349       g_param_spec_uint ("padding",
350           "Padding",
351           "Write a PADDING block with this length in bytes", 0, G_MAXUINT,
352           DEFAULT_PADDING,
353           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
354
355   /**
356    * GstFlacEnc:seekpoints
357    *
358    * Write a SEEKTABLE block with a specific number of seekpoints
359    * or with a specific interval spacing.
360    *
361    * Since: 0.10.18
362    **/
363   g_object_class_install_property (G_OBJECT_CLASS (klass),
364       PROP_SEEKPOINTS,
365       g_param_spec_int ("seekpoints",
366           "Seekpoints",
367           "Add SEEKTABLE metadata (if > 0, number of entries, if < 0, interval in sec)",
368           -G_MAXINT, G_MAXINT,
369           DEFAULT_SEEKPOINTS,
370           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
371
372   gstelement_class->change_state = gst_flac_enc_change_state;
373
374   gst_element_class_add_pad_template (gstelement_class,
375       gst_static_pad_template_get (&src_factory));
376   gst_element_class_add_pad_template (gstelement_class,
377       gst_static_pad_template_get (&sink_factory));
378
379   gst_element_class_set_details_simple (gstelement_class, "FLAC audio encoder",
380       "Codec/Encoder/Audio",
381       "Encodes audio with the FLAC lossless audio encoder",
382       "Wim Taymans <wim.taymans@chello.be>");
383 }
384
385 static void
386 gst_flac_enc_init (GstFlacEnc * flacenc)
387 {
388   flacenc->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
389   gst_pad_set_chain_function (flacenc->sinkpad,
390       GST_DEBUG_FUNCPTR (gst_flac_enc_chain));
391   gst_pad_set_event_function (flacenc->sinkpad,
392       GST_DEBUG_FUNCPTR (gst_flac_enc_sink_event));
393   gst_pad_set_getcaps_function (flacenc->sinkpad,
394       GST_DEBUG_FUNCPTR (gst_flac_enc_sink_getcaps));
395   gst_pad_set_setcaps_function (flacenc->sinkpad,
396       GST_DEBUG_FUNCPTR (gst_flac_enc_sink_setcaps));
397   gst_element_add_pad (GST_ELEMENT (flacenc), flacenc->sinkpad);
398
399   flacenc->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
400   gst_pad_use_fixed_caps (flacenc->srcpad);
401   gst_element_add_pad (GST_ELEMENT (flacenc), flacenc->srcpad);
402
403   flacenc->encoder = FLAC__stream_encoder_new ();
404
405   flacenc->offset = 0;
406   flacenc->samples_written = 0;
407   flacenc->channels = 0;
408   gst_flac_enc_update_quality (flacenc, DEFAULT_QUALITY);
409   flacenc->tags = gst_tag_list_new ();
410   flacenc->got_headers = FALSE;
411   flacenc->headers = NULL;
412   flacenc->last_flow = GST_FLOW_OK;
413 }
414
415 static void
416 gst_flac_enc_finalize (GObject * object)
417 {
418   GstFlacEnc *flacenc = GST_FLAC_ENC (object);
419
420   gst_tag_list_free (flacenc->tags);
421   FLAC__stream_encoder_delete (flacenc->encoder);
422
423   G_OBJECT_CLASS (parent_class)->finalize (object);
424 }
425
426 static void
427 add_one_tag (const GstTagList * list, const gchar * tag, gpointer user_data)
428 {
429   GList *comments;
430   GList *it;
431   GstFlacEnc *flacenc = GST_FLAC_ENC (user_data);
432
433   /* IMAGE and PREVIEW_IMAGE tags are already written
434    * differently, no need to store them inside the
435    * vorbiscomments too */
436   if (strcmp (tag, GST_TAG_IMAGE) == 0
437       || strcmp (tag, GST_TAG_PREVIEW_IMAGE) == 0)
438     return;
439
440   comments = gst_tag_to_vorbis_comments (list, tag);
441   for (it = comments; it != NULL; it = it->next) {
442     FLAC__StreamMetadata_VorbisComment_Entry commment_entry;
443
444     commment_entry.length = strlen (it->data);
445     commment_entry.entry = it->data;
446     FLAC__metadata_object_vorbiscomment_insert_comment (flacenc->meta[0],
447         flacenc->meta[0]->data.vorbis_comment.num_comments,
448         commment_entry, TRUE);
449     g_free (it->data);
450   }
451   g_list_free (comments);
452 }
453
454 static void
455 gst_flac_enc_set_metadata (GstFlacEnc * flacenc, guint64 total_samples)
456 {
457   const GstTagList *user_tags;
458   GstTagList *copy;
459   gint entries = 1;
460   gint n_images, n_preview_images;
461
462   g_return_if_fail (flacenc != NULL);
463   user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (flacenc));
464   if ((flacenc->tags == NULL) && (user_tags == NULL)) {
465     return;
466   }
467   copy = gst_tag_list_merge (user_tags, flacenc->tags,
468       gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (flacenc)));
469   n_images = gst_tag_list_get_tag_size (copy, GST_TAG_IMAGE);
470   n_preview_images = gst_tag_list_get_tag_size (copy, GST_TAG_PREVIEW_IMAGE);
471
472   flacenc->meta =
473       g_new0 (FLAC__StreamMetadata *, 3 + n_images + n_preview_images);
474
475   flacenc->meta[0] =
476       FLAC__metadata_object_new (FLAC__METADATA_TYPE_VORBIS_COMMENT);
477   gst_tag_list_foreach (copy, add_one_tag, flacenc);
478
479   if (n_images + n_preview_images > 0) {
480     GstBuffer *buffer;
481     GstCaps *caps;
482     GstStructure *structure;
483     GstTagImageType image_type = GST_TAG_IMAGE_TYPE_NONE;
484     gint i;
485     guint8 *data;
486     gsize size;
487
488     for (i = 0; i < n_images + n_preview_images; i++) {
489       if (i < n_images) {
490         if (!gst_tag_list_get_buffer_index (copy, GST_TAG_IMAGE, i, &buffer))
491           continue;
492       } else {
493         if (!gst_tag_list_get_buffer_index (copy, GST_TAG_PREVIEW_IMAGE,
494                 i - n_images, &buffer))
495           continue;
496       }
497
498       flacenc->meta[entries] =
499           FLAC__metadata_object_new (FLAC__METADATA_TYPE_PICTURE);
500
501       caps = gst_buffer_get_caps (buffer);
502       structure = gst_caps_get_structure (caps, 0);
503
504       gst_structure_get (structure, "image-type", GST_TYPE_TAG_IMAGE_TYPE,
505           &image_type, NULL);
506       /* Convert to ID3v2 APIC image type */
507       if (image_type == GST_TAG_IMAGE_TYPE_NONE)
508         image_type = (i < n_images) ? 0x00 : 0x01;
509       else
510         image_type = image_type + 2;
511
512       data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ);
513       FLAC__metadata_object_picture_set_data (flacenc->meta[entries],
514           data, size, TRUE);
515       gst_buffer_unmap (buffer, data, size);
516
517       /* FIXME: There's no way to set the picture type in libFLAC */
518       flacenc->meta[entries]->data.picture.type = image_type;
519       FLAC__metadata_object_picture_set_mime_type (flacenc->meta[entries],
520           (char *) gst_structure_get_name (structure), TRUE);
521
522       gst_caps_unref (caps);
523       gst_buffer_unref (buffer);
524       entries++;
525     }
526   }
527
528   if (flacenc->seekpoints && total_samples != GST_CLOCK_TIME_NONE) {
529     gboolean res;
530     guint samples;
531
532     flacenc->meta[entries] =
533         FLAC__metadata_object_new (FLAC__METADATA_TYPE_SEEKTABLE);
534     if (flacenc->seekpoints > 0) {
535       res =
536           FLAC__metadata_object_seektable_template_append_spaced_points
537           (flacenc->meta[entries], flacenc->seekpoints, total_samples);
538     } else {
539       samples = -flacenc->seekpoints * flacenc->sample_rate;
540       res =
541           FLAC__metadata_object_seektable_template_append_spaced_points_by_samples
542           (flacenc->meta[entries], samples, total_samples);
543     }
544     if (!res) {
545       GST_DEBUG_OBJECT (flacenc, "adding seekpoint template %d failed",
546           flacenc->seekpoints);
547       FLAC__metadata_object_delete (flacenc->meta[1]);
548       flacenc->meta[entries] = NULL;
549     } else {
550       entries++;
551     }
552   } else if (flacenc->seekpoints && total_samples == GST_CLOCK_TIME_NONE) {
553     GST_WARNING_OBJECT (flacenc, "total time unknown; can not add seekpoints");
554   }
555
556   if (flacenc->padding > 0) {
557     flacenc->meta[entries] =
558         FLAC__metadata_object_new (FLAC__METADATA_TYPE_PADDING);
559     flacenc->meta[entries]->length = flacenc->padding;
560     entries++;
561   }
562
563   if (FLAC__stream_encoder_set_metadata (flacenc->encoder,
564           flacenc->meta, entries) != true)
565     g_warning ("Dude, i'm already initialized!");
566
567   gst_tag_list_free (copy);
568 }
569
570 static void
571 gst_flac_enc_caps_append_structure_with_widths (GstCaps * caps,
572     GstStructure * s)
573 {
574   GstStructure *tmp;
575   GValue list = { 0, };
576   GValue depth = { 0, };
577
578
579   tmp = gst_structure_copy (s);
580   gst_structure_set (tmp, "width", G_TYPE_INT, 8, "depth", G_TYPE_INT, 8, NULL);
581   gst_caps_append_structure (caps, tmp);
582
583   tmp = gst_structure_copy (s);
584
585   g_value_init (&depth, G_TYPE_INT);
586   g_value_init (&list, GST_TYPE_LIST);
587   g_value_set_int (&depth, 12);
588   gst_value_list_append_value (&list, &depth);
589   g_value_set_int (&depth, 16);
590   gst_value_list_append_value (&list, &depth);
591
592   gst_structure_set (tmp, "width", G_TYPE_INT, 16, NULL);
593   gst_structure_set_value (tmp, "depth", &list);
594   gst_caps_append_structure (caps, tmp);
595
596   g_value_reset (&list);
597
598   tmp = s;
599
600   g_value_set_int (&depth, 20);
601   gst_value_list_append_value (&list, &depth);
602   g_value_set_int (&depth, 24);
603   gst_value_list_append_value (&list, &depth);
604
605   gst_structure_set (tmp, "width", G_TYPE_INT, 32, NULL);
606   gst_structure_set_value (tmp, "depth", &list);
607   gst_caps_append_structure (caps, tmp);
608
609   g_value_unset (&list);
610   g_value_unset (&depth);
611 }
612
613 static GstCaps *
614 gst_flac_enc_sink_getcaps (GstPad * pad)
615 {
616   GstCaps *ret = NULL;
617
618   GST_OBJECT_LOCK (pad);
619
620   if (GST_PAD_CAPS (pad)) {
621     ret = gst_caps_ref (GST_PAD_CAPS (pad));
622   } else {
623     gint i, c;
624
625     ret = gst_caps_new_empty ();
626
627     gst_flac_enc_caps_append_structure_with_widths (ret,
628         gst_structure_new ("audio/x-raw-int",
629             "endianness", G_TYPE_INT, G_BYTE_ORDER,
630             "signed", G_TYPE_BOOLEAN, TRUE,
631             "rate", GST_TYPE_INT_RANGE, 1, 655350,
632             "channels", GST_TYPE_INT_RANGE, 1, 2, NULL));
633
634     for (i = 3; i <= 8; i++) {
635       GValue positions = { 0, };
636       GValue pos = { 0, };
637       GstStructure *s;
638
639       g_value_init (&positions, GST_TYPE_ARRAY);
640       g_value_init (&pos, GST_TYPE_AUDIO_CHANNEL_POSITION);
641
642       for (c = 0; c < i; c++) {
643         g_value_set_enum (&pos, channel_positions[i - 1][c]);
644         gst_value_array_append_value (&positions, &pos);
645       }
646       g_value_unset (&pos);
647
648       s = gst_structure_new ("audio/x-raw-int",
649           "endianness", G_TYPE_INT, G_BYTE_ORDER,
650           "signed", G_TYPE_BOOLEAN, TRUE,
651           "rate", GST_TYPE_INT_RANGE, 1, 655350,
652           "channels", G_TYPE_INT, i, NULL);
653       gst_structure_set_value (s, "channel-positions", &positions);
654       g_value_unset (&positions);
655
656       gst_flac_enc_caps_append_structure_with_widths (ret, s);
657     }
658   }
659
660   GST_OBJECT_UNLOCK (pad);
661
662   GST_DEBUG_OBJECT (pad, "Return caps %" GST_PTR_FORMAT, ret);
663
664   return ret;
665 }
666
667 static guint64
668 gst_flac_enc_query_peer_total_samples (GstFlacEnc * flacenc, GstPad * pad)
669 {
670   GstFormat fmt = GST_FORMAT_DEFAULT;
671   gint64 duration;
672
673   GST_DEBUG_OBJECT (flacenc, "querying peer for DEFAULT format duration");
674   if (gst_pad_query_peer_duration (pad, &fmt, &duration)
675       && fmt == GST_FORMAT_DEFAULT && duration != GST_CLOCK_TIME_NONE)
676     goto done;
677
678   fmt = GST_FORMAT_TIME;
679   GST_DEBUG_OBJECT (flacenc, "querying peer for TIME format duration");
680
681   if (gst_pad_query_peer_duration (pad, &fmt, &duration) &&
682       fmt == GST_FORMAT_TIME && duration != GST_CLOCK_TIME_NONE) {
683     GST_DEBUG_OBJECT (flacenc, "peer reported duration %" GST_TIME_FORMAT,
684         GST_TIME_ARGS (duration));
685     duration = GST_CLOCK_TIME_TO_FRAMES (duration, flacenc->sample_rate);
686
687     goto done;
688   }
689
690   GST_DEBUG_OBJECT (flacenc, "Upstream reported no total samples");
691   return GST_CLOCK_TIME_NONE;
692
693 done:
694   GST_DEBUG_OBJECT (flacenc,
695       "Upstream reported %" G_GUINT64_FORMAT " total samples", duration);
696
697   return duration;
698 }
699
700 static gboolean
701 gst_flac_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
702 {
703   GstFlacEnc *flacenc;
704   GstStructure *structure;
705   guint64 total_samples = GST_CLOCK_TIME_NONE;
706   FLAC__StreamEncoderInitStatus init_status;
707   gint depth, chans, rate, width;
708
709   flacenc = GST_FLAC_ENC (gst_pad_get_parent (pad));
710
711   if (FLAC__stream_encoder_get_state (flacenc->encoder) !=
712       FLAC__STREAM_ENCODER_UNINITIALIZED)
713     goto encoder_already_initialized;
714
715   structure = gst_caps_get_structure (caps, 0);
716
717   if (!gst_structure_get_int (structure, "channels", &chans) ||
718       !gst_structure_get_int (structure, "width", &width) ||
719       !gst_structure_get_int (structure, "depth", &depth) ||
720       !gst_structure_get_int (structure, "rate", &rate)) {
721     GST_DEBUG_OBJECT (flacenc, "incomplete caps: %" GST_PTR_FORMAT, caps);
722     return FALSE;
723   }
724
725   flacenc->channels = chans;
726   flacenc->width = width;
727   flacenc->depth = depth;
728   flacenc->sample_rate = rate;
729
730   caps = gst_caps_new_simple ("audio/x-flac",
731       "channels", G_TYPE_INT, flacenc->channels,
732       "rate", G_TYPE_INT, flacenc->sample_rate, NULL);
733
734   if (!gst_pad_set_caps (flacenc->srcpad, caps))
735     goto setting_src_caps_failed;
736
737   gst_caps_unref (caps);
738
739   total_samples = gst_flac_enc_query_peer_total_samples (flacenc, pad);
740
741   FLAC__stream_encoder_set_bits_per_sample (flacenc->encoder, flacenc->depth);
742   FLAC__stream_encoder_set_sample_rate (flacenc->encoder, flacenc->sample_rate);
743   FLAC__stream_encoder_set_channels (flacenc->encoder, flacenc->channels);
744
745   if (total_samples != GST_CLOCK_TIME_NONE)
746     FLAC__stream_encoder_set_total_samples_estimate (flacenc->encoder,
747         MIN (total_samples, G_GUINT64_CONSTANT (0x0FFFFFFFFF)));
748
749   gst_flac_enc_set_metadata (flacenc, total_samples);
750
751   init_status = FLAC__stream_encoder_init_stream (flacenc->encoder,
752       gst_flac_enc_write_callback, gst_flac_enc_seek_callback,
753       gst_flac_enc_tell_callback, NULL, flacenc);
754   if (init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK)
755     goto failed_to_initialize;
756
757   gst_object_unref (flacenc);
758
759   return TRUE;
760
761 encoder_already_initialized:
762   {
763     g_warning ("flac already initialized -- fixme allow this");
764     gst_object_unref (flacenc);
765     return FALSE;
766   }
767 setting_src_caps_failed:
768   {
769     GST_DEBUG_OBJECT (flacenc,
770         "Couldn't set caps on source pad: %" GST_PTR_FORMAT, caps);
771     gst_caps_unref (caps);
772     gst_object_unref (flacenc);
773     return FALSE;
774   }
775 failed_to_initialize:
776   {
777     GST_ELEMENT_ERROR (flacenc, LIBRARY, INIT, (NULL),
778         ("could not initialize encoder (wrong parameters?)"));
779     gst_object_unref (flacenc);
780     return FALSE;
781   }
782 }
783
784 static gboolean
785 gst_flac_enc_update_quality (GstFlacEnc * flacenc, gint quality)
786 {
787   flacenc->quality = quality;
788
789 #define DO_UPDATE(name, val, str)                                               \
790   G_STMT_START {                                                                \
791     if (FLAC__stream_encoder_get_##name (flacenc->encoder) !=                   \
792         flacenc_params[quality].val) {                                          \
793       FLAC__stream_encoder_set_##name (flacenc->encoder,                        \
794           flacenc_params[quality].val);                                         \
795       g_object_notify (G_OBJECT (flacenc), str);                                \
796     }                                                                           \
797   } G_STMT_END
798
799   g_object_freeze_notify (G_OBJECT (flacenc));
800
801   if (flacenc->channels == 2 || flacenc->channels == 0) {
802     DO_UPDATE (do_mid_side_stereo, mid_side, "mid_side_stereo");
803     DO_UPDATE (loose_mid_side_stereo, loose_mid_side, "loose_mid_side");
804   }
805
806   DO_UPDATE (blocksize, blocksize, "blocksize");
807   DO_UPDATE (max_lpc_order, max_lpc_order, "max_lpc_order");
808   DO_UPDATE (qlp_coeff_precision, qlp_coeff_precision, "qlp_coeff_precision");
809   DO_UPDATE (do_qlp_coeff_prec_search, qlp_coeff_prec_search,
810       "qlp_coeff_prec_search");
811   DO_UPDATE (do_escape_coding, escape_coding, "escape_coding");
812   DO_UPDATE (do_exhaustive_model_search, exhaustive_model_search,
813       "exhaustive_model_search");
814   DO_UPDATE (min_residual_partition_order, min_residual_partition_order,
815       "min_residual_partition_order");
816   DO_UPDATE (max_residual_partition_order, max_residual_partition_order,
817       "max_residual_partition_order");
818   DO_UPDATE (rice_parameter_search_dist, rice_parameter_search_dist,
819       "rice_parameter_search_dist");
820
821 #undef DO_UPDATE
822
823   g_object_thaw_notify (G_OBJECT (flacenc));
824
825   return TRUE;
826 }
827
828 static FLAC__StreamEncoderSeekStatus
829 gst_flac_enc_seek_callback (const FLAC__StreamEncoder * encoder,
830     FLAC__uint64 absolute_byte_offset, void *client_data)
831 {
832   GstFlacEnc *flacenc;
833   GstEvent *event;
834   GstPad *peerpad;
835
836   flacenc = GST_FLAC_ENC (client_data);
837
838   if (flacenc->stopped)
839     return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
840
841   event = gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_BYTES,
842       absolute_byte_offset, GST_BUFFER_OFFSET_NONE, 0);
843
844   if ((peerpad = gst_pad_get_peer (flacenc->srcpad))) {
845     gboolean ret = gst_pad_send_event (peerpad, event);
846
847     gst_object_unref (peerpad);
848
849     if (ret) {
850       GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " %s",
851           (guint64) absolute_byte_offset, "succeeded");
852     } else {
853       GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " %s",
854           (guint64) absolute_byte_offset, "failed");
855       return FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED;
856     }
857   } else {
858     GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " failed (no peer pad)",
859         (guint64) absolute_byte_offset);
860   }
861
862   flacenc->offset = absolute_byte_offset;
863   return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
864 }
865
866 static void
867 notgst_value_array_append_buffer (GValue * array_val, GstBuffer * buf)
868 {
869   GValue value = { 0, };
870
871   g_value_init (&value, GST_TYPE_BUFFER);
872   /* copy buffer to avoid problems with circular refcounts */
873   buf = gst_buffer_copy (buf);
874   /* again, for good measure */
875   GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
876   gst_value_set_buffer (&value, buf);
877   gst_buffer_unref (buf);
878   gst_value_array_append_value (array_val, &value);
879   g_value_unset (&value);
880 }
881
882 #define HDR_TYPE_STREAMINFO     0
883 #define HDR_TYPE_VORBISCOMMENT  4
884
885 static void
886 gst_flac_enc_process_stream_headers (GstFlacEnc * enc)
887 {
888   GstBuffer *vorbiscomment = NULL;
889   GstBuffer *streaminfo = NULL;
890   GstBuffer *marker = NULL;
891   GValue array = { 0, };
892   GstCaps *caps;
893   GList *l;
894
895   caps = gst_caps_new_simple ("audio/x-flac",
896       "channels", G_TYPE_INT, enc->channels,
897       "rate", G_TYPE_INT, enc->sample_rate, NULL);
898
899   for (l = enc->headers; l != NULL; l = l->next) {
900     GstBuffer *buf;
901     guint8 *data;
902     gsize size;
903
904     /* mark buffers so oggmux will ignore them if it already muxed the
905      * header buffers from the streamheaders field in the caps */
906     l->data = gst_buffer_make_writable (GST_BUFFER_CAST (l->data));
907
908     buf = GST_BUFFER_CAST (l->data);
909     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
910
911     data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
912
913     /* find initial 4-byte marker which we need to skip later on */
914     if (size == 4 && memcmp (data, "fLaC", 4) == 0) {
915       marker = buf;
916     } else if (size > 1 && (data[0] & 0x7f) == HDR_TYPE_STREAMINFO) {
917       streaminfo = buf;
918     } else if (size > 1 && (data[0] & 0x7f) == HDR_TYPE_VORBISCOMMENT) {
919       vorbiscomment = buf;
920     }
921
922     gst_buffer_unmap (buf, data, size);
923   }
924
925   if (marker == NULL || streaminfo == NULL || vorbiscomment == NULL) {
926     GST_WARNING_OBJECT (enc, "missing header %p %p %p, muxing into container "
927         "formats may be broken", marker, streaminfo, vorbiscomment);
928     goto push_headers;
929   }
930
931   g_value_init (&array, GST_TYPE_ARRAY);
932
933   /* add marker including STREAMINFO header */
934   {
935     GstBuffer *buf;
936     guint16 num;
937     guint8 *bdata;
938     gsize bsize, slen;
939
940     /* minus one for the marker that is merged with streaminfo here */
941     num = g_list_length (enc->headers) - 1;
942
943     slen = gst_buffer_get_size (streaminfo);
944     buf = gst_buffer_new_and_alloc (13 + slen);
945
946     bdata = gst_buffer_map (buf, &bsize, NULL, GST_MAP_WRITE);
947     bdata[0] = 0x7f;
948     memcpy (bdata + 1, "FLAC", 4);
949     bdata[5] = 0x01;            /* mapping version major */
950     bdata[6] = 0x00;            /* mapping version minor */
951     bdata[7] = (num & 0xFF00) >> 8;
952     bdata[8] = (num & 0x00FF) >> 0;
953     memcpy (bdata + 9, "fLaC", 4);
954     gst_buffer_extract (streaminfo, 0, bdata + 13, slen);
955     gst_buffer_unmap (buf, bdata, bsize);
956
957     notgst_value_array_append_buffer (&array, buf);
958     gst_buffer_unref (buf);
959   }
960
961   /* add VORBISCOMMENT header */
962   notgst_value_array_append_buffer (&array, vorbiscomment);
963
964   /* add other headers, if there are any */
965   for (l = enc->headers; l != NULL; l = l->next) {
966     GstBuffer *buf = GST_BUFFER_CAST (l->data);
967
968     if (buf != marker && buf != streaminfo && buf != vorbiscomment) {
969       notgst_value_array_append_buffer (&array, buf);
970     }
971   }
972
973   gst_structure_set_value (gst_caps_get_structure (caps, 0),
974       "streamheader", &array);
975   g_value_unset (&array);
976
977 push_headers:
978
979   gst_pad_set_caps (enc->srcpad, caps);
980
981   /* push header buffers; update caps, so when we push the first buffer the
982    * negotiated caps will change to caps that include the streamheader field */
983   for (l = enc->headers; l != NULL; l = l->next) {
984     GstBuffer *buf;
985
986     buf = GST_BUFFER (l->data);
987     gst_buffer_set_caps (buf, caps);
988     GST_LOG_OBJECT (enc, "Pushing header buffer, size %u bytes",
989         gst_buffer_get_size (buf));
990 #if 0
991     GST_MEMDUMP_OBJECT (enc, "header buffer", GST_BUFFER_DATA (buf),
992         GST_BUFFER_SIZE (buf));
993 #endif
994     (void) gst_pad_push (enc->srcpad, buf);
995     l->data = NULL;
996   }
997   g_list_free (enc->headers);
998   enc->headers = NULL;
999
1000   gst_caps_unref (caps);
1001 }
1002
1003 static FLAC__StreamEncoderWriteStatus
1004 gst_flac_enc_write_callback (const FLAC__StreamEncoder * encoder,
1005     const FLAC__byte buffer[], size_t bytes,
1006     unsigned samples, unsigned current_frame, void *client_data)
1007 {
1008   GstFlowReturn ret = GST_FLOW_OK;
1009   GstFlacEnc *flacenc;
1010   GstBuffer *outbuf;
1011
1012   flacenc = GST_FLAC_ENC (client_data);
1013
1014   if (flacenc->stopped)
1015     return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
1016
1017   outbuf = gst_buffer_new_and_alloc (bytes);
1018   gst_buffer_fill (outbuf, 0, buffer, bytes);
1019
1020   if (samples > 0 && flacenc->samples_written != (guint64) - 1) {
1021     guint64 granulepos;
1022
1023     GST_BUFFER_TIMESTAMP (outbuf) = flacenc->start_ts +
1024         GST_FRAMES_TO_CLOCK_TIME (flacenc->samples_written,
1025         flacenc->sample_rate);
1026     GST_BUFFER_DURATION (outbuf) =
1027         GST_FRAMES_TO_CLOCK_TIME (samples, flacenc->sample_rate);
1028     /* offset_end = granulepos for ogg muxer */
1029     granulepos =
1030         flacenc->granulepos_offset + flacenc->samples_written + samples;
1031     GST_BUFFER_OFFSET_END (outbuf) = granulepos;
1032     /* offset = timestamp corresponding to granulepos for ogg muxer
1033      * (see vorbisenc for a much more elaborate version of this) */
1034     GST_BUFFER_OFFSET (outbuf) =
1035         GST_FRAMES_TO_CLOCK_TIME (granulepos, flacenc->sample_rate);
1036   } else {
1037     GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
1038     GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
1039     GST_BUFFER_OFFSET (outbuf) =
1040         flacenc->samples_written * flacenc->width * flacenc->channels;
1041     GST_BUFFER_OFFSET_END (outbuf) = 0;
1042     GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_IN_CAPS);
1043   }
1044
1045   /* we assume libflac passes us stuff neatly framed */
1046   if (!flacenc->got_headers) {
1047     if (samples == 0) {
1048       GST_DEBUG_OBJECT (flacenc, "Got header, queueing (%u bytes)",
1049           (guint) bytes);
1050       flacenc->headers = g_list_append (flacenc->headers, outbuf);
1051       /* note: it's important that we increase our byte offset */
1052       goto out;
1053     } else {
1054       GST_INFO_OBJECT (flacenc, "Non-header packet, we have all headers now");
1055       gst_flac_enc_process_stream_headers (flacenc);
1056       flacenc->got_headers = TRUE;
1057     }
1058   } else if (flacenc->got_headers && samples == 0) {
1059     GST_DEBUG_OBJECT (flacenc, "Fixing up headers at pos=%" G_GUINT64_FORMAT
1060         ", size=%u", flacenc->offset, (guint) bytes);
1061 #if 0
1062     GST_MEMDUMP_OBJECT (flacenc, "Presumed header fragment",
1063         GST_BUFFER_DATA (outbuf), GST_BUFFER_SIZE (outbuf));
1064 #endif
1065   } else {
1066     GST_LOG ("Pushing buffer: ts=%" GST_TIME_FORMAT ", samples=%u, size=%u, "
1067         "pos=%" G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1068         samples, (guint) bytes, flacenc->offset);
1069   }
1070
1071   gst_buffer_set_caps (outbuf, GST_PAD_CAPS (flacenc->srcpad));
1072   ret = gst_pad_push (flacenc->srcpad, outbuf);
1073
1074   if (ret != GST_FLOW_OK)
1075     GST_DEBUG_OBJECT (flacenc, "flow: %s", gst_flow_get_name (ret));
1076
1077   flacenc->last_flow = ret;
1078
1079 out:
1080
1081   flacenc->offset += bytes;
1082   flacenc->samples_written += samples;
1083
1084   if (ret != GST_FLOW_OK)
1085     return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
1086
1087   return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
1088 }
1089
1090 static FLAC__StreamEncoderTellStatus
1091 gst_flac_enc_tell_callback (const FLAC__StreamEncoder * encoder,
1092     FLAC__uint64 * absolute_byte_offset, void *client_data)
1093 {
1094   GstFlacEnc *flacenc = GST_FLAC_ENC (client_data);
1095
1096   *absolute_byte_offset = flacenc->offset;
1097
1098   return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
1099 }
1100
1101 static gboolean
1102 gst_flac_enc_sink_event (GstPad * pad, GstEvent * event)
1103 {
1104   GstFlacEnc *flacenc;
1105   GstTagList *taglist;
1106   gboolean ret = TRUE;
1107
1108   flacenc = GST_FLAC_ENC (gst_pad_get_parent (pad));
1109
1110   GST_DEBUG ("Received %s event on sinkpad", GST_EVENT_TYPE_NAME (event));
1111
1112   switch (GST_EVENT_TYPE (event)) {
1113     case GST_EVENT_NEWSEGMENT:{
1114       GstFormat format;
1115       gint64 start, stream_time;
1116
1117       if (flacenc->offset == 0) {
1118         gst_event_parse_new_segment (event, NULL, NULL, &format, &start, NULL,
1119             &stream_time);
1120       } else {
1121         start = -1;
1122         stream_time = -1;
1123       }
1124
1125       if (start > 0) {
1126         if (flacenc->offset > 0)
1127           GST_DEBUG ("Not handling mid-stream newsegment event");
1128         else
1129           GST_DEBUG ("Not handling newsegment event with non-zero start");
1130       } else {
1131         GstEvent *e = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES,
1132             0, -1, 0);
1133
1134         ret = gst_pad_push_event (flacenc->srcpad, e);
1135       }
1136
1137       if (stream_time > 0) {
1138         GST_DEBUG ("Not handling non-zero stream time");
1139       }
1140
1141       gst_event_unref (event);
1142       /* don't push it downstream, we'll generate our own via seek to 0 */
1143       break;
1144     }
1145     case GST_EVENT_EOS:
1146       FLAC__stream_encoder_finish (flacenc->encoder);
1147       ret = gst_pad_event_default (pad, event);
1148       break;
1149     case GST_EVENT_TAG:
1150       if (flacenc->tags) {
1151         gst_event_parse_tag (event, &taglist);
1152         gst_tag_list_insert (flacenc->tags, taglist,
1153             gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (flacenc)));
1154       } else {
1155         g_assert_not_reached ();
1156       }
1157       ret = gst_pad_event_default (pad, event);
1158       break;
1159     default:
1160       ret = gst_pad_event_default (pad, event);
1161       break;
1162   }
1163
1164   gst_object_unref (flacenc);
1165
1166   return ret;
1167 }
1168
1169 static gboolean
1170 gst_flac_enc_check_discont (GstFlacEnc * flacenc, GstClockTime expected,
1171     GstClockTime timestamp)
1172 {
1173   guint allowed_diff = GST_SECOND / flacenc->sample_rate / 2;
1174
1175   if ((timestamp + allowed_diff < expected)
1176       || (timestamp > expected + allowed_diff)) {
1177     GST_ELEMENT_WARNING (flacenc, STREAM, FORMAT, (NULL),
1178         ("Stream discontinuity detected (wanted %" GST_TIME_FORMAT " got %"
1179             GST_TIME_FORMAT "). The output will have wrong timestamps,"
1180             " consider using audiorate to handle discontinuities",
1181             GST_TIME_ARGS (expected), GST_TIME_ARGS (timestamp)));
1182     return TRUE;
1183   }
1184
1185   /* TODO: Do something to handle discontinuities in the stream. The FLAC encoder
1186    * unfortunately doesn't have any way to flush it's internal buffers */
1187
1188   return FALSE;
1189 }
1190
1191 static GstFlowReturn
1192 gst_flac_enc_chain (GstPad * pad, GstBuffer * buffer)
1193 {
1194   GstFlacEnc *flacenc;
1195   FLAC__int32 *data;
1196   gsize bsize;
1197   gint samples, width;
1198   gulong i;
1199   FLAC__bool res;
1200   gpointer bdata;
1201
1202   flacenc = GST_FLAC_ENC (GST_PAD_PARENT (pad));
1203
1204   /* make sure setcaps has been called and the encoder is set up */
1205   if (G_UNLIKELY (flacenc->depth == 0))
1206     return GST_FLOW_NOT_NEGOTIATED;
1207
1208   width = flacenc->width;
1209
1210   /* Save the timestamp of the first buffer. This will be later
1211    * used as offset for all following buffers */
1212   if (flacenc->start_ts == GST_CLOCK_TIME_NONE) {
1213     if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) {
1214       flacenc->start_ts = GST_BUFFER_TIMESTAMP (buffer);
1215       flacenc->granulepos_offset = gst_util_uint64_scale
1216           (GST_BUFFER_TIMESTAMP (buffer), flacenc->sample_rate, GST_SECOND);
1217     } else {
1218       flacenc->start_ts = 0;
1219       flacenc->granulepos_offset = 0;
1220     }
1221   }
1222
1223   /* Check if we have a continous stream, if not drop some samples or the buffer or
1224    * insert some silence samples */
1225   if (flacenc->next_ts != GST_CLOCK_TIME_NONE
1226       && GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) {
1227     gst_flac_enc_check_discont (flacenc, flacenc->next_ts,
1228         GST_BUFFER_TIMESTAMP (buffer));
1229   }
1230
1231   if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)
1232       && GST_BUFFER_DURATION_IS_VALID (buffer))
1233     flacenc->next_ts =
1234         GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer);
1235   else
1236     flacenc->next_ts = GST_CLOCK_TIME_NONE;
1237
1238   bdata = gst_buffer_map (buffer, &bsize, NULL, GST_MAP_READ);
1239   samples = bsize / (width >> 3);
1240
1241   data = g_malloc (samples * sizeof (FLAC__int32));
1242
1243   if (width == 8) {
1244     gint8 *indata = (gint8 *) bdata;
1245
1246     for (i = 0; i < samples; i++)
1247       data[i] = (FLAC__int32) indata[i];
1248   } else if (width == 16) {
1249     gint16 *indata = (gint16 *) bdata;
1250
1251     for (i = 0; i < samples; i++)
1252       data[i] = (FLAC__int32) indata[i];
1253   } else if (width == 32) {
1254     gint32 *indata = (gint32 *) bdata;
1255
1256     for (i = 0; i < samples; i++)
1257       data[i] = (FLAC__int32) indata[i];
1258   } else {
1259     g_assert_not_reached ();
1260   }
1261   gst_buffer_unmap (buffer, bdata, bsize);
1262   gst_buffer_unref (buffer);
1263
1264   res = FLAC__stream_encoder_process_interleaved (flacenc->encoder,
1265       (const FLAC__int32 *) data, samples / flacenc->channels);
1266
1267   g_free (data);
1268
1269   if (!res) {
1270     if (flacenc->last_flow == GST_FLOW_OK)
1271       return GST_FLOW_ERROR;
1272     else
1273       return flacenc->last_flow;
1274   }
1275
1276   return GST_FLOW_OK;
1277 }
1278
1279 static void
1280 gst_flac_enc_set_property (GObject * object, guint prop_id,
1281     const GValue * value, GParamSpec * pspec)
1282 {
1283   GstFlacEnc *this = GST_FLAC_ENC (object);
1284
1285   GST_OBJECT_LOCK (this);
1286
1287   switch (prop_id) {
1288     case PROP_QUALITY:
1289       gst_flac_enc_update_quality (this, g_value_get_enum (value));
1290       break;
1291     case PROP_STREAMABLE_SUBSET:
1292       FLAC__stream_encoder_set_streamable_subset (this->encoder,
1293           g_value_get_boolean (value));
1294       break;
1295     case PROP_MID_SIDE_STEREO:
1296       FLAC__stream_encoder_set_do_mid_side_stereo (this->encoder,
1297           g_value_get_boolean (value));
1298       break;
1299     case PROP_LOOSE_MID_SIDE_STEREO:
1300       FLAC__stream_encoder_set_loose_mid_side_stereo (this->encoder,
1301           g_value_get_boolean (value));
1302       break;
1303     case PROP_BLOCKSIZE:
1304       FLAC__stream_encoder_set_blocksize (this->encoder,
1305           g_value_get_uint (value));
1306       break;
1307     case PROP_MAX_LPC_ORDER:
1308       FLAC__stream_encoder_set_max_lpc_order (this->encoder,
1309           g_value_get_uint (value));
1310       break;
1311     case PROP_QLP_COEFF_PRECISION:
1312       FLAC__stream_encoder_set_qlp_coeff_precision (this->encoder,
1313           g_value_get_uint (value));
1314       break;
1315     case PROP_QLP_COEFF_PREC_SEARCH:
1316       FLAC__stream_encoder_set_do_qlp_coeff_prec_search (this->encoder,
1317           g_value_get_boolean (value));
1318       break;
1319     case PROP_ESCAPE_CODING:
1320       FLAC__stream_encoder_set_do_escape_coding (this->encoder,
1321           g_value_get_boolean (value));
1322       break;
1323     case PROP_EXHAUSTIVE_MODEL_SEARCH:
1324       FLAC__stream_encoder_set_do_exhaustive_model_search (this->encoder,
1325           g_value_get_boolean (value));
1326       break;
1327     case PROP_MIN_RESIDUAL_PARTITION_ORDER:
1328       FLAC__stream_encoder_set_min_residual_partition_order (this->encoder,
1329           g_value_get_uint (value));
1330       break;
1331     case PROP_MAX_RESIDUAL_PARTITION_ORDER:
1332       FLAC__stream_encoder_set_max_residual_partition_order (this->encoder,
1333           g_value_get_uint (value));
1334       break;
1335     case PROP_RICE_PARAMETER_SEARCH_DIST:
1336       FLAC__stream_encoder_set_rice_parameter_search_dist (this->encoder,
1337           g_value_get_uint (value));
1338       break;
1339     case PROP_PADDING:
1340       this->padding = g_value_get_uint (value);
1341       break;
1342     case PROP_SEEKPOINTS:
1343       this->seekpoints = g_value_get_int (value);
1344       break;
1345     default:
1346       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1347       break;
1348   }
1349
1350   GST_OBJECT_UNLOCK (this);
1351 }
1352
1353 static void
1354 gst_flac_enc_get_property (GObject * object, guint prop_id,
1355     GValue * value, GParamSpec * pspec)
1356 {
1357   GstFlacEnc *this = GST_FLAC_ENC (object);
1358
1359   GST_OBJECT_LOCK (this);
1360
1361   switch (prop_id) {
1362     case PROP_QUALITY:
1363       g_value_set_enum (value, this->quality);
1364       break;
1365     case PROP_STREAMABLE_SUBSET:
1366       g_value_set_boolean (value,
1367           FLAC__stream_encoder_get_streamable_subset (this->encoder));
1368       break;
1369     case PROP_MID_SIDE_STEREO:
1370       g_value_set_boolean (value,
1371           FLAC__stream_encoder_get_do_mid_side_stereo (this->encoder));
1372       break;
1373     case PROP_LOOSE_MID_SIDE_STEREO:
1374       g_value_set_boolean (value,
1375           FLAC__stream_encoder_get_loose_mid_side_stereo (this->encoder));
1376       break;
1377     case PROP_BLOCKSIZE:
1378       g_value_set_uint (value,
1379           FLAC__stream_encoder_get_blocksize (this->encoder));
1380       break;
1381     case PROP_MAX_LPC_ORDER:
1382       g_value_set_uint (value,
1383           FLAC__stream_encoder_get_max_lpc_order (this->encoder));
1384       break;
1385     case PROP_QLP_COEFF_PRECISION:
1386       g_value_set_uint (value,
1387           FLAC__stream_encoder_get_qlp_coeff_precision (this->encoder));
1388       break;
1389     case PROP_QLP_COEFF_PREC_SEARCH:
1390       g_value_set_boolean (value,
1391           FLAC__stream_encoder_get_do_qlp_coeff_prec_search (this->encoder));
1392       break;
1393     case PROP_ESCAPE_CODING:
1394       g_value_set_boolean (value,
1395           FLAC__stream_encoder_get_do_escape_coding (this->encoder));
1396       break;
1397     case PROP_EXHAUSTIVE_MODEL_SEARCH:
1398       g_value_set_boolean (value,
1399           FLAC__stream_encoder_get_do_exhaustive_model_search (this->encoder));
1400       break;
1401     case PROP_MIN_RESIDUAL_PARTITION_ORDER:
1402       g_value_set_uint (value,
1403           FLAC__stream_encoder_get_min_residual_partition_order
1404           (this->encoder));
1405       break;
1406     case PROP_MAX_RESIDUAL_PARTITION_ORDER:
1407       g_value_set_uint (value,
1408           FLAC__stream_encoder_get_max_residual_partition_order
1409           (this->encoder));
1410       break;
1411     case PROP_RICE_PARAMETER_SEARCH_DIST:
1412       g_value_set_uint (value,
1413           FLAC__stream_encoder_get_rice_parameter_search_dist (this->encoder));
1414       break;
1415     case PROP_PADDING:
1416       g_value_set_uint (value, this->padding);
1417       break;
1418     case PROP_SEEKPOINTS:
1419       g_value_set_int (value, this->seekpoints);
1420       break;
1421     default:
1422       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1423       break;
1424   }
1425
1426   GST_OBJECT_UNLOCK (this);
1427 }
1428
1429 static GstStateChangeReturn
1430 gst_flac_enc_change_state (GstElement * element, GstStateChange transition)
1431 {
1432   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1433   GstFlacEnc *flacenc = GST_FLAC_ENC (element);
1434
1435   switch (transition) {
1436     case GST_STATE_CHANGE_NULL_TO_READY:
1437     case GST_STATE_CHANGE_READY_TO_PAUSED:
1438       flacenc->stopped = FALSE;
1439       flacenc->start_ts = GST_CLOCK_TIME_NONE;
1440       flacenc->next_ts = GST_CLOCK_TIME_NONE;
1441       flacenc->granulepos_offset = 0;
1442       break;
1443     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1444     default:
1445       break;
1446   }
1447
1448   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1449
1450   switch (transition) {
1451     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1452       break;
1453     case GST_STATE_CHANGE_PAUSED_TO_READY:
1454       if (FLAC__stream_encoder_get_state (flacenc->encoder) !=
1455           FLAC__STREAM_ENCODER_UNINITIALIZED) {
1456         flacenc->stopped = TRUE;
1457         FLAC__stream_encoder_finish (flacenc->encoder);
1458       }
1459       flacenc->offset = 0;
1460       flacenc->samples_written = 0;
1461       flacenc->channels = 0;
1462       flacenc->depth = 0;
1463       flacenc->sample_rate = 0;
1464       if (flacenc->meta) {
1465         FLAC__metadata_object_delete (flacenc->meta[0]);
1466
1467         if (flacenc->meta[1])
1468           FLAC__metadata_object_delete (flacenc->meta[1]);
1469
1470         if (flacenc->meta[2])
1471           FLAC__metadata_object_delete (flacenc->meta[2]);
1472
1473         g_free (flacenc->meta);
1474         flacenc->meta = NULL;
1475       }
1476       g_list_foreach (flacenc->headers, (GFunc) gst_mini_object_unref, NULL);
1477       g_list_free (flacenc->headers);
1478       flacenc->headers = NULL;
1479       flacenc->got_headers = FALSE;
1480       flacenc->last_flow = GST_FLOW_OK;
1481       break;
1482     case GST_STATE_CHANGE_READY_TO_NULL:
1483     default:
1484       break;
1485   }
1486
1487   return ret;
1488 }