| 36 | static constexpr size_t DECODE_BUFFER_BYTES = DECODE_BUFFER_SAMPLES * sizeof(opus_int16); |
| 37 | |
| 38 | bool Load(SoundEntry &sound, bool new_format, std::vector<std::byte> &data) const override |
| 39 | { |
| 40 | if (!new_format) return false; |
| 41 | |
| 42 | /* At least 57 bytes are needed for an Opus-only file. */ |
| 43 | if (sound.file_size < MIN_OPUS_FILE_SIZE) return false; |
| 44 | |
| 45 | /* Test if data is an Ogg Opus stream, as identified by the initial file header. */ |
| 46 | auto filepos = sound.file->GetPos(); |
| 47 | std::vector<uint8_t> tmp(MIN_OPUS_FILE_SIZE); |
| 48 | sound.file->ReadBlock(tmp.data(), tmp.size()); |
| 49 | if (op_test(nullptr, tmp.data(), tmp.size()) != 0) return false; |
| 50 | |
| 51 | /* Read the whole file into memory. */ |
| 52 | tmp.resize(sound.file_size); |
| 53 | sound.file->SeekTo(filepos, SEEK_SET); |
| 54 | sound.file->ReadBlock(tmp.data(), tmp.size()); |
| 55 | |
| 56 | int error = 0; |
| 57 | auto of = AutoRelease<OggOpusFile, op_free>(op_open_memory(tmp.data(), tmp.size(), &error)); |
| 58 | if (error != 0) { |
| 59 | Debug(grf, 0, "SoundLoader_Opus: Unable to open stream."); |
| 60 | return false; |
| 61 | } |
| 62 | |
| 63 | size_t datapos = 0; |
| 64 | for (;;) { |
| 65 | data.resize(datapos + DECODE_BUFFER_BYTES); |
| 66 | |
| 67 | int link_index; |
| 68 | int read = op_read(of.get(), reinterpret_cast<opus_int16 *>(&data[datapos]), DECODE_BUFFER_BYTES, &link_index); |
| 69 | if (read == 0) break; |
| 70 | |
| 71 | if (read < 0) { |
| 72 | Debug(grf, 0, "SoundLoader_Opus: Unexpected end of stream."); |
| 73 | data.clear(); |
| 74 | return false; |
| 75 | } |
| 76 | |
| 77 | int channels = op_channel_count(of.get(), link_index); |
| 78 | if (channels != 1) { |
| 79 | Debug(grf, 0, "SoundLoader_Opus: Unsupported channels {}, expected 1.", channels); |
| 80 | data.clear(); |
| 81 | return false; |
| 82 | } |
| 83 | |
| 84 | datapos += read * sizeof(opus_int16); |
| 85 | } |
| 86 | |
| 87 | /* OpusFile always decodes at 48kHz. */ |
| 88 | sound.channels = 1; |
| 89 | sound.bits_per_sample = OPUS_SAMPLE_BITS; |
| 90 | sound.rate = OPUS_SAMPLE_RATE; |
| 91 | |
| 92 | /* We resized by DECODE_BUFFER_BYTES just before finally reading zero bytes, undo this. */ |
| 93 | data.resize(data.size() - DECODE_BUFFER_BYTES); |
| 94 | |
| 95 | return true; |