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