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