Branch data Line data Source code
1 : : /* GStreamer
2 : : * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 : : *
4 : : * This library is free software; you can redistribute it and/or
5 : : * modify it under the terms of the GNU Library General Public
6 : : * License as published by the Free Software Foundation; either
7 : : * version 2 of the License, or (at your option) any later version.
8 : : *
9 : : * This library is distributed in the hope that it will be useful,
10 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : : * Library General Public License for more details.
13 : : *
14 : : * You should have received a copy of the GNU Library General Public
15 : : * License along with this library; if not, write to the
16 : : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 : : * Boston, MA 02111-1307, USA.
18 : : */
19 : :
20 : : /**
21 : : * SECTION:element-mad
22 : : * @see_also: lame
23 : : *
24 : : * MP3 audio decoder.
25 : : *
26 : : * <refsect2>
27 : : * <title>Example pipelines</title>
28 : : * |[
29 : : * gst-launch filesrc location=music.mp3 ! mad ! audioconvert ! audioresample ! autoaudiosink
30 : : * ]| Decode the mp3 file and play
31 : : * </refsect2>
32 : : */
33 : :
34 : : #ifdef HAVE_CONFIG_H
35 : : #include "config.h"
36 : : #endif
37 : :
38 : : #include <stdlib.h>
39 : : #include <string.h>
40 : : #include "gstmad.h"
41 : : #include <gst/audio/audio.h>
42 : :
43 : : #ifdef HAVE_ID3TAG
44 : : #include <id3tag.h>
45 : : #endif
46 : :
47 : : enum
48 : : {
49 : : ARG_0,
50 : : ARG_HALF,
51 : : ARG_IGNORE_CRC
52 : : };
53 : :
54 : : GST_DEBUG_CATEGORY_STATIC (mad_debug);
55 : : #define GST_CAT_DEFAULT mad_debug
56 : :
57 : : static GstStaticPadTemplate mad_src_template_factory =
58 : : GST_STATIC_PAD_TEMPLATE ("src",
59 : : GST_PAD_SRC,
60 : : GST_PAD_ALWAYS,
61 : : GST_STATIC_CAPS ("audio/x-raw-int, "
62 : : "endianness = (int) " G_STRINGIFY (G_BYTE_ORDER) ", "
63 : : "signed = (boolean) true, "
64 : : "width = (int) 32, "
65 : : "depth = (int) 32, "
66 : : "rate = (int) { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 }, "
67 : : "channels = (int) [ 1, 2 ]")
68 : : );
69 : :
70 : : /* FIXME: make three caps, for mpegversion 1, 2 and 2.5 */
71 : : static GstStaticPadTemplate mad_sink_template_factory =
72 : : GST_STATIC_PAD_TEMPLATE ("sink",
73 : : GST_PAD_SINK,
74 : : GST_PAD_ALWAYS,
75 : : GST_STATIC_CAPS ("audio/mpeg, "
76 : : "mpegversion = (int) 1, "
77 : : "layer = (int) [ 1, 3 ], "
78 : : "rate = (int) { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 }, "
79 : : "channels = (int) [ 1, 2 ]")
80 : : );
81 : :
82 : : static void gst_mad_dispose (GObject * object);
83 : : static void gst_mad_clear_queues (GstMad * mad);
84 : :
85 : : static void gst_mad_set_property (GObject * object, guint prop_id,
86 : : const GValue * value, GParamSpec * pspec);
87 : : static void gst_mad_get_property (GObject * object, guint prop_id,
88 : : GValue * value, GParamSpec * pspec);
89 : :
90 : : static gboolean gst_mad_src_event (GstPad * pad, GstEvent * event);
91 : :
92 : : static const GstQueryType *gst_mad_get_query_types (GstPad * pad);
93 : :
94 : : static gboolean gst_mad_src_query (GstPad * pad, GstQuery * query);
95 : : static gboolean gst_mad_convert_sink (GstPad * pad, GstFormat src_format,
96 : : gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
97 : : static gboolean gst_mad_convert_src (GstPad * pad, GstFormat src_format,
98 : : gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
99 : :
100 : : static gboolean gst_mad_sink_event (GstPad * pad, GstEvent * event);
101 : : static GstFlowReturn gst_mad_chain (GstPad * pad, GstBuffer * buffer);
102 : : static GstFlowReturn gst_mad_chain_reverse (GstMad * mad, GstBuffer * buf);
103 : :
104 : : static GstStateChangeReturn gst_mad_change_state (GstElement * element,
105 : : GstStateChange transition);
106 : :
107 : : static void gst_mad_set_index (GstElement * element, GstIndex * index);
108 : : static GstIndex *gst_mad_get_index (GstElement * element);
109 : :
110 : : #ifdef HAVE_ID3TAG
111 : : static GstTagList *gst_mad_id3_to_tag_list (const struct id3_tag *tag);
112 : : #endif
113 : :
114 [ + + ]: 50 : GST_BOILERPLATE (GstMad, gst_mad, GstElement, GST_TYPE_ELEMENT);
115 : :
116 : : /*
117 : : #define GST_TYPE_MAD_LAYER (gst_mad_layer_get_type())
118 : : static GType
119 : : gst_mad_layer_get_type (void)
120 : : {
121 : : static GType mad_layer_type = 0;
122 : : static GEnumValue mad_layer[] = {
123 : : {0, "Unknown", "unknown"},
124 : : {MAD_LAYER_I, "Layer I", "1"},
125 : : {MAD_LAYER_II, "Layer II", "2"},
126 : : {MAD_LAYER_III, "Layer III", "3"},
127 : : {0, NULL, NULL},
128 : : };
129 : :
130 : : if (!mad_layer_type) {
131 : : mad_layer_type = g_enum_register_static ("GstMadLayer", mad_layer);
132 : : }
133 : : return mad_layer_type;
134 : : }
135 : : */
136 : :
137 : : #define GST_TYPE_MAD_MODE (gst_mad_mode_get_type())
138 : : static GType
139 : 5 : gst_mad_mode_get_type (void)
140 : : {
141 : : static GType mad_mode_type = 0;
142 : : static GEnumValue mad_mode[] = {
143 : : {-1, "Unknown", "unknown"},
144 : : {MAD_MODE_SINGLE_CHANNEL, "Mono", "mono"},
145 : : {MAD_MODE_DUAL_CHANNEL, "Dual Channel", "dual"},
146 : : {MAD_MODE_JOINT_STEREO, "Joint Stereo", "joint"},
147 : : {MAD_MODE_STEREO, "Stereo", "stereo"},
148 : : {0, NULL, NULL},
149 : : };
150 : :
151 [ + - ]: 5 : if (!mad_mode_type) {
152 : 5 : mad_mode_type = g_enum_register_static ("GstMadMode", mad_mode);
153 : : }
154 : 5 : return mad_mode_type;
155 : : }
156 : :
157 : : #define GST_TYPE_MAD_EMPHASIS (gst_mad_emphasis_get_type())
158 : : static GType
159 : 5 : gst_mad_emphasis_get_type (void)
160 : : {
161 : : static GType mad_emphasis_type = 0;
162 : : static GEnumValue mad_emphasis[] = {
163 : : {-1, "Unknown", "unknown"},
164 : : {MAD_EMPHASIS_NONE, "None", "none"},
165 : : {MAD_EMPHASIS_50_15_US, "50/15 Microseconds", "50-15"},
166 : : {MAD_EMPHASIS_CCITT_J_17, "CCITT J.17", "j-17"},
167 : : {MAD_EMPHASIS_RESERVED, "Reserved", "reserved"},
168 : : {0, NULL, NULL},
169 : : };
170 : :
171 [ + - ]: 5 : if (!mad_emphasis_type) {
172 : 5 : mad_emphasis_type = g_enum_register_static ("GstMadEmphasis", mad_emphasis);
173 : : }
174 : 5 : return mad_emphasis_type;
175 : : }
176 : :
177 : : static void
178 : 5 : gst_mad_base_init (gpointer g_class)
179 : : {
180 : 5 : GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
181 : :
182 : 5 : gst_element_class_add_pad_template (element_class,
183 : : gst_static_pad_template_get (&mad_sink_template_factory));
184 : 5 : gst_element_class_add_pad_template (element_class,
185 : : gst_static_pad_template_get (&mad_src_template_factory));
186 : 5 : gst_element_class_set_details_simple (element_class, "mad mp3 decoder",
187 : : "Codec/Decoder/Audio",
188 : : "Uses mad code to decode mp3 streams", "Wim Taymans <wim@fluendo.com>");
189 : 5 : }
190 : :
191 : : static void
192 : 5 : gst_mad_class_init (GstMadClass * klass)
193 : : {
194 : : GObjectClass *gobject_class;
195 : : GstElementClass *gstelement_class;
196 : :
197 : 5 : gobject_class = (GObjectClass *) klass;
198 : 5 : gstelement_class = (GstElementClass *) klass;
199 : :
200 : 5 : parent_class = g_type_class_peek_parent (klass);
201 : :
202 : 5 : gobject_class->set_property = gst_mad_set_property;
203 : 5 : gobject_class->get_property = gst_mad_get_property;
204 : 5 : gobject_class->dispose = gst_mad_dispose;
205 : :
206 : 5 : gstelement_class->change_state = gst_mad_change_state;
207 : 5 : gstelement_class->set_index = gst_mad_set_index;
208 : 5 : gstelement_class->get_index = gst_mad_get_index;
209 : :
210 : : /* init properties */
211 : : /* currently, string representations are used, we might want to change that */
212 : : /* FIXME: descriptions need to be more technical,
213 : : * default values and ranges need to be selected right */
214 : 5 : g_object_class_install_property (gobject_class, ARG_HALF,
215 : : g_param_spec_boolean ("half", "Half", "Generate PCM at 1/2 sample rate",
216 : : FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
217 : 5 : g_object_class_install_property (gobject_class, ARG_IGNORE_CRC,
218 : : g_param_spec_boolean ("ignore-crc", "Ignore CRC", "Ignore CRC errors",
219 : : TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
220 : :
221 : : /* register tags */
222 : : #define GST_TAG_LAYER "layer"
223 : : #define GST_TAG_MODE "mode"
224 : : #define GST_TAG_EMPHASIS "emphasis"
225 : :
226 : : /* FIXME 0.11: strings!? why? */
227 : 5 : gst_tag_register (GST_TAG_LAYER, GST_TAG_FLAG_ENCODED, G_TYPE_UINT,
228 : : "layer", "MPEG audio layer", NULL);
229 : 5 : gst_tag_register (GST_TAG_MODE, GST_TAG_FLAG_ENCODED, G_TYPE_STRING,
230 : : "mode", "MPEG audio channel mode", NULL);
231 : 5 : gst_tag_register (GST_TAG_EMPHASIS, GST_TAG_FLAG_ENCODED, G_TYPE_STRING,
232 : : "emphasis", "MPEG audio emphasis", NULL);
233 : :
234 : : /* ref these here from a thread-safe context (ie. not the streaming thread) */
235 : 5 : g_type_class_ref (GST_TYPE_MAD_MODE);
236 : 5 : g_type_class_ref (GST_TYPE_MAD_EMPHASIS);
237 : 5 : }
238 : :
239 : : static void
240 : 3 : gst_mad_init (GstMad * mad, GstMadClass * klass)
241 : : {
242 : : GstPadTemplate *template;
243 : :
244 : : /* create the sink and src pads */
245 : 3 : template = gst_static_pad_template_get (&mad_sink_template_factory);
246 : 3 : mad->sinkpad = gst_pad_new_from_template (template, "sink");
247 : 3 : gst_object_unref (template);
248 : 3 : gst_element_add_pad (GST_ELEMENT (mad), mad->sinkpad);
249 : 3 : gst_pad_set_chain_function (mad->sinkpad, GST_DEBUG_FUNCPTR (gst_mad_chain));
250 : 3 : gst_pad_set_event_function (mad->sinkpad,
251 : 3 : GST_DEBUG_FUNCPTR (gst_mad_sink_event));
252 : :
253 : 3 : template = gst_static_pad_template_get (&mad_src_template_factory);
254 : 3 : mad->srcpad = gst_pad_new_from_template (template, "src");
255 : 3 : gst_object_unref (template);
256 : 3 : gst_element_add_pad (GST_ELEMENT (mad), mad->srcpad);
257 : 3 : gst_pad_set_event_function (mad->srcpad,
258 : 3 : GST_DEBUG_FUNCPTR (gst_mad_src_event));
259 : 3 : gst_pad_set_query_function (mad->srcpad,
260 : 3 : GST_DEBUG_FUNCPTR (gst_mad_src_query));
261 : 3 : gst_pad_set_query_type_function (mad->srcpad,
262 : 3 : GST_DEBUG_FUNCPTR (gst_mad_get_query_types));
263 : 3 : gst_pad_use_fixed_caps (mad->srcpad);
264 : :
265 : 3 : mad->tempbuffer = g_malloc (MAD_BUFFER_MDLEN * 3);
266 : 3 : mad->tempsize = 0;
267 : 3 : mad->base_byte_offset = 0;
268 : 3 : mad->bytes_consumed = 0;
269 : 3 : mad->total_samples = 0;
270 : 3 : mad->new_header = TRUE;
271 : 3 : mad->framecount = 0;
272 : 3 : mad->vbr_average = 0;
273 : 3 : mad->vbr_rate = 0;
274 : 3 : mad->restart = TRUE;
275 : 3 : mad->segment_start = 0;
276 : 3 : gst_segment_init (&mad->segment, GST_FORMAT_TIME);
277 : 3 : mad->header.mode = -1;
278 : 3 : mad->header.emphasis = -1;
279 : 3 : mad->tags = NULL;
280 : :
281 : 3 : mad->half = FALSE;
282 : 3 : mad->ignore_crc = TRUE;
283 : 3 : mad->check_for_xing = TRUE;
284 : 3 : mad->xing_found = FALSE;
285 : 3 : }
286 : :
287 : : static void
288 : 3 : gst_mad_dispose (GObject * object)
289 : : {
290 : 3 : GstMad *mad = GST_MAD (object);
291 : :
292 : 3 : gst_mad_set_index (GST_ELEMENT (object), NULL);
293 : :
294 : 3 : g_free (mad->tempbuffer);
295 : 3 : mad->tempbuffer = NULL;
296 : :
297 : 3 : g_list_foreach (mad->pending_events, (GFunc) gst_mini_object_unref, NULL);
298 : 3 : g_list_free (mad->pending_events);
299 : 3 : mad->pending_events = NULL;
300 : :
301 : 3 : G_OBJECT_CLASS (parent_class)->dispose (object);
302 : 3 : }
303 : :
304 : : static void
305 : 3 : gst_mad_set_index (GstElement * element, GstIndex * index)
306 : : {
307 : 3 : GstMad *mad = GST_MAD (element);
308 : :
309 : 3 : mad->index = index;
310 : :
311 [ - + ]: 3 : if (index)
312 : 0 : gst_index_get_writer_id (index, GST_OBJECT (element), &mad->index_id);
313 : 3 : }
314 : :
315 : : static GstIndex *
316 : 0 : gst_mad_get_index (GstElement * element)
317 : : {
318 : 0 : GstMad *mad = GST_MAD (element);
319 : :
320 : 0 : return mad->index;
321 : : }
322 : :
323 : : static gboolean
324 : 0 : gst_mad_convert_sink (GstPad * pad, GstFormat src_format, gint64 src_value,
325 : : GstFormat * dest_format, gint64 * dest_value)
326 : : {
327 : 0 : gboolean res = TRUE;
328 : : GstMad *mad;
329 : :
330 [ # # ]: 0 : if (src_format == *dest_format) {
331 : 0 : *dest_value = src_value;
332 : 0 : return TRUE;
333 : : }
334 : :
335 : : /* -1 always maps to -1, and 0 to 0, we don't need any more info for that */
336 [ # # ][ # # ]: 0 : if (src_value == -1 || src_value == 0) {
337 : 0 : *dest_value = src_value;
338 : 0 : return TRUE;
339 : : }
340 : :
341 : 0 : mad = GST_MAD (GST_PAD_PARENT (pad));
342 : :
343 [ # # ]: 0 : if (mad->vbr_average == 0)
344 : 0 : return FALSE;
345 : :
346 [ # # # ]: 0 : switch (src_format) {
347 : : case GST_FORMAT_BYTES:
348 [ # # ]: 0 : switch (*dest_format) {
349 : : case GST_FORMAT_TIME:
350 : : /* multiply by 8 because vbr is in bits/second */
351 : 0 : *dest_value = gst_util_uint64_scale (src_value, 8 * GST_SECOND,
352 : 0 : mad->vbr_average);
353 : 0 : break;
354 : : default:
355 : 0 : res = FALSE;
356 : : }
357 : 0 : break;
358 : : case GST_FORMAT_TIME:
359 [ # # ]: 0 : switch (*dest_format) {
360 : : case GST_FORMAT_BYTES:
361 : : /* multiply by 8 because vbr is in bits/second */
362 : 0 : *dest_value = gst_util_uint64_scale (src_value, mad->vbr_average,
363 : : 8 * GST_SECOND);
364 : 0 : break;
365 : : default:
366 : 0 : res = FALSE;
367 : : }
368 : 0 : break;
369 : : default:
370 : 0 : res = FALSE;
371 : : }
372 : 0 : return res;
373 : : }
374 : :
375 : : static gboolean
376 : 0 : gst_mad_convert_src (GstPad * pad, GstFormat src_format, gint64 src_value,
377 : : GstFormat * dest_format, gint64 * dest_value)
378 : : {
379 : 0 : gboolean res = TRUE;
380 : 0 : guint scale = 1;
381 : : gint bytes_per_sample;
382 : : GstMad *mad;
383 : :
384 [ # # ]: 0 : if (src_format == *dest_format) {
385 : 0 : *dest_value = src_value;
386 : 0 : return TRUE;
387 : : }
388 : :
389 : : /* -1 always maps to -1, and 0 to 0, we don't need any more info for that */
390 [ # # ][ # # ]: 0 : if (src_value == -1 || src_value == 0) {
391 : 0 : *dest_value = src_value;
392 : 0 : return TRUE;
393 : : }
394 : :
395 : 0 : mad = GST_MAD (GST_PAD_PARENT (pad));
396 : :
397 : 0 : bytes_per_sample = mad->channels * 4;
398 : :
399 [ # # # # ]: 0 : switch (src_format) {
400 : : case GST_FORMAT_BYTES:
401 [ # # # ]: 0 : switch (*dest_format) {
402 : : case GST_FORMAT_DEFAULT:
403 [ # # ]: 0 : if (bytes_per_sample == 0)
404 : 0 : return FALSE;
405 : 0 : *dest_value = src_value / bytes_per_sample;
406 : 0 : break;
407 : : case GST_FORMAT_TIME:
408 : : {
409 : 0 : gint byterate = bytes_per_sample * mad->rate;
410 : :
411 [ # # ]: 0 : if (byterate == 0)
412 : 0 : return FALSE;
413 : 0 : *dest_value =
414 : 0 : gst_util_uint64_scale_int (src_value, GST_SECOND, byterate);
415 : 0 : break;
416 : : }
417 : : default:
418 : 0 : res = FALSE;
419 : : }
420 : 0 : break;
421 : : case GST_FORMAT_DEFAULT:
422 [ # # # ]: 0 : switch (*dest_format) {
423 : : case GST_FORMAT_BYTES:
424 : 0 : *dest_value = src_value * bytes_per_sample;
425 : 0 : break;
426 : : case GST_FORMAT_TIME:
427 [ # # ]: 0 : if (mad->rate == 0)
428 : 0 : return FALSE;
429 : 0 : *dest_value = gst_util_uint64_scale_int (src_value, GST_SECOND,
430 : : mad->rate);
431 : 0 : break;
432 : : default:
433 : 0 : res = FALSE;
434 : : }
435 : 0 : break;
436 : : case GST_FORMAT_TIME:
437 [ # # # ]: 0 : switch (*dest_format) {
438 : : case GST_FORMAT_BYTES:
439 : 0 : scale = bytes_per_sample;
440 : : /* fallthrough */
441 : : case GST_FORMAT_DEFAULT:
442 : 0 : *dest_value = gst_util_uint64_scale_int (src_value,
443 : 0 : scale * mad->rate, GST_SECOND);
444 : 0 : break;
445 : : default:
446 : 0 : res = FALSE;
447 : : }
448 : 0 : break;
449 : : default:
450 : 0 : res = FALSE;
451 : : }
452 : 0 : return res;
453 : : }
454 : :
455 : : static const GstQueryType *
456 : 0 : gst_mad_get_query_types (GstPad * pad)
457 : : {
458 : : static const GstQueryType gst_mad_src_query_types[] = {
459 : : GST_QUERY_POSITION,
460 : : GST_QUERY_DURATION,
461 : : GST_QUERY_CONVERT,
462 : : 0
463 : : };
464 : :
465 : 0 : return gst_mad_src_query_types;
466 : : }
467 : :
468 : : static gboolean
469 : 0 : gst_mad_src_query (GstPad * pad, GstQuery * query)
470 : : {
471 : 0 : gboolean res = TRUE;
472 : : GstPad *peer;
473 : : GstMad *mad;
474 : :
475 : 0 : mad = GST_MAD (GST_PAD_PARENT (pad));
476 : :
477 : 0 : peer = gst_pad_get_peer (mad->sinkpad);
478 : :
479 [ # # # # : 0 : switch (GST_QUERY_TYPE (query)) {
# ]
480 : : case GST_QUERY_FORMATS:
481 : 0 : gst_query_set_formats (query, 3, GST_FORMAT_DEFAULT, GST_FORMAT_TIME,
482 : : GST_FORMAT_BYTES);
483 : 0 : break;
484 : : case GST_QUERY_POSITION:
485 : : {
486 : : GstFormat format;
487 : : gint64 cur;
488 : :
489 : : /* save requested format */
490 : 0 : gst_query_parse_position (query, &format, NULL);
491 : :
492 : : /* try any demuxer before us first */
493 [ # # ][ # # ]: 0 : if (format == GST_FORMAT_TIME && peer && gst_pad_query (peer, query)) {
[ # # ]
494 : 0 : gst_query_parse_position (query, NULL, &cur);
495 [ # # ][ # # ]: 0 : GST_LOG_OBJECT (mad, "peer returned position %" GST_TIME_FORMAT,
[ # # ][ # # ]
[ # # ]
496 : : GST_TIME_ARGS (cur));
497 : 0 : break;
498 : : }
499 : :
500 : : /* and convert to the requested format */
501 [ # # ]: 0 : if (format != GST_FORMAT_DEFAULT) {
502 [ # # ]: 0 : if (!gst_mad_convert_src (pad, GST_FORMAT_DEFAULT, mad->total_samples,
503 : : &format, &cur))
504 : 0 : goto error;
505 : : } else {
506 : 0 : cur = mad->total_samples;
507 : : }
508 : :
509 : 0 : gst_query_set_position (query, format, cur);
510 : :
511 [ # # ]: 0 : if (format == GST_FORMAT_TIME) {
512 [ # # ][ # # ]: 0 : GST_LOG ("position=%" GST_TIME_FORMAT, GST_TIME_ARGS (cur));
[ # # ][ # # ]
[ # # ]
513 : : } else {
514 [ # # ]: 0 : GST_LOG ("position=%" G_GINT64_FORMAT ", format=%u", cur, format);
515 : : }
516 : 0 : break;
517 : : }
518 : : case GST_QUERY_DURATION:
519 : : {
520 : 0 : GstFormat bytes_format = GST_FORMAT_BYTES;
521 : 0 : GstFormat time_format = GST_FORMAT_TIME;
522 : : GstFormat req_format;
523 : : gint64 total, total_bytes;
524 : :
525 : : /* save requested format */
526 : 0 : gst_query_parse_duration (query, &req_format, NULL);
527 : :
528 [ # # ]: 0 : if (peer == NULL)
529 : 0 : goto error;
530 : :
531 : : /* try any demuxer before us first */
532 [ # # ][ # # ]: 0 : if (req_format == GST_FORMAT_TIME && gst_pad_query (peer, query)) {
533 : 0 : gst_query_parse_duration (query, NULL, &total);
534 [ # # ][ # # ]: 0 : GST_LOG_OBJECT (mad, "peer returned duration %" GST_TIME_FORMAT,
[ # # ][ # # ]
[ # # ]
535 : : GST_TIME_ARGS (total));
536 : 0 : break;
537 : : }
538 : :
539 : : /* query peer for total length in bytes */
540 [ # # ]: 0 : if (!gst_pad_query_peer_duration (mad->sinkpad, &bytes_format,
541 [ # # ]: 0 : &total_bytes) || total_bytes <= 0) {
542 [ # # ]: 0 : GST_LOG_OBJECT (mad, "duration query on peer pad failed");
543 : 0 : goto error;
544 : : }
545 : :
546 [ # # ]: 0 : GST_LOG_OBJECT (mad, "peer pad returned total=%" G_GINT64_FORMAT
547 : : " bytes", total_bytes);
548 : :
549 [ # # ]: 0 : if (!gst_mad_convert_sink (pad, GST_FORMAT_BYTES, total_bytes,
550 : : &time_format, &total)) {
551 [ # # ]: 0 : GST_DEBUG_OBJECT (mad, "conversion BYTE => TIME failed");
552 : 0 : goto error;
553 : : }
554 [ # # ]: 0 : if (!gst_mad_convert_src (pad, GST_FORMAT_TIME, total,
555 : : &req_format, &total)) {
556 [ # # ]: 0 : GST_DEBUG_OBJECT (mad, "conversion TIME => %s failed",
557 : : gst_format_get_name (req_format));
558 : 0 : goto error;
559 : : }
560 : :
561 : 0 : gst_query_set_duration (query, req_format, total);
562 : :
563 [ # # ]: 0 : if (req_format == GST_FORMAT_TIME) {
564 [ # # ][ # # ]: 0 : GST_LOG_OBJECT (mad, "duration=%" GST_TIME_FORMAT,
[ # # ][ # # ]
[ # # ]
565 : : GST_TIME_ARGS (total));
566 : : } else {
567 [ # # ]: 0 : GST_LOG_OBJECT (mad, "duration=%" G_GINT64_FORMAT " (%s)",
568 : : total, gst_format_get_name (req_format));
569 : : }
570 : 0 : break;
571 : : }
572 : : case GST_QUERY_CONVERT:
573 : : {
574 : : GstFormat src_fmt, dest_fmt;
575 : : gint64 src_val, dest_val;
576 : :
577 : 0 : gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
578 [ # # ]: 0 : if (!(res =
579 : 0 : gst_mad_convert_src (pad, src_fmt, src_val, &dest_fmt,
580 : : &dest_val)))
581 : 0 : goto error;
582 : 0 : gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
583 : 0 : break;
584 : : }
585 : : default:
586 : 0 : res = gst_pad_query_default (pad, query);
587 : 0 : break;
588 : : }
589 : :
590 [ # # ]: 0 : if (peer)
591 : 0 : gst_object_unref (peer);
592 : :
593 : 0 : return res;
594 : :
595 : : error:
596 : :
597 [ # # ]: 0 : GST_DEBUG ("error handling query");
598 : :
599 [ # # ]: 0 : if (peer)
600 : 0 : gst_object_unref (peer);
601 : :
602 : 0 : return FALSE;
603 : : }
604 : :
605 : : static gboolean
606 : 0 : index_seek (GstMad * mad, GstPad * pad, GstEvent * event)
607 : : {
608 : : gdouble rate;
609 : : GstFormat format;
610 : : GstSeekFlags flags;
611 : : GstSeekType cur_type, stop_type;
612 : : gint64 cur, stop;
613 : 0 : GstIndexEntry *entry = NULL;
614 : :
615 : : /* since we know the exact byteoffset of the frame,
616 : : make sure to try bytes first */
617 : :
618 : 0 : const GstFormat try_all_formats[] = {
619 : : GST_FORMAT_BYTES,
620 : : GST_FORMAT_TIME,
621 : : 0
622 : : };
623 : 0 : const GstFormat *try_formats = try_all_formats;
624 : : const GstFormat *peer_formats;
625 : :
626 : 0 : gst_event_parse_seek (event, &rate, &format, &flags,
627 : : &cur_type, &cur, &stop_type, &stop);
628 : :
629 [ # # ]: 0 : if (rate < 0.0)
630 : 0 : return FALSE;
631 : :
632 [ # # ]: 0 : if (format == GST_FORMAT_TIME) {
633 : 0 : gst_segment_set_seek (&mad->segment, rate, format, flags, cur_type,
634 : : cur, stop_type, stop, NULL);
635 : : } else {
636 : 0 : gst_segment_init (&mad->segment, GST_FORMAT_UNDEFINED);
637 : : }
638 : :
639 : 0 : entry = gst_index_get_assoc_entry (mad->index, mad->index_id,
640 : : GST_INDEX_LOOKUP_BEFORE, 0, format, cur);
641 : :
642 [ # # ]: 0 : GST_DEBUG ("index seek");
643 : :
644 [ # # ]: 0 : if (!entry)
645 : 0 : return FALSE;
646 : :
647 : : #if 0
648 : : peer_formats = gst_pad_get_formats (GST_PAD_PEER (mad->sinkpad));
649 : : #else
650 : 0 : peer_formats = try_all_formats; /* FIXME */
651 : : #endif
652 : :
653 [ # # ]: 0 : while (gst_formats_contains (peer_formats, *try_formats)) {
654 : : gint64 value;
655 : : GstEvent *seek_event;
656 : :
657 [ # # ]: 0 : if (gst_index_entry_assoc_map (entry, *try_formats, &value)) {
658 : : /* lookup succeeded, create the seek */
659 : :
660 [ # # ]: 0 : GST_DEBUG ("index %s %" G_GINT64_FORMAT
661 : : " -> %s %" G_GINT64_FORMAT,
662 : : gst_format_get_details (format)->nick,
663 : : cur, gst_format_get_details (*try_formats)->nick, value);
664 : :
665 : 0 : seek_event = gst_event_new_seek (rate, *try_formats, flags,
666 : : cur_type, value, stop_type, stop);
667 : :
668 [ # # ]: 0 : if (gst_pad_send_event (GST_PAD_PEER (mad->sinkpad), seek_event)) {
669 : : /* seek worked, we're done, loop will exit */
670 : 0 : mad->restart = TRUE;
671 [ # # ]: 0 : g_assert (format == GST_FORMAT_TIME);
672 : 0 : mad->segment_start = cur;
673 : 0 : return TRUE;
674 : : }
675 : : }
676 : 0 : try_formats++;
677 : : }
678 : :
679 : 0 : return FALSE;
680 : : }
681 : :
682 : : static gboolean
683 : 0 : normal_seek (GstMad * mad, GstPad * pad, GstEvent * event)
684 : : {
685 : : gdouble rate;
686 : : GstFormat format, conv;
687 : : GstSeekFlags flags;
688 : : GstSeekType cur_type, stop_type;
689 : : gint64 cur, stop;
690 : : gint64 time_cur, time_stop;
691 : : gint64 bytes_cur, bytes_stop;
692 : : gboolean flush;
693 : :
694 : : /* const GstFormat *peer_formats; */
695 : : gboolean res;
696 : :
697 [ # # ]: 0 : GST_DEBUG ("normal seek");
698 : :
699 : 0 : gst_event_parse_seek (event, &rate, &format, &flags,
700 : : &cur_type, &cur, &stop_type, &stop);
701 : :
702 [ # # ]: 0 : if (rate < 0.0)
703 : 0 : return FALSE;
704 : :
705 [ # # ]: 0 : if (format != GST_FORMAT_TIME) {
706 : 0 : conv = GST_FORMAT_TIME;
707 [ # # ]: 0 : if (!gst_mad_convert_src (pad, format, cur, &conv, &time_cur))
708 : 0 : goto convert_error;
709 [ # # ]: 0 : if (!gst_mad_convert_src (pad, format, stop, &conv, &time_stop))
710 : 0 : goto convert_error;
711 : : } else {
712 : 0 : time_cur = cur;
713 : 0 : time_stop = stop;
714 : : }
715 : :
716 : 0 : gst_segment_set_seek (&mad->segment, rate, GST_FORMAT_TIME, flags, cur_type,
717 : : time_cur, stop_type, time_stop, NULL);
718 : :
719 [ # # ][ # # ]: 0 : GST_DEBUG ("seek to time %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
720 : : GST_TIME_ARGS (time_cur), GST_TIME_ARGS (time_stop));
721 : :
722 : : /* shave off the flush flag, we'll need it later */
723 : 0 : flush = ((flags & GST_SEEK_FLAG_FLUSH) != 0);
724 : :
725 : 0 : conv = GST_FORMAT_BYTES;
726 [ # # ]: 0 : if (!gst_mad_convert_sink (pad, GST_FORMAT_TIME, time_cur, &conv, &bytes_cur))
727 : 0 : goto convert_error;
728 [ # # ]: 0 : if (!gst_mad_convert_sink (pad, GST_FORMAT_TIME, time_stop, &conv,
729 : : &bytes_stop))
730 : 0 : goto convert_error;
731 : :
732 : : {
733 : : GstEvent *seek_event;
734 : :
735 : : /* conversion succeeded, create the seek */
736 : 0 : seek_event =
737 : 0 : gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type,
738 : : bytes_cur, stop_type, bytes_stop);
739 : :
740 : : /* do the seek */
741 : 0 : res = gst_pad_push_event (mad->sinkpad, seek_event);
742 : :
743 [ # # ]: 0 : if (res) {
744 : : /* we need to break out of the processing loop on flush */
745 : 0 : mad->restart = flush;
746 : 0 : mad->segment_start = time_cur;
747 : 0 : mad->last_ts = time_cur;
748 : : }
749 : : }
750 : : #if 0
751 : : peer_formats = gst_pad_get_formats (GST_PAD_PEER (mad->sinkpad));
752 : : /* while we did not exhaust our seek formats without result */
753 : : while (peer_formats && *peer_formats && !res) {
754 : : gint64 desired_offset;
755 : :
756 : : format = *peer_formats;
757 : :
758 : : /* try to convert requested format to one we can seek with on the sinkpad */
759 : : if (gst_pad_convert (mad->sinkpad, GST_FORMAT_TIME, src_offset,
760 : : &format, &desired_offset)) {
761 : : GstEvent *seek_event;
762 : :
763 : : /* conversion succeeded, create the seek */
764 : : seek_event =
765 : : gst_event_new_seek (format | GST_EVENT_SEEK_METHOD (event) | flush,
766 : : desired_offset);
767 : : /* do the seek */
768 : : if (gst_pad_send_event (GST_PAD_PEER (mad->sinkpad), seek_event)) {
769 : : /* seek worked, we're done, loop will exit */
770 : : res = TRUE;
771 : : }
772 : : }
773 : : /* at this point, either the seek worked or res == FALSE */
774 : : if (res)
775 : : /* we need to break out of the processing loop on flush */
776 : : mad->restart = flush;
777 : :
778 : : peer_formats++;
779 : : }
780 : : #endif
781 : :
782 : 0 : return res;
783 : :
784 : : /* ERRORS */
785 : : convert_error:
786 : : {
787 : : /* probably unsupported seek format */
788 [ # # ]: 0 : GST_DEBUG ("failed to convert format %u into GST_FORMAT_TIME", format);
789 : 0 : return FALSE;
790 : : }
791 : : }
792 : :
793 : : static gboolean
794 : 0 : gst_mad_src_event (GstPad * pad, GstEvent * event)
795 : : {
796 : 0 : gboolean res = TRUE;
797 : : GstMad *mad;
798 : :
799 : 0 : mad = GST_MAD (GST_PAD_PARENT (pad));
800 : :
801 [ # # ]: 0 : switch (GST_EVENT_TYPE (event)) {
802 : : case GST_EVENT_SEEK:
803 : : /* the all-formats seek logic, ref the event, we need it later */
804 : 0 : gst_event_ref (event);
805 [ # # ]: 0 : if (!(res = gst_pad_push_event (mad->sinkpad, event))) {
806 [ # # ]: 0 : if (mad->index)
807 : 0 : res = index_seek (mad, pad, event);
808 : : else
809 : 0 : res = normal_seek (mad, pad, event);
810 : : }
811 : 0 : gst_event_unref (event);
812 : 0 : break;
813 : : default:
814 : 0 : res = gst_pad_push_event (mad->sinkpad, event);
815 : 0 : break;
816 : : }
817 : :
818 : 0 : return res;
819 : : }
820 : :
821 : : static inline gint32
822 : 0 : scale (mad_fixed_t sample)
823 : : {
824 : : #if MAD_F_FRACBITS < 28
825 : : /* round */
826 : : sample += (1L << (28 - MAD_F_FRACBITS - 1));
827 : : #endif
828 : :
829 : : /* clip */
830 [ # # ]: 0 : if (sample >= MAD_F_ONE)
831 : 0 : sample = MAD_F_ONE - 1;
832 [ # # ]: 0 : else if (sample < -MAD_F_ONE)
833 : 0 : sample = -MAD_F_ONE;
834 : :
835 : : #if MAD_F_FRACBITS < 28
836 : : /* quantize */
837 : : sample >>= (28 - MAD_F_FRACBITS);
838 : : #endif
839 : :
840 : : /* convert from 29 bits to 32 bits */
841 : 0 : return (gint32) (sample << 3);
842 : : }
843 : :
844 : : /* do we need this function? */
845 : : static void
846 : 0 : gst_mad_set_property (GObject * object, guint prop_id,
847 : : const GValue * value, GParamSpec * pspec)
848 : : {
849 : : GstMad *mad;
850 : :
851 : 0 : mad = GST_MAD (object);
852 : :
853 [ # # # ]: 0 : switch (prop_id) {
854 : : case ARG_HALF:
855 : 0 : mad->half = g_value_get_boolean (value);
856 : 0 : break;
857 : : case ARG_IGNORE_CRC:
858 : 0 : mad->ignore_crc = g_value_get_boolean (value);
859 : 0 : break;
860 : : default:
861 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
862 : 0 : break;
863 : : }
864 : 0 : }
865 : :
866 : : static void
867 : 0 : gst_mad_get_property (GObject * object, guint prop_id,
868 : : GValue * value, GParamSpec * pspec)
869 : : {
870 : : GstMad *mad;
871 : :
872 : 0 : mad = GST_MAD (object);
873 : :
874 [ # # # ]: 0 : switch (prop_id) {
875 : : case ARG_HALF:
876 : 0 : g_value_set_boolean (value, mad->half);
877 : 0 : break;
878 : : case ARG_IGNORE_CRC:
879 : 0 : g_value_set_boolean (value, mad->ignore_crc);
880 : 0 : break;
881 : : default:
882 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
883 : 0 : break;
884 : : }
885 : 0 : }
886 : :
887 : : static void
888 : 0 : gst_mad_update_info (GstMad * mad)
889 : : {
890 : 0 : struct mad_header *header = &mad->frame.header;
891 : 0 : gboolean changed = FALSE;
892 : :
893 : : #define CHECK_HEADER(h1,str) \
894 : : G_STMT_START{ \
895 : : if (mad->header.h1 != header->h1 || mad->new_header) { \
896 : : mad->header.h1 = header->h1; \
897 : : changed = TRUE; \
898 : : }; \
899 : : } G_STMT_END
900 : :
901 : : /* update average bitrate */
902 [ # # ]: 0 : if (mad->new_header) {
903 : 0 : mad->framecount = 1;
904 : 0 : mad->vbr_rate = header->bitrate;
905 : : } else {
906 : 0 : mad->framecount++;
907 : 0 : mad->vbr_rate += header->bitrate;
908 : : }
909 : 0 : mad->vbr_average = (gint) (mad->vbr_rate / mad->framecount);
910 : :
911 [ # # ][ # # ]: 0 : CHECK_HEADER (layer, "layer");
912 [ # # ][ # # ]: 0 : CHECK_HEADER (mode, "mode");
913 [ # # ][ # # ]: 0 : CHECK_HEADER (emphasis, "emphasis");
914 : 0 : mad->header.bitrate = header->bitrate;
915 : 0 : mad->new_header = FALSE;
916 : :
917 [ # # ]: 0 : if (changed) {
918 : : GstTagList *list;
919 : : GEnumValue *mode;
920 : : GEnumValue *emphasis;
921 : :
922 : 0 : mode =
923 : 0 : g_enum_get_value (g_type_class_peek (GST_TYPE_MAD_MODE),
924 : 0 : mad->header.mode);
925 : 0 : emphasis =
926 : 0 : g_enum_get_value (g_type_class_peek (GST_TYPE_MAD_EMPHASIS),
927 : 0 : mad->header.emphasis);
928 : 0 : list = gst_tag_list_new ();
929 : 0 : gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
930 : 0 : GST_TAG_LAYER, mad->header.layer,
931 : : GST_TAG_MODE, mode->value_nick,
932 : : GST_TAG_EMPHASIS, emphasis->value_nick, NULL);
933 [ # # ]: 0 : if (!mad->framed) {
934 : : gchar *str;
935 : :
936 : 0 : str = g_strdup_printf ("MPEG-1 layer %d", mad->header.layer);
937 : 0 : gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
938 : : GST_TAG_AUDIO_CODEC, str, NULL);
939 : 0 : g_free (str);
940 : : }
941 [ # # ]: 0 : if (!mad->xing_found) {
942 : 0 : gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
943 : : GST_TAG_BITRATE, mad->header.bitrate, NULL);
944 : : }
945 : 0 : gst_element_post_message (GST_ELEMENT (mad),
946 : 0 : gst_message_new_tag (GST_OBJECT (mad), list));
947 : : }
948 : : #undef CHECK_HEADER
949 : :
950 : 0 : }
951 : :
952 : : static gboolean
953 : 0 : gst_mad_sink_event (GstPad * pad, GstEvent * event)
954 : : {
955 : 0 : GstMad *mad = GST_MAD (GST_PAD_PARENT (pad));
956 : : gboolean result;
957 : :
958 [ # # ]: 0 : GST_DEBUG ("handling %s event", GST_EVENT_TYPE_NAME (event));
959 : :
960 [ # # # # : 0 : switch (GST_EVENT_TYPE (event)) {
# ]
961 : : case GST_EVENT_NEWSEGMENT:{
962 : : GstFormat format;
963 : : gboolean update;
964 : : gdouble rate, applied_rate;
965 : : gint64 start, stop, pos;
966 : :
967 : 0 : gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate,
968 : : &format, &start, &stop, &pos);
969 : :
970 [ # # ]: 0 : if (format == GST_FORMAT_TIME) {
971 : : /* FIXME: is this really correct? */
972 : 0 : mad->tempsize = 0;
973 : 0 : result = gst_pad_push_event (mad->srcpad, event);
974 : : /* we don't need to restart when we get here */
975 : 0 : mad->restart = FALSE;
976 : 0 : mad->framed = TRUE;
977 : 0 : gst_segment_set_newsegment_full (&mad->segment, update, rate,
978 : : applied_rate, GST_FORMAT_TIME, start, stop, pos);
979 : : } else {
980 [ # # ]: 0 : GST_DEBUG ("dropping newsegment event in format %s",
981 : : gst_format_get_name (format));
982 : : /* on restart the chain function will generate a new
983 : : * newsegment event, so we can just drop this one */
984 : 0 : mad->restart = TRUE;
985 : 0 : gst_event_unref (event);
986 : 0 : mad->tempsize = 0;
987 : 0 : mad->framed = FALSE;
988 : 0 : result = TRUE;
989 : : }
990 : 0 : break;
991 : : }
992 : : case GST_EVENT_EOS:
993 [ # # ]: 0 : if (mad->segment.rate < 0.0)
994 : 0 : gst_mad_chain_reverse (mad, NULL);
995 : 0 : mad->caps_set = FALSE; /* could be a new stream */
996 : 0 : result = gst_pad_push_event (mad->srcpad, event);
997 : 0 : break;
998 : : case GST_EVENT_FLUSH_STOP:
999 : : /* Clear any stored data, as it won't make sense once
1000 : : * the new data arrives */
1001 : 0 : mad->tempsize = 0;
1002 : 0 : mad_frame_mute (&mad->frame);
1003 : 0 : mad_synth_mute (&mad->synth);
1004 : 0 : gst_mad_clear_queues (mad);
1005 : : /* fall-through */
1006 : : case GST_EVENT_FLUSH_START:
1007 : 0 : result = gst_pad_event_default (pad, event);
1008 : 0 : break;
1009 : : default:
1010 [ # # ]: 0 : if (mad->restart) {
1011 : : /* Cache all other events if we still have to send a NEWSEGMENT */
1012 : 0 : mad->pending_events = g_list_append (mad->pending_events, event);
1013 : 0 : result = TRUE;
1014 : : } else {
1015 : 0 : result = gst_pad_event_default (pad, event);
1016 : : }
1017 : 0 : break;
1018 : : }
1019 : 0 : return result;
1020 : : }
1021 : :
1022 : : static gboolean
1023 : 0 : gst_mad_check_restart (GstMad * mad)
1024 : : {
1025 : 0 : gboolean yes = mad->restart;
1026 : :
1027 [ # # ]: 0 : if (mad->restart) {
1028 : 0 : mad->restart = FALSE;
1029 : 0 : mad->tempsize = 0;
1030 : : }
1031 : 0 : return yes;
1032 : : }
1033 : :
1034 : :
1035 : : /* The following code has been taken from
1036 : : * rhythmbox/metadata/monkey-media/stream-info-impl/id3-vfs/mp3bitrate.c
1037 : : * which took it from xine-lib/src/demuxers/demux_mpgaudio.c
1038 : : * This code has been kindly relicensed to LGPL by Thibaut Mattern and
1039 : : * Bastien Nocera
1040 : : */
1041 : : #define BE_32(x) GST_READ_UINT32_BE(x)
1042 : :
1043 : : #define FOURCC_TAG( ch0, ch1, ch2, ch3 ) \
1044 : : ( (long)(unsigned char)(ch3) | \
1045 : : ( (long)(unsigned char)(ch2) << 8 ) | \
1046 : : ( (long)(unsigned char)(ch1) << 16 ) | \
1047 : : ( (long)(unsigned char)(ch0) << 24 ) )
1048 : :
1049 : : /* Xing header stuff */
1050 : : #define XING_TAG FOURCC_TAG('X', 'i', 'n', 'g')
1051 : : #define XING_FRAMES_FLAG 0x0001
1052 : : #define XING_BYTES_FLAG 0x0002
1053 : : #define XING_TOC_FLAG 0x0004
1054 : : #define XING_VBR_SCALE_FLAG 0x0008
1055 : : #define XING_TOC_LENGTH 100
1056 : :
1057 : : /* check for valid "Xing" VBR header */
1058 : : static int
1059 : 0 : is_xhead (unsigned char *buf)
1060 : : {
1061 : 0 : return (BE_32 (buf) == XING_TAG);
1062 : : }
1063 : :
1064 : :
1065 : : #undef LOG
1066 : : /*#define LOG*/
1067 : : #ifdef LOG
1068 : : #ifndef WIN32
1069 : : #define lprintf(x...) g_print(x)
1070 : : #else
1071 : : #define lprintf GST_DEBUG
1072 : : #endif
1073 : : #else
1074 : : #ifndef WIN32
1075 : : #define lprintf(x...)
1076 : : #else
1077 : : #define lprintf GST_DEBUG
1078 : : #endif
1079 : : #endif
1080 : :
1081 : : static int
1082 : 0 : mpg123_parse_xing_header (struct mad_header *header,
1083 : : const guint8 * buf, int bufsize, int *bitrate, int *time)
1084 : : {
1085 : : int i;
1086 : 0 : guint8 *ptr = (guint8 *) buf;
1087 : : double frame_duration;
1088 : : int xflags, xframes, xbytes;
1089 : : int abr;
1090 : : guint8 xtoc[XING_TOC_LENGTH];
1091 : 0 : int lsf_bit = !(header->flags & MAD_FLAG_LSF_EXT);
1092 : :
1093 : 0 : xframes = xbytes = 0;
1094 : :
1095 : : /* offset of the Xing header */
1096 [ # # ]: 0 : if (lsf_bit) {
1097 [ # # ]: 0 : if (header->mode != MAD_MODE_SINGLE_CHANNEL)
1098 : 0 : ptr += (32 + 4);
1099 : : else
1100 : 0 : ptr += (17 + 4);
1101 : : } else {
1102 [ # # ]: 0 : if (header->mode != MAD_MODE_SINGLE_CHANNEL)
1103 : 0 : ptr += (17 + 4);
1104 : : else
1105 : 0 : ptr += (9 + 4);
1106 : : }
1107 : :
1108 [ # # ]: 0 : if (ptr >= (buf + bufsize - 4))
1109 : 0 : return 0;
1110 : :
1111 [ # # ]: 0 : if (is_xhead (ptr)) {
1112 : : lprintf ("Xing header found\n");
1113 : :
1114 : 0 : ptr += 4;
1115 [ # # ]: 0 : if (ptr >= (buf + bufsize - 4))
1116 : 0 : return 0;
1117 : :
1118 : 0 : xflags = BE_32 (ptr);
1119 : 0 : ptr += 4;
1120 : :
1121 [ # # ]: 0 : if (xflags & XING_FRAMES_FLAG) {
1122 [ # # ]: 0 : if (ptr >= (buf + bufsize - 4))
1123 : 0 : return 0;
1124 : 0 : xframes = BE_32 (ptr);
1125 : : lprintf ("xframes: %d\n", xframes);
1126 : 0 : ptr += 4;
1127 : : }
1128 [ # # ]: 0 : if (xflags & XING_BYTES_FLAG) {
1129 [ # # ]: 0 : if (ptr >= (buf + bufsize - 4))
1130 : 0 : return 0;
1131 : 0 : xbytes = BE_32 (ptr);
1132 : : lprintf ("xbytes: %d\n", xbytes);
1133 : 0 : ptr += 4;
1134 : : }
1135 [ # # ]: 0 : if (xflags & XING_TOC_FLAG) {
1136 : 0 : guchar old = 0;
1137 : :
1138 : : lprintf ("toc found\n");
1139 [ # # ]: 0 : if (ptr >= (buf + bufsize - XING_TOC_LENGTH))
1140 : 0 : return 0;
1141 [ # # ]: 0 : if (*ptr != 0) {
1142 : : lprintf ("skipping broken Xing TOC\n");
1143 : 0 : goto skip_toc;
1144 : : }
1145 [ # # ]: 0 : for (i = 0; i < XING_TOC_LENGTH; i++) {
1146 : 0 : xtoc[i] = *(ptr + i);
1147 [ # # ]: 0 : if (old > xtoc[i]) {
1148 : : lprintf ("skipping broken Xing TOC\n");
1149 : 0 : goto skip_toc;
1150 : : }
1151 : : lprintf ("%d ", xtoc[i]);
1152 : : }
1153 : : lprintf ("\n");
1154 : : skip_toc:
1155 : 0 : ptr += XING_TOC_LENGTH;
1156 : : }
1157 : :
1158 [ # # ]: 0 : if (xflags & XING_VBR_SCALE_FLAG) {
1159 [ # # ]: 0 : if (ptr >= (buf + bufsize - 4))
1160 : 0 : return 0;
1161 : : lprintf ("xvbr_scale: %d\n", BE_32 (ptr));
1162 : : }
1163 : :
1164 : : /* 1 kbit = 1000 bits ! (and not 1024 bits) */
1165 [ # # ]: 0 : if (xflags & (XING_FRAMES_FLAG | XING_BYTES_FLAG)) {
1166 [ # # ]: 0 : if (header->layer == MAD_LAYER_I) {
1167 : 0 : frame_duration = 384.0 / (double) header->samplerate;
1168 : : } else {
1169 : : int slots_per_frame;
1170 : :
1171 : 0 : slots_per_frame = ((header->layer == MAD_LAYER_III)
1172 [ # # ][ # # ]: 0 : && !lsf_bit) ? 72 : 144;
1173 : 0 : frame_duration = slots_per_frame * 8.0 / (double) header->samplerate;
1174 : : }
1175 : 0 : abr = ((double) xbytes * 8.0) / ((double) xframes * frame_duration);
1176 : : lprintf ("abr: %d bps\n", abr);
1177 [ # # ]: 0 : if (bitrate != NULL) {
1178 : 0 : *bitrate = abr;
1179 : : }
1180 [ # # ]: 0 : if (time != NULL) {
1181 : 0 : *time = (double) xframes *frame_duration;
1182 : :
1183 : : lprintf ("stream_length: %d s, %d min %d s\n", *time,
1184 : : *time / 60, *time % 60);
1185 : : }
1186 : : } else {
1187 : : /* it's a stupid Xing header */
1188 : : lprintf ("not a Xing VBR file\n");
1189 : : }
1190 : 0 : return 1;
1191 : : } else {
1192 : : lprintf ("Xing header not found\n");
1193 : 0 : return 0;
1194 : : }
1195 : : }
1196 : :
1197 : : /* End of Xine code */
1198 : :
1199 : : /* internal function to check if the header has changed and thus the
1200 : : * caps need to be reset. Only call during normal mode, not resyncing */
1201 : : static void
1202 : 0 : gst_mad_check_caps_reset (GstMad * mad)
1203 : : {
1204 : : guint nchannels;
1205 : 0 : guint rate, old_rate = mad->rate;
1206 : :
1207 [ # # ]: 0 : nchannels = MAD_NCHANNELS (&mad->frame.header);
1208 : :
1209 : : #if MAD_VERSION_MINOR <= 12
1210 : : rate = mad->header.sfreq;
1211 : : #else
1212 : 0 : rate = mad->frame.header.samplerate;
1213 : : #endif
1214 : :
1215 : : /* rate and channels are not supposed to change in a continuous stream,
1216 : : * so check this first before doing anything */
1217 : :
1218 : : /* only set caps if they weren't already set for this continuous stream */
1219 [ # # ][ # # ]: 0 : if (mad->channels != nchannels || mad->rate != rate) {
1220 [ # # ]: 0 : if (mad->caps_set) {
1221 [ # # ]: 0 : GST_DEBUG
1222 : : ("Header changed from %d Hz/%d ch to %d Hz/%d ch, failed sync after seek ?",
1223 : : mad->rate, mad->channels, rate, nchannels);
1224 : : /* we're conservative on stream changes. However, our *initial* caps
1225 : : * might have been wrong as well - mad ain't perfect in syncing. So,
1226 : : * we count caps changes and change if we pass a limit treshold (3). */
1227 [ # # ][ # # ]: 0 : if (nchannels != mad->pending_channels || rate != mad->pending_rate) {
1228 : 0 : mad->times_pending = 0;
1229 : 0 : mad->pending_channels = nchannels;
1230 : 0 : mad->pending_rate = rate;
1231 : : }
1232 [ # # ]: 0 : if (++mad->times_pending < 3)
1233 : 0 : return;
1234 : : }
1235 : : }
1236 : 0 : gst_mad_update_info (mad);
1237 : :
1238 [ # # ][ # # ]: 0 : if (mad->channels != nchannels || mad->rate != rate) {
1239 : : GstCaps *caps;
1240 : :
1241 [ # # ]: 0 : if (mad->stream.options & MAD_OPTION_HALFSAMPLERATE)
1242 : 0 : rate >>= 1;
1243 : :
1244 : : /* FIXME see if peer can accept the caps */
1245 : :
1246 : : /* we set the caps even when the pad is not connected so they
1247 : : * can be gotten for streaminfo */
1248 : 0 : caps = gst_caps_new_simple ("audio/x-raw-int",
1249 : : "endianness", G_TYPE_INT, G_BYTE_ORDER,
1250 : : "signed", G_TYPE_BOOLEAN, TRUE,
1251 : : "width", G_TYPE_INT, 32,
1252 : : "depth", G_TYPE_INT, 32,
1253 : : "rate", G_TYPE_INT, rate, "channels", G_TYPE_INT, nchannels, NULL);
1254 : :
1255 : 0 : gst_pad_set_caps (mad->srcpad, caps);
1256 : 0 : gst_caps_unref (caps);
1257 : :
1258 : 0 : mad->caps_set = TRUE; /* set back to FALSE on discont */
1259 : 0 : mad->channels = nchannels;
1260 : 0 : mad->rate = rate;
1261 : :
1262 : : /* update sample count so we don't come up with crazy timestamps */
1263 [ # # ][ # # ]: 0 : if (mad->total_samples && old_rate) {
1264 : 0 : mad->total_samples = mad->total_samples * rate / old_rate;
1265 : : }
1266 : : }
1267 : : }
1268 : :
1269 : : static void
1270 : 7 : gst_mad_clear_queues (GstMad * mad)
1271 : : {
1272 : 7 : g_list_foreach (mad->queued, (GFunc) gst_mini_object_unref, NULL);
1273 : 7 : g_list_free (mad->queued);
1274 : 7 : mad->queued = NULL;
1275 : 7 : g_list_foreach (mad->gather, (GFunc) gst_mini_object_unref, NULL);
1276 : 7 : g_list_free (mad->gather);
1277 : 7 : mad->gather = NULL;
1278 : 7 : g_list_foreach (mad->decode, (GFunc) gst_mini_object_unref, NULL);
1279 : 7 : g_list_free (mad->decode);
1280 : 7 : mad->decode = NULL;
1281 : 7 : }
1282 : :
1283 : : static GstFlowReturn
1284 : 0 : gst_mad_flush_decode (GstMad * mad)
1285 : : {
1286 : 0 : GstFlowReturn res = GST_FLOW_OK;
1287 : : GList *walk;
1288 : :
1289 : 0 : walk = mad->decode;
1290 : :
1291 [ # # ]: 0 : GST_DEBUG_OBJECT (mad, "flushing buffers to decoder");
1292 : :
1293 : : /* clear buffer and decoder state */
1294 : 0 : mad->tempsize = 0;
1295 : 0 : mad_frame_mute (&mad->frame);
1296 : 0 : mad_synth_mute (&mad->synth);
1297 : :
1298 : 0 : mad->process = TRUE;
1299 [ # # ]: 0 : while (walk) {
1300 : : GList *next;
1301 : 0 : GstBuffer *buf = GST_BUFFER_CAST (walk->data);
1302 : :
1303 [ # # ][ # # ]: 0 : GST_DEBUG_OBJECT (mad, "decoding buffer %p, ts %" GST_TIME_FORMAT,
[ # # ][ # # ]
[ # # ]
1304 : : buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
1305 : :
1306 [ # # ]: 0 : next = g_list_next (walk);
1307 : : /* decode buffer, resulting data prepended to output queue */
1308 : 0 : gst_buffer_ref (buf);
1309 : 0 : res = gst_mad_chain (mad->sinkpad, buf);
1310 : :
1311 : : /* if we generated output, we can discard the buffer, else we
1312 : : * keep it in the queue */
1313 [ # # ]: 0 : if (mad->queued) {
1314 [ # # ]: 0 : GST_DEBUG_OBJECT (mad, "decoded buffer to %p", mad->queued->data);
1315 : 0 : mad->decode = g_list_delete_link (mad->decode, walk);
1316 : 0 : gst_buffer_unref (buf);
1317 : : } else {
1318 [ # # ]: 0 : GST_DEBUG_OBJECT (mad, "buffer did not decode, keeping");
1319 : : }
1320 : 0 : walk = next;
1321 : : }
1322 : 0 : mad->process = FALSE;
1323 : :
1324 : : /* now send queued data downstream */
1325 [ # # ]: 0 : while (mad->queued) {
1326 : 0 : GstBuffer *buf = GST_BUFFER_CAST (mad->queued->data);
1327 : :
1328 [ # # ][ # # ]: 0 : GST_DEBUG_OBJECT (mad, "pushing buffer %p of size %u, "
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
1329 : : "time %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT, buf,
1330 : : GST_BUFFER_SIZE (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
1331 : : GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
1332 : 0 : res = gst_pad_push (mad->srcpad, buf);
1333 : :
1334 : 0 : mad->queued = g_list_delete_link (mad->queued, mad->queued);
1335 : : }
1336 : :
1337 : 0 : return res;
1338 : : }
1339 : :
1340 : : static GstFlowReturn
1341 : 0 : gst_mad_chain_reverse (GstMad * mad, GstBuffer * buf)
1342 : : {
1343 : 0 : GstFlowReturn result = GST_FLOW_OK;
1344 : :
1345 : : /* if we have a discont, move buffers to the decode list */
1346 [ # # ][ # # ]: 0 : if (!buf || GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) {
1347 [ # # ]: 0 : GST_DEBUG_OBJECT (mad, "received discont");
1348 [ # # ]: 0 : while (mad->gather) {
1349 : : GstBuffer *gbuf;
1350 : :
1351 : 0 : gbuf = GST_BUFFER_CAST (mad->gather->data);
1352 : : /* remove from the gather list */
1353 : 0 : mad->gather = g_list_delete_link (mad->gather, mad->gather);
1354 : : /* copy to decode queue */
1355 : 0 : mad->decode = g_list_prepend (mad->decode, gbuf);
1356 : : }
1357 : : /* decode stuff in the decode queue */
1358 : 0 : gst_mad_flush_decode (mad);
1359 : : }
1360 : :
1361 [ # # ]: 0 : if (G_LIKELY (buf)) {
1362 [ # # ][ # # ]: 0 : GST_DEBUG_OBJECT (mad, "gathering buffer %p of size %u, "
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
1363 : : "time %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT, buf,
1364 : : GST_BUFFER_SIZE (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
1365 : : GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));
1366 : :
1367 : : /* add buffer to gather queue */
1368 : 0 : mad->gather = g_list_prepend (mad->gather, buf);
1369 : : }
1370 : :
1371 : 0 : return result;
1372 : : }
1373 : :
1374 : : static GstFlowReturn
1375 : 0 : gst_mad_chain (GstPad * pad, GstBuffer * buffer)
1376 : : {
1377 : : GstMad *mad;
1378 : : guint8 *data;
1379 : : glong size, tempsize;
1380 : 0 : gboolean new_pts = FALSE;
1381 : : gboolean discont;
1382 : : GstClockTime timestamp;
1383 : 0 : GstFlowReturn result = GST_FLOW_OK;
1384 : :
1385 : 0 : mad = GST_MAD (GST_PAD_PARENT (pad));
1386 : :
1387 : : /* restarts happen on discontinuities, ie. seek, flush, PAUSED to PLAYING */
1388 [ # # ]: 0 : if (gst_mad_check_restart (mad)) {
1389 : 0 : mad->need_newsegment = TRUE;
1390 [ # # ]: 0 : GST_DEBUG ("mad restarted");
1391 : : }
1392 : :
1393 [ # # ]: 0 : if (mad->segment.rate < 0.0) {
1394 [ # # ]: 0 : if (!mad->process)
1395 : 0 : return gst_mad_chain_reverse (mad, buffer);
1396 : : /* no output discont */
1397 : 0 : discont = FALSE;
1398 : : } else {
1399 : : /* take discont flag */
1400 : 0 : discont = GST_BUFFER_IS_DISCONT (buffer);
1401 : : }
1402 : :
1403 : 0 : timestamp = GST_BUFFER_TIMESTAMP (buffer);
1404 [ # # ][ # # ]: 0 : GST_DEBUG ("mad in timestamp %" GST_TIME_FORMAT " duration:%" GST_TIME_FORMAT,
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
1405 : : GST_TIME_ARGS (timestamp), GST_TIME_ARGS (GST_BUFFER_DURATION (buffer)));
1406 : :
1407 : : /* handle timestamps */
1408 [ # # ]: 0 : if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
1409 : : /* if there is nothing left to process in our temporary buffer,
1410 : : * we can set this timestamp on the next outgoing buffer */
1411 [ # # ]: 0 : if (mad->tempsize == 0) {
1412 : : /* we have to save the result here because we can't yet convert
1413 : : * the timestamp to a sample offset, as the samplerate might not
1414 : : * be known yet */
1415 : 0 : mad->last_ts = timestamp;
1416 : 0 : mad->base_byte_offset = GST_BUFFER_OFFSET (buffer);
1417 : 0 : mad->bytes_consumed = 0;
1418 : : }
1419 : : /* else we need to finish the current partial frame with the old timestamp
1420 : : * and queue this timestamp for the next frame */
1421 : : else {
1422 : 0 : new_pts = TRUE;
1423 : : }
1424 : : }
1425 [ # # ][ # # ]: 0 : GST_DEBUG ("last_ts %" GST_TIME_FORMAT, GST_TIME_ARGS (mad->last_ts));
[ # # ][ # # ]
[ # # ]
1426 : :
1427 : : /* handle data */
1428 : 0 : data = GST_BUFFER_DATA (buffer);
1429 : 0 : size = GST_BUFFER_SIZE (buffer);
1430 : :
1431 : 0 : tempsize = mad->tempsize;
1432 : :
1433 : : /* process the incoming buffer in chunks of maximum MAD_BUFFER_MDLEN bytes;
1434 : : * this is the upper limit on processable chunk sizes set by mad */
1435 [ # # ]: 0 : while (size > 0) {
1436 : : gint tocopy;
1437 : : guchar *mad_input_buffer; /* convenience pointer to tempbuffer */
1438 : :
1439 [ # # ][ # # ]: 0 : if (mad->tempsize == 0 && discont) {
1440 : 0 : mad->discont = TRUE;
1441 : 0 : discont = FALSE;
1442 : : }
1443 : 0 : tocopy =
1444 : 0 : MIN (MAD_BUFFER_MDLEN, MIN (size,
1445 : : MAD_BUFFER_MDLEN * 3 - mad->tempsize));
1446 [ # # ]: 0 : if (tocopy == 0) {
1447 [ # # ][ # # ]: 0 : GST_ELEMENT_ERROR (mad, STREAM, DECODE, (NULL),
[ # # ][ # # ]
1448 : : ("mad claims to need more data than %u bytes, we don't have that much",
1449 : : MAD_BUFFER_MDLEN * 3));
1450 : 0 : result = GST_FLOW_ERROR;
1451 : 0 : goto end;
1452 : : }
1453 : :
1454 : : /* append the chunk to process to our internal temporary buffer */
1455 [ # # ]: 0 : GST_LOG ("tempbuffer size %ld, copying %d bytes from incoming buffer",
1456 : : mad->tempsize, tocopy);
1457 : 0 : memcpy (mad->tempbuffer + mad->tempsize, data, tocopy);
1458 : 0 : mad->tempsize += tocopy;
1459 : :
1460 : : /* update our incoming buffer's parameters to reflect this */
1461 : 0 : size -= tocopy;
1462 : 0 : data += tocopy;
1463 : :
1464 : 0 : mad_input_buffer = mad->tempbuffer;
1465 : :
1466 : : /* while we have data we can consume it */
1467 [ # # ]: 0 : while (mad->tempsize > 0) {
1468 : 0 : gint consumed = 0;
1469 : : guint nsamples;
1470 : 0 : guint64 time_offset = GST_CLOCK_TIME_NONE;
1471 : 0 : guint64 time_duration = GST_CLOCK_TIME_NONE;
1472 : : unsigned char const *before_sync, *after_sync;
1473 : 0 : gboolean goto_exit = FALSE;
1474 : :
1475 : 0 : mad->in_error = FALSE;
1476 : :
1477 : 0 : mad_stream_buffer (&mad->stream, mad_input_buffer, mad->tempsize);
1478 : :
1479 : : /* added separate header decoding to catch errors earlier, also fixes
1480 : : * some weird decoding errors... */
1481 [ # # ]: 0 : GST_LOG ("decoding the header now");
1482 [ # # ]: 0 : if (mad_header_decode (&mad->frame.header, &mad->stream) == -1) {
1483 [ # # ]: 0 : if (mad->stream.error == MAD_ERROR_BUFLEN) {
1484 [ # # ]: 0 : GST_LOG ("not enough data in tempbuffer (%ld), breaking to get more",
1485 : : mad->tempsize);
1486 : 0 : break;
1487 : : } else {
1488 [ # # ]: 0 : GST_WARNING ("mad_header_decode had an error: %s",
1489 : : mad_stream_errorstr (&mad->stream));
1490 : : }
1491 : : }
1492 : :
1493 [ # # ]: 0 : GST_LOG ("decoding one frame now");
1494 : :
1495 [ # # ]: 0 : if (mad_frame_decode (&mad->frame, &mad->stream) == -1) {
1496 [ # # ]: 0 : GST_LOG ("got error %d", mad->stream.error);
1497 : :
1498 : : /* not enough data, need to wait for next buffer? */
1499 [ # # ]: 0 : if (mad->stream.error == MAD_ERROR_BUFLEN) {
1500 [ # # ]: 0 : if (mad->stream.next_frame == mad_input_buffer) {
1501 [ # # ]: 0 : GST_LOG
1502 : : ("not enough data in tempbuffer (%ld), breaking to get more",
1503 : : mad->tempsize);
1504 : 0 : break;
1505 : : } else {
1506 [ # # ]: 0 : GST_LOG ("sync error, flushing unneeded data");
1507 : 0 : goto next_no_samples;
1508 : : }
1509 [ # # ]: 0 : } else if (mad->stream.error == MAD_ERROR_BADDATAPTR) {
1510 : : /* Flush data */
1511 : 0 : goto next_no_samples;
1512 : : }
1513 : : /* we are in an error state */
1514 : 0 : mad->in_error = TRUE;
1515 [ # # ]: 0 : GST_WARNING ("mad_frame_decode had an error: %s",
1516 : : mad_stream_errorstr (&mad->stream));
1517 [ # # ]: 0 : if (!MAD_RECOVERABLE (mad->stream.error)) {
1518 [ # # ][ # # ]: 0 : GST_ELEMENT_ERROR (mad, STREAM, DECODE, (NULL), (NULL));
[ # # ][ # # ]
1519 : 0 : result = GST_FLOW_ERROR;
1520 : 0 : goto end;
1521 [ # # ]: 0 : } else if (mad->stream.error == MAD_ERROR_LOSTSYNC) {
1522 : : /* lost sync, force a resync */
1523 [ # # ]: 0 : GST_INFO ("recoverable lost sync error");
1524 : :
1525 : : #ifdef HAVE_ID3TAG
1526 : : {
1527 : : signed long tagsize;
1528 : :
1529 : 0 : tagsize = id3_tag_query (mad->stream.this_frame,
1530 : 0 : mad->stream.bufend - mad->stream.this_frame);
1531 : :
1532 [ # # ]: 0 : if (tagsize > mad->tempsize) {
1533 [ # # ]: 0 : GST_INFO ("mad: got partial id3 tag in buffer, skipping");
1534 [ # # ]: 0 : } else if (tagsize > 0) {
1535 : : struct id3_tag *tag;
1536 : : id3_byte_t const *data;
1537 : :
1538 [ # # ]: 0 : GST_INFO ("mad: got ID3 tag size %ld", tagsize);
1539 : :
1540 : 0 : data = mad->stream.this_frame;
1541 : :
1542 : : /* mad has moved the pointer to the next frame over the start of the
1543 : : * id3 tags, so we need to flush one byte less than the tagsize */
1544 : 0 : mad_stream_skip (&mad->stream, tagsize - 1);
1545 : :
1546 : 0 : tag = id3_tag_parse (data, tagsize);
1547 [ # # ]: 0 : if (tag) {
1548 : : GstTagList *list;
1549 : :
1550 : 0 : list = gst_mad_id3_to_tag_list (tag);
1551 : 0 : id3_tag_delete (tag);
1552 [ # # ]: 0 : GST_DEBUG ("found tag");
1553 : 0 : gst_element_post_message (GST_ELEMENT (mad),
1554 : 0 : gst_message_new_tag (GST_OBJECT (mad),
1555 : : gst_tag_list_copy (list)));
1556 [ # # ]: 0 : if (mad->tags) {
1557 : 0 : gst_tag_list_insert (mad->tags, list, GST_TAG_MERGE_PREPEND);
1558 : : } else {
1559 : 0 : mad->tags = gst_tag_list_copy (list);
1560 : : }
1561 [ # # ]: 0 : if (mad->need_newsegment)
1562 : 0 : mad->pending_events =
1563 : 0 : g_list_append (mad->pending_events,
1564 : 0 : gst_event_new_tag (list));
1565 : : else
1566 : 0 : gst_pad_push_event (mad->srcpad, gst_event_new_tag (list));
1567 : : }
1568 : : }
1569 : : }
1570 : : #endif /* HAVE_ID3TAG */
1571 : : }
1572 : :
1573 : 0 : mad_frame_mute (&mad->frame);
1574 : 0 : mad_synth_mute (&mad->synth);
1575 : 0 : before_sync = mad->stream.ptr.byte;
1576 [ # # ]: 0 : if (mad_stream_sync (&mad->stream) != 0)
1577 [ # # ]: 0 : GST_WARNING ("mad_stream_sync failed");
1578 : 0 : after_sync = mad->stream.ptr.byte;
1579 : : /* a succesful resync should make us drop bytes as consumed, so
1580 : : calculate from the byte pointers before and after resync */
1581 : 0 : consumed = after_sync - before_sync;
1582 [ # # ]: 0 : GST_DEBUG ("resynchronization consumes %d bytes", consumed);
1583 [ # # ]: 0 : GST_DEBUG ("synced to data: 0x%0x 0x%0x", *mad->stream.ptr.byte,
1584 : : *(mad->stream.ptr.byte + 1));
1585 : :
1586 : 0 : mad_stream_sync (&mad->stream);
1587 : : /* recoverable errors pass */
1588 : 0 : goto next_no_samples;
1589 : : }
1590 : :
1591 [ # # ]: 0 : if (mad->check_for_xing) {
1592 : 0 : int bitrate = 0, time = 0;
1593 : : GstTagList *list;
1594 : 0 : int frame_len = mad->stream.next_frame - mad->stream.this_frame;
1595 : :
1596 : 0 : mad->check_for_xing = FALSE;
1597 : :
1598 : : /* Assume Xing headers can only be the first frame in a mp3 file */
1599 [ # # ]: 0 : if (mpg123_parse_xing_header (&mad->frame.header,
1600 : 0 : mad->stream.this_frame, frame_len, &bitrate, &time)) {
1601 : 0 : mad->xing_found = TRUE;
1602 : 0 : list = gst_tag_list_new ();
1603 : 0 : gst_tag_list_add (list, GST_TAG_MERGE_REPLACE,
1604 : 0 : GST_TAG_DURATION, (gint64) time * 1000 * 1000 * 1000,
1605 : : GST_TAG_BITRATE, bitrate, NULL);
1606 : 0 : gst_element_post_message (GST_ELEMENT (mad),
1607 : 0 : gst_message_new_tag (GST_OBJECT (mad), gst_tag_list_copy (list)));
1608 : :
1609 [ # # ]: 0 : if (mad->need_newsegment)
1610 : 0 : mad->pending_events =
1611 : 0 : g_list_append (mad->pending_events, gst_event_new_tag (list));
1612 : : else
1613 : 0 : gst_pad_push_event (mad->srcpad, gst_event_new_tag (list));
1614 : :
1615 : 0 : goto next_no_samples;
1616 : : }
1617 : : }
1618 : :
1619 : : /* if we're not resyncing/in error, check if caps need to be set again */
1620 [ # # ]: 0 : if (!mad->in_error)
1621 : 0 : gst_mad_check_caps_reset (mad);
1622 [ # # ][ # # ]: 0 : nsamples = MAD_NSBSAMPLES (&mad->frame.header) *
[ # # ]
1623 [ # # ]: 0 : (mad->stream.options & MAD_OPTION_HALFSAMPLERATE ? 16 : 32);
1624 : :
1625 [ # # ]: 0 : if (mad->rate == 0) {
1626 : 0 : g_warning ("mad->rate is 0; timestamps cannot be calculated");
1627 : : } else {
1628 : : /* if we have a pending timestamp, we can use it now to calculate the sample offset */
1629 [ # # ]: 0 : if (GST_CLOCK_TIME_IS_VALID (mad->last_ts)) {
1630 : 0 : GstFormat format = GST_FORMAT_DEFAULT;
1631 : : gint64 total;
1632 : :
1633 : : /* Convert incoming timestamp to a number of encoded samples */
1634 : 0 : gst_pad_query_convert (mad->srcpad, GST_FORMAT_TIME, mad->last_ts,
1635 : : &format, &total);
1636 : :
1637 [ # # ]: 0 : GST_DEBUG_OBJECT (mad, "calculated samples offset from ts is %"
1638 : : G_GUINT64_FORMAT " accumulated samples offset is %"
1639 : : G_GUINT64_FORMAT, total, mad->total_samples);
1640 : :
1641 : : /* We are using the incoming timestamps to generate the outgoing ones
1642 : : * if available. However some muxing formats are not precise enough
1643 : : * to allow us to generate a perfect stream. When converting the
1644 : : * timestamp to a number of encoded samples so far we are introducing
1645 : : * a lot of potential error compared to our accumulated number of
1646 : : * samples encoded. If the difference between those 2 numbers is
1647 : : * bigger than half a frame we then use the incoming timestamp
1648 : : * as a reference, otherwise we continue using our accumulated samples
1649 : : * counter */
1650 [ # # ]: 0 : if (ABS (mad->total_samples - total) > nsamples / 2) {
1651 [ # # ]: 0 : GST_DEBUG_OBJECT (mad, "difference is bigger than half a frame, "
1652 : : "using calculated samples offset %" G_GUINT64_FORMAT, total);
1653 : : /* Override our accumulated samples counter */
1654 : 0 : mad->total_samples = total;
1655 : : /* We use that timestamp directly */
1656 : 0 : time_offset = mad->last_ts;
1657 : : }
1658 : :
1659 : 0 : mad->last_ts = GST_CLOCK_TIME_NONE;
1660 : : }
1661 : :
1662 [ # # ]: 0 : if (!GST_CLOCK_TIME_IS_VALID (time_offset)) {
1663 : 0 : time_offset = gst_util_uint64_scale_int (mad->total_samples,
1664 : : GST_SECOND, mad->rate);
1665 : : }
1666 : : /* Duration is next timestamp - this one to generate a continuous
1667 : : * stream */
1668 : 0 : time_duration =
1669 : 0 : gst_util_uint64_scale_int (mad->total_samples + nsamples,
1670 : : GST_SECOND, mad->rate) - time_offset;
1671 : : }
1672 : :
1673 [ # # ]: 0 : if (mad->index) {
1674 : 0 : guint64 x_bytes = mad->base_byte_offset + mad->bytes_consumed;
1675 : :
1676 : 0 : gst_index_add_association (mad->index, mad->index_id,
1677 : : GST_ASSOCIATION_FLAG_DELTA_UNIT,
1678 : : GST_FORMAT_BYTES, x_bytes, GST_FORMAT_TIME, time_offset, NULL);
1679 : : }
1680 : :
1681 [ # # ]: 0 : if (mad->segment_start <= (time_offset ==
1682 [ # # ]: 0 : GST_CLOCK_TIME_NONE ? 0 : time_offset)) {
1683 : :
1684 : : /* for sample accurate seeking, calculate how many samples
1685 : : to skip and send the remaining pcm samples */
1686 : :
1687 : 0 : GstBuffer *outbuffer = NULL;
1688 : : gint32 *outdata;
1689 : : mad_fixed_t const *left_ch, *right_ch;
1690 : :
1691 [ # # ]: 0 : if (mad->need_newsegment) {
1692 : 0 : gint64 start = time_offset;
1693 : :
1694 [ # # ][ # # ]: 0 : GST_DEBUG ("Sending NEWSEGMENT event, start=%" GST_TIME_FORMAT,
[ # # ][ # # ]
[ # # ]
1695 : : GST_TIME_ARGS (start));
1696 : :
1697 : 0 : gst_segment_set_newsegment (&mad->segment, FALSE, 1.0,
1698 : : GST_FORMAT_TIME, start, GST_CLOCK_TIME_NONE, start);
1699 : :
1700 : 0 : gst_pad_push_event (mad->srcpad,
1701 : : gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
1702 : : start, GST_CLOCK_TIME_NONE, start));
1703 : 0 : mad->need_newsegment = FALSE;
1704 : : }
1705 : :
1706 [ # # ]: 0 : if (mad->pending_events) {
1707 : : GList *l;
1708 : :
1709 [ # # ]: 0 : for (l = mad->pending_events; l != NULL; l = l->next) {
1710 : 0 : gst_pad_push_event (mad->srcpad, GST_EVENT (l->data));
1711 : : }
1712 : 0 : g_list_free (mad->pending_events);
1713 : 0 : mad->pending_events = NULL;
1714 : : }
1715 : :
1716 : : /* will attach the caps to the buffer */
1717 : 0 : result =
1718 : 0 : gst_pad_alloc_buffer_and_set_caps (mad->srcpad, 0,
1719 : 0 : nsamples * mad->channels * 4, GST_PAD_CAPS (mad->srcpad),
1720 : : &outbuffer);
1721 [ # # ]: 0 : if (result != GST_FLOW_OK) {
1722 : : /* Head for the exit, dropping samples as we go */
1723 [ # # ]: 0 : GST_LOG ("Skipping frame synthesis due to pad_alloc return value");
1724 : 0 : goto_exit = TRUE;
1725 : 0 : goto skip_frame;
1726 : : }
1727 : :
1728 [ # # ]: 0 : if (GST_BUFFER_SIZE (outbuffer) != nsamples * mad->channels * 4) {
1729 : 0 : gst_buffer_unref (outbuffer);
1730 : :
1731 : 0 : outbuffer = gst_buffer_new_and_alloc (nsamples * mad->channels * 4);
1732 : 0 : gst_buffer_set_caps (outbuffer, GST_PAD_CAPS (mad->srcpad));
1733 : : }
1734 : :
1735 : 0 : mad_synth_frame (&mad->synth, &mad->frame);
1736 : 0 : left_ch = mad->synth.pcm.samples[0];
1737 : 0 : right_ch = mad->synth.pcm.samples[1];
1738 : :
1739 : 0 : outdata = (gint32 *) GST_BUFFER_DATA (outbuffer);
1740 : :
1741 [ # # ][ # # ]: 0 : GST_DEBUG ("mad out timestamp %" GST_TIME_FORMAT " dur: %"
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
1742 : : GST_TIME_FORMAT, GST_TIME_ARGS (time_offset),
1743 : : GST_TIME_ARGS (time_duration));
1744 : :
1745 : 0 : GST_BUFFER_TIMESTAMP (outbuffer) = time_offset;
1746 : 0 : GST_BUFFER_DURATION (outbuffer) = time_duration;
1747 : 0 : GST_BUFFER_OFFSET (outbuffer) = mad->total_samples;
1748 : 0 : GST_BUFFER_OFFSET_END (outbuffer) = mad->total_samples + nsamples;
1749 : :
1750 : : /* output sample(s) in 16-bit signed native-endian PCM */
1751 [ # # ]: 0 : if (mad->channels == 1) {
1752 : 0 : gint count = nsamples;
1753 : :
1754 [ # # ]: 0 : while (count--) {
1755 : 0 : *outdata++ = scale (*left_ch++) & 0xffffffff;
1756 : : }
1757 : : } else {
1758 : 0 : gint count = nsamples;
1759 : :
1760 [ # # ]: 0 : while (count--) {
1761 : 0 : *outdata++ = scale (*left_ch++) & 0xffffffff;
1762 : 0 : *outdata++ = scale (*right_ch++) & 0xffffffff;
1763 : : }
1764 : : }
1765 : :
1766 [ # # ]: 0 : if ((outbuffer = gst_audio_buffer_clip (outbuffer, &mad->segment,
1767 : 0 : mad->rate, 4 * mad->channels))) {
1768 [ # # ][ # # ]: 0 : GST_LOG_OBJECT (mad,
[ # # ][ # # ]
[ # # ]
1769 : : "pushing buffer, off=%" G_GUINT64_FORMAT ", ts=%" GST_TIME_FORMAT,
1770 : : GST_BUFFER_OFFSET (outbuffer),
1771 : : GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuffer)));
1772 : :
1773 : : /* apply discont */
1774 [ # # ]: 0 : if (mad->discont) {
1775 : 0 : GST_BUFFER_FLAG_SET (outbuffer, GST_BUFFER_FLAG_DISCONT);
1776 : 0 : mad->discont = FALSE;
1777 : : }
1778 : :
1779 : 0 : mad->segment.last_stop = GST_BUFFER_TIMESTAMP (outbuffer);
1780 [ # # ]: 0 : if (mad->segment.rate > 0.0) {
1781 : 0 : result = gst_pad_push (mad->srcpad, outbuffer);
1782 : : } else {
1783 [ # # ]: 0 : GST_LOG_OBJECT (mad, "queued buffer");
1784 : 0 : mad->queued = g_list_prepend (mad->queued, outbuffer);
1785 : 0 : result = GST_FLOW_OK;
1786 : : }
1787 [ # # ]: 0 : if (result != GST_FLOW_OK) {
1788 : : /* Head for the exit, dropping samples as we go */
1789 : 0 : goto_exit = TRUE;
1790 : : }
1791 : : } else {
1792 [ # # ]: 0 : GST_LOG_OBJECT (mad, "Dropping buffer");
1793 : : }
1794 : : }
1795 : :
1796 : : skip_frame:
1797 : 0 : mad->total_samples += nsamples;
1798 : :
1799 : : /* we have a queued timestamp on the incoming buffer that we should
1800 : : * use for the next frame */
1801 [ # # ][ # # ]: 0 : if (new_pts && (mad->stream.next_frame - mad_input_buffer >= tempsize)) {
1802 : 0 : new_pts = FALSE;
1803 : 0 : mad->last_ts = timestamp;
1804 : 0 : mad->base_byte_offset = GST_BUFFER_OFFSET (buffer);
1805 : 0 : mad->bytes_consumed = 0;
1806 : : }
1807 : 0 : tempsize = 0;
1808 [ # # ]: 0 : if (discont) {
1809 : 0 : mad->discont = TRUE;
1810 : 0 : discont = FALSE;
1811 : : }
1812 : :
1813 [ # # ]: 0 : if (gst_mad_check_restart (mad)) {
1814 : 0 : goto end;
1815 : : }
1816 : :
1817 : : next_no_samples:
1818 : : /* figure out how many bytes mad consumed */
1819 : : /* if consumed is already set, it's from the resync higher up, so
1820 : : we need to use that value instead. Otherwise, recalculate from
1821 : : mad's consumption */
1822 [ # # ]: 0 : if (consumed == 0)
1823 : 0 : consumed = mad->stream.next_frame - mad_input_buffer;
1824 : :
1825 [ # # ]: 0 : GST_LOG ("mad consumed %d bytes", consumed);
1826 : : /* move out pointer to where mad want the next data */
1827 : 0 : mad_input_buffer += consumed;
1828 : 0 : mad->tempsize -= consumed;
1829 : 0 : mad->bytes_consumed += consumed;
1830 [ # # ]: 0 : if (goto_exit == TRUE)
1831 : 0 : goto end;
1832 : : }
1833 : : /* we only get here from breaks, tempsize never actually drops below 0 */
1834 : 0 : memmove (mad->tempbuffer, mad_input_buffer, mad->tempsize);
1835 : : }
1836 : 0 : result = GST_FLOW_OK;
1837 : :
1838 : : end:
1839 : 0 : gst_buffer_unref (buffer);
1840 : :
1841 : 0 : return result;
1842 : : }
1843 : :
1844 : : static GstStateChangeReturn
1845 : 34 : gst_mad_change_state (GstElement * element, GstStateChange transition)
1846 : : {
1847 : : GstMad *mad;
1848 : : GstStateChangeReturn ret;
1849 : :
1850 : 34 : mad = GST_MAD (element);
1851 : :
1852 [ + + + + ]: 34 : switch (transition) {
1853 : : case GST_STATE_CHANGE_NULL_TO_READY:
1854 : 4 : break;
1855 : : case GST_STATE_CHANGE_READY_TO_PAUSED:
1856 : : {
1857 : 7 : guint options = 0;
1858 : :
1859 : 7 : mad_stream_init (&mad->stream);
1860 : 7 : mad_frame_init (&mad->frame);
1861 : 7 : mad_synth_init (&mad->synth);
1862 : 7 : mad->tempsize = 0;
1863 : 7 : mad->discont = TRUE;
1864 : 7 : mad->total_samples = 0;
1865 : 7 : mad->rate = 0;
1866 : 7 : mad->channels = 0;
1867 : 7 : mad->caps_set = FALSE;
1868 : 7 : mad->times_pending = mad->pending_rate = mad->pending_channels = 0;
1869 : 7 : mad->vbr_average = 0;
1870 : 7 : gst_segment_init (&mad->segment, GST_FORMAT_TIME);
1871 : 7 : mad->new_header = TRUE;
1872 : 7 : mad->framed = FALSE;
1873 : 7 : mad->framecount = 0;
1874 : 7 : mad->vbr_rate = 0;
1875 : 7 : mad->frame.header.samplerate = 0;
1876 : 7 : mad->last_ts = GST_CLOCK_TIME_NONE;
1877 [ + - ]: 7 : if (mad->ignore_crc)
1878 : 7 : options |= MAD_OPTION_IGNORECRC;
1879 [ - + ]: 7 : if (mad->half)
1880 : 0 : options |= MAD_OPTION_HALFSAMPLERATE;
1881 : 7 : mad_stream_options (&mad->stream, options);
1882 : 7 : break;
1883 : : }
1884 : : case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1885 : 6 : break;
1886 : : default:
1887 : 17 : break;
1888 : : }
1889 : :
1890 : 34 : ret = parent_class->change_state (element, transition);
1891 : :
1892 [ + + + + ]: 34 : switch (transition) {
1893 : : case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
1894 : 6 : break;
1895 : : case GST_STATE_CHANGE_PAUSED_TO_READY:
1896 : : mad_synth_finish (&mad->synth);
1897 : 7 : mad_frame_finish (&mad->frame);
1898 : 7 : mad_stream_finish (&mad->stream);
1899 : 7 : mad->restart = TRUE;
1900 : 7 : mad->check_for_xing = TRUE;
1901 [ - + ]: 7 : if (mad->tags) {
1902 : 0 : gst_tag_list_free (mad->tags);
1903 : 0 : mad->tags = NULL;
1904 : : }
1905 : 7 : gst_mad_clear_queues (mad);
1906 : 7 : break;
1907 : : case GST_STATE_CHANGE_READY_TO_NULL:
1908 : 4 : break;
1909 : : default:
1910 : 17 : break;
1911 : : }
1912 : 34 : return ret;
1913 : : }
1914 : :
1915 : : #ifdef HAVE_ID3TAG
1916 : : /* id3 tag helper (FIXME: why does mad parse id3 tags at all? It shouldn't) */
1917 : : static GstTagList *
1918 : 0 : gst_mad_id3_to_tag_list (const struct id3_tag *tag)
1919 : : {
1920 : : const struct id3_frame *frame;
1921 : : const id3_ucs4_t *ucs4;
1922 : : id3_utf8_t *utf8;
1923 : : GstTagList *tag_list;
1924 : : GType tag_type;
1925 : 0 : guint i = 0;
1926 : :
1927 : 0 : tag_list = gst_tag_list_new ();
1928 : :
1929 [ # # ]: 0 : while ((frame = id3_tag_findframe (tag, NULL, i++)) != NULL) {
1930 : : const union id3_field *field;
1931 : : unsigned int nstrings, j;
1932 : : const gchar *tag_name;
1933 : :
1934 : : /* find me the function to query the frame id */
1935 : 0 : gchar *id = g_strndup (frame->id, 5);
1936 : :
1937 : 0 : tag_name = gst_tag_from_id3_tag (id);
1938 [ # # ]: 0 : if (tag_name == NULL) {
1939 : 0 : g_free (id);
1940 : 0 : continue;
1941 : : }
1942 : :
1943 [ # # ]: 0 : if (strcmp (id, "COMM") == 0) {
1944 [ # # ]: 0 : if (frame->nfields < 4)
1945 : 0 : continue;
1946 : :
1947 : 0 : ucs4 = id3_field_getfullstring (&frame->fields[3]);
1948 [ # # ]: 0 : g_assert (ucs4);
1949 : :
1950 : 0 : utf8 = id3_ucs4_utf8duplicate (ucs4);
1951 [ # # ]: 0 : if (utf8 == 0)
1952 : 0 : continue;
1953 : :
1954 [ # # ]: 0 : if (!g_utf8_validate ((char *) utf8, -1, NULL)) {
1955 [ # # ]: 0 : GST_ERROR ("converted string is not valid utf-8");
1956 : 0 : g_free (utf8);
1957 : 0 : continue;
1958 : : }
1959 : :
1960 : 0 : gst_tag_list_add (tag_list, GST_TAG_MERGE_APPEND,
1961 : : GST_TAG_COMMENT, utf8, NULL);
1962 : :
1963 : 0 : g_free (utf8);
1964 : 0 : continue;
1965 : : }
1966 : :
1967 [ # # ]: 0 : if (frame->nfields < 2)
1968 : 0 : continue;
1969 : :
1970 : 0 : field = &frame->fields[1];
1971 : 0 : nstrings = id3_field_getnstrings (field);
1972 : :
1973 [ # # ]: 0 : for (j = 0; j < nstrings; ++j) {
1974 : 0 : ucs4 = id3_field_getstrings (field, j);
1975 [ # # ]: 0 : g_assert (ucs4);
1976 : :
1977 [ # # ]: 0 : if (strcmp (id, ID3_FRAME_GENRE) == 0)
1978 : 0 : ucs4 = id3_genre_name (ucs4);
1979 : :
1980 : 0 : utf8 = id3_ucs4_utf8duplicate (ucs4);
1981 [ # # ]: 0 : if (utf8 == 0)
1982 : 0 : continue;
1983 : :
1984 [ # # ]: 0 : if (!g_utf8_validate ((char *) utf8, -1, NULL)) {
1985 [ # # ]: 0 : GST_ERROR ("converted string is not valid utf-8");
1986 : 0 : free (utf8);
1987 : 0 : continue;
1988 : : }
1989 : :
1990 : 0 : tag_type = gst_tag_get_type (tag_name);
1991 : :
1992 : : /* be sure to add non-string tags here */
1993 [ # # # # ]: 0 : switch (tag_type) {
1994 : : case G_TYPE_UINT:
1995 : : {
1996 : : guint tmp;
1997 : : gchar *check;
1998 : :
1999 : 0 : tmp = strtoul ((char *) utf8, &check, 10);
2000 : :
2001 [ # # ]: 0 : if (strcmp (tag_name, GST_TAG_DATE) == 0) {
2002 : : GDate *d;
2003 : :
2004 [ # # ]: 0 : if (*check != '\0')
2005 : 0 : break;
2006 [ # # ]: 0 : if (tmp == 0)
2007 : 0 : break;
2008 : 0 : d = g_date_new_dmy (1, 1, tmp);
2009 : 0 : tmp = g_date_get_julian (d);
2010 : 0 : g_date_free (d);
2011 [ # # ]: 0 : } else if (strcmp (tag_name, GST_TAG_TRACK_NUMBER) == 0) {
2012 [ # # ]: 0 : if (*check == '/') {
2013 : : guint total;
2014 : :
2015 : 0 : check++;
2016 : 0 : total = strtoul (check, &check, 10);
2017 [ # # ]: 0 : if (*check != '\0')
2018 : 0 : break;
2019 : :
2020 : 0 : gst_tag_list_add (tag_list, GST_TAG_MERGE_APPEND,
2021 : : GST_TAG_TRACK_COUNT, total, NULL);
2022 : : }
2023 [ # # ]: 0 : } else if (strcmp (tag_name, GST_TAG_ALBUM_VOLUME_NUMBER) == 0) {
2024 [ # # ]: 0 : if (*check == '/') {
2025 : : guint total;
2026 : :
2027 : 0 : check++;
2028 : 0 : total = strtoul (check, &check, 10);
2029 [ # # ]: 0 : if (*check != '\0')
2030 : 0 : break;
2031 : :
2032 : 0 : gst_tag_list_add (tag_list, GST_TAG_MERGE_APPEND,
2033 : : GST_TAG_ALBUM_VOLUME_COUNT, total, NULL);
2034 : : }
2035 : : }
2036 : :
2037 [ # # ]: 0 : if (*check != '\0')
2038 : 0 : break;
2039 : 0 : gst_tag_list_add (tag_list, GST_TAG_MERGE_APPEND, tag_name, tmp,
2040 : : NULL);
2041 : 0 : break;
2042 : : }
2043 : : case G_TYPE_UINT64:
2044 : : {
2045 : : guint64 tmp;
2046 : :
2047 [ # # ]: 0 : g_assert (strcmp (tag_name, GST_TAG_DURATION) == 0);
2048 : 0 : tmp = strtoul ((char *) utf8, NULL, 10);
2049 [ # # ]: 0 : if (tmp == 0) {
2050 : 0 : break;
2051 : : }
2052 : 0 : gst_tag_list_add (tag_list, GST_TAG_MERGE_APPEND,
2053 : : GST_TAG_DURATION, tmp * 1000 * 1000, NULL);
2054 : 0 : break;
2055 : : }
2056 : : case G_TYPE_STRING:{
2057 : 0 : gst_tag_list_add (tag_list, GST_TAG_MERGE_APPEND,
2058 : : tag_name, (const gchar *) utf8, NULL);
2059 : 0 : break;
2060 : : }
2061 : : /* handles GST_TYPE_DATE and anything else */
2062 : : default:{
2063 : 0 : GValue src = { 0, };
2064 : 0 : GValue dest = { 0, };
2065 : :
2066 : 0 : g_value_init (&src, G_TYPE_STRING);
2067 : 0 : g_value_set_string (&src, (const gchar *) utf8);
2068 : :
2069 : 0 : g_value_init (&dest, tag_type);
2070 [ # # ]: 0 : if (g_value_transform (&src, &dest)) {
2071 : 0 : gst_tag_list_add_values (tag_list, GST_TAG_MERGE_APPEND,
2072 : : tag_name, &dest, NULL);
2073 : : } else {
2074 [ # # ]: 0 : GST_WARNING ("Failed to transform tag from string to type '%s'",
2075 : : g_type_name (tag_type));
2076 : : }
2077 : 0 : g_value_unset (&src);
2078 : 0 : g_value_unset (&dest);
2079 : 0 : break;
2080 : : }
2081 : : }
2082 : 0 : free (utf8);
2083 : : }
2084 : 0 : g_free (id);
2085 : : }
2086 : :
2087 : 0 : return tag_list;
2088 : : }
2089 : : #endif /* HAVE_ID3TAG */
2090 : :
2091 : : /* plugin initialisation */
2092 : :
2093 : : static gboolean
2094 : 5 : plugin_init (GstPlugin * plugin)
2095 : : {
2096 [ + - ]: 5 : GST_DEBUG_CATEGORY_INIT (mad_debug, "mad", 0, "mad mp3 decoding");
2097 : :
2098 : 5 : return gst_element_register (plugin, "mad", GST_RANK_SECONDARY,
2099 : : gst_mad_get_type ());
2100 : : }
2101 : :
2102 : : GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
2103 : : GST_VERSION_MINOR,
2104 : : "mad",
2105 : : "mp3 decoding based on the mad library",
2106 : : plugin_init, VERSION, "GPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);
|