From 0f3ab5732d6c23a4353b36ddb67845e8293279f0 Mon Sep 17 00:00:00 2001 From: Nomango Date: Sun, 8 Oct 2023 15:05:45 +0800 Subject: [PATCH] [deploy] pref: estimate the size of ogg file --- src/kiwano-audio/AudioData.h | 5 ++++ src/kiwano-audio/AudioModule.cpp | 2 +- src/kiwano-audio/Ogg/OggTranscoder.cpp | 38 ++++++++++++++++---------- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/kiwano-audio/AudioData.h b/src/kiwano-audio/AudioData.h index f8c9c17c..9338ff9a 100644 --- a/src/kiwano-audio/AudioData.h +++ b/src/kiwano-audio/AudioData.h @@ -55,6 +55,11 @@ struct AudioMeta uint32_t samples_per_sec = 44100; ///< 采样率,11025 表示 11.025kHz。PCM格式的采样率通常为44.1kHz uint16_t bits_per_sample = 16; ///< 位深,PCM格式为 8 或 16 uint16_t block_align = 4; ///< 块对齐,PCM格式通常是 (channels * bits_per_sample) / 8 + + inline uint32_t avg_bytes_per_sec() const noexcept + { + return uint32_t(this->samples_per_sec * this->block_align); + } }; /** diff --git a/src/kiwano-audio/AudioModule.cpp b/src/kiwano-audio/AudioModule.cpp index 6a58492e..caa89374 100644 --- a/src/kiwano-audio/AudioModule.cpp +++ b/src/kiwano-audio/AudioModule.cpp @@ -140,7 +140,7 @@ bool AudioModule::CreateSound(Sound& sound, AudioDataPtr data) tmp.nSamplesPerSec = DWORD(meta.samples_per_sec); tmp.wBitsPerSample = WORD(meta.bits_per_sample); tmp.nBlockAlign = WORD(meta.block_align); - tmp.nAvgBytesPerSec = DWORD(meta.samples_per_sec * meta.block_align); + tmp.nAvgBytesPerSec = DWORD(meta.avg_bytes_per_sec()); data->SetNative(tmp); wave_fmt = const_cast(data->GetNative().CastPtr()); diff --git a/src/kiwano-audio/Ogg/OggTranscoder.cpp b/src/kiwano-audio/Ogg/OggTranscoder.cpp index 6d473a48..47fa00d9 100644 --- a/src/kiwano-audio/Ogg/OggTranscoder.cpp +++ b/src/kiwano-audio/Ogg/OggTranscoder.cpp @@ -47,7 +47,7 @@ AudioDataPtr OggTranscoder::Decode(const String& file_path) int err = ov_fopen(file_path.c_str(), &vf); if (err != 0) { - KGE_ERROR(strings::Format("%s failed (%d): %s", __FUNCTION__, err, "Load audio failed")); + KGE_ERROR(strings::Format("%s failed (%d): %s", __FUNCTION__, err, "Open ogg audio failed")); return nullptr; } @@ -57,28 +57,38 @@ AudioDataPtr OggTranscoder::Decode(const String& file_path) AudioMeta meta; meta.samples_per_sec = uint32_t(vi->rate); meta.channels = uint16_t(vi->channels); + meta.bits_per_sample = uint16_t(16); // the 'word' param of ov_read sets to 2, which means 16-bits samples. + meta.block_align = uint16_t(meta.channels * meta.bits_per_sample / 8); + + // Get the audio total duration (in microseconds) + auto duration = static_cast(math::Ceil(ov_time_total(&vf, -1) * 1e6)); + + // allocate buffer + std::vector data; + + const size_t expected_size = size_t(((duration * meta.avg_bytes_per_sec())) / 1000000) + 1; + data.resize(expected_size); // read ogg audio - size_t buffer_size = 4096; - size_t grow_size = buffer_size; + size_t pos = 0; + size_t step = 4096; int bitstream; - - std::vector data; - size_t pos = data.size(); while (true) { - if (data.size() < pos + buffer_size) + if (data.size() <= pos) { - // allocate buffer - data.resize(pos + grow_size); - if (grow_size < 1024000) - { - grow_size = size_t(double(grow_size) * 1.25); - } + data.resize(pos + step); } + const size_t buffer_size = std::min(step, data.size() - pos); + int bytes_read = ov_read(&vf, data.data() + pos, int(buffer_size), 0, 2, 1, &bitstream); - if (bytes_read <= 0) + if (bytes_read == 0) break; + if (bytes_read < 0) + { + KGE_ERROR(strings::Format("%s failed (%d): %s", __FUNCTION__, bytes_read, "Decode ogg audio failed")); + return nullptr; + } pos += bytes_read; } ov_clear(&vf);