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