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.
This commit is contained in:
Michael Smith 2008-09-09 01:14:10 +00:00
parent 5d1c162f06
commit 8618e452ae
2 changed files with 88 additions and 60 deletions

View file

@ -1,3 +1,10 @@
2008-09-08 Michael Smith <msmith@songbirdnest.com>
* 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 <wim.taymans@collabora.co.uk> 2008-09-08 Wim Taymans <wim.taymans@collabora.co.uk>
* gst/selector/gstinputselector.c: (gst_selector_pad_reset), * gst/selector/gstinputselector.c: (gst_selector_pad_reset),

View file

@ -670,9 +670,15 @@ gst_aiffparse_parse_comm (AIFFParse * aiff, GstBuffer * buf)
* either big or little endian */ * either big or little endian */
if (GST_READ_UINT32_LE (data + 18) == GST_MAKE_FOURCC ('N', 'O', 'N', 'E')) if (GST_READ_UINT32_LE (data + 18) == GST_MAKE_FOURCC ('N', 'O', 'N', 'E'))
aiff->endianness = G_BIG_ENDIAN; aiff->endianness = G_BIG_ENDIAN;
else if (GST_READ_UINT32_LE (data + 18) == GST_MAKE_FOURCC ('s', 'o', 'w', else if (GST_READ_UINT32_LE (data + 18) ==
't')) GST_MAKE_FOURCC ('s', 'o', 'w', 't'))
aiff->endianness = G_LITTLE_ENDIAN; 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 } else
aiff->endianness = G_BIG_ENDIAN; aiff->endianness = G_BIG_ENDIAN;
@ -742,13 +748,37 @@ gst_aiffparse_stream_headers (AIFFParse * aiff)
GstBuffer *buf; GstBuffer *buf;
guint32 tag, size; guint32 tag, size;
gboolean gotdata = FALSE; gboolean gotdata = FALSE;
gboolean done = FALSE;
GstEvent **event_p; GstEvent **event_p;
GstFormat bformat; GstFormat bformat;
gint64 upstream_size = 0; gint64 upstream_size = 0;
/* search for "comm" chunk, which should be first */ bformat = GST_FORMAT_BYTES;
while (!aiff->got_comm) { gst_pad_query_peer_duration (aiff->sinkpad, &bformat, &upstream_size);
/* The header starts with a 'comm' tag */ GST_DEBUG_OBJECT (aiff, "upstream size %" G_GUINT64_FORMAT, upstream_size);
/* loop headers until we get data */
while (!done) {
if (aiff->streaming) {
if (!gst_aiffparse_peek_chunk_info (aiff, &tag, &size))
return GST_FLOW_OK;
} else {
if ((res =
gst_pad_pull_range (aiff->sinkpad, aiff->offset, 8,
&buf)) != GST_FLOW_OK)
goto header_read_error;
tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf));
size = GST_READ_UINT32_BE (GST_BUFFER_DATA (buf) + 4);
}
GST_INFO_OBJECT (aiff,
"Got TAG: %" GST_FOURCC_FORMAT ", offset %" G_GUINT64_FORMAT,
GST_FOURCC_ARGS (tag), aiff->offset);
/* 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 (aiff->streaming) {
if (!gst_aiffparse_peek_chunk (aiff, &tag, &size)) if (!gst_aiffparse_peek_chunk (aiff, &tag, &size))
return GST_FLOW_OK; return GST_FLOW_OK;
@ -763,18 +793,13 @@ gst_aiffparse_stream_headers (AIFFParse * aiff)
return res; 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)) { if (!gst_aiffparse_parse_comm (aiff, buf)) {
gst_buffer_unref (buf); gst_buffer_unref (buf);
goto parse_header_error; goto parse_header_error;
} }
gst_buffer_unref (buf);
/* do sanity checks of header fields */ /* do sanity checks of header fields */
if (aiff->channels == 0) if (aiff->channels == 0)
goto no_channels; goto no_channels;
@ -796,40 +821,15 @@ gst_aiffparse_stream_headers (AIFFParse * aiff)
goto no_bytes_per_sample; goto no_bytes_per_sample;
aiff->got_comm = TRUE; aiff->got_comm = TRUE;
break;
} }
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) {
if (aiff->streaming) {
if (!gst_aiffparse_peek_chunk_info (aiff, &tag, &size))
return GST_FLOW_OK;
} else {
if ((res =
gst_pad_pull_range (aiff->sinkpad, aiff->offset, 8,
&buf)) != GST_FLOW_OK)
goto header_read_error;
tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf));
size = GST_READ_UINT32_BE (GST_BUFFER_DATA (buf) + 4);
}
GST_INFO_OBJECT (aiff,
"Got TAG: %" GST_FOURCC_FORMAT ", offset %" G_GUINT64_FORMAT,
GST_FOURCC_ARGS (tag), aiff->offset);
/* We just keep reading chunks until we find the one we're interested in.
*/
switch (tag) {
case GST_MAKE_FOURCC ('S', 'S', 'N', 'D'):{ case GST_MAKE_FOURCC ('S', 'S', 'N', 'D'):{
GstFormat fmt; GstFormat fmt;
GST_DEBUG_OBJECT (aiff, "Got 'SSND' TAG, size : %d", size); GST_DEBUG_OBJECT (aiff, "Got 'SSND' TAG, size : %d", size);
gotdata = TRUE;
if (aiff->streaming) { if (aiff->streaming) {
gst_adapter_flush (aiff->adapter, 8); gst_adapter_flush (aiff->adapter, 8);
gotdata = TRUE;
} else { } else {
gst_buffer_unref (buf); gst_buffer_unref (buf);
} }
@ -849,6 +849,9 @@ gst_aiffparse_stream_headers (AIFFParse * aiff)
aiff->offset += size; aiff->offset += size;
} }
GST_DEBUG_OBJECT (aiff, "datasize = %d", size); GST_DEBUG_OBJECT (aiff, "datasize = %d", size);
if (aiff->streaming) {
done = TRUE;
}
break; break;
} }
default: default:
@ -857,10 +860,23 @@ gst_aiffparse_stream_headers (AIFFParse * aiff)
if (upstream_size && (aiff->offset >= upstream_size)) { if (upstream_size && (aiff->offset >= upstream_size)) {
/* Now we have gone through the whole file */ /* 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"); GST_DEBUG_OBJECT (aiff, "Finished parsing headers");
if (gst_aiffparse_calculate_duration (aiff)) { if (gst_aiffparse_calculate_duration (aiff)) {
@ -888,11 +904,16 @@ gst_aiffparse_stream_headers (AIFFParse * aiff)
return GST_FLOW_OK; return GST_FLOW_OK;
/* ERROR */ /* ERROR */
invalid_aiff: no_header:
{ {
GST_ELEMENT_ERROR (aiff, STREAM, TYPE_NOT_FOUND, (NULL), GST_ELEMENT_ERROR (aiff, STREAM, TYPE_NOT_FOUND, (NULL),
("Invalid AIFF header (no COMM at start): %" ("Invalid AIFF header (no COMM found)"));
GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag))); return GST_FLOW_ERROR;
}
no_data:
{
GST_ELEMENT_ERROR (aiff, STREAM, TYPE_NOT_FOUND, (NULL),
("Invalid AIFF: no SSND found"));
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
} }
parse_header_error: parse_header_error: