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 flacenc->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
311 gst_pad_set_chain_function (flacenc->sinkpad,
312 GST_DEBUG_FUNCPTR (gst_flac_enc_chain));
313 gst_pad_set_event_function (flacenc->sinkpad,
314 GST_DEBUG_FUNCPTR (gst_flac_enc_sink_event));
315 gst_pad_set_setcaps_function (flacenc->sinkpad,
316 GST_DEBUG_FUNCPTR (gst_flac_enc_sink_setcaps));
317 gst_element_add_pad (GST_ELEMENT (flacenc), flacenc->sinkpad);
319 flacenc->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
320 gst_pad_use_fixed_caps (flacenc->srcpad);
321 gst_element_add_pad (GST_ELEMENT (flacenc), flacenc->srcpad);
324 flacenc->encoder = FLAC__seekable_stream_encoder_new ();
326 flacenc->encoder = FLAC__stream_encoder_new ();
330 flacenc->samples_written = 0;
331 gst_flac_enc_update_quality (flacenc, DEFAULT_QUALITY);
332 flacenc->tags = gst_tag_list_new ();
333 flacenc->got_headers = FALSE;
334 flacenc->headers = NULL;
335 flacenc->last_flow = GST_FLOW_OK;
339 gst_flac_enc_finalize (GObject * object)
341 GstFlacEnc *flacenc = GST_FLAC_ENC (object);
343 gst_tag_list_free (flacenc->tags);
345 FLAC__seekable_stream_encoder_delete (flacenc->encoder);
347 FLAC__stream_encoder_delete (flacenc->encoder);
350 G_OBJECT_CLASS (parent_class)->finalize (object);
354 add_one_tag (const GstTagList * list, const gchar * tag, gpointer user_data)
358 GstFlacEnc *flacenc = GST_FLAC_ENC (user_data);
360 comments = gst_tag_to_vorbis_comments (list, tag);
361 for (it = comments; it != NULL; it = it->next) {
362 FLAC__StreamMetadata_VorbisComment_Entry commment_entry;
364 commment_entry.length = strlen (it->data);
365 commment_entry.entry = it->data;
366 FLAC__metadata_object_vorbiscomment_insert_comment (flacenc->meta[0],
367 flacenc->meta[0]->data.vorbis_comment.num_comments,
368 commment_entry, TRUE);
371 g_list_free (comments);
375 gst_flac_enc_set_metadata (GstFlacEnc * flacenc)
377 const GstTagList *user_tags;
380 g_return_if_fail (flacenc != NULL);
381 user_tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (flacenc));
382 if ((flacenc->tags == NULL) && (user_tags == NULL)) {
385 copy = gst_tag_list_merge (user_tags, flacenc->tags,
386 gst_tag_setter_get_tag_merge_mode (GST_TAG_SETTER (flacenc)));
387 flacenc->meta = g_malloc (sizeof (FLAC__StreamMetadata **));
390 FLAC__metadata_object_new (FLAC__METADATA_TYPE_VORBIS_COMMENT);
391 gst_tag_list_foreach (copy, add_one_tag, flacenc);
394 if (FLAC__seekable_stream_encoder_set_metadata (flacenc->encoder,
395 flacenc->meta, 1) != true)
397 if (FLAC__stream_encoder_set_metadata (flacenc->encoder,
398 flacenc->meta, 1) != true)
400 g_warning ("Dude, i'm already initialized!");
401 gst_tag_list_free (copy);
405 gst_flac_enc_sink_setcaps (GstPad * pad, GstCaps * caps)
408 GstStructure *structure;
411 FLAC__SeekableStreamEncoderState state;
413 FLAC__StreamEncoderInitStatus init_status;
415 gint depth, chans, rate, width;
417 flacenc = GST_FLAC_ENC (gst_pad_get_parent (pad));
420 if (FLAC__seekable_stream_encoder_get_state (flacenc->encoder) !=
421 FLAC__SEEKABLE_STREAM_ENCODER_UNINITIALIZED)
423 if (FLAC__stream_encoder_get_state (flacenc->encoder) !=
424 FLAC__STREAM_ENCODER_UNINITIALIZED)
427 goto encoder_already_initialized;
429 structure = gst_caps_get_structure (caps, 0);
431 if (!gst_structure_get_int (structure, "channels", &chans) ||
432 !gst_structure_get_int (structure, "width", &width) ||
433 !gst_structure_get_int (structure, "depth", &depth) ||
434 !gst_structure_get_int (structure, "rate", &rate)) {
435 GST_DEBUG_OBJECT (flacenc, "incomplete caps: %" GST_PTR_FORMAT, caps);
439 flacenc->channels = chans;
440 flacenc->depth = depth;
441 flacenc->sample_rate = rate;
443 caps = gst_caps_new_simple ("audio/x-flac",
444 "channels", G_TYPE_INT, flacenc->channels,
445 "rate", G_TYPE_INT, flacenc->sample_rate, NULL);
447 if (!gst_pad_set_caps (flacenc->srcpad, caps))
448 goto setting_src_caps_failed;
450 gst_caps_unref (caps);
453 FLAC__seekable_stream_encoder_set_bits_per_sample (flacenc->encoder,
455 FLAC__seekable_stream_encoder_set_sample_rate (flacenc->encoder,
456 flacenc->sample_rate);
457 FLAC__seekable_stream_encoder_set_channels (flacenc->encoder,
460 FLAC__seekable_stream_encoder_set_write_callback (flacenc->encoder,
461 gst_flac_enc_write_callback);
462 FLAC__seekable_stream_encoder_set_seek_callback (flacenc->encoder,
463 gst_flac_enc_seek_callback);
464 FLAC__seekable_stream_encoder_set_tell_callback (flacenc->encoder,
465 gst_flac_enc_tell_callback);
467 FLAC__seekable_stream_encoder_set_client_data (flacenc->encoder, flacenc);
469 FLAC__stream_encoder_set_bits_per_sample (flacenc->encoder, flacenc->depth);
470 FLAC__stream_encoder_set_sample_rate (flacenc->encoder, flacenc->sample_rate);
471 FLAC__stream_encoder_set_channels (flacenc->encoder, flacenc->channels);
474 gst_flac_enc_set_metadata (flacenc);
477 state = FLAC__seekable_stream_encoder_init (flacenc->encoder);
478 if (state != FLAC__STREAM_ENCODER_OK)
479 goto failed_to_initialize;
481 init_status = FLAC__stream_encoder_init_stream (flacenc->encoder,
482 gst_flac_enc_write_callback, gst_flac_enc_seek_callback,
483 gst_flac_enc_tell_callback, NULL, flacenc);
484 if (init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK)
485 goto failed_to_initialize;
488 gst_object_unref (flacenc);
492 encoder_already_initialized:
494 g_warning ("flac already initialized -- fixme allow this");
495 gst_object_unref (flacenc);
498 setting_src_caps_failed:
500 GST_DEBUG_OBJECT (flacenc,
501 "Couldn't set caps on source pad: %" GST_PTR_FORMAT, caps);
502 gst_caps_unref (caps);
503 gst_object_unref (flacenc);
506 failed_to_initialize:
508 GST_ELEMENT_ERROR (flacenc, LIBRARY, INIT, (NULL),
509 ("could not initialize encoder (wrong parameters?)"));
510 gst_object_unref (flacenc);
516 gst_flac_enc_update_quality (GstFlacEnc * flacenc, gint quality)
518 flacenc->quality = quality;
521 #define DO_UPDATE(name, val, str) \
523 if (FLAC__seekable_stream_encoder_get_##name (flacenc->encoder) != \
524 flacenc_params[quality].val) { \
525 FLAC__seekable_stream_encoder_set_##name (flacenc->encoder, \
526 flacenc_params[quality].val); \
527 g_object_notify (G_OBJECT (flacenc), str); \
532 #define DO_UPDATE(name, val, str) \
534 if (FLAC__stream_encoder_get_##name (flacenc->encoder) != \
535 flacenc_params[quality].val) { \
536 FLAC__stream_encoder_set_##name (flacenc->encoder, \
537 flacenc_params[quality].val); \
538 g_object_notify (G_OBJECT (flacenc), str); \
544 g_object_freeze_notify (G_OBJECT (flacenc));
546 if (flacenc->channels == 2) {
547 DO_UPDATE (do_mid_side_stereo, mid_side, "mid_side_stereo");
548 DO_UPDATE (loose_mid_side_stereo, loose_mid_side, "loose_mid_side");
551 DO_UPDATE (blocksize, blocksize, "blocksize");
552 DO_UPDATE (max_lpc_order, max_lpc_order, "max_lpc_order");
553 DO_UPDATE (qlp_coeff_precision, qlp_coeff_precision, "qlp_coeff_precision");
554 DO_UPDATE (do_qlp_coeff_prec_search, qlp_coeff_prec_search,
555 "qlp_coeff_prec_search");
556 DO_UPDATE (do_escape_coding, escape_coding, "escape_coding");
557 DO_UPDATE (do_exhaustive_model_search, exhaustive_model_search,
558 "exhaustive_model_search");
559 DO_UPDATE (min_residual_partition_order, min_residual_partition_order,
560 "min_residual_partition_order");
561 DO_UPDATE (max_residual_partition_order, max_residual_partition_order,
562 "max_residual_partition_order");
563 DO_UPDATE (rice_parameter_search_dist, rice_parameter_search_dist,
564 "rice_parameter_search_dist");
568 g_object_thaw_notify (G_OBJECT (flacenc));
574 static FLAC__SeekableStreamEncoderSeekStatus
575 gst_flac_enc_seek_callback (const FLAC__SeekableStreamEncoder * encoder,
576 FLAC__uint64 absolute_byte_offset, void *client_data)
578 static FLAC__StreamEncoderSeekStatus
579 gst_flac_enc_seek_callback (const FLAC__StreamEncoder * encoder,
580 FLAC__uint64 absolute_byte_offset, void *client_data)
587 flacenc = GST_FLAC_ENC (client_data);
589 if (flacenc->stopped)
591 return FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK;
593 return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
595 event = gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_BYTES,
596 absolute_byte_offset, GST_BUFFER_OFFSET_NONE, 0);
598 if ((peerpad = gst_pad_get_peer (flacenc->srcpad))) {
599 gboolean ret = gst_pad_send_event (peerpad, event);
601 gst_object_unref (peerpad);
604 GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " %s", absolute_byte_offset,
607 GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " %s", absolute_byte_offset,
611 GST_DEBUG ("Seek to %" G_GUINT64_FORMAT " failed (no peer pad)",
612 absolute_byte_offset);
615 flacenc->offset = absolute_byte_offset;
617 return FLAC__SEEKABLE_STREAM_ENCODER_SEEK_STATUS_OK;
619 return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
624 notgst_value_array_append_buffer (GValue * array_val, GstBuffer * buf)
626 GValue value = { 0, };
628 g_value_init (&value, GST_TYPE_BUFFER);
629 /* copy buffer to avoid problems with circular refcounts */
630 buf = gst_buffer_copy (buf);
631 /* again, for good measure */
632 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
633 gst_value_set_buffer (&value, buf);
634 gst_buffer_unref (buf);
635 gst_value_array_append_value (array_val, &value);
636 g_value_unset (&value);
639 #define HDR_TYPE_STREAMINFO 0
640 #define HDR_TYPE_VORBISCOMMENT 4
643 gst_flac_enc_process_stream_headers (GstFlacEnc * enc)
645 GstBuffer *vorbiscomment = NULL;
646 GstBuffer *streaminfo = NULL;
647 GstBuffer *marker = NULL;
648 GValue array = { 0, };
652 caps = gst_caps_new_simple ("audio/x-flac",
653 "channels", G_TYPE_INT, enc->channels,
654 "rate", G_TYPE_INT, enc->sample_rate, NULL);
656 for (l = enc->headers; l != NULL; l = l->next) {
660 /* mark buffers so oggmux will ignore them if it already muxed the
661 * header buffers from the streamheaders field in the caps */
662 l->data = gst_buffer_make_metadata_writable (GST_BUFFER (l->data));
663 GST_BUFFER_FLAG_SET (GST_BUFFER (l->data), GST_BUFFER_FLAG_IN_CAPS);
665 data = GST_BUFFER_DATA (GST_BUFFER_CAST (l->data));
666 size = GST_BUFFER_SIZE (GST_BUFFER_CAST (l->data));
668 /* find initial 4-byte marker which we need to skip later on */
669 if (size == 4 && memcmp (data, "fLaC", 4) == 0) {
670 marker = GST_BUFFER_CAST (l->data);
671 } else if (size > 1 && (data[0] & 0x7f) == HDR_TYPE_STREAMINFO) {
672 streaminfo = GST_BUFFER_CAST (l->data);
673 } else if (size > 1 && (data[0] & 0x7f) == HDR_TYPE_VORBISCOMMENT) {
674 vorbiscomment = GST_BUFFER_CAST (l->data);
678 if (marker == NULL || streaminfo == NULL || vorbiscomment == NULL) {
679 GST_WARNING_OBJECT (enc, "missing header %p %p %p, muxing into container "
680 "formats may be broken", marker, streaminfo, vorbiscomment);
684 g_value_init (&array, GST_TYPE_ARRAY);
686 /* add marker including STREAMINFO header */
691 /* minus one for the marker that is merged with streaminfo here */
692 num = g_list_length (enc->headers) - 1;
694 buf = gst_buffer_new_and_alloc (13 + GST_BUFFER_SIZE (streaminfo));
695 GST_BUFFER_DATA (buf)[0] = 0x7f;
696 memcpy (GST_BUFFER_DATA (buf) + 1, "FLAC", 4);
697 GST_BUFFER_DATA (buf)[5] = 0x01; /* mapping version major */
698 GST_BUFFER_DATA (buf)[6] = 0x00; /* mapping version minor */
699 GST_BUFFER_DATA (buf)[7] = (num & 0xFF00) >> 8;
700 GST_BUFFER_DATA (buf)[8] = (num & 0x00FF) >> 0;
701 memcpy (GST_BUFFER_DATA (buf) + 9, "fLaC", 4);
702 memcpy (GST_BUFFER_DATA (buf) + 13, GST_BUFFER_DATA (streaminfo),
703 GST_BUFFER_SIZE (streaminfo));
704 notgst_value_array_append_buffer (&array, buf);
705 gst_buffer_unref (buf);
708 /* add VORBISCOMMENT header */
709 notgst_value_array_append_buffer (&array, vorbiscomment);
711 /* add other headers, if there are any */
712 for (l = enc->headers; l != NULL; l = l->next) {
713 if (GST_BUFFER_CAST (l->data) != marker &&
714 GST_BUFFER_CAST (l->data) != streaminfo &&
715 GST_BUFFER_CAST (l->data) != vorbiscomment) {
716 notgst_value_array_append_buffer (&array, GST_BUFFER_CAST (l->data));
720 gst_structure_set_value (gst_caps_get_structure (caps, 0),
721 "streamheader", &array);
722 g_value_unset (&array);
726 gst_pad_set_caps (enc->srcpad, caps);
728 /* push header buffers; update caps, so when we push the first buffer the
729 * negotiated caps will change to caps that include the streamheader field */
730 for (l = enc->headers; l != NULL; l = l->next) {
733 buf = GST_BUFFER (l->data);
734 gst_buffer_set_caps (buf, caps);
735 GST_LOG ("Pushing header buffer, size %u bytes", GST_BUFFER_SIZE (buf));
736 (void) gst_pad_push (enc->srcpad, buf);
739 g_list_free (enc->headers);
742 gst_caps_unref (caps);
746 static FLAC__StreamEncoderWriteStatus
747 gst_flac_enc_write_callback (const FLAC__SeekableStreamEncoder * encoder,
748 const FLAC__byte buffer[], unsigned bytes,
749 unsigned samples, unsigned current_frame, void *client_data)
751 static FLAC__StreamEncoderWriteStatus
752 gst_flac_enc_write_callback (const FLAC__StreamEncoder * encoder,
753 const FLAC__byte buffer[], size_t bytes,
754 unsigned samples, unsigned current_frame, void *client_data)
757 GstFlowReturn ret = GST_FLOW_OK;
761 flacenc = GST_FLAC_ENC (client_data);
763 if (flacenc->stopped)
764 return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
766 outbuf = gst_buffer_new_and_alloc (bytes);
767 memcpy (GST_BUFFER_DATA (outbuf), buffer, bytes);
769 if (samples > 0 && flacenc->samples_written != (guint64) - 1) {
772 GST_BUFFER_TIMESTAMP (outbuf) =
773 GST_FRAMES_TO_CLOCK_TIME (flacenc->samples_written,
774 flacenc->sample_rate);
775 GST_BUFFER_DURATION (outbuf) =
776 GST_FRAMES_TO_CLOCK_TIME (samples, flacenc->sample_rate);
777 /* offset_end = granulepos for ogg muxer */
778 granulepos = flacenc->samples_written + samples;
779 GST_BUFFER_OFFSET_END (outbuf) = granulepos;
780 /* offset = timestamp corresponding to granulepos for ogg muxer
781 * (see vorbisenc for a much more elaborate version of this) */
782 GST_BUFFER_OFFSET (outbuf) =
783 GST_FRAMES_TO_CLOCK_TIME (granulepos, flacenc->sample_rate);
785 GST_BUFFER_TIMESTAMP (outbuf) = GST_CLOCK_TIME_NONE;
786 GST_BUFFER_DURATION (outbuf) = GST_CLOCK_TIME_NONE;
789 /* we assume libflac passes us stuff neatly framed */
790 if (!flacenc->got_headers) {
792 GST_DEBUG_OBJECT (flacenc, "Got header, queueing (%u bytes)", bytes);
793 flacenc->headers = g_list_append (flacenc->headers, outbuf);
794 /* note: it's important that we increase our byte offset */
797 GST_INFO_OBJECT (flacenc, "Non-header packet, we have all headers now");
798 gst_flac_enc_process_stream_headers (flacenc);
799 flacenc->got_headers = TRUE;
803 GST_LOG ("Pushing buffer: ts=%" GST_TIME_FORMAT ", samples=%u, size=%u, "
804 "pos=%" G_GUINT64_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
805 samples, bytes, flacenc->offset);
807 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (flacenc->srcpad));
808 ret = gst_pad_push (flacenc->srcpad, outbuf);
810 if (ret != GST_FLOW_OK)
811 GST_DEBUG_OBJECT (flacenc, "flow: %s", gst_flow_get_name (ret));
813 flacenc->last_flow = ret;
817 flacenc->offset += bytes;
818 flacenc->samples_written += samples;
820 if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED)
821 return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
823 return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
827 static FLAC__SeekableStreamEncoderTellStatus
828 gst_flac_enc_tell_callback (const FLAC__SeekableStreamEncoder * encoder,
829 FLAC__uint64 * absolute_byte_offset, void *client_data)
831 static FLAC__StreamEncoderTellStatus
832 gst_flac_enc_tell_callback (const FLAC__StreamEncoder * encoder,
833 FLAC__uint64 * absolute_byte_offset, void *client_data)
836 GstFlacEnc *flacenc = GST_FLAC_ENC (client_data);
838 *absolute_byte_offset = flacenc->offset;
841 return FLAC__SEEKABLE_STREAM_ENCODER_TELL_STATUS_OK;
843 return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
848 gst_flac_enc_sink_event (GstPad * pad, GstEvent * event)
854 flacenc = GST_FLAC_ENC (gst_pad_get_parent (pad));
856 GST_DEBUG ("Received %s event on sinkpad", GST_EVENT_TYPE_NAME (event));
858 switch (GST_EVENT_TYPE (event)) {
859 case GST_EVENT_NEWSEGMENT:{
861 gint64 start, stream_time;
863 if (flacenc->offset == 0) {
864 gst_event_parse_new_segment (event, NULL, NULL, &format, &start, NULL,
870 if (flacenc->offset > 0)
871 GST_DEBUG ("Not handling mid-stream newsegment event");
873 GST_DEBUG ("Not handling newsegment event with non-zero start");
875 GstEvent *e = gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_BYTES,
878 ret = gst_pad_push_event (flacenc->srcpad, e);
880 if (stream_time != 0) {
881 GST_DEBUG ("Not handling non-zero stream time");
883 gst_event_unref (event);
884 /* don't push it downstream, we'll generate our own via seek to 0 */
889 FLAC__seekable_stream_encoder_finish (flacenc->encoder);
891 FLAC__stream_encoder_finish (flacenc->encoder);
893 ret = gst_pad_event_default (pad, event);
897 gst_event_parse_tag (event, &taglist);
898 gst_tag_list_insert (flacenc->tags, taglist, GST_TAG_MERGE_REPLACE);
900 g_assert_not_reached ();
902 ret = gst_pad_event_default (pad, event);
905 ret = gst_pad_event_default (pad, event);
909 gst_object_unref (flacenc);
915 gst_flac_enc_chain (GstPad * pad, GstBuffer * buffer)
924 flacenc = GST_FLAC_ENC (GST_PAD_PARENT (pad));
926 /* make sure setcaps has been called and the encoder is set up */
927 if (G_UNLIKELY (flacenc->depth == 0))
928 return GST_FLOW_NOT_NEGOTIATED;
930 depth = flacenc->depth;
932 insize = GST_BUFFER_SIZE (buffer);
933 samples = insize / ((depth + 7) >> 3);
935 data = g_malloc (samples * sizeof (FLAC__int32));
938 gint8 *indata = (gint8 *) GST_BUFFER_DATA (buffer);
940 for (i = 0; i < samples; i++)
941 data[i] = (FLAC__int32) indata[i];
942 } else if (depth == 16) {
943 gint16 *indata = (gint16 *) GST_BUFFER_DATA (buffer);
945 for (i = 0; i < samples; i++)
946 data[i] = (FLAC__int32) indata[i];
948 g_assert_not_reached ();
951 gst_buffer_unref (buffer);
954 res = FLAC__seekable_stream_encoder_process_interleaved (flacenc->encoder,
955 (const FLAC__int32 *) data, samples / flacenc->channels);
957 res = FLAC__stream_encoder_process_interleaved (flacenc->encoder,
958 (const FLAC__int32 *) data, samples / flacenc->channels);
964 if (flacenc->last_flow == GST_FLOW_OK)
965 return GST_FLOW_ERROR;
967 return flacenc->last_flow;
974 gst_flac_enc_set_property (GObject * object, guint prop_id,
975 const GValue * value, GParamSpec * pspec)
977 GstFlacEnc *this = GST_FLAC_ENC (object);
979 GST_OBJECT_LOCK (this);
983 gst_flac_enc_update_quality (this, g_value_get_enum (value));
985 case PROP_STREAMABLE_SUBSET:
987 FLAC__seekable_stream_encoder_set_streamable_subset (this->encoder,
988 g_value_get_boolean (value));
990 FLAC__stream_encoder_set_streamable_subset (this->encoder,
991 g_value_get_boolean (value));
994 case PROP_MID_SIDE_STEREO:
996 FLAC__seekable_stream_encoder_set_do_mid_side_stereo (this->encoder,
997 g_value_get_boolean (value));
999 FLAC__stream_encoder_set_do_mid_side_stereo (this->encoder,
1000 g_value_get_boolean (value));
1003 case PROP_LOOSE_MID_SIDE_STEREO:
1005 FLAC__seekable_stream_encoder_set_loose_mid_side_stereo (this->encoder,
1006 g_value_get_boolean (value));
1008 FLAC__stream_encoder_set_loose_mid_side_stereo (this->encoder,
1009 g_value_get_boolean (value));
1012 case PROP_BLOCKSIZE:
1014 FLAC__seekable_stream_encoder_set_blocksize (this->encoder,
1015 g_value_get_uint (value));
1017 FLAC__stream_encoder_set_blocksize (this->encoder,
1018 g_value_get_uint (value));
1021 case PROP_MAX_LPC_ORDER:
1023 FLAC__seekable_stream_encoder_set_max_lpc_order (this->encoder,
1024 g_value_get_uint (value));
1026 FLAC__stream_encoder_set_max_lpc_order (this->encoder,
1027 g_value_get_uint (value));
1030 case PROP_QLP_COEFF_PRECISION:
1032 FLAC__seekable_stream_encoder_set_qlp_coeff_precision (this->encoder,
1033 g_value_get_uint (value));
1035 FLAC__stream_encoder_set_qlp_coeff_precision (this->encoder,
1036 g_value_get_uint (value));
1039 case PROP_QLP_COEFF_PREC_SEARCH:
1041 FLAC__seekable_stream_encoder_set_do_qlp_coeff_prec_search (this->encoder,
1042 g_value_get_boolean (value));
1044 FLAC__stream_encoder_set_do_qlp_coeff_prec_search (this->encoder,
1045 g_value_get_boolean (value));
1048 case PROP_ESCAPE_CODING:
1050 FLAC__seekable_stream_encoder_set_do_escape_coding (this->encoder,
1051 g_value_get_boolean (value));
1053 FLAC__stream_encoder_set_do_escape_coding (this->encoder,
1054 g_value_get_boolean (value));
1057 case PROP_EXHAUSTIVE_MODEL_SEARCH:
1059 FLAC__seekable_stream_encoder_set_do_exhaustive_model_search (this->
1060 encoder, g_value_get_boolean (value));
1062 FLAC__stream_encoder_set_do_exhaustive_model_search (this->
1063 encoder, g_value_get_boolean (value));
1066 case PROP_MIN_RESIDUAL_PARTITION_ORDER:
1068 FLAC__seekable_stream_encoder_set_min_residual_partition_order (this->
1069 encoder, g_value_get_uint (value));
1071 FLAC__stream_encoder_set_min_residual_partition_order (this->
1072 encoder, g_value_get_uint (value));
1075 case PROP_MAX_RESIDUAL_PARTITION_ORDER:
1077 FLAC__seekable_stream_encoder_set_max_residual_partition_order (this->
1078 encoder, g_value_get_uint (value));
1080 FLAC__stream_encoder_set_max_residual_partition_order (this->
1081 encoder, g_value_get_uint (value));
1084 case PROP_RICE_PARAMETER_SEARCH_DIST:
1086 FLAC__seekable_stream_encoder_set_rice_parameter_search_dist (this->
1087 encoder, g_value_get_uint (value));
1089 FLAC__stream_encoder_set_rice_parameter_search_dist (this->
1090 encoder, g_value_get_uint (value));
1094 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1098 GST_OBJECT_UNLOCK (this);
1102 gst_flac_enc_get_property (GObject * object, guint prop_id,
1103 GValue * value, GParamSpec * pspec)
1105 GstFlacEnc *this = GST_FLAC_ENC (object);
1107 GST_OBJECT_LOCK (this);
1111 g_value_set_enum (value, this->quality);
1113 case PROP_STREAMABLE_SUBSET:
1115 g_value_set_boolean (value,
1116 FLAC__seekable_stream_encoder_get_streamable_subset (this->encoder));
1118 g_value_set_boolean (value,
1119 FLAC__stream_encoder_get_streamable_subset (this->encoder));
1122 case PROP_MID_SIDE_STEREO:
1124 g_value_set_boolean (value,
1125 FLAC__seekable_stream_encoder_get_do_mid_side_stereo (this->encoder));
1127 g_value_set_boolean (value,
1128 FLAC__stream_encoder_get_do_mid_side_stereo (this->encoder));
1131 case PROP_LOOSE_MID_SIDE_STEREO:
1133 g_value_set_boolean (value,
1134 FLAC__seekable_stream_encoder_get_loose_mid_side_stereo (this->
1137 g_value_set_boolean (value,
1138 FLAC__stream_encoder_get_loose_mid_side_stereo (this->encoder));
1141 case PROP_BLOCKSIZE:
1143 g_value_set_uint (value,
1144 FLAC__seekable_stream_encoder_get_blocksize (this->encoder));
1146 g_value_set_uint (value,
1147 FLAC__stream_encoder_get_blocksize (this->encoder));
1150 case PROP_MAX_LPC_ORDER:
1152 g_value_set_uint (value,
1153 FLAC__seekable_stream_encoder_get_max_lpc_order (this->encoder));
1155 g_value_set_uint (value,
1156 FLAC__stream_encoder_get_max_lpc_order (this->encoder));
1159 case PROP_QLP_COEFF_PRECISION:
1161 g_value_set_uint (value,
1162 FLAC__seekable_stream_encoder_get_qlp_coeff_precision (this->
1165 g_value_set_uint (value,
1166 FLAC__stream_encoder_get_qlp_coeff_precision (this->encoder));
1169 case PROP_QLP_COEFF_PREC_SEARCH:
1171 g_value_set_boolean (value,
1172 FLAC__seekable_stream_encoder_get_do_qlp_coeff_prec_search (this->
1175 g_value_set_boolean (value,
1176 FLAC__stream_encoder_get_do_qlp_coeff_prec_search (this->encoder));
1179 case PROP_ESCAPE_CODING:
1181 g_value_set_boolean (value,
1182 FLAC__seekable_stream_encoder_get_do_escape_coding (this->encoder));
1184 g_value_set_boolean (value,
1185 FLAC__stream_encoder_get_do_escape_coding (this->encoder));
1188 case PROP_EXHAUSTIVE_MODEL_SEARCH:
1190 g_value_set_boolean (value,
1191 FLAC__seekable_stream_encoder_get_do_exhaustive_model_search (this->
1194 g_value_set_boolean (value,
1195 FLAC__stream_encoder_get_do_exhaustive_model_search (this->encoder));
1198 case PROP_MIN_RESIDUAL_PARTITION_ORDER:
1200 g_value_set_uint (value,
1201 FLAC__seekable_stream_encoder_get_min_residual_partition_order (this->
1204 g_value_set_uint (value,
1205 FLAC__stream_encoder_get_min_residual_partition_order (this->
1209 case PROP_MAX_RESIDUAL_PARTITION_ORDER:
1211 g_value_set_uint (value,
1212 FLAC__seekable_stream_encoder_get_max_residual_partition_order (this->
1215 g_value_set_uint (value,
1216 FLAC__stream_encoder_get_max_residual_partition_order (this->
1220 case PROP_RICE_PARAMETER_SEARCH_DIST:
1222 g_value_set_uint (value,
1223 FLAC__seekable_stream_encoder_get_rice_parameter_search_dist (this->
1226 g_value_set_uint (value,
1227 FLAC__stream_encoder_get_rice_parameter_search_dist (this->encoder));
1231 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1235 GST_OBJECT_UNLOCK (this);
1238 static GstStateChangeReturn
1239 gst_flac_enc_change_state (GstElement * element, GstStateChange transition)
1241 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1242 GstFlacEnc *flacenc = GST_FLAC_ENC (element);
1244 switch (transition) {
1245 case GST_STATE_CHANGE_NULL_TO_READY:
1246 case GST_STATE_CHANGE_READY_TO_PAUSED:
1247 flacenc->stopped = FALSE;
1249 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1254 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1256 switch (transition) {
1257 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1259 case GST_STATE_CHANGE_PAUSED_TO_READY:
1261 if (FLAC__seekable_stream_encoder_get_state (flacenc->encoder) !=
1262 FLAC__STREAM_ENCODER_UNINITIALIZED) {
1263 flacenc->stopped = TRUE;
1264 FLAC__seekable_stream_encoder_finish (flacenc->encoder);
1267 if (FLAC__stream_encoder_get_state (flacenc->encoder) !=
1268 FLAC__STREAM_ENCODER_UNINITIALIZED) {
1269 flacenc->stopped = TRUE;
1270 FLAC__stream_encoder_finish (flacenc->encoder);
1273 flacenc->offset = 0;
1274 flacenc->samples_written = 0;
1275 flacenc->channels = 0;
1277 flacenc->sample_rate = 0;
1278 if (flacenc->meta) {
1279 FLAC__metadata_object_delete (flacenc->meta[0]);
1280 g_free (flacenc->meta);
1281 flacenc->meta = NULL;
1283 g_list_foreach (flacenc->headers, (GFunc) gst_mini_object_unref, NULL);
1284 g_list_free (flacenc->headers);
1285 flacenc->headers = NULL;
1286 flacenc->got_headers = FALSE;
1287 flacenc->last_flow = GST_FLOW_OK;
1289 case GST_STATE_CHANGE_READY_TO_NULL: