ext/flac/gstflacdec.c: Support decoding of all depths between 4 and 32 bits and read...
[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 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 gboolean
558 gst_flac_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
559 {
560   GstFlacEnc *flacenc;
561   GstStructure *structure;
562
563 #ifdef LEGACY_FLAC
564   FLAC__SeekableStreamEncoderState state;
565 #else
566   FLAC__StreamEncoderInitStatus init_status;
567 #endif
568   gint depth, chans, rate, width;
569
570   flacenc = GST_FLAC_ENC (gst_pad_get_parent (pad));
571
572 #ifdef LEGACY_FLAC
573   if (FLAC__seekable_stream_encoder_get_state (flacenc->encoder) !=
574       FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
575 #else
576   if (FLAC__stream_encoder_get_state (flacenc->encoder) !=
577       FLAC__STREAM_ENCODER_UNINITIALIZED)
578 #endif
579
580     goto encoder_already_initialized;
581
582   structure = gst_caps_get_structure (caps, 0);
583
584   if (!gst_structure_get_int (structure, "channels", &chans) ||
585       !gst_structure_get_int (structure, "width", &width) ||
586       !gst_structure_get_int (structure, "depth", &depth) ||
587       !gst_structure_get_int (structure, "rate", &rate)) {
588     GST_DEBUG_OBJECT (flacenc, "incomplete caps: %" GST_PTR_FORMAT, caps);
589     return FALSE;
590   }
591
592   flacenc->channels = chans;
593   flacenc->width = width;
594   flacenc->depth = depth;
595   flacenc->sample_rate = rate;
596
597   caps = gst_caps_new_simple ("audio/x-flac",
598       "channels", G_TYPE_INT, flacenc->channels,
599       "rate", G_TYPE_INT, flacenc->sample_rate, NULL);
600
601   if (!gst_pad_set_caps (flacenc->srcpad, caps))
602     goto setting_src_caps_failed;
603
604   gst_caps_unref (caps);
605
606 #ifdef LEGACY_FLAC
607   FLAC__seekable_stream_encoder_set_bits_per_sample (flacenc->encoder,
608       flacenc->depth);
609   FLAC__seekable_stream_encoder_set_sample_rate (flacenc->encoder,
610       flacenc->sample_rate);
611   FLAC__seekable_stream_encoder_set_channels (flacenc->encoder,
612       flacenc->channels);
613
614   FLAC__seekable_stream_encoder_set_write_callback (flacenc->encoder,
615       gst_flac_enc_write_callback);
616   FLAC__seekable_stream_encoder_set_seek_callback (flacenc->encoder,
617       gst_flac_enc_seek_callback);
618   FLAC__seekable_stream_encoder_set_tell_callback (flacenc->encoder,
619       gst_flac_enc_tell_callback);
620
621   FLAC__seekable_stream_encoder_set_client_data (flacenc->encoder, flacenc);
622 #else
623   FLAC__stream_encoder_set_bits_per_sample (flacenc->encoder, flacenc->depth);
624   FLAC__stream_encoder_set_sample_rate (flacenc->encoder, flacenc->sample_rate);
625   FLAC__stream_encoder_set_channels (flacenc->encoder, flacenc->channels);
626 #endif
627
628   gst_flac_enc_set_metadata (flacenc);
629
630 #ifdef LEGACY_FLAC
631   state = FLAC__seekable_stream_encoder_init (flacenc->encoder);
632   if (state != FLAC__STREAM_ENCODER_OK)
633     goto failed_to_initialize;
634 #else
635   init_status = FLAC__stream_encoder_init_stream (flacenc->encoder,
636       gst_flac_enc_write_callback, gst_flac_enc_seek_callback,
637       gst_flac_enc_tell_callback, NULL, flacenc);
638   if (init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK)
639     goto failed_to_initialize;
640 #endif
641
642   gst_object_unref (flacenc);
643
644   return TRUE;
645
646 encoder_already_initialized:
647   {
648     g_warning ("flac already initialized -- fixme allow this");
649     gst_object_unref (flacenc);
650     return FALSE;
651   }
652 setting_src_caps_failed:
653   {
654     GST_DEBUG_OBJECT (flacenc,
655         "Couldn't set caps on source pad: %" GST_PTR_FORMAT, caps);
656     gst_caps_unref (caps);
657     gst_object_unref (flacenc);
658     return FALSE;
659   }
660 failed_to_initialize:
661   {
662     GST_ELEMENT_ERROR (flacenc, LIBRARY, INIT, (NULL),
663         ("could not initialize encoder (wrong parameters?)"));
664     gst_object_unref (flacenc);
665     return FALSE;
666   }
667 }
668
669 static gboolean
670 gst_flac_enc_update_quality (GstFlacEnc * flacenc, gint quality)
671 {
672   flacenc->quality = quality;
673
674 #ifdef LEGACY_FLAC
675 #define DO_UPDATE(name, val, str)                                               \
676   G_STMT_START {                                                                \
677     if (FLAC__seekable_stream_encoder_get_##name (flacenc->encoder) !=          \
678         flacenc_params[quality].val) {                                          \
679       FLAC__seekable_stream_encoder_set_##name (flacenc->encoder,               \
680           flacenc_params[quality].val);                                         \
681       g_object_notify (G_OBJECT (flacenc), str);                                \
682     }                                                                           \
683   } G_STMT_END
684
685 #else
686 #define DO_UPDATE(name, val, str)                                               \
687   G_STMT_START {                                                                \
688     if (FLAC__stream_encoder_get_##name (flacenc->encoder) !=                   \
689         flacenc_params[quality].val) {                                          \
690       FLAC__stream_encoder_set_##name (flacenc->encoder,                        \
691           flacenc_params[quality].val);                                         \
692       g_object_notify (G_OBJECT (flacenc), str);                                \
693     }                                                                           \
694   } G_STMT_END
695
696 #endif
697
698   g_object_freeze_notify (G_OBJECT (flacenc));
699
700   if (flacenc->channels == 2) {
701     DO_UPDATE (do_mid_side_stereo, mid_side, "mid_side_stereo");
702     DO_UPDATE (loose_mid_side_stereo, loose_mid_side, "loose_mid_side");
703   }
704
705   DO_UPDATE (blocksize, blocksize, "blocksize");
706   DO_UPDATE (max_lpc_order, max_lpc_order, "max_lpc_order");
707   DO_UPDATE (qlp_coeff_precision, qlp_coeff_precision, "qlp_coeff_precision");
708   DO_UPDATE (do_qlp_coeff_prec_search, qlp_coeff_prec_search,
709       "qlp_coeff_prec_search");
710   DO_UPDATE (do_escape_coding, escape_coding, "escape_coding");
711   DO_UPDATE (do_exhaustive_model_search, exhaustive_model_search,
712       "exhaustive_model_search");
713   DO_UPDATE (min_residual_partition_order, min_residual_partition_order,
714       "min_residual_partition_order");
715   DO_UPDATE (max_residual_partition_order, max_residual_partition_order,
716       "max_residual_partition_order");
717   DO_UPDATE (rice_parameter_search_dist, rice_parameter_search_dist,
718       "rice_parameter_search_dist");
719
720 #undef DO_UPDATE
721
722   g_object_thaw_notify (G_OBJECT (flacenc));
723
724   return TRUE;
725 }
726
727 #ifdef LEGACY_FLAC
728 static FLAC__SeekableStreamEncoderSeekStatus
729 gst_flac_enc_seek_callback (const FLAC__SeekableStreamEncoder * encoder,
730     FLAC__uint64 absolute_byte_offset, void *client_data)
731 #else
732 static FLAC__StreamEncoderSeekStatus
733 gst_flac_enc_seek_callback (const FLAC__StreamEncoder * encoder,
734     FLAC__uint64 absolute_byte_offset, void *client_data)
735 #endif
736 {
737   GstFlacEnc *flacenc;
738   GstEvent *event;
739   GstPad *peerpad;
740
741   flacenc = GST_FLAC_ENC (client_data);
742
743   if (flacenc->stopped)
744 #ifdef LEGACY_FLAC
745     return FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK;
746 #else
747     return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
748 #endif
749   event = gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_BYTES,
750       absolute_byte_offset, GST_BUFFER_OFFSET_NONE, 0);
751
752   if ((peerpad = gst_pad_get_peer (flacenc->srcpad))) {
753     gboolean ret = gst_pad_send_event (peerpad, event);
754
755     gst_object_unref (peerpad);
756
757     if (ret) {
758       GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " %s", absolute_byte_offset,
759           "succeeded");
760     } else {
761       GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " %s", absolute_byte_offset,
762           "failed");
763     }
764   } else {
765     GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " failed (no peer pad)",
766         absolute_byte_offset);
767   }
768
769   flacenc->offset = absolute_byte_offset;
770 #ifdef LEGACY_FLAC
771   return FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK;
772 #else
773   return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
774 #endif
775 }
776
777 static void
778 notgst_value_array_append_buffer (GValue * array_val, GstBuffer * buf)
779 {
780   GValue value = { 0, };
781
782   g_value_init (&value, GST_TYPE_BUFFER);
783   /* copy buffer to avoid problems with circular refcounts */
784   buf = gst_buffer_copy (buf);
785   /* again, for good measure */
786   GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
787   gst_value_set_buffer (&value, buf);
788   gst_buffer_unref (buf);
789   gst_value_array_append_value (array_val, &value);
790   g_value_unset (&value);
791 }
792
793 #define HDR_TYPE_STREAMINFO     0
794 #define HDR_TYPE_VORBISCOMMENT  4
795
796 static void
797 gst_flac_enc_process_stream_headers (GstFlacEnc * enc)
798 {
799   GstBuffer *vorbiscomment = NULL;
800   GstBuffer *streaminfo = NULL;
801   GstBuffer *marker = NULL;
802   GValue array = { 0, };
803   GstCaps *caps;
804   GList *l;
805
806   caps = gst_caps_new_simple ("audio/x-flac",
807       "channels", G_TYPE_INT, enc->channels,
808       "rate", G_TYPE_INT, enc->sample_rate, NULL);
809
810   for (l = enc->headers; l != NULL; l = l->next) {
811     const guint8 *data;
812     guint size;
813
814     /* mark buffers so oggmux will ignore them if it already muxed the
815      * header buffers from the streamheaders field in the caps */
816     l->data = gst_buffer_make_metadata_writable (GST_BUFFER (l->data));
817     GST_BUFFER_FLAG_SET (GST_BUFFER (l->data), GST_BUFFER_FLAG_IN_CAPS);
818
819     data = GST_BUFFER_DATA (GST_BUFFER_CAST (l->data));
820     size = GST_BUFFER_SIZE (GST_BUFFER_CAST (l->data));
821
822     /* find initial 4-byte marker which we need to skip later on */
823     if (size == 4 && memcmp (data, "fLaC", 4) == 0) {
824       marker = GST_BUFFER_CAST (l->data);
825     } else if (size > 1 && (data[0] & 0x7f) == HDR_TYPE_STREAMINFO) {
826       streaminfo = GST_BUFFER_CAST (l->data);
827     } else if (size > 1 && (data[0] & 0x7f) == HDR_TYPE_VORBISCOMMENT) {
828       vorbiscomment = GST_BUFFER_CAST (l->data);
829     }
830   }
831
832   if (marker == NULL || streaminfo == NULL || vorbiscomment == NULL) {
833     GST_WARNING_OBJECT (enc, "missing header %p %p %p, muxing into container "
834         "formats may be broken", marker, streaminfo, vorbiscomment);
835     goto push_headers;
836   }
837
838   g_value_init (&array, GST_TYPE_ARRAY);
839
840   /* add marker including STREAMINFO header */
841   {
842     GstBuffer *buf;
843     guint16 num;
844
845     /* minus one for the marker that is merged with streaminfo here */
846     num = g_list_length (enc->headers) - 1;
847
848     buf = gst_buffer_new_and_alloc (13 + GST_BUFFER_SIZE (streaminfo));
849     GST_BUFFER_DATA (buf)[0] = 0x7f;
850     memcpy (GST_BUFFER_DATA (buf) + 1, "FLAC", 4);
851     GST_BUFFER_DATA (buf)[5] = 0x01;    /* mapping version major */
852     GST_BUFFER_DATA (buf)[6] = 0x00;    /* mapping version minor */
853     GST_BUFFER_DATA (buf)[7] = (num & 0xFF00) >> 8;
854     GST_BUFFER_DATA (buf)[8] = (num & 0x00FF) >> 0;
855     memcpy (GST_BUFFER_DATA (buf) + 9, "fLaC", 4);
856     memcpy (GST_BUFFER_DATA (buf) + 13, GST_BUFFER_DATA (streaminfo),
857         GST_BUFFER_SIZE (streaminfo));
858     notgst_value_array_append_buffer (&array, buf);
859     gst_buffer_unref (buf);
860   }
861
862   /* add VORBISCOMMENT header */
863   notgst_value_array_append_buffer (&array, vorbiscomment);
864
865   /* add other headers, if there are any */
866   for (l = enc->headers; l != NULL; l = l->next) {
867     if (GST_BUFFER_CAST (l->data) != marker &&
868         GST_BUFFER_CAST (l->data) != streaminfo &&
869         GST_BUFFER_CAST (l->data) != vorbiscomment) {
870       notgst_value_array_append_buffer (&array, GST_BUFFER_CAST (l->data));
871     }
872   }
873
874   gst_structure_set_value (gst_caps_get_structure (caps, 0),
875       "streamheader", &array);
876   g_value_unset (&array);
877
878 push_headers:
879
880   gst_pad_set_caps (enc->srcpad, caps);
881
882   /* push header buffers; update caps, so when we push the first buffer the
883    * negotiated caps will change to caps that include the streamheader field */
884   for (l = enc->headers; l != NULL; l = l->next) {
885     GstBuffer *buf;
886
887     buf = GST_BUFFER (l->data);
888     gst_buffer_set_caps (buf, caps);
889     GST_LOG ("Pushing header buffer, size %u bytes", GST_BUFFER_SIZE (buf));
890     (void) gst_pad_push (enc->srcpad, buf);
891     l->data = NULL;
892   }
893   g_list_free (enc->headers);
894   enc->headers = NULL;
895
896   gst_caps_unref (caps);
897 }
898
899 #ifdef LEGACY_FLAC
900 static FLAC__StreamEncoderWriteStatus
901 gst_flac_enc_write_callback (const FLAC__SeekableStreamEncoder * encoder,
902     const FLAC__byte buffer[], unsigned bytes,
903     unsigned samples, unsigned current_frame, void *client_data)
904 #else
905 static FLAC__StreamEncoderWriteStatus
906 gst_flac_enc_write_callback (const FLAC__StreamEncoder * encoder,
907     const FLAC__byte buffer[], size_t bytes,
908     unsigned samples, unsigned current_frame, void *client_data)
909 #endif
910 {
911   GstFlowReturn ret = GST_FLOW_OK;
912   GstFlacEnc *flacenc;
913   GstBuffer *outbuf;
914
915   flacenc = GST_FLAC_ENC (client_data);
916
917   if (flacenc->stopped)
918     return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
919
920   outbuf = gst_buffer_new_and_alloc (bytes);
921   memcpy (GST_BUFFER_DATA (outbuf), buffer, bytes);
922
923   if (samples > 0 && flacenc->samples_written != (guint64) - 1) {
924     guint64 granulepos;
925
926     GST_BUFFER_TIMESTAMP (outbuf) =
927         GST_FRAMES_TO_CLOCK_TIME (flacenc->samples_written,
928         flacenc->sample_rate);
929     GST_BUFFER_DURATION (outbuf) =
930         GST_FRAMES_TO_CLOCK_TIME (samples, flacenc->sample_rate);
931     /* offset_end = granulepos for ogg muxer */
932     granulepos = flacenc->samples_written + samples;
933     GST_BUFFER_OFFSET_END (outbuf) = granulepos;
934     /* offset = timestamp corresponding to granulepos for ogg muxer
935      * (see vorbisenc for a much more elaborate version of this) */
936     GST_BUFFER_OFFSET (outbuf) =
937         GST_FRAMES_TO_CLOCK_TIME (granulepos, flacenc->sample_rate);
938   } else {
939     GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
940     GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
941   }
942
943   /* we assume libflac passes us stuff neatly framed */
944   if (!flacenc->got_headers) {
945     if (samples == 0) {
946       GST_DEBUG_OBJECT (flacenc, "Got header, queueing (%u bytes)", bytes);
947       flacenc->headers = g_list_append (flacenc->headers, outbuf);
948       /* note: it's important that we increase our byte offset */
949       goto out;
950     } else {
951       GST_INFO_OBJECT (flacenc, "Non-header packet, we have all headers now");
952       gst_flac_enc_process_stream_headers (flacenc);
953       flacenc->got_headers = TRUE;
954     }
955   }
956
957   GST_LOG ("Pushing buffer: ts=%" GST_TIME_FORMAT ", samples=%u, size=%u, "
958       "pos=%" G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
959       samples, bytes, flacenc->offset);
960
961   gst_buffer_set_caps (outbuf, GST_PAD_CAPS (flacenc->srcpad));
962   ret = gst_pad_push (flacenc->srcpad, outbuf);
963
964   if (ret != GST_FLOW_OK)
965     GST_DEBUG_OBJECT (flacenc, "flow: %s", gst_flow_get_name (ret));
966
967   flacenc->last_flow = ret;
968
969 out:
970
971   flacenc->offset += bytes;
972   flacenc->samples_written += samples;
973
974   if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED)
975     return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
976
977   return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
978 }
979
980 #ifdef LEGACY_FLAC
981 static FLAC__SeekableStreamEncoderTellStatus
982 gst_flac_enc_tell_callback (const FLAC__SeekableStreamEncoder * encoder,
983     FLAC__uint64 * absolute_byte_offset, void *client_data)
984 #else
985 static FLAC__StreamEncoderTellStatus
986 gst_flac_enc_tell_callback (const FLAC__StreamEncoder * encoder,
987     FLAC__uint64 * absolute_byte_offset, void *client_data)
988 #endif
989 {
990   GstFlacEnc *flacenc = GST_FLAC_ENC (client_data);
991
992   *absolute_byte_offset = flacenc->offset;
993
994 #ifdef LEGACY_FLAC
995   return FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK;
996 #else
997   return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
998 #endif
999 }
1000
1001 static gboolean
1002 gst_flac_enc_sink_event (GstPad * pad, GstEvent * event)
1003 {
1004   GstFlacEnc *flacenc;
1005   GstTagList *taglist;
1006   gboolean ret = TRUE;
1007
1008   flacenc = GST_FLAC_ENC (gst_pad_get_parent (pad));
1009
1010   GST_DEBUG ("Received %s event on sinkpad", GST_EVENT_TYPE_NAME (event));
1011
1012   switch (GST_EVENT_TYPE (event)) {
1013     case GST_EVENT_NEWSEGMENT:{
1014       GstFormat format;
1015       gint64 start, stream_time;
1016
1017       if (flacenc->offset == 0) {
1018         gst_event_parse_new_segment (event, NULL, NULL, &format, &start, NULL,
1019             &stream_time);
1020       } else {
1021         start = -1;
1022       }
1023       if (start != 0) {
1024         if (flacenc->offset > 0)
1025           GST_DEBUG ("Not handling mid-stream newsegment event");
1026         else
1027           GST_DEBUG ("Not handling newsegment event with non-zero start");
1028       } else {
1029         GstEvent *e = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES,
1030             0, -1, 0);
1031
1032         ret = gst_pad_push_event (flacenc->srcpad, e);
1033       }
1034       if (stream_time != 0) {
1035         GST_DEBUG ("Not handling non-zero stream time");
1036       }
1037       gst_event_unref (event);
1038       /* don't push it downstream, we'll generate our own via seek to 0 */
1039       break;
1040     }
1041     case GST_EVENT_EOS:
1042 #ifdef LEGACY_FLAC
1043       FLAC__seekable_stream_encoder_finish (flacenc->encoder);
1044 #else
1045       FLAC__stream_encoder_finish (flacenc->encoder);
1046 #endif
1047       ret = gst_pad_event_default (pad, event);
1048       break;
1049     case GST_EVENT_TAG:
1050       if (flacenc->tags) {
1051         gst_event_parse_tag (event, &taglist);
1052         gst_tag_list_insert (flacenc->tags, taglist, GST_TAG_MERGE_REPLACE);
1053       } else {
1054         g_assert_not_reached ();
1055       }
1056       ret = gst_pad_event_default (pad, event);
1057       break;
1058     default:
1059       ret = gst_pad_event_default (pad, event);
1060       break;
1061   }
1062
1063   gst_object_unref (flacenc);
1064
1065   return ret;
1066 }
1067
1068 static GstFlowReturn
1069 gst_flac_enc_chain (GstPad * pad, GstBuffer * buffer)
1070 {
1071   GstFlacEnc *flacenc;
1072   FLAC__int32 *data;
1073   gulong insize;
1074   gint samples, width;
1075   gulong i;
1076   FLAC__bool res;
1077
1078   flacenc = GST_FLAC_ENC (GST_PAD_PARENT (pad));
1079
1080   /* make sure setcaps has been called and the encoder is set up */
1081   if (G_UNLIKELY (flacenc->depth == 0))
1082     return GST_FLOW_NOT_NEGOTIATED;
1083
1084   width = flacenc->width;
1085
1086   insize = GST_BUFFER_SIZE (buffer);
1087   samples = insize / (width >> 3);
1088
1089   data = g_malloc (samples * sizeof (FLAC__int32));
1090
1091   if (width == 8) {
1092     gint8 *indata = (gint8 *) GST_BUFFER_DATA (buffer);
1093
1094     for (i = 0; i < samples; i++)
1095       data[i] = (FLAC__int32) indata[i];
1096   } else if (width == 16) {
1097     gint16 *indata = (gint16 *) GST_BUFFER_DATA (buffer);
1098
1099     for (i = 0; i < samples; i++)
1100       data[i] = (FLAC__int32) indata[i];
1101   } else if (width == 32) {
1102     gint32 *indata = (gint32 *) GST_BUFFER_DATA (buffer);
1103
1104     for (i = 0; i < samples; i++)
1105       data[i] = (FLAC__int32) indata[i];
1106   } else {
1107     g_assert_not_reached ();
1108   }
1109
1110   gst_buffer_unref (buffer);
1111
1112 #ifdef LEGACY_FLAC
1113   res = FLAC__seekable_stream_encoder_process_interleaved (flacenc->encoder,
1114       (const FLAC__int32 *) data, samples / flacenc->channels);
1115 #else
1116   res = FLAC__stream_encoder_process_interleaved (flacenc->encoder,
1117       (const FLAC__int32 *) data, samples / flacenc->channels);
1118 #endif
1119
1120   g_free (data);
1121
1122   if (!res) {
1123     if (flacenc->last_flow == GST_FLOW_OK)
1124       return GST_FLOW_ERROR;
1125     else
1126       return flacenc->last_flow;
1127   }
1128
1129   return GST_FLOW_OK;
1130 }
1131
1132 static void
1133 gst_flac_enc_set_property (GObject * object, guint prop_id,
1134     const GValue * value, GParamSpec * pspec)
1135 {
1136   GstFlacEnc *this = GST_FLAC_ENC (object);
1137
1138   GST_OBJECT_LOCK (this);
1139
1140   switch (prop_id) {
1141     case PROP_QUALITY:
1142       gst_flac_enc_update_quality (this, g_value_get_enum (value));
1143       break;
1144     case PROP_STREAMABLE_SUBSET:
1145 #ifdef LEGACY_FLAC
1146       FLAC__seekable_stream_encoder_set_streamable_subset (this->encoder,
1147           g_value_get_boolean (value));
1148 #else
1149       FLAC__stream_encoder_set_streamable_subset (this->encoder,
1150           g_value_get_boolean (value));
1151 #endif
1152       break;
1153     case PROP_MID_SIDE_STEREO:
1154 #ifdef LEGACY_FLAC
1155       FLAC__seekable_stream_encoder_set_do_mid_side_stereo (this->encoder,
1156           g_value_get_boolean (value));
1157 #else
1158       FLAC__stream_encoder_set_do_mid_side_stereo (this->encoder,
1159           g_value_get_boolean (value));
1160 #endif
1161       break;
1162     case PROP_LOOSE_MID_SIDE_STEREO:
1163 #ifdef LEGACY_FLAC
1164       FLAC__seekable_stream_encoder_set_loose_mid_side_stereo (this->encoder,
1165           g_value_get_boolean (value));
1166 #else
1167       FLAC__stream_encoder_set_loose_mid_side_stereo (this->encoder,
1168           g_value_get_boolean (value));
1169 #endif
1170       break;
1171     case PROP_BLOCKSIZE:
1172 #ifdef LEGACY_FLAC
1173       FLAC__seekable_stream_encoder_set_blocksize (this->encoder,
1174           g_value_get_uint (value));
1175 #else
1176       FLAC__stream_encoder_set_blocksize (this->encoder,
1177           g_value_get_uint (value));
1178 #endif
1179       break;
1180     case PROP_MAX_LPC_ORDER:
1181 #ifdef LEGACY_FLAC
1182       FLAC__seekable_stream_encoder_set_max_lpc_order (this->encoder,
1183           g_value_get_uint (value));
1184 #else
1185       FLAC__stream_encoder_set_max_lpc_order (this->encoder,
1186           g_value_get_uint (value));
1187 #endif
1188       break;
1189     case PROP_QLP_COEFF_PRECISION:
1190 #ifdef LEGACY_FLAC
1191       FLAC__seekable_stream_encoder_set_qlp_coeff_precision (this->encoder,
1192           g_value_get_uint (value));
1193 #else
1194       FLAC__stream_encoder_set_qlp_coeff_precision (this->encoder,
1195           g_value_get_uint (value));
1196 #endif
1197       break;
1198     case PROP_QLP_COEFF_PREC_SEARCH:
1199 #ifdef LEGACY_FLAC
1200       FLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search (this->encoder,
1201           g_value_get_boolean (value));
1202 #else
1203       FLAC__stream_encoder_set_do_qlp_coeff_prec_search (this->encoder,
1204           g_value_get_boolean (value));
1205 #endif
1206       break;
1207     case PROP_ESCAPE_CODING:
1208 #ifdef LEGACY_FLAC
1209       FLAC__seekable_stream_encoder_set_do_escape_coding (this->encoder,
1210           g_value_get_boolean (value));
1211 #else
1212       FLAC__stream_encoder_set_do_escape_coding (this->encoder,
1213           g_value_get_boolean (value));
1214 #endif
1215       break;
1216     case PROP_EXHAUSTIVE_MODEL_SEARCH:
1217 #ifdef LEGACY_FLAC
1218       FLAC__seekable_stream_encoder_set_do_exhaustive_model_search
1219           (this->encoder, g_value_get_boolean (value));
1220 #else
1221       FLAC__stream_encoder_set_do_exhaustive_model_search (this->encoder,
1222           g_value_get_boolean (value));
1223 #endif
1224       break;
1225     case PROP_MIN_RESIDUAL_PARTITION_ORDER:
1226 #ifdef LEGACY_FLAC
1227       FLAC__seekable_stream_encoder_set_min_residual_partition_order
1228           (this->encoder, g_value_get_uint (value));
1229 #else
1230       FLAC__stream_encoder_set_min_residual_partition_order (this->encoder,
1231           g_value_get_uint (value));
1232 #endif
1233       break;
1234     case PROP_MAX_RESIDUAL_PARTITION_ORDER:
1235 #ifdef LEGACY_FLAC
1236       FLAC__seekable_stream_encoder_set_max_residual_partition_order
1237           (this->encoder, g_value_get_uint (value));
1238 #else
1239       FLAC__stream_encoder_set_max_residual_partition_order (this->encoder,
1240           g_value_get_uint (value));
1241 #endif
1242       break;
1243     case PROP_RICE_PARAMETER_SEARCH_DIST:
1244 #ifdef LEGACY_FLAC
1245       FLAC__seekable_stream_encoder_set_rice_parameter_search_dist
1246           (this->encoder, g_value_get_uint (value));
1247 #else
1248       FLAC__stream_encoder_set_rice_parameter_search_dist (this->encoder,
1249           g_value_get_uint (value));
1250 #endif
1251       break;
1252     default:
1253       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1254       break;
1255   }
1256
1257   GST_OBJECT_UNLOCK (this);
1258 }
1259
1260 static void
1261 gst_flac_enc_get_property (GObject * object, guint prop_id,
1262     GValue * value, GParamSpec * pspec)
1263 {
1264   GstFlacEnc *this = GST_FLAC_ENC (object);
1265
1266   GST_OBJECT_LOCK (this);
1267
1268   switch (prop_id) {
1269     case PROP_QUALITY:
1270       g_value_set_enum (value, this->quality);
1271       break;
1272     case PROP_STREAMABLE_SUBSET:
1273 #ifdef LEGACY_FLAC
1274       g_value_set_boolean (value,
1275           FLAC__seekable_stream_encoder_get_streamable_subset (this->encoder));
1276 #else
1277       g_value_set_boolean (value,
1278           FLAC__stream_encoder_get_streamable_subset (this->encoder));
1279 #endif
1280       break;
1281     case PROP_MID_SIDE_STEREO:
1282 #ifdef LEGACY_FLAC
1283       g_value_set_boolean (value,
1284           FLAC__seekable_stream_encoder_get_do_mid_side_stereo (this->encoder));
1285 #else
1286       g_value_set_boolean (value,
1287           FLAC__stream_encoder_get_do_mid_side_stereo (this->encoder));
1288 #endif
1289       break;
1290     case PROP_LOOSE_MID_SIDE_STEREO:
1291 #ifdef LEGACY_FLAC
1292       g_value_set_boolean (value,
1293           FLAC__seekable_stream_encoder_get_loose_mid_side_stereo
1294           (this->encoder));
1295 #else
1296       g_value_set_boolean (value,
1297           FLAC__stream_encoder_get_loose_mid_side_stereo (this->encoder));
1298 #endif
1299       break;
1300     case PROP_BLOCKSIZE:
1301 #ifdef LEGACY_FLAC
1302       g_value_set_uint (value,
1303           FLAC__seekable_stream_encoder_get_blocksize (this->encoder));
1304 #else
1305       g_value_set_uint (value,
1306           FLAC__stream_encoder_get_blocksize (this->encoder));
1307 #endif
1308       break;
1309     case PROP_MAX_LPC_ORDER:
1310 #ifdef LEGACY_FLAC
1311       g_value_set_uint (value,
1312           FLAC__seekable_stream_encoder_get_max_lpc_order (this->encoder));
1313 #else
1314       g_value_set_uint (value,
1315           FLAC__stream_encoder_get_max_lpc_order (this->encoder));
1316 #endif
1317       break;
1318     case PROP_QLP_COEFF_PRECISION:
1319 #ifdef LEGACY_FLAC
1320       g_value_set_uint (value,
1321           FLAC__seekable_stream_encoder_get_qlp_coeff_precision
1322           (this->encoder));
1323 #else
1324       g_value_set_uint (value,
1325           FLAC__stream_encoder_get_qlp_coeff_precision (this->encoder));
1326 #endif
1327       break;
1328     case PROP_QLP_COEFF_PREC_SEARCH:
1329 #ifdef LEGACY_FLAC
1330       g_value_set_boolean (value,
1331           FLAC__seekable_stream_encoder_get_do_qlp_coeff_prec_search
1332           (this->encoder));
1333 #else
1334       g_value_set_boolean (value,
1335           FLAC__stream_encoder_get_do_qlp_coeff_prec_search (this->encoder));
1336 #endif
1337       break;
1338     case PROP_ESCAPE_CODING:
1339 #ifdef LEGACY_FLAC
1340       g_value_set_boolean (value,
1341           FLAC__seekable_stream_encoder_get_do_escape_coding (this->encoder));
1342 #else
1343       g_value_set_boolean (value,
1344           FLAC__stream_encoder_get_do_escape_coding (this->encoder));
1345 #endif
1346       break;
1347     case PROP_EXHAUSTIVE_MODEL_SEARCH:
1348 #ifdef LEGACY_FLAC
1349       g_value_set_boolean (value,
1350           FLAC__seekable_stream_encoder_get_do_exhaustive_model_search
1351           (this->encoder));
1352 #else
1353       g_value_set_boolean (value,
1354           FLAC__stream_encoder_get_do_exhaustive_model_search (this->encoder));
1355 #endif
1356       break;
1357     case PROP_MIN_RESIDUAL_PARTITION_ORDER:
1358 #ifdef LEGACY_FLAC
1359       g_value_set_uint (value,
1360           FLAC__seekable_stream_encoder_get_min_residual_partition_order
1361           (this->encoder));
1362 #else
1363       g_value_set_uint (value,
1364           FLAC__stream_encoder_get_min_residual_partition_order
1365           (this->encoder));
1366 #endif
1367       break;
1368     case PROP_MAX_RESIDUAL_PARTITION_ORDER:
1369 #ifdef LEGACY_FLAC
1370       g_value_set_uint (value,
1371           FLAC__seekable_stream_encoder_get_max_residual_partition_order
1372           (this->encoder));
1373 #else
1374       g_value_set_uint (value,
1375           FLAC__stream_encoder_get_max_residual_partition_order
1376           (this->encoder));
1377 #endif
1378       break;
1379     case PROP_RICE_PARAMETER_SEARCH_DIST:
1380 #ifdef LEGACY_FLAC
1381       g_value_set_uint (value,
1382           FLAC__seekable_stream_encoder_get_rice_parameter_search_dist
1383           (this->encoder));
1384 #else
1385       g_value_set_uint (value,
1386           FLAC__stream_encoder_get_rice_parameter_search_dist (this->encoder));
1387 #endif
1388       break;
1389     default:
1390       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1391       break;
1392   }
1393
1394   GST_OBJECT_UNLOCK (this);
1395 }
1396
1397 static GstStateChangeReturn
1398 gst_flac_enc_change_state (GstElement * element, GstStateChange transition)
1399 {
1400   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1401   GstFlacEnc *flacenc = GST_FLAC_ENC (element);
1402
1403   switch (transition) {
1404     case GST_STATE_CHANGE_NULL_TO_READY:
1405     case GST_STATE_CHANGE_READY_TO_PAUSED:
1406       flacenc->stopped = FALSE;
1407       break;
1408     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1409     default:
1410       break;
1411   }
1412
1413   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1414
1415   switch (transition) {
1416     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1417       break;
1418     case GST_STATE_CHANGE_PAUSED_TO_READY:
1419 #ifdef LEGACY_FLAC
1420       if (FLAC__seekable_stream_encoder_get_state (flacenc->encoder) !=
1421           FLAC__STREAM_ENCODER_UNINITIALIZED) {
1422         flacenc->stopped = TRUE;
1423         FLAC__seekable_stream_encoder_finish (flacenc->encoder);
1424       }
1425 #else
1426       if (FLAC__stream_encoder_get_state (flacenc->encoder) !=
1427           FLAC__STREAM_ENCODER_UNINITIALIZED) {
1428         flacenc->stopped = TRUE;
1429         FLAC__stream_encoder_finish (flacenc->encoder);
1430       }
1431 #endif
1432       flacenc->offset = 0;
1433       flacenc->samples_written = 0;
1434       flacenc->channels = 0;
1435       flacenc->depth = 0;
1436       flacenc->sample_rate = 0;
1437       if (flacenc->meta) {
1438         FLAC__metadata_object_delete (flacenc->meta[0]);
1439         g_free (flacenc->meta);
1440         flacenc->meta = NULL;
1441       }
1442       g_list_foreach (flacenc->headers, (GFunc) gst_mini_object_unref, NULL);
1443       g_list_free (flacenc->headers);
1444       flacenc->headers = NULL;
1445       flacenc->got_headers = FALSE;
1446       flacenc->last_flow = GST_FLOW_OK;
1447       break;
1448     case GST_STATE_CHANGE_READY_TO_NULL:
1449     default:
1450       break;
1451   }
1452
1453   return ret;
1454 }