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