1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: t; c-basic-offset: 2 -*- */
2 /* GStreamer AIFF parser
3 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
4 * <2006> Nokia Corporation, Stefan Kost <stefan.kost@nokia.com>.
5 * <2008> Pioneers of the Inevitable <songbird@songbirdnest.com>
6 *
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-aiffparse
26 * @title: aiffparse
27 *
28 * Parse a .aiff file into raw or compressed audio.
29 *
30 * The aiffparse element supports both push and pull mode operations, making it
31 * possible to stream from a network source.
32 *
33 * ## Example launch line
34 *
35 * |[
36 * gst-launch-1.0 filesrc location=sine.aiff ! aiffparse ! audioconvert ! alsasink
37 * ]|
38 * Read a aiff file and output to the soundcard using the ALSA element. The
39 * aiff file is assumed to contain raw uncompressed samples.
40 *
41 * |[
42 * gst-launch-1.0 souphttpsrc location=http://www.example.org/sine.aiff ! queue ! aiffparse ! audioconvert ! alsasink
43 * ]|
44 * Stream data from a network url.
45 *
46 */
47
48 #ifdef HAVE_CONFIG_H
49 #include "config.h"
50 #endif
51
52 #include <string.h>
53 #include <math.h>
54
55 #include "aiffparse.h"
56 #include <gst/audio/audio.h>
57 #include <gst/tag/tag.h>
58 #include <gst/pbutils/descriptions.h>
59 #include <gst/gst-i18n-plugin.h>
60
61 GST_DEBUG_CATEGORY (aiffparse_debug);
62 #define GST_CAT_DEFAULT (aiffparse_debug)
63
64 static void gst_aiff_parse_dispose (GObject * object);
65
66 static gboolean gst_aiff_parse_sink_activate (GstPad * sinkpad,
67 GstObject * parent);
68 static gboolean gst_aiff_parse_sink_activate_mode (GstPad * sinkpad,
69 GstObject * parent, GstPadMode mode, gboolean active);
70 static gboolean gst_aiff_parse_sink_event (GstPad * pad, GstObject * parent,
71 GstEvent * buf);
72 static gboolean gst_aiff_parse_send_event (GstElement * element,
73 GstEvent * event);
74 static GstStateChangeReturn gst_aiff_parse_change_state (GstElement * element,
75 GstStateChange transition);
76
77 static gboolean gst_aiff_parse_pad_query (GstPad * pad, GstObject * parent,
78 GstQuery * query);
79 static gboolean gst_aiff_parse_pad_convert (GstPad * pad,
80 GstFormat src_format,
81 gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
82
83 static GstFlowReturn gst_aiff_parse_chain (GstPad * pad, GstObject * parent,
84 GstBuffer * buf);
85 static void gst_aiff_parse_loop (GstPad * pad);
86 static gboolean gst_aiff_parse_srcpad_event (GstPad * pad, GstObject * parent,
87 GstEvent * event);
88
89 static GstStaticPadTemplate sink_template_factory =
90 GST_STATIC_PAD_TEMPLATE ("sink",
91 GST_PAD_SINK,
92 GST_PAD_ALWAYS,
93 GST_STATIC_CAPS ("audio/x-aiff")
94 );
95
96 static GstStaticPadTemplate src_template_factory =
97 GST_STATIC_PAD_TEMPLATE ("src",
98 GST_PAD_SRC,
99 GST_PAD_ALWAYS,
100 GST_STATIC_CAPS (GST_AUDIO_CAPS_MAKE ("{ S8, S16BE, S16LE, S24BE, S24LE, "
101 "S32LE, S32BE, F32BE, F64BE }"))
102 );
103
104 #define MAX_BUFFER_SIZE 4096
105
106 #define gst_aiff_parse_parent_class parent_class
107 G_DEFINE_TYPE (GstAiffParse, gst_aiff_parse, GST_TYPE_ELEMENT);
108
109 static void
gst_aiff_parse_class_init(GstAiffParseClass * klass)110 gst_aiff_parse_class_init (GstAiffParseClass * klass)
111 {
112 GstElementClass *gstelement_class;
113 GObjectClass *object_class;
114
115 gstelement_class = (GstElementClass *) klass;
116 object_class = (GObjectClass *) klass;
117
118 object_class->dispose = gst_aiff_parse_dispose;
119
120 gst_element_class_add_static_pad_template (gstelement_class,
121 &sink_template_factory);
122 gst_element_class_add_static_pad_template (gstelement_class,
123 &src_template_factory);
124
125 gst_element_class_set_static_metadata (gstelement_class,
126 "AIFF audio demuxer", "Codec/Demuxer/Audio",
127 "Parse a .aiff file into raw audio",
128 "Pioneers of the Inevitable <songbird@songbirdnest.com>");
129
130 gstelement_class->change_state =
131 GST_DEBUG_FUNCPTR (gst_aiff_parse_change_state);
132 gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_aiff_parse_send_event);
133 }
134
135 static void
gst_aiff_parse_reset(GstAiffParse * aiff)136 gst_aiff_parse_reset (GstAiffParse * aiff)
137 {
138 aiff->state = AIFF_PARSE_START;
139
140 /* These will all be set correctly in the fmt chunk */
141 aiff->rate = 0;
142 aiff->width = 0;
143 aiff->depth = 0;
144 aiff->channels = 0;
145 aiff->bps = 0;
146 aiff->offset = 0;
147 aiff->end_offset = 0;
148 aiff->dataleft = 0;
149 aiff->datasize = 0;
150 aiff->datastart = 0;
151 aiff->duration = 0;
152 aiff->got_comm = FALSE;
153
154 if (aiff->seek_event)
155 gst_event_unref (aiff->seek_event);
156 aiff->seek_event = NULL;
157 if (aiff->adapter) {
158 gst_adapter_clear (aiff->adapter);
159 aiff->adapter = NULL;
160 }
161
162 if (aiff->tags != NULL) {
163 gst_tag_list_unref (aiff->tags);
164 aiff->tags = NULL;
165 }
166 }
167
168 static void
gst_aiff_parse_dispose(GObject * object)169 gst_aiff_parse_dispose (GObject * object)
170 {
171 GstAiffParse *aiff = GST_AIFF_PARSE (object);
172
173 GST_DEBUG_OBJECT (aiff, "AIFF: Dispose");
174 gst_aiff_parse_reset (aiff);
175
176 G_OBJECT_CLASS (parent_class)->dispose (object);
177 }
178
179 static void
gst_aiff_parse_init(GstAiffParse * aiffparse)180 gst_aiff_parse_init (GstAiffParse * aiffparse)
181 {
182 gst_aiff_parse_reset (aiffparse);
183
184 /* sink */
185 aiffparse->sinkpad =
186 gst_pad_new_from_static_template (&sink_template_factory, "sink");
187 gst_pad_set_activate_function (aiffparse->sinkpad,
188 GST_DEBUG_FUNCPTR (gst_aiff_parse_sink_activate));
189 gst_pad_set_activatemode_function (aiffparse->sinkpad,
190 GST_DEBUG_FUNCPTR (gst_aiff_parse_sink_activate_mode));
191 gst_pad_set_event_function (aiffparse->sinkpad,
192 GST_DEBUG_FUNCPTR (gst_aiff_parse_sink_event));
193 gst_pad_set_chain_function (aiffparse->sinkpad,
194 GST_DEBUG_FUNCPTR (gst_aiff_parse_chain));
195 gst_element_add_pad (GST_ELEMENT_CAST (aiffparse), aiffparse->sinkpad);
196
197 /* source */
198 aiffparse->srcpad =
199 gst_pad_new_from_static_template (&src_template_factory, "src");
200 gst_pad_use_fixed_caps (aiffparse->srcpad);
201 gst_pad_set_query_function (aiffparse->srcpad,
202 GST_DEBUG_FUNCPTR (gst_aiff_parse_pad_query));
203 gst_pad_set_event_function (aiffparse->srcpad,
204 GST_DEBUG_FUNCPTR (gst_aiff_parse_srcpad_event));
205 gst_element_add_pad (GST_ELEMENT_CAST (aiffparse), aiffparse->srcpad);
206 }
207
208 static gboolean
gst_aiff_parse_parse_file_header(GstAiffParse * aiff,GstBuffer * buf)209 gst_aiff_parse_parse_file_header (GstAiffParse * aiff, GstBuffer * buf)
210 {
211 guint32 header, type = 0;
212 GstMapInfo info;
213
214 if (!gst_buffer_map (buf, &info, GST_MAP_READ)) {
215 GST_WARNING_OBJECT (aiff, "Could not map buffer");
216 goto not_aiff;
217 }
218
219 if (info.size < 12) {
220 GST_WARNING_OBJECT (aiff, "Buffer too short");
221 gst_buffer_unmap (buf, &info);
222 goto not_aiff;
223 }
224
225 header = GST_READ_UINT32_LE (info.data);
226 type = GST_READ_UINT32_LE (info.data + 8);
227 gst_buffer_unmap (buf, &info);
228
229 if (header != GST_MAKE_FOURCC ('F', 'O', 'R', 'M'))
230 goto not_aiff;
231
232 if (type == GST_MAKE_FOURCC ('A', 'I', 'F', 'F'))
233 aiff->is_aifc = FALSE;
234 else if (type == GST_MAKE_FOURCC ('A', 'I', 'F', 'C'))
235 aiff->is_aifc = TRUE;
236 else
237 goto not_aiff;
238
239 gst_buffer_unref (buf);
240 return TRUE;
241
242 /* ERRORS */
243 not_aiff:
244 {
245 GST_ELEMENT_ERROR (aiff, STREAM, WRONG_TYPE, (NULL),
246 ("File is not an AIFF file: 0x%" G_GINT32_MODIFIER "x", type));
247 gst_buffer_unref (buf);
248 return FALSE;
249 }
250 }
251
252 static GstFlowReturn
gst_aiff_parse_stream_init(GstAiffParse * aiff)253 gst_aiff_parse_stream_init (GstAiffParse * aiff)
254 {
255 GstFlowReturn res;
256 GstBuffer *buf = NULL;
257
258 if ((res = gst_pad_pull_range (aiff->sinkpad,
259 aiff->offset, 12, &buf)) != GST_FLOW_OK)
260 return res;
261 else if (!gst_aiff_parse_parse_file_header (aiff, buf))
262 return GST_FLOW_ERROR;
263
264 aiff->offset += 12;
265
266 return GST_FLOW_OK;
267 }
268
269 static gboolean
gst_aiff_parse_time_to_bytepos(GstAiffParse * aiff,gint64 ts,gint64 * bytepos)270 gst_aiff_parse_time_to_bytepos (GstAiffParse * aiff, gint64 ts,
271 gint64 * bytepos)
272 {
273 /* -1 always maps to -1 */
274 if (ts == -1) {
275 *bytepos = -1;
276 return TRUE;
277 }
278
279 /* 0 always maps to 0 */
280 if (ts == 0) {
281 *bytepos = 0;
282 return TRUE;
283 }
284
285 if (aiff->bps > 0) {
286 *bytepos = gst_util_uint64_scale_ceil (ts, (guint64) aiff->bps, GST_SECOND);
287 return TRUE;
288 }
289
290 GST_WARNING_OBJECT (aiff, "No valid bps to convert position");
291
292 return FALSE;
293 }
294
295 /* This function is used to perform seeks on the element in
296 * pull mode.
297 *
298 * It also works when event is NULL, in which case it will just
299 * start from the last configured segment. This technique is
300 * used when activating the element and to perform the seek in
301 * READY.
302 */
303 static gboolean
gst_aiff_parse_perform_seek(GstAiffParse * aiff,GstEvent * event,gboolean starting)304 gst_aiff_parse_perform_seek (GstAiffParse * aiff, GstEvent * event,
305 gboolean starting)
306 {
307 gboolean res;
308 gdouble rate;
309 GstFormat format;
310 GstSeekFlags flags;
311 GstSeekType start_type = GST_SEEK_TYPE_NONE, stop_type;
312 gint64 start, stop, upstream_size;
313 gboolean flush;
314 gboolean update;
315 GstSegment seeksegment = { 0, };
316 gint64 position;
317
318 if (event) {
319 GST_DEBUG_OBJECT (aiff, "doing seek with event");
320
321 gst_event_parse_seek (event, &rate, &format, &flags,
322 &start_type, &start, &stop_type, &stop);
323
324 /* no negative rates yet */
325 if (rate < 0.0)
326 goto negative_rate;
327
328 if (format != aiff->segment.format) {
329 GST_INFO_OBJECT (aiff, "converting seek-event from %s to %s",
330 gst_format_get_name (format),
331 gst_format_get_name (aiff->segment.format));
332 res = TRUE;
333 if (start_type != GST_SEEK_TYPE_NONE)
334 res =
335 gst_pad_query_convert (aiff->srcpad, format, start,
336 aiff->segment.format, &start);
337 if (res && stop_type != GST_SEEK_TYPE_NONE)
338 res =
339 gst_pad_query_convert (aiff->srcpad, format, stop,
340 aiff->segment.format, &stop);
341 if (!res)
342 goto no_format;
343
344 format = aiff->segment.format;
345 }
346 } else {
347 GST_DEBUG_OBJECT (aiff, "doing seek without event");
348 flags = 0;
349 rate = 1.0;
350 start = 0;
351 start_type = GST_SEEK_TYPE_SET;
352 stop = -1;
353 stop_type = GST_SEEK_TYPE_SET;
354 }
355
356 /* get flush flag */
357 flush = flags & GST_SEEK_FLAG_FLUSH;
358
359 if (aiff->streaming && !starting) {
360 GstEvent *new_event;
361
362 /* streaming seek */
363 if ((start_type != GST_SEEK_TYPE_NONE)) {
364 /* bring offset to bytes, if the bps is 0, we have the segment in BYTES and
365 * we can just copy the position. If not, we use the bps to convert TIME to
366 * bytes. */
367 if (aiff->bps > 0)
368 start =
369 gst_util_uint64_scale_ceil (start, (guint64) aiff->bps, GST_SECOND);
370 start -= (start % aiff->bytes_per_sample);
371 start += aiff->datastart;
372 }
373
374 if (stop_type != GST_SEEK_TYPE_NONE) {
375 if (aiff->bps > 0)
376 stop =
377 gst_util_uint64_scale_ceil (stop, (guint64) aiff->bps, GST_SECOND);
378 stop -= (stop % aiff->bytes_per_sample);
379 stop += aiff->datastart;
380 }
381
382 /* make sure filesize is not exceeded due to rounding errors or so,
383 * same precaution as in _stream_headers */
384 if (gst_pad_peer_query_duration (aiff->sinkpad, GST_FORMAT_BYTES,
385 &upstream_size))
386 stop = MIN (stop, upstream_size);
387
388 if (stop >= 0 && stop <= start)
389 stop = start;
390
391 new_event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags,
392 start_type, start, stop_type, stop);
393
394 res = gst_pad_push_event (aiff->sinkpad, new_event);
395 } else {
396 /* now we need to make sure the streaming thread is stopped. We do this by
397 * either sending a FLUSH_START event downstream which will cause the
398 * streaming thread to stop with a FLUSHING.
399 * For a non-flushing seek we simply pause the task, which will happen as soon
400 * as it completes one iteration (and thus might block when the sink is
401 * blocking in preroll). */
402 if (flush) {
403 GST_DEBUG_OBJECT (aiff, "sending flush start");
404 gst_pad_push_event (aiff->srcpad, gst_event_new_flush_start ());
405 } else {
406 gst_pad_pause_task (aiff->sinkpad);
407 }
408
409 /* we should now be able to grab the streaming thread because we stopped it
410 * with the above flush/pause code */
411 GST_PAD_STREAM_LOCK (aiff->sinkpad);
412
413 /* save current position */
414 position = aiff->segment.position;
415
416 GST_DEBUG_OBJECT (aiff, "stopped streaming at %" G_GINT64_FORMAT, position);
417
418 /* copy segment, we need this because we still need the old
419 * segment when we close the current segment. */
420 memcpy (&seeksegment, &aiff->segment, sizeof (GstSegment));
421
422 /* configure the seek parameters in the seeksegment. We will then have the
423 * right values in the segment to perform the seek */
424 if (event) {
425 GST_DEBUG_OBJECT (aiff, "configuring seek");
426 gst_segment_do_seek (&seeksegment, rate, format, flags,
427 start_type, start, stop_type, stop, &update);
428 }
429
430 /* figure out the last position we need to play. If it's configured (stop !=
431 * -1), use that, else we play until the total duration of the file */
432 if ((stop = seeksegment.stop) == -1)
433 stop = seeksegment.duration;
434
435 GST_DEBUG_OBJECT (aiff, "start_type =%d", start_type);
436 if ((start_type != GST_SEEK_TYPE_NONE)) {
437 /* bring offset to bytes, if the bps is 0, we have the segment in BYTES and
438 * we can just copy the position. If not, we use the bps to convert TIME to
439 * bytes. */
440 if (aiff->bps > 0)
441 aiff->offset =
442 gst_util_uint64_scale_ceil (seeksegment.position,
443 (guint64) aiff->bps, GST_SECOND);
444 else
445 aiff->offset = seeksegment.position;
446 GST_LOG_OBJECT (aiff, "offset=%" G_GUINT64_FORMAT, aiff->offset);
447 aiff->offset -= (aiff->offset % aiff->bytes_per_sample);
448 GST_LOG_OBJECT (aiff, "offset=%" G_GUINT64_FORMAT, aiff->offset);
449 aiff->offset += aiff->datastart;
450 GST_LOG_OBJECT (aiff, "offset=%" G_GUINT64_FORMAT, aiff->offset);
451 } else {
452 GST_LOG_OBJECT (aiff, "continue from offset=%" G_GUINT64_FORMAT,
453 aiff->offset);
454 }
455
456 if (stop_type != GST_SEEK_TYPE_NONE) {
457 if (aiff->bps > 0)
458 aiff->end_offset =
459 gst_util_uint64_scale_ceil (stop, (guint64) aiff->bps, GST_SECOND);
460 else
461 aiff->end_offset = stop;
462 GST_LOG_OBJECT (aiff, "end_offset=%" G_GUINT64_FORMAT, aiff->end_offset);
463 aiff->end_offset -= (aiff->end_offset % aiff->bytes_per_sample);
464 GST_LOG_OBJECT (aiff, "end_offset=%" G_GUINT64_FORMAT, aiff->end_offset);
465 aiff->end_offset += aiff->datastart;
466 GST_LOG_OBJECT (aiff, "end_offset=%" G_GUINT64_FORMAT, aiff->end_offset);
467 } else {
468 GST_LOG_OBJECT (aiff, "continue to end_offset=%" G_GUINT64_FORMAT,
469 aiff->end_offset);
470 }
471
472 /* make sure filesize is not exceeded due to rounding errors or so,
473 * same precaution as in _stream_headers */
474 if (gst_pad_peer_query_duration (aiff->sinkpad, GST_FORMAT_BYTES,
475 &upstream_size))
476 aiff->end_offset = MIN (aiff->end_offset, upstream_size);
477
478 /* this is the range of bytes we will use for playback */
479 aiff->offset = MIN (aiff->offset, aiff->end_offset);
480 aiff->dataleft = aiff->end_offset - aiff->offset;
481
482 GST_DEBUG_OBJECT (aiff,
483 "seek: rate %lf, offset %" G_GUINT64_FORMAT ", end %" G_GUINT64_FORMAT
484 ", segment %" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT, rate,
485 aiff->offset, aiff->end_offset, GST_TIME_ARGS (seeksegment.start),
486 GST_TIME_ARGS (stop));
487
488 /* prepare for streaming again */
489 if (flush) {
490 /* if we sent a FLUSH_START, we now send a FLUSH_STOP */
491 GST_DEBUG_OBJECT (aiff, "sending flush stop");
492 gst_pad_push_event (aiff->srcpad, gst_event_new_flush_stop (TRUE));
493 }
494
495 /* now we did the seek and can activate the new segment values */
496 memcpy (&aiff->segment, &seeksegment, sizeof (GstSegment));
497
498 /* if we're doing a segment seek, post a SEGMENT_START message */
499 if (aiff->segment.flags & GST_SEEK_FLAG_SEGMENT) {
500 gst_element_post_message (GST_ELEMENT_CAST (aiff),
501 gst_message_new_segment_start (GST_OBJECT_CAST (aiff),
502 aiff->segment.format, aiff->segment.position));
503 }
504
505 /* now create the segment */
506 GST_DEBUG_OBJECT (aiff, "Creating segment from %" G_GINT64_FORMAT
507 " to %" G_GINT64_FORMAT, aiff->segment.position, stop);
508
509 /* store the segment event so it can be sent from the streaming thread. */
510 if (aiff->start_segment)
511 gst_event_unref (aiff->start_segment);
512 aiff->start_segment = gst_event_new_segment (&aiff->segment);
513
514 /* mark discont if we are going to stream from another position. */
515 if (position != aiff->segment.position) {
516 GST_DEBUG_OBJECT (aiff,
517 "mark DISCONT, we did a seek to another position");
518 aiff->discont = TRUE;
519 }
520
521 /* and start the streaming task again */
522 aiff->segment_running = TRUE;
523 if (!aiff->streaming) {
524 gst_pad_start_task (aiff->sinkpad, (GstTaskFunction) gst_aiff_parse_loop,
525 aiff->sinkpad, NULL);
526 }
527
528 GST_PAD_STREAM_UNLOCK (aiff->sinkpad);
529
530 res = TRUE;
531 }
532
533 return res;
534
535 /* ERRORS */
536 negative_rate:
537 {
538 GST_DEBUG_OBJECT (aiff, "negative playback rates are not supported yet.");
539 return FALSE;
540 }
541 no_format:
542 {
543 GST_DEBUG_OBJECT (aiff, "unsupported format given, seek aborted.");
544 return FALSE;
545 }
546 }
547
548 /*
549 * gst_aiff_parse_peek_chunk_info:
550 * @aiff AIFFparse object
551 * @tag holder for tag
552 * @size holder for tag size
553 *
554 * Peek next chunk info (tag and size)
555 *
556 * Returns: %TRUE when the chunk info (header) is available
557 */
558 static gboolean
gst_aiff_parse_peek_chunk_info(GstAiffParse * aiff,guint32 * tag,guint32 * size)559 gst_aiff_parse_peek_chunk_info (GstAiffParse * aiff, guint32 * tag,
560 guint32 * size)
561 {
562 const guint8 *data = NULL;
563
564 if (gst_adapter_available (aiff->adapter) < 8)
565 return FALSE;
566
567 data = gst_adapter_map (aiff->adapter, 8);
568 *tag = GST_READ_UINT32_LE (data);
569 *size = GST_READ_UINT32_BE (data + 4);
570 gst_adapter_unmap (aiff->adapter);
571
572 GST_DEBUG_OBJECT (aiff,
573 "Next chunk size is %d bytes, type %" GST_FOURCC_FORMAT, *size,
574 GST_FOURCC_ARGS (*tag));
575
576 return TRUE;
577 }
578
579 /*
580 * gst_aiff_parse_peek_chunk:
581 * @aiff AIFFparse object
582 * @tag holder for tag
583 * @size holder for tag size
584 *
585 * Peek enough data for one full chunk
586 *
587 * Returns: %TRUE when the full chunk is available
588 */
589 static gboolean
gst_aiff_parse_peek_chunk(GstAiffParse * aiff,guint32 * tag,guint32 * size)590 gst_aiff_parse_peek_chunk (GstAiffParse * aiff, guint32 * tag, guint32 * size)
591 {
592 guint32 peek_size = 0;
593 guint available;
594
595 if (!gst_aiff_parse_peek_chunk_info (aiff, tag, size))
596 return FALSE;
597
598 GST_DEBUG_OBJECT (aiff, "Need to peek chunk of %d bytes", *size);
599 peek_size = (*size + 1) & ~1;
600
601 available = gst_adapter_available (aiff->adapter);
602 if (available >= (8 + peek_size)) {
603 return TRUE;
604 } else {
605 GST_LOG_OBJECT (aiff, "but only %u bytes available now", available);
606 return FALSE;
607 }
608 }
609
610 static gboolean
gst_aiff_parse_peek_data(GstAiffParse * aiff,guint32 size,const guint8 ** data)611 gst_aiff_parse_peek_data (GstAiffParse * aiff, guint32 size,
612 const guint8 ** data)
613 {
614 if (gst_adapter_available (aiff->adapter) < size)
615 return FALSE;
616
617 *data = gst_adapter_map (aiff->adapter, size);
618 return TRUE;
619 }
620
621 /*
622 * gst_aiff_parse_calculate_duration:
623 * @aiff: aiffparse object
624 *
625 * Calculate duration on demand and store in @aiff.
626 *
627 * Returns: %TRUE if duration is available.
628 */
629 static gboolean
gst_aiff_parse_calculate_duration(GstAiffParse * aiff)630 gst_aiff_parse_calculate_duration (GstAiffParse * aiff)
631 {
632 if (aiff->duration > 0)
633 return TRUE;
634
635 if (aiff->datasize > 0 && aiff->bps > 0) {
636 aiff->duration =
637 gst_util_uint64_scale_ceil (aiff->datasize, GST_SECOND,
638 (guint64) aiff->bps);
639 GST_INFO_OBJECT (aiff, "Got duration %" GST_TIME_FORMAT,
640 GST_TIME_ARGS (aiff->duration));
641 return TRUE;
642 }
643 return FALSE;
644 }
645
646 static gboolean
gst_aiff_parse_ignore_chunk(GstAiffParse * aiff,guint32 tag,guint32 size)647 gst_aiff_parse_ignore_chunk (GstAiffParse * aiff, guint32 tag, guint32 size)
648 {
649 guint flush;
650
651 if (aiff->streaming) {
652 if (!gst_aiff_parse_peek_chunk (aiff, &tag, &size)) {
653 GST_LOG_OBJECT (aiff, "Not enough data to skip tag %" GST_FOURCC_FORMAT,
654 GST_FOURCC_ARGS (tag));
655 return FALSE;
656 }
657 }
658 GST_WARNING_OBJECT (aiff, "Ignoring tag %" GST_FOURCC_FORMAT,
659 GST_FOURCC_ARGS (tag));
660 flush = 8 + ((size + 1) & ~1);
661 aiff->offset += flush;
662 if (aiff->streaming) {
663 gst_adapter_flush (aiff->adapter, flush);
664 }
665 return TRUE;
666 }
667
668 static double
gst_aiff_parse_read_IEEE80(guint8 * buf)669 gst_aiff_parse_read_IEEE80 (guint8 * buf)
670 {
671 int s = buf[0] & 0xff;
672 int e = ((buf[0] & 0x7f) << 8) | (buf[1] & 0xff);
673 double f = ((unsigned long) (buf[2] & 0xff) << 24) |
674 ((buf[3] & 0xff) << 16) | ((buf[4] & 0xff) << 8) | (buf[5] & 0xff);
675
676 if (e == 32767) {
677 if (buf[2] & 0x80)
678 return HUGE_VAL; /* Really NaN, but this won't happen in reality */
679 else {
680 if (s)
681 return -HUGE_VAL;
682 else
683 return HUGE_VAL;
684 }
685 }
686
687 f = ldexp (f, 32);
688 f += ((buf[6] & 0xff) << 24) |
689 ((buf[7] & 0xff) << 16) | ((buf[8] & 0xff) << 8) | (buf[9] & 0xff);
690
691 return ldexp (f, e - 16446);
692 }
693
694 static gboolean
gst_aiff_parse_parse_comm(GstAiffParse * aiff,GstBuffer * buf)695 gst_aiff_parse_parse_comm (GstAiffParse * aiff, GstBuffer * buf)
696 {
697 int size;
698 GstMapInfo info;
699 guint32 fourcc;
700
701 if (!gst_buffer_map (buf, &info, GST_MAP_READ)) {
702 GST_WARNING_OBJECT (aiff, "Can't map buffer");
703 gst_buffer_unref (buf);
704 return FALSE;
705 }
706
707 if (aiff->is_aifc)
708 size = 22;
709 else
710 size = 18;
711
712 if (info.size < size)
713 goto too_small;
714
715 aiff->channels = GST_READ_UINT16_BE (info.data);
716 aiff->total_frames = GST_READ_UINT32_BE (info.data + 2);
717 aiff->depth = GST_READ_UINT16_BE (info.data + 6);
718 aiff->width = GST_ROUND_UP_8 (aiff->depth);
719 aiff->rate = (int) gst_aiff_parse_read_IEEE80 (info.data + 8);
720
721 aiff->floating_point = FALSE;
722
723 if (aiff->is_aifc) {
724 fourcc = GST_READ_UINT32_LE (info.data + 18);
725
726 /* We only support the 'trivial' uncompressed AIFC, but it can be
727 * either big or little endian */
728 switch (fourcc) {
729 case GST_MAKE_FOURCC ('N', 'O', 'N', 'E'):
730 aiff->endianness = G_BIG_ENDIAN;
731 break;
732 case GST_MAKE_FOURCC ('s', 'o', 'w', 't'):
733 aiff->endianness = G_LITTLE_ENDIAN;
734 break;
735 case GST_MAKE_FOURCC ('F', 'L', '3', '2'):
736 case GST_MAKE_FOURCC ('f', 'l', '3', '2'):
737 aiff->floating_point = TRUE;
738 aiff->width = aiff->depth = 32;
739 aiff->endianness = G_BIG_ENDIAN;
740 break;
741 case GST_MAKE_FOURCC ('f', 'l', '6', '4'):
742 aiff->floating_point = TRUE;
743 aiff->width = aiff->depth = 64;
744 aiff->endianness = G_BIG_ENDIAN;
745 break;
746 default:
747 goto unknown_compression;
748 }
749 } else
750 aiff->endianness = G_BIG_ENDIAN;
751
752 gst_buffer_unmap (buf, &info);
753 gst_buffer_unref (buf);
754
755 return TRUE;
756
757 /* ERRORS */
758 too_small:
759 {
760 GST_WARNING_OBJECT (aiff, "COMM chunk too short, cannot parse header");
761 gst_buffer_unmap (buf, &info);
762 gst_buffer_unref (buf);
763 return FALSE;
764 }
765 unknown_compression:
766 {
767 GST_WARNING_OBJECT (aiff, "Unsupported compression in AIFC "
768 "file: %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (fourcc));
769 gst_buffer_unmap (buf, &info);
770 gst_buffer_unref (buf);
771 return FALSE;
772 }
773 }
774
775 static GstFlowReturn
gst_aiff_parse_read_chunk(GstAiffParse * aiff,guint64 * offset,guint32 * tag,GstBuffer ** data)776 gst_aiff_parse_read_chunk (GstAiffParse * aiff, guint64 * offset, guint32 * tag,
777 GstBuffer ** data)
778 {
779 guint size;
780 GstFlowReturn res;
781 GstBuffer *buf = NULL;
782 GstMapInfo info;
783
784 if ((res =
785 gst_pad_pull_range (aiff->sinkpad, *offset, 8, &buf)) != GST_FLOW_OK)
786 return res;
787
788 gst_buffer_map (buf, &info, GST_MAP_READ);
789 *tag = GST_READ_UINT32_LE (info.data);
790 size = GST_READ_UINT32_BE (info.data + 4);
791 gst_buffer_unmap (buf, &info);
792 gst_buffer_unref (buf);
793 buf = NULL;
794
795 if ((res =
796 gst_pad_pull_range (aiff->sinkpad, (*offset) + 8, size,
797 &buf)) != GST_FLOW_OK)
798 return res;
799 else if (gst_buffer_get_size (buf) < size)
800 goto too_small;
801
802 *data = buf;
803 *offset += 8 + GST_ROUND_UP_2 (size);
804
805 return GST_FLOW_OK;
806
807 /* ERRORS */
808 too_small:
809 {
810 /* short read, we return EOS to mark the EOS case */
811 GST_DEBUG_OBJECT (aiff,
812 "not enough data (available=%" G_GSIZE_FORMAT ", needed=%u)",
813 gst_buffer_get_size (buf), size);
814 gst_buffer_unref (buf);
815 return GST_FLOW_EOS;
816 }
817
818 }
819
820 #define _P(pos) (G_GUINT64_CONSTANT (1) << GST_AUDIO_CHANNEL_POSITION_ ##pos)
821
822 static GstCaps *
gst_aiff_parse_create_caps(GstAiffParse * aiff)823 gst_aiff_parse_create_caps (GstAiffParse * aiff)
824 {
825 GstCaps *caps = NULL;
826 const gchar *format = NULL;
827 guint64 channel_mask;
828
829 if (aiff->floating_point) {
830 if (aiff->endianness == G_BIG_ENDIAN) {
831 if (aiff->width == 32)
832 format = "F32BE";
833 else if (aiff->width == 64)
834 format = "F64BE";
835 }
836 } else {
837 if (aiff->endianness == G_BIG_ENDIAN) {
838 if (aiff->width == 8)
839 format = "S8";
840 else if (aiff->width == 16)
841 format = "S16BE";
842 else if (aiff->width == 24)
843 format = "S24BE";
844 else if (aiff->width == 32)
845 format = "S32BE";
846 } else {
847 if (aiff->width == 8)
848 format = "S8";
849 else if (aiff->width == 16)
850 format = "S16LE";
851 else if (aiff->width == 24)
852 format = "S24LE";
853 else if (aiff->width == 32)
854 format = "S32LE";
855 }
856 }
857 if (format) {
858 caps = gst_caps_new_simple ("audio/x-raw",
859 "format", G_TYPE_STRING, format,
860 "channels", G_TYPE_INT, aiff->channels,
861 "layout", G_TYPE_STRING, "interleaved",
862 "rate", G_TYPE_INT, aiff->rate, NULL);
863 }
864
865 if (aiff->channels > 2) {
866 GST_FIXME_OBJECT (aiff, "using fallback channel layout for %d channels",
867 aiff->channels);
868
869 /* based on AIFF-1.3.pdf */
870 switch (aiff->channels) {
871 case 1:
872 channel_mask = 0;
873 break;
874 case 2:
875 channel_mask = _P (FRONT_LEFT) | _P (FRONT_RIGHT);
876 break;
877 case 3:
878 channel_mask = _P (FRONT_LEFT) | _P (FRONT_RIGHT) | _P (FRONT_CENTER);
879 break;
880 case 4:
881 /* lists both this and 'quad' but doesn't say how to distinguish the two */
882 channel_mask =
883 _P (FRONT_LEFT) | _P (FRONT_RIGHT) | _P (REAR_LEFT) |
884 _P (REAR_RIGHT);
885 break;
886 case 6:
887 channel_mask =
888 _P (FRONT_LEFT) | _P (FRONT_LEFT_OF_CENTER) | _P (FRONT_CENTER) |
889 _P (FRONT_RIGHT) | _P (FRONT_RIGHT_OF_CENTER) | _P (LFE1);
890 break;
891 default:
892 channel_mask = gst_audio_channel_get_fallback_mask (aiff->channels);
893 break;
894 }
895
896
897 if (channel_mask != 0) {
898 gst_caps_set_simple (caps, "channel-mask", GST_TYPE_BITMASK, channel_mask,
899 NULL);
900 }
901 }
902
903 GST_DEBUG_OBJECT (aiff, "Created caps: %" GST_PTR_FORMAT, caps);
904
905 return caps;
906 }
907
908 static GstFlowReturn
gst_aiff_parse_stream_headers(GstAiffParse * aiff)909 gst_aiff_parse_stream_headers (GstAiffParse * aiff)
910 {
911 GstFlowReturn res;
912 GstBuffer *buf = NULL;
913 guint32 tag, size;
914 gboolean gotdata = FALSE;
915 gboolean done = FALSE;
916 GstEvent **event_p;
917 gint64 upstream_size = 0;
918
919 gst_pad_peer_query_duration (aiff->sinkpad, GST_FORMAT_BYTES, &upstream_size);
920 GST_DEBUG_OBJECT (aiff, "upstream size %" G_GUINT64_FORMAT, upstream_size);
921
922 /* loop headers until we get data */
923 while (!done) {
924 if (aiff->streaming) {
925 if (!gst_aiff_parse_peek_chunk_info (aiff, &tag, &size))
926 return GST_FLOW_OK;
927 } else {
928 GstMapInfo info;
929
930 if ((res =
931 gst_pad_pull_range (aiff->sinkpad, aiff->offset, 8,
932 &buf)) != GST_FLOW_OK)
933 goto header_read_error;
934
935 gst_buffer_map (buf, &info, GST_MAP_READ);
936 tag = GST_READ_UINT32_LE (info.data);
937 size = GST_READ_UINT32_BE (info.data + 4);
938 gst_buffer_unmap (buf, &info);
939 gst_buffer_unref (buf);
940 buf = NULL;
941 }
942
943 GST_INFO_OBJECT (aiff,
944 "Got TAG: %" GST_FOURCC_FORMAT ", offset %" G_GUINT64_FORMAT,
945 GST_FOURCC_ARGS (tag), aiff->offset);
946
947 /* We just keep reading chunks until we find the one we're interested in.
948 */
949 switch (tag) {
950 case GST_MAKE_FOURCC ('C', 'O', 'M', 'M'):{
951 GstCaps *caps;
952 GstEvent *event;
953 gchar *stream_id;
954
955 if (aiff->streaming) {
956 if (!gst_aiff_parse_peek_chunk (aiff, &tag, &size))
957 return GST_FLOW_OK;
958
959 gst_adapter_flush (aiff->adapter, 8);
960 aiff->offset += 8;
961
962 buf = gst_adapter_take_buffer (aiff->adapter, size);
963 aiff->offset += size;
964 } else {
965 if ((res = gst_aiff_parse_read_chunk (aiff,
966 &aiff->offset, &tag, &buf)) != GST_FLOW_OK)
967 return res;
968 }
969
970 if (!gst_aiff_parse_parse_comm (aiff, buf))
971 goto parse_header_error;
972
973 /* do sanity checks of header fields */
974 if (aiff->channels == 0)
975 goto no_channels;
976 if (aiff->rate == 0)
977 goto no_rate;
978
979 stream_id =
980 gst_pad_create_stream_id (aiff->srcpad, GST_ELEMENT_CAST (aiff),
981 NULL);
982 event = gst_event_new_stream_start (stream_id);
983 gst_event_set_group_id (event, gst_util_group_id_next ());
984 gst_pad_push_event (aiff->srcpad, event);
985 g_free (stream_id);
986
987 GST_DEBUG_OBJECT (aiff, "creating the caps");
988
989 caps = gst_aiff_parse_create_caps (aiff);
990 if (caps == NULL)
991 goto unknown_format;
992
993 gst_pad_push_event (aiff->srcpad, gst_event_new_caps (caps));
994 gst_caps_unref (caps);
995
996 aiff->bytes_per_sample = aiff->channels * aiff->width / 8;
997 aiff->bps = aiff->bytes_per_sample * aiff->rate;
998
999 if (!aiff->tags)
1000 aiff->tags = gst_tag_list_new_empty ();
1001
1002 {
1003 GstCaps *templ_caps = gst_pad_get_pad_template_caps (aiff->sinkpad);
1004 gst_pb_utils_add_codec_description_to_tag_list (aiff->tags,
1005 GST_TAG_CONTAINER_FORMAT, templ_caps);
1006 gst_caps_unref (templ_caps);
1007 }
1008
1009 if (aiff->bps) {
1010 guint bitrate = aiff->bps * 8;
1011
1012 GST_DEBUG_OBJECT (aiff, "adding bitrate of %u bps to tag list",
1013 bitrate);
1014
1015 /* At the moment, aiffparse only supports uncompressed PCM data.
1016 * Therefore, nominal, actual, minimum, maximum bitrate are the same.
1017 * XXX: If AIFF-C support is extended to include compression,
1018 * make sure that aiff->bps is set properly. */
1019 gst_tag_list_add (aiff->tags, GST_TAG_MERGE_REPLACE,
1020 GST_TAG_BITRATE, bitrate, GST_TAG_NOMINAL_BITRATE, bitrate,
1021 GST_TAG_MINIMUM_BITRATE, bitrate, GST_TAG_MAXIMUM_BITRATE,
1022 bitrate, NULL);
1023 }
1024
1025 if (aiff->bytes_per_sample <= 0)
1026 goto no_bytes_per_sample;
1027
1028 aiff->got_comm = TRUE;
1029 break;
1030 }
1031 case GST_MAKE_FOURCC ('S', 'S', 'N', 'D'):{
1032 guint32 datasize;
1033
1034 GST_DEBUG_OBJECT (aiff, "Got 'SSND' TAG, size : %d", size);
1035
1036 /* Now, read the 8-byte header in the SSND chunk */
1037 if (aiff->streaming) {
1038 const guint8 *ssnddata = NULL;
1039
1040 if (!gst_aiff_parse_peek_data (aiff, 16, &ssnddata))
1041 return GST_FLOW_OK;
1042
1043 aiff->ssnd_offset = GST_READ_UINT32_BE (ssnddata + 8);
1044 aiff->ssnd_blocksize = GST_READ_UINT32_BE (ssnddata + 12);
1045 gst_adapter_unmap (aiff->adapter);
1046 gst_adapter_flush (aiff->adapter, 16);
1047 } else {
1048 GstBuffer *ssndbuf = NULL;
1049 GstMapInfo info;
1050
1051 if ((res =
1052 gst_pad_pull_range (aiff->sinkpad, aiff->offset, 16,
1053 &ssndbuf)) != GST_FLOW_OK)
1054 goto header_read_error;
1055
1056 gst_buffer_map (ssndbuf, &info, GST_MAP_READ);
1057 aiff->ssnd_offset = GST_READ_UINT32_BE (info.data + 8);
1058 aiff->ssnd_blocksize = GST_READ_UINT32_BE (info.data + 12);
1059 gst_buffer_unmap (ssndbuf, &info);
1060 gst_buffer_unref (ssndbuf);
1061 }
1062
1063 gotdata = TRUE;
1064
1065 /* 8 byte chunk header, 8 byte SSND header */
1066 aiff->offset += 16;
1067 datasize = size - 8;
1068
1069 aiff->datastart = aiff->offset + aiff->ssnd_offset;
1070 /* file might be truncated */
1071 if (upstream_size) {
1072 size = MIN (datasize, (upstream_size - aiff->datastart));
1073 }
1074 aiff->datasize = (guint64) datasize;
1075 aiff->dataleft = (guint64) datasize;
1076 aiff->end_offset = datasize + aiff->datastart;
1077 if (!aiff->streaming) {
1078 /* We will continue looking at chunks until the end - to read tags,
1079 * etc. */
1080 aiff->offset += datasize;
1081 }
1082 GST_DEBUG_OBJECT (aiff, "datasize = %d", datasize);
1083 if (aiff->streaming) {
1084 done = TRUE;
1085 }
1086 break;
1087 }
1088 case GST_MAKE_FOURCC ('I', 'D', '3', ' '):{
1089 GstTagList *tags;
1090
1091 if (aiff->streaming) {
1092 if (!gst_aiff_parse_peek_chunk (aiff, &tag, &size))
1093 return GST_FLOW_OK;
1094
1095 gst_adapter_flush (aiff->adapter, 8);
1096 aiff->offset += 8;
1097
1098 buf = gst_adapter_take_buffer (aiff->adapter, size);
1099 } else {
1100 if ((res = gst_aiff_parse_read_chunk (aiff,
1101 &aiff->offset, &tag, &buf)) != GST_FLOW_OK)
1102 return res;
1103 }
1104
1105 GST_LOG_OBJECT (aiff, "ID3 chunk of size %" G_GSIZE_FORMAT,
1106 gst_buffer_get_size (buf));
1107
1108 tags = gst_tag_list_from_id3v2_tag (buf);
1109 gst_buffer_unref (buf);
1110
1111 GST_INFO_OBJECT (aiff, "ID3 tags: %" GST_PTR_FORMAT, tags);
1112
1113 if (aiff->tags == NULL) {
1114 aiff->tags = tags;
1115 } else {
1116 gst_tag_list_insert (aiff->tags, tags, GST_TAG_MERGE_APPEND);
1117 gst_tag_list_unref (tags);
1118 }
1119 break;
1120 }
1121 case GST_MAKE_FOURCC ('C', 'H', 'A', 'N'):{
1122 GST_FIXME_OBJECT (aiff, "Handle CHAN chunk with channel layouts");
1123 if (!gst_aiff_parse_ignore_chunk (aiff, tag, size)) {
1124 return GST_FLOW_OK;
1125 }
1126 break;
1127 }
1128 default:
1129 if (!gst_aiff_parse_ignore_chunk (aiff, tag, size)) {
1130 return GST_FLOW_OK;
1131 }
1132 }
1133
1134 buf = NULL;
1135
1136 if (upstream_size && (aiff->offset >= upstream_size)) {
1137 /* Now we have gone through the whole file */
1138 done = TRUE;
1139 }
1140 }
1141
1142 /* We read all the chunks (in pull mode) or reached the SSND chunk
1143 * (in push mode). We must have both COMM and SSND now; error out
1144 * otherwise.
1145 */
1146 if (!aiff->got_comm) {
1147 GST_WARNING_OBJECT (aiff, "Failed to find COMM chunk");
1148 goto no_header;
1149 }
1150 if (!gotdata) {
1151 GST_WARNING_OBJECT (aiff, "Failed to find SSND chunk");
1152 goto no_data;
1153 }
1154
1155 GST_DEBUG_OBJECT (aiff, "Finished parsing headers");
1156
1157 if (gst_aiff_parse_calculate_duration (aiff)) {
1158 gst_segment_init (&aiff->segment, GST_FORMAT_TIME);
1159 aiff->segment.duration = aiff->duration;
1160 } else {
1161 /* no bitrate, let downstream peer do the math, we'll feed it bytes. */
1162 gst_segment_init (&aiff->segment, GST_FORMAT_BYTES);
1163 aiff->segment.duration = aiff->datasize;
1164 }
1165
1166 /* now we have all the info to perform a pending seek if any, if no
1167 * event, this will still do the right thing and it will also send
1168 * the right segment event downstream. */
1169 gst_aiff_parse_perform_seek (aiff, aiff->seek_event, TRUE);
1170 /* remove pending event */
1171 event_p = &aiff->seek_event;
1172 gst_event_replace (event_p, NULL);
1173
1174 /* we just started, we are discont */
1175 aiff->discont = TRUE;
1176
1177 aiff->state = AIFF_PARSE_DATA;
1178
1179 /* determine reasonable max buffer size,
1180 * that is, buffers not too small either size or time wise
1181 * so we do not end up with too many of them */
1182 /* var abuse */
1183 upstream_size = 0;
1184 gst_aiff_parse_time_to_bytepos (aiff, 40 * GST_MSECOND, &upstream_size);
1185 aiff->max_buf_size = upstream_size;
1186 aiff->max_buf_size = MAX (aiff->max_buf_size, MAX_BUFFER_SIZE);
1187 if (aiff->bytes_per_sample > 0)
1188 aiff->max_buf_size -= (aiff->max_buf_size % aiff->bytes_per_sample);
1189
1190 GST_DEBUG_OBJECT (aiff, "max buffer size %u", aiff->max_buf_size);
1191
1192 return GST_FLOW_OK;
1193
1194 /* ERROR */
1195 no_header:
1196 {
1197 GST_ELEMENT_ERROR (aiff, STREAM, TYPE_NOT_FOUND, (NULL),
1198 ("Invalid AIFF header (no COMM found)"));
1199 return GST_FLOW_ERROR;
1200 }
1201 no_data:
1202 {
1203 GST_ELEMENT_ERROR (aiff, STREAM, TYPE_NOT_FOUND, (NULL),
1204 ("Invalid AIFF: no SSND found"));
1205 return GST_FLOW_ERROR;
1206 }
1207 parse_header_error:
1208 {
1209 GST_ELEMENT_ERROR (aiff, STREAM, DEMUX, (NULL),
1210 ("Couldn't parse audio header"));
1211 return GST_FLOW_ERROR;
1212 }
1213 no_channels:
1214 {
1215 GST_ELEMENT_ERROR (aiff, STREAM, FAILED, (NULL),
1216 ("Stream claims to contain no channels - invalid data"));
1217 return GST_FLOW_ERROR;
1218 }
1219 no_rate:
1220 {
1221 GST_ELEMENT_ERROR (aiff, STREAM, FAILED, (NULL),
1222 ("Stream with sample_rate == 0 - invalid data"));
1223 return GST_FLOW_ERROR;
1224 }
1225 no_bytes_per_sample:
1226 {
1227 GST_ELEMENT_ERROR (aiff, STREAM, FAILED, (NULL),
1228 ("Could not calculate bytes per sample - invalid data"));
1229 return GST_FLOW_ERROR;
1230 }
1231 unknown_format:
1232 {
1233 GST_ELEMENT_ERROR (aiff, STREAM, TYPE_NOT_FOUND, (NULL),
1234 ("No caps found for format 0x%x, %d channels, %d Hz",
1235 aiff->format, aiff->channels, aiff->rate));
1236 return GST_FLOW_ERROR;
1237 }
1238 header_read_error:
1239 {
1240 GST_ELEMENT_ERROR (aiff, STREAM, DEMUX, (NULL),
1241 ("Couldn't read in header"));
1242 return GST_FLOW_ERROR;
1243 }
1244 }
1245
1246 /*
1247 * Read AIFF file tag when streaming
1248 */
1249 static GstFlowReturn
gst_aiff_parse_parse_stream_init(GstAiffParse * aiff)1250 gst_aiff_parse_parse_stream_init (GstAiffParse * aiff)
1251 {
1252 if (gst_adapter_available (aiff->adapter) >= 12) {
1253 GstBuffer *tmp;
1254
1255 /* _take flushes the data */
1256 tmp = gst_adapter_take_buffer (aiff->adapter, 12);
1257
1258 GST_DEBUG_OBJECT (aiff, "Parsing aiff header");
1259 if (!gst_aiff_parse_parse_file_header (aiff, tmp))
1260 return GST_FLOW_ERROR;
1261
1262 aiff->offset += 12;
1263 /* Go to next state */
1264 aiff->state = AIFF_PARSE_HEADER;
1265 }
1266 return GST_FLOW_OK;
1267 }
1268
1269 /* handle an event sent directly to the element.
1270 *
1271 * This event can be sent either in the READY state or the
1272 * >READY state. The only event of interest really is the seek
1273 * event.
1274 *
1275 * In the READY state we can only store the event and try to
1276 * respect it when going to PAUSED. We assume we are in the
1277 * READY state when our parsing state != AIFF_PARSE_DATA.
1278 *
1279 * When we are steaming, we can simply perform the seek right
1280 * away.
1281 */
1282 static gboolean
gst_aiff_parse_send_event(GstElement * element,GstEvent * event)1283 gst_aiff_parse_send_event (GstElement * element, GstEvent * event)
1284 {
1285 GstAiffParse *aiff = GST_AIFF_PARSE (element);
1286 gboolean res = FALSE;
1287 GstEvent **event_p;
1288
1289 GST_DEBUG_OBJECT (aiff, "received event %s", GST_EVENT_TYPE_NAME (event));
1290
1291 switch (GST_EVENT_TYPE (event)) {
1292 case GST_EVENT_SEEK:
1293 if (aiff->state == AIFF_PARSE_DATA) {
1294 /* we can handle the seek directly when streaming data */
1295 res = gst_aiff_parse_perform_seek (aiff, event, FALSE);
1296 } else {
1297 GST_DEBUG_OBJECT (aiff, "queuing seek for later");
1298
1299 event_p = &aiff->seek_event;
1300 gst_event_replace (event_p, event);
1301
1302 /* we always return true */
1303 res = TRUE;
1304 }
1305 break;
1306 default:
1307 break;
1308 }
1309 gst_event_unref (event);
1310 return res;
1311 }
1312
1313 static GstFlowReturn
gst_aiff_parse_stream_data(GstAiffParse * aiff)1314 gst_aiff_parse_stream_data (GstAiffParse * aiff)
1315 {
1316 GstBuffer *buf = NULL;
1317 GstFlowReturn res = GST_FLOW_OK;
1318 guint64 desired, obtained;
1319 GstClockTime timestamp, next_timestamp, duration;
1320 guint64 pos, nextpos;
1321
1322 if (aiff->bytes_per_sample <= 0) {
1323 GST_ELEMENT_ERROR (aiff, STREAM, WRONG_TYPE, (NULL),
1324 ("File is not a valid AIFF file (invalid bytes per sample)"));
1325 return GST_FLOW_ERROR;
1326 }
1327
1328 iterate_adapter:
1329 GST_LOG_OBJECT (aiff,
1330 "offset: %" G_GINT64_FORMAT " , end: %" G_GINT64_FORMAT " , dataleft: %"
1331 G_GINT64_FORMAT, aiff->offset, aiff->end_offset, aiff->dataleft);
1332
1333 /* Get the next n bytes and output them */
1334 if (aiff->dataleft == 0 || aiff->dataleft < aiff->bytes_per_sample)
1335 goto found_eos;
1336
1337 /* scale the amount of data by the segment rate so we get equal
1338 * amounts of data regardless of the playback rate */
1339 desired =
1340 MIN (gst_guint64_to_gdouble (aiff->dataleft),
1341 aiff->max_buf_size * ABS (aiff->segment.rate));
1342
1343 if (desired >= aiff->bytes_per_sample)
1344 desired -= (desired % aiff->bytes_per_sample);
1345
1346 GST_LOG_OBJECT (aiff, "Fetching %" G_GINT64_FORMAT " bytes of data "
1347 "from the sinkpad", desired);
1348
1349 if (aiff->streaming) {
1350 guint avail = gst_adapter_available (aiff->adapter);
1351
1352 if (avail < desired) {
1353 GST_LOG_OBJECT (aiff, "Got only %d bytes of data from the sinkpad",
1354 avail);
1355 return GST_FLOW_OK;
1356 }
1357
1358 buf = gst_adapter_take_buffer (aiff->adapter, desired);
1359 } else {
1360 if ((res = gst_pad_pull_range (aiff->sinkpad, aiff->offset,
1361 desired, &buf)) != GST_FLOW_OK)
1362 goto pull_error;
1363 }
1364
1365 /* If we have a pending close/start segment, send it now. */
1366 if (G_UNLIKELY (aiff->close_segment != NULL)) {
1367 gst_pad_push_event (aiff->srcpad, aiff->close_segment);
1368 aiff->close_segment = NULL;
1369 }
1370 if (G_UNLIKELY (aiff->start_segment != NULL)) {
1371 gst_pad_push_event (aiff->srcpad, aiff->start_segment);
1372 aiff->start_segment = NULL;
1373 }
1374 if (G_UNLIKELY (aiff->tags != NULL)) {
1375 gst_pad_push_event (aiff->srcpad, gst_event_new_tag (aiff->tags));
1376 aiff->tags = NULL;
1377 }
1378
1379 obtained = gst_buffer_get_size (buf);
1380
1381 /* our positions in bytes */
1382 pos = aiff->offset - aiff->datastart;
1383 nextpos = pos + obtained;
1384
1385 /* update offsets, does not overflow. */
1386 GST_BUFFER_OFFSET (buf) = pos / aiff->bytes_per_sample;
1387 GST_BUFFER_OFFSET_END (buf) = nextpos / aiff->bytes_per_sample;
1388
1389 if (aiff->bps > 0) {
1390 /* and timestamps if we have a bitrate, be careful for overflows */
1391 timestamp =
1392 gst_util_uint64_scale_ceil (pos, GST_SECOND, (guint64) aiff->bps);
1393 next_timestamp =
1394 gst_util_uint64_scale_ceil (nextpos, GST_SECOND, (guint64) aiff->bps);
1395 duration = next_timestamp - timestamp;
1396
1397 /* update current running segment position */
1398 aiff->segment.position = next_timestamp;
1399 } else {
1400 /* no bitrate, all we know is that the first sample has timestamp 0, all
1401 * other positions and durations have unknown timestamp. */
1402 if (pos == 0)
1403 timestamp = 0;
1404 else
1405 timestamp = GST_CLOCK_TIME_NONE;
1406 duration = GST_CLOCK_TIME_NONE;
1407 /* update current running segment position with byte offset */
1408 aiff->segment.position = nextpos;
1409 }
1410 if (aiff->discont) {
1411 GST_DEBUG_OBJECT (aiff, "marking DISCONT");
1412 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
1413 aiff->discont = FALSE;
1414 }
1415
1416 GST_BUFFER_TIMESTAMP (buf) = timestamp;
1417 GST_BUFFER_DURATION (buf) = duration;
1418
1419 GST_LOG_OBJECT (aiff,
1420 "Got buffer. timestamp:%" GST_TIME_FORMAT " , duration:%" GST_TIME_FORMAT
1421 ", size:%" G_GUINT64_FORMAT, GST_TIME_ARGS (timestamp),
1422 GST_TIME_ARGS (duration), obtained);
1423
1424 if ((res = gst_pad_push (aiff->srcpad, buf)) != GST_FLOW_OK)
1425 goto push_error;
1426
1427 if (obtained < aiff->dataleft) {
1428 aiff->offset += obtained;
1429 aiff->dataleft -= obtained;
1430 } else {
1431 aiff->offset += aiff->dataleft;
1432 aiff->dataleft = 0;
1433 }
1434
1435 /* Iterate until need more data, so adapter size won't grow */
1436 if (aiff->streaming) {
1437 GST_LOG_OBJECT (aiff,
1438 "offset: %" G_GINT64_FORMAT " , end: %" G_GINT64_FORMAT, aiff->offset,
1439 aiff->end_offset);
1440 goto iterate_adapter;
1441 }
1442 return res;
1443
1444 /* ERROR */
1445 found_eos:
1446 {
1447 GST_DEBUG_OBJECT (aiff, "found EOS");
1448 return GST_FLOW_EOS;
1449 }
1450 pull_error:
1451 {
1452 /* check if we got EOS */
1453 if (res == GST_FLOW_EOS)
1454 goto found_eos;
1455
1456 GST_WARNING_OBJECT (aiff,
1457 "Error getting %" G_GINT64_FORMAT " bytes from the "
1458 "sinkpad (dataleft = %" G_GINT64_FORMAT ")", desired, aiff->dataleft);
1459 return res;
1460 }
1461 push_error:
1462 {
1463 GST_INFO_OBJECT (aiff,
1464 "Error pushing on srcpad %s:%s, reason %s, is linked? = %d",
1465 GST_DEBUG_PAD_NAME (aiff->srcpad), gst_flow_get_name (res),
1466 gst_pad_is_linked (aiff->srcpad));
1467 return res;
1468 }
1469 }
1470
1471 static void
gst_aiff_parse_loop(GstPad * pad)1472 gst_aiff_parse_loop (GstPad * pad)
1473 {
1474 GstFlowReturn ret;
1475 GstAiffParse *aiff = GST_AIFF_PARSE (GST_PAD_PARENT (pad));
1476
1477 GST_LOG_OBJECT (aiff, "process data");
1478
1479 switch (aiff->state) {
1480 case AIFF_PARSE_START:
1481 GST_INFO_OBJECT (aiff, "AIFF_PARSE_START");
1482 if ((ret = gst_aiff_parse_stream_init (aiff)) != GST_FLOW_OK)
1483 goto pause;
1484
1485 aiff->state = AIFF_PARSE_HEADER;
1486 /* fall-through */
1487
1488 case AIFF_PARSE_HEADER:
1489 GST_INFO_OBJECT (aiff, "AIFF_PARSE_HEADER");
1490 if ((ret = gst_aiff_parse_stream_headers (aiff)) != GST_FLOW_OK)
1491 goto pause;
1492
1493 aiff->state = AIFF_PARSE_DATA;
1494 GST_INFO_OBJECT (aiff, "AIFF_PARSE_DATA");
1495 /* fall-through */
1496
1497 case AIFF_PARSE_DATA:
1498 if ((ret = gst_aiff_parse_stream_data (aiff)) != GST_FLOW_OK)
1499 goto pause;
1500 break;
1501 default:
1502 g_assert_not_reached ();
1503 }
1504 return;
1505
1506 /* ERRORS */
1507 pause:
1508 {
1509 const gchar *reason = gst_flow_get_name (ret);
1510
1511 GST_DEBUG_OBJECT (aiff, "pausing task, reason %s", reason);
1512 aiff->segment_running = FALSE;
1513 gst_pad_pause_task (pad);
1514
1515 if (ret == GST_FLOW_EOS) {
1516 /* perform EOS logic */
1517 if (aiff->segment.flags & GST_SEEK_FLAG_SEGMENT) {
1518 GstClockTime stop;
1519
1520 if ((stop = aiff->segment.stop) == -1)
1521 stop = aiff->segment.duration;
1522
1523 gst_element_post_message (GST_ELEMENT_CAST (aiff),
1524 gst_message_new_segment_done (GST_OBJECT_CAST (aiff),
1525 aiff->segment.format, stop));
1526 gst_pad_push_event (aiff->srcpad,
1527 gst_event_new_segment_done (aiff->segment.format, stop));
1528 } else {
1529 gst_pad_push_event (aiff->srcpad, gst_event_new_eos ());
1530 }
1531 } else if (ret < GST_FLOW_EOS || ret == GST_FLOW_NOT_LINKED) {
1532 /* for fatal errors we post an error message, post the error
1533 * first so the app knows about the error first. */
1534 GST_ELEMENT_FLOW_ERROR (aiff, ret);
1535 gst_pad_push_event (aiff->srcpad, gst_event_new_eos ());
1536 }
1537 return;
1538 }
1539 }
1540
1541 static GstFlowReturn
gst_aiff_parse_chain(GstPad * pad,GstObject * parent,GstBuffer * buf)1542 gst_aiff_parse_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
1543 {
1544 GstFlowReturn ret;
1545 GstAiffParse *aiff = GST_AIFF_PARSE (parent);
1546
1547 GST_LOG_OBJECT (aiff, "adapter_push %" G_GSIZE_FORMAT " bytes",
1548 gst_buffer_get_size (buf));
1549
1550 gst_adapter_push (aiff->adapter, buf);
1551
1552 switch (aiff->state) {
1553 case AIFF_PARSE_START:
1554 GST_INFO_OBJECT (aiff, "AIFF_PARSE_START");
1555 if ((ret = gst_aiff_parse_parse_stream_init (aiff)) != GST_FLOW_OK)
1556 goto done;
1557
1558 if (aiff->state != AIFF_PARSE_HEADER)
1559 break;
1560
1561 /* otherwise fall-through */
1562 case AIFF_PARSE_HEADER:
1563 GST_INFO_OBJECT (aiff, "AIFF_PARSE_HEADER");
1564 if ((ret = gst_aiff_parse_stream_headers (aiff)) != GST_FLOW_OK)
1565 goto done;
1566
1567 if (!aiff->got_comm || aiff->datastart == 0)
1568 break;
1569
1570 aiff->state = AIFF_PARSE_DATA;
1571 GST_INFO_OBJECT (aiff, "AIFF_PARSE_DATA");
1572
1573 /* fall-through */
1574 case AIFF_PARSE_DATA:
1575 if ((ret = gst_aiff_parse_stream_data (aiff)) != GST_FLOW_OK)
1576 goto done;
1577 break;
1578 default:
1579 g_return_val_if_reached (GST_FLOW_ERROR);
1580 }
1581 done:
1582 return ret;
1583 }
1584
1585 static gboolean
gst_aiff_parse_pad_convert(GstPad * pad,GstFormat src_format,gint64 src_value,GstFormat * dest_format,gint64 * dest_value)1586 gst_aiff_parse_pad_convert (GstPad * pad,
1587 GstFormat src_format, gint64 src_value,
1588 GstFormat * dest_format, gint64 * dest_value)
1589 {
1590 GstAiffParse *aiffparse;
1591 gboolean res = TRUE;
1592
1593 aiffparse = GST_AIFF_PARSE (GST_PAD_PARENT (pad));
1594
1595 if (*dest_format == src_format) {
1596 *dest_value = src_value;
1597 return TRUE;
1598 }
1599
1600 if (aiffparse->bytes_per_sample <= 0)
1601 return FALSE;
1602
1603 GST_INFO_OBJECT (aiffparse, "converting value from %s to %s",
1604 gst_format_get_name (src_format), gst_format_get_name (*dest_format));
1605
1606 switch (src_format) {
1607 case GST_FORMAT_BYTES:
1608 switch (*dest_format) {
1609 case GST_FORMAT_DEFAULT:
1610 *dest_value = src_value / aiffparse->bytes_per_sample;
1611 break;
1612 case GST_FORMAT_TIME:
1613 if (aiffparse->bps > 0) {
1614 *dest_value = gst_util_uint64_scale_ceil (src_value, GST_SECOND,
1615 (guint64) aiffparse->bps);
1616 break;
1617 }
1618 /* Else fallthrough */
1619 default:
1620 res = FALSE;
1621 goto done;
1622 }
1623 break;
1624
1625 case GST_FORMAT_DEFAULT:
1626 switch (*dest_format) {
1627 case GST_FORMAT_BYTES:
1628 *dest_value = src_value * aiffparse->bytes_per_sample;
1629 break;
1630 case GST_FORMAT_TIME:
1631 *dest_value = gst_util_uint64_scale (src_value, GST_SECOND,
1632 (guint64) aiffparse->rate);
1633 break;
1634 default:
1635 res = FALSE;
1636 goto done;
1637 }
1638 break;
1639
1640 case GST_FORMAT_TIME:
1641 switch (*dest_format) {
1642 case GST_FORMAT_BYTES:
1643 if (aiffparse->bps > 0) {
1644 *dest_value = gst_util_uint64_scale (src_value,
1645 (guint64) aiffparse->bps, GST_SECOND);
1646 break;
1647 }
1648 /* Else fallthrough */
1649 break;
1650 case GST_FORMAT_DEFAULT:
1651 *dest_value = gst_util_uint64_scale (src_value,
1652 (guint64) aiffparse->rate, GST_SECOND);
1653 break;
1654 default:
1655 res = FALSE;
1656 goto done;
1657 }
1658 break;
1659
1660 default:
1661 res = FALSE;
1662 goto done;
1663 }
1664
1665 done:
1666 return res;
1667
1668 }
1669
1670 /* handle queries for location and length in requested format */
1671 static gboolean
gst_aiff_parse_pad_query(GstPad * pad,GstObject * parent,GstQuery * query)1672 gst_aiff_parse_pad_query (GstPad * pad, GstObject * parent, GstQuery * query)
1673 {
1674 gboolean res = FALSE;
1675 GstAiffParse *aiff = GST_AIFF_PARSE (parent);
1676
1677 switch (GST_QUERY_TYPE (query)) {
1678 case GST_QUERY_DURATION:
1679 {
1680 gint64 duration = 0;
1681 GstFormat format;
1682
1683 /* only if we know */
1684 if (aiff->state != AIFF_PARSE_DATA)
1685 break;
1686
1687 gst_query_parse_duration (query, &format, NULL);
1688
1689 switch (format) {
1690 case GST_FORMAT_TIME:{
1691 if ((res = gst_aiff_parse_calculate_duration (aiff))) {
1692 duration = aiff->duration;
1693 }
1694 break;
1695 }
1696 default:
1697 format = GST_FORMAT_BYTES;
1698 duration = aiff->datasize;
1699 break;
1700 }
1701 gst_query_set_duration (query, format, duration);
1702 break;
1703 }
1704 case GST_QUERY_CONVERT:
1705 {
1706 gint64 srcvalue, dstvalue;
1707 GstFormat srcformat, dstformat;
1708
1709 /* only if we know */
1710 if (aiff->state != AIFF_PARSE_DATA)
1711 break;
1712
1713 gst_query_parse_convert (query, &srcformat, &srcvalue,
1714 &dstformat, &dstvalue);
1715 res = gst_aiff_parse_pad_convert (pad, srcformat, srcvalue,
1716 &dstformat, &dstvalue);
1717 if (res)
1718 gst_query_set_convert (query, srcformat, srcvalue, dstformat, dstvalue);
1719 break;
1720 }
1721 case GST_QUERY_SEEKING:{
1722 GstFormat fmt;
1723
1724 /* only if we know */
1725 if (aiff->state != AIFF_PARSE_DATA)
1726 break;
1727
1728 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
1729 if (fmt == GST_FORMAT_TIME) {
1730 gboolean seekable = TRUE;
1731
1732 if (!gst_aiff_parse_calculate_duration (aiff)) {
1733 seekable = FALSE;
1734 }
1735 gst_query_set_seeking (query, GST_FORMAT_TIME, seekable,
1736 0, aiff->duration);
1737 res = TRUE;
1738 }
1739 break;
1740 }
1741 default:
1742 res = gst_pad_query_default (pad, parent, query);
1743 break;
1744 }
1745 return res;
1746 }
1747
1748 static gboolean
gst_aiff_parse_srcpad_event(GstPad * pad,GstObject * parent,GstEvent * event)1749 gst_aiff_parse_srcpad_event (GstPad * pad, GstObject * parent, GstEvent * event)
1750 {
1751 GstAiffParse *aiffparse = GST_AIFF_PARSE (parent);
1752 gboolean res = FALSE;
1753
1754 GST_DEBUG_OBJECT (aiffparse, "%s event", GST_EVENT_TYPE_NAME (event));
1755
1756 switch (GST_EVENT_TYPE (event)) {
1757 case GST_EVENT_SEEK:
1758 /* can only handle events when we are in the data state */
1759 if (aiffparse->state == AIFF_PARSE_DATA) {
1760 res = gst_aiff_parse_perform_seek (aiffparse, event, FALSE);
1761 }
1762 gst_event_unref (event);
1763 break;
1764 default:
1765 res = gst_pad_push_event (aiffparse->sinkpad, event);
1766 break;
1767 }
1768 return res;
1769 }
1770
1771 static gboolean
gst_aiff_parse_sink_activate(GstPad * sinkpad,GstObject * parent)1772 gst_aiff_parse_sink_activate (GstPad * sinkpad, GstObject * parent)
1773 {
1774 GstQuery *query;
1775 gboolean pull_mode;
1776
1777 query = gst_query_new_scheduling ();
1778
1779 if (!gst_pad_peer_query (sinkpad, query)) {
1780 gst_query_unref (query);
1781 goto activate_push;
1782 }
1783
1784 pull_mode = gst_query_has_scheduling_mode_with_flags (query,
1785 GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
1786 gst_query_unref (query);
1787
1788 if (!pull_mode)
1789 goto activate_push;
1790
1791 GST_DEBUG_OBJECT (sinkpad, "going to pull mode");
1792 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
1793
1794 activate_push:
1795 {
1796 GST_DEBUG_OBJECT (sinkpad, "going to push (streaming) mode");
1797 return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
1798 }
1799 }
1800
1801
1802 static gboolean
gst_aiff_parse_sink_activate_mode(GstPad * sinkpad,GstObject * parent,GstPadMode mode,gboolean active)1803 gst_aiff_parse_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
1804 GstPadMode mode, gboolean active)
1805 {
1806 gboolean res;
1807 GstAiffParse *aiff = GST_AIFF_PARSE (parent);
1808
1809 if (aiff->adapter) {
1810 g_object_unref (aiff->adapter);
1811 aiff->adapter = NULL;
1812 }
1813
1814 switch (mode) {
1815 case GST_PAD_MODE_PUSH:
1816 if (active) {
1817 aiff->streaming = TRUE;
1818 aiff->adapter = gst_adapter_new ();
1819 }
1820 res = TRUE;
1821 break;
1822 case GST_PAD_MODE_PULL:
1823 if (active) {
1824 aiff->streaming = FALSE;
1825 aiff->adapter = NULL;
1826 aiff->segment_running = TRUE;
1827 res =
1828 gst_pad_start_task (sinkpad, (GstTaskFunction) gst_aiff_parse_loop,
1829 sinkpad, NULL);
1830 } else {
1831 aiff->segment_running = FALSE;
1832 res = gst_pad_stop_task (sinkpad);
1833 }
1834 break;
1835 default:
1836 res = FALSE;
1837 break;
1838 }
1839 return res;
1840 };
1841
1842 static GstFlowReturn
gst_aiff_parse_flush_data(GstAiffParse * aiff)1843 gst_aiff_parse_flush_data (GstAiffParse * aiff)
1844 {
1845 GstFlowReturn ret = GST_FLOW_OK;
1846 guint av;
1847
1848 if ((av = gst_adapter_available (aiff->adapter)) > 0) {
1849 aiff->dataleft = av;
1850 aiff->end_offset = aiff->offset + av;
1851 ret = gst_aiff_parse_stream_data (aiff);
1852 }
1853
1854 return ret;
1855 }
1856
1857
1858 static gboolean
gst_aiff_parse_sink_event(GstPad * pad,GstObject * parent,GstEvent * event)1859 gst_aiff_parse_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
1860 {
1861 GstAiffParse *aiff = GST_AIFF_PARSE (parent);
1862 gboolean ret = TRUE;
1863
1864 GST_DEBUG_OBJECT (aiff, "handling %s event", GST_EVENT_TYPE_NAME (event));
1865
1866 switch (GST_EVENT_TYPE (event)) {
1867 case GST_EVENT_CAPS:
1868 {
1869 /* discard, we'll come up with proper src caps */
1870 gst_event_unref (event);
1871 break;
1872 }
1873 case GST_EVENT_SEGMENT:
1874 {
1875 gint64 start, stop, offset = 0, end_offset = -1;
1876 GstSegment segment;
1877
1878 /* some debug output */
1879 gst_event_copy_segment (event, &segment);
1880 GST_DEBUG_OBJECT (aiff, "received segment %" GST_SEGMENT_FORMAT,
1881 &segment);
1882
1883 /* now we are either committed to TIME or BYTE format,
1884 * and we only expect a BYTE segment, e.g. following a seek */
1885 if (segment.format == GST_FORMAT_BYTES) {
1886 /* handle (un)signed issues */
1887 start = segment.start;
1888 stop = segment.stop;
1889 if (start > 0) {
1890 offset = start;
1891 start -= aiff->datastart;
1892 start = MAX (start, 0);
1893 }
1894 if (stop > 0) {
1895 end_offset = stop;
1896 stop -= aiff->datastart;
1897 stop = MAX (stop, 0);
1898 }
1899 if (aiff->state == AIFF_PARSE_DATA &&
1900 aiff->segment.format == GST_FORMAT_TIME) {
1901 /* operating in format TIME, so we can convert */
1902 if (aiff->bps) {
1903 if (start >= 0)
1904 start =
1905 gst_util_uint64_scale_ceil (start, GST_SECOND,
1906 (guint64) aiff->bps);
1907 if (stop >= 0)
1908 stop =
1909 gst_util_uint64_scale_ceil (stop, GST_SECOND,
1910 (guint64) aiff->bps);
1911 } else {
1912 GST_DEBUG_OBJECT (aiff, "unable to compute segment start/stop");
1913 goto exit;
1914 }
1915 }
1916 } else {
1917 GST_DEBUG_OBJECT (aiff, "unsupported segment format, ignoring");
1918 goto exit;
1919 }
1920
1921 segment.start = start;
1922 segment.stop = stop;
1923
1924 /* accept upstream's notion of segment and distribute along */
1925 if (aiff->state == AIFF_PARSE_DATA) {
1926 segment.format = aiff->segment.format;
1927 segment.time = segment.position = segment.start;
1928 segment.duration = aiff->segment.duration;
1929 }
1930
1931 gst_segment_copy_into (&segment, &aiff->segment);
1932
1933 if (aiff->start_segment)
1934 gst_event_unref (aiff->start_segment);
1935
1936 aiff->start_segment = gst_event_new_segment (&segment);
1937
1938 /* If the seek is within the same SSND chunk and there is no new
1939 * end_offset defined keep the previous end_offset. This will avoid noise
1940 * at the end of playback if e.g. a metadata chunk is located at the end
1941 * of the file. */
1942 if (aiff->end_offset > 0 && offset < aiff->end_offset &&
1943 offset >= aiff->datastart && end_offset == -1) {
1944 end_offset = aiff->end_offset;
1945 }
1946
1947 /* stream leftover data in current segment */
1948 if (aiff->state == AIFF_PARSE_DATA)
1949 gst_aiff_parse_flush_data (aiff);
1950 /* and set up streaming thread for next one */
1951 aiff->offset = offset;
1952 aiff->end_offset = end_offset;
1953 if (aiff->end_offset > 0) {
1954 aiff->dataleft = aiff->end_offset - aiff->offset;
1955 } else {
1956 /* infinity; upstream will EOS when done */
1957 aiff->dataleft = G_MAXUINT64;
1958 }
1959 exit:
1960 gst_event_unref (event);
1961 break;
1962 }
1963 case GST_EVENT_FLUSH_START:
1964 ret = gst_pad_push_event (aiff->srcpad, event);
1965 break;
1966 case GST_EVENT_FLUSH_STOP:
1967 ret = gst_pad_push_event (aiff->srcpad, event);
1968 gst_adapter_clear (aiff->adapter);
1969 break;
1970 default:
1971 ret = gst_pad_event_default (aiff->sinkpad, parent, event);
1972 break;
1973 }
1974
1975 return ret;
1976 }
1977
1978 static GstStateChangeReturn
gst_aiff_parse_change_state(GstElement * element,GstStateChange transition)1979 gst_aiff_parse_change_state (GstElement * element, GstStateChange transition)
1980 {
1981 GstStateChangeReturn ret;
1982 GstAiffParse *aiff = GST_AIFF_PARSE (element);
1983
1984 switch (transition) {
1985 case GST_STATE_CHANGE_NULL_TO_READY:
1986 break;
1987 case GST_STATE_CHANGE_READY_TO_PAUSED:
1988 gst_aiff_parse_reset (aiff);
1989 break;
1990 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1991 break;
1992 default:
1993 break;
1994 }
1995
1996 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1997
1998 switch (transition) {
1999 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
2000 break;
2001 case GST_STATE_CHANGE_PAUSED_TO_READY:
2002 gst_aiff_parse_reset (aiff);
2003 break;
2004 case GST_STATE_CHANGE_READY_TO_NULL:
2005 break;
2006 default:
2007 break;
2008 }
2009 return ret;
2010 }
2011