[deploy] pref: estimate the size of ogg file

This commit is contained in:
Nomango 2023-10-08 15:05:45 +08:00
parent 24368788eb
commit 0f3ab5732d
3 changed files with 30 additions and 15 deletions

View File

@ -55,6 +55,11 @@ struct AudioMeta
uint32_t samples_per_sec = 44100; ///< 采样率11025 表示 11.025kHz。PCM格式的采样率通常为44.1kHz uint32_t samples_per_sec = 44100; ///< 采样率11025 表示 11.025kHz。PCM格式的采样率通常为44.1kHz
uint16_t bits_per_sample = 16; ///< 位深PCM格式为 8 或 16 uint16_t bits_per_sample = 16; ///< 位深PCM格式为 8 或 16
uint16_t block_align = 4; ///< 块对齐PCM格式通常是 (channels * bits_per_sample) / 8 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);
}
}; };
/** /**

View File

@ -140,7 +140,7 @@ bool AudioModule::CreateSound(Sound& sound, AudioDataPtr data)
tmp.nSamplesPerSec = DWORD(meta.samples_per_sec); tmp.nSamplesPerSec = DWORD(meta.samples_per_sec);
tmp.wBitsPerSample = WORD(meta.bits_per_sample); tmp.wBitsPerSample = WORD(meta.bits_per_sample);
tmp.nBlockAlign = WORD(meta.block_align); 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); data->SetNative(tmp);
wave_fmt = const_cast<WAVEFORMATEX*>(data->GetNative().CastPtr<WAVEFORMATEX>()); wave_fmt = const_cast<WAVEFORMATEX*>(data->GetNative().CastPtr<WAVEFORMATEX>());

View File

@ -47,7 +47,7 @@ AudioDataPtr OggTranscoder::Decode(const String& file_path)
int err = ov_fopen(file_path.c_str(), &vf); int err = ov_fopen(file_path.c_str(), &vf);
if (err != 0) 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; return nullptr;
} }
@ -57,28 +57,38 @@ AudioDataPtr OggTranscoder::Decode(const String& file_path)
AudioMeta meta; AudioMeta meta;
meta.samples_per_sec = uint32_t(vi->rate); meta.samples_per_sec = uint32_t(vi->rate);
meta.channels = uint16_t(vi->channels); 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<std::uintmax_t>(math::Ceil(ov_time_total(&vf, -1) * 1e6));
// allocate buffer
std::vector<char> data;
const size_t expected_size = size_t(((duration * meta.avg_bytes_per_sec())) / 1000000) + 1;
data.resize(expected_size);
// read ogg audio // read ogg audio
size_t buffer_size = 4096; size_t pos = 0;
size_t grow_size = buffer_size; size_t step = 4096;
int bitstream; int bitstream;
std::vector<char> data;
size_t pos = data.size();
while (true) while (true)
{ {
if (data.size() < pos + buffer_size) if (data.size() <= pos)
{ {
// allocate buffer data.resize(pos + step);
data.resize(pos + grow_size);
if (grow_size < 1024000)
{
grow_size = size_t(double(grow_size) * 1.25);
}
} }
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); 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; 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; pos += bytes_read;
} }
ov_clear(&vf); ov_clear(&vf);