Fix PCM provider bugs

This commit is contained in:
wangqr 2019-09-15 13:27:54 -04:00 committed by Thomas Goyne
parent 1122c0880a
commit 10f7458b5f
2 changed files with 16 additions and 10 deletions

View File

@ -56,6 +56,7 @@ class PCMAudioProvider : public AudioProvider {
start += read_count;
pos += ip.num_samples;
}
ZeroFill(write_buf, count);
}
protected:
@ -67,7 +68,7 @@ protected:
template<typename T, typename UInt>
T Read(UInt *data_left) {
if (*data_left < sizeof(T)) throw file_ended();
if (file.size() - file_pos < sizeof(T)) throw file_ended();
if (file_pos > file.size() || file.size() - file_pos < sizeof(T)) throw file_ended();
auto data = file.read(file_pos, sizeof(T));
file_pos += sizeof(T);
@ -89,7 +90,7 @@ struct FourCC {
bool operator==(const char *cmp) const { return !(*this != cmp); }
};
// Overview of RIFF WAV: <http://www.sonicspot.com/guide/wavefiles.html>
// Overview of RIFF WAV: https://docs.microsoft.com/en-us/previous-versions/windows/hardware/design/dn653308(v=vs.85)
struct RiffWav {
using DataSize = uint32_t;
using ChunkId = FourCC;
@ -97,7 +98,7 @@ struct RiffWav {
static const char *riff_id() { return "RIFF"; }
static const char *wave_id() { return "WAVE"; }
static const char *fmt_id() { return "fmt "; }
static const char *data_id() { return "data "; }
static const char *data_id() { return "data"; }
static const int alignment = 1;
@ -127,7 +128,7 @@ static const GUID w64Guiddata = {{
0x64, 0x61, 0x74, 0x61, 0xF3, 0xAC, 0xD3, 0x11, 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A
}};
// http://www.vcs.de/fileadmin/user_upload/MBS/PDF/Whitepaper/Informations_about_Sony_Wave64.pdf
// http://www.ambisonia.com/Members/mleese/sony_wave64.pdf/sony_wave64.pdf
struct Wave64 {
using DataSize = uint64_t;
using ChunkId = GUID;
@ -140,7 +141,7 @@ struct Wave64 {
static const uint64_t alignment = 7ULL;
// Wave 64 includes the size of the header in the chunk sizes
static uint64_t data_size(uint64_t size) { return size - 16; }
static uint64_t data_size(uint64_t size) { return size - 24; }
static uint64_t chunk_size(uint64_t size) { return size - 24; }
};
@ -164,9 +165,11 @@ public:
throw AudioDataNotFound("File is not a RIFF WAV file");
while (data_left) {
auto chunk_fcc = Read<ChunkId>(&data_left);
auto chunk_size = Impl::chunk_size(Read<DataSize>(&data_left));
uint64_t chunk_end = file_pos + chunk_size;
data_left -= std::min(chunk_size, data_left);
if (chunk_fcc == Impl::fmt_id()) {
@ -186,14 +189,16 @@ public:
else if (chunk_fcc == Impl::data_id()) {
if (!channels || !sample_rate || !bytes_per_sample)
throw AudioProviderError("Found 'data' chunk without format being set.");
index_points.emplace_back(IndexPoint{file_pos, chunk_size / bytes_per_sample / channels});
num_samples += chunk_size / bytes_per_sample / channels;
uint64_t chunk_decoded_samples = std::min<uint64_t>(chunk_size, file.size() - file_pos) / bytes_per_sample / channels;
decoded_samples += chunk_decoded_samples;
index_points.emplace_back(IndexPoint{file_pos, chunk_decoded_samples });
}
// There's a bunch of other chunk types. They're all dumb.
// blocks are aligned and the padding bytes are not included in
// the size of the chunk
file_pos += (chunk_size + Impl::alignment) & ~Impl::alignment;
file_pos = (chunk_end + Impl::alignment) & ~Impl::alignment;
}
}
@ -202,7 +207,8 @@ public:
throw AudioDataNotFound("File ended before reaching format chunk");
// Truncated files are fine otherwise
}
decoded_samples = num_samples;
if (decoded_samples == 0)
throw AudioDataNotFound("No audio sample can be decoded");
}
};
}

View File

@ -417,7 +417,7 @@ TEST(lagi_audio, pcm_truncated) {
}
#define RIFF "RIFF\0\0\0\x60WAVE"
#define FMT_VALID "fmt \20\0\0\0\1\0\1\0\20\0\0\0\0\0\0\0\0\0\20\0"
#define FMT_VALID "fmt \x10\0\0\0\1\0\1\0\x10\0\0\0\x20\0\0\0\2\0\x10\0"
#define DATA_VALID "data\1\0\0\0\0\0"
#define WRITE(str) do { bfs::ofstream s(path, std::ios_base::binary); s.write(str, sizeof(str) - 1); } while (false)
@ -438,7 +438,7 @@ TEST(lagi_audio, pcm_incomplete) {
ASSERT_THROW(agi::CreatePCMAudioProvider(path, nullptr), agi::AudioDataNotFound);
// Incomplete files
auto valid_file = RIFF FMT_VALID DATA_VALID;
const char valid_file[] = RIFF FMT_VALID DATA_VALID;
// -1 for nul term, -3 so that longest file is still invalid
for (size_t i = 0; i < sizeof(valid_file) - 4; ++i) {