3 * Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>.
4 * Copyright (C) 2009 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
5 * Copyright (C) 2009 Nokia Corporation. All rights reserved.
6 * Contact: Stefan Kost <stefan.kost@nokia.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
25 * SECTION:element-flacparse
26 * @see_also: flacdec, oggdemux, vorbisparse
28 * The flacparse element will parse the header packets of the FLAC
29 * stream and put them as the streamheader in the caps. This is used in the
30 * multifdsink case where you want to stream live FLAC streams to multiple
31 * clients, each client has to receive the streamheaders first before they can
32 * consume the FLAC packets.
34 * This element also makes sure that the buffers that it pushes out are properly
35 * timestamped and that their offset and offset_end are set. The buffers that
36 * flacparse outputs have all of the metadata that oggmux expects to receive,
37 * which allows you to (for example) remux an ogg/flac or convert a native FLAC
38 * format file to an ogg bitstream.
41 * <title>Example pipelines</title>
43 * gst-launch -v filesrc location=sine.flac ! flacparse ! identity \
44 * ! oggmux ! filesink location=sine-remuxed.ogg
45 * ]| This pipeline converts a native FLAC format file to an ogg bitstream.
46 * It also illustrates that the streamheader is set in the caps, and that each
47 * buffer has the timestamp, duration, offset, and offset_end set.
56 #include "gstflacparse.h"
59 #include <gst/tag/tag.h>
60 #include <gst/audio/audio.h>
62 #include <gst/base/gstbitreader.h>
63 #include <gst/base/gstbytereader.h>
65 GST_DEBUG_CATEGORY_STATIC (flacparse_debug);
66 #define GST_CAT_DEFAULT flacparse_debug
68 /* CRC-8, poly = x^8 + x^2 + x^1 + x^0, init = 0 */
69 static const guint8 crc8_table[256] = {
70 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
71 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
72 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
73 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
74 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
75 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
76 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
77 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
78 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
79 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
80 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
81 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
82 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
83 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
84 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
85 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
86 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
87 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
88 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
89 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
90 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
91 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
92 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
93 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
94 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
95 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
96 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
97 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
98 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
99 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
100 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
101 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
105 gst_flac_calculate_crc8 (const guint8 * data, guint length)
110 crc = crc8_table[crc ^ *data];
117 /* CRC-16, poly = x^16 + x^15 + x^2 + x^0, init = 0 */
118 static const guint16 crc16_table[256] = {
119 0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011,
120 0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022,
121 0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072,
122 0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041,
123 0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2,
124 0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1,
125 0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1,
126 0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082,
127 0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192,
128 0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1,
129 0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1,
130 0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2,
131 0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151,
132 0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162,
133 0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132,
134 0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101,
135 0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312,
136 0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321,
137 0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371,
138 0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342,
139 0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1,
140 0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2,
141 0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2,
142 0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381,
143 0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291,
144 0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2,
145 0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2,
146 0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1,
147 0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252,
148 0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261,
149 0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231,
150 0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202
154 gst_flac_calculate_crc16 (const guint8 * data, guint length)
159 crc = ((crc << 8) ^ crc16_table[(crc >> 8) ^ *data]) & 0xffff;
169 PROP_CHECK_FRAME_CHECKSUMS
172 #define DEFAULT_CHECK_FRAME_CHECKSUMS FALSE
174 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
177 GST_STATIC_CAPS ("audio/x-flac, framed = (boolean) true, "
178 "channels = (int) [ 1, 8 ], " "rate = (int) [ 1, 655350 ]")
181 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
184 GST_STATIC_CAPS ("audio/x-flac, framed = (boolean) false")
187 static void gst_flac_parse_finalize (GObject * object);
188 static void gst_flac_parse_set_property (GObject * object, guint prop_id,
189 const GValue * value, GParamSpec * pspec);
190 static void gst_flac_parse_get_property (GObject * object, guint prop_id,
191 GValue * value, GParamSpec * pspec);
193 static gboolean gst_flac_parse_start (GstBaseParse * parse);
194 static gboolean gst_flac_parse_stop (GstBaseParse * parse);
195 static gboolean gst_flac_parse_check_valid_frame (GstBaseParse * parse,
196 GstBuffer * buffer, guint * framesize, gint * skipsize);
197 static GstFlowReturn gst_flac_parse_parse_frame (GstBaseParse * parse,
199 static gint gst_flac_parse_get_frame_overhead (GstBaseParse * parse,
201 static GstFlowReturn gst_flac_parse_pre_push_buffer (GstBaseParse * parse,
204 GST_BOILERPLATE (GstFlacParse, gst_flac_parse, GstBaseParse,
205 GST_TYPE_BASE_PARSE);
208 gst_flac_parse_base_init (gpointer g_class)
210 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
212 gst_element_class_add_pad_template (element_class,
213 gst_static_pad_template_get (&src_factory));
214 gst_element_class_add_pad_template (element_class,
215 gst_static_pad_template_get (&sink_factory));
217 gst_element_class_set_details_simple (element_class, "FLAC audio parser",
218 "Codec/Parser/Audio",
219 "Parses audio with the FLAC lossless audio codec",
220 "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
222 GST_DEBUG_CATEGORY_INIT (flacparse_debug, "flacparse", 0,
223 "Flac parser element");
227 gst_flac_parse_class_init (GstFlacParseClass * klass)
229 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
230 GstBaseParseClass *baseparse_class = GST_BASE_PARSE_CLASS (klass);
232 gobject_class->finalize = gst_flac_parse_finalize;
233 gobject_class->set_property = gst_flac_parse_set_property;
234 gobject_class->get_property = gst_flac_parse_get_property;
236 g_object_class_install_property (gobject_class, PROP_CHECK_FRAME_CHECKSUMS,
237 g_param_spec_boolean ("check-frame-checksums", "Check Frame Checksums",
238 "Check the overall checksums of every frame",
239 DEFAULT_CHECK_FRAME_CHECKSUMS,
240 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
242 baseparse_class->start = GST_DEBUG_FUNCPTR (gst_flac_parse_start);
243 baseparse_class->stop = GST_DEBUG_FUNCPTR (gst_flac_parse_stop);
244 baseparse_class->check_valid_frame =
245 GST_DEBUG_FUNCPTR (gst_flac_parse_check_valid_frame);
246 baseparse_class->parse_frame = GST_DEBUG_FUNCPTR (gst_flac_parse_parse_frame);
247 baseparse_class->get_frame_overhead =
248 GST_DEBUG_FUNCPTR (gst_flac_parse_get_frame_overhead);
249 baseparse_class->pre_push_buffer =
250 GST_DEBUG_FUNCPTR (gst_flac_parse_pre_push_buffer);
254 gst_flac_parse_init (GstFlacParse * flacparse, GstFlacParseClass * klass)
256 flacparse->check_frame_checksums = DEFAULT_CHECK_FRAME_CHECKSUMS;
260 gst_flac_parse_set_property (GObject * object, guint prop_id,
261 const GValue * value, GParamSpec * pspec)
263 GstFlacParse *flacparse = GST_FLAC_PARSE (object);
266 case PROP_CHECK_FRAME_CHECKSUMS:
267 flacparse->check_frame_checksums = g_value_get_boolean (value);
270 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
276 gst_flac_parse_get_property (GObject * object, guint prop_id,
277 GValue * value, GParamSpec * pspec)
279 GstFlacParse *flacparse = GST_FLAC_PARSE (object);
282 case PROP_CHECK_FRAME_CHECKSUMS:
283 g_value_set_boolean (value, flacparse->check_frame_checksums);
286 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
292 gst_flac_parse_finalize (GObject * object)
294 GstFlacParse *flacparse = GST_FLAC_PARSE (object);
296 if (flacparse->tags) {
297 gst_tag_list_free (flacparse->tags);
298 flacparse->tags = NULL;
301 g_list_foreach (flacparse->headers, (GFunc) gst_mini_object_unref, NULL);
302 g_list_free (flacparse->headers);
303 flacparse->headers = NULL;
305 G_OBJECT_CLASS (parent_class)->finalize (object);
309 gst_flac_parse_start (GstBaseParse * parse)
311 GstFlacParse *flacparse = GST_FLAC_PARSE (parse);
313 flacparse->state = GST_FLAC_PARSE_STATE_INIT;
314 flacparse->min_blocksize = 0;
315 flacparse->max_blocksize = 0;
316 flacparse->min_framesize = 0;
317 flacparse->max_framesize = 0;
319 flacparse->upstream_length = -1;
321 flacparse->samplerate = 0;
322 flacparse->channels = 0;
324 flacparse->total_samples = 0;
326 flacparse->offset = GST_CLOCK_TIME_NONE;
327 flacparse->blocking_strategy = 0;
328 flacparse->block_size = 0;
329 flacparse->sample_number = 0;
332 gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), 4);
338 gst_flac_parse_stop (GstBaseParse * parse)
340 GstFlacParse *flacparse = GST_FLAC_PARSE (parse);
342 if (flacparse->tags) {
343 gst_tag_list_free (flacparse->tags);
344 flacparse->tags = NULL;
347 g_list_foreach (flacparse->headers, (GFunc) gst_mini_object_unref, NULL);
348 g_list_free (flacparse->headers);
349 flacparse->headers = NULL;
354 static const guint8 sample_size_table[] = { 0, 8, 12, 0, 16, 20, 24, 0 };
356 static const guint16 blocksize_table[16] = {
357 0, 192, 576 << 0, 576 << 1, 576 << 2, 576 << 3, 0, 0,
358 256 << 0, 256 << 1, 256 << 2, 256 << 3, 256 << 4, 256 << 5, 256 << 6,
362 static const guint32 sample_rate_table[16] = {
364 88200, 176400, 192000,
365 8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000,
372 FRAME_HEADER_INVALID,
373 FRAME_HEADER_MORE_DATA
374 } FrameHeaderCheckReturn;
376 static FrameHeaderCheckReturn
377 gst_flac_parse_frame_header_is_valid (GstFlacParse * flacparse,
378 const guint8 * data, guint size, gboolean set, guint16 * block_size_ret)
380 GstBitReader reader = GST_BIT_READER_INIT (data, size);
381 guint8 blocking_strategy;
383 guint32 samplerate = 0;
384 guint64 sample_number;
385 guint8 channels, bps;
387 guint8 actual_crc, expected_crc = 0;
389 /* Skip 14 bit sync code */
390 gst_bit_reader_skip_unchecked (&reader, 14);
393 if (gst_bit_reader_get_bits_uint8_unchecked (&reader, 1) != 0)
396 /* 0 == fixed block size, 1 == variable block size */
397 blocking_strategy = gst_bit_reader_get_bits_uint8_unchecked (&reader, 1);
399 /* block size index, calculation of the real blocksize below */
400 block_size = gst_bit_reader_get_bits_uint16_unchecked (&reader, 4);
404 /* sample rate index, calculation of the real samplerate below */
405 samplerate = gst_bit_reader_get_bits_uint16_unchecked (&reader, 4);
406 if (samplerate == 0x0f)
409 /* channel assignment */
410 channels = gst_bit_reader_get_bits_uint8_unchecked (&reader, 4);
413 } else if (channels <= 10) {
415 } else if (channels > 10) {
418 if (flacparse->channels && flacparse->channels != channels)
421 /* bits per sample */
422 bps = gst_bit_reader_get_bits_uint8_unchecked (&reader, 3);
423 if (bps == 0x03 || bps == 0x07) {
425 } else if (bps == 0 && flacparse->bps == 0) {
426 goto need_streaminfo;
428 bps = sample_size_table[bps];
429 if (flacparse->bps && bps != flacparse->bps)
432 /* reserved, must be 0 */
433 if (gst_bit_reader_get_bits_uint8_unchecked (&reader, 1) != 0)
436 /* read "utf8" encoded sample/frame number */
440 len = gst_bit_reader_get_bits_uint8_unchecked (&reader, 8);
442 /* This is slightly faster than a loop */
446 } else if ((len & 0xc0) && !(len & 0x20)) {
447 sample_number = len & 0x1f;
449 } else if ((len & 0xe0) && !(len & 0x10)) {
450 sample_number = len & 0x0f;
452 } else if ((len & 0xf0) && !(len & 0x08)) {
453 sample_number = len & 0x07;
455 } else if ((len & 0xf8) && !(len & 0x04)) {
456 sample_number = len & 0x03;
458 } else if ((len & 0xfc) && !(len & 0x02)) {
459 sample_number = len & 0x01;
461 } else if ((len & 0xfe) && !(len & 0x01)) {
462 sample_number = len & 0x0;
468 if ((blocking_strategy == 0 && len > 5) ||
469 (blocking_strategy == 1 && len > 6))
473 if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp, 8))
476 if ((tmp & 0xc0) != 0x80)
480 sample_number |= (tmp & 0x3f);
485 /* calculate real blocksize from the blocksize index */
486 if (block_size == 0) {
488 } else if (block_size == 6) {
489 if (!gst_bit_reader_get_bits_uint16 (&reader, &block_size, 8))
492 } else if (block_size == 7) {
493 if (!gst_bit_reader_get_bits_uint16 (&reader, &block_size, 16))
497 block_size = blocksize_table[block_size];
500 /* calculate the real samplerate from the samplerate index */
501 if (samplerate == 0 && flacparse->samplerate == 0) {
502 goto need_streaminfo;
503 } else if (samplerate < 12) {
504 samplerate = sample_rate_table[samplerate];
505 } else if (samplerate == 12) {
506 if (!gst_bit_reader_get_bits_uint32 (&reader, &samplerate, 8))
509 } else if (samplerate == 13) {
510 if (!gst_bit_reader_get_bits_uint32 (&reader, &samplerate, 16))
512 } else if (samplerate == 14) {
513 if (!gst_bit_reader_get_bits_uint32 (&reader, &samplerate, 16))
518 if (flacparse->samplerate && flacparse->samplerate != samplerate)
521 /* check crc-8 for the header */
522 if (!gst_bit_reader_get_bits_uint8 (&reader, &expected_crc, 8))
526 gst_flac_calculate_crc8 (data,
527 (gst_bit_reader_get_pos (&reader) / 8) - 1);
528 if (actual_crc != expected_crc)
532 flacparse->block_size = block_size;
533 if (!flacparse->samplerate)
534 flacparse->samplerate = samplerate;
536 flacparse->bps = bps;
537 if (!flacparse->blocking_strategy)
538 flacparse->blocking_strategy = blocking_strategy;
539 if (!flacparse->channels)
540 flacparse->channels = channels;
541 if (!flacparse->sample_number)
542 flacparse->sample_number = sample_number;
544 GST_DEBUG_OBJECT (flacparse,
545 "Parsed frame at offset %" G_GUINT64_FORMAT ":\n" "Block size: %u\n"
546 "Sample/Frame number: %" G_GUINT64_FORMAT, flacparse->offset,
547 flacparse->block_size, flacparse->sample_number);
551 *block_size_ret = block_size;
553 return FRAME_HEADER_VALID;
556 GST_ERROR_OBJECT (flacparse, "Need STREAMINFO");
557 return FRAME_HEADER_INVALID;
559 return FRAME_HEADER_INVALID;
562 return FRAME_HEADER_MORE_DATA;
566 gst_flac_parse_frame_is_valid (GstFlacParse * flacparse, GstBuffer * buffer,
570 guint max, size, remaining;
571 guint i, search_start, search_end;
572 FrameHeaderCheckReturn header_ret;
575 data = GST_BUFFER_DATA (buffer);
576 size = GST_BUFFER_SIZE (buffer);
578 if (size <= flacparse->min_framesize)
582 gst_flac_parse_frame_header_is_valid (flacparse, data, size, TRUE,
584 if (header_ret == FRAME_HEADER_INVALID) {
587 } else if (header_ret == FRAME_HEADER_MORE_DATA) {
591 /* mind unknown framesize */
592 search_start = MAX (2, flacparse->min_framesize);
593 if (flacparse->max_framesize)
594 search_end = MIN (size, flacparse->max_framesize + 9 + 2);
601 for (i = search_start; i < search_end; i++, remaining--) {
602 if ((GST_READ_UINT16_BE (data + i) & 0xfffe) == 0xfff8) {
604 gst_flac_parse_frame_header_is_valid (flacparse, data + i, remaining,
606 if (header_ret == FRAME_HEADER_VALID) {
607 if (flacparse->check_frame_checksums) {
608 guint16 actual_crc = gst_flac_calculate_crc16 (data, i - 2);
609 guint16 expected_crc = GST_READ_UINT16_BE (data + i - 2);
611 if (actual_crc != expected_crc)
615 flacparse->block_size = block_size;
617 } else if (header_ret == FRAME_HEADER_MORE_DATA) {
623 /* For the last frame output everything to the end */
624 if (G_UNLIKELY (gst_base_parse_get_drain (GST_BASE_PARSE (flacparse)))) {
625 if (flacparse->check_frame_checksums) {
626 guint16 actual_crc = gst_flac_calculate_crc16 (data, size - 2);
627 guint16 expected_crc = GST_READ_UINT16_BE (data + size - 2);
629 if (actual_crc == expected_crc) {
631 flacparse->block_size = block_size;
636 flacparse->block_size = block_size;
642 max = flacparse->max_framesize + 16;
645 *ret = MIN (size + 4096, max);
650 gst_flac_parse_check_valid_frame (GstBaseParse * parse,
651 GstBuffer * buffer, guint * framesize, gint * skipsize)
653 GstFlacParse *flacparse = GST_FLAC_PARSE (parse);
654 const guint8 *data = GST_BUFFER_DATA (buffer);
656 if (G_UNLIKELY (GST_BUFFER_SIZE (buffer) < 4))
659 if (flacparse->state == GST_FLAC_PARSE_STATE_INIT) {
660 if (memcmp (GST_BUFFER_DATA (buffer), "fLaC", 4) == 0) {
661 GST_DEBUG_OBJECT (flacparse, "fLaC marker found");
664 } else if (data[0] == 0xff && (data[1] >> 2) == 0x3e) {
665 GST_DEBUG_OBJECT (flacparse, "Found headerless FLAC");
666 /* Minimal size of a frame header */
667 gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), 9);
668 flacparse->state = GST_FLAC_PARSE_STATE_GENERATE_HEADERS;
672 GST_DEBUG_OBJECT (flacparse, "fLaC marker not found");
675 } else if (flacparse->state == GST_FLAC_PARSE_STATE_HEADERS) {
676 guint size = 4 + ((data[1] << 16) | (data[2] << 8) | (data[3]));
678 GST_DEBUG_OBJECT (flacparse, "Found metadata block of size %u", size);
682 if ((GST_READ_UINT16_BE (data) & 0xfffe) == 0xfff8) {
686 flacparse->offset = GST_BUFFER_OFFSET (buffer);
687 flacparse->blocking_strategy = 0;
688 flacparse->block_size = 0;
689 flacparse->sample_number = 0;
691 GST_DEBUG_OBJECT (flacparse, "Found sync code");
692 ret = gst_flac_parse_frame_is_valid (flacparse, buffer, &next);
697 /* If we're at EOS and the frame was not valid, drop it! */
698 if (G_UNLIKELY (gst_base_parse_get_drain (parse))) {
699 GST_WARNING_OBJECT (flacparse, "EOS");
704 } else if (next > GST_BUFFER_SIZE (buffer)) {
705 GST_DEBUG_OBJECT (flacparse, "Requesting %u bytes", next);
707 gst_base_parse_set_min_frame_size (parse, next);
710 GST_ERROR_OBJECT (flacparse,
711 "Giving up on invalid frame (%d bytes)",
712 GST_BUFFER_SIZE (buffer));
717 GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (buffer);
721 gst_byte_reader_masked_scan_uint32 (&reader, 0xfffc0000, 0xfff80000,
722 0, GST_BUFFER_SIZE (buffer));
725 GST_DEBUG_OBJECT (parse, "Possible sync at buffer offset %d", off);
729 GST_DEBUG_OBJECT (flacparse, "Sync code not found");
730 *skipsize = GST_BUFFER_SIZE (buffer) - 3;
740 gst_flac_parse_handle_streaminfo (GstFlacParse * flacparse, GstBuffer * buffer)
742 GstBitReader reader = GST_BIT_READER_INIT_FROM_BUFFER (buffer);
744 if (GST_BUFFER_SIZE (buffer) != 4 + 34) {
745 GST_ERROR_OBJECT (flacparse, "Invalid metablock size for STREAMINFO: %u",
746 GST_BUFFER_SIZE (buffer));
750 /* Skip metadata block header */
751 gst_bit_reader_skip (&reader, 32);
753 if (!gst_bit_reader_get_bits_uint16 (&reader, &flacparse->min_blocksize, 16))
755 if (flacparse->min_blocksize < 16) {
756 GST_ERROR_OBJECT (flacparse, "Invalid minimum block size: %u",
757 flacparse->min_blocksize);
761 if (!gst_bit_reader_get_bits_uint16 (&reader, &flacparse->max_blocksize, 16))
763 if (flacparse->max_blocksize < 16) {
764 GST_ERROR_OBJECT (flacparse, "Invalid maximum block size: %u",
765 flacparse->max_blocksize);
769 if (!gst_bit_reader_get_bits_uint32 (&reader, &flacparse->min_framesize, 24))
771 if (!gst_bit_reader_get_bits_uint32 (&reader, &flacparse->max_framesize, 24))
774 if (!gst_bit_reader_get_bits_uint32 (&reader, &flacparse->samplerate, 20))
776 if (flacparse->samplerate == 0) {
777 GST_ERROR_OBJECT (flacparse, "Invalid sample rate 0");
781 if (!gst_bit_reader_get_bits_uint8 (&reader, &flacparse->channels, 3))
783 flacparse->channels++;
784 if (flacparse->channels > 8) {
785 GST_ERROR_OBJECT (flacparse, "Invalid number of channels %u",
786 flacparse->channels);
790 if (!gst_bit_reader_get_bits_uint8 (&reader, &flacparse->bps, 5))
794 if (!gst_bit_reader_get_bits_uint64 (&reader, &flacparse->total_samples, 36))
796 if (flacparse->total_samples)
797 gst_base_parse_set_duration (GST_BASE_PARSE (flacparse), GST_FORMAT_TIME,
798 GST_FRAMES_TO_CLOCK_TIME (flacparse->total_samples,
799 flacparse->samplerate), 0);
801 GST_DEBUG_OBJECT (flacparse, "STREAMINFO:\n"
802 "\tmin/max blocksize: %u/%u,\n"
803 "\tmin/max framesize: %u/%u,\n"
804 "\tsamplerate: %u,\n"
806 "\tbits per sample: %u,\n"
807 "\ttotal samples: %" G_GUINT64_FORMAT,
808 flacparse->min_blocksize, flacparse->max_blocksize,
809 flacparse->min_framesize, flacparse->max_framesize,
810 flacparse->samplerate,
811 flacparse->channels, flacparse->bps, flacparse->total_samples);
816 GST_ERROR_OBJECT (flacparse, "Failed to read data");
821 gst_flac_parse_handle_vorbiscomment (GstFlacParse * flacparse,
824 flacparse->tags = gst_tag_list_from_vorbiscomment_buffer (buffer,
825 GST_BUFFER_DATA (buffer), 4, NULL);
827 if (flacparse->tags == NULL) {
828 GST_ERROR_OBJECT (flacparse, "Invalid vorbiscomment block");
829 } else if (gst_tag_list_is_empty (flacparse->tags)) {
830 gst_tag_list_free (flacparse->tags);
831 flacparse->tags = NULL;
838 gst_flac_parse_handle_picture (GstFlacParse * flacparse, GstBuffer * buffer)
840 GstByteReader reader = GST_BYTE_READER_INIT_FROM_BUFFER (buffer);
841 const guint8 *data = GST_BUFFER_DATA (buffer);
842 guint32 img_len = 0, img_type = 0;
843 guint32 img_mimetype_len = 0, img_description_len = 0;
845 if (!gst_byte_reader_skip (&reader, 4))
848 if (!gst_byte_reader_get_uint32_be (&reader, &img_type))
851 if (!gst_byte_reader_get_uint32_be (&reader, &img_mimetype_len))
853 if (!gst_byte_reader_skip (&reader, img_mimetype_len))
856 if (!gst_byte_reader_get_uint32_be (&reader, &img_description_len))
858 if (!gst_byte_reader_skip (&reader, img_description_len))
861 if (!gst_byte_reader_skip (&reader, 4 * 4))
864 if (!gst_byte_reader_get_uint32_be (&reader, &img_len))
867 if (!flacparse->tags)
868 flacparse->tags = gst_tag_list_new ();
870 gst_tag_list_add_id3_image (flacparse->tags,
871 data + gst_byte_reader_get_pos (&reader), img_len, img_type);
873 if (gst_tag_list_is_empty (flacparse->tags)) {
874 gst_tag_list_free (flacparse->tags);
875 flacparse->tags = NULL;
881 GST_ERROR_OBJECT (flacparse, "Error reading data");
886 _value_array_append_buffer (GValue * array_val, GstBuffer * buf)
888 GValue value = { 0, };
890 g_value_init (&value, GST_TYPE_BUFFER);
891 /* copy buffer to avoid problems with circular refcounts */
892 buf = gst_buffer_copy (buf);
893 /* again, for good measure */
894 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
895 gst_value_set_buffer (&value, buf);
896 gst_buffer_unref (buf);
897 gst_value_array_append_value (array_val, &value);
898 g_value_unset (&value);
902 gst_flac_parse_handle_headers (GstFlacParse * flacparse)
904 GstBuffer *vorbiscomment = NULL;
905 GstBuffer *streaminfo = NULL;
906 GstBuffer *marker = NULL;
907 GValue array = { 0, };
911 caps = gst_caps_new_simple ("audio/x-flac",
912 "channels", G_TYPE_INT, flacparse->channels,
913 "framed", G_TYPE_BOOLEAN, TRUE,
914 "rate", G_TYPE_INT, flacparse->samplerate, NULL);
916 if (!flacparse->headers)
919 for (l = flacparse->headers; l; l = l->next) {
920 GstBuffer *header = l->data;
921 const guint8 *data = GST_BUFFER_DATA (header);
922 guint size = GST_BUFFER_SIZE (header);
924 GST_BUFFER_FLAG_SET (header, GST_BUFFER_FLAG_IN_CAPS);
926 if (size == 4 && memcmp (data, "fLaC", 4) == 0) {
928 } else if (size > 1 && (data[0] & 0x7f) == 0) {
930 } else if (size > 1 && (data[0] & 0x7f) == 4) {
931 vorbiscomment = header;
935 if (marker == NULL || streaminfo == NULL || vorbiscomment == NULL) {
936 GST_WARNING_OBJECT (flacparse,
937 "missing header %p %p %p, muxing into container "
938 "formats may be broken", marker, streaminfo, vorbiscomment);
942 g_value_init (&array, GST_TYPE_ARRAY);
944 /* add marker including STREAMINFO header */
949 /* minus one for the marker that is merged with streaminfo here */
950 num = g_list_length (flacparse->headers) - 1;
952 buf = gst_buffer_new_and_alloc (13 + GST_BUFFER_SIZE (streaminfo));
953 GST_BUFFER_DATA (buf)[0] = 0x7f;
954 memcpy (GST_BUFFER_DATA (buf) + 1, "FLAC", 4);
955 GST_BUFFER_DATA (buf)[5] = 0x01; /* mapping version major */
956 GST_BUFFER_DATA (buf)[6] = 0x00; /* mapping version minor */
957 GST_BUFFER_DATA (buf)[7] = (num & 0xFF00) >> 8;
958 GST_BUFFER_DATA (buf)[8] = (num & 0x00FF) >> 0;
959 memcpy (GST_BUFFER_DATA (buf) + 9, "fLaC", 4);
960 memcpy (GST_BUFFER_DATA (buf) + 13, GST_BUFFER_DATA (streaminfo),
961 GST_BUFFER_SIZE (streaminfo));
962 _value_array_append_buffer (&array, buf);
963 gst_buffer_unref (buf);
966 /* add VORBISCOMMENT header */
967 _value_array_append_buffer (&array, vorbiscomment);
969 /* add other headers, if there are any */
970 for (l = flacparse->headers; l; l = l->next) {
971 if (GST_BUFFER_CAST (l->data) != marker &&
972 GST_BUFFER_CAST (l->data) != streaminfo &&
973 GST_BUFFER_CAST (l->data) != vorbiscomment) {
974 _value_array_append_buffer (&array, GST_BUFFER_CAST (l->data));
978 gst_structure_set_value (gst_caps_get_structure (caps, 0),
979 "streamheader", &array);
980 g_value_unset (&array);
984 gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (GST_BASE_PARSE (flacparse)), caps);
985 gst_caps_unref (caps);
987 /* push header buffers; update caps, so when we push the first buffer the
988 * negotiated caps will change to caps that include the streamheader field */
989 for (l = flacparse->headers; l != NULL; l = l->next) {
990 GstBuffer *buf = GST_BUFFER (l->data);
994 buf = gst_buffer_make_metadata_writable (buf);
995 gst_buffer_set_caps (buf,
996 GST_PAD_CAPS (GST_BASE_PARSE_SRC_PAD (GST_BASE_PARSE (flacparse))));
998 ret = gst_base_parse_push_buffer (GST_BASE_PARSE (flacparse), buf);
999 if (ret != GST_FLOW_OK)
1002 g_list_free (flacparse->headers);
1003 flacparse->headers = NULL;
1009 gst_flac_parse_generate_headers (GstFlacParse * flacparse)
1011 GstBuffer *marker, *streaminfo, *vorbiscomment;
1014 marker = gst_buffer_new_and_alloc (4);
1015 memcpy (GST_BUFFER_DATA (marker), "fLaC", 4);
1016 GST_BUFFER_TIMESTAMP (marker) = GST_CLOCK_TIME_NONE;
1017 GST_BUFFER_DURATION (marker) = GST_CLOCK_TIME_NONE;
1018 GST_BUFFER_OFFSET (marker) = 0;
1019 GST_BUFFER_OFFSET_END (marker) = 0;
1020 flacparse->headers = g_list_append (flacparse->headers, marker);
1022 streaminfo = gst_buffer_new_and_alloc (4 + 34);
1023 data = GST_BUFFER_DATA (streaminfo);
1024 memset (data, 0, 4 + 34);
1026 /* metadata block header */
1027 data[0] = 0x00; /* is_last = 0; type = 0; */
1028 data[1] = 0x00; /* length = 34; */
1034 data[4] = (flacparse->block_size >> 8) & 0xff; /* min blocksize = blocksize; */
1035 data[5] = (flacparse->block_size) & 0xff;
1036 data[6] = (flacparse->block_size >> 8) & 0xff; /* max blocksize = blocksize; */
1037 data[7] = (flacparse->block_size) & 0xff;
1039 data[8] = 0x00; /* min framesize = 0; */
1042 data[11] = 0x00; /* max framesize = 0; */
1046 data[14] = (flacparse->samplerate >> 12) & 0xff;
1047 data[15] = (flacparse->samplerate >> 4) & 0xff;
1048 data[16] = (flacparse->samplerate >> 0) & 0xf0;
1050 data[16] |= (flacparse->channels - 1) << 1;
1052 data[16] |= ((flacparse->bps - 1) >> 4) & 0x01;
1053 data[17] = (((flacparse->bps - 1)) & 0x0f) << 4;
1057 GstFormat fmt = GST_FORMAT_TIME;
1059 if (gst_pad_query_peer_duration (GST_BASE_PARSE_SINK_PAD (GST_BASE_PARSE
1060 (flacparse)), &fmt, &duration) && fmt == GST_FORMAT_TIME) {
1061 duration = GST_CLOCK_TIME_TO_FRAMES (duration, flacparse->samplerate);
1063 data[17] |= (duration >> 32) & 0xff;
1064 data[18] |= (duration >> 24) & 0xff;
1065 data[19] |= (duration >> 16) & 0xff;
1066 data[20] |= (duration >> 8) & 0xff;
1067 data[21] |= (duration >> 0) & 0xff;
1072 GST_BUFFER_TIMESTAMP (streaminfo) = GST_CLOCK_TIME_NONE;
1073 GST_BUFFER_DURATION (streaminfo) = GST_CLOCK_TIME_NONE;
1074 GST_BUFFER_OFFSET (streaminfo) = 0;
1075 GST_BUFFER_OFFSET_END (streaminfo) = 0;
1076 flacparse->headers = g_list_append (flacparse->headers, streaminfo);
1078 /* empty vorbiscomment */
1080 GstTagList *taglist = gst_tag_list_new ();
1084 header[0] = 0x84; /* is_last = 1; type = 4; */
1087 gst_tag_list_to_vorbiscomment_buffer (taglist, header,
1088 sizeof (header), NULL);
1089 gst_tag_list_free (taglist);
1091 /* Get rid of framing bit */
1092 if (GST_BUFFER_DATA (vorbiscomment)[GST_BUFFER_SIZE (vorbiscomment) -
1097 gst_buffer_create_sub (vorbiscomment, 0,
1098 GST_BUFFER_SIZE (vorbiscomment) - 1);
1099 gst_buffer_unref (vorbiscomment);
1100 vorbiscomment = sub;
1103 size = GST_BUFFER_SIZE (vorbiscomment) - 4;
1104 GST_BUFFER_DATA (vorbiscomment)[1] = ((size & 0xFF0000) >> 16);
1105 GST_BUFFER_DATA (vorbiscomment)[2] = ((size & 0x00FF00) >> 8);
1106 GST_BUFFER_DATA (vorbiscomment)[3] = (size & 0x0000FF);
1108 GST_BUFFER_TIMESTAMP (vorbiscomment) = GST_CLOCK_TIME_NONE;
1109 GST_BUFFER_DURATION (vorbiscomment) = GST_CLOCK_TIME_NONE;
1110 GST_BUFFER_OFFSET (vorbiscomment) = 0;
1111 GST_BUFFER_OFFSET_END (vorbiscomment) = 0;
1112 flacparse->headers = g_list_append (flacparse->headers, vorbiscomment);
1118 static GstFlowReturn
1119 gst_flac_parse_parse_frame (GstBaseParse * parse, GstBuffer * buffer)
1121 GstFlacParse *flacparse = GST_FLAC_PARSE (parse);
1122 const guint8 *data = GST_BUFFER_DATA (buffer);
1124 if (flacparse->state == GST_FLAC_PARSE_STATE_INIT) {
1125 GST_BUFFER_TIMESTAMP (buffer) = GST_CLOCK_TIME_NONE;
1126 GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
1127 GST_BUFFER_OFFSET (buffer) = 0;
1128 GST_BUFFER_OFFSET_END (buffer) = 0;
1130 /* 32 bits metadata block */
1131 gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), 4);
1132 flacparse->state = GST_FLAC_PARSE_STATE_HEADERS;
1134 flacparse->headers =
1135 g_list_append (flacparse->headers, gst_buffer_ref (buffer));
1137 return GST_BASE_PARSE_FLOW_DROPPED;
1138 } else if (flacparse->state == GST_FLAC_PARSE_STATE_HEADERS) {
1139 gboolean is_last = ((data[0] & 0x80) == 0x80);
1140 guint type = (data[0] & 0x7F);
1143 GST_WARNING_OBJECT (flacparse, "Invalid metadata block type");
1144 return GST_BASE_PARSE_FLOW_DROPPED;
1147 GST_DEBUG_OBJECT (flacparse, "Handling metadata block of type %u", type);
1150 case 0: /* STREAMINFO */
1151 if (!gst_flac_parse_handle_streaminfo (flacparse, buffer))
1152 return GST_FLOW_ERROR;
1154 case 3: /* SEEKTABLE */
1155 /* TODO: handle seektables */
1157 case 4: /* VORBIS_COMMENT */
1158 if (!gst_flac_parse_handle_vorbiscomment (flacparse, buffer))
1159 return GST_FLOW_ERROR;
1161 case 6: /* PICTURE */
1162 if (!gst_flac_parse_handle_picture (flacparse, buffer))
1163 return GST_FLOW_ERROR;
1165 case 1: /* PADDING */
1166 case 2: /* APPLICATION */
1167 case 5: /* CUESHEET */
1168 default: /* RESERVED */
1172 GST_BUFFER_TIMESTAMP (buffer) = GST_CLOCK_TIME_NONE;
1173 GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
1174 GST_BUFFER_OFFSET (buffer) = 0;
1175 GST_BUFFER_OFFSET_END (buffer) = 0;
1178 flacparse->headers =
1179 g_list_append (flacparse->headers, gst_buffer_ref (buffer));
1181 if (!gst_flac_parse_handle_headers (flacparse))
1182 return GST_FLOW_ERROR;
1184 /* Minimal size of a frame header */
1185 gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), MAX (9,
1186 flacparse->min_framesize));
1187 flacparse->state = GST_FLAC_PARSE_STATE_DATA;
1189 /* DROPPED because we pushed all headers manually already */
1190 return GST_BASE_PARSE_FLOW_DROPPED;
1192 flacparse->headers =
1193 g_list_append (flacparse->headers, gst_buffer_ref (buffer));
1194 return GST_BASE_PARSE_FLOW_DROPPED;
1197 if (flacparse->offset != GST_BUFFER_OFFSET (buffer)) {
1198 FrameHeaderCheckReturn ret;
1200 flacparse->offset = GST_BUFFER_OFFSET (buffer);
1202 gst_flac_parse_frame_header_is_valid (flacparse,
1203 GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), TRUE, NULL);
1204 if (ret != FRAME_HEADER_VALID) {
1205 GST_ERROR_OBJECT (flacparse,
1206 "Baseclass didn't provide a complete frame");
1207 return GST_FLOW_ERROR;
1211 if (flacparse->block_size == 0) {
1212 GST_ERROR_OBJECT (flacparse, "Unparsed frame");
1213 return GST_FLOW_ERROR;
1216 if (flacparse->state == GST_FLAC_PARSE_STATE_GENERATE_HEADERS) {
1217 if (flacparse->blocking_strategy == 1) {
1218 GST_WARNING_OBJECT (flacparse,
1219 "Generating headers for variable blocksize streams not supported");
1221 if (!gst_flac_parse_handle_headers (flacparse))
1222 return GST_FLOW_ERROR;
1224 GST_DEBUG_OBJECT (flacparse, "Generating headers");
1226 if (!gst_flac_parse_generate_headers (flacparse))
1227 return GST_FLOW_ERROR;
1229 if (!gst_flac_parse_handle_headers (flacparse))
1230 return GST_FLOW_ERROR;
1232 flacparse->state = GST_FLAC_PARSE_STATE_DATA;
1235 /* also cater for oggmux metadata */
1236 if (flacparse->blocking_strategy == 0) {
1237 GST_BUFFER_TIMESTAMP (buffer) =
1238 gst_util_uint64_scale (flacparse->sample_number,
1239 flacparse->block_size * GST_SECOND, flacparse->samplerate);
1240 GST_BUFFER_OFFSET_END (buffer) =
1241 flacparse->sample_number * flacparse->block_size +
1242 flacparse->block_size;
1244 GST_BUFFER_TIMESTAMP (buffer) =
1245 gst_util_uint64_scale (flacparse->sample_number, GST_SECOND,
1246 flacparse->samplerate);
1247 GST_BUFFER_OFFSET_END (buffer) =
1248 flacparse->sample_number + flacparse->block_size;
1250 GST_BUFFER_DURATION (buffer) =
1251 GST_FRAMES_TO_CLOCK_TIME (flacparse->block_size, flacparse->samplerate);
1252 GST_BUFFER_OFFSET (buffer) =
1253 GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer);
1255 /* Minimal size of a frame header */
1256 gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), MAX (9,
1257 flacparse->min_framesize));
1259 flacparse->offset = -1;
1260 flacparse->blocking_strategy = 0;
1261 flacparse->block_size = 0;
1262 flacparse->sample_number = 0;
1268 gst_flac_parse_get_frame_overhead (GstBaseParse * parse, GstBuffer * buffer)
1270 GstFlacParse *flacparse = GST_FLAC_PARSE (parse);
1272 if (flacparse->state != GST_FLAC_PARSE_STATE_DATA)
1275 /* To simplify, we just assume that it's a fixed size header and ignore
1276 * subframe headers. The first could lead us to being off by 88 bits and
1277 * the second even less, so the total inaccuracy is negligible. */
1281 static GstFlowReturn
1282 gst_flac_parse_pre_push_buffer (GstBaseParse * parse, GstBuffer * buf)
1284 GstFlacParse *flacparse = GST_FLAC_PARSE (parse);
1287 if (flacparse->tags) {
1288 gst_element_found_tags (GST_ELEMENT (flacparse), flacparse->tags);
1289 flacparse->tags = NULL;