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
24 * - need to support wider caps, flac can do 1-8 channels and 4-32 bit pcm
25 * http://flac.sourceforge.net/faq.html#general__channels
26 * it also support sampling rate from 1Hz - 655350Hz
35 #include <gstflacenc.h>
36 #include <gst/audio/audio.h>
37 #include <gst/tag/tag.h>
38 #include <gst/gsttagsetter.h>
41 static const GstElementDetails flacenc_details =
42 GST_ELEMENT_DETAILS ("FLAC audio encoder",
43 "Codec/Encoder/Audio",
44 "Encodes audio with the FLAC lossless audio encoder",
45 "Wim Taymans <wim.taymans@chello.be>");
47 #define FLAC_SINK_CAPS \
49 "endianness = (int) BYTE_ORDER, " \
50 "signed = (boolean) TRUE, " \
51 "width = (int) 16, " \
52 "depth = (int) 16, " \
53 "rate = (int) [ 8000, 96000 ], " \
54 "channels = (int) [ 1, 2 ]"
56 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
59 GST_STATIC_CAPS ("audio/x-flac")
62 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
65 GST_STATIC_CAPS (FLAC_SINK_CAPS)
72 PROP_STREAMABLE_SUBSET,
74 PROP_LOOSE_MID_SIDE_STEREO,
77 PROP_QLP_COEFF_PRECISION,
78 PROP_QLP_COEFF_PREC_SEARCH,
80 PROP_EXHAUSTIVE_MODEL_SEARCH,
81 PROP_MIN_RESIDUAL_PARTITION_ORDER,
82 PROP_MAX_RESIDUAL_PARTITION_ORDER,
83 PROP_RICE_PARAMETER_SEARCH_DIST
86 GST_DEBUG_CATEGORY_STATIC (flacenc_debug);
87 #define GST_CAT_DEFAULT flacenc_debug
90 #define _do_init(type) \
92 static const GInterfaceInfo tag_setter_info = { \
97 g_type_add_interface_static (type, GST_TYPE_TAG_SETTER, \
101 GST_BOILERPLATE_FULL (GstFlacEnc, gst_flac_enc, GstElement, GST_TYPE_ELEMENT,
104 static void gst_flac_enc_finalize (GObject * object);
106 static gboolean gst_flac_enc_sink_setcaps (GstPad * pad, GstCaps * caps);
107 static gboolean gst_flac_enc_sink_event (GstPad * pad, GstEvent * event);
108 static GstFlowReturn gst_flac_enc_chain (GstPad * pad, GstBuffer * buffer);
110 static gboolean gst_flac_enc_update_quality (GstFlacEnc * flacenc,
112 static void gst_flac_enc_set_property (GObject * object, guint prop_id,
113 const GValue * value, GParamSpec * pspec);
114 static void gst_flac_enc_get_property (GObject * object, guint prop_id,
115 GValue * value, GParamSpec * pspec);
116 static GstStateChangeReturn gst_flac_enc_change_state (GstElement * element,
117 GstStateChange transition);
120 static FLAC__StreamEncoderWriteStatus
121 gst_flac_enc_write_callback (const FLAC__SeekableStreamEncoder * encoder,
122 const FLAC__byte buffer[], unsigned bytes,
123 unsigned samples, unsigned current_frame, void *client_data);
124 static FLAC__SeekableStreamEncoderSeekStatus
125 gst_flac_enc_seek_callback (const FLAC__SeekableStreamEncoder * encoder,
126 FLAC__uint64 absolute_byte_offset, void *client_data);
127 static FLAC__SeekableStreamEncoderTellStatus
128 gst_flac_enc_tell_callback (const FLAC__SeekableStreamEncoder * encoder,
129 FLAC__uint64 * absolute_byte_offset, void *client_data);
131 static FLAC__StreamEncoderWriteStatus
132 gst_flac_enc_write_callback (const FLAC__StreamEncoder * encoder,
133 const FLAC__byte buffer[], size_t bytes,
134 unsigned samples, unsigned current_frame, void *client_data);
135 static FLAC__StreamEncoderSeekStatus
136 gst_flac_enc_seek_callback (const FLAC__StreamEncoder * encoder,
137 FLAC__uint64 absolute_byte_offset, void *client_data);
138 static FLAC__StreamEncoderTellStatus
139 gst_flac_enc_tell_callback (const FLAC__StreamEncoder * encoder,
140 FLAC__uint64 * absolute_byte_offset, void *client_data);
145 gboolean exhaustive_model_search;
146 gboolean escape_coding;
148 gboolean loose_mid_side;
149 guint qlp_coeff_precision;
150 gboolean qlp_coeff_prec_search;
151 guint min_residual_partition_order;
152 guint max_residual_partition_order;
153 guint rice_parameter_search_dist;
159 static const GstFlacEncParams flacenc_params[] = {
160 {FALSE, FALSE, FALSE, FALSE, 0, FALSE, 2, 2, 0, 0, 1152},
161 {FALSE, FALSE, TRUE, TRUE, 0, FALSE, 2, 2, 0, 0, 1152},
162 {FALSE, FALSE, TRUE, FALSE, 0, FALSE, 0, 3, 0, 0, 1152},
163 {FALSE, FALSE, FALSE, FALSE, 0, FALSE, 3, 3, 0, 6, 4608},
164 {FALSE, FALSE, TRUE, TRUE, 0, FALSE, 3, 3, 0, 8, 4608},
165 {FALSE, FALSE, TRUE, FALSE, 0, FALSE, 3, 3, 0, 8, 4608},
166 {FALSE, FALSE, TRUE, FALSE, 0, FALSE, 0, 4, 0, 8, 4608},
167 {TRUE, FALSE, TRUE, FALSE, 0, FALSE, 0, 6, 0, 8, 4608},
168 {TRUE, FALSE, TRUE, FALSE, 0, FALSE, 0, 6, 0, 12, 4608},
169 {TRUE, TRUE, TRUE, FALSE, 0, FALSE, 0, 16, 0, 32, 4608},
172 #define DEFAULT_QUALITY 5
174 #define GST_TYPE_FLAC_ENC_QUALITY (gst_flac_enc_quality_get_type ())
176 gst_flac_enc_quality_get_type (void)
178 static GType qtype = 0;
181 static const GEnumValue values[] = {
182 {0, "0 - Fastest compression", "0"},
187 {5, "5 - Default", "5"},
190 {8, "8 - Highest compression", "8"},
191 {9, "9 - Insane", "9"},
195 qtype = g_enum_register_static ("GstFlacEncQuality", values);
201 gst_flac_enc_base_init (gpointer g_class)
203 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
205 gst_element_class_add_pad_template (element_class,
206 gst_static_pad_template_get (&src_factory));
207 gst_element_class_add_pad_template (element_class,
208 gst_static_pad_template_get (&sink_factory));
210 gst_element_class_set_details (element_class, &flacenc_details);
212 GST_DEBUG_CATEGORY_INIT (flacenc_debug, "flacenc", 0,
213 "Flac encoding element");
217 gst_flac_enc_class_init (GstFlacEncClass * klass)
219 GObjectClass *gobject_class;
220 GstElementClass *gstelement_class;
222 gobject_class = (GObjectClass *) klass;
223 gstelement_class = (GstElementClass *) klass;
225 gobject_class->set_property = gst_flac_enc_set_property;
226 gobject_class->get_property = gst_flac_enc_get_property;
227 gobject_class->finalize = gst_flac_enc_finalize;
229 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_QUALITY,
230 g_param_spec_enum ("quality",
232 "Speed versus compression tradeoff",
233 GST_TYPE_FLAC_ENC_QUALITY, DEFAULT_QUALITY, G_PARAM_READWRITE));
234 g_object_class_install_property (G_OBJECT_CLASS (klass),
235 PROP_STREAMABLE_SUBSET, g_param_spec_boolean ("streamable_subset",
237 "true to limit encoder to generating a Subset stream, else false",
238 TRUE, G_PARAM_READWRITE));
239 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MID_SIDE_STEREO,
240 g_param_spec_boolean ("mid_side_stereo", "Do mid side stereo",
241 "Do mid side stereo (only for stereo input)",
242 flacenc_params[DEFAULT_QUALITY].mid_side, G_PARAM_READWRITE));
243 g_object_class_install_property (G_OBJECT_CLASS (klass),
244 PROP_LOOSE_MID_SIDE_STEREO, g_param_spec_boolean ("loose_mid_side_stereo",
245 "Loose mid side stereo", "Loose mid side stereo",
246 flacenc_params[DEFAULT_QUALITY].loose_mid_side, G_PARAM_READWRITE));
247 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BLOCKSIZE,
248 g_param_spec_uint ("blocksize", "Blocksize", "Blocksize in samples",
249 FLAC__MIN_BLOCK_SIZE, FLAC__MAX_BLOCK_SIZE,
250 flacenc_params[DEFAULT_QUALITY].blocksize, G_PARAM_READWRITE));
251 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MAX_LPC_ORDER,
252 g_param_spec_uint ("max_lpc_order", "Max LPC order",
253 "Max LPC order; 0 => use only fixed predictors", 0,
254 FLAC__MAX_LPC_ORDER, flacenc_params[DEFAULT_QUALITY].max_lpc_order,
256 g_object_class_install_property (G_OBJECT_CLASS (klass),
257 PROP_QLP_COEFF_PRECISION, g_param_spec_uint ("qlp_coeff_precision",
258 "QLP coefficients precision",
259 "Precision in bits of quantized linear-predictor coefficients; 0 = automatic",
260 0, 32, flacenc_params[DEFAULT_QUALITY].qlp_coeff_precision,
262 g_object_class_install_property (G_OBJECT_CLASS (klass),
263 PROP_QLP_COEFF_PREC_SEARCH, g_param_spec_boolean ("qlp_coeff_prec_search",
264 "Do QLP coefficients precision search",
265 "false = use qlp_coeff_precision, "
266 "true = search around qlp_coeff_precision, take best",
267 flacenc_params[DEFAULT_QUALITY].qlp_coeff_prec_search,
269 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ESCAPE_CODING,
270 g_param_spec_boolean ("escape_coding", "Do Escape coding",
271 "search for escape codes in the entropy coding stage "
272 "for slightly better compression",
273 flacenc_params[DEFAULT_QUALITY].escape_coding, G_PARAM_READWRITE));
274 g_object_class_install_property (G_OBJECT_CLASS (klass),
275 PROP_EXHAUSTIVE_MODEL_SEARCH,
276 g_param_spec_boolean ("exhaustive_model_search",
277 "Do exhaustive model search",
278 "do exhaustive search of LP coefficient quantization (expensive!)",
279 flacenc_params[DEFAULT_QUALITY].exhaustive_model_search,
281 g_object_class_install_property (G_OBJECT_CLASS (klass),
282 PROP_MIN_RESIDUAL_PARTITION_ORDER,
283 g_param_spec_uint ("min_residual_partition_order",
284 "Min residual partition order",
285 "Min residual partition order (above 4 doesn't usually help much)", 0,
286 16, flacenc_params[DEFAULT_QUALITY].min_residual_partition_order,
288 g_object_class_install_property (G_OBJECT_CLASS (klass),
289 PROP_MAX_RESIDUAL_PARTITION_ORDER,
290 g_param_spec_uint ("max_residual_partition_order",
291 "Max residual partition order",
292 "Max residual partition order (above 4 doesn't usually help much)", 0,
293 16, flacenc_params[DEFAULT_QUALITY].max_residual_partition_order,
295 g_object_class_install_property (G_OBJECT_CLASS (klass),
296 PROP_RICE_PARAMETER_SEARCH_DIST,
297 g_param_spec_uint ("rice_parameter_search_dist",
298 "rice_parameter_search_dist",
299 "0 = try only calc'd parameter k; else try all [k-dist..k+dist] "
300 "parameters, use best", 0, FLAC__MAX_RICE_PARTITION_ORDER,
301 flacenc_params[DEFAULT_QUALITY].rice_parameter_search_dist,
304 gstelement_class->change_state = gst_flac_enc_change_state;
308 gst_flac_enc_init (GstFlacEnc * flacenc, GstFlacEncClass * klass)
310 GstElementClass *eclass = GST_ELEMENT_CLASS (klass);
313 gst_pad_new_from_template (gst_element_class_get_pad_template (eclass,
315 gst_element_add_pad (GST_ELEMENT (flacenc), flacenc->sinkpad);
316 gst_pad_set_chain_function (flacenc->sinkpad, gst_flac_enc_chain);
317 gst_pad_set_event_function (flacenc->sinkpad, gst_flac_enc_sink_event);
318 gst_pad_set_setcaps_function (flacenc->sinkpad, gst_flac_enc_sink_setcaps);
321 gst_pad_new_from_template (gst_element_class_get_pad_template (eclass,
323 gst_pad_use_fixed_caps (flacenc->srcpad);
324 gst_element_add_pad (GST_ELEMENT (flacenc), flacenc->srcpad);
327 flacenc->encoder = FLAC__seekable_stream_encoder_new ();
329 flacenc->encoder = FLAC__stream_encoder_new ();
333 flacenc->samples_written = 0;
334 gst_flac_enc_update_quality (flacenc, DEFAULT_QUALITY);
335 flacenc->tags = gst_tag_list_new ();
336 flacenc->got_headers = FALSE;
337 flacenc->headers = NULL;
341 gst_flac_enc_finalize (GObject * object)
343 GstFlacEnc *flacenc = GST_FLAC_ENC (object);
345 gst_tag_list_free (flacenc->tags);
347 FLAC__seekable_stream_encoder_delete (flacenc->encoder);
349 FLAC__stream_encoder_delete (flacenc->encoder);
352 G_OBJECT_CLASS (parent_class)->finalize (object);
356 add_one_tag (const GstTagList * list, const gchar * tag, gpointer user_data)
360 GstFlacEnc *flacenc = GST_FLAC_ENC (user_data);
362 comments = gst_tag_to_vorbis_comments (list, tag);
363 for (it = comments; it != NULL; it = it->next) {
364 FLAC__StreamMetadata_VorbisComment_Entry commment_entry;
366 commment_entry.length = strlen (it->data);
367 commment_entry.entry = it->data;
368 FLAC__metadata_object_vorbiscomment_insert_comment (flacenc->meta[0],
369 flacenc->meta[0]->data.vorbis_comment.num_comments,
370 commment_entry, TRUE);
373 g_list_free (comments);
377 gst_flac_enc_set_metadata (GstFlacEnc * flacenc)
379 const GstTagList *user_tags;
382 g_return_if_fail (flacenc != NULL);
383 user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (flacenc));
384 if ((flacenc->tags == NULL) && (user_tags == NULL)) {
387 copy = gst_tag_list_merge (user_tags, flacenc->tags,
388 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (flacenc)));
389 flacenc->meta = g_malloc (sizeof (FLAC__StreamMetadata **));
392 FLAC__metadata_object_new (FLAC__METADATA_TYPE_VORBIS_COMMENT);
393 gst_tag_list_foreach (copy, add_one_tag, flacenc);
396 if (FLAC__seekable_stream_encoder_set_metadata (flacenc->encoder,
397 flacenc->meta, 1) != true)
399 if (FLAC__stream_encoder_set_metadata (flacenc->encoder,
400 flacenc->meta, 1) != true)
402 g_warning ("Dude, i'm already initialized!");
403 gst_tag_list_free (copy);
407 gst_flac_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
410 GstStructure *structure;
413 FLAC__SeekableStreamEncoderState state;
415 FLAC__StreamEncoderInitStatus init_status;
417 gint depth, chans, rate, width;
419 flacenc = GST_FLAC_ENC (gst_pad_get_parent (pad));
422 if (FLAC__seekable_stream_encoder_get_state (flacenc->encoder) !=
423 FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
425 if (FLAC__stream_encoder_get_state (flacenc->encoder) !=
426 FLAC__STREAM_ENCODER_UNINITIALIZED)
429 goto encoder_already_initialized;
431 structure = gst_caps_get_structure (caps, 0);
433 if (!gst_structure_get_int (structure, "channels", &chans) ||
434 !gst_structure_get_int (structure, "width", &width) ||
435 !gst_structure_get_int (structure, "depth", &depth) ||
436 !gst_structure_get_int (structure, "rate", &rate)) {
437 GST_DEBUG_OBJECT (flacenc, "incomplete caps: %" GST_PTR_FORMAT, caps);
441 flacenc->channels = chans;
442 flacenc->depth = depth;
443 flacenc->sample_rate = rate;
445 caps = gst_caps_new_simple ("audio/x-flac",
446 "channels", G_TYPE_INT, flacenc->channels,
447 "rate", G_TYPE_INT, flacenc->sample_rate, NULL);
449 if (!gst_pad_set_caps (flacenc->srcpad, caps))
450 goto setting_src_caps_failed;
452 gst_caps_unref (caps);
455 FLAC__seekable_stream_encoder_set_bits_per_sample (flacenc->encoder,
457 FLAC__seekable_stream_encoder_set_sample_rate (flacenc->encoder,
458 flacenc->sample_rate);
459 FLAC__seekable_stream_encoder_set_channels (flacenc->encoder,
462 FLAC__seekable_stream_encoder_set_write_callback (flacenc->encoder,
463 gst_flac_enc_write_callback);
464 FLAC__seekable_stream_encoder_set_seek_callback (flacenc->encoder,
465 gst_flac_enc_seek_callback);
466 FLAC__seekable_stream_encoder_set_tell_callback (flacenc->encoder,
467 gst_flac_enc_tell_callback);
469 FLAC__seekable_stream_encoder_set_client_data (flacenc->encoder, flacenc);
471 FLAC__stream_encoder_set_bits_per_sample (flacenc->encoder, flacenc->depth);
472 FLAC__stream_encoder_set_sample_rate (flacenc->encoder, flacenc->sample_rate);
473 FLAC__stream_encoder_set_channels (flacenc->encoder, flacenc->channels);
476 gst_flac_enc_set_metadata (flacenc);
479 state = FLAC__seekable_stream_encoder_init (flacenc->encoder);
480 if (state != FLAC__STREAM_ENCODER_OK)
481 goto failed_to_initialize;
483 init_status = FLAC__stream_encoder_init_stream (flacenc->encoder,
484 gst_flac_enc_write_callback, gst_flac_enc_seek_callback,
485 gst_flac_enc_tell_callback, NULL, flacenc);
486 if (init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK)
487 goto failed_to_initialize;
490 gst_object_unref (flacenc);
494 encoder_already_initialized:
496 g_warning ("flac already initialized -- fixme allow this");
497 gst_object_unref (flacenc);
500 setting_src_caps_failed:
502 GST_DEBUG_OBJECT (flacenc,
503 "Couldn't set caps on source pad: %" GST_PTR_FORMAT, caps);
504 gst_caps_unref (caps);
505 gst_object_unref (flacenc);
508 failed_to_initialize:
510 GST_ELEMENT_ERROR (flacenc, LIBRARY, INIT, (NULL),
511 ("could not initialize encoder (wrong parameters?)"));
512 gst_object_unref (flacenc);
518 gst_flac_enc_update_quality (GstFlacEnc * flacenc, gint quality)
520 flacenc->quality = quality;
523 #define DO_UPDATE(name, val, str) \
525 if (FLAC__seekable_stream_encoder_get_##name (flacenc->encoder) != \
526 flacenc_params[quality].val) { \
527 FLAC__seekable_stream_encoder_set_##name (flacenc->encoder, \
528 flacenc_params[quality].val); \
529 g_object_notify (G_OBJECT (flacenc), str); \
534 #define DO_UPDATE(name, val, str) \
536 if (FLAC__stream_encoder_get_##name (flacenc->encoder) != \
537 flacenc_params[quality].val) { \
538 FLAC__stream_encoder_set_##name (flacenc->encoder, \
539 flacenc_params[quality].val); \
540 g_object_notify (G_OBJECT (flacenc), str); \
546 g_object_freeze_notify (G_OBJECT (flacenc));
548 if (flacenc->channels == 2) {
549 DO_UPDATE (do_mid_side_stereo, mid_side, "mid_side_stereo");
550 DO_UPDATE (loose_mid_side_stereo, loose_mid_side, "loose_mid_side");
553 DO_UPDATE (blocksize, blocksize, "blocksize");
554 DO_UPDATE (max_lpc_order, max_lpc_order, "max_lpc_order");
555 DO_UPDATE (qlp_coeff_precision, qlp_coeff_precision, "qlp_coeff_precision");
556 DO_UPDATE (do_qlp_coeff_prec_search, qlp_coeff_prec_search,
557 "qlp_coeff_prec_search");
558 DO_UPDATE (do_escape_coding, escape_coding, "escape_coding");
559 DO_UPDATE (do_exhaustive_model_search, exhaustive_model_search,
560 "exhaustive_model_search");
561 DO_UPDATE (min_residual_partition_order, min_residual_partition_order,
562 "min_residual_partition_order");
563 DO_UPDATE (max_residual_partition_order, max_residual_partition_order,
564 "max_residual_partition_order");
565 DO_UPDATE (rice_parameter_search_dist, rice_parameter_search_dist,
566 "rice_parameter_search_dist");
570 g_object_thaw_notify (G_OBJECT (flacenc));
576 static FLAC__SeekableStreamEncoderSeekStatus
577 gst_flac_enc_seek_callback (const FLAC__SeekableStreamEncoder * encoder,
578 FLAC__uint64 absolute_byte_offset, void *client_data)
580 static FLAC__StreamEncoderSeekStatus
581 gst_flac_enc_seek_callback (const FLAC__StreamEncoder * encoder,
582 FLAC__uint64 absolute_byte_offset, void *client_data)
589 flacenc = GST_FLAC_ENC (client_data);
591 if (flacenc->stopped)
593 return FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK;
595 return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
597 event = gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_BYTES,
598 absolute_byte_offset, GST_BUFFER_OFFSET_NONE, 0);
600 if ((peerpad = gst_pad_get_peer (flacenc->srcpad))) {
601 gboolean ret = gst_pad_send_event (peerpad, event);
603 gst_object_unref (peerpad);
606 GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " %s", absolute_byte_offset,
609 GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " %s", absolute_byte_offset,
613 GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " failed (no peer pad)",
614 absolute_byte_offset);
617 flacenc->offset = absolute_byte_offset;
619 return FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK;
621 return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
626 notgst_value_array_append_buffer (GValue * array_val, GstBuffer * buf)
628 GValue value = { 0, };
630 g_value_init (&value, GST_TYPE_BUFFER);
631 /* copy buffer to avoid problems with circular refcounts */
632 buf = gst_buffer_copy (buf);
633 /* again, for good measure */
634 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
635 gst_value_set_buffer (&value, buf);
636 gst_buffer_unref (buf);
637 gst_value_array_append_value (array_val, &value);
638 g_value_unset (&value);
641 #define HDR_TYPE_STREAMINFO 0
642 #define HDR_TYPE_VORBISCOMMENT 4
645 gst_flac_enc_process_stream_headers (GstFlacEnc * enc)
647 GstBuffer *vorbiscomment = NULL;
648 GstBuffer *streaminfo = NULL;
649 GstBuffer *marker = NULL;
650 GValue array = { 0, };
654 caps = gst_caps_new_simple ("audio/x-flac",
655 "channels", G_TYPE_INT, enc->channels,
656 "rate", G_TYPE_INT, enc->sample_rate, NULL);
658 for (l = enc->headers; l != NULL; l = l->next) {
662 /* mark buffers so oggmux will ignore them if it already muxed the
663 * header buffers from the streamheaders field in the caps */
664 l->data = gst_buffer_make_metadata_writable (GST_BUFFER (l->data));
665 GST_BUFFER_FLAG_SET (GST_BUFFER (l->data), GST_BUFFER_FLAG_IN_CAPS);
667 data = GST_BUFFER_DATA (GST_BUFFER_CAST (l->data));
668 size = GST_BUFFER_SIZE (GST_BUFFER_CAST (l->data));
670 /* find initial 4-byte marker which we need to skip later on */
671 if (size == 4 && memcmp (data, "fLaC", 4) == 0) {
672 marker = GST_BUFFER_CAST (l->data);
673 } else if (size > 1 && (data[0] & 0x7f) == HDR_TYPE_STREAMINFO) {
674 streaminfo = GST_BUFFER_CAST (l->data);
675 } else if (size > 1 && (data[0] & 0x7f) == HDR_TYPE_VORBISCOMMENT) {
676 vorbiscomment = GST_BUFFER_CAST (l->data);
680 if (marker == NULL || streaminfo == NULL || vorbiscomment == NULL) {
681 GST_WARNING_OBJECT (enc, "missing header %p %p %p, muxing into container "
682 "formats may be broken", marker, streaminfo, vorbiscomment);
686 g_value_init (&array, GST_TYPE_ARRAY);
688 /* add marker including STREAMINFO header */
693 /* minus one for the marker that is merged with streaminfo here */
694 num = g_list_length (enc->headers) - 1;
696 buf = gst_buffer_new_and_alloc (13 + GST_BUFFER_SIZE (streaminfo));
697 GST_BUFFER_DATA (buf)[0] = 0x7f;
698 memcpy (GST_BUFFER_DATA (buf) + 1, "FLAC", 4);
699 GST_BUFFER_DATA (buf)[5] = 0x01; /* mapping version major */
700 GST_BUFFER_DATA (buf)[6] = 0x00; /* mapping version minor */
701 GST_BUFFER_DATA (buf)[7] = (num & 0xFF00) >> 8;
702 GST_BUFFER_DATA (buf)[8] = (num & 0x00FF) >> 0;
703 memcpy (GST_BUFFER_DATA (buf) + 9, "fLaC", 4);
704 memcpy (GST_BUFFER_DATA (buf) + 13, GST_BUFFER_DATA (streaminfo),
705 GST_BUFFER_SIZE (streaminfo));
706 notgst_value_array_append_buffer (&array, buf);
707 gst_buffer_unref (buf);
710 /* add VORBISCOMMENT header */
711 notgst_value_array_append_buffer (&array, vorbiscomment);
713 /* add other headers, if there are any */
714 for (l = enc->headers; l != NULL; l = l->next) {
715 if (GST_BUFFER_CAST (l->data) != marker &&
716 GST_BUFFER_CAST (l->data) != streaminfo &&
717 GST_BUFFER_CAST (l->data) != vorbiscomment) {
718 notgst_value_array_append_buffer (&array, GST_BUFFER_CAST (l->data));
722 gst_structure_set_value (gst_caps_get_structure (caps, 0),
723 "streamheader", &array);
724 g_value_unset (&array);
728 gst_pad_set_caps (enc->srcpad, caps);
730 /* push header buffers; update caps, so when we push the first buffer the
731 * negotiated caps will change to caps that include the streamheader field */
732 for (l = enc->headers; l != NULL; l = l->next) {
735 buf = GST_BUFFER (l->data);
736 gst_buffer_set_caps (buf, caps);
737 GST_LOG ("Pushing header buffer, size %u bytes", GST_BUFFER_SIZE (buf));
738 (void) gst_pad_push (enc->srcpad, buf);
741 g_list_free (enc->headers);
744 gst_caps_unref (caps);
748 static FLAC__StreamEncoderWriteStatus
749 gst_flac_enc_write_callback (const FLAC__SeekableStreamEncoder * encoder,
750 const FLAC__byte buffer[], unsigned bytes,
751 unsigned samples, unsigned current_frame, void *client_data)
753 static FLAC__StreamEncoderWriteStatus
754 gst_flac_enc_write_callback (const FLAC__StreamEncoder * encoder,
755 const FLAC__byte buffer[], size_t bytes,
756 unsigned samples, unsigned current_frame, void *client_data)
759 GstFlowReturn ret = GST_FLOW_OK;
763 flacenc = GST_FLAC_ENC (client_data);
765 if (flacenc->stopped)
766 return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
768 outbuf = gst_buffer_new_and_alloc (bytes);
769 memcpy (GST_BUFFER_DATA (outbuf), buffer, bytes);
771 if (samples > 0 && flacenc->samples_written != (guint64) - 1) {
774 GST_BUFFER_TIMESTAMP (outbuf) =
775 GST_FRAMES_TO_CLOCK_TIME (flacenc->samples_written,
776 flacenc->sample_rate);
777 GST_BUFFER_DURATION (outbuf) =
778 GST_FRAMES_TO_CLOCK_TIME (samples, flacenc->sample_rate);
779 /* offset_end = granulepos for ogg muxer */
780 granulepos = flacenc->samples_written + samples;
781 GST_BUFFER_OFFSET_END (outbuf) = granulepos;
782 /* offset = timestamp corresponding to granulepos for ogg muxer
783 * (see vorbisenc for a much more elaborate version of this) */
784 GST_BUFFER_OFFSET (outbuf) =
785 GST_FRAMES_TO_CLOCK_TIME (granulepos, flacenc->sample_rate);
787 GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
788 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
791 /* we assume libflac passes us stuff neatly framed */
792 if (!flacenc->got_headers) {
794 GST_DEBUG_OBJECT (flacenc, "Got header, queueing (%u bytes)", bytes);
795 flacenc->headers = g_list_append (flacenc->headers, outbuf);
796 /* note: it's important that we increase our byte offset */
799 GST_INFO_OBJECT (flacenc, "Non-header packet, we have all headers now");
800 gst_flac_enc_process_stream_headers (flacenc);
801 flacenc->got_headers = TRUE;
805 GST_LOG ("Pushing buffer: ts=%" GST_TIME_FORMAT ", samples=%u, size=%u, "
806 "pos=%" G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
807 samples, bytes, flacenc->offset);
809 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (flacenc->srcpad));
810 ret = gst_pad_push (flacenc->srcpad, outbuf);
814 flacenc->offset += bytes;
815 flacenc->samples_written += samples;
817 if (GST_FLOW_IS_FATAL (ret))
818 return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
820 return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
824 static FLAC__SeekableStreamEncoderTellStatus
825 gst_flac_enc_tell_callback (const FLAC__SeekableStreamEncoder * encoder,
826 FLAC__uint64 * absolute_byte_offset, void *client_data)
828 static FLAC__StreamEncoderTellStatus
829 gst_flac_enc_tell_callback (const FLAC__StreamEncoder * encoder,
830 FLAC__uint64 * absolute_byte_offset, void *client_data)
833 GstFlacEnc *flacenc = GST_FLAC_ENC (client_data);
835 *absolute_byte_offset = flacenc->offset;
838 return FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK;
840 return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
845 gst_flac_enc_sink_event (GstPad * pad, GstEvent * event)
851 flacenc = GST_FLAC_ENC (gst_pad_get_parent (pad));
853 GST_DEBUG ("Received %s event on sinkpad", GST_EVENT_TYPE_NAME (event));
855 switch (GST_EVENT_TYPE (event)) {
856 case GST_EVENT_NEWSEGMENT:{
858 gint64 start, stream_time;
860 if (flacenc->offset == 0) {
861 gst_event_parse_new_segment (event, NULL, NULL, &format, &start, NULL,
867 if (flacenc->offset > 0)
868 GST_DEBUG ("Not handling mid-stream newsegment event");
870 GST_DEBUG ("Not handling newsegment event with non-zero start");
872 GstEvent *e = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES,
875 ret = gst_pad_push_event (flacenc->srcpad, e);
877 if (stream_time != 0) {
878 GST_DEBUG ("Not handling non-zero stream time");
880 gst_event_unref (event);
881 /* don't push it downstream, we'll generate our own via seek to 0 */
886 FLAC__seekable_stream_encoder_finish (flacenc->encoder);
888 FLAC__stream_encoder_finish (flacenc->encoder);
890 ret = gst_pad_event_default (pad, event);
894 gst_event_parse_tag (event, &taglist);
895 gst_tag_list_insert (flacenc->tags, taglist, GST_TAG_MERGE_REPLACE);
897 g_assert_not_reached ();
899 ret = gst_pad_event_default (pad, event);
902 ret = gst_pad_event_default (pad, event);
906 gst_object_unref (flacenc);
912 gst_flac_enc_chain (GstPad * pad, GstBuffer * buffer)
921 flacenc = GST_FLAC_ENC (GST_PAD_PARENT (pad));
923 /* make sure setcaps has been called and the encoder is set up */
924 if (G_UNLIKELY (flacenc->depth == 0))
925 return GST_FLOW_NOT_NEGOTIATED;
927 depth = flacenc->depth;
929 insize = GST_BUFFER_SIZE (buffer);
930 samples = insize / ((depth + 7) >> 3);
932 data = g_malloc (samples * sizeof (FLAC__int32));
935 gint8 *indata = (gint8 *) GST_BUFFER_DATA (buffer);
937 for (i = 0; i < samples; i++)
938 data[i] = (FLAC__int32) indata[i];
939 } else if (depth == 16) {
940 gint16 *indata = (gint16 *) GST_BUFFER_DATA (buffer);
942 for (i = 0; i < samples; i++)
943 data[i] = (FLAC__int32) indata[i];
945 g_assert_not_reached ();
948 gst_buffer_unref (buffer);
951 res = FLAC__seekable_stream_encoder_process_interleaved (flacenc->encoder,
952 (const FLAC__int32 *) data, samples / flacenc->channels);
954 res = FLAC__stream_encoder_process_interleaved (flacenc->encoder,
955 (const FLAC__int32 *) data, samples / flacenc->channels);
963 return GST_FLOW_ERROR;
967 gst_flac_enc_set_property (GObject * object, guint prop_id,
968 const GValue * value, GParamSpec * pspec)
970 GstFlacEnc *this = GST_FLAC_ENC (object);
972 GST_OBJECT_LOCK (this);
976 gst_flac_enc_update_quality (this, g_value_get_enum (value));
978 case PROP_STREAMABLE_SUBSET:
980 FLAC__seekable_stream_encoder_set_streamable_subset (this->encoder,
981 g_value_get_boolean (value));
983 FLAC__stream_encoder_set_streamable_subset (this->encoder,
984 g_value_get_boolean (value));
987 case PROP_MID_SIDE_STEREO:
989 FLAC__seekable_stream_encoder_set_do_mid_side_stereo (this->encoder,
990 g_value_get_boolean (value));
992 FLAC__stream_encoder_set_do_mid_side_stereo (this->encoder,
993 g_value_get_boolean (value));
996 case PROP_LOOSE_MID_SIDE_STEREO:
998 FLAC__seekable_stream_encoder_set_loose_mid_side_stereo (this->encoder,
999 g_value_get_boolean (value));
1001 FLAC__stream_encoder_set_loose_mid_side_stereo (this->encoder,
1002 g_value_get_boolean (value));
1005 case PROP_BLOCKSIZE:
1007 FLAC__seekable_stream_encoder_set_blocksize (this->encoder,
1008 g_value_get_uint (value));
1010 FLAC__stream_encoder_set_blocksize (this->encoder,
1011 g_value_get_uint (value));
1014 case PROP_MAX_LPC_ORDER:
1016 FLAC__seekable_stream_encoder_set_max_lpc_order (this->encoder,
1017 g_value_get_uint (value));
1019 FLAC__stream_encoder_set_max_lpc_order (this->encoder,
1020 g_value_get_uint (value));
1023 case PROP_QLP_COEFF_PRECISION:
1025 FLAC__seekable_stream_encoder_set_qlp_coeff_precision (this->encoder,
1026 g_value_get_uint (value));
1028 FLAC__stream_encoder_set_qlp_coeff_precision (this->encoder,
1029 g_value_get_uint (value));
1032 case PROP_QLP_COEFF_PREC_SEARCH:
1034 FLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search (this->encoder,
1035 g_value_get_boolean (value));
1037 FLAC__stream_encoder_set_do_qlp_coeff_prec_search (this->encoder,
1038 g_value_get_boolean (value));
1041 case PROP_ESCAPE_CODING:
1043 FLAC__seekable_stream_encoder_set_do_escape_coding (this->encoder,
1044 g_value_get_boolean (value));
1046 FLAC__stream_encoder_set_do_escape_coding (this->encoder,
1047 g_value_get_boolean (value));
1050 case PROP_EXHAUSTIVE_MODEL_SEARCH:
1052 FLAC__seekable_stream_encoder_set_do_exhaustive_model_search (this->
1053 encoder, g_value_get_boolean (value));
1055 FLAC__stream_encoder_set_do_exhaustive_model_search (this->
1056 encoder, g_value_get_boolean (value));
1059 case PROP_MIN_RESIDUAL_PARTITION_ORDER:
1061 FLAC__seekable_stream_encoder_set_min_residual_partition_order (this->
1062 encoder, g_value_get_uint (value));
1064 FLAC__stream_encoder_set_min_residual_partition_order (this->
1065 encoder, g_value_get_uint (value));
1068 case PROP_MAX_RESIDUAL_PARTITION_ORDER:
1070 FLAC__seekable_stream_encoder_set_max_residual_partition_order (this->
1071 encoder, g_value_get_uint (value));
1073 FLAC__stream_encoder_set_max_residual_partition_order (this->
1074 encoder, g_value_get_uint (value));
1077 case PROP_RICE_PARAMETER_SEARCH_DIST:
1079 FLAC__seekable_stream_encoder_set_rice_parameter_search_dist (this->
1080 encoder, g_value_get_uint (value));
1082 FLAC__stream_encoder_set_rice_parameter_search_dist (this->
1083 encoder, g_value_get_uint (value));
1087 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1091 GST_OBJECT_UNLOCK (this);
1095 gst_flac_enc_get_property (GObject * object, guint prop_id,
1096 GValue * value, GParamSpec * pspec)
1098 GstFlacEnc *this = GST_FLAC_ENC (object);
1100 GST_OBJECT_LOCK (this);
1104 g_value_set_enum (value, this->quality);
1106 case PROP_STREAMABLE_SUBSET:
1108 g_value_set_boolean (value,
1109 FLAC__seekable_stream_encoder_get_streamable_subset (this->encoder));
1111 g_value_set_boolean (value,
1112 FLAC__stream_encoder_get_streamable_subset (this->encoder));
1115 case PROP_MID_SIDE_STEREO:
1117 g_value_set_boolean (value,
1118 FLAC__seekable_stream_encoder_get_do_mid_side_stereo (this->encoder));
1120 g_value_set_boolean (value,
1121 FLAC__stream_encoder_get_do_mid_side_stereo (this->encoder));
1124 case PROP_LOOSE_MID_SIDE_STEREO:
1126 g_value_set_boolean (value,
1127 FLAC__seekable_stream_encoder_get_loose_mid_side_stereo (this->
1130 g_value_set_boolean (value,
1131 FLAC__stream_encoder_get_loose_mid_side_stereo (this->encoder));
1134 case PROP_BLOCKSIZE:
1136 g_value_set_uint (value,
1137 FLAC__seekable_stream_encoder_get_blocksize (this->encoder));
1139 g_value_set_uint (value,
1140 FLAC__stream_encoder_get_blocksize (this->encoder));
1143 case PROP_MAX_LPC_ORDER:
1145 g_value_set_uint (value,
1146 FLAC__seekable_stream_encoder_get_max_lpc_order (this->encoder));
1148 g_value_set_uint (value,
1149 FLAC__stream_encoder_get_max_lpc_order (this->encoder));
1152 case PROP_QLP_COEFF_PRECISION:
1154 g_value_set_uint (value,
1155 FLAC__seekable_stream_encoder_get_qlp_coeff_precision (this->
1158 g_value_set_uint (value,
1159 FLAC__stream_encoder_get_qlp_coeff_precision (this->encoder));
1162 case PROP_QLP_COEFF_PREC_SEARCH:
1164 g_value_set_boolean (value,
1165 FLAC__seekable_stream_encoder_get_do_qlp_coeff_prec_search (this->
1168 g_value_set_boolean (value,
1169 FLAC__stream_encoder_get_do_qlp_coeff_prec_search (this->encoder));
1172 case PROP_ESCAPE_CODING:
1174 g_value_set_boolean (value,
1175 FLAC__seekable_stream_encoder_get_do_escape_coding (this->encoder));
1177 g_value_set_boolean (value,
1178 FLAC__stream_encoder_get_do_escape_coding (this->encoder));
1181 case PROP_EXHAUSTIVE_MODEL_SEARCH:
1183 g_value_set_boolean (value,
1184 FLAC__seekable_stream_encoder_get_do_exhaustive_model_search (this->
1187 g_value_set_boolean (value,
1188 FLAC__stream_encoder_get_do_exhaustive_model_search (this->encoder));
1191 case PROP_MIN_RESIDUAL_PARTITION_ORDER:
1193 g_value_set_uint (value,
1194 FLAC__seekable_stream_encoder_get_min_residual_partition_order (this->
1197 g_value_set_uint (value,
1198 FLAC__stream_encoder_get_min_residual_partition_order (this->
1202 case PROP_MAX_RESIDUAL_PARTITION_ORDER:
1204 g_value_set_uint (value,
1205 FLAC__seekable_stream_encoder_get_max_residual_partition_order (this->
1208 g_value_set_uint (value,
1209 FLAC__stream_encoder_get_max_residual_partition_order (this->
1213 case PROP_RICE_PARAMETER_SEARCH_DIST:
1215 g_value_set_uint (value,
1216 FLAC__seekable_stream_encoder_get_rice_parameter_search_dist (this->
1219 g_value_set_uint (value,
1220 FLAC__stream_encoder_get_rice_parameter_search_dist (this->encoder));
1224 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1228 GST_OBJECT_UNLOCK (this);
1231 static GstStateChangeReturn
1232 gst_flac_enc_change_state (GstElement * element, GstStateChange transition)
1234 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1235 GstFlacEnc *flacenc = GST_FLAC_ENC (element);
1237 switch (transition) {
1238 case GST_STATE_CHANGE_NULL_TO_READY:
1239 case GST_STATE_CHANGE_READY_TO_PAUSED:
1240 flacenc->stopped = FALSE;
1242 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1247 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1249 switch (transition) {
1250 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1252 case GST_STATE_CHANGE_PAUSED_TO_READY:
1254 if (FLAC__seekable_stream_encoder_get_state (flacenc->encoder) !=
1255 FLAC__STREAM_ENCODER_UNINITIALIZED) {
1256 flacenc->stopped = TRUE;
1257 FLAC__seekable_stream_encoder_finish (flacenc->encoder);
1260 if (FLAC__stream_encoder_get_state (flacenc->encoder) !=
1261 FLAC__STREAM_ENCODER_UNINITIALIZED) {
1262 flacenc->stopped = TRUE;
1263 FLAC__stream_encoder_finish (flacenc->encoder);
1266 flacenc->offset = 0;
1267 flacenc->samples_written = 0;
1268 flacenc->channels = 0;
1270 flacenc->sample_rate = 0;
1271 if (flacenc->meta) {
1272 FLAC__metadata_object_delete (flacenc->meta[0]);
1273 g_free (flacenc->meta);
1274 flacenc->meta = NULL;
1276 g_list_foreach (flacenc->headers, (GFunc) gst_mini_object_unref, NULL);
1277 g_list_free (flacenc->headers);
1278 flacenc->headers = NULL;
1279 flacenc->got_headers = FALSE;
1281 case GST_STATE_CHANGE_READY_TO_NULL: