diff options
Diffstat (limited to 'linden/indra/llaudio/llaudiodecodemgr.cpp')
-rw-r--r-- | linden/indra/llaudio/llaudiodecodemgr.cpp | 635 |
1 files changed, 635 insertions, 0 deletions
diff --git a/linden/indra/llaudio/llaudiodecodemgr.cpp b/linden/indra/llaudio/llaudiodecodemgr.cpp new file mode 100644 index 0000000..d98ff5d --- /dev/null +++ b/linden/indra/llaudio/llaudiodecodemgr.cpp | |||
@@ -0,0 +1,635 @@ | |||
1 | /** | ||
2 | * @file llaudiodecodemgr.cpp | ||
3 | * | ||
4 | * Copyright (c) 2003-2007, Linden Research, Inc. | ||
5 | * | ||
6 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
7 | * to you under the terms of the GNU General Public License, version 2.0 | ||
8 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
9 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
10 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
11 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
12 | * | ||
13 | * There are special exceptions to the terms and conditions of the GPL as | ||
14 | * it is applied to this Source Code. View the full text of the exception | ||
15 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
16 | * online at http://secondlife.com/developers/opensource/flossexception | ||
17 | * | ||
18 | * By copying, modifying or distributing this software, you acknowledge | ||
19 | * that you have read and understood your obligations described above, | ||
20 | * and agree to abide by those obligations. | ||
21 | * | ||
22 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
23 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
24 | * COMPLETENESS OR PERFORMANCE. | ||
25 | */ | ||
26 | |||
27 | #include "linden_common.h" | ||
28 | |||
29 | #include <vector> | ||
30 | #include <iterator> | ||
31 | #include <algorithm> | ||
32 | #include <stdio.h> | ||
33 | |||
34 | #include "llaudiodecodemgr.h" | ||
35 | |||
36 | #include "vorbisdecode.h" | ||
37 | #include "audioengine.h" | ||
38 | #include "lllfsthread.h" | ||
39 | #include "llvfile.h" | ||
40 | #include "llstring.h" | ||
41 | #include "lldir.h" | ||
42 | #include "llendianswizzle.h" | ||
43 | #include "audioengine.h" | ||
44 | #include "llassetstorage.h" | ||
45 | |||
46 | #include "vorbis/codec.h" | ||
47 | #include "vorbis/vorbisfile.h" | ||
48 | |||
49 | extern LLAudioEngine *gAudiop; | ||
50 | |||
51 | LLAudioDecodeMgr *gAudioDecodeMgrp = NULL; | ||
52 | |||
53 | static const S32 WAV_HEADER_SIZE = 44; | ||
54 | |||
55 | class LLVorbisDecodeState | ||
56 | { | ||
57 | public: | ||
58 | LLVorbisDecodeState(const LLUUID &uuid, const LLString &out_filename); | ||
59 | virtual ~LLVorbisDecodeState(); | ||
60 | |||
61 | BOOL initDecode(); | ||
62 | BOOL decodeSection(); // Return TRUE if done. | ||
63 | BOOL finishDecode(); | ||
64 | |||
65 | void flushBadFile(); | ||
66 | |||
67 | BOOL isValid() const { return mValid; } | ||
68 | BOOL isDone() const { return mDone; } | ||
69 | const LLUUID &getUUID() const { return mUUID; } | ||
70 | protected: | ||
71 | BOOL mValid; | ||
72 | BOOL mDone; | ||
73 | LLUUID mUUID; | ||
74 | |||
75 | std::vector<U8> mWAVBuffer; | ||
76 | #if !defined(USE_WAV_VFILE) | ||
77 | LLString mOutFilename; | ||
78 | LLLFSThread::handle_t mFileHandle; | ||
79 | #endif | ||
80 | |||
81 | LLVFile *mInFilep; | ||
82 | OggVorbis_File mVF; | ||
83 | S32 mCurrentSection; | ||
84 | }; | ||
85 | |||
86 | void LLVorbisDecodeState::flushBadFile() | ||
87 | { | ||
88 | if (mInFilep) | ||
89 | { | ||
90 | llwarns << "Flushing bad vorbis file from VFS for " << mUUID << llendl; | ||
91 | mInFilep->remove(); | ||
92 | } | ||
93 | } | ||
94 | |||
95 | |||
96 | LLAudioDecodeMgr::LLAudioDecodeMgr() | ||
97 | { | ||
98 | mCurrentDecodep = NULL; | ||
99 | } | ||
100 | |||
101 | LLAudioDecodeMgr::~LLAudioDecodeMgr() | ||
102 | { | ||
103 | delete mCurrentDecodep; | ||
104 | mCurrentDecodep = NULL; | ||
105 | } | ||
106 | |||
107 | |||
108 | void LLAudioDecodeMgr::processQueue(const F32 num_secs) | ||
109 | { | ||
110 | LLUUID uuid; | ||
111 | |||
112 | LLTimer decode_timer; | ||
113 | |||
114 | BOOL done = FALSE; | ||
115 | while (!done) | ||
116 | { | ||
117 | if (mCurrentDecodep) | ||
118 | { | ||
119 | BOOL res; | ||
120 | |||
121 | // Decode in a loop until we're done or have run out of time. | ||
122 | while(!(res = mCurrentDecodep->decodeSection()) && (decode_timer.getElapsedTimeF32() < num_secs)) | ||
123 | { | ||
124 | // decodeSection does all of the work above | ||
125 | } | ||
126 | |||
127 | if (mCurrentDecodep->isDone() && !mCurrentDecodep->isValid()) | ||
128 | { | ||
129 | // We had an error when decoding, abort. | ||
130 | llwarns << mCurrentDecodep->getUUID() << " has invalid vorbis data, aborting decode" << llendl; | ||
131 | mCurrentDecodep->flushBadFile(); | ||
132 | LLAudioData *adp = gAudiop->getAudioData(mCurrentDecodep->getUUID()); | ||
133 | adp->setHasValidData(FALSE); | ||
134 | delete mCurrentDecodep; | ||
135 | mCurrentDecodep = NULL; | ||
136 | done = TRUE; | ||
137 | } | ||
138 | |||
139 | if (!res) | ||
140 | { | ||
141 | // We've used up out time slice, bail... | ||
142 | done = TRUE; | ||
143 | } | ||
144 | else if (mCurrentDecodep) | ||
145 | { | ||
146 | if (mCurrentDecodep->finishDecode()) | ||
147 | { | ||
148 | // We finished! | ||
149 | if (mCurrentDecodep->isValid() && mCurrentDecodep->isDone()) | ||
150 | { | ||
151 | LLAudioData *adp = gAudiop->getAudioData(mCurrentDecodep->getUUID()); | ||
152 | adp->setHasDecodedData(TRUE); | ||
153 | adp->setHasValidData(TRUE); | ||
154 | |||
155 | // At this point, we could see if anyone needs this sound immediately, but | ||
156 | // I'm not sure that there's a reason to - we need to poll all of the playing | ||
157 | // sounds anyway. | ||
158 | //llinfos << "Finished the vorbis decode, now what?" << llendl; | ||
159 | } | ||
160 | else | ||
161 | { | ||
162 | llinfos << "Vorbis decode failed!!!" << llendl; | ||
163 | } | ||
164 | delete mCurrentDecodep; | ||
165 | mCurrentDecodep = NULL; | ||
166 | } | ||
167 | done = TRUE; // done for now | ||
168 | } | ||
169 | } | ||
170 | |||
171 | if (!done) | ||
172 | { | ||
173 | if (!mDecodeQueue.getLength()) | ||
174 | { | ||
175 | // Nothing else on the queue. | ||
176 | done = TRUE; | ||
177 | } | ||
178 | else | ||
179 | { | ||
180 | LLUUID uuid; | ||
181 | mDecodeQueue.pop(uuid); | ||
182 | if (gAudiop->hasDecodedFile(uuid)) | ||
183 | { | ||
184 | // This file has already been decoded, don't decode it again. | ||
185 | continue; | ||
186 | } | ||
187 | |||
188 | lldebugs << "Decoding " << uuid << " from audio queue!" << llendl; | ||
189 | |||
190 | char uuid_str[64]; /*Flawfinder: ignore*/ | ||
191 | char d_path[LL_MAX_PATH]; /*Flawfinder: ignore*/ | ||
192 | |||
193 | LLTimer timer; | ||
194 | timer.reset(); | ||
195 | |||
196 | uuid.toString(uuid_str); | ||
197 | snprintf(d_path, LL_MAX_PATH, "%s.dsf", gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str).c_str()); /*Flawfinder: ignore*/ | ||
198 | |||
199 | mCurrentDecodep = new LLVorbisDecodeState(uuid, d_path); | ||
200 | if (!mCurrentDecodep->initDecode()) | ||
201 | { | ||
202 | delete mCurrentDecodep; | ||
203 | mCurrentDecodep = NULL; | ||
204 | } | ||
205 | } | ||
206 | } | ||
207 | } | ||
208 | } | ||
209 | |||
210 | |||
211 | BOOL LLAudioDecodeMgr::addDecodeRequest(const LLUUID &uuid) | ||
212 | { | ||
213 | if (gAudiop->hasDecodedFile(uuid)) | ||
214 | { | ||
215 | // Already have a decoded version, don't need to decode it. | ||
216 | return TRUE; | ||
217 | } | ||
218 | |||
219 | if (gAssetStorage->hasLocalAsset(uuid, LLAssetType::AT_SOUND)) | ||
220 | { | ||
221 | // Just put it on the decode queue. | ||
222 | gAudioDecodeMgrp->mDecodeQueue.push(uuid); | ||
223 | return TRUE; | ||
224 | } | ||
225 | |||
226 | return FALSE; | ||
227 | } | ||
228 | |||
229 | |||
230 | S32 LLAudioDecodeMgr::getRequestCount() | ||
231 | { | ||
232 | /* | ||
233 | S32 count = 0; | ||
234 | if (mCurrentTransfer.notNull()) | ||
235 | { | ||
236 | count++; | ||
237 | } | ||
238 | |||
239 | count += mRequestQueue.getLength(); | ||
240 | return count; | ||
241 | */ | ||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | |||
246 | |||
247 | |||
248 | |||
249 | |||
250 | |||
251 | |||
252 | size_t vfs_read(void *ptr, size_t size, size_t nmemb, void *datasource) | ||
253 | { | ||
254 | LLVFile *file = (LLVFile *)datasource; | ||
255 | |||
256 | if (file->read((U8*)ptr, (S32)(size * nmemb))) /*Flawfinder: ignore*/ | ||
257 | { | ||
258 | S32 read = file->getLastBytesRead(); | ||
259 | return read / size; /*Flawfinder: ignore*/ | ||
260 | } | ||
261 | else | ||
262 | { | ||
263 | return 0; | ||
264 | } | ||
265 | } | ||
266 | |||
267 | int vfs_seek(void *datasource, ogg_int64_t offset, int whence) | ||
268 | { | ||
269 | LLVFile *file = (LLVFile *)datasource; | ||
270 | |||
271 | // vfs has 31-bit files | ||
272 | if (offset > S32_MAX) | ||
273 | { | ||
274 | return -1; | ||
275 | } | ||
276 | |||
277 | S32 origin; | ||
278 | switch (whence) { | ||
279 | case SEEK_SET: | ||
280 | origin = 0; | ||
281 | break; | ||
282 | case SEEK_END: | ||
283 | origin = file->getSize(); | ||
284 | break; | ||
285 | case SEEK_CUR: | ||
286 | origin = -1; | ||
287 | break; | ||
288 | default: | ||
289 | llerrs << "Invalid whence argument to vfs_seek" << llendl; | ||
290 | return -1; | ||
291 | } | ||
292 | |||
293 | if (file->seek((S32)offset, origin)) | ||
294 | { | ||
295 | return 0; | ||
296 | } | ||
297 | else | ||
298 | { | ||
299 | return -1; | ||
300 | } | ||
301 | } | ||
302 | |||
303 | int vfs_close (void *datasource) | ||
304 | { | ||
305 | LLVFile *file = (LLVFile *)datasource; | ||
306 | |||
307 | delete file; | ||
308 | |||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | long vfs_tell (void *datasource) | ||
313 | { | ||
314 | LLVFile *file = (LLVFile *)datasource; | ||
315 | |||
316 | return file->tell(); | ||
317 | } | ||
318 | |||
319 | |||
320 | |||
321 | |||
322 | LLVorbisDecodeState::LLVorbisDecodeState(const LLUUID &uuid, const LLString &out_filename) | ||
323 | { | ||
324 | mDone = FALSE; | ||
325 | mValid = FALSE; | ||
326 | mUUID = uuid; | ||
327 | mInFilep = NULL; | ||
328 | mCurrentSection = 0; | ||
329 | #if !defined(USE_WAV_VFILE) | ||
330 | mOutFilename = out_filename; | ||
331 | mFileHandle = LLLFSThread::nullHandle(); | ||
332 | #endif | ||
333 | // No default value for mVF, it's an ogg structure? | ||
334 | } | ||
335 | |||
336 | LLVorbisDecodeState::~LLVorbisDecodeState() | ||
337 | { | ||
338 | if (!mDone) | ||
339 | { | ||
340 | delete mInFilep; | ||
341 | mInFilep = NULL; | ||
342 | } | ||
343 | } | ||
344 | |||
345 | |||
346 | BOOL LLVorbisDecodeState::initDecode() | ||
347 | { | ||
348 | ov_callbacks vfs_callbacks; | ||
349 | vfs_callbacks.read_func = vfs_read; | ||
350 | vfs_callbacks.seek_func = vfs_seek; | ||
351 | vfs_callbacks.close_func = vfs_close; | ||
352 | vfs_callbacks.tell_func = vfs_tell; | ||
353 | |||
354 | //llinfos << "Initing decode from vfile: " << mUUID << llendl; | ||
355 | |||
356 | mInFilep = new LLVFile(gVFS, mUUID, LLAssetType::AT_SOUND); | ||
357 | if (!mInFilep || !mInFilep->getSize()) | ||
358 | { | ||
359 | llwarns << "unable to open vorbis source vfile for reading" << llendl; | ||
360 | delete mInFilep; | ||
361 | mInFilep = NULL; | ||
362 | return FALSE; | ||
363 | } | ||
364 | |||
365 | int r = ov_open_callbacks(mInFilep, &mVF, NULL, 0, vfs_callbacks); | ||
366 | if(r < 0) | ||
367 | { | ||
368 | llwarns << r << " Input to vorbis decode does not appear to be an Ogg bitstream: " << mUUID << llendl; | ||
369 | return(FALSE); | ||
370 | } | ||
371 | |||
372 | size_t size_guess = (size_t)ov_pcm_total(&mVF, -1); | ||
373 | vorbis_info* vi = ov_info(&mVF, -1); | ||
374 | size_guess *= vi->channels; | ||
375 | size_guess *= 2; | ||
376 | size_guess += 2048; | ||
377 | mWAVBuffer.reserve(size_guess); | ||
378 | mWAVBuffer.resize(WAV_HEADER_SIZE); | ||
379 | |||
380 | { | ||
381 | // write the .wav format header | ||
382 | //"RIFF" | ||
383 | mWAVBuffer[0] = 0x52; | ||
384 | mWAVBuffer[1] = 0x49; | ||
385 | mWAVBuffer[2] = 0x46; | ||
386 | mWAVBuffer[3] = 0x46; | ||
387 | |||
388 | // length = datalen + 36 (to be filled in later) | ||
389 | mWAVBuffer[4] = 0x00; | ||
390 | mWAVBuffer[5] = 0x00; | ||
391 | mWAVBuffer[6] = 0x00; | ||
392 | mWAVBuffer[7] = 0x00; | ||
393 | |||
394 | //"WAVE" | ||
395 | mWAVBuffer[8] = 0x57; | ||
396 | mWAVBuffer[9] = 0x41; | ||
397 | mWAVBuffer[10] = 0x56; | ||
398 | mWAVBuffer[11] = 0x45; | ||
399 | |||
400 | // "fmt " | ||
401 | mWAVBuffer[12] = 0x66; | ||
402 | mWAVBuffer[13] = 0x6D; | ||
403 | mWAVBuffer[14] = 0x74; | ||
404 | mWAVBuffer[15] = 0x20; | ||
405 | |||
406 | // chunk size = 16 | ||
407 | mWAVBuffer[16] = 0x10; | ||
408 | mWAVBuffer[17] = 0x00; | ||
409 | mWAVBuffer[18] = 0x00; | ||
410 | mWAVBuffer[19] = 0x00; | ||
411 | |||
412 | // format (1 = PCM) | ||
413 | mWAVBuffer[20] = 0x01; | ||
414 | mWAVBuffer[21] = 0x00; | ||
415 | |||
416 | // number of channels | ||
417 | mWAVBuffer[22] = 0x01; | ||
418 | mWAVBuffer[23] = 0x00; | ||
419 | |||
420 | // samples per second | ||
421 | mWAVBuffer[24] = 0x44; | ||
422 | mWAVBuffer[25] = 0xAC; | ||
423 | mWAVBuffer[26] = 0x00; | ||
424 | mWAVBuffer[27] = 0x00; | ||
425 | |||
426 | // average bytes per second | ||
427 | mWAVBuffer[28] = 0x88; | ||
428 | mWAVBuffer[29] = 0x58; | ||
429 | mWAVBuffer[30] = 0x01; | ||
430 | mWAVBuffer[31] = 0x00; | ||
431 | |||
432 | // bytes to output at a single time | ||
433 | mWAVBuffer[32] = 0x02; | ||
434 | mWAVBuffer[33] = 0x00; | ||
435 | |||
436 | // 16 bits per sample | ||
437 | mWAVBuffer[34] = 0x10; | ||
438 | mWAVBuffer[35] = 0x00; | ||
439 | |||
440 | // "data" | ||
441 | mWAVBuffer[36] = 0x64; | ||
442 | mWAVBuffer[37] = 0x61; | ||
443 | mWAVBuffer[38] = 0x74; | ||
444 | mWAVBuffer[39] = 0x61; | ||
445 | |||
446 | // these are the length of the data chunk, to be filled in later | ||
447 | mWAVBuffer[40] = 0x00; | ||
448 | mWAVBuffer[41] = 0x00; | ||
449 | mWAVBuffer[42] = 0x00; | ||
450 | mWAVBuffer[43] = 0x00; | ||
451 | } | ||
452 | |||
453 | //{ | ||
454 | //char **ptr=ov_comment(&mVF,-1)->user_comments; | ||
455 | // vorbis_info *vi=ov_info(&vf,-1); | ||
456 | //while(*ptr){ | ||
457 | // fprintf(stderr,"%s\n",*ptr); | ||
458 | // ++ptr; | ||
459 | //} | ||
460 | // fprintf(stderr,"\nBitstream is %d channel, %ldHz\n",vi->channels,vi->rate); | ||
461 | // fprintf(stderr,"\nDecoded length: %ld samples\n", (long)ov_pcm_total(&vf,-1)); | ||
462 | // fprintf(stderr,"Encoded by: %s\n\n",ov_comment(&vf,-1)->vendor); | ||
463 | //} | ||
464 | return TRUE; | ||
465 | } | ||
466 | |||
467 | BOOL LLVorbisDecodeState::decodeSection() | ||
468 | { | ||
469 | if (!mInFilep) | ||
470 | { | ||
471 | llwarns << "No VFS file to decode in vorbis!" << llendl; | ||
472 | return TRUE; | ||
473 | } | ||
474 | if (mDone) | ||
475 | { | ||
476 | // llwarns << "Already done with decode, aborting!" << llendl; | ||
477 | return TRUE; | ||
478 | } | ||
479 | char pcmout[4096]; /*Flawfinder: ignore*/ | ||
480 | |||
481 | BOOL eof = FALSE; | ||
482 | long ret=ov_read(&mVF, pcmout, sizeof(pcmout), 0, 2, 1, &mCurrentSection); | ||
483 | if (ret == 0) | ||
484 | { | ||
485 | /* EOF */ | ||
486 | eof = TRUE; | ||
487 | mDone = TRUE; | ||
488 | mValid = TRUE; | ||
489 | // llinfos << "Vorbis EOF" << llendl; | ||
490 | } | ||
491 | else if (ret < 0) | ||
492 | { | ||
493 | /* error in the stream. Not a problem, just reporting it in | ||
494 | case we (the app) cares. In this case, we don't. */ | ||
495 | |||
496 | llwarns << "BAD vorbis decode in decodeSection." << llendl; | ||
497 | |||
498 | mValid = FALSE; | ||
499 | mDone = TRUE; | ||
500 | // We're done, return TRUE. | ||
501 | return TRUE; | ||
502 | } | ||
503 | else | ||
504 | { | ||
505 | // llinfos << "Vorbis read " << ret << "bytes" << llendl; | ||
506 | /* we don't bother dealing with sample rate changes, etc, but. | ||
507 | you'll have to*/ | ||
508 | std::copy(pcmout, pcmout+ret, std::back_inserter(mWAVBuffer)); | ||
509 | } | ||
510 | return eof; | ||
511 | } | ||
512 | |||
513 | BOOL LLVorbisDecodeState::finishDecode() | ||
514 | { | ||
515 | if (!isValid()) | ||
516 | { | ||
517 | llwarns << "Bogus vorbis decode state for " << getUUID() << ", aborting!" << llendl; | ||
518 | return TRUE; // We've finished | ||
519 | } | ||
520 | |||
521 | #if !defined(USE_WAV_VFILE) | ||
522 | if (mFileHandle == LLLFSThread::nullHandle()) | ||
523 | #endif | ||
524 | { | ||
525 | ov_clear(&mVF); | ||
526 | |||
527 | // write "data" chunk length, in little-endian format | ||
528 | S32 data_length = mWAVBuffer.size() - WAV_HEADER_SIZE; | ||
529 | mWAVBuffer[40] = (data_length) & 0x000000FF; | ||
530 | mWAVBuffer[41] = (data_length >> 8) & 0x000000FF; | ||
531 | mWAVBuffer[42] = (data_length >> 16) & 0x000000FF; | ||
532 | mWAVBuffer[43] = (data_length >> 24) & 0x000000FF; | ||
533 | // write overall "RIFF" length, in little-endian format | ||
534 | data_length += 36; | ||
535 | mWAVBuffer[4] = (data_length) & 0x000000FF; | ||
536 | mWAVBuffer[5] = (data_length >> 8) & 0x000000FF; | ||
537 | mWAVBuffer[6] = (data_length >> 16) & 0x000000FF; | ||
538 | mWAVBuffer[7] = (data_length >> 24) & 0x000000FF; | ||
539 | |||
540 | // | ||
541 | // FUCK!!! Vorbis encode/decode messes up loop point transitions (pop) | ||
542 | // do a cheap-and-cheesy crossfade | ||
543 | // | ||
544 | { | ||
545 | S16 *samplep; | ||
546 | S32 i; | ||
547 | S32 fade_length; | ||
548 | char pcmout[4096]; /*Flawfinder: ignore*/ | ||
549 | |||
550 | fade_length = llmin((S32)128,(S32)(data_length-36)/8); | ||
551 | if((S32)mWAVBuffer.size() >= (WAV_HEADER_SIZE + 2* fade_length)) | ||
552 | { | ||
553 | memcpy(pcmout, &mWAVBuffer[WAV_HEADER_SIZE], (2 * fade_length)); /*Flawfinder: ignore*/ | ||
554 | } | ||
555 | llendianswizzle(&pcmout, 2, fade_length); | ||
556 | |||
557 | samplep = (S16 *)pcmout; | ||
558 | for (i = 0 ;i < fade_length; i++) | ||
559 | { | ||
560 | *samplep = llfloor((F32)*samplep * ((F32)i/(F32)fade_length)); | ||
561 | samplep++; | ||
562 | } | ||
563 | |||
564 | llendianswizzle(&pcmout, 2, fade_length); | ||
565 | if((WAV_HEADER_SIZE+(2 * fade_length)) < (S32)mWAVBuffer.size()) | ||
566 | { | ||
567 | memcpy(&mWAVBuffer[WAV_HEADER_SIZE], pcmout, (2 * fade_length)); /*Flawfinder: ignore*/ | ||
568 | } | ||
569 | S32 near_end = mWAVBuffer.size() - (2 * fade_length); | ||
570 | if ((S32)mWAVBuffer.size() >= ( near_end + 2* fade_length)) | ||
571 | { | ||
572 | memcpy(pcmout, &mWAVBuffer[near_end], (2 * fade_length)); /*Flawfinder: ignore*/ | ||
573 | } | ||
574 | llendianswizzle(&pcmout, 2, fade_length); | ||
575 | |||
576 | samplep = (S16 *)pcmout; | ||
577 | for (i = fade_length-1 ; i >= 0; i--) | ||
578 | { | ||
579 | *samplep = llfloor((F32)*samplep * ((F32)i/(F32)fade_length)); | ||
580 | samplep++; | ||
581 | } | ||
582 | |||
583 | llendianswizzle(&pcmout, 2, fade_length); | ||
584 | if (near_end + (2 * fade_length) < (S32)mWAVBuffer.size()) | ||
585 | { | ||
586 | memcpy(&mWAVBuffer[near_end], pcmout, (2 * fade_length));/*Flawfinder: ignore*/ | ||
587 | } | ||
588 | } | ||
589 | |||
590 | if (36 == data_length) | ||
591 | { | ||
592 | llwarns << "BAD Vorbis decode in finishDecode!" << llendl; | ||
593 | mValid = FALSE; | ||
594 | return TRUE; // we've finished | ||
595 | } | ||
596 | #if !defined(USE_WAV_VFILE) | ||
597 | mFileHandle = LLLFSThread::sLocal->write(mOutFilename, &mWAVBuffer[0], 0, data_length); | ||
598 | #endif | ||
599 | } | ||
600 | |||
601 | if (mFileHandle != LLLFSThread::nullHandle()) | ||
602 | { | ||
603 | LLLFSThread::status_t s = LLLFSThread::sLocal->getRequestStatus(mFileHandle); | ||
604 | if (s != LLLFSThread::STATUS_COMPLETE) | ||
605 | { | ||
606 | if (s != LLLFSThread::STATUS_QUEUED && s != LLLFSThread::STATUS_INPROGRESS) | ||
607 | { | ||
608 | llerrs << "Bad file status in LLVorbisDecodeState::finishDecode: " << s << llendl; | ||
609 | } | ||
610 | return FALSE; // not finished | ||
611 | } | ||
612 | else | ||
613 | { | ||
614 | LLLFSThread::Request* req = (LLLFSThread::Request*)LLLFSThread::sLocal->getRequest(mFileHandle); | ||
615 | if (req->getBytesRead() == 0) //!= req->getBytes() // should be safe, but needs testing | ||
616 | { | ||
617 | llwarns << "Unable to write file in LLVorbisDecodeState::finishDecode" << llendl; | ||
618 | mValid = FALSE; | ||
619 | return TRUE; // we've finished | ||
620 | } | ||
621 | } | ||
622 | LLLFSThread::sLocal->completeRequest(mFileHandle); | ||
623 | } | ||
624 | |||
625 | mDone = TRUE; | ||
626 | |||
627 | #if defined(USE_WAV_VFILE) | ||
628 | // write the data. | ||
629 | LLVFile output(gVFS, mUUID, LLAssetType::AT_SOUND_WAV); | ||
630 | output.write(&mWAVBuffer[0], mWAVBuffer.size()); | ||
631 | #endif | ||
632 | //llinfos << "Finished decode for " << getUUID() << llendl; | ||
633 | |||
634 | return TRUE; | ||
635 | } | ||