• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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