From 8618e452ae28d2df745925cb13961c039d565a48 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Tue, 9 Sep 2008 01:14:10 +0000 Subject: [PATCH] gst/aiffparse/aiffparse.c: Support chunks in AIFF in any order in pull mode, and any order so long as we get COMM bef... Original commit message from CVS: * gst/aiffparse/aiffparse.c: Support chunks in AIFF in any order in pull mode, and any order so long as we get COMM before the actual data (SSND) in push mode. Fixes playback of AIFC files. --- ChangeLog | 7 ++ gst/aiffparse/aiffparse.c | 141 ++++++++++++++++++++++---------------- 2 files changed, 88 insertions(+), 60 deletions(-) diff --git a/ChangeLog b/ChangeLog index 467444373b..7008103356 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2008-09-08 Michael Smith + + * gst/aiffparse/aiffparse.c: + Support chunks in AIFF in any order in pull mode, and any order so + long as we get COMM before the actual data (SSND) in push mode. + Fixes playback of AIFC files. + 2008-09-08 Wim Taymans * gst/selector/gstinputselector.c: (gst_selector_pad_reset), diff --git a/gst/aiffparse/aiffparse.c b/gst/aiffparse/aiffparse.c index 09ec2e52ef..08f273b7df 100644 --- a/gst/aiffparse/aiffparse.c +++ b/gst/aiffparse/aiffparse.c @@ -670,9 +670,15 @@ gst_aiffparse_parse_comm (AIFFParse * aiff, GstBuffer * buf) * either big or little endian */ if (GST_READ_UINT32_LE (data + 18) == GST_MAKE_FOURCC ('N', 'O', 'N', 'E')) aiff->endianness = G_BIG_ENDIAN; - else if (GST_READ_UINT32_LE (data + 18) == GST_MAKE_FOURCC ('s', 'o', 'w', - 't')) + else if (GST_READ_UINT32_LE (data + 18) == + GST_MAKE_FOURCC ('s', 'o', 'w', 't')) aiff->endianness = G_LITTLE_ENDIAN; + else { + GST_WARNING_OBJECT (aiff, "Unsupported compression in AIFC " + "file: %" GST_FOURCC_FORMAT, + GST_FOURCC_ARGS (GST_READ_UINT32_LE (data + 18))); + return FALSE; + } } else aiff->endianness = G_BIG_ENDIAN; @@ -742,68 +748,17 @@ gst_aiffparse_stream_headers (AIFFParse * aiff) GstBuffer *buf; guint32 tag, size; gboolean gotdata = FALSE; + gboolean done = FALSE; GstEvent **event_p; GstFormat bformat; gint64 upstream_size = 0; - /* search for "comm" chunk, which should be first */ - while (!aiff->got_comm) { - /* The header starts with a 'comm' tag */ - if (aiff->streaming) { - if (!gst_aiffparse_peek_chunk (aiff, &tag, &size)) - return GST_FLOW_OK; - - gst_adapter_flush (aiff->adapter, 8); - aiff->offset += 8; - - buf = gst_adapter_take_buffer (aiff->adapter, size); - } else { - if ((res = gst_aiffparse_read_chunk (aiff, - &aiff->offset, &tag, &buf)) != GST_FLOW_OK) - return res; - } - - /* TODO: allow some non-COMM chunks here */ - - if (tag != GST_MAKE_FOURCC ('C', 'O', 'M', 'M')) { - gst_buffer_unref (buf); - goto invalid_aiff; - } - - if (!gst_aiffparse_parse_comm (aiff, buf)) { - gst_buffer_unref (buf); - goto parse_header_error; - } - - /* do sanity checks of header fields */ - if (aiff->channels == 0) - goto no_channels; - if (aiff->rate == 0) - goto no_rate; - - GST_DEBUG_OBJECT (aiff, "creating the caps"); - - aiff->caps = gst_aiffparse_create_caps (aiff); - if (!aiff->caps) - goto unknown_format; - - gst_pad_set_caps (aiff->srcpad, aiff->caps); - - aiff->bytes_per_sample = aiff->channels * aiff->width / 8; - aiff->bps = aiff->bytes_per_sample * aiff->rate; - - if (aiff->bytes_per_sample <= 0) - goto no_bytes_per_sample; - - aiff->got_comm = TRUE; - } - bformat = GST_FORMAT_BYTES; gst_pad_query_peer_duration (aiff->sinkpad, &bformat, &upstream_size); GST_DEBUG_OBJECT (aiff, "upstream size %" G_GUINT64_FORMAT, upstream_size); /* loop headers until we get data */ - while (!gotdata) { + while (!done) { if (aiff->streaming) { if (!gst_aiffparse_peek_chunk_info (aiff, &tag, &size)) return GST_FLOW_OK; @@ -823,13 +778,58 @@ gst_aiffparse_stream_headers (AIFFParse * aiff) /* We just keep reading chunks until we find the one we're interested in. */ switch (tag) { + case GST_MAKE_FOURCC ('C', 'O', 'M', 'M'):{ + if (aiff->streaming) { + if (!gst_aiffparse_peek_chunk (aiff, &tag, &size)) + return GST_FLOW_OK; + + gst_adapter_flush (aiff->adapter, 8); + aiff->offset += 8; + + buf = gst_adapter_take_buffer (aiff->adapter, size); + } else { + if ((res = gst_aiffparse_read_chunk (aiff, + &aiff->offset, &tag, &buf)) != GST_FLOW_OK) + return res; + } + + if (!gst_aiffparse_parse_comm (aiff, buf)) { + gst_buffer_unref (buf); + goto parse_header_error; + } + + gst_buffer_unref (buf); + + /* do sanity checks of header fields */ + if (aiff->channels == 0) + goto no_channels; + if (aiff->rate == 0) + goto no_rate; + + GST_DEBUG_OBJECT (aiff, "creating the caps"); + + aiff->caps = gst_aiffparse_create_caps (aiff); + if (!aiff->caps) + goto unknown_format; + + gst_pad_set_caps (aiff->srcpad, aiff->caps); + + aiff->bytes_per_sample = aiff->channels * aiff->width / 8; + aiff->bps = aiff->bytes_per_sample * aiff->rate; + + if (aiff->bytes_per_sample <= 0) + goto no_bytes_per_sample; + + aiff->got_comm = TRUE; + break; + } case GST_MAKE_FOURCC ('S', 'S', 'N', 'D'):{ GstFormat fmt; GST_DEBUG_OBJECT (aiff, "Got 'SSND' TAG, size : %d", size); + gotdata = TRUE; if (aiff->streaming) { gst_adapter_flush (aiff->adapter, 8); - gotdata = TRUE; } else { gst_buffer_unref (buf); } @@ -849,6 +849,9 @@ gst_aiffparse_stream_headers (AIFFParse * aiff) aiff->offset += size; } GST_DEBUG_OBJECT (aiff, "datasize = %d", size); + if (aiff->streaming) { + done = TRUE; + } break; } default: @@ -857,10 +860,23 @@ gst_aiffparse_stream_headers (AIFFParse * aiff) if (upstream_size && (aiff->offset >= upstream_size)) { /* Now we have gone through the whole file */ - gotdata = TRUE; + done = TRUE; } } + /* We read all the chunks (in pull mode) or reached the SSND chunk + * (in push mode). We must have both COMM and SSND now; error out + * otherwise. + */ + if (!aiff->got_comm) { + GST_WARNING_OBJECT (aiff, "Failed to find COMM chunk"); + goto no_header; + } + if (!gotdata) { + GST_WARNING_OBJECT (aiff, "Failed to find SSND chunk"); + goto no_data; + } + GST_DEBUG_OBJECT (aiff, "Finished parsing headers"); if (gst_aiffparse_calculate_duration (aiff)) { @@ -888,11 +904,16 @@ gst_aiffparse_stream_headers (AIFFParse * aiff) return GST_FLOW_OK; /* ERROR */ -invalid_aiff: +no_header: { GST_ELEMENT_ERROR (aiff, STREAM, TYPE_NOT_FOUND, (NULL), - ("Invalid AIFF header (no COMM at start): %" - GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag))); + ("Invalid AIFF header (no COMM found)")); + return GST_FLOW_ERROR; + } +no_data: + { + GST_ELEMENT_ERROR (aiff, STREAM, TYPE_NOT_FOUND, (NULL), + ("Invalid AIFF: no SSND found")); return GST_FLOW_ERROR; } parse_header_error: