2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
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.
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.
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.
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
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>
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 */
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}
80 #define FLAC_SINK_CAPS \
82 "endianness = (int) BYTE_ORDER, " \
83 "signed = (boolean) TRUE, " \
86 "rate = (int) [ 1, 655350 ], " \
87 "channels = (int) [ 1, 8 ]; " \
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 ]; " \
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 ]"
103 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
106 GST_STATIC_CAPS ("audio/x-flac")
109 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
112 GST_STATIC_CAPS (FLAC_SINK_CAPS)
119 PROP_STREAMABLE_SUBSET,
120 PROP_MID_SIDE_STEREO,
121 PROP_LOOSE_MID_SIDE_STEREO,
124 PROP_QLP_COEFF_PRECISION,
125 PROP_QLP_COEFF_PREC_SEARCH,
127 PROP_EXHAUSTIVE_MODEL_SEARCH,
128 PROP_MIN_RESIDUAL_PARTITION_ORDER,
129 PROP_MAX_RESIDUAL_PARTITION_ORDER,
130 PROP_RICE_PARAMETER_SEARCH_DIST
133 GST_DEBUG_CATEGORY_STATIC (flacenc_debug);
134 #define GST_CAT_DEFAULT flacenc_debug
137 #define _do_init(type) \
139 static const GInterfaceInfo tag_setter_info = { \
144 g_type_add_interface_static (type, GST_TYPE_TAG_SETTER, \
148 GST_BOILERPLATE_FULL (GstFlacEnc, gst_flac_enc, GstElement, GST_TYPE_ELEMENT,
151 static void gst_flac_enc_finalize (GObject * object);
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);
158 static gboolean gst_flac_enc_update_quality (GstFlacEnc * flacenc,
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);
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);
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);
193 gboolean exhaustive_model_search;
194 gboolean escape_coding;
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;
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},
220 #define DEFAULT_QUALITY 5
222 #define GST_TYPE_FLAC_ENC_QUALITY (gst_flac_enc_quality_get_type ())
224 gst_flac_enc_quality_get_type (void)
226 static GType qtype = 0;
229 static const GEnumValue values[] = {
230 {0, "0 - Fastest compression", "0"},
235 {5, "5 - Default", "5"},
238 {8, "8 - Highest compression", "8"},
239 {9, "9 - Insane", "9"},
243 qtype = g_enum_register_static ("GstFlacEncQuality", values);
249 gst_flac_enc_base_init (gpointer g_class)
251 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
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));
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>");
263 GST_DEBUG_CATEGORY_INIT (flacenc_debug, "flacenc", 0,
264 "Flac encoding element");
268 gst_flac_enc_class_init (GstFlacEncClass * klass)
270 GObjectClass *gobject_class;
271 GstElementClass *gstelement_class;
273 gobject_class = (GObjectClass *) klass;
274 gstelement_class = (GstElementClass *) klass;
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;
280 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QUALITY,
281 g_param_spec_enum ("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",
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,
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,
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,
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,
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,
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,
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,
355 gstelement_class->change_state = gst_flac_enc_change_state;
359 gst_flac_enc_init (GstFlacEnc * flacenc, GstFlacEncClass * klass)
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);
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);
377 flacenc->encoder = FLAC__seekable_stream_encoder_new ();
379 flacenc->encoder = FLAC__stream_encoder_new ();
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;
392 gst_flac_enc_finalize (GObject * object)
394 GstFlacEnc *flacenc = GST_FLAC_ENC (object);
396 gst_tag_list_free (flacenc->tags);
398 FLAC__seekable_stream_encoder_delete (flacenc->encoder);
400 FLAC__stream_encoder_delete (flacenc->encoder);
403 G_OBJECT_CLASS (parent_class)->finalize (object);
407 add_one_tag (const GstTagList * list, const gchar * tag, gpointer user_data)
411 GstFlacEnc *flacenc = GST_FLAC_ENC (user_data);
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;
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);
424 g_list_free (comments);
428 gst_flac_enc_set_metadata (GstFlacEnc * flacenc)
430 const GstTagList *user_tags;
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)) {
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 **));
443 FLAC__metadata_object_new (FLAC__METADATA_TYPE_VORBIS_COMMENT);
444 gst_tag_list_foreach (copy, add_one_tag, flacenc);
447 if (FLAC__seekable_stream_encoder_set_metadata (flacenc->encoder,
448 flacenc->meta, 1) != true)
450 if (FLAC__stream_encoder_set_metadata (flacenc->encoder,
451 flacenc->meta, 1) != true)
453 g_warning ("Dude, i'm already initialized!");
454 gst_tag_list_free (copy);
458 gst_flac_enc_caps_append_structure_with_widths (GstCaps * caps,
462 GValue list = { 0, };
463 GValue depth = { 0, };
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);
470 tmp = gst_structure_copy (s);
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);
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);
483 g_value_reset (&list);
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);
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);
496 g_value_unset (&list);
497 g_value_unset (&depth);
501 gst_flac_enc_sink_getcaps (GstPad * pad)
505 GST_OBJECT_LOCK (pad);
507 if (GST_PAD_CAPS (pad)) {
508 ret = gst_caps_ref (GST_PAD_CAPS (pad));
512 ret = gst_caps_new_empty ();
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));
521 for (i = 3; i <= 8; i++) {
522 GValue positions = { 0, };
526 g_value_init (&positions, GST_TYPE_ARRAY);
527 g_value_init (&pos, GST_TYPE_AUDIO_CHANNEL_POSITION);
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);
533 g_value_unset (&pos);
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);
543 gst_flac_enc_caps_append_structure_with_widths (ret, s);
547 GST_OBJECT_UNLOCK (pad);
549 GST_DEBUG_OBJECT (pad, "Return caps %" GST_PTR_FORMAT, ret);
555 gst_flac_enc_query_peer_total_samples (GstFlacEnc * flacenc, GstPad * pad)
557 GstFormat fmt = GST_FORMAT_DEFAULT;
560 if (gst_pad_query_peer_duration (pad, &fmt, &duration)
561 && fmt == GST_FORMAT_DEFAULT && duration != GST_CLOCK_TIME_NONE)
564 fmt = GST_FORMAT_TIME;
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);
573 GST_DEBUG_OBJECT (flacenc, "Upstream reported no total samples");
574 return GST_CLOCK_TIME_NONE;
577 GST_DEBUG_OBJECT (flacenc,
578 "Upstream reported %" G_GUINT64_FORMAT " total samples", duration);
584 gst_flac_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
587 GstStructure *structure;
588 guint64 total_samples = GST_CLOCK_TIME_NONE;
591 FLAC__SeekableStreamEncoderState state;
593 FLAC__StreamEncoderInitStatus init_status;
595 gint depth, chans, rate, width;
597 flacenc = GST_FLAC_ENC (gst_pad_get_parent (pad));
600 if (FLAC__seekable_stream_encoder_get_state (flacenc->encoder) !=
601 FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
603 if (FLAC__stream_encoder_get_state (flacenc->encoder) !=
604 FLAC__STREAM_ENCODER_UNINITIALIZED)
607 goto encoder_already_initialized;
609 structure = gst_caps_get_structure (caps, 0);
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);
619 flacenc->channels = chans;
620 flacenc->width = width;
621 flacenc->depth = depth;
622 flacenc->sample_rate = rate;
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);
628 if (!gst_pad_set_caps (flacenc->srcpad, caps))
629 goto setting_src_caps_failed;
631 gst_caps_unref (caps);
633 total_samples = gst_flac_enc_query_peer_total_samples (flacenc, pad);
636 FLAC__seekable_stream_encoder_set_bits_per_sample (flacenc->encoder,
638 FLAC__seekable_stream_encoder_set_sample_rate (flacenc->encoder,
639 flacenc->sample_rate);
640 FLAC__seekable_stream_encoder_set_channels (flacenc->encoder,
643 if (total_samples != GST_CLOCK_TIME_NONE)
644 FLAC__seekable_stream_encoder_set_total_samples_estimate (flacenc->encoder,
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);
654 FLAC__seekable_stream_encoder_set_client_data (flacenc->encoder, flacenc);
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);
660 if (total_samples != GST_CLOCK_TIME_NONE)
661 FLAC__stream_encoder_set_total_samples_estimate (flacenc->encoder,
665 gst_flac_enc_set_metadata (flacenc);
668 state = FLAC__seekable_stream_encoder_init (flacenc->encoder);
669 if (state != FLAC__STREAM_ENCODER_OK)
670 goto failed_to_initialize;
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;
679 gst_object_unref (flacenc);
683 encoder_already_initialized:
685 g_warning ("flac already initialized -- fixme allow this");
686 gst_object_unref (flacenc);
689 setting_src_caps_failed:
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);
697 failed_to_initialize:
699 GST_ELEMENT_ERROR (flacenc, LIBRARY, INIT, (NULL),
700 ("could not initialize encoder (wrong parameters?)"));
701 gst_object_unref (flacenc);
707 gst_flac_enc_update_quality (GstFlacEnc * flacenc, gint quality)
709 flacenc->quality = quality;
712 #define DO_UPDATE(name, val, str) \
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); \
723 #define DO_UPDATE(name, val, str) \
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); \
735 g_object_freeze_notify (G_OBJECT (flacenc));
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");
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");
759 g_object_thaw_notify (G_OBJECT (flacenc));
765 static FLAC__SeekableStreamEncoderSeekStatus
766 gst_flac_enc_seek_callback (const FLAC__SeekableStreamEncoder * encoder,
767 FLAC__uint64 absolute_byte_offset, void *client_data)
769 static FLAC__StreamEncoderSeekStatus
770 gst_flac_enc_seek_callback (const FLAC__StreamEncoder * encoder,
771 FLAC__uint64 absolute_byte_offset, void *client_data)
778 flacenc = GST_FLAC_ENC (client_data);
780 if (flacenc->stopped)
782 return FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK;
784 return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
786 event = gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_BYTES,
787 absolute_byte_offset, GST_BUFFER_OFFSET_NONE, 0);
789 if ((peerpad = gst_pad_get_peer (flacenc->srcpad))) {
790 gboolean ret = gst_pad_send_event (peerpad, event);
792 gst_object_unref (peerpad);
795 GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " %s", absolute_byte_offset,
798 GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " %s", absolute_byte_offset,
801 return FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED;
803 return FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED;
808 GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " failed (no peer pad)",
809 absolute_byte_offset);
812 flacenc->offset = absolute_byte_offset;
814 return FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK;
816 return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
821 notgst_value_array_append_buffer (GValue * array_val, GstBuffer * buf)
823 GValue value = { 0, };
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);
836 #define HDR_TYPE_STREAMINFO 0
837 #define HDR_TYPE_VORBISCOMMENT 4
840 gst_flac_enc_process_stream_headers (GstFlacEnc * enc)
842 GstBuffer *vorbiscomment = NULL;
843 GstBuffer *streaminfo = NULL;
844 GstBuffer *marker = NULL;
845 GValue array = { 0, };
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);
853 for (l = enc->headers; l != NULL; l = l->next) {
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);
862 data = GST_BUFFER_DATA (GST_BUFFER_CAST (l->data));
863 size = GST_BUFFER_SIZE (GST_BUFFER_CAST (l->data));
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);
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);
881 g_value_init (&array, GST_TYPE_ARRAY);
883 /* add marker including STREAMINFO header */
888 /* minus one for the marker that is merged with streaminfo here */
889 num = g_list_length (enc->headers) - 1;
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);
905 /* add VORBISCOMMENT header */
906 notgst_value_array_append_buffer (&array, vorbiscomment);
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));
917 gst_structure_set_value (gst_caps_get_structure (caps, 0),
918 "streamheader", &array);
919 g_value_unset (&array);
923 gst_pad_set_caps (enc->srcpad, caps);
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) {
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);
936 g_list_free (enc->headers);
939 gst_caps_unref (caps);
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)
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)
954 GstFlowReturn ret = GST_FLOW_OK;
958 flacenc = GST_FLAC_ENC (client_data);
960 if (flacenc->stopped)
961 return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
963 outbuf = gst_buffer_new_and_alloc (bytes);
964 memcpy (GST_BUFFER_DATA (outbuf), buffer, bytes);
966 if (samples > 0 && flacenc->samples_written != (guint64) - 1) {
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);
982 GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
983 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
986 /* we assume libflac passes us stuff neatly framed */
987 if (!flacenc->got_headers) {
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 */
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;
998 } else if (flacenc->got_headers && samples == 0) {
999 GST_WARNING_OBJECT (flacenc, "Got header packet after data packets");
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);
1006 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (flacenc->srcpad));
1007 ret = gst_pad_push (flacenc->srcpad, outbuf);
1009 if (ret != GST_FLOW_OK)
1010 GST_DEBUG_OBJECT (flacenc, "flow: %s", gst_flow_get_name (ret));
1012 flacenc->last_flow = ret;
1016 flacenc->offset += bytes;
1017 flacenc->samples_written += samples;
1019 if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED)
1020 return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
1022 return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
1026 static FLAC__SeekableStreamEncoderTellStatus
1027 gst_flac_enc_tell_callback (const FLAC__SeekableStreamEncoder * encoder,
1028 FLAC__uint64 * absolute_byte_offset, void *client_data)
1030 static FLAC__StreamEncoderTellStatus
1031 gst_flac_enc_tell_callback (const FLAC__StreamEncoder * encoder,
1032 FLAC__uint64 * absolute_byte_offset, void *client_data)
1035 GstFlacEnc *flacenc = GST_FLAC_ENC (client_data);
1037 *absolute_byte_offset = flacenc->offset;
1040 return FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK;
1042 return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
1047 gst_flac_enc_sink_event (GstPad * pad, GstEvent * event)
1049 GstFlacEnc *flacenc;
1050 GstTagList *taglist;
1051 gboolean ret = TRUE;
1053 flacenc = GST_FLAC_ENC (gst_pad_get_parent (pad));
1055 GST_DEBUG ("Received %s event on sinkpad", GST_EVENT_TYPE_NAME (event));
1057 switch (GST_EVENT_TYPE (event)) {
1058 case GST_EVENT_NEWSEGMENT:{
1060 gint64 start, stream_time;
1062 if (flacenc->offset == 0) {
1063 gst_event_parse_new_segment (event, NULL, NULL, &format, &start, NULL,
1069 if (flacenc->offset > 0)
1070 GST_DEBUG ("Not handling mid-stream newsegment event");
1072 GST_DEBUG ("Not handling newsegment event with non-zero start");
1074 GstEvent *e = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES,
1077 ret = gst_pad_push_event (flacenc->srcpad, e);
1079 if (stream_time != 0) {
1080 GST_DEBUG ("Not handling non-zero stream time");
1082 gst_event_unref (event);
1083 /* don't push it downstream, we'll generate our own via seek to 0 */
1088 FLAC__seekable_stream_encoder_finish (flacenc->encoder);
1090 FLAC__stream_encoder_finish (flacenc->encoder);
1092 ret = gst_pad_event_default (pad, event);
1095 if (flacenc->tags) {
1096 gst_event_parse_tag (event, &taglist);
1097 gst_tag_list_insert (flacenc->tags, taglist, GST_TAG_MERGE_REPLACE);
1099 g_assert_not_reached ();
1101 ret = gst_pad_event_default (pad, event);
1104 ret = gst_pad_event_default (pad, event);
1108 gst_object_unref (flacenc);
1113 static GstFlowReturn
1114 gst_flac_enc_chain (GstPad * pad, GstBuffer * buffer)
1116 GstFlacEnc *flacenc;
1119 gint samples, width;
1123 flacenc = GST_FLAC_ENC (GST_PAD_PARENT (pad));
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;
1129 width = flacenc->width;
1131 insize = GST_BUFFER_SIZE (buffer);
1132 samples = insize / (width >> 3);
1134 data = g_malloc (samples * sizeof (FLAC__int32));
1137 gint8 *indata = (gint8 *) GST_BUFFER_DATA (buffer);
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);
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);
1149 for (i = 0; i < samples; i++)
1150 data[i] = (FLAC__int32) indata[i];
1152 g_assert_not_reached ();
1155 gst_buffer_unref (buffer);
1158 res = FLAC__seekable_stream_encoder_process_interleaved (flacenc->encoder,
1159 (const FLAC__int32 *) data, samples / flacenc->channels);
1161 res = FLAC__stream_encoder_process_interleaved (flacenc->encoder,
1162 (const FLAC__int32 *) data, samples / flacenc->channels);
1168 if (flacenc->last_flow == GST_FLOW_OK)
1169 return GST_FLOW_ERROR;
1171 return flacenc->last_flow;
1178 gst_flac_enc_set_property (GObject * object, guint prop_id,
1179 const GValue * value, GParamSpec * pspec)
1181 GstFlacEnc *this = GST_FLAC_ENC (object);
1183 GST_OBJECT_LOCK (this);
1187 gst_flac_enc_update_quality (this, g_value_get_enum (value));
1189 case PROP_STREAMABLE_SUBSET:
1191 FLAC__seekable_stream_encoder_set_streamable_subset (this->encoder,
1192 g_value_get_boolean (value));
1194 FLAC__stream_encoder_set_streamable_subset (this->encoder,
1195 g_value_get_boolean (value));
1198 case PROP_MID_SIDE_STEREO:
1200 FLAC__seekable_stream_encoder_set_do_mid_side_stereo (this->encoder,
1201 g_value_get_boolean (value));
1203 FLAC__stream_encoder_set_do_mid_side_stereo (this->encoder,
1204 g_value_get_boolean (value));
1207 case PROP_LOOSE_MID_SIDE_STEREO:
1209 FLAC__seekable_stream_encoder_set_loose_mid_side_stereo (this->encoder,
1210 g_value_get_boolean (value));
1212 FLAC__stream_encoder_set_loose_mid_side_stereo (this->encoder,
1213 g_value_get_boolean (value));
1216 case PROP_BLOCKSIZE:
1218 FLAC__seekable_stream_encoder_set_blocksize (this->encoder,
1219 g_value_get_uint (value));
1221 FLAC__stream_encoder_set_blocksize (this->encoder,
1222 g_value_get_uint (value));
1225 case PROP_MAX_LPC_ORDER:
1227 FLAC__seekable_stream_encoder_set_max_lpc_order (this->encoder,
1228 g_value_get_uint (value));
1230 FLAC__stream_encoder_set_max_lpc_order (this->encoder,
1231 g_value_get_uint (value));
1234 case PROP_QLP_COEFF_PRECISION:
1236 FLAC__seekable_stream_encoder_set_qlp_coeff_precision (this->encoder,
1237 g_value_get_uint (value));
1239 FLAC__stream_encoder_set_qlp_coeff_precision (this->encoder,
1240 g_value_get_uint (value));
1243 case PROP_QLP_COEFF_PREC_SEARCH:
1245 FLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search (this->encoder,
1246 g_value_get_boolean (value));
1248 FLAC__stream_encoder_set_do_qlp_coeff_prec_search (this->encoder,
1249 g_value_get_boolean (value));
1252 case PROP_ESCAPE_CODING:
1254 FLAC__seekable_stream_encoder_set_do_escape_coding (this->encoder,
1255 g_value_get_boolean (value));
1257 FLAC__stream_encoder_set_do_escape_coding (this->encoder,
1258 g_value_get_boolean (value));
1261 case PROP_EXHAUSTIVE_MODEL_SEARCH:
1263 FLAC__seekable_stream_encoder_set_do_exhaustive_model_search
1264 (this->encoder, g_value_get_boolean (value));
1266 FLAC__stream_encoder_set_do_exhaustive_model_search (this->encoder,
1267 g_value_get_boolean (value));
1270 case PROP_MIN_RESIDUAL_PARTITION_ORDER:
1272 FLAC__seekable_stream_encoder_set_min_residual_partition_order
1273 (this->encoder, g_value_get_uint (value));
1275 FLAC__stream_encoder_set_min_residual_partition_order (this->encoder,
1276 g_value_get_uint (value));
1279 case PROP_MAX_RESIDUAL_PARTITION_ORDER:
1281 FLAC__seekable_stream_encoder_set_max_residual_partition_order
1282 (this->encoder, g_value_get_uint (value));
1284 FLAC__stream_encoder_set_max_residual_partition_order (this->encoder,
1285 g_value_get_uint (value));
1288 case PROP_RICE_PARAMETER_SEARCH_DIST:
1290 FLAC__seekable_stream_encoder_set_rice_parameter_search_dist
1291 (this->encoder, g_value_get_uint (value));
1293 FLAC__stream_encoder_set_rice_parameter_search_dist (this->encoder,
1294 g_value_get_uint (value));
1298 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1302 GST_OBJECT_UNLOCK (this);
1306 gst_flac_enc_get_property (GObject * object, guint prop_id,
1307 GValue * value, GParamSpec * pspec)
1309 GstFlacEnc *this = GST_FLAC_ENC (object);
1311 GST_OBJECT_LOCK (this);
1315 g_value_set_enum (value, this->quality);
1317 case PROP_STREAMABLE_SUBSET:
1319 g_value_set_boolean (value,
1320 FLAC__seekable_stream_encoder_get_streamable_subset (this->encoder));
1322 g_value_set_boolean (value,
1323 FLAC__stream_encoder_get_streamable_subset (this->encoder));
1326 case PROP_MID_SIDE_STEREO:
1328 g_value_set_boolean (value,
1329 FLAC__seekable_stream_encoder_get_do_mid_side_stereo (this->encoder));
1331 g_value_set_boolean (value,
1332 FLAC__stream_encoder_get_do_mid_side_stereo (this->encoder));
1335 case PROP_LOOSE_MID_SIDE_STEREO:
1337 g_value_set_boolean (value,
1338 FLAC__seekable_stream_encoder_get_loose_mid_side_stereo
1341 g_value_set_boolean (value,
1342 FLAC__stream_encoder_get_loose_mid_side_stereo (this->encoder));
1345 case PROP_BLOCKSIZE:
1347 g_value_set_uint (value,
1348 FLAC__seekable_stream_encoder_get_blocksize (this->encoder));
1350 g_value_set_uint (value,
1351 FLAC__stream_encoder_get_blocksize (this->encoder));
1354 case PROP_MAX_LPC_ORDER:
1356 g_value_set_uint (value,
1357 FLAC__seekable_stream_encoder_get_max_lpc_order (this->encoder));
1359 g_value_set_uint (value,
1360 FLAC__stream_encoder_get_max_lpc_order (this->encoder));
1363 case PROP_QLP_COEFF_PRECISION:
1365 g_value_set_uint (value,
1366 FLAC__seekable_stream_encoder_get_qlp_coeff_precision
1369 g_value_set_uint (value,
1370 FLAC__stream_encoder_get_qlp_coeff_precision (this->encoder));
1373 case PROP_QLP_COEFF_PREC_SEARCH:
1375 g_value_set_boolean (value,
1376 FLAC__seekable_stream_encoder_get_do_qlp_coeff_prec_search
1379 g_value_set_boolean (value,
1380 FLAC__stream_encoder_get_do_qlp_coeff_prec_search (this->encoder));
1383 case PROP_ESCAPE_CODING:
1385 g_value_set_boolean (value,
1386 FLAC__seekable_stream_encoder_get_do_escape_coding (this->encoder));
1388 g_value_set_boolean (value,
1389 FLAC__stream_encoder_get_do_escape_coding (this->encoder));
1392 case PROP_EXHAUSTIVE_MODEL_SEARCH:
1394 g_value_set_boolean (value,
1395 FLAC__seekable_stream_encoder_get_do_exhaustive_model_search
1398 g_value_set_boolean (value,
1399 FLAC__stream_encoder_get_do_exhaustive_model_search (this->encoder));
1402 case PROP_MIN_RESIDUAL_PARTITION_ORDER:
1404 g_value_set_uint (value,
1405 FLAC__seekable_stream_encoder_get_min_residual_partition_order
1408 g_value_set_uint (value,
1409 FLAC__stream_encoder_get_min_residual_partition_order
1413 case PROP_MAX_RESIDUAL_PARTITION_ORDER:
1415 g_value_set_uint (value,
1416 FLAC__seekable_stream_encoder_get_max_residual_partition_order
1419 g_value_set_uint (value,
1420 FLAC__stream_encoder_get_max_residual_partition_order
1424 case PROP_RICE_PARAMETER_SEARCH_DIST:
1426 g_value_set_uint (value,
1427 FLAC__seekable_stream_encoder_get_rice_parameter_search_dist
1430 g_value_set_uint (value,
1431 FLAC__stream_encoder_get_rice_parameter_search_dist (this->encoder));
1435 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1439 GST_OBJECT_UNLOCK (this);
1442 static GstStateChangeReturn
1443 gst_flac_enc_change_state (GstElement * element, GstStateChange transition)
1445 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1446 GstFlacEnc *flacenc = GST_FLAC_ENC (element);
1448 switch (transition) {
1449 case GST_STATE_CHANGE_NULL_TO_READY:
1450 case GST_STATE_CHANGE_READY_TO_PAUSED:
1451 flacenc->stopped = FALSE;
1453 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1458 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1460 switch (transition) {
1461 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1463 case GST_STATE_CHANGE_PAUSED_TO_READY:
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);
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);
1477 flacenc->offset = 0;
1478 flacenc->samples_written = 0;
1479 flacenc->channels = 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;
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;
1493 case GST_STATE_CHANGE_READY_TO_NULL: