• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  *
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>
7  *
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.
12  *
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.
17  *
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., 51 Franklin St, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23 
24 /**
25  * SECTION:element-flacparse
26  * @title: flacparse
27  * @see_also: flacdec, oggdemux, vorbisparse
28  *
29  * The flacparse element will parse the header packets of the FLAC
30  * stream and put them as the streamheader in the caps. This is used in the
31  * multifdsink case where you want to stream live FLAC streams to multiple
32  * clients, each client has to receive the streamheaders first before they can
33  * consume the FLAC packets.
34  *
35  * This element also makes sure that the buffers that it pushes out are properly
36  * timestamped and that their offset and offset_end are set. The buffers that
37  * flacparse outputs have all of the metadata that oggmux expects to receive,
38  * which allows you to (for example) remux an ogg/flac or convert a native FLAC
39  * format file to an ogg bitstream.
40  *
41  * ## Example pipelines
42  * |[
43  * gst-launch-1.0 -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.
48  *
49  */
50 
51 #ifdef HAVE_CONFIG_H
52 #include "config.h"
53 #endif
54 
55 #include "gstaudioparserselements.h"
56 #include "gstflacparse.h"
57 
58 #include <string.h>
59 #include <gst/tag/tag.h>
60 #include <gst/audio/audio.h>
61 #include <gst/base/base.h>
62 #include <gst/pbutils/pbutils.h>
63 
64 GST_DEBUG_CATEGORY_STATIC (flacparse_debug);
65 #define GST_CAT_DEFAULT flacparse_debug
66 
67 /* CRC-8, poly = x^8 + x^2 + x^1 + x^0, init = 0 */
68 static const guint8 crc8_table[256] = {
69   0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
70   0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
71   0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
72   0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
73   0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
74   0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
75   0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
76   0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
77   0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
78   0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
79   0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
80   0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
81   0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
82   0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
83   0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
84   0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
85   0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
86   0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
87   0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
88   0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
89   0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
90   0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
91   0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
92   0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
93   0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
94   0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
95   0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
96   0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
97   0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
98   0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
99   0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
100   0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
101 };
102 
103 static guint8
gst_flac_calculate_crc8(const guint8 * data,guint length)104 gst_flac_calculate_crc8 (const guint8 * data, guint length)
105 {
106   guint8 crc = 0;
107 
108   while (length--) {
109     crc = crc8_table[crc ^ *data];
110     ++data;
111   }
112 
113   return crc;
114 }
115 
116 /* CRC-16, poly = x^16 + x^15 + x^2 + x^0, init = 0 */
117 static const guint16 crc16_table[256] = {
118   0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011,
119   0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022,
120   0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072,
121   0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041,
122   0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2,
123   0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1,
124   0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1,
125   0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082,
126   0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192,
127   0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1,
128   0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1,
129   0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2,
130   0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151,
131   0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162,
132   0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132,
133   0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101,
134   0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312,
135   0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321,
136   0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371,
137   0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342,
138   0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1,
139   0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2,
140   0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2,
141   0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381,
142   0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291,
143   0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2,
144   0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2,
145   0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1,
146   0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252,
147   0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261,
148   0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231,
149   0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202
150 };
151 
152 static guint16
gst_flac_calculate_crc16(const guint8 * data,guint length)153 gst_flac_calculate_crc16 (const guint8 * data, guint length)
154 {
155   guint16 crc = 0;
156 
157   while (length--) {
158     crc = ((crc << 8) ^ crc16_table[(crc >> 8) ^ *data]) & 0xffff;
159     data++;
160   }
161 
162   return crc;
163 }
164 
165 enum
166 {
167   PROP_0,
168   PROP_CHECK_FRAME_CHECKSUMS
169 };
170 
171 #define DEFAULT_CHECK_FRAME_CHECKSUMS FALSE
172 
173 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
174     GST_PAD_SRC,
175     GST_PAD_ALWAYS,
176     GST_STATIC_CAPS ("audio/x-flac, framed = (boolean) true, "
177         "channels = (int) [ 1, 8 ], " "rate = (int) [ 1, 655350 ]")
178     );
179 
180 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
181     GST_PAD_SINK,
182     GST_PAD_ALWAYS,
183     GST_STATIC_CAPS ("audio/x-flac")
184     );
185 
186 static GstBuffer *gst_flac_parse_generate_vorbiscomment (GstFlacParse *
187     flacparse, gboolean is_last);
188 
189 static inline void gst_flac_parse_reset_buffer_time_and_offset (GstBuffer *
190     buffer);
191 static void gst_flac_parse_reset (GstFlacParse * parser);
192 static gboolean gst_flac_parse_handle_block_type (GstFlacParse * flacparse,
193     guint type, GstBuffer * sbuffer);
194 static void gst_flac_parse_finalize (GObject * object);
195 static void gst_flac_parse_set_property (GObject * object, guint prop_id,
196     const GValue * value, GParamSpec * pspec);
197 static void gst_flac_parse_get_property (GObject * object, guint prop_id,
198     GValue * value, GParamSpec * pspec);
199 
200 static gboolean gst_flac_parse_start (GstBaseParse * parse);
201 static gboolean gst_flac_parse_stop (GstBaseParse * parse);
202 static GstFlowReturn gst_flac_parse_handle_frame (GstBaseParse * parse,
203     GstBaseParseFrame * frame, gint * skipsize);
204 static GstFlowReturn gst_flac_parse_parse_frame (GstBaseParse * parse,
205     GstBaseParseFrame * frame, gint size);
206 static GstFlowReturn gst_flac_parse_pre_push_frame (GstBaseParse * parse,
207     GstBaseParseFrame * frame);
208 static gboolean gst_flac_parse_convert (GstBaseParse * parse,
209     GstFormat src_format, gint64 src_value, GstFormat dest_format,
210     gint64 * dest_value);
211 static gboolean gst_flac_parse_src_event (GstBaseParse * parse,
212     GstEvent * event);
213 static GstCaps *gst_flac_parse_get_sink_caps (GstBaseParse * parse,
214     GstCaps * filter);
215 static gboolean gst_flac_parse_set_sink_caps (GstBaseParse * parse,
216     GstCaps * caps);
217 
218 #define gst_flac_parse_parent_class parent_class
219 G_DEFINE_TYPE (GstFlacParse, gst_flac_parse, GST_TYPE_BASE_PARSE);
220 GST_ELEMENT_REGISTER_DEFINE (flacparse, "flacparse",
221     GST_RANK_PRIMARY + 1, GST_TYPE_FLAC_PARSE);
222 
223 static void
gst_flac_parse_class_init(GstFlacParseClass * klass)224 gst_flac_parse_class_init (GstFlacParseClass * klass)
225 {
226   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
227   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
228   GstBaseParseClass *baseparse_class = GST_BASE_PARSE_CLASS (klass);
229 
230   GST_DEBUG_CATEGORY_INIT (flacparse_debug, "flacparse", 0,
231       "Flac parser element");
232 
233   gobject_class->finalize = gst_flac_parse_finalize;
234   gobject_class->set_property = gst_flac_parse_set_property;
235   gobject_class->get_property = gst_flac_parse_get_property;
236 
237   g_object_class_install_property (gobject_class, PROP_CHECK_FRAME_CHECKSUMS,
238       g_param_spec_boolean ("check-frame-checksums", "Check Frame Checksums",
239           "Check the overall checksums of every frame",
240           DEFAULT_CHECK_FRAME_CHECKSUMS,
241           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
242 
243   baseparse_class->start = GST_DEBUG_FUNCPTR (gst_flac_parse_start);
244   baseparse_class->stop = GST_DEBUG_FUNCPTR (gst_flac_parse_stop);
245   baseparse_class->handle_frame =
246       GST_DEBUG_FUNCPTR (gst_flac_parse_handle_frame);
247   baseparse_class->pre_push_frame =
248       GST_DEBUG_FUNCPTR (gst_flac_parse_pre_push_frame);
249   baseparse_class->convert = GST_DEBUG_FUNCPTR (gst_flac_parse_convert);
250   baseparse_class->src_event = GST_DEBUG_FUNCPTR (gst_flac_parse_src_event);
251   baseparse_class->get_sink_caps =
252       GST_DEBUG_FUNCPTR (gst_flac_parse_get_sink_caps);
253   baseparse_class->set_sink_caps =
254       GST_DEBUG_FUNCPTR (gst_flac_parse_set_sink_caps);
255 
256   gst_element_class_add_static_pad_template (element_class, &src_factory);
257   gst_element_class_add_static_pad_template (element_class, &sink_factory);
258 
259   gst_element_class_set_static_metadata (element_class, "FLAC audio parser",
260       "Codec/Parser/Audio",
261       "Parses audio with the FLAC lossless audio codec",
262       "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
263 }
264 
265 static void
gst_flac_parse_init(GstFlacParse * flacparse)266 gst_flac_parse_init (GstFlacParse * flacparse)
267 {
268   flacparse->check_frame_checksums = DEFAULT_CHECK_FRAME_CHECKSUMS;
269   GST_PAD_SET_ACCEPT_INTERSECT (GST_BASE_PARSE_SINK_PAD (flacparse));
270   GST_PAD_SET_ACCEPT_TEMPLATE (GST_BASE_PARSE_SINK_PAD (flacparse));
271 }
272 
273 static void
gst_flac_parse_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)274 gst_flac_parse_set_property (GObject * object, guint prop_id,
275     const GValue * value, GParamSpec * pspec)
276 {
277   GstFlacParse *flacparse = GST_FLAC_PARSE (object);
278 
279   switch (prop_id) {
280     case PROP_CHECK_FRAME_CHECKSUMS:
281       flacparse->check_frame_checksums = g_value_get_boolean (value);
282       break;
283     default:
284       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
285       break;
286   }
287 }
288 
289 static void
gst_flac_parse_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)290 gst_flac_parse_get_property (GObject * object, guint prop_id,
291     GValue * value, GParamSpec * pspec)
292 {
293   GstFlacParse *flacparse = GST_FLAC_PARSE (object);
294 
295   switch (prop_id) {
296     case PROP_CHECK_FRAME_CHECKSUMS:
297       g_value_set_boolean (value, flacparse->check_frame_checksums);
298       break;
299     default:
300       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
301       break;
302   }
303 }
304 
305 static void
gst_flac_parse_reset(GstFlacParse * parser)306 gst_flac_parse_reset (GstFlacParse * parser)
307 {
308   if (parser->tags) {
309     gst_tag_list_unref (parser->tags);
310     parser->tags = NULL;
311   }
312   if (parser->toc) {
313     gst_toc_unref (parser->toc);
314     parser->toc = NULL;
315   }
316   if (parser->seektable) {
317     gst_buffer_unref (parser->seektable);
318     parser->seektable = NULL;
319   }
320 
321   g_list_foreach (parser->headers, (GFunc) gst_mini_object_unref, NULL);
322   g_list_free (parser->headers);
323   parser->headers = NULL;
324 }
325 
326 static void
gst_flac_parse_finalize(GObject * object)327 gst_flac_parse_finalize (GObject * object)
328 {
329   GstFlacParse *flacparse = GST_FLAC_PARSE (object);
330 
331   gst_flac_parse_reset (flacparse);
332   G_OBJECT_CLASS (parent_class)->finalize (object);
333 }
334 
335 static gboolean
gst_flac_parse_start(GstBaseParse * parse)336 gst_flac_parse_start (GstBaseParse * parse)
337 {
338   GstFlacParse *flacparse = GST_FLAC_PARSE (parse);
339 
340   flacparse->state = GST_FLAC_PARSE_STATE_INIT;
341   flacparse->min_blocksize = 0;
342   flacparse->max_blocksize = 0;
343   flacparse->min_framesize = 0;
344   flacparse->max_framesize = 0;
345 
346   flacparse->upstream_length = -1;
347 
348   flacparse->samplerate = 0;
349   flacparse->channels = 0;
350   flacparse->bps = 0;
351   flacparse->total_samples = 0;
352 
353   flacparse->offset = GST_CLOCK_TIME_NONE;
354   flacparse->blocking_strategy = 0;
355   flacparse->block_size = 0;
356   flacparse->sample_number = 0;
357   flacparse->strategy_checked = FALSE;
358 
359   flacparse->sent_codec_tag = FALSE;
360 
361   /* "fLaC" marker */
362   gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), 4);
363 
364   /* inform baseclass we can come up with ts, based on counters in packets */
365   gst_base_parse_set_has_timing_info (GST_BASE_PARSE_CAST (flacparse), TRUE);
366   gst_base_parse_set_syncable (GST_BASE_PARSE_CAST (flacparse), TRUE);
367 
368   return TRUE;
369 }
370 
371 static gboolean
gst_flac_parse_stop(GstBaseParse * parse)372 gst_flac_parse_stop (GstBaseParse * parse)
373 {
374   GstFlacParse *flacparse = GST_FLAC_PARSE (parse);
375 
376   gst_flac_parse_reset (flacparse);
377   return TRUE;
378 }
379 
380 static const guint8 sample_size_table[] = { 0, 8, 12, 0, 16, 20, 24, 0 };
381 
382 static const guint16 blocksize_table[16] = {
383   0, 192, 576 << 0, 576 << 1, 576 << 2, 576 << 3, 0, 0,
384   256 << 0, 256 << 1, 256 << 2, 256 << 3, 256 << 4, 256 << 5, 256 << 6,
385   256 << 7,
386 };
387 
388 static const guint32 sample_rate_table[16] = {
389   0,
390   88200, 176400, 192000,
391   8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000,
392   0, 0, 0, 0,
393 };
394 
395 typedef enum
396 {
397   FRAME_HEADER_VALID,
398   FRAME_HEADER_INVALID,
399   FRAME_HEADER_MORE_DATA
400 } FrameHeaderCheckReturn;
401 
402 static FrameHeaderCheckReturn
gst_flac_parse_frame_header_is_valid(GstFlacParse * flacparse,const guint8 * data,guint size,gboolean set,guint16 * block_size_ret,gboolean * suspect)403 gst_flac_parse_frame_header_is_valid (GstFlacParse * flacparse,
404     const guint8 * data, guint size, gboolean set, guint16 * block_size_ret,
405     gboolean * suspect)
406 {
407   GstBitReader reader = GST_BIT_READER_INIT (data, size);
408   guint8 blocking_strategy;
409   guint16 block_size;
410   guint32 samplerate = 0;
411   guint64 sample_number;
412   guint8 channels, bps;
413   guint8 tmp = 0;
414   guint8 actual_crc, expected_crc = 0;
415 
416   /* Skip 14 bit sync code */
417   gst_bit_reader_skip_unchecked (&reader, 14);
418 
419   /* Must be 0 */
420   if (gst_bit_reader_get_bits_uint8_unchecked (&reader, 1) != 0)
421     goto error;
422 
423   /* 0 == fixed block size, 1 == variable block size */
424   blocking_strategy = gst_bit_reader_get_bits_uint8_unchecked (&reader, 1);
425   if (flacparse->force_variable_block_size)
426     blocking_strategy = 1;
427 
428   /* block size index, calculation of the real blocksize below */
429   block_size = gst_bit_reader_get_bits_uint16_unchecked (&reader, 4);
430   if (block_size == 0)
431     goto error;
432 
433   /* sample rate index, calculation of the real samplerate below */
434   samplerate = gst_bit_reader_get_bits_uint16_unchecked (&reader, 4);
435   if (samplerate == 0x0f)
436     goto error;
437 
438   /* channel assignment */
439   channels = gst_bit_reader_get_bits_uint8_unchecked (&reader, 4);
440   if (channels < 8) {
441     channels++;
442   } else if (channels <= 10) {
443     channels = 2;
444   } else if (channels > 10) {
445     goto error;
446   }
447   if (flacparse->channels && flacparse->channels != channels)
448     goto error;
449 
450   /* bits per sample */
451   bps = gst_bit_reader_get_bits_uint8_unchecked (&reader, 3);
452   if (bps == 0x03 || bps == 0x07) {
453     goto error;
454   } else if (bps == 0 && flacparse->bps == 0) {
455     goto need_streaminfo;
456   }
457   bps = sample_size_table[bps];
458   if (flacparse->bps && bps != flacparse->bps)
459     goto error;
460 
461   /* reserved, must be 0 */
462   if (gst_bit_reader_get_bits_uint8_unchecked (&reader, 1) != 0)
463     goto error;
464 
465   /* read "utf8" encoded sample/frame number */
466   {
467     gint len = 0;
468 
469     len = gst_bit_reader_get_bits_uint8_unchecked (&reader, 8);
470 
471     /* This is slightly faster than a loop */
472     if (!(len & 0x80)) {
473       sample_number = len;
474       len = 0;
475     } else if ((len & 0xc0) && !(len & 0x20)) {
476       sample_number = len & 0x1f;
477       len = 1;
478     } else if ((len & 0xe0) && !(len & 0x10)) {
479       sample_number = len & 0x0f;
480       len = 2;
481     } else if ((len & 0xf0) && !(len & 0x08)) {
482       sample_number = len & 0x07;
483       len = 3;
484     } else if ((len & 0xf8) && !(len & 0x04)) {
485       sample_number = len & 0x03;
486       len = 4;
487     } else if ((len & 0xfc) && !(len & 0x02)) {
488       sample_number = len & 0x01;
489       len = 5;
490     } else if ((len & 0xfe) && !(len & 0x01)) {
491       sample_number = len & 0x0;
492       len = 6;
493     } else {
494       goto error;
495     }
496 
497     if ((blocking_strategy == 0 && len > 5) ||
498         (blocking_strategy == 1 && len > 6))
499       goto error;
500 
501     while (len > 0) {
502       if (!gst_bit_reader_get_bits_uint8 (&reader, &tmp, 8))
503         goto need_more_data;
504 
505       if ((tmp & 0xc0) != 0x80)
506         goto error;
507 
508       sample_number <<= 6;
509       sample_number |= (tmp & 0x3f);
510       len--;
511     }
512   }
513 
514   /* calculate real blocksize from the blocksize index */
515   if (block_size == 6) {
516     if (!gst_bit_reader_get_bits_uint16 (&reader, &block_size, 8))
517       goto need_more_data;
518     block_size++;
519   } else if (block_size == 7) {
520     if (!gst_bit_reader_get_bits_uint16 (&reader, &block_size, 16))
521       goto need_more_data;
522     block_size++;
523   } else {
524     block_size = blocksize_table[block_size];
525   }
526 
527   /* calculate the real samplerate from the samplerate index */
528   if (samplerate == 0 && flacparse->samplerate == 0) {
529     goto need_streaminfo;
530   } else if (samplerate < 12) {
531     samplerate = sample_rate_table[samplerate];
532   } else if (samplerate == 12) {
533     if (!gst_bit_reader_get_bits_uint32 (&reader, &samplerate, 8))
534       goto need_more_data;
535     samplerate *= 1000;
536   } else if (samplerate == 13) {
537     if (!gst_bit_reader_get_bits_uint32 (&reader, &samplerate, 16))
538       goto need_more_data;
539   } else if (samplerate == 14) {
540     if (!gst_bit_reader_get_bits_uint32 (&reader, &samplerate, 16))
541       goto need_more_data;
542     samplerate *= 10;
543   }
544 
545   if (flacparse->samplerate && flacparse->samplerate != samplerate)
546     goto error;
547 
548   /* check crc-8 for the header */
549   if (!gst_bit_reader_get_bits_uint8 (&reader, &expected_crc, 8))
550     goto need_more_data;
551 
552   actual_crc =
553       gst_flac_calculate_crc8 (data,
554       (gst_bit_reader_get_pos (&reader) / 8) - 1);
555   if (actual_crc != expected_crc) {
556     GST_DEBUG_OBJECT (flacparse,
557         "Checksum mismatch. Header CRC was '%d' but frame has '%d'",
558         expected_crc, actual_crc);
559     goto error;
560   }
561 
562   /* Sanity check sample number against blocking strategy, as it seems
563      some files claim fixed block size but supply sample numbers,
564      rather than block numbers. */
565   if (blocking_strategy == 0 && flacparse->block_size != 0) {
566     if (!flacparse->strategy_checked) {
567       if (block_size == sample_number) {
568         GST_WARNING_OBJECT (flacparse, "This file claims fixed block size, "
569             "but seems to be lying: assuming variable block size");
570         flacparse->force_variable_block_size = TRUE;
571         blocking_strategy = 1;
572       }
573       flacparse->strategy_checked = TRUE;
574     }
575   }
576 
577   /* documentation says:
578    * The "blocking strategy" bit must be the same throughout the entire stream. */
579   if (flacparse->blocking_strategy != blocking_strategy) {
580     if (flacparse->block_size != 0) {
581       GST_WARNING_OBJECT (flacparse, "blocking strategy is not constant");
582       if (suspect)
583         *suspect = TRUE;
584     }
585   }
586 
587   /*
588      The FLAC format documentation says:
589      The "blocking strategy" bit determines how to calculate the sample number
590      of the first sample in the frame. If the bit is 0 (fixed-blocksize), the
591      frame header encodes the frame number as above, and the frame's starting
592      sample number will be the frame number times the blocksize. If it is 1
593      (variable-blocksize), the frame header encodes the frame's starting
594      sample number itself. (In the case of a fixed-blocksize stream, only the
595      last block may be shorter than the stream blocksize; its starting sample
596      number will be calculated as the frame number times the previous frame's
597      blocksize, or zero if it is the first frame).
598 
599      Therefore, when in fixed block size mode, we only update the block size
600      the first time, then reuse that block size for subsequent calls.
601      This will also fix a timestamp problem with the last block's timestamp
602      being miscalculated by scaling the block number by a "wrong" block size.
603    */
604   if (blocking_strategy == 0) {
605     if (flacparse->block_size != 0) {
606       /* after first block */
607       if (flacparse->block_size != block_size) {
608         /* TODO: can we know we're on the last frame, to avoid warning ? */
609         GST_WARNING_OBJECT (flacparse, "Block size is not constant");
610         block_size = flacparse->block_size;
611         if (suspect)
612           *suspect = TRUE;
613       }
614     }
615   }
616 
617   if (set) {
618     flacparse->block_size = block_size;
619     if (!flacparse->samplerate)
620       flacparse->samplerate = samplerate;
621     if (!flacparse->bps)
622       flacparse->bps = bps;
623     if (!flacparse->blocking_strategy)
624       flacparse->blocking_strategy = blocking_strategy;
625     if (!flacparse->channels)
626       flacparse->channels = channels;
627     if (!flacparse->sample_number)
628       flacparse->sample_number = sample_number;
629 
630     GST_DEBUG_OBJECT (flacparse,
631         "Parsed frame at offset %" G_GUINT64_FORMAT ":\n" "Block size: %u\n"
632         "Sample/Frame number: %" G_GUINT64_FORMAT, flacparse->offset,
633         flacparse->block_size, flacparse->sample_number);
634   }
635 
636   if (block_size_ret)
637     *block_size_ret = block_size;
638 
639   return FRAME_HEADER_VALID;
640 
641 need_streaminfo:
642   GST_ERROR_OBJECT (flacparse, "Need STREAMINFO metadata. Bits per sample "
643       "or sample rate not in frame header");
644 error:
645   return FRAME_HEADER_INVALID;
646 
647 need_more_data:
648   return FRAME_HEADER_MORE_DATA;
649 }
650 
651 static gboolean
gst_flac_parse_frame_is_valid(GstFlacParse * flacparse,const guint8 * data,gsize size,guint * ret)652 gst_flac_parse_frame_is_valid (GstFlacParse * flacparse,
653     const guint8 * data, gsize size, guint * ret)
654 {
655   guint max, remaining;
656   guint i, search_start, search_end;
657   FrameHeaderCheckReturn header_ret;
658   guint16 block_size;
659   gboolean suspect_start = FALSE, suspect_end = FALSE;
660 
661   if (size < flacparse->min_framesize)
662     goto need_more;
663 
664   header_ret =
665       gst_flac_parse_frame_header_is_valid (flacparse, data, size, TRUE,
666       &block_size, &suspect_start);
667   if (header_ret == FRAME_HEADER_INVALID) {
668     *ret = 0;
669     return FALSE;
670   }
671   if (header_ret == FRAME_HEADER_MORE_DATA)
672     goto need_more;
673 
674   /* mind unknown framesize */
675   search_start = MAX (2, flacparse->min_framesize);
676   if (flacparse->max_framesize)
677     search_end = MIN (size, flacparse->max_framesize + 9 + 2);
678   else
679     search_end = size;
680   search_end -= 2;
681 
682   remaining = size;
683 
684   for (i = search_start; i < search_end; i++, remaining--) {
685 
686     if ((GST_READ_UINT16_BE (data + i) & 0xfffe) != 0xfff8)
687       continue;
688 
689     GST_LOG_OBJECT (flacparse, "possible frame end at offset %d", i);
690     suspect_end = FALSE;
691     header_ret =
692         gst_flac_parse_frame_header_is_valid (flacparse, data + i,
693         remaining, FALSE, NULL, &suspect_end);
694     if (header_ret == FRAME_HEADER_VALID) {
695       if (flacparse->check_frame_checksums || suspect_start || suspect_end) {
696         guint16 actual_crc = gst_flac_calculate_crc16 (data, i - 2);
697         guint16 expected_crc = GST_READ_UINT16_BE (data + i - 2);
698 
699         GST_LOG_OBJECT (flacparse,
700             "Found possible frame (%d, %d). Checking for CRC match",
701             suspect_start, suspect_end);
702         if (actual_crc != expected_crc) {
703           GST_DEBUG_OBJECT (flacparse,
704               "Checksum mismatch. Header CRC was '%d' but frame has '%d'",
705               expected_crc, actual_crc);
706           continue;
707         }
708       }
709       *ret = i;
710       flacparse->block_size = block_size;
711       return TRUE;
712     } else if (header_ret == FRAME_HEADER_MORE_DATA) {
713       goto need_more;
714     }
715   }
716 
717   /* For the last frame output everything to the end */
718   if (G_UNLIKELY (GST_BASE_PARSE_DRAINING (flacparse))) {
719     if (flacparse->check_frame_checksums) {
720       guint16 actual_crc = gst_flac_calculate_crc16 (data, size - 2);
721       guint16 expected_crc = GST_READ_UINT16_BE (data + size - 2);
722 
723       if (actual_crc == expected_crc) {
724         *ret = size;
725         flacparse->block_size = block_size;
726         return TRUE;
727       }
728     } else {
729       *ret = size;
730       flacparse->block_size = block_size;
731       return TRUE;
732     }
733   }
734 
735   /* so we searched to expected end and found nothing,
736    * give up on this frame (start) */
737   if (flacparse->max_framesize && i > 2 * flacparse->max_framesize) {
738     GST_LOG_OBJECT (flacparse,
739         "could not determine valid frame end, discarding frame (start)");
740     *ret = 1;
741     return FALSE;
742   }
743 
744 need_more:
745   max = flacparse->max_framesize + 16;
746   if (max == 16)
747     max = 1 << 24;
748   *ret = MIN (size + 4096, max);
749   return TRUE;
750 }
751 
752 static GstFlowReturn
gst_flac_parse_handle_frame(GstBaseParse * parse,GstBaseParseFrame * frame,gint * skipsize)753 gst_flac_parse_handle_frame (GstBaseParse * parse,
754     GstBaseParseFrame * frame, gint * skipsize)
755 {
756   GstFlacParse *flacparse = GST_FLAC_PARSE (parse);
757   GstBuffer *buffer = frame->buffer;
758   GstMapInfo map;
759   gboolean result = TRUE;
760   GstFlowReturn ret = GST_FLOW_OK;
761   guint framesize = 0;
762 
763   gst_buffer_map (buffer, &map, GST_MAP_READ);
764 
765   *skipsize = 1;
766 
767   if (G_UNLIKELY (map.size < 4)) {
768     result = FALSE;
769     goto cleanup;
770   }
771 
772   if (flacparse->state == GST_FLAC_PARSE_STATE_INIT) {
773     if (memcmp (map.data, "fLaC", 4) == 0) {
774       GST_DEBUG_OBJECT (flacparse, "fLaC marker found");
775       framesize = 4;
776       goto cleanup;
777     }
778     if (map.data[0] == 0xff && (map.data[1] >> 2) == 0x3e) {
779       GST_DEBUG_OBJECT (flacparse, "Found headerless FLAC");
780       /* Minimal size of a frame header */
781       gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), 9);
782       flacparse->state = GST_FLAC_PARSE_STATE_GENERATE_HEADERS;
783       *skipsize = 0;
784       result = FALSE;
785       goto cleanup;
786     }
787     GST_DEBUG_OBJECT (flacparse, "fLaC marker not found");
788     result = FALSE;
789     goto cleanup;
790   }
791 
792   if (flacparse->state == GST_FLAC_PARSE_STATE_HEADERS) {
793     guint size = 4 + ((map.data[1] << 16) | (map.data[2] << 8) | (map.data[3]));
794 
795     GST_DEBUG_OBJECT (flacparse, "Found metadata block of size %u", size);
796     framesize = size;
797     gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), framesize);
798     goto cleanup;
799   }
800 
801   if ((GST_READ_UINT16_BE (map.data) & 0xfffe) == 0xfff8) {
802     gboolean ret, is_first = !flacparse->strategy_checked;
803     guint next;
804 
805     flacparse->offset = GST_BUFFER_OFFSET (buffer);
806     flacparse->blocking_strategy = 0;
807     flacparse->sample_number = 0;
808 
809     GST_DEBUG_OBJECT (flacparse, "Found sync code");
810     ret = gst_flac_parse_frame_is_valid (flacparse, map.data, map.size, &next);
811     if (ret) {
812       if (is_first) {
813         GST_INFO_OBJECT (flacparse, "First sample number is %" G_GUINT64_FORMAT,
814             flacparse->sample_number);
815         flacparse->first_sample_number = flacparse->sample_number;
816       }
817       framesize = next;
818       goto cleanup;
819     }
820 
821     /* If we're at EOS and the frame was not valid, drop it! */
822     if (G_UNLIKELY (GST_BASE_PARSE_DRAINING (flacparse))) {
823       GST_WARNING_OBJECT (flacparse, "EOS");
824       result = FALSE;
825       goto cleanup;
826     }
827 
828     if (next == 0) {
829     } else if (next > map.size) {
830       GST_DEBUG_OBJECT (flacparse, "Requesting %u bytes", next);
831       *skipsize = 0;
832       gst_base_parse_set_min_frame_size (parse, next);
833       result = FALSE;
834       goto cleanup;
835     } else {
836       GST_ERROR_OBJECT (flacparse,
837           "Giving up on invalid frame (%" G_GSIZE_FORMAT " bytes)", map.size);
838       result = FALSE;
839       goto cleanup;
840     }
841   } else {
842     GstByteReader reader;
843     gint off;
844 
845     gst_byte_reader_init (&reader, map.data, map.size);
846     off =
847         gst_byte_reader_masked_scan_uint32 (&reader, 0xfffc0000, 0xfff80000,
848         0, map.size);
849 
850     if (off > 0) {
851       GST_DEBUG_OBJECT (parse, "Possible sync at buffer offset %d", off);
852       *skipsize = off;
853       result = FALSE;
854       goto cleanup;
855     }
856 
857     GST_DEBUG_OBJECT (flacparse, "Sync code not found");
858     *skipsize = map.size - 3;
859     result = FALSE;
860     goto cleanup;
861   }
862 
863   result = FALSE;
864 
865 cleanup:
866   gst_buffer_unmap (buffer, &map);
867 
868   if (result)
869     *skipsize = 0;
870 
871   if (result && framesize <= map.size) {
872     ret = gst_flac_parse_parse_frame (parse, frame, framesize);
873     if (ret == GST_BASE_PARSE_FLOW_DROPPED) {
874       frame->flags |= GST_BASE_PARSE_FRAME_FLAG_DROP;
875       ret = GST_FLOW_OK;
876     }
877     if (ret == GST_FLOW_OK)
878       ret = gst_base_parse_finish_frame (parse, frame, framesize);
879   }
880 
881   return ret;
882 }
883 
884 static gboolean
gst_flac_parse_handle_streaminfo(GstFlacParse * flacparse,GstBuffer * buffer)885 gst_flac_parse_handle_streaminfo (GstFlacParse * flacparse, GstBuffer * buffer)
886 {
887   GstBitReader reader;
888   GstMapInfo map;
889 
890   gst_buffer_map (buffer, &map, GST_MAP_READ);
891   gst_bit_reader_init (&reader, map.data, map.size);
892 
893   if (map.size != 4 + 34) {
894     GST_ERROR_OBJECT (flacparse,
895         "Invalid metablock size for STREAMINFO: %" G_GSIZE_FORMAT "", map.size);
896     goto failure;
897   }
898 
899   /* Skip metadata block header */
900   if (!gst_bit_reader_skip (&reader, 32))
901     goto error;
902 
903   if (!gst_bit_reader_get_bits_uint16 (&reader, &flacparse->min_blocksize, 16))
904     goto error;
905   if (flacparse->min_blocksize < 16) {
906     GST_WARNING_OBJECT (flacparse, "Invalid minimum block size: %u",
907         flacparse->min_blocksize);
908   }
909 
910   if (!gst_bit_reader_get_bits_uint16 (&reader, &flacparse->max_blocksize, 16))
911     goto error;
912   if (flacparse->max_blocksize < 16) {
913     GST_WARNING_OBJECT (flacparse, "Invalid maximum block size: %u",
914         flacparse->max_blocksize);
915   }
916 
917   if (!gst_bit_reader_get_bits_uint32 (&reader, &flacparse->min_framesize, 24))
918     goto error;
919   if (!gst_bit_reader_get_bits_uint32 (&reader, &flacparse->max_framesize, 24))
920     goto error;
921 
922   if (!gst_bit_reader_get_bits_uint32 (&reader, &flacparse->samplerate, 20))
923     goto error;
924   if (flacparse->samplerate == 0) {
925     GST_ERROR_OBJECT (flacparse, "Invalid sample rate 0");
926     goto failure;
927   }
928 
929   if (!gst_bit_reader_get_bits_uint8 (&reader, &flacparse->channels, 3))
930     goto error;
931   flacparse->channels++;
932   if (flacparse->channels > 8) {
933     GST_ERROR_OBJECT (flacparse, "Invalid number of channels %u",
934         flacparse->channels);
935     goto failure;
936   }
937 
938   if (!gst_bit_reader_get_bits_uint8 (&reader, &flacparse->bps, 5))
939     goto error;
940   flacparse->bps++;
941 
942   if (!gst_bit_reader_get_bits_uint64 (&reader, &flacparse->total_samples, 36))
943     goto error;
944   if (flacparse->total_samples) {
945     gst_base_parse_set_duration (GST_BASE_PARSE (flacparse),
946         GST_FORMAT_DEFAULT, flacparse->total_samples, 0);
947   }
948 
949   gst_buffer_unmap (buffer, &map);
950 
951   GST_DEBUG_OBJECT (flacparse, "STREAMINFO:\n"
952       "\tmin/max blocksize: %u/%u,\n"
953       "\tmin/max framesize: %u/%u,\n"
954       "\tsamplerate: %u,\n"
955       "\tchannels: %u,\n"
956       "\tbits per sample: %u,\n"
957       "\ttotal samples: %" G_GUINT64_FORMAT,
958       flacparse->min_blocksize, flacparse->max_blocksize,
959       flacparse->min_framesize, flacparse->max_framesize,
960       flacparse->samplerate,
961       flacparse->channels, flacparse->bps, flacparse->total_samples);
962 
963   return TRUE;
964 
965 error:
966   GST_ERROR_OBJECT (flacparse, "Failed to read data");
967 failure:
968   gst_buffer_unmap (buffer, &map);
969   return FALSE;
970 }
971 
972 static gboolean
gst_flac_parse_handle_vorbiscomment(GstFlacParse * flacparse,GstBuffer * buffer)973 gst_flac_parse_handle_vorbiscomment (GstFlacParse * flacparse,
974     GstBuffer * buffer)
975 {
976   GstTagList *tags;
977   GstMapInfo map;
978 
979   gst_buffer_map (buffer, &map, GST_MAP_READ);
980 
981   tags =
982       gst_tag_list_from_vorbiscomment (map.data, map.size, map.data, 4, NULL);
983   gst_buffer_unmap (buffer, &map);
984 
985   if (tags == NULL) {
986     GST_ERROR_OBJECT (flacparse, "Invalid vorbiscomment block");
987   } else if (gst_tag_list_is_empty (tags)) {
988     gst_tag_list_unref (tags);
989   } else if (flacparse->tags == NULL) {
990     flacparse->tags = tags;
991   } else {
992     gst_tag_list_insert (flacparse->tags, tags, GST_TAG_MERGE_APPEND);
993     gst_tag_list_unref (tags);
994   }
995 
996   return TRUE;
997 }
998 
999 static gboolean
gst_flac_parse_handle_cuesheet(GstFlacParse * flacparse,GstBuffer * buffer)1000 gst_flac_parse_handle_cuesheet (GstFlacParse * flacparse, GstBuffer * buffer)
1001 {
1002   GstByteReader reader;
1003   GstMapInfo map;
1004   guint i, j;
1005   guint8 n_tracks, track_num, index;
1006   guint64 offset;
1007   gint64 start, stop;
1008   gchar *id;
1009   gchar isrc[13];
1010   GstTagList *tags;
1011   GstToc *toc;
1012   GstTocEntry *cur_entry = NULL, *prev_entry = NULL;
1013 
1014   gst_buffer_map (buffer, &map, GST_MAP_READ);
1015   gst_byte_reader_init (&reader, map.data, map.size);
1016 
1017   toc = gst_toc_new (GST_TOC_SCOPE_GLOBAL);
1018 
1019   /* skip 4 bytes METADATA_BLOCK_HEADER */
1020   /* https://xiph.org/flac/format.html#metadata_block_header */
1021   if (!gst_byte_reader_skip (&reader, 4))
1022     goto error;
1023 
1024   /* skip 395 bytes from METADATA_BLOCK_CUESHEET */
1025   /* https://xiph.org/flac/format.html#metadata_block_cuesheet */
1026   if (!gst_byte_reader_skip (&reader, 395))
1027     goto error;
1028 
1029   if (!gst_byte_reader_get_uint8 (&reader, &n_tracks))
1030     goto error;
1031 
1032   /* CUESHEET_TRACK */
1033   /* https://xiph.org/flac/format.html#cuesheet_track */
1034   for (i = 0; i < n_tracks; i++) {
1035     if (!gst_byte_reader_get_uint64_be (&reader, &offset))
1036       goto error;
1037     if (!gst_byte_reader_get_uint8 (&reader, &track_num))
1038       goto error;
1039 
1040     if (gst_byte_reader_get_remaining (&reader) < 12)
1041       goto error;
1042     memcpy (isrc, map.data + gst_byte_reader_get_pos (&reader), 12);
1043     /* \0-terminate the string */
1044     isrc[12] = '\0';
1045     if (!gst_byte_reader_skip (&reader, 12))
1046       goto error;
1047 
1048     /* skip 14 bytes from CUESHEET_TRACK */
1049     if (!gst_byte_reader_skip (&reader, 14))
1050       goto error;
1051     if (!gst_byte_reader_get_uint8 (&reader, &index))
1052       goto error;
1053     /* add tracks in TOC */
1054     /* lead-out tack has number 170 or 255 */
1055     if (track_num != 170 && track_num != 255) {
1056       prev_entry = cur_entry;
1057       /* previous track stop time = current track start time */
1058       if (prev_entry != NULL) {
1059         gst_toc_entry_get_start_stop_times (prev_entry, &start, NULL);
1060         stop =
1061             gst_util_uint64_scale_round (offset, GST_SECOND,
1062             flacparse->samplerate);
1063         gst_toc_entry_set_start_stop_times (prev_entry, start, stop);
1064       }
1065       id = g_strdup_printf ("%08x", track_num);
1066       cur_entry = gst_toc_entry_new (GST_TOC_ENTRY_TYPE_TRACK, id);
1067       g_free (id);
1068       start =
1069           gst_util_uint64_scale_round (offset, GST_SECOND,
1070           flacparse->samplerate);
1071       gst_toc_entry_set_start_stop_times (cur_entry, start, -1);
1072       /* add ISRC as tag in track */
1073       if (strlen (isrc) != 0) {
1074         tags = gst_tag_list_new_empty ();
1075         gst_tag_list_add (tags, GST_TAG_MERGE_APPEND, GST_TAG_ISRC, isrc, NULL);
1076         gst_toc_entry_set_tags (cur_entry, tags);
1077       }
1078       gst_toc_append_entry (toc, cur_entry);
1079       /* CUESHEET_TRACK_INDEX */
1080       /* https://xiph.org/flac/format.html#cuesheet_track_index */
1081       for (j = 0; j < index; j++) {
1082         if (!gst_byte_reader_skip (&reader, 12))
1083           goto error;
1084       }
1085     } else {
1086       /* set stop time in last track */
1087       stop =
1088           gst_util_uint64_scale_round (offset, GST_SECOND,
1089           flacparse->samplerate);
1090       gst_toc_entry_set_start_stop_times (cur_entry, start, stop);
1091     }
1092   }
1093 
1094   /* send data as TOC */
1095   if (!flacparse->toc)
1096     flacparse->toc = toc;
1097 
1098   gst_buffer_unmap (buffer, &map);
1099   return TRUE;
1100 
1101 error:
1102   GST_ERROR_OBJECT (flacparse, "Error reading data");
1103   gst_buffer_unmap (buffer, &map);
1104   return FALSE;
1105 }
1106 
1107 static gboolean
gst_flac_parse_handle_picture(GstFlacParse * flacparse,GstBuffer * buffer)1108 gst_flac_parse_handle_picture (GstFlacParse * flacparse, GstBuffer * buffer)
1109 {
1110   GstByteReader reader;
1111   GstMapInfo map;
1112   guint32 img_len = 0, img_type = 0;
1113   guint32 img_mimetype_len = 0, img_description_len = 0;
1114 #ifdef OHOS_OPT_CVE
1115   const guint8 *img_data;
1116 #endif
1117 
1118   gst_buffer_map (buffer, &map, GST_MAP_READ);
1119   gst_byte_reader_init (&reader, map.data, map.size);
1120 
1121   if (!gst_byte_reader_skip (&reader, 4))
1122     goto error;
1123 
1124   if (!gst_byte_reader_get_uint32_be (&reader, &img_type))
1125     goto error;
1126 
1127   if (!gst_byte_reader_get_uint32_be (&reader, &img_mimetype_len))
1128     goto error;
1129   if (!gst_byte_reader_skip (&reader, img_mimetype_len))
1130     goto error;
1131 
1132   if (!gst_byte_reader_get_uint32_be (&reader, &img_description_len))
1133     goto error;
1134   if (!gst_byte_reader_skip (&reader, img_description_len))
1135     goto error;
1136 
1137   if (!gst_byte_reader_skip (&reader, 4 * 4))
1138     goto error;
1139 
1140   if (!gst_byte_reader_get_uint32_be (&reader, &img_len))
1141     goto error;
1142 
1143 #ifdef OHOS_OPT_CVE
1144   if (!gst_byte_reader_get_data (&reader, img_len, &img_data))
1145 #else
1146   if (gst_byte_reader_get_pos (&reader) + img_len > map.size)
1147 #endif
1148     goto error;
1149 
1150   GST_INFO_OBJECT (flacparse, "Got image of %d bytes", img_len);
1151 
1152   if (img_len > 0) {
1153     if (flacparse->tags == NULL)
1154       flacparse->tags = gst_tag_list_new_empty ();
1155 
1156 #ifdef OHOS_OPT_CVE
1157     gst_tag_list_add_id3_image (flacparse->tags, img_data, img_len, img_type);
1158 #else
1159     gst_tag_list_add_id3_image (flacparse->tags,
1160         map.data + gst_byte_reader_get_pos (&reader), img_len, img_type);
1161 #endif
1162   }
1163 
1164   gst_buffer_unmap (buffer, &map);
1165   return TRUE;
1166 
1167 error:
1168   GST_ERROR_OBJECT (flacparse, "Error reading data");
1169   gst_buffer_unmap (buffer, &map);
1170   return FALSE;
1171 }
1172 
1173 static gboolean
gst_flac_parse_handle_seektable(GstFlacParse * flacparse,GstBuffer * buffer)1174 gst_flac_parse_handle_seektable (GstFlacParse * flacparse, GstBuffer * buffer)
1175 {
1176 
1177   GST_DEBUG_OBJECT (flacparse, "storing seektable");
1178   /* only store for now;
1179    * offset of the first frame is needed to get real info */
1180   if (flacparse->seektable)
1181     gst_buffer_unref (flacparse->seektable);
1182   flacparse->seektable = gst_buffer_ref (buffer);
1183 
1184   return TRUE;
1185 }
1186 
1187 static void
gst_flac_parse_process_seektable(GstFlacParse * flacparse,gint64 boffset)1188 gst_flac_parse_process_seektable (GstFlacParse * flacparse, gint64 boffset)
1189 {
1190   GstByteReader br;
1191   gint64 offset = 0, samples = 0;
1192   GstMapInfo map;
1193 
1194   GST_DEBUG_OBJECT (flacparse,
1195       "parsing seektable; base offset %" G_GINT64_FORMAT, boffset);
1196 
1197   if (boffset <= 0)
1198     goto exit;
1199 
1200   gst_buffer_map (flacparse->seektable, &map, GST_MAP_READ);
1201   gst_byte_reader_init (&br, map.data, map.size);
1202 
1203   /* skip header */
1204   if (!gst_byte_reader_skip (&br, 4))
1205     goto done;
1206 
1207   /* seekpoints */
1208   while (gst_byte_reader_get_remaining (&br)) {
1209     if (!gst_byte_reader_get_int64_be (&br, &samples))
1210       break;
1211     if (!gst_byte_reader_get_int64_be (&br, &offset))
1212       break;
1213     if (!gst_byte_reader_skip (&br, 2))
1214       break;
1215 
1216     GST_LOG_OBJECT (flacparse, "samples %" G_GINT64_FORMAT " -> offset %"
1217         G_GINT64_FORMAT, samples, offset);
1218 
1219     /* sanity check */
1220     if (G_LIKELY (offset > 0 && samples > 0)) {
1221       gst_base_parse_add_index_entry (GST_BASE_PARSE (flacparse),
1222           boffset + offset, gst_util_uint64_scale (samples, GST_SECOND,
1223               flacparse->samplerate), TRUE, FALSE);
1224     }
1225   }
1226 
1227 done:
1228   gst_buffer_unmap (flacparse->seektable, &map);
1229 exit:
1230   gst_buffer_unref (flacparse->seektable);
1231   flacparse->seektable = NULL;
1232 }
1233 
1234 static void
_value_array_append_buffer(GValue * array_val,GstBuffer * buf)1235 _value_array_append_buffer (GValue * array_val, GstBuffer * buf)
1236 {
1237   GValue value = { 0, };
1238 
1239   g_value_init (&value, GST_TYPE_BUFFER);
1240   /* copy buffer to avoid problems with circular refcounts */
1241   buf = gst_buffer_copy (buf);
1242   /* again, for good measure */
1243   GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
1244   gst_value_set_buffer (&value, buf);
1245   gst_buffer_unref (buf);
1246   gst_value_array_append_value (array_val, &value);
1247   g_value_unset (&value);
1248 }
1249 
1250 static GstFlowReturn
gst_flac_parse_handle_headers(GstFlacParse * flacparse)1251 gst_flac_parse_handle_headers (GstFlacParse * flacparse)
1252 {
1253   GstBuffer *vorbiscomment = NULL;
1254   GstBuffer *streaminfo = NULL;
1255   GstBuffer *marker = NULL;
1256   GValue array = { 0, };
1257   GstCaps *caps;
1258   GList *l;
1259   GstFlowReturn res = GST_FLOW_OK;
1260   gboolean is_streaminfo_last = FALSE;
1261 
1262   caps = gst_caps_new_simple ("audio/x-flac",
1263       "channels", G_TYPE_INT, flacparse->channels,
1264       "framed", G_TYPE_BOOLEAN, TRUE,
1265       "rate", G_TYPE_INT, flacparse->samplerate, NULL);
1266 
1267   if (!flacparse->headers)
1268     goto push_headers;
1269 
1270   for (l = flacparse->headers; l; l = l->next) {
1271     GstBuffer *header = l->data;
1272     GstMapInfo map;
1273 
1274     gst_buffer_map (header, &map, GST_MAP_READ);
1275 
1276     GST_BUFFER_FLAG_SET (header, GST_BUFFER_FLAG_HEADER);
1277 
1278     if (map.size == 4 && memcmp (map.data, "fLaC", 4) == 0) {
1279       marker = header;
1280     } else if (map.size > 1 && (map.data[0] & 0x7f) == 0) {
1281       streaminfo = header;
1282       is_streaminfo_last = (map.data[0] & 0x80) != 0;
1283     } else if (map.size > 1 && (map.data[0] & 0x7f) == 4) {
1284       vorbiscomment = header;
1285     }
1286 
1287     gst_buffer_unmap (header, &map);
1288   }
1289 
1290   /* at least this one we can generate easily
1291    * to provide full headers downstream */
1292   if (vorbiscomment == NULL && streaminfo != NULL) {
1293     GST_DEBUG_OBJECT (flacparse,
1294         "missing vorbiscomment header; generating dummy");
1295     /* this vorbiscomment header is inserted after streaminfo and inherits its last-metadata-block flag */
1296     vorbiscomment =
1297         gst_flac_parse_generate_vorbiscomment (flacparse, is_streaminfo_last);
1298     flacparse->headers =
1299         g_list_insert (flacparse->headers, vorbiscomment,
1300         g_list_index (flacparse->headers, streaminfo) + 1);
1301   }
1302 
1303   if (marker == NULL || streaminfo == NULL || vorbiscomment == NULL) {
1304     GST_WARNING_OBJECT (flacparse,
1305         "missing header %p %p %p, muxing into container "
1306         "formats may be broken", marker, streaminfo, vorbiscomment);
1307     goto push_headers;
1308   }
1309 
1310   g_value_init (&array, GST_TYPE_ARRAY);
1311 
1312   /* add marker including STREAMINFO header */
1313   {
1314     GstBuffer *buf;
1315     guint16 num;
1316     GstMapInfo sinfomap, writemap;
1317 
1318     gst_buffer_map (streaminfo, &sinfomap, GST_MAP_READ);
1319 
1320     /* minus one for the marker that is merged with streaminfo here */
1321     num = g_list_length (flacparse->headers) - 1;
1322 
1323     buf = gst_buffer_new_and_alloc (13 + sinfomap.size);
1324     gst_buffer_map (buf, &writemap, GST_MAP_WRITE);
1325 
1326     writemap.data[0] = 0x7f;
1327     memcpy (writemap.data + 1, "FLAC", 4);
1328     writemap.data[5] = 0x01;    /* mapping version major */
1329     writemap.data[6] = 0x00;    /* mapping version minor */
1330     writemap.data[7] = (num & 0xFF00) >> 8;
1331     writemap.data[8] = (num & 0x00FF) >> 0;
1332     memcpy (writemap.data + 9, "fLaC", 4);
1333     memcpy (writemap.data + 13, sinfomap.data, sinfomap.size);
1334     /* clear the last-metadata-block flag because a VORBISCOMMENT always follows */
1335     writemap.data[13] = 0x00;   /* is_last = 0; type = 0; */
1336     _value_array_append_buffer (&array, buf);
1337 
1338     gst_buffer_unmap (streaminfo, &sinfomap);
1339     gst_buffer_unmap (buf, &writemap);
1340     gst_buffer_unref (buf);
1341   }
1342 
1343   /* add other headers, including VORBISCOMMENT */
1344   for (l = flacparse->headers; l; l = l->next) {
1345     if (GST_BUFFER_CAST (l->data) != marker &&
1346         GST_BUFFER_CAST (l->data) != streaminfo) {
1347       _value_array_append_buffer (&array, GST_BUFFER_CAST (l->data));
1348     }
1349   }
1350 
1351   gst_structure_set_value (gst_caps_get_structure (caps, 0),
1352       "streamheader", &array);
1353   g_value_unset (&array);
1354 
1355 push_headers:
1356 
1357   gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (GST_BASE_PARSE (flacparse)), caps);
1358   gst_caps_unref (caps);
1359 
1360   /* push header buffers; update caps, so when we push the first buffer the
1361    * negotiated caps will change to caps that include the streamheader field */
1362   while (flacparse->headers) {
1363     GstBuffer *buf = GST_BUFFER (flacparse->headers->data);
1364     GstBaseParseFrame frame;
1365 
1366     flacparse->headers =
1367         g_list_delete_link (flacparse->headers, flacparse->headers);
1368     buf = gst_buffer_make_writable (buf);
1369 
1370     /* init, set and give away frame */
1371     gst_base_parse_frame_init (&frame);
1372     frame.buffer = buf;
1373     frame.overhead = -1;
1374     res = gst_base_parse_push_frame (GST_BASE_PARSE (flacparse), &frame);
1375     gst_base_parse_frame_free (&frame);
1376     if (res != GST_FLOW_OK)
1377       break;
1378   }
1379   g_list_foreach (flacparse->headers, (GFunc) gst_mini_object_unref, NULL);
1380   g_list_free (flacparse->headers);
1381   flacparse->headers = NULL;
1382 
1383   return res;
1384 }
1385 
1386 /* empty vorbiscomment */
1387 static GstBuffer *
gst_flac_parse_generate_vorbiscomment(GstFlacParse * flacparse,gboolean is_last)1388 gst_flac_parse_generate_vorbiscomment (GstFlacParse * flacparse,
1389     gboolean is_last)
1390 {
1391   GstTagList *taglist = gst_tag_list_new_empty ();
1392   guchar header[4];
1393   guint size;
1394   GstBuffer *vorbiscomment;
1395   GstMapInfo map;
1396 
1397   header[0] = (is_last ? 0x80 : 0x00) | 0x04;   /* is_last may vary; type = 4; */
1398 
1399   vorbiscomment =
1400       gst_tag_list_to_vorbiscomment_buffer (taglist, header,
1401       sizeof (header), NULL);
1402   gst_tag_list_unref (taglist);
1403 
1404   gst_buffer_map (vorbiscomment, &map, GST_MAP_WRITE);
1405 
1406   /* Get rid of framing bit */
1407   if (map.data[map.size - 1] == 1) {
1408     GstBuffer *sub;
1409 
1410     sub =
1411         gst_buffer_copy_region (vorbiscomment, GST_BUFFER_COPY_ALL, 0,
1412         map.size - 1);
1413     gst_buffer_unmap (vorbiscomment, &map);
1414     gst_buffer_unref (vorbiscomment);
1415     vorbiscomment = sub;
1416     gst_buffer_map (vorbiscomment, &map, GST_MAP_WRITE);
1417   }
1418 
1419   size = map.size - 4;
1420   map.data[1] = ((size & 0xFF0000) >> 16);
1421   map.data[2] = ((size & 0x00FF00) >> 8);
1422   map.data[3] = (size & 0x0000FF);
1423   gst_buffer_unmap (vorbiscomment, &map);
1424   gst_flac_parse_reset_buffer_time_and_offset (vorbiscomment);
1425 
1426   return vorbiscomment;
1427 }
1428 
1429 static gboolean
gst_flac_parse_generate_headers(GstFlacParse * flacparse)1430 gst_flac_parse_generate_headers (GstFlacParse * flacparse)
1431 {
1432   GstBuffer *marker, *streaminfo;
1433   GstMapInfo map;
1434 
1435   marker = gst_buffer_new_and_alloc (4);
1436   gst_buffer_map (marker, &map, GST_MAP_WRITE);
1437   memcpy (map.data, "fLaC", 4);
1438   gst_buffer_unmap (marker, &map);
1439   gst_flac_parse_reset_buffer_time_and_offset (marker);
1440   flacparse->headers = g_list_append (flacparse->headers, marker);
1441 
1442   streaminfo = gst_buffer_new_and_alloc (4 + 34);
1443   gst_buffer_map (streaminfo, &map, GST_MAP_WRITE);
1444   memset (map.data, 0, 4 + 34);
1445 
1446   /* metadata block header */
1447   map.data[0] = 0x00;           /* is_last = 0; type = 0; */
1448   map.data[1] = 0x00;           /* length = 34; */
1449   map.data[2] = 0x00;
1450   map.data[3] = 0x22;
1451 
1452   /* streaminfo */
1453 
1454   map.data[4] = (flacparse->block_size >> 8) & 0xff;    /* min blocksize = blocksize; */
1455   map.data[5] = (flacparse->block_size) & 0xff;
1456   map.data[6] = (flacparse->block_size >> 8) & 0xff;    /* max blocksize = blocksize; */
1457   map.data[7] = (flacparse->block_size) & 0xff;
1458 
1459   map.data[8] = 0x00;           /* min framesize = 0; */
1460   map.data[9] = 0x00;
1461   map.data[10] = 0x00;
1462   map.data[11] = 0x00;          /* max framesize = 0; */
1463   map.data[12] = 0x00;
1464   map.data[13] = 0x00;
1465 
1466   map.data[14] = (flacparse->samplerate >> 12) & 0xff;
1467   map.data[15] = (flacparse->samplerate >> 4) & 0xff;
1468   map.data[16] = (flacparse->samplerate >> 0) & 0xf0;
1469 
1470   map.data[16] |= (flacparse->channels - 1) << 1;
1471 
1472   map.data[16] |= ((flacparse->bps - 1) >> 4) & 0x01;
1473   map.data[17] = (((flacparse->bps - 1)) & 0x0f) << 4;
1474 
1475   {
1476     gint64 duration;
1477 
1478     if (gst_pad_peer_query_duration (GST_BASE_PARSE_SINK_PAD (flacparse),
1479             GST_FORMAT_TIME, &duration) && duration != -1) {
1480       duration = GST_CLOCK_TIME_TO_FRAMES (duration, flacparse->samplerate);
1481 
1482       map.data[17] |= (duration >> 32) & 0xff;
1483       map.data[18] |= (duration >> 24) & 0xff;
1484       map.data[19] |= (duration >> 16) & 0xff;
1485       map.data[20] |= (duration >> 8) & 0xff;
1486       map.data[21] |= (duration >> 0) & 0xff;
1487     }
1488   }
1489   /* MD5 = 0; */
1490 
1491   gst_buffer_unmap (streaminfo, &map);
1492   gst_flac_parse_reset_buffer_time_and_offset (streaminfo);
1493   flacparse->headers = g_list_append (flacparse->headers, streaminfo);
1494 
1495   flacparse->headers = g_list_append (flacparse->headers,
1496       gst_flac_parse_generate_vorbiscomment (flacparse, TRUE));
1497 
1498   return TRUE;
1499 }
1500 
1501 static inline void
gst_flac_parse_reset_buffer_time_and_offset(GstBuffer * buffer)1502 gst_flac_parse_reset_buffer_time_and_offset (GstBuffer * buffer)
1503 {
1504   GST_BUFFER_TIMESTAMP (buffer) = GST_CLOCK_TIME_NONE;
1505   GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
1506   GST_BUFFER_OFFSET (buffer) = 0;
1507   GST_BUFFER_OFFSET_END (buffer) = 0;
1508 }
1509 
1510 /* Type 127 is invalid for a metadata block header & should
1511  * be discarded _before_ calling this function */
1512 static gboolean
gst_flac_parse_handle_block_type(GstFlacParse * flacparse,guint type,GstBuffer * sbuffer)1513 gst_flac_parse_handle_block_type (GstFlacParse * flacparse, guint type,
1514     GstBuffer * sbuffer)
1515 {
1516   gboolean ret = TRUE;
1517 
1518   switch (type) {
1519     case 0:                    /* STREAMINFO */
1520       GST_INFO_OBJECT (flacparse, "STREAMINFO header");
1521       ret = gst_flac_parse_handle_streaminfo (flacparse, sbuffer);
1522       break;
1523     case 3:                    /* SEEKTABLE */
1524       GST_INFO_OBJECT (flacparse, "SEEKTABLE header");
1525       ret = gst_flac_parse_handle_seektable (flacparse, sbuffer);
1526       break;
1527     case 4:                    /* VORBIS_COMMENT */
1528       GST_INFO_OBJECT (flacparse, "VORBISCOMMENT header");
1529       ret = gst_flac_parse_handle_vorbiscomment (flacparse, sbuffer);
1530       break;
1531     case 5:                    /* CUESHEET */
1532       GST_INFO_OBJECT (flacparse, "CUESHEET header");
1533       ret = gst_flac_parse_handle_cuesheet (flacparse, sbuffer);
1534       break;
1535     case 6:                    /* PICTURE */
1536       GST_INFO_OBJECT (flacparse, "PICTURE header");
1537       ret = gst_flac_parse_handle_picture (flacparse, sbuffer);
1538       break;
1539     case 1:                    /* PADDING */
1540       GST_INFO_OBJECT (flacparse, "PADDING header");
1541       break;
1542     case 2:                    /* APPLICATION */
1543       GST_INFO_OBJECT (flacparse, "APPLICATION header");
1544       break;
1545     default:                   /* RESERVED */
1546       GST_INFO_OBJECT (flacparse, "Unhandled metadata header type '%u'", type);
1547       GST_FIXME_OBJECT (flacparse, "FLAC version might not be fully supported");
1548       break;
1549   }
1550 
1551   return ret;
1552 }
1553 
1554 static GstFlowReturn
gst_flac_parse_parse_frame(GstBaseParse * parse,GstBaseParseFrame * frame,gint size)1555 gst_flac_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame,
1556     gint size)
1557 {
1558   GstFlacParse *flacparse = GST_FLAC_PARSE (parse);
1559   GstBuffer *buffer = frame->buffer, *sbuffer;
1560   GstMapInfo map;
1561   GstFlowReturn res = GST_FLOW_ERROR;
1562   guint64 relative_sample_number;
1563 
1564   gst_buffer_map (buffer, &map, GST_MAP_READ);
1565 
1566   if (flacparse->state == GST_FLAC_PARSE_STATE_INIT) {
1567     sbuffer = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, 0, size);
1568     gst_flac_parse_reset_buffer_time_and_offset (sbuffer);
1569 
1570     /* 32 bits metadata block */
1571     gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), 4);
1572     flacparse->state = GST_FLAC_PARSE_STATE_HEADERS;
1573 
1574     flacparse->headers = g_list_append (flacparse->headers, sbuffer);
1575 
1576     res = GST_BASE_PARSE_FLOW_DROPPED;
1577   } else if (flacparse->state == GST_FLAC_PARSE_STATE_HEADERS) {
1578     gboolean is_last = map.data[0] >> 7;
1579     guint type = (map.data[0] & 0x7F);
1580 
1581     if (type == 127) {
1582       GST_WARNING_OBJECT (flacparse, "Invalid metadata block type 127");
1583       res = GST_BASE_PARSE_FLOW_DROPPED;
1584       goto cleanup;
1585     }
1586 
1587     GST_DEBUG_OBJECT (flacparse, "Handling metadata block of type %u", type);
1588 
1589     sbuffer = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, 0, size);
1590 
1591     if (gst_flac_parse_handle_block_type (flacparse, type, sbuffer)) {
1592       gst_flac_parse_reset_buffer_time_and_offset (sbuffer);
1593       flacparse->headers = g_list_append (flacparse->headers, sbuffer);
1594     } else {
1595       GST_WARNING_OBJECT (parse, "failed to parse header of type %u", type);
1596       GST_MEMDUMP_OBJECT (parse, "bad header data", map.data, size);
1597 
1598       gst_buffer_unref (sbuffer);
1599 
1600       /* error out unless we have a STREAMINFO header */
1601       if (flacparse->samplerate == 0 || flacparse->bps == 0)
1602         goto header_parsing_error;
1603 
1604       /* .. in which case just stop header parsing and try to find audio */
1605       is_last = TRUE;
1606     }
1607 
1608     if (is_last) {
1609       res = gst_flac_parse_handle_headers (flacparse);
1610 
1611       /* Minimal size of a frame header */
1612       gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), MAX (9,
1613               flacparse->min_framesize));
1614       flacparse->state = GST_FLAC_PARSE_STATE_DATA;
1615 
1616       if (res != GST_FLOW_OK)
1617         goto cleanup;
1618     } else {
1619       /* Header length */
1620       gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), 4);
1621     }
1622 
1623     /* DROPPED because we pushed already or will push all headers manually */
1624     res = GST_BASE_PARSE_FLOW_DROPPED;
1625   } else {
1626     if (flacparse->offset != GST_BUFFER_OFFSET (buffer)) {
1627       FrameHeaderCheckReturn ret;
1628 
1629       flacparse->offset = GST_BUFFER_OFFSET (buffer);
1630       ret =
1631           gst_flac_parse_frame_header_is_valid (flacparse,
1632           map.data, map.size, TRUE, NULL, NULL);
1633       if (ret != FRAME_HEADER_VALID) {
1634         GST_ERROR_OBJECT (flacparse,
1635             "Baseclass didn't provide a complete frame");
1636         goto cleanup;
1637       }
1638     }
1639 
1640     if (flacparse->block_size == 0) {
1641       GST_ERROR_OBJECT (flacparse, "Unparsed frame");
1642       goto cleanup;
1643     }
1644 
1645     if (flacparse->seektable)
1646       gst_flac_parse_process_seektable (flacparse, GST_BUFFER_OFFSET (buffer));
1647 
1648     if (flacparse->state == GST_FLAC_PARSE_STATE_GENERATE_HEADERS) {
1649       if (flacparse->blocking_strategy == 1) {
1650         GST_WARNING_OBJECT (flacparse,
1651             "Generating headers for variable blocksize streams not supported");
1652 
1653         res = gst_flac_parse_handle_headers (flacparse);
1654       } else {
1655         GST_DEBUG_OBJECT (flacparse, "Generating headers");
1656 
1657         if (!gst_flac_parse_generate_headers (flacparse))
1658           goto cleanup;
1659 
1660         res = gst_flac_parse_handle_headers (flacparse);
1661       }
1662       flacparse->state = GST_FLAC_PARSE_STATE_DATA;
1663       if (res != GST_FLOW_OK)
1664         goto cleanup;
1665     }
1666 
1667     /* also cater for oggmux metadata */
1668     relative_sample_number =
1669         flacparse->sample_number - flacparse->first_sample_number;
1670     if (flacparse->blocking_strategy == 0) {
1671       GST_BUFFER_PTS (buffer) =
1672           gst_util_uint64_scale (relative_sample_number,
1673           flacparse->block_size * GST_SECOND, flacparse->samplerate);
1674       GST_BUFFER_OFFSET_END (buffer) =
1675           relative_sample_number * flacparse->block_size +
1676           flacparse->block_size;
1677     } else {
1678       GST_BUFFER_PTS (buffer) =
1679           gst_util_uint64_scale (relative_sample_number, GST_SECOND,
1680           flacparse->samplerate);
1681       GST_BUFFER_OFFSET_END (buffer) =
1682           relative_sample_number + flacparse->block_size;
1683     }
1684 
1685     GST_BUFFER_DTS (buffer) = GST_BUFFER_PTS (buffer);
1686     GST_BUFFER_OFFSET (buffer) =
1687         gst_util_uint64_scale (GST_BUFFER_OFFSET_END (buffer), GST_SECOND,
1688         flacparse->samplerate);
1689     GST_BUFFER_DURATION (buffer) =
1690         GST_BUFFER_OFFSET (buffer) - GST_BUFFER_PTS (buffer);
1691 
1692     /* To simplify, we just assume that it's a fixed size header and ignore
1693      * subframe headers. The first could lead us to be off by 88 bits and
1694      * the second even less, so the total inaccuracy is negligible. */
1695     frame->overhead = 7;
1696 
1697     /* Minimal size of a frame header */
1698     gst_base_parse_set_min_frame_size (GST_BASE_PARSE (flacparse), MAX (9,
1699             flacparse->min_framesize));
1700 
1701     flacparse->offset = -1;
1702     flacparse->blocking_strategy = 0;
1703     flacparse->sample_number = 0;
1704     res = GST_FLOW_OK;
1705   }
1706 
1707 cleanup:
1708   gst_buffer_unmap (buffer, &map);
1709   return res;
1710 
1711 header_parsing_error:
1712   GST_ELEMENT_ERROR (flacparse, STREAM, DECODE, (NULL),
1713       ("Failed to parse headers"));
1714   goto cleanup;
1715 }
1716 
1717 static GstFlowReturn
gst_flac_parse_pre_push_frame(GstBaseParse * parse,GstBaseParseFrame * frame)1718 gst_flac_parse_pre_push_frame (GstBaseParse * parse, GstBaseParseFrame * frame)
1719 {
1720   GstFlacParse *flacparse = GST_FLAC_PARSE (parse);
1721 
1722   if (!flacparse->sent_codec_tag) {
1723     GstCaps *caps;
1724 
1725     if (flacparse->tags == NULL)
1726       flacparse->tags = gst_tag_list_new_empty ();
1727 
1728     /* codec tag */
1729     caps = gst_pad_get_current_caps (GST_BASE_PARSE_SRC_PAD (parse));
1730     if (G_UNLIKELY (caps == NULL)) {
1731       if (GST_PAD_IS_FLUSHING (GST_BASE_PARSE_SRC_PAD (parse))) {
1732         GST_INFO_OBJECT (parse, "Src pad is flushing");
1733         return GST_FLOW_FLUSHING;
1734       }
1735       GST_INFO_OBJECT (parse, "Src pad is not negotiated!");
1736       return GST_FLOW_NOT_NEGOTIATED;
1737     }
1738     gst_pb_utils_add_codec_description_to_tag_list (flacparse->tags,
1739         GST_TAG_AUDIO_CODEC, caps);
1740     gst_caps_unref (caps);
1741 
1742     /* Announce our pending tags */
1743     gst_base_parse_merge_tags (parse, flacparse->tags, GST_TAG_MERGE_REPLACE);
1744 
1745     /* also signals the end of first-frame processing */
1746     flacparse->sent_codec_tag = TRUE;
1747   }
1748 
1749   /* Push toc */
1750   if (flacparse->toc) {
1751     gst_pad_push_event (GST_BASE_PARSE_SRC_PAD (flacparse),
1752         gst_event_new_toc (flacparse->toc, FALSE));
1753   }
1754 
1755   frame->flags |= GST_BASE_PARSE_FRAME_FLAG_CLIP;
1756 
1757   return GST_FLOW_OK;
1758 }
1759 
1760 static gboolean
gst_flac_parse_convert(GstBaseParse * parse,GstFormat src_format,gint64 src_value,GstFormat dest_format,gint64 * dest_value)1761 gst_flac_parse_convert (GstBaseParse * parse,
1762     GstFormat src_format, gint64 src_value, GstFormat dest_format,
1763     gint64 * dest_value)
1764 {
1765   GstFlacParse *flacparse = GST_FLAC_PARSE (parse);
1766 
1767   if (flacparse->samplerate > 0) {
1768     if (src_format == GST_FORMAT_DEFAULT && dest_format == GST_FORMAT_TIME) {
1769       if (src_value != -1)
1770         *dest_value =
1771             gst_util_uint64_scale (src_value, GST_SECOND,
1772             flacparse->samplerate);
1773       else
1774         *dest_value = -1;
1775       return TRUE;
1776     } else if (src_format == GST_FORMAT_TIME &&
1777         dest_format == GST_FORMAT_DEFAULT) {
1778       if (src_value != -1)
1779         *dest_value =
1780             gst_util_uint64_scale (src_value, flacparse->samplerate,
1781             GST_SECOND);
1782       else
1783         *dest_value = -1;
1784       return TRUE;
1785     }
1786   }
1787 
1788   return GST_BASE_PARSE_CLASS (parent_class)->convert (parse, src_format,
1789       src_value, dest_format, dest_value);
1790 }
1791 
1792 static gboolean
gst_flac_parse_src_event(GstBaseParse * parse,GstEvent * event)1793 gst_flac_parse_src_event (GstBaseParse * parse, GstEvent * event)
1794 {
1795   GstFlacParse *flacparse = GST_FLAC_PARSE (parse);
1796   gboolean res = FALSE;
1797 
1798   switch (GST_EVENT_TYPE (event)) {
1799     case GST_EVENT_TOC_SELECT:
1800     {
1801       GstTocEntry *entry = NULL;
1802       GstEvent *seek_event;
1803       GstToc *toc = NULL;
1804       gint64 start_pos;
1805       gchar *uid = NULL;
1806 
1807       /* FIXME: some locking would be good */
1808       if (flacparse->toc)
1809         toc = gst_toc_ref (flacparse->toc);
1810 
1811       if (toc != NULL) {
1812         gst_event_parse_toc_select (event, &uid);
1813         if (uid != NULL) {
1814           entry = gst_toc_find_entry (toc, uid);
1815           if (entry != NULL) {
1816             gst_toc_entry_get_start_stop_times (entry, &start_pos, NULL);
1817 
1818             /* FIXME: use segment rate here instead? */
1819             seek_event = gst_event_new_seek (1.0,
1820                 GST_FORMAT_TIME,
1821                 GST_SEEK_FLAG_FLUSH,
1822                 GST_SEEK_TYPE_SET, start_pos, GST_SEEK_TYPE_NONE, -1);
1823 
1824             res =
1825                 GST_BASE_PARSE_CLASS (parent_class)->src_event (parse,
1826                 seek_event);
1827 
1828           } else {
1829             GST_WARNING_OBJECT (parse, "no TOC entry with given UID: %s", uid);
1830           }
1831           g_free (uid);
1832         }
1833         gst_toc_unref (toc);
1834       } else {
1835         GST_DEBUG_OBJECT (flacparse, "no TOC to select");
1836       }
1837       gst_event_unref (event);
1838       break;
1839     }
1840     default:
1841       res = GST_BASE_PARSE_CLASS (parent_class)->src_event (parse, event);
1842       break;
1843   }
1844   return res;
1845 }
1846 
1847 static void
remove_fields(GstCaps * caps)1848 remove_fields (GstCaps * caps)
1849 {
1850   guint i, n;
1851 
1852   n = gst_caps_get_size (caps);
1853   for (i = 0; i < n; i++) {
1854     GstStructure *s = gst_caps_get_structure (caps, i);
1855 
1856     gst_structure_remove_field (s, "framed");
1857   }
1858 }
1859 
1860 static GstCaps *
gst_flac_parse_get_sink_caps(GstBaseParse * parse,GstCaps * filter)1861 gst_flac_parse_get_sink_caps (GstBaseParse * parse, GstCaps * filter)
1862 {
1863   GstCaps *peercaps, *templ;
1864   GstCaps *res;
1865 
1866   templ = gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD (parse));
1867   if (filter) {
1868     GstCaps *fcopy = gst_caps_copy (filter);
1869     /* Remove the fields we convert */
1870     remove_fields (fcopy);
1871     peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), fcopy);
1872     gst_caps_unref (fcopy);
1873   } else
1874     peercaps = gst_pad_peer_query_caps (GST_BASE_PARSE_SRC_PAD (parse), NULL);
1875 
1876   if (peercaps) {
1877     /* Remove the framed field */
1878     peercaps = gst_caps_make_writable (peercaps);
1879     remove_fields (peercaps);
1880 
1881     res = gst_caps_intersect_full (peercaps, templ, GST_CAPS_INTERSECT_FIRST);
1882     gst_caps_unref (peercaps);
1883     gst_caps_unref (templ);
1884   } else {
1885     res = templ;
1886   }
1887 
1888   if (filter) {
1889     GstCaps *intersection;
1890 
1891     intersection =
1892         gst_caps_intersect_full (filter, res, GST_CAPS_INTERSECT_FIRST);
1893     gst_caps_unref (res);
1894     res = intersection;
1895   }
1896 
1897   return res;
1898 }
1899 
1900 static gboolean
gst_flac_parse_set_sink_caps(GstBaseParse * parse,GstCaps * caps)1901 gst_flac_parse_set_sink_caps (GstBaseParse * parse, GstCaps * caps)
1902 {
1903   GstCaps *current_caps;
1904   GstFlacParse *flacparse = GST_FLAC_PARSE (parse);
1905 
1906   /* If caps are changing, drain any pending frames we have so that afterwards
1907    * we can potentially accept a new stream that is starting with the FLAC
1908    * headers again. If headers appear in the middle of the stream we can't
1909    * detect them
1910    */
1911   gst_base_parse_drain (parse);
1912 
1913   /* If the caps did really change we need to reset the parser */
1914   current_caps = gst_pad_get_current_caps (GST_BASE_PARSE_SINK_PAD (parse));
1915   if (current_caps) {
1916     if (!gst_caps_is_strictly_equal (caps, current_caps)) {
1917       GST_DEBUG_OBJECT (flacparse, "Reset parser on sink pad caps change");
1918       gst_flac_parse_stop (parse);
1919       gst_flac_parse_start (parse);
1920     }
1921     gst_caps_unref (current_caps);
1922   }
1923 
1924   return TRUE;
1925 }
1926