2 #include "opusfile.hpp"
15 static int read(void *user_data
, unsigned char *ptr
, int size
)
17 std::istream
*stream
= static_cast<std::istream
*>(user_data
);
20 if(size
< 0 || !stream
->read(reinterpret_cast<char*>(ptr
), size
))
22 return stream
->gcount();
25 static int seek(void *user_data
, opus_int64 offset
, int whence
)
27 std::istream
*stream
= static_cast<std::istream
*>(user_data
);
30 if(whence
== SEEK_CUR
)
31 stream
->seekg(offset
, std::ios_base::cur
);
32 else if(whence
== SEEK_SET
)
33 stream
->seekg(offset
, std::ios_base::beg
);
34 else if(whence
== SEEK_END
)
35 stream
->seekg(offset
, std::ios_base::end
);
39 return stream
->good() ? 0 : -1;
42 static opus_int64
tell(void *user_data
)
44 std::istream
*stream
= static_cast<std::istream
*>(user_data
);
46 return stream
->tellg();
50 class OpusFileDecoder
: public Decoder
{
51 UniquePtr
<std::istream
> mFile
;
53 OggOpusFile
*mOggFile
;
56 ChannelConfig mChannelConfig
;
59 OpusFileDecoder(UniquePtr
<std::istream
> file
, OggOpusFile
*oggfile
, ChannelConfig sconfig
)
60 : mFile(std::move(file
)), mOggFile(oggfile
), mOggBitstream(0), mChannelConfig(sconfig
)
62 ~OpusFileDecoder() override final
;
64 ALuint
getFrequency() const override final
;
65 ChannelConfig
getChannelConfig() const override final
;
66 SampleType
getSampleType() const override final
;
68 uint64_t getLength() const override final
;
69 uint64_t getPosition() const override final
;
70 bool seek(uint64_t pos
) override final
;
72 std::pair
<uint64_t,uint64_t> getLoopPoints() const override final
;
74 ALuint
read(ALvoid
*ptr
, ALuint count
) override final
;
77 OpusFileDecoder::~OpusFileDecoder()
83 ALuint
OpusFileDecoder::getFrequency() const
85 // libopusfile always decodes to 48khz.
89 ChannelConfig
OpusFileDecoder::getChannelConfig() const
91 return mChannelConfig
;
94 SampleType
OpusFileDecoder::getSampleType() const
96 return SampleType::Int16
;
100 uint64_t OpusFileDecoder::getLength() const
102 ogg_int64_t len
= op_pcm_total(mOggFile
, -1);
103 return std::max
<ogg_int64_t
>(len
, 0);
106 uint64_t OpusFileDecoder::getPosition() const
108 ogg_int64_t pos
= op_pcm_tell(mOggFile
);
109 return std::max
<ogg_int64_t
>(pos
, 0);
112 bool OpusFileDecoder::seek(uint64_t pos
)
114 return op_pcm_seek(mOggFile
, pos
) == 0;
117 std::pair
<uint64_t,uint64_t> OpusFileDecoder::getLoopPoints() const
119 return std::make_pair(0, std::numeric_limits
<uint64_t>::max());
122 ALuint
OpusFileDecoder::read(ALvoid
*ptr
, ALuint count
)
125 opus_int16
*samples
= (opus_int16
*)ptr
;
126 int num_chans
= FramesToBytes(1, mChannelConfig
, SampleType::UInt8
);
129 if(num_chans
!= op_head(mOggFile
, -1)->channel_count
)
131 int len
= (count
-total
) * num_chans
;
133 long got
= op_read(mOggFile
, samples
, len
, &mOggBitstream
);
136 samples
+= got
*num_chans
;
140 // 1, 2, and 4 channel files decode into the same channel order as
141 // OpenAL, however 6 (5.1), 7 (6.1), and 8 (7.1) channel files need to be
143 if(mChannelConfig
== ChannelConfig::X51
)
145 samples
= (opus_int16
*)ptr
;
146 for(ALuint i
= 0;i
< total
;++i
)
148 // OpenAL : FL, FR, FC, LFE, RL, RR
149 // Opus : FL, FC, FR, RL, RR, LFE
150 std::swap(samples
[i
*6 + 1], samples
[i
*6 + 2]);
151 std::swap(samples
[i
*6 + 3], samples
[i
*6 + 5]);
152 std::swap(samples
[i
*6 + 4], samples
[i
*6 + 5]);
155 else if(mChannelConfig
== ChannelConfig::X61
)
157 samples
= (opus_int16
*)ptr
;
158 for(ALuint i
= 0;i
< total
;++i
)
160 // OpenAL : FL, FR, FC, LFE, RC, SL, SR
161 // Opus : FL, FC, FR, SL, SR, RC, LFE
162 std::swap(samples
[i
*7 + 1], samples
[i
*7 + 2]);
163 std::swap(samples
[i
*7 + 3], samples
[i
*7 + 6]);
164 std::swap(samples
[i
*7 + 4], samples
[i
*7 + 5]);
165 std::swap(samples
[i
*7 + 5], samples
[i
*7 + 6]);
168 else if(mChannelConfig
== ChannelConfig::X71
)
170 samples
= (opus_int16
*)ptr
;
171 for(ALuint i
= 0;i
< total
;++i
)
173 // OpenAL : FL, FR, FC, LFE, RL, RR, SL, SR
174 // Opus : FL, FC, FR, SL, SR, RL, RR, LFE
175 std::swap(samples
[i
*8 + 1], samples
[i
*8 + 2]);
176 std::swap(samples
[i
*8 + 3], samples
[i
*8 + 7]);
177 std::swap(samples
[i
*8 + 4], samples
[i
*8 + 5]);
178 std::swap(samples
[i
*8 + 5], samples
[i
*8 + 6]);
179 std::swap(samples
[i
*8 + 6], samples
[i
*8 + 7]);
187 SharedPtr
<Decoder
> OpusFileDecoderFactory::createDecoder(UniquePtr
<std::istream
> &file
)
189 static const OpusFileCallbacks streamIO
= {
190 read
, seek
, tell
, nullptr
193 OggOpusFile
*oggfile
= op_open_callbacks(file
.get(), &streamIO
, nullptr, 0, nullptr);
194 if(!oggfile
) return nullptr;
196 int num_chans
= op_head(oggfile
, -1)->channel_count
;
197 ChannelConfig channels
= ChannelConfig::Mono
;
199 channels
= ChannelConfig::Mono
;
200 else if(num_chans
== 2)
201 channels
= ChannelConfig::Stereo
;
202 else if(num_chans
== 4)
203 channels
= ChannelConfig::Quad
;
204 else if(num_chans
== 6)
205 channels
= ChannelConfig::X51
;
206 else if(num_chans
== 7)
207 channels
= ChannelConfig::X61
;
208 else if(num_chans
== 8)
209 channels
= ChannelConfig::X71
;
216 return MakeShared
<OpusFileDecoder
>(std::move(file
), oggfile
, channels
);