diff options
author | Dave Bryant <bryant@rockbox.org> | 2010-12-05 19:25:32 +0000 |
---|---|---|
committer | Dave Bryant <bryant@rockbox.org> | 2010-12-05 19:25:32 +0000 |
commit | 516693fcc9a35eeae86422a17ac9d2be4bbe899c (patch) | |
tree | 7343dcda98f60cca9ecfc47f37310a2d4822d2d9 /apps/metadata/wavpack.c | |
parent | 271441eb9d568525a72cde810a64b63db5a39147 (diff) |
make WavPack library check the extent of the block that it is parsing so that it cannot run into the next block; also enhance the metadata code to handle the case of files with non-audio blocks at the beginning (which can happen if the source WAV file has lots of RIFF data)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28736 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/metadata/wavpack.c')
-rw-r--r-- | apps/metadata/wavpack.c | 108 |
1 files changed, 65 insertions, 43 deletions
diff --git a/apps/metadata/wavpack.c b/apps/metadata/wavpack.c index bb181b8d3f..7d19435543 100644 --- a/apps/metadata/wavpack.c +++ b/apps/metadata/wavpack.c @@ -47,14 +47,16 @@ static const long wavpack_sample_rates [] = * now works with self-extrating WavPack files and also will scan the * metadata for non-standard sampling rates. This no longer fails on * WavPack files containing floating-point audio data because these are - * now converted to standard Rockbox format in the decoder. + * now converted to standard Rockbox format in the decoder, and also + * handles the case where up to 15 non-audio blocks might occur at the + * beginning of the file. */ bool get_wavpack_metadata(int fd, struct mp3entry* id3) { /* Use the trackname part of the id3 structure as a temporary buffer */ unsigned char* buf = (unsigned char *)id3->path; - uint32_t totalsamples, blocksamples, flags; + uint32_t totalsamples = (uint32_t) -1; int i; for (i = 0; i < 256; ++i) { @@ -78,66 +80,86 @@ bool get_wavpack_metadata(int fd, struct mp3entry* id3) id3->vbr = true; /* All WavPack files are VBR */ id3->filesize = filesize (fd); - totalsamples = get_long_le(&buf[12]); - blocksamples = get_long_le(&buf[20]); - flags = get_long_le(&buf[24]); - if (blocksamples) { - int srindx = ((buf [26] >> 7) & 1) + ((buf [27] << 1) & 14); + /* check up to 16 headers before we give up finding one with audio */ - if (srindx == 15) { - uint32_t meta_bytes = buf [4] + (buf [5] << 8) + (buf [6] << 16) - 24; - uint32_t meta_size; + for (i = 0; i < 16; ++i) { + uint32_t trial_totalsamples = get_long_le(&buf[12]); + uint32_t blockindex = get_long_le(&buf[16]); + uint32_t blocksamples = get_long_le(&buf[20]); + uint32_t flags = get_long_le(&buf[24]); - id3->frequency = 44100; + if (totalsamples == (uint32_t) -1 && trial_totalsamples != (uint32_t) -1 && blockindex == 0) + totalsamples = trial_totalsamples; - while (meta_bytes >= 6) { - if (read(fd, buf, 2) < 2) - break; + if (blocksamples) { + int srindx = ((buf [26] >> 7) & 1) + ((buf [27] << 1) & 14); + + if (srindx == 15) { + uint32_t meta_bytes = buf [4] + (buf [5] << 8) + (buf [6] << 16) - 24; + uint32_t meta_size; - if (buf [0] & ID_LARGE) { - if (read(fd, buf + 2, 2) < 2) + id3->frequency = 44100; + + while (meta_bytes >= 6) { + if (read(fd, buf, 2) < 2) break; - meta_size = (buf [1] << 1) + (buf [2] << 9) + (buf [3] << 17); - meta_bytes -= meta_size + 4; - } - else { - meta_size = buf [1] << 1; - meta_bytes -= meta_size + 2; + if (buf [0] & ID_LARGE) { + if (read(fd, buf + 2, 2) < 2) + break; - if ((buf [0] & ID_UNIQUE) == ID_SAMPLE_RATE) { - if (meta_size == 4 && read(fd, buf + 2, 4) == 4) - id3->frequency = buf [2] + (buf [3] << 8) + (buf [4] << 16); + meta_size = (buf [1] << 1) + (buf [2] << 9) + (buf [3] << 17); + meta_bytes -= meta_size + 4; + } + else { + meta_size = buf [1] << 1; + meta_bytes -= meta_size + 2; - break; + if ((buf [0] & ID_UNIQUE) == ID_SAMPLE_RATE) { + if (meta_size == 4 && read(fd, buf + 2, 4) == 4) + id3->frequency = buf [2] + (buf [3] << 8) + (buf [4] << 16); + + break; + } } - } - if (meta_size > 0 && lseek(fd, meta_size, SEEK_CUR) < 0) - break; + if (meta_size > 0 && lseek(fd, meta_size, SEEK_CUR) < 0) + break; + } } - } - else - id3->frequency = wavpack_sample_rates[srindx]; + else + id3->frequency = wavpack_sample_rates[srindx]; + + /* if the total number of samples is still unknown, make a guess on the high side (for now) */ + + if (totalsamples == (uint32_t) -1) { + totalsamples = filesize (fd) * 3; - /* if the total number of samples is unknown, make a guess on the high side (for now) */ + if (!(flags & HYBRID_FLAG)) + totalsamples /= 2; - if (totalsamples == (uint32_t) -1) { - totalsamples = filesize (fd) * 3; + if (!(flags & MONO_FLAG)) + totalsamples /= 2; + } - if (!(flags & HYBRID_FLAG)) - totalsamples /= 2; + id3->length = ((int64_t) totalsamples * 1000) / id3->frequency; + id3->bitrate = filesize (fd) / (id3->length / 8); - if (!(flags & MONO_FLAG)) - totalsamples /= 2; + read_ape_tags(fd, id3); + return true; } + else { /* block did not contain audio, so seek to the end and see if there's another */ + uint32_t meta_bytes = buf [4] + (buf [5] << 8) + (buf [6] << 16) - 24; - id3->length = ((int64_t) totalsamples * 1000) / id3->frequency; - id3->bitrate = filesize (fd) / (id3->length / 8); + if ((meta_bytes > 0 && lseek(fd, meta_bytes, SEEK_CUR) < 0) || + read(fd, buf, 32) < 32) + break; - read_ape_tags(fd, id3); - return true; + if (memcmp (buf, "wvpk", 4) != 0 || buf [9] != 4 || + buf [8] < 2 || buf [8] > 0x10) + break; + } } return false; |