• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "VorbisDecoderTest"
19 #include <utils/Log.h>
20 
21 #include <fstream>
22 
23 #include "VorbisDecoderTestEnvironment.h"
24 
25 #define OUTPUT_FILE_NAME "/data/local/tmp/VorbisDecoderOutput.raw"
26 
27 constexpr uint32_t kMaxChannels = 255;
28 constexpr uint32_t kMaxNumSamplesPerChannel = 8192;
29 
30 struct vorbis_dsp_state;
31 struct vorbis_info;
32 struct FrameInfo {
33     int32_t bytesCount;
34     uint32_t flags;
35     int64_t timestamp;
36 };
37 
38 extern "C" {
39     #include <Tremolo/codec_internal.h>
40 
41     int _vorbis_unpack_books(vorbis_info* vi, oggpack_buffer* opb);
42     int _vorbis_unpack_info(vorbis_info* vi, oggpack_buffer* opb);
43     int _vorbis_unpack_comment(vorbis_comment* vc, oggpack_buffer* opb);
44 }
45 
46 static VorbisDecoderTestEnvironment* gEnv = nullptr;
47 
48 class VorbisDecoderTest : public ::testing::TestWithParam<pair<string, string>> {
49   public:
VorbisDecoderTest()50     VorbisDecoderTest()
51         : mNumFramesLeftOnPage(-1),
52           mInfoUnpacked(false),
53           mBooksUnpacked(false),
54           mInputBuffer(nullptr),
55           mOutputBuffer(nullptr),
56           mState(nullptr),
57           mVi(nullptr) {}
58 
~VorbisDecoderTest()59     ~VorbisDecoderTest() {
60         if (mInputBuffer) free(mInputBuffer);
61         if (mOutputBuffer) free(mOutputBuffer);
62         if (mEleStream.is_open()) mEleStream.close();
63         if (mState) {
64             vorbis_dsp_clear(mState);
65             delete mState;
66             mState = nullptr;
67         }
68 
69         if (mVi) {
70             vorbis_info_clear(mVi);
71             delete mVi;
72             mVi = nullptr;
73         }
74         mNumFramesLeftOnPage = -1;
75         if (gEnv->cleanUp()) remove(OUTPUT_FILE_NAME);
76     }
77 
78     int32_t initVorbisDecoder();
79     void processVorbisDecoder(vector<FrameInfo> Info, int32_t offset, int32_t range,
80                               ofstream& ostrm);
81 
82     ifstream mEleStream;
83     int32_t mNumFramesLeftOnPage;
84     bool mInfoUnpacked;
85     bool mBooksUnpacked;
86     char* mInputBuffer;
87     int16_t* mOutputBuffer;
88     vorbis_dsp_state* mState;
89     vorbis_info* mVi;
90 };
91 
getInfo(string infoFileName,vector<FrameInfo> & Info)92 void getInfo(string infoFileName, vector<FrameInfo>& Info) {
93     ifstream eleInfo;
94     eleInfo.open(infoFileName);
95     ASSERT_EQ(eleInfo.is_open(), true) << "Failed to open " << infoFileName;
96     while (1) {
97         int32_t bytesCount = 0;
98         uint32_t flags = 0;
99         uint32_t timestamp = 0;
100 
101         if (!(eleInfo >> bytesCount)) break;
102         eleInfo >> flags;
103         eleInfo >> timestamp;
104         Info.push_back({bytesCount, flags, timestamp});
105     }
106     if (eleInfo.is_open()) eleInfo.close();
107 }
108 
initVorbisDecoder()109 int32_t VorbisDecoderTest::initVorbisDecoder() {
110     if (!mVi) {
111         mVi = new vorbis_info{};
112         if (!mVi) return -1;
113     }
114     vorbis_info_clear(mVi);
115 
116     if (!mState) {
117         mState = new vorbis_dsp_state{};
118         if (!mState) return -1;
119     }
120     vorbis_dsp_clear(mState);
121 
122     return 0;
123 }
124 
makeBitReader(const void * inputBuffer,size_t size,ogg_buffer * buf,ogg_reference * ref,oggpack_buffer * bits)125 static void makeBitReader(const void* inputBuffer, size_t size, ogg_buffer* buf, ogg_reference* ref,
126                           oggpack_buffer* bits) {
127     buf->data = (uint8_t*)inputBuffer;
128     buf->size = size;
129     buf->refcount = 1;
130     buf->ptr.owner = nullptr;
131 
132     ref->buffer = buf;
133     ref->begin = 0;
134     ref->length = size;
135     ref->next = nullptr;
136 
137     oggpack_readinit(bits, ref);
138 }
139 
processVorbisDecoder(vector<FrameInfo> Info,int32_t offset,int32_t range,ofstream & ostrm)140 void VorbisDecoderTest::processVorbisDecoder(vector<FrameInfo> Info, int32_t offset, int32_t range,
141                                              ofstream& ostrm) {
142     int32_t frameID = offset;
143     ASSERT_GE(range, 0) << "Invalid Range";
144     ASSERT_GE(offset, 0) << "Invalid Offset";
145     ASSERT_LT(offset, Info.size()) << "Offset must be less than ";
146 
147     while (1) {
148         if (frameID == Info.size() || frameID == (offset + range)) break;
149         int32_t size = (Info)[frameID].bytesCount;
150         ASSERT_GE(size, 0) << "Size for the memory allocation is negative" << size;
151 
152         if (!mInputBuffer) {
153             mInputBuffer = (char*)malloc(size);
154             ASSERT_NE(mInputBuffer, nullptr) << "Insufficient memory to read frame";
155         }
156 
157         mEleStream.read(mInputBuffer, size);
158         ASSERT_EQ(mEleStream.gcount(), size)
159                 << "Invalid size read. Requested: " << size << " and read: " << mEleStream.gcount();
160 
161         int32_t numChannels = mVi->channels;
162         /* Decode vorbis headers only once */
163         if (size > 7 && !memcmp(&mInputBuffer[1], "vorbis", 6) &&
164             (!mInfoUnpacked || !mBooksUnpacked)) {
165             ASSERT_TRUE((mInputBuffer[0] == 1) || (mInputBuffer[0] == 5))
166                     << "unexpected type received " << mInputBuffer[0];
167             ogg_buffer buf;
168             ogg_reference ref;
169             oggpack_buffer bits;
170 
171             // skip 7 <type + "vorbis"> bytes
172             makeBitReader((const uint8_t*)mInputBuffer + 7, size - 7, &buf, &ref, &bits);
173             if (mInputBuffer[0] == 1) {
174                 vorbis_info_init(mVi);
175                 int32_t status = _vorbis_unpack_info(mVi, &bits);
176                 ASSERT_EQ(status, 0) << "Encountered error while unpacking info";
177                 if (mVi->channels != numChannels) {
178                     ALOGV("num channels changed: %d, sample rate: %ld", mVi->channels, mVi->rate);
179                     numChannels = mVi->channels;
180                 }
181                 ASSERT_FALSE(numChannels < 1 || numChannels > kMaxChannels)
182                         << "Invalid number of channels: " << numChannels;
183                 mInfoUnpacked = true;
184             } else {
185                 ASSERT_TRUE(mInfoUnpacked) << "Data with type:5 sent before sending type:1";
186                 int32_t status = _vorbis_unpack_books(mVi, &bits);
187                 ASSERT_EQ(status, 0) << "Encountered error while unpacking books";
188                 status = vorbis_dsp_init(mState, mVi);
189                 ASSERT_EQ(status, 0) << "Encountered error while dsp init";
190                 mBooksUnpacked = true;
191             }
192             ALOGV("frameID= %d", frameID);
193             frameID++;
194             free(mInputBuffer);
195             mInputBuffer = nullptr;
196             continue;
197         }
198 
199         ASSERT_TRUE(mInfoUnpacked && mBooksUnpacked)
200                 << "Missing CODEC_CONFIG data mInfoUnpacked: " << mInfoUnpacked
201                 << " mBooksUnpack: " << mBooksUnpacked;
202 
203         int32_t numPageFrames = 0;
204         ASSERT_GE(size, sizeof(numPageFrames))
205                 << "input header has size: " << size << " expected: " << sizeof(numPageFrames);
206         memcpy(&numPageFrames, mInputBuffer + size - sizeof(numPageFrames), sizeof(numPageFrames));
207         size -= sizeof(numPageFrames);
208         if (numPageFrames >= 0) {
209             mNumFramesLeftOnPage = numPageFrames;
210         }
211 
212         ogg_buffer buf;
213         buf.data = reinterpret_cast<unsigned char*>(mInputBuffer);
214         buf.size = size;
215         buf.refcount = 1;
216         buf.ptr.owner = nullptr;
217 
218         ogg_reference ref;
219         ref.buffer = &buf;
220         ref.begin = 0;
221         ref.length = buf.size;
222         ref.next = nullptr;
223 
224         ogg_packet pack;
225         pack.packet = &ref;
226         pack.bytes = ref.length;
227         pack.b_o_s = 0;
228         pack.e_o_s = 0;
229         pack.granulepos = 0;
230         pack.packetno = 0;
231 
232         size_t outCapacity = kMaxNumSamplesPerChannel * numChannels * sizeof(int16_t);
233         if (!mOutputBuffer) {
234             mOutputBuffer = (int16_t*)malloc(outCapacity);
235             ASSERT_NE(mOutputBuffer, nullptr) << "Insufficient memory";
236         }
237 
238         int32_t numFrames = 0;
239         int32_t ret = vorbis_dsp_synthesis(mState, &pack, 1);
240         if (0 != ret) {
241             ALOGV("vorbis_dsp_synthesis returned %d; ignored", ret);
242         } else {
243             numFrames = vorbis_dsp_pcmout(mState, mOutputBuffer, kMaxNumSamplesPerChannel);
244             if (numFrames < 0) {
245                 ALOGV("vorbis_dsp_pcmout returned %d", numFrames);
246                 numFrames = 0;
247             }
248         }
249 
250         if (mNumFramesLeftOnPage >= 0) {
251             if (numFrames > mNumFramesLeftOnPage) {
252                 ALOGV("discarding %d frames at end of page", numFrames - mNumFramesLeftOnPage);
253                 numFrames = mNumFramesLeftOnPage;
254             }
255             mNumFramesLeftOnPage -= numFrames;
256         }
257         if (numFrames) {
258             int32_t outSize = numFrames * sizeof(int16_t) * numChannels;
259             ostrm.write(reinterpret_cast<char*>(mOutputBuffer), outSize);
260         }
261         frameID++;
262         free(mInputBuffer);
263         mInputBuffer = nullptr;
264     }
265     ALOGV("Last frame decoded = %d", frameID);
266 }
267 
TEST_P(VorbisDecoderTest,FlushTest)268 TEST_P(VorbisDecoderTest, FlushTest) {
269     string inputFileName = gEnv->getRes() + GetParam().first;
270     string infoFileName = gEnv->getRes() + GetParam().second;
271 
272     vector<FrameInfo> Info;
273     ASSERT_NO_FATAL_FAILURE(getInfo(infoFileName, Info));
274 
275     mEleStream.open(inputFileName, ifstream::binary);
276     ASSERT_EQ(mEleStream.is_open(), true) << "Failed to open " << inputFileName;
277 
278     ofstream ostrm;
279     ostrm.open(OUTPUT_FILE_NAME, std::ofstream::binary);
280     ASSERT_EQ(ostrm.is_open(), true) << "Failed to open " << OUTPUT_FILE_NAME;
281 
282     int32_t err = initVorbisDecoder();
283     ASSERT_EQ(err, 0) << "initVorbisDecoder: failed to create decoder " << err;
284 
285     ASSERT_NO_FATAL_FAILURE(processVorbisDecoder(Info, 0, Info.size() / 3, ostrm));
286 
287     // flushing the decoder
288     mNumFramesLeftOnPage = -1;
289     int32_t status = vorbis_dsp_restart(mState);
290     ASSERT_EQ(status, 0) << "Encountered error while restarting";
291 
292     ASSERT_NO_FATAL_FAILURE(processVorbisDecoder(Info, (Info.size() / 3), Info.size(), ostrm));
293 
294     ostrm.close();
295     Info.clear();
296 }
297 
TEST_P(VorbisDecoderTest,DecodeTest)298 TEST_P(VorbisDecoderTest, DecodeTest) {
299     string inputFileName = gEnv->getRes() + GetParam().first;
300     string infoFileName = gEnv->getRes() + GetParam().second;
301 
302     vector<FrameInfo> Info;
303     ASSERT_NO_FATAL_FAILURE(getInfo(infoFileName, Info));
304 
305     mEleStream.open(inputFileName, ifstream::binary);
306     ASSERT_EQ(mEleStream.is_open(), true) << "Failed to open " << inputFileName;
307 
308     ofstream ostrm;
309     ostrm.open(OUTPUT_FILE_NAME, std::ofstream::binary);
310     ASSERT_EQ(ostrm.is_open(), true) << "Failed to open " << OUTPUT_FILE_NAME;
311 
312     int32_t err = initVorbisDecoder();
313     ASSERT_EQ(err, 0) << "initVorbisDecoder: failed to create decoder " << err;
314 
315     ASSERT_NO_FATAL_FAILURE(processVorbisDecoder(Info, 0, Info.size(), ostrm));
316     ostrm.close();
317     Info.clear();
318 }
319 
320 INSTANTIATE_TEST_SUITE_P(
321         VorbisDecoderTestAll, VorbisDecoderTest,
322         ::testing::Values(make_pair("bbb_vorbis_mono_64kbps_48000hz.vorbis",
323                                     "bbb_vorbis_mono_64kbps_48000hz.info"),
324                           make_pair("bbb_vorbis_stereo_128kbps_44100hz_crypt.vorbis",
325                                     "bbb_vorbis_stereo_128kbps_44100hz_crypt.info"),
326                           make_pair("bbb_vorbis_stereo_128kbps_48000hz.vorbis",
327                                     "bbb_vorbis_stereo_128kbps_48000hz.info"),
328                           make_pair("bbb_vorbis_5ch_320kbps_48000hz.vorbis",
329                                     "bbb_vorbis_5ch_320kbps_48000hz.info"),
330                           make_pair("bbb_vorbis_6ch_384kbps_24000hz.vorbis",
331                                     "bbb_vorbis_6ch_384kbps_24000hz.info")));
332 
main(int argc,char ** argv)333 int main(int argc, char** argv) {
334     gEnv = new VorbisDecoderTestEnvironment();
335     ::testing::AddGlobalTestEnvironment(gEnv);
336     ::testing::InitGoogleTest(&argc, argv);
337     int status = gEnv->initFromOptions(argc, argv);
338     if (status == 0) {
339         status = RUN_ALL_TESTS();
340         ALOGV("Vorbis Decoder Test Result = %d", status);
341     }
342     return status;
343 }
344