Merge branch '0.11' of ssh://git.freedesktop.org/git/gstreamer/gst-plugins-good into...
[platform/upstream/gstreamer.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/tag/tag.h>
49 #include <gst/gsttagsetter.h>
50
51 /* Taken from http://flac.sourceforge.net/format.html#frame_header */
52 static const GstAudioChannelPosition channel_positions[8][8] = {
53   {GST_AUDIO_CHANNEL_POSITION_MONO},
54   {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
55       GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, {
56         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
57         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
58       GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER}, {
59         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
60         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
61         GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
62       GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}, {
63         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
64         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
65         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
66         GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
67       GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}, {
68         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
69         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
70         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
71         GST_AUDIO_CHANNEL_POSITION_LFE1,
72         GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
73       GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT},
74   /* FIXME: 7/8 channel layouts are not defined in the FLAC specs */
75   {
76         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
77         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
78         GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
79         GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
80         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
81         GST_AUDIO_CHANNEL_POSITION_LFE1,
82       GST_AUDIO_CHANNEL_POSITION_REAR_CENTER}, {
83         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
84         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
85         GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
86         GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
87         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
88         GST_AUDIO_CHANNEL_POSITION_LFE1,
89         GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
90       GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}
91 };
92
93 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
94 #define FORMATS "{ S8LE, S16LE, S24LE, S32LE } "
95 #else
96 #define FORMATS "{ S8BE, S16BE, S24BE, S32BE } "
97 #endif
98
99 #define FLAC_SINK_CAPS                                    \
100     "audio/x-raw, "                                       \
101     "format = (string) " FORMATS ", "                     \
102     "layout = (string) interleaved, "                     \
103     "rate = (int) [ 1, 655350 ], "                        \
104     "channels = (int) [ 1, 8 ]"
105
106 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
107     GST_PAD_SRC,
108     GST_PAD_ALWAYS,
109     GST_STATIC_CAPS ("audio/x-flac")
110     );
111
112 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
113     GST_PAD_SINK,
114     GST_PAD_ALWAYS,
115     GST_STATIC_CAPS (FLAC_SINK_CAPS)
116     );
117
118 enum
119 {
120   PROP_0,
121   PROP_QUALITY,
122   PROP_STREAMABLE_SUBSET,
123   PROP_MID_SIDE_STEREO,
124   PROP_LOOSE_MID_SIDE_STEREO,
125   PROP_BLOCKSIZE,
126   PROP_MAX_LPC_ORDER,
127   PROP_QLP_COEFF_PRECISION,
128   PROP_QLP_COEFF_PREC_SEARCH,
129   PROP_ESCAPE_CODING,
130   PROP_EXHAUSTIVE_MODEL_SEARCH,
131   PROP_MIN_RESIDUAL_PARTITION_ORDER,
132   PROP_MAX_RESIDUAL_PARTITION_ORDER,
133   PROP_RICE_PARAMETER_SEARCH_DIST,
134   PROP_PADDING,
135   PROP_SEEKPOINTS
136 };
137
138 GST_DEBUG_CATEGORY_STATIC (flacenc_debug);
139 #define GST_CAT_DEFAULT flacenc_debug
140
141 #define gst_flac_enc_parent_class parent_class
142 G_DEFINE_TYPE_WITH_CODE (GstFlacEnc, gst_flac_enc, GST_TYPE_AUDIO_ENCODER,
143     G_IMPLEMENT_INTERFACE (GST_TYPE_TAG_SETTER, NULL));
144
145 static gboolean gst_flac_enc_start (GstAudioEncoder * enc);
146 static gboolean gst_flac_enc_stop (GstAudioEncoder * enc);
147 static gboolean gst_flac_enc_set_format (GstAudioEncoder * enc,
148     GstAudioInfo * info);
149 static GstFlowReturn gst_flac_enc_handle_frame (GstAudioEncoder * enc,
150     GstBuffer * in_buf);
151 static GstCaps *gst_flac_enc_getcaps (GstAudioEncoder * enc, GstCaps * filter);
152 static gboolean gst_flac_enc_sink_event (GstAudioEncoder * enc,
153     GstEvent * event);
154
155 static void gst_flac_enc_finalize (GObject * object);
156
157 static gboolean gst_flac_enc_update_quality (GstFlacEnc * flacenc,
158     gint quality);
159 static void gst_flac_enc_set_property (GObject * object, guint prop_id,
160     const GValue * value, GParamSpec * pspec);
161 static void gst_flac_enc_get_property (GObject * object, guint prop_id,
162     GValue * value, GParamSpec * pspec);
163
164 static FLAC__StreamEncoderWriteStatus
165 gst_flac_enc_write_callback (const FLAC__StreamEncoder * encoder,
166     const FLAC__byte buffer[], size_t bytes,
167     unsigned samples, unsigned current_frame, void *client_data);
168 static FLAC__StreamEncoderSeekStatus
169 gst_flac_enc_seek_callback (const FLAC__StreamEncoder * encoder,
170     FLAC__uint64 absolute_byte_offset, void *client_data);
171 static FLAC__StreamEncoderTellStatus
172 gst_flac_enc_tell_callback (const FLAC__StreamEncoder * encoder,
173     FLAC__uint64 * absolute_byte_offset, void *client_data);
174
175 typedef struct
176 {
177   gboolean exhaustive_model_search;
178   gboolean escape_coding;
179   gboolean mid_side;
180   gboolean loose_mid_side;
181   guint qlp_coeff_precision;
182   gboolean qlp_coeff_prec_search;
183   guint min_residual_partition_order;
184   guint max_residual_partition_order;
185   guint rice_parameter_search_dist;
186   guint max_lpc_order;
187   guint blocksize;
188 }
189 GstFlacEncParams;
190
191 static const GstFlacEncParams flacenc_params[] = {
192   {FALSE, FALSE, FALSE, FALSE, 0, FALSE, 2, 2, 0, 0, 1152},
193   {FALSE, FALSE, TRUE, TRUE, 0, FALSE, 2, 2, 0, 0, 1152},
194   {FALSE, FALSE, TRUE, FALSE, 0, FALSE, 0, 3, 0, 0, 1152},
195   {FALSE, FALSE, FALSE, FALSE, 0, FALSE, 3, 3, 0, 6, 4608},
196   {FALSE, FALSE, TRUE, TRUE, 0, FALSE, 3, 3, 0, 8, 4608},
197   {FALSE, FALSE, TRUE, FALSE, 0, FALSE, 3, 3, 0, 8, 4608},
198   {FALSE, FALSE, TRUE, FALSE, 0, FALSE, 0, 4, 0, 8, 4608},
199   {TRUE, FALSE, TRUE, FALSE, 0, FALSE, 0, 6, 0, 8, 4608},
200   {TRUE, FALSE, TRUE, FALSE, 0, FALSE, 0, 6, 0, 12, 4608},
201   {TRUE, TRUE, TRUE, FALSE, 0, FALSE, 0, 16, 0, 32, 4608},
202 };
203
204 #define DEFAULT_QUALITY 5
205 #define DEFAULT_PADDING 0
206 #define DEFAULT_SEEKPOINTS 0
207
208 #define GST_TYPE_FLAC_ENC_QUALITY (gst_flac_enc_quality_get_type ())
209 static GType
210 gst_flac_enc_quality_get_type (void)
211 {
212   static GType qtype = 0;
213
214   if (qtype == 0) {
215     static const GEnumValue values[] = {
216       {0, "0 - Fastest compression", "0"},
217       {1, "1", "1"},
218       {2, "2", "2"},
219       {3, "3", "3"},
220       {4, "4", "4"},
221       {5, "5 - Default", "5"},
222       {6, "6", "6"},
223       {7, "7", "7"},
224       {8, "8 - Highest compression", "8"},
225       {9, "9 - Insane", "9"},
226       {0, NULL, NULL}
227     };
228
229     qtype = g_enum_register_static ("GstFlacEncQuality", values);
230   }
231   return qtype;
232 }
233
234 static void
235 gst_flac_enc_class_init (GstFlacEncClass * klass)
236 {
237   GObjectClass *gobject_class;
238   GstElementClass *gstelement_class;
239   GstAudioEncoderClass *base_class;
240
241   gobject_class = (GObjectClass *) klass;
242   gstelement_class = (GstElementClass *) klass;
243   base_class = (GstAudioEncoderClass *) (klass);
244
245   GST_DEBUG_CATEGORY_INIT (flacenc_debug, "flacenc", 0,
246       "Flac encoding element");
247
248   gobject_class->set_property = gst_flac_enc_set_property;
249   gobject_class->get_property = gst_flac_enc_get_property;
250   gobject_class->finalize = gst_flac_enc_finalize;
251
252   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QUALITY,
253       g_param_spec_enum ("quality",
254           "Quality",
255           "Speed versus compression tradeoff",
256           GST_TYPE_FLAC_ENC_QUALITY, DEFAULT_QUALITY,
257           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
258   g_object_class_install_property (G_OBJECT_CLASS (klass),
259       PROP_STREAMABLE_SUBSET, g_param_spec_boolean ("streamable-subset",
260           "Streamable subset",
261           "true to limit encoder to generating a Subset stream, else false",
262           TRUE,
263           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
264   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MID_SIDE_STEREO,
265       g_param_spec_boolean ("mid-side-stereo", "Do mid side stereo",
266           "Do mid side stereo (only for stereo input)",
267           flacenc_params[DEFAULT_QUALITY].mid_side,
268           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
269   g_object_class_install_property (G_OBJECT_CLASS (klass),
270       PROP_LOOSE_MID_SIDE_STEREO, g_param_spec_boolean ("loose-mid-side-stereo",
271           "Loose mid side stereo", "Loose mid side stereo",
272           flacenc_params[DEFAULT_QUALITY].loose_mid_side,
273           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
274   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BLOCKSIZE,
275       g_param_spec_uint ("blocksize", "Blocksize", "Blocksize in samples",
276           FLAC__MIN_BLOCK_SIZE, FLAC__MAX_BLOCK_SIZE,
277           flacenc_params[DEFAULT_QUALITY].blocksize,
278           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
279   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MAX_LPC_ORDER,
280       g_param_spec_uint ("max-lpc-order", "Max LPC order",
281           "Max LPC order; 0 => use only fixed predictors", 0,
282           FLAC__MAX_LPC_ORDER, flacenc_params[DEFAULT_QUALITY].max_lpc_order,
283           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
284   g_object_class_install_property (G_OBJECT_CLASS (klass),
285       PROP_QLP_COEFF_PRECISION, g_param_spec_uint ("qlp-coeff-precision",
286           "QLP coefficients precision",
287           "Precision in bits of quantized linear-predictor coefficients; 0 = automatic",
288           0, 32, flacenc_params[DEFAULT_QUALITY].qlp_coeff_precision,
289           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
290   g_object_class_install_property (G_OBJECT_CLASS (klass),
291       PROP_QLP_COEFF_PREC_SEARCH, g_param_spec_boolean ("qlp-coeff-prec-search",
292           "Do QLP coefficients precision search",
293           "false = use qlp_coeff_precision, "
294           "true = search around qlp_coeff_precision, take best",
295           flacenc_params[DEFAULT_QUALITY].qlp_coeff_prec_search,
296           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
297   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ESCAPE_CODING,
298       g_param_spec_boolean ("escape-coding", "Do Escape coding",
299           "search for escape codes in the entropy coding stage "
300           "for slightly better compression",
301           flacenc_params[DEFAULT_QUALITY].escape_coding,
302           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
303   g_object_class_install_property (G_OBJECT_CLASS (klass),
304       PROP_EXHAUSTIVE_MODEL_SEARCH,
305       g_param_spec_boolean ("exhaustive-model-search",
306           "Do exhaustive model search",
307           "do exhaustive search of LP coefficient quantization (expensive!)",
308           flacenc_params[DEFAULT_QUALITY].exhaustive_model_search,
309           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
310   g_object_class_install_property (G_OBJECT_CLASS (klass),
311       PROP_MIN_RESIDUAL_PARTITION_ORDER,
312       g_param_spec_uint ("min-residual-partition-order",
313           "Min residual partition order",
314           "Min residual partition order (above 4 doesn't usually help much)", 0,
315           16, flacenc_params[DEFAULT_QUALITY].min_residual_partition_order,
316           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
317   g_object_class_install_property (G_OBJECT_CLASS (klass),
318       PROP_MAX_RESIDUAL_PARTITION_ORDER,
319       g_param_spec_uint ("max-residual-partition-order",
320           "Max residual partition order",
321           "Max residual partition order (above 4 doesn't usually help much)", 0,
322           16, flacenc_params[DEFAULT_QUALITY].max_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_RICE_PARAMETER_SEARCH_DIST,
326       g_param_spec_uint ("rice-parameter-search-dist",
327           "rice_parameter_search_dist",
328           "0 = try only calc'd parameter k; else try all [k-dist..k+dist] "
329           "parameters, use best", 0, FLAC__MAX_RICE_PARTITION_ORDER,
330           flacenc_params[DEFAULT_QUALITY].rice_parameter_search_dist,
331           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
332
333   /**
334    * GstFlacEnc:padding
335    *
336    * Write a PADDING block with this length in bytes
337    *
338    * Since: 0.10.16
339    **/
340   g_object_class_install_property (G_OBJECT_CLASS (klass),
341       PROP_PADDING,
342       g_param_spec_uint ("padding",
343           "Padding",
344           "Write a PADDING block with this length in bytes", 0, G_MAXUINT,
345           DEFAULT_PADDING,
346           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
347
348   /**
349    * GstFlacEnc:seekpoints
350    *
351    * Write a SEEKTABLE block with a specific number of seekpoints
352    * or with a specific interval spacing.
353    *
354    * Since: 0.10.18
355    **/
356   g_object_class_install_property (G_OBJECT_CLASS (klass),
357       PROP_SEEKPOINTS,
358       g_param_spec_int ("seekpoints",
359           "Seekpoints",
360           "Add SEEKTABLE metadata (if > 0, number of entries, if < 0, interval in sec)",
361           -G_MAXINT, G_MAXINT,
362           DEFAULT_SEEKPOINTS,
363           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
364
365   gst_element_class_add_pad_template (gstelement_class,
366       gst_static_pad_template_get (&src_factory));
367   gst_element_class_add_pad_template (gstelement_class,
368       gst_static_pad_template_get (&sink_factory));
369
370   gst_element_class_set_details_simple (gstelement_class, "FLAC audio encoder",
371       "Codec/Encoder/Audio",
372       "Encodes audio with the FLAC lossless audio encoder",
373       "Wim Taymans <wim.taymans@chello.be>");
374
375   base_class->start = GST_DEBUG_FUNCPTR (gst_flac_enc_start);
376   base_class->stop = GST_DEBUG_FUNCPTR (gst_flac_enc_stop);
377   base_class->set_format = GST_DEBUG_FUNCPTR (gst_flac_enc_set_format);
378   base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_flac_enc_handle_frame);
379   base_class->getcaps = GST_DEBUG_FUNCPTR (gst_flac_enc_getcaps);
380   base_class->event = GST_DEBUG_FUNCPTR (gst_flac_enc_sink_event);
381 }
382
383 static void
384 gst_flac_enc_init (GstFlacEnc * flacenc)
385 {
386   GstAudioEncoder *enc = GST_AUDIO_ENCODER (flacenc);
387
388   flacenc->encoder = FLAC__stream_encoder_new ();
389   gst_flac_enc_update_quality (flacenc, DEFAULT_QUALITY);
390
391   /* arrange granulepos marking (and required perfect ts) */
392   gst_audio_encoder_set_mark_granule (enc, TRUE);
393   gst_audio_encoder_set_perfect_timestamp (enc, TRUE);
394 }
395
396 static void
397 gst_flac_enc_finalize (GObject * object)
398 {
399   GstFlacEnc *flacenc = GST_FLAC_ENC (object);
400
401   FLAC__stream_encoder_delete (flacenc->encoder);
402
403   G_OBJECT_CLASS (parent_class)->finalize (object);
404 }
405
406 static gboolean
407 gst_flac_enc_start (GstAudioEncoder * enc)
408 {
409   GstFlacEnc *flacenc = GST_FLAC_ENC (enc);
410
411   GST_DEBUG_OBJECT (enc, "start");
412   flacenc->stopped = TRUE;
413   flacenc->got_headers = FALSE;
414   flacenc->last_flow = GST_FLOW_OK;
415   flacenc->offset = 0;
416   flacenc->eos = FALSE;
417   flacenc->tags = gst_tag_list_new_empty ();
418
419   return TRUE;
420 }
421
422 static gboolean
423 gst_flac_enc_stop (GstAudioEncoder * enc)
424 {
425   GstFlacEnc *flacenc = GST_FLAC_ENC (enc);
426
427   GST_DEBUG_OBJECT (enc, "stop");
428   gst_tag_list_free (flacenc->tags);
429   flacenc->tags = NULL;
430   if (FLAC__stream_encoder_get_state (flacenc->encoder) !=
431       FLAC__STREAM_ENCODER_UNINITIALIZED) {
432     flacenc->stopped = TRUE;
433     FLAC__stream_encoder_finish (flacenc->encoder);
434   }
435   if (flacenc->meta) {
436     FLAC__metadata_object_delete (flacenc->meta[0]);
437
438     if (flacenc->meta[1])
439       FLAC__metadata_object_delete (flacenc->meta[1]);
440
441     if (flacenc->meta[2])
442       FLAC__metadata_object_delete (flacenc->meta[2]);
443
444     g_free (flacenc->meta);
445     flacenc->meta = NULL;
446   }
447   g_list_foreach (flacenc->headers, (GFunc) gst_mini_object_unref, NULL);
448   g_list_free (flacenc->headers);
449   flacenc->headers = NULL;
450
451   gst_tag_setter_reset_tags (GST_TAG_SETTER (enc));
452
453   return TRUE;
454 }
455
456 static void
457 add_one_tag (const GstTagList * list, const gchar * tag, gpointer user_data)
458 {
459   GList *comments;
460   GList *it;
461   GstFlacEnc *flacenc = GST_FLAC_ENC (user_data);
462
463   /* IMAGE and PREVIEW_IMAGE tags are already written
464    * differently, no need to store them inside the
465    * vorbiscomments too */
466   if (strcmp (tag, GST_TAG_IMAGE) == 0
467       || strcmp (tag, GST_TAG_PREVIEW_IMAGE) == 0)
468     return;
469
470   comments = gst_tag_to_vorbis_comments (list, tag);
471   for (it = comments; it != NULL; it = it->next) {
472     FLAC__StreamMetadata_VorbisComment_Entry commment_entry;
473
474     commment_entry.length = strlen (it->data);
475     commment_entry.entry = it->data;
476     FLAC__metadata_object_vorbiscomment_insert_comment (flacenc->meta[0],
477         flacenc->meta[0]->data.vorbis_comment.num_comments,
478         commment_entry, TRUE);
479     g_free (it->data);
480   }
481   g_list_free (comments);
482 }
483
484 static void
485 gst_flac_enc_set_metadata (GstFlacEnc * flacenc, guint64 total_samples)
486 {
487   const GstTagList *user_tags;
488   GstTagList *copy;
489   gint entries = 1;
490   gint n_images, n_preview_images;
491   GstAudioInfo *info =
492       gst_audio_encoder_get_audio_info (GST_AUDIO_ENCODER (flacenc));
493
494   g_return_if_fail (flacenc != NULL);
495   user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (flacenc));
496   if ((flacenc->tags == NULL) && (user_tags == NULL)) {
497     return;
498   }
499   copy = gst_tag_list_merge (user_tags, flacenc->tags,
500       gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (flacenc)));
501   n_images = gst_tag_list_get_tag_size (copy, GST_TAG_IMAGE);
502   n_preview_images = gst_tag_list_get_tag_size (copy, GST_TAG_PREVIEW_IMAGE);
503
504   flacenc->meta =
505       g_new0 (FLAC__StreamMetadata *, 3 + n_images + n_preview_images);
506
507   flacenc->meta[0] =
508       FLAC__metadata_object_new (FLAC__METADATA_TYPE_VORBIS_COMMENT);
509   gst_tag_list_foreach (copy, add_one_tag, flacenc);
510
511   if (n_images + n_preview_images > 0) {
512     GstBuffer *buffer;
513 #if 0
514     GstCaps *caps;
515     GstStructure *structure;
516     GstTagImageType image_type = GST_TAG_IMAGE_TYPE_NONE;
517 #endif
518     gint i;
519     GstMapInfo map;
520
521     for (i = 0; i < n_images + n_preview_images; i++) {
522       if (i < n_images) {
523         if (!gst_tag_list_get_buffer_index (copy, GST_TAG_IMAGE, i, &buffer))
524           continue;
525       } else {
526         if (!gst_tag_list_get_buffer_index (copy, GST_TAG_PREVIEW_IMAGE,
527                 i - n_images, &buffer))
528           continue;
529       }
530
531       flacenc->meta[entries] =
532           FLAC__metadata_object_new (FLAC__METADATA_TYPE_PICTURE);
533
534 #if 0
535       caps = gst_buffer_get_caps (buffer);
536       structure = gst_caps_get_structure (caps, 0);
537
538       gst_structure_get (structure, "image-type", GST_TYPE_TAG_IMAGE_TYPE,
539           &image_type, NULL);
540       /* Convert to ID3v2 APIC image type */
541       if (image_type == GST_TAG_IMAGE_TYPE_NONE)
542         image_type = (i < n_images) ? 0x00 : 0x01;
543       else
544         image_type = image_type + 2;
545 #endif
546
547       gst_buffer_map (buffer, &map, GST_MAP_READ);
548       FLAC__metadata_object_picture_set_data (flacenc->meta[entries],
549           map.data, map.size, TRUE);
550       gst_buffer_unmap (buffer, &map);
551
552 #if 0
553       /* FIXME: There's no way to set the picture type in libFLAC */
554       flacenc->meta[entries]->data.picture.type = image_type;
555       FLAC__metadata_object_picture_set_mime_type (flacenc->meta[entries],
556           (char *) gst_structure_get_name (structure), TRUE);
557       gst_caps_unref (caps);
558 #endif
559
560       gst_buffer_unref (buffer);
561       entries++;
562     }
563   }
564
565   if (flacenc->seekpoints && total_samples != GST_CLOCK_TIME_NONE) {
566     gboolean res;
567     guint samples;
568
569     flacenc->meta[entries] =
570         FLAC__metadata_object_new (FLAC__METADATA_TYPE_SEEKTABLE);
571     if (flacenc->seekpoints > 0) {
572       res =
573           FLAC__metadata_object_seektable_template_append_spaced_points
574           (flacenc->meta[entries], flacenc->seekpoints, total_samples);
575     } else {
576       samples = -flacenc->seekpoints * GST_AUDIO_INFO_RATE (info);
577       res =
578           FLAC__metadata_object_seektable_template_append_spaced_points_by_samples
579           (flacenc->meta[entries], samples, total_samples);
580     }
581     if (!res) {
582       GST_DEBUG_OBJECT (flacenc, "adding seekpoint template %d failed",
583           flacenc->seekpoints);
584       FLAC__metadata_object_delete (flacenc->meta[1]);
585       flacenc->meta[entries] = NULL;
586     } else {
587       entries++;
588     }
589   } else if (flacenc->seekpoints && total_samples == GST_CLOCK_TIME_NONE) {
590     GST_WARNING_OBJECT (flacenc, "total time unknown; can not add seekpoints");
591   }
592
593   if (flacenc->padding > 0) {
594     flacenc->meta[entries] =
595         FLAC__metadata_object_new (FLAC__METADATA_TYPE_PADDING);
596     flacenc->meta[entries]->length = flacenc->padding;
597     entries++;
598   }
599
600   if (FLAC__stream_encoder_set_metadata (flacenc->encoder,
601           flacenc->meta, entries) != true)
602     g_warning ("Dude, i'm already initialized!");
603
604   gst_tag_list_free (copy);
605 }
606
607 static GstCaps *
608 gst_flac_enc_getcaps (GstAudioEncoder * enc, GstCaps * filter)
609 {
610   GstCaps *ret = NULL, *caps = NULL;
611   GstPad *pad;
612
613   pad = GST_AUDIO_ENCODER_SINK_PAD (enc);
614
615   if (gst_pad_has_current_caps (pad)) {
616     ret = gst_pad_get_current_caps (pad);
617   } else {
618     gint i;
619     GValue v_list = { 0, };
620     GValue v = { 0, };
621     GstStructure *s, *s2;
622
623     g_value_init (&v_list, GST_TYPE_LIST);
624     g_value_init (&v, G_TYPE_STRING);
625
626     g_value_set_static_string (&v, GST_AUDIO_NE (S8));
627     gst_value_list_append_value (&v_list, &v);
628     g_value_set_static_string (&v, GST_AUDIO_NE (S16));
629     gst_value_list_append_value (&v_list, &v);
630     g_value_set_static_string (&v, GST_AUDIO_NE (S24));
631     gst_value_list_append_value (&v_list, &v);
632     g_value_set_static_string (&v, GST_AUDIO_NE (S32));
633     gst_value_list_append_value (&v_list, &v);
634     g_value_unset (&v);
635
636     s = gst_structure_new_empty ("audio/x-raw");
637     gst_structure_take_value (s, "format", &v_list);
638
639     gst_structure_set (s, "layout", G_TYPE_STRING, "interleaved",
640         "rate", GST_TYPE_INT_RANGE, 1, 655350, NULL);
641
642     ret = gst_caps_new_empty ();
643     for (i = 1; i <= 8; i++) {
644       s2 = gst_structure_copy (s);
645
646       if (i == 1) {
647         gst_structure_set (s2, "channels", G_TYPE_INT, 1, NULL);
648       } else {
649         guint64 channel_mask;
650
651         gst_audio_channel_positions_to_mask (channel_positions[i - 1], i,
652             &channel_mask);
653         gst_structure_set (s2, "channels", G_TYPE_INT, i, "channel-mask",
654             GST_TYPE_BITMASK, channel_mask, NULL);
655       }
656
657       gst_caps_append_structure (ret, s2);
658     }
659     gst_structure_free (s);
660   }
661
662   GST_DEBUG_OBJECT (pad, "Return caps %" GST_PTR_FORMAT, ret);
663
664   caps = gst_audio_encoder_proxy_getcaps (enc, ret);
665   gst_caps_unref (ret);
666
667   return caps;
668 }
669
670 static guint64
671 gst_flac_enc_peer_query_total_samples (GstFlacEnc * flacenc, GstPad * pad)
672 {
673   gint64 duration;
674   GstAudioInfo *info =
675       gst_audio_encoder_get_audio_info (GST_AUDIO_ENCODER (flacenc));
676
677   GST_DEBUG_OBJECT (flacenc, "querying peer for DEFAULT format duration");
678   if (gst_pad_peer_query_duration (pad, GST_FORMAT_DEFAULT, &duration)
679       && duration != GST_CLOCK_TIME_NONE)
680     goto done;
681
682   GST_DEBUG_OBJECT (flacenc, "querying peer for TIME format duration");
683
684   if (gst_pad_peer_query_duration (pad, GST_FORMAT_TIME, &duration)
685       && duration != GST_CLOCK_TIME_NONE) {
686     GST_DEBUG_OBJECT (flacenc, "peer reported duration %" GST_TIME_FORMAT,
687         GST_TIME_ARGS (duration));
688     duration = GST_CLOCK_TIME_TO_FRAMES (duration, GST_AUDIO_INFO_RATE (info));
689
690     goto done;
691   }
692
693   GST_DEBUG_OBJECT (flacenc, "Upstream reported no total samples");
694   return GST_CLOCK_TIME_NONE;
695
696 done:
697   GST_DEBUG_OBJECT (flacenc,
698       "Upstream reported %" G_GUINT64_FORMAT " total samples", duration);
699
700   return duration;
701 }
702
703 static gboolean
704 gst_flac_enc_set_format (GstAudioEncoder * enc, GstAudioInfo * info)
705 {
706   GstFlacEnc *flacenc;
707   guint64 total_samples = GST_CLOCK_TIME_NONE;
708   FLAC__StreamEncoderInitStatus init_status;
709   GstCaps *caps;
710
711   flacenc = GST_FLAC_ENC (enc);
712
713   /* if configured again, means something changed, can't handle that */
714   if (FLAC__stream_encoder_get_state (flacenc->encoder) !=
715       FLAC__STREAM_ENCODER_UNINITIALIZED)
716     goto encoder_already_initialized;
717
718   caps = gst_caps_new_simple ("audio/x-flac",
719       "channels", G_TYPE_INT, GST_AUDIO_INFO_CHANNELS (info),
720       "rate", G_TYPE_INT, GST_AUDIO_INFO_RATE (info), NULL);
721
722   if (!gst_audio_encoder_set_output_format (enc, caps))
723     goto setting_src_caps_failed;
724
725   gst_caps_unref (caps);
726
727   gst_audio_get_channel_reorder_map (GST_AUDIO_INFO_CHANNELS (info),
728       channel_positions[GST_AUDIO_INFO_CHANNELS (info) - 1], info->position,
729       flacenc->channel_reorder_map);
730
731   total_samples = gst_flac_enc_peer_query_total_samples (flacenc,
732       GST_AUDIO_ENCODER_SINK_PAD (enc));
733
734   FLAC__stream_encoder_set_bits_per_sample (flacenc->encoder,
735       GST_AUDIO_INFO_WIDTH (info));
736   FLAC__stream_encoder_set_sample_rate (flacenc->encoder,
737       GST_AUDIO_INFO_RATE (info));
738   FLAC__stream_encoder_set_channels (flacenc->encoder,
739       GST_AUDIO_INFO_CHANNELS (info));
740
741   if (total_samples != GST_CLOCK_TIME_NONE)
742     FLAC__stream_encoder_set_total_samples_estimate (flacenc->encoder,
743         MIN (total_samples, G_GUINT64_CONSTANT (0x0FFFFFFFFF)));
744
745   gst_flac_enc_set_metadata (flacenc, total_samples);
746
747   /* callbacks clear to go now;
748    * write callbacks receives headers during init */
749   flacenc->stopped = FALSE;
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   /* no special feedback to base class; should provide all available samples */
758
759   return TRUE;
760
761 encoder_already_initialized:
762   {
763     g_warning ("flac already initialized -- fixme allow this");
764     return FALSE;
765   }
766 setting_src_caps_failed:
767   {
768     GST_DEBUG_OBJECT (flacenc,
769         "Couldn't set caps on source pad: %" GST_PTR_FORMAT, caps);
770     gst_caps_unref (caps);
771     return FALSE;
772   }
773 failed_to_initialize:
774   {
775     GST_ELEMENT_ERROR (flacenc, LIBRARY, INIT, (NULL),
776         ("could not initialize encoder (wrong parameters?)"));
777     return FALSE;
778   }
779 }
780
781 static gboolean
782 gst_flac_enc_update_quality (GstFlacEnc * flacenc, gint quality)
783 {
784   GstAudioInfo *info =
785       gst_audio_encoder_get_audio_info (GST_AUDIO_ENCODER (flacenc));
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 (GST_AUDIO_INFO_CHANNELS (info) == 2
802       || GST_AUDIO_INFO_CHANNELS (info) == 0) {
803     DO_UPDATE (do_mid_side_stereo, mid_side, "mid_side_stereo");
804     DO_UPDATE (loose_mid_side_stereo, loose_mid_side, "loose_mid_side");
805   }
806
807   DO_UPDATE (blocksize, blocksize, "blocksize");
808   DO_UPDATE (max_lpc_order, max_lpc_order, "max_lpc_order");
809   DO_UPDATE (qlp_coeff_precision, qlp_coeff_precision, "qlp_coeff_precision");
810   DO_UPDATE (do_qlp_coeff_prec_search, qlp_coeff_prec_search,
811       "qlp_coeff_prec_search");
812   DO_UPDATE (do_escape_coding, escape_coding, "escape_coding");
813   DO_UPDATE (do_exhaustive_model_search, exhaustive_model_search,
814       "exhaustive_model_search");
815   DO_UPDATE (min_residual_partition_order, min_residual_partition_order,
816       "min_residual_partition_order");
817   DO_UPDATE (max_residual_partition_order, max_residual_partition_order,
818       "max_residual_partition_order");
819   DO_UPDATE (rice_parameter_search_dist, rice_parameter_search_dist,
820       "rice_parameter_search_dist");
821
822 #undef DO_UPDATE
823
824   g_object_thaw_notify (G_OBJECT (flacenc));
825
826   return TRUE;
827 }
828
829 static FLAC__StreamEncoderSeekStatus
830 gst_flac_enc_seek_callback (const FLAC__StreamEncoder * encoder,
831     FLAC__uint64 absolute_byte_offset, void *client_data)
832 {
833   GstFlacEnc *flacenc;
834   GstPad *peerpad;
835   GstSegment seg;
836
837   flacenc = GST_FLAC_ENC (client_data);
838
839   if (flacenc->stopped)
840     return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
841
842   if ((peerpad = gst_pad_get_peer (GST_AUDIO_ENCODER_SRC_PAD (flacenc)))) {
843     GstEvent *event;
844     gboolean ret;
845
846     gst_segment_init (&seg, GST_FORMAT_BYTES);
847     seg.start = absolute_byte_offset;
848     seg.stop = GST_BUFFER_OFFSET_NONE;
849     seg.time = 0;
850     event = gst_event_new_segment (&seg);
851
852     ret = gst_pad_send_event (peerpad, event);
853     gst_object_unref (peerpad);
854
855     if (ret) {
856       GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " %s",
857           (guint64) absolute_byte_offset, "succeeded");
858     } else {
859       GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " %s",
860           (guint64) absolute_byte_offset, "failed");
861       return FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED;
862     }
863   } else {
864     GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " failed (no peer pad)",
865         (guint64) absolute_byte_offset);
866   }
867
868   flacenc->offset = absolute_byte_offset;
869   return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
870 }
871
872 static void
873 notgst_value_array_append_buffer (GValue * array_val, GstBuffer * buf)
874 {
875   GValue value = { 0, };
876
877   g_value_init (&value, GST_TYPE_BUFFER);
878   /* copy buffer to avoid problems with circular refcounts */
879   buf = gst_buffer_copy (buf);
880   /* again, for good measure */
881   GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
882   gst_value_set_buffer (&value, buf);
883   gst_buffer_unref (buf);
884   gst_value_array_append_value (array_val, &value);
885   g_value_unset (&value);
886 }
887
888 #define HDR_TYPE_STREAMINFO     0
889 #define HDR_TYPE_VORBISCOMMENT  4
890
891 static GstFlowReturn
892 gst_flac_enc_process_stream_headers (GstFlacEnc * enc)
893 {
894   GstBuffer *vorbiscomment = NULL;
895   GstBuffer *streaminfo = NULL;
896   GstBuffer *marker = NULL;
897   GValue array = { 0, };
898   GstCaps *caps;
899   GList *l;
900   GstFlowReturn ret = GST_FLOW_OK;
901   GstAudioInfo *info =
902       gst_audio_encoder_get_audio_info (GST_AUDIO_ENCODER (enc));
903
904   caps = gst_caps_new_simple ("audio/x-flac",
905       "channels", G_TYPE_INT, GST_AUDIO_INFO_CHANNELS (info),
906       "rate", G_TYPE_INT, GST_AUDIO_INFO_RATE (info), NULL);
907
908   for (l = enc->headers; l != NULL; l = l->next) {
909     GstBuffer *buf;
910     GstMapInfo map;
911     guint8 *data;
912     gsize size;
913
914     /* mark buffers so oggmux will ignore them if it already muxed the
915      * header buffers from the streamheaders field in the caps */
916     l->data = gst_buffer_make_writable (GST_BUFFER_CAST (l->data));
917
918     buf = GST_BUFFER_CAST (l->data);
919     GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
920
921     gst_buffer_map (buf, &map, GST_MAP_READ);
922     data = map.data;
923     size = map.size;
924
925     /* find initial 4-byte marker which we need to skip later on */
926     if (size == 4 && memcmp (data, "fLaC", 4) == 0) {
927       marker = buf;
928     } else if (size > 1 && (data[0] & 0x7f) == HDR_TYPE_STREAMINFO) {
929       streaminfo = buf;
930     } else if (size > 1 && (data[0] & 0x7f) == HDR_TYPE_VORBISCOMMENT) {
931       vorbiscomment = buf;
932     }
933
934     gst_buffer_unmap (buf, &map);
935   }
936
937   if (marker == NULL || streaminfo == NULL || vorbiscomment == NULL) {
938     GST_WARNING_OBJECT (enc, "missing header %p %p %p, muxing into container "
939         "formats may be broken", marker, streaminfo, vorbiscomment);
940     goto push_headers;
941   }
942
943   g_value_init (&array, GST_TYPE_ARRAY);
944
945   /* add marker including STREAMINFO header */
946   {
947     GstBuffer *buf;
948     guint16 num;
949     GstMapInfo map;
950     guint8 *bdata;
951     gsize slen;
952
953     /* minus one for the marker that is merged with streaminfo here */
954     num = g_list_length (enc->headers) - 1;
955
956     slen = gst_buffer_get_size (streaminfo);
957     buf = gst_buffer_new_and_alloc (13 + slen);
958
959     gst_buffer_map (buf, &map, GST_MAP_WRITE);
960     bdata = map.data;
961     bdata[0] = 0x7f;
962     memcpy (bdata + 1, "FLAC", 4);
963     bdata[5] = 0x01;            /* mapping version major */
964     bdata[6] = 0x00;            /* mapping version minor */
965     bdata[7] = (num & 0xFF00) >> 8;
966     bdata[8] = (num & 0x00FF) >> 0;
967     memcpy (bdata + 9, "fLaC", 4);
968     gst_buffer_extract (streaminfo, 0, bdata + 13, slen);
969     gst_buffer_unmap (buf, &map);
970
971     notgst_value_array_append_buffer (&array, buf);
972     gst_buffer_unref (buf);
973   }
974
975   /* add VORBISCOMMENT header */
976   notgst_value_array_append_buffer (&array, vorbiscomment);
977
978   /* add other headers, if there are any */
979   for (l = enc->headers; l != NULL; l = l->next) {
980     GstBuffer *buf = GST_BUFFER_CAST (l->data);
981
982     if (buf != marker && buf != streaminfo && buf != vorbiscomment) {
983       notgst_value_array_append_buffer (&array, buf);
984     }
985   }
986
987   gst_structure_set_value (gst_caps_get_structure (caps, 0),
988       "streamheader", &array);
989   g_value_unset (&array);
990
991 push_headers:
992
993   /* push header buffers; update caps, so when we push the first buffer the
994    * negotiated caps will change to caps that include the streamheader field */
995   for (l = enc->headers; l != NULL; l = l->next) {
996     GstBuffer *buf;
997
998     buf = GST_BUFFER (l->data);
999     GST_LOG_OBJECT (enc,
1000         "Pushing header buffer, size %" G_GSIZE_FORMAT " bytes",
1001         gst_buffer_get_size (buf));
1002 #if 0
1003     GST_MEMDUMP_OBJECT (enc, "header buffer", GST_BUFFER_DATA (buf),
1004         GST_BUFFER_SIZE (buf));
1005 #endif
1006     ret = gst_pad_push (GST_AUDIO_ENCODER_SRC_PAD (enc), buf);
1007     l->data = NULL;
1008   }
1009   g_list_free (enc->headers);
1010   enc->headers = NULL;
1011
1012   gst_caps_unref (caps);
1013
1014   return ret;
1015 }
1016
1017 static FLAC__StreamEncoderWriteStatus
1018 gst_flac_enc_write_callback (const FLAC__StreamEncoder * encoder,
1019     const FLAC__byte buffer[], size_t bytes,
1020     unsigned samples, unsigned current_frame, void *client_data)
1021 {
1022   GstFlowReturn ret = GST_FLOW_OK;
1023   GstFlacEnc *flacenc;
1024   GstBuffer *outbuf;
1025
1026   flacenc = GST_FLAC_ENC (client_data);
1027
1028   if (flacenc->stopped)
1029     return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
1030
1031   outbuf = gst_buffer_new_and_alloc (bytes);
1032   gst_buffer_fill (outbuf, 0, buffer, bytes);
1033
1034   /* we assume libflac passes us stuff neatly framed */
1035   if (!flacenc->got_headers) {
1036     if (samples == 0) {
1037       GST_DEBUG_OBJECT (flacenc, "Got header, queueing (%u bytes)",
1038           (guint) bytes);
1039       flacenc->headers = g_list_append (flacenc->headers, outbuf);
1040       /* note: it's important that we increase our byte offset */
1041       goto out;
1042     } else {
1043       GST_INFO_OBJECT (flacenc, "Non-header packet, we have all headers now");
1044       ret = gst_flac_enc_process_stream_headers (flacenc);
1045       flacenc->got_headers = TRUE;
1046     }
1047   }
1048
1049   if (flacenc->got_headers && samples == 0) {
1050     /* header fixup, push downstream directly */
1051     GST_DEBUG_OBJECT (flacenc, "Fixing up headers at pos=%" G_GUINT64_FORMAT
1052         ", size=%u", flacenc->offset, (guint) bytes);
1053 #if 0
1054     GST_MEMDUMP_OBJECT (flacenc, "Presumed header fragment",
1055         GST_BUFFER_DATA (outbuf), GST_BUFFER_SIZE (outbuf));
1056 #endif
1057     ret = gst_pad_push (GST_AUDIO_ENCODER_SRC_PAD (flacenc), outbuf);
1058   } else {
1059     /* regular frame data, pass to base class */
1060     GST_LOG ("Pushing buffer: ts=%" GST_TIME_FORMAT ", samples=%u, size=%u, "
1061         "pos=%" G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
1062         samples, (guint) bytes, flacenc->offset);
1063     ret = gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (flacenc),
1064         outbuf, samples);
1065   }
1066
1067   if (ret != GST_FLOW_OK)
1068     GST_DEBUG_OBJECT (flacenc, "flow: %s", gst_flow_get_name (ret));
1069
1070   flacenc->last_flow = ret;
1071
1072 out:
1073   flacenc->offset += bytes;
1074
1075   if (ret != GST_FLOW_OK)
1076     return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
1077
1078   return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
1079 }
1080
1081 static FLAC__StreamEncoderTellStatus
1082 gst_flac_enc_tell_callback (const FLAC__StreamEncoder * encoder,
1083     FLAC__uint64 * absolute_byte_offset, void *client_data)
1084 {
1085   GstFlacEnc *flacenc = GST_FLAC_ENC (client_data);
1086
1087   *absolute_byte_offset = flacenc->offset;
1088
1089   return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
1090 }
1091
1092 static gboolean
1093 gst_flac_enc_sink_event (GstAudioEncoder * enc, GstEvent * event)
1094 {
1095   GstFlacEnc *flacenc;
1096   GstTagList *taglist;
1097   gboolean ret = FALSE;
1098
1099   flacenc = GST_FLAC_ENC (enc);
1100
1101   GST_DEBUG ("Received %s event on sinkpad", GST_EVENT_TYPE_NAME (event));
1102
1103   switch (GST_EVENT_TYPE (event)) {
1104     case GST_EVENT_EOS:
1105       flacenc->eos = TRUE;
1106       ret = GST_AUDIO_ENCODER_CLASS (parent_class)->event (enc, event);
1107       break;
1108     case GST_EVENT_TAG:
1109       if (flacenc->tags) {
1110         gst_event_parse_tag (event, &taglist);
1111         gst_tag_list_insert (flacenc->tags, taglist,
1112             gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (flacenc)));
1113       } else {
1114         g_assert_not_reached ();
1115       }
1116       ret = GST_AUDIO_ENCODER_CLASS (parent_class)->event (enc, event);
1117       break;
1118     default:
1119       ret = GST_AUDIO_ENCODER_CLASS (parent_class)->event (enc, event);
1120       break;
1121   }
1122
1123   return ret;
1124 }
1125
1126 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
1127 #define READ_INT24 GST_READ_UINT24_LE
1128 #else
1129 #define READ_INT24 GST_READ_UINT24_BE
1130 #endif
1131
1132 static GstFlowReturn
1133 gst_flac_enc_handle_frame (GstAudioEncoder * enc, GstBuffer * buffer)
1134 {
1135   GstFlacEnc *flacenc;
1136   FLAC__int32 *data;
1137   gint samples, width, channels;
1138   gulong i;
1139   gint j;
1140   FLAC__bool res;
1141   GstMapInfo map;
1142   GstAudioInfo *info =
1143       gst_audio_encoder_get_audio_info (GST_AUDIO_ENCODER (enc));
1144   gint *reorder_map;
1145
1146   flacenc = GST_FLAC_ENC (enc);
1147
1148   /* base class ensures configuration */
1149   g_return_val_if_fail (GST_AUDIO_INFO_WIDTH (info) != 0,
1150       GST_FLOW_NOT_NEGOTIATED);
1151
1152   width = GST_AUDIO_INFO_WIDTH (info);
1153   channels = GST_AUDIO_INFO_CHANNELS (info);
1154   reorder_map = flacenc->channel_reorder_map;
1155
1156   if (G_UNLIKELY (!buffer)) {
1157     if (flacenc->eos) {
1158       FLAC__stream_encoder_finish (flacenc->encoder);
1159     } else {
1160       /* can't handle intermittent draining/resyncing */
1161       GST_ELEMENT_WARNING (flacenc, STREAM, FORMAT, (NULL),
1162           ("Stream discontinuity detected. "
1163               "The output may have wrong timestamps, "
1164               "consider using audiorate to handle discontinuities"));
1165     }
1166     return flacenc->last_flow;
1167   }
1168
1169   gst_buffer_map (buffer, &map, GST_MAP_READ);
1170   samples = map.size / (width >> 3);
1171
1172   data = g_malloc (samples * sizeof (FLAC__int32));
1173
1174   samples /= channels;
1175   if (width == 8) {
1176     gint8 *indata = (gint8 *) map.data;
1177
1178     for (i = 0; i < samples; i++)
1179       for (j = 0; j < channels; j++)
1180         data[i * channels + reorder_map[j]] =
1181             (FLAC__int32) indata[i * channels + j];
1182   } else if (width == 16) {
1183     gint16 *indata = (gint16 *) map.data;
1184
1185     for (i = 0; i < samples; i++)
1186       for (j = 0; j < channels; j++)
1187         data[i * channels + reorder_map[j]] =
1188             (FLAC__int32) indata[i * channels + j];
1189   } else if (width == 24) {
1190     guint8 *indata = (guint8 *) map.data;
1191     guint32 val;
1192
1193     for (i = 0; i < samples; i++)
1194       for (j = 0; j < channels; j++) {
1195         val = READ_INT24 (&indata[3 * (i * channels + j)]);
1196         if (val & 0x00800000)
1197           val |= 0xff000000;
1198         data[i * channels + reorder_map[j]] = (FLAC__int32) val;
1199       }
1200   } else if (width == 32) {
1201     gint32 *indata = (gint32 *) map.data;
1202
1203     for (i = 0; i < samples; i++)
1204       for (j = 0; j < channels; j++)
1205         data[i * channels + reorder_map[j]] =
1206             (FLAC__int32) indata[i * channels + j];
1207   } else {
1208     g_assert_not_reached ();
1209   }
1210   gst_buffer_unmap (buffer, &map);
1211
1212   res = FLAC__stream_encoder_process_interleaved (flacenc->encoder,
1213       (const FLAC__int32 *) data, samples / channels);
1214
1215   g_free (data);
1216
1217   if (!res) {
1218     if (flacenc->last_flow == GST_FLOW_OK)
1219       return GST_FLOW_ERROR;
1220     else
1221       return flacenc->last_flow;
1222   }
1223
1224   return GST_FLOW_OK;
1225 }
1226
1227 static void
1228 gst_flac_enc_set_property (GObject * object, guint prop_id,
1229     const GValue * value, GParamSpec * pspec)
1230 {
1231   GstFlacEnc *this = GST_FLAC_ENC (object);
1232
1233   GST_OBJECT_LOCK (this);
1234
1235   switch (prop_id) {
1236     case PROP_QUALITY:
1237       gst_flac_enc_update_quality (this, g_value_get_enum (value));
1238       break;
1239     case PROP_STREAMABLE_SUBSET:
1240       FLAC__stream_encoder_set_streamable_subset (this->encoder,
1241           g_value_get_boolean (value));
1242       break;
1243     case PROP_MID_SIDE_STEREO:
1244       FLAC__stream_encoder_set_do_mid_side_stereo (this->encoder,
1245           g_value_get_boolean (value));
1246       break;
1247     case PROP_LOOSE_MID_SIDE_STEREO:
1248       FLAC__stream_encoder_set_loose_mid_side_stereo (this->encoder,
1249           g_value_get_boolean (value));
1250       break;
1251     case PROP_BLOCKSIZE:
1252       FLAC__stream_encoder_set_blocksize (this->encoder,
1253           g_value_get_uint (value));
1254       break;
1255     case PROP_MAX_LPC_ORDER:
1256       FLAC__stream_encoder_set_max_lpc_order (this->encoder,
1257           g_value_get_uint (value));
1258       break;
1259     case PROP_QLP_COEFF_PRECISION:
1260       FLAC__stream_encoder_set_qlp_coeff_precision (this->encoder,
1261           g_value_get_uint (value));
1262       break;
1263     case PROP_QLP_COEFF_PREC_SEARCH:
1264       FLAC__stream_encoder_set_do_qlp_coeff_prec_search (this->encoder,
1265           g_value_get_boolean (value));
1266       break;
1267     case PROP_ESCAPE_CODING:
1268       FLAC__stream_encoder_set_do_escape_coding (this->encoder,
1269           g_value_get_boolean (value));
1270       break;
1271     case PROP_EXHAUSTIVE_MODEL_SEARCH:
1272       FLAC__stream_encoder_set_do_exhaustive_model_search (this->encoder,
1273           g_value_get_boolean (value));
1274       break;
1275     case PROP_MIN_RESIDUAL_PARTITION_ORDER:
1276       FLAC__stream_encoder_set_min_residual_partition_order (this->encoder,
1277           g_value_get_uint (value));
1278       break;
1279     case PROP_MAX_RESIDUAL_PARTITION_ORDER:
1280       FLAC__stream_encoder_set_max_residual_partition_order (this->encoder,
1281           g_value_get_uint (value));
1282       break;
1283     case PROP_RICE_PARAMETER_SEARCH_DIST:
1284       FLAC__stream_encoder_set_rice_parameter_search_dist (this->encoder,
1285           g_value_get_uint (value));
1286       break;
1287     case PROP_PADDING:
1288       this->padding = g_value_get_uint (value);
1289       break;
1290     case PROP_SEEKPOINTS:
1291       this->seekpoints = g_value_get_int (value);
1292       break;
1293     default:
1294       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1295       break;
1296   }
1297
1298   GST_OBJECT_UNLOCK (this);
1299 }
1300
1301 static void
1302 gst_flac_enc_get_property (GObject * object, guint prop_id,
1303     GValue * value, GParamSpec * pspec)
1304 {
1305   GstFlacEnc *this = GST_FLAC_ENC (object);
1306
1307   GST_OBJECT_LOCK (this);
1308
1309   switch (prop_id) {
1310     case PROP_QUALITY:
1311       g_value_set_enum (value, this->quality);
1312       break;
1313     case PROP_STREAMABLE_SUBSET:
1314       g_value_set_boolean (value,
1315           FLAC__stream_encoder_get_streamable_subset (this->encoder));
1316       break;
1317     case PROP_MID_SIDE_STEREO:
1318       g_value_set_boolean (value,
1319           FLAC__stream_encoder_get_do_mid_side_stereo (this->encoder));
1320       break;
1321     case PROP_LOOSE_MID_SIDE_STEREO:
1322       g_value_set_boolean (value,
1323           FLAC__stream_encoder_get_loose_mid_side_stereo (this->encoder));
1324       break;
1325     case PROP_BLOCKSIZE:
1326       g_value_set_uint (value,
1327           FLAC__stream_encoder_get_blocksize (this->encoder));
1328       break;
1329     case PROP_MAX_LPC_ORDER:
1330       g_value_set_uint (value,
1331           FLAC__stream_encoder_get_max_lpc_order (this->encoder));
1332       break;
1333     case PROP_QLP_COEFF_PRECISION:
1334       g_value_set_uint (value,
1335           FLAC__stream_encoder_get_qlp_coeff_precision (this->encoder));
1336       break;
1337     case PROP_QLP_COEFF_PREC_SEARCH:
1338       g_value_set_boolean (value,
1339           FLAC__stream_encoder_get_do_qlp_coeff_prec_search (this->encoder));
1340       break;
1341     case PROP_ESCAPE_CODING:
1342       g_value_set_boolean (value,
1343           FLAC__stream_encoder_get_do_escape_coding (this->encoder));
1344       break;
1345     case PROP_EXHAUSTIVE_MODEL_SEARCH:
1346       g_value_set_boolean (value,
1347           FLAC__stream_encoder_get_do_exhaustive_model_search (this->encoder));
1348       break;
1349     case PROP_MIN_RESIDUAL_PARTITION_ORDER:
1350       g_value_set_uint (value,
1351           FLAC__stream_encoder_get_min_residual_partition_order
1352           (this->encoder));
1353       break;
1354     case PROP_MAX_RESIDUAL_PARTITION_ORDER:
1355       g_value_set_uint (value,
1356           FLAC__stream_encoder_get_max_residual_partition_order
1357           (this->encoder));
1358       break;
1359     case PROP_RICE_PARAMETER_SEARCH_DIST:
1360       g_value_set_uint (value,
1361           FLAC__stream_encoder_get_rice_parameter_search_dist (this->encoder));
1362       break;
1363     case PROP_PADDING:
1364       g_value_set_uint (value, this->padding);
1365       break;
1366     case PROP_SEEKPOINTS:
1367       g_value_set_int (value, this->seekpoints);
1368       break;
1369     default:
1370       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1371       break;
1372   }
1373
1374   GST_OBJECT_UNLOCK (this);
1375 }