CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Core/HW/SimpleAudioDec.cpp
Views: 1401
1
// Copyright (c) 2013- PPSSPP Project.
2
3
// This program is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, version 2.0 or later versions.
6
7
// This program is distributed in the hope that it will be useful,
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
// GNU General Public License 2.0 for more details.
11
12
// A copy of the GPL 2.0 should have been included with the program.
13
// If not, see http://www.gnu.org/licenses/
14
15
// Official git repository and contact information can be found at
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18
#include <algorithm>
19
#include <cmath>
20
21
#include "Common/Serialize/SerializeFuncs.h"
22
#include "Core/Config.h"
23
#include "Core/Debugger/MemBlockInfo.h"
24
#include "Core/HLE/FunctionWrappers.h"
25
#include "Core/HW/SimpleAudioDec.h"
26
#include "Core/HW/MediaEngine.h"
27
#include "Core/HW/BufferQueue.h"
28
#include "Core/HW/Atrac3Standalone.h"
29
30
#include "ext/minimp3/minimp3.h"
31
32
#ifdef USE_FFMPEG
33
34
extern "C" {
35
#include "libavformat/avformat.h"
36
#include "libswresample/swresample.h"
37
#include "libavutil/samplefmt.h"
38
#include "libavcodec/avcodec.h"
39
#include "libavutil/version.h"
40
41
#include "Core/FFMPEGCompat.h"
42
}
43
44
#else
45
46
extern "C" {
47
struct AVCodec;
48
struct AVCodecContext;
49
struct SwrContext;
50
struct AVFrame;
51
}
52
53
#endif // USE_FFMPEG
54
55
// AAC decoder candidates:
56
// * https://github.com/mstorsjo/fdk-aac/tree/master
57
58
// h.264 decoder candidates:
59
// * https://github.com/meerkat-cv/h264_decoder
60
// * https://github.com/shengbinmeng/ffmpeg-h264-dec
61
62
// minimp3-based decoder.
63
class MiniMp3Audio : public AudioDecoder {
64
public:
65
MiniMp3Audio() {
66
mp3dec_init(&mp3_);
67
}
68
~MiniMp3Audio() {}
69
70
bool Decode(const uint8_t* inbuf, int inbytes, int *inbytesConsumed, int outputChannels, int16_t *outbuf, int *outSamples) override {
71
_dbg_assert_(outputChannels == 2);
72
73
mp3dec_frame_info_t info{};
74
int samplesWritten = mp3dec_decode_frame(&mp3_, inbuf, inbytes, (mp3d_sample_t *)outbuf, &info);
75
*inbytesConsumed = info.frame_bytes;
76
*outSamples = samplesWritten;
77
return true;
78
}
79
80
bool IsOK() const override { return true; }
81
void SetChannels(int channels) override {
82
// Hmm. ignore for now.
83
}
84
85
PSPAudioType GetAudioType() const override { return PSP_CODEC_MP3; }
86
87
private:
88
// We use the lowest-level API.
89
mp3dec_t mp3_{};
90
};
91
92
// FFMPEG-based decoder. TODO: Replace with individual codecs.
93
// Based on http://ffmpeg.org/doxygen/trunk/doc_2examples_2decoding_encoding_8c-example.html#_a13
94
class FFmpegAudioDecoder : public AudioDecoder {
95
public:
96
FFmpegAudioDecoder(PSPAudioType audioType, int sampleRateHz = 44100, int channels = 2);
97
~FFmpegAudioDecoder();
98
99
bool Decode(const uint8_t* inbuf, int inbytes, int *inbytesConsumed, int outputChannels, int16_t *outbuf, int *outSamples) override;
100
bool IsOK() const override {
101
#ifdef USE_FFMPEG
102
return codec_ != 0;
103
#else
104
return 0;
105
#endif
106
}
107
108
void SetChannels(int channels) override;
109
110
// These two are only here because of save states.
111
PSPAudioType GetAudioType() const override { return audioType; }
112
113
private:
114
bool OpenCodec(int block_align);
115
116
PSPAudioType audioType;
117
int sample_rate_;
118
int channels_;
119
120
AVFrame *frame_ = nullptr;
121
AVCodec *codec_ = nullptr;
122
AVCodecContext *codecCtx_ = nullptr;
123
SwrContext *swrCtx_ = nullptr;
124
125
bool codecOpen_ = false;
126
};
127
128
AudioDecoder *CreateAudioDecoder(PSPAudioType audioType, int sampleRateHz, int channels, size_t blockAlign, const uint8_t *extraData, size_t extraDataSize) {
129
switch (audioType) {
130
case PSP_CODEC_MP3:
131
return new MiniMp3Audio();
132
case PSP_CODEC_AT3:
133
return CreateAtrac3Audio(channels, blockAlign, extraData, extraDataSize);
134
case PSP_CODEC_AT3PLUS:
135
return CreateAtrac3PlusAudio(channels, blockAlign);
136
default:
137
// Only AAC falls back to FFMPEG now.
138
return new FFmpegAudioDecoder(audioType, sampleRateHz, channels);
139
}
140
}
141
142
static int GetAudioCodecID(int audioType) {
143
#ifdef USE_FFMPEG
144
switch (audioType) {
145
case PSP_CODEC_AAC:
146
return AV_CODEC_ID_AAC;
147
case PSP_CODEC_AT3:
148
return AV_CODEC_ID_ATRAC3;
149
case PSP_CODEC_AT3PLUS:
150
return AV_CODEC_ID_ATRAC3P;
151
case PSP_CODEC_MP3:
152
return AV_CODEC_ID_MP3;
153
default:
154
return AV_CODEC_ID_NONE;
155
}
156
#else
157
return 0;
158
#endif // USE_FFMPEG
159
}
160
161
FFmpegAudioDecoder::FFmpegAudioDecoder(PSPAudioType audioType, int sampleRateHz, int channels)
162
: audioType(audioType), sample_rate_(sampleRateHz), channels_(channels) {
163
164
#ifdef USE_FFMPEG
165
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 18, 100)
166
avcodec_register_all();
167
#endif
168
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 12, 100)
169
av_register_all();
170
#endif
171
InitFFmpeg();
172
173
frame_ = av_frame_alloc();
174
175
// Get AUDIO Codec ctx
176
int audioCodecId = GetAudioCodecID(audioType);
177
if (!audioCodecId) {
178
ERROR_LOG(Log::ME, "This version of FFMPEG does not support Audio codec type: %08x. Update your submodule.", audioType);
179
return;
180
}
181
// Find decoder
182
codec_ = avcodec_find_decoder((AVCodecID)audioCodecId);
183
if (!codec_) {
184
// Eh, we shouldn't even have managed to compile. But meh.
185
ERROR_LOG(Log::ME, "This version of FFMPEG does not support AV_CODEC_ctx for audio (%s). Update your submodule.", GetCodecName(audioType));
186
return;
187
}
188
// Allocate codec context
189
codecCtx_ = avcodec_alloc_context3(codec_);
190
if (!codecCtx_) {
191
ERROR_LOG(Log::ME, "Failed to allocate a codec context");
192
return;
193
}
194
codecCtx_->channels = channels_;
195
codecCtx_->channel_layout = channels_ == 2 ? AV_CH_LAYOUT_STEREO : AV_CH_LAYOUT_MONO;
196
codecCtx_->sample_rate = sample_rate_;
197
codecOpen_ = false;
198
#endif // USE_FFMPEG
199
}
200
201
bool FFmpegAudioDecoder::OpenCodec(int block_align) {
202
#ifdef USE_FFMPEG
203
// Some versions of FFmpeg require this set. May be set in SetExtraData(), but optional.
204
// When decoding, we decode by packet, so we know the size.
205
if (codecCtx_->block_align == 0) {
206
codecCtx_->block_align = block_align;
207
}
208
209
AVDictionary *opts = 0;
210
int retval = avcodec_open2(codecCtx_, codec_, &opts);
211
if (retval < 0) {
212
ERROR_LOG(Log::ME, "Failed to open codec: retval = %i", retval);
213
}
214
av_dict_free(&opts);
215
codecOpen_ = true;
216
return retval >= 0;
217
#else
218
return false;
219
#endif // USE_FFMPEG
220
}
221
222
void FFmpegAudioDecoder::SetChannels(int channels) {
223
if (channels_ == channels) {
224
// Do nothing, already set.
225
return;
226
}
227
#ifdef USE_FFMPEG
228
229
if (codecOpen_) {
230
ERROR_LOG(Log::ME, "Codec already open, cannot change channels");
231
} else {
232
channels_ = channels;
233
codecCtx_->channels = channels_;
234
codecCtx_->channel_layout = channels_ == 2 ? AV_CH_LAYOUT_STEREO : AV_CH_LAYOUT_MONO;
235
}
236
#endif
237
}
238
239
FFmpegAudioDecoder::~FFmpegAudioDecoder() {
240
#ifdef USE_FFMPEG
241
swr_free(&swrCtx_);
242
av_frame_free(&frame_);
243
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 52, 0)
244
avcodec_free_context(&codecCtx_);
245
#else
246
// Future versions may add other things to free, but avcodec_free_context didn't exist yet here.
247
avcodec_close(codecCtx_);
248
av_freep(&codecCtx_->extradata);
249
av_freep(&codecCtx_->subtitle_header);
250
av_freep(&codecCtx_);
251
#endif
252
codec_ = 0;
253
#endif // USE_FFMPEG
254
}
255
256
// Decodes a single input frame.
257
bool FFmpegAudioDecoder::Decode(const uint8_t *inbuf, int inbytes, int *inbytesConsumed, int outputChannels, int16_t *outbuf, int *outSamples) {
258
#ifdef USE_FFMPEG
259
if (!codecOpen_) {
260
OpenCodec(inbytes);
261
}
262
263
AVPacket packet;
264
av_init_packet(&packet);
265
packet.data = (uint8_t *)(inbuf);
266
packet.size = inbytes;
267
268
int got_frame = 0;
269
av_frame_unref(frame_);
270
271
if (outSamples) {
272
*outSamples = 0;
273
}
274
if (inbytesConsumed) {
275
*inbytesConsumed = 0;
276
}
277
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
278
if (inbytes != 0) {
279
int err = avcodec_send_packet(codecCtx_, &packet);
280
if (err < 0) {
281
ERROR_LOG(Log::ME, "Error sending audio frame to decoder (%d bytes): %d (%08x)", inbytes, err, err);
282
return false;
283
}
284
}
285
int err = avcodec_receive_frame(codecCtx_, frame_);
286
int len = 0;
287
if (err >= 0) {
288
len = frame_->pkt_size;
289
got_frame = 1;
290
} else if (err != AVERROR(EAGAIN)) {
291
len = err;
292
}
293
#else
294
int len = avcodec_decode_audio4(codecCtx_, frame_, &got_frame, &packet);
295
#endif
296
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 12, 100)
297
av_packet_unref(&packet);
298
#else
299
av_free_packet(&packet);
300
#endif
301
302
if (len < 0) {
303
ERROR_LOG(Log::ME, "Error decoding Audio frame (%i bytes): %i (%08x)", inbytes, len, len);
304
return false;
305
}
306
307
// get bytes consumed in source
308
*inbytesConsumed = len;
309
310
if (got_frame) {
311
// Initializing the sample rate convert. We will use it to convert float output into int.
312
_dbg_assert_(outputChannels == 2);
313
int64_t wanted_channel_layout = AV_CH_LAYOUT_STEREO; // we want stereo output layout
314
int64_t dec_channel_layout = frame_->channel_layout; // decoded channel layout
315
316
if (!swrCtx_) {
317
swrCtx_ = swr_alloc_set_opts(
318
swrCtx_,
319
wanted_channel_layout,
320
AV_SAMPLE_FMT_S16,
321
codecCtx_->sample_rate,
322
dec_channel_layout,
323
codecCtx_->sample_fmt,
324
codecCtx_->sample_rate,
325
0,
326
NULL);
327
328
if (!swrCtx_ || swr_init(swrCtx_) < 0) {
329
ERROR_LOG(Log::ME, "swr_init: Failed to initialize the resampling context");
330
avcodec_close(codecCtx_);
331
codec_ = 0;
332
return false;
333
}
334
}
335
336
// convert audio to AV_SAMPLE_FMT_S16
337
int swrRet = 0;
338
if (outbuf != nullptr) {
339
swrRet = swr_convert(swrCtx_, (uint8_t **)&outbuf, frame_->nb_samples, (const u8 **)frame_->extended_data, frame_->nb_samples);
340
}
341
if (swrRet < 0) {
342
ERROR_LOG(Log::ME, "swr_convert: Error while converting: %d", swrRet);
343
return false;
344
}
345
// output stereo samples per frame
346
*outSamples = swrRet;
347
348
// Save outbuf into pcm audio, you can uncomment this line to save and check the decoded audio into pcm file.
349
// SaveAudio("dump.pcm", outbuf, *outbytes);
350
}
351
return true;
352
#else
353
// Zero bytes output. No need to memset.
354
*outbytes = 0;
355
return true;
356
#endif // USE_FFMPEG
357
}
358
359
void AudioClose(AudioDecoder **ctx) {
360
#ifdef USE_FFMPEG
361
delete *ctx;
362
*ctx = 0;
363
#endif // USE_FFMPEG
364
}
365
366
void AudioClose(FFmpegAudioDecoder **ctx) {
367
#ifdef USE_FFMPEG
368
delete *ctx;
369
*ctx = 0;
370
#endif // USE_FFMPEG
371
}
372
373
static const char *const codecNames[4] = {
374
"AT3+", "AT3", "MP3", "AAC",
375
};
376
377
const char *GetCodecName(int codec) {
378
if (codec >= PSP_CODEC_AT3PLUS && codec <= PSP_CODEC_AAC) {
379
return codecNames[codec - PSP_CODEC_AT3PLUS];
380
} else {
381
return "(unk)";
382
}
383
};
384
385
bool IsValidCodec(PSPAudioType codec){
386
if (codec >= PSP_CODEC_AT3PLUS && codec <= PSP_CODEC_AAC) {
387
return true;
388
}
389
return false;
390
}
391
392
393
// sceAu module starts from here
394
395
AuCtx::AuCtx() {
396
}
397
398
AuCtx::~AuCtx() {
399
if (decoder) {
400
AudioClose(&decoder);
401
decoder = nullptr;
402
}
403
}
404
405
size_t AuCtx::FindNextMp3Sync() {
406
for (size_t i = 0; i < sourcebuff.size() - 2; ++i) {
407
if ((sourcebuff[i] & 0xFF) == 0xFF && (sourcebuff[i + 1] & 0xC0) == 0xC0) {
408
return i;
409
}
410
}
411
return 0;
412
}
413
414
// return output pcm size, <0 error
415
u32 AuCtx::AuDecode(u32 pcmAddr) {
416
u32 outptr = PCMBuf + nextOutputHalf * PCMBufSize / 2;
417
auto outbuf = Memory::GetPointerWriteRange(outptr, PCMBufSize / 2);
418
int outpcmbufsize = 0;
419
420
if (pcmAddr)
421
Memory::Write_U32(outptr, pcmAddr);
422
423
// Decode a single frame in sourcebuff and output into PCMBuf.
424
if (!sourcebuff.empty()) {
425
// FFmpeg doesn't seem to search for a sync for us, so let's do that.
426
int nextSync = 0;
427
if (decoder->GetAudioType() == PSP_CODEC_MP3) {
428
nextSync = (int)FindNextMp3Sync();
429
}
430
int inbytesConsumed = 0;
431
int outSamples = 0;
432
decoder->Decode(&sourcebuff[nextSync], (int)sourcebuff.size() - nextSync, &inbytesConsumed, 2, (int16_t *)outbuf, &outSamples);
433
outpcmbufsize = outSamples * 2 * sizeof(int16_t);
434
435
if (outpcmbufsize == 0) {
436
// Nothing was output, hopefully we're at the end of the stream.
437
AuBufAvailable = 0;
438
sourcebuff.clear();
439
} else {
440
// Update our total decoded samples, but don't count stereo.
441
SumDecodedSamples += outSamples;
442
// get consumed source length
443
int srcPos = inbytesConsumed + nextSync;
444
// remove the consumed source
445
if (srcPos > 0)
446
sourcebuff.erase(sourcebuff.begin(), sourcebuff.begin() + srcPos);
447
// reduce the available Aubuff size
448
// (the available buff size is now used to know if we can read again from file and how many to read)
449
AuBufAvailable -= srcPos;
450
}
451
}
452
453
bool end = readPos - AuBufAvailable >= (int64_t)endPos;
454
if (end && LoopNum != 0) {
455
// When looping, start the sum back off at zero and reset readPos to the start.
456
SumDecodedSamples = 0;
457
readPos = startPos;
458
if (LoopNum > 0)
459
LoopNum--;
460
}
461
462
if (outpcmbufsize == 0 && !end) {
463
// If we didn't decode anything, we fill this half of the buffer with zeros.
464
outpcmbufsize = PCMBufSize / 2;
465
if (outbuf != nullptr)
466
memset(outbuf, 0, outpcmbufsize);
467
} else if ((u32)outpcmbufsize < PCMBufSize) {
468
// TODO: Not sure it actually zeros this out.
469
if (outbuf != nullptr)
470
memset(outbuf + outpcmbufsize, 0, PCMBufSize / 2 - outpcmbufsize);
471
}
472
473
if (outpcmbufsize != 0)
474
NotifyMemInfo(MemBlockFlags::WRITE, outptr, outpcmbufsize, "AuDecode");
475
476
nextOutputHalf ^= 1;
477
return outpcmbufsize;
478
}
479
480
// return 1 to read more data stream, 0 don't read
481
int AuCtx::AuCheckStreamDataNeeded() {
482
// If we would ask for bytes, then some are needed.
483
if (AuStreamBytesNeeded() > 0) {
484
return 1;
485
}
486
return 0;
487
}
488
489
int AuCtx::AuStreamBytesNeeded() {
490
if (decoder->GetAudioType() == PSP_CODEC_MP3) {
491
// The endPos and readPos are not considered, except when you've read to the end.
492
if (readPos >= endPos)
493
return 0;
494
// Account for the workarea.
495
int offset = AuStreamWorkareaSize();
496
return (int)AuBufSize - AuBufAvailable - offset;
497
}
498
499
// TODO: Untested. Maybe similar to MP3.
500
return std::min((int)AuBufSize - AuBufAvailable, (int)endPos - readPos);
501
}
502
503
int AuCtx::AuStreamWorkareaSize() {
504
// Note that this is 31 bytes more than the max layer 3 frame size.
505
if (decoder->GetAudioType() == PSP_CODEC_MP3)
506
return 0x05c0;
507
return 0;
508
}
509
510
// check how many bytes we have read from source file
511
u32 AuCtx::AuNotifyAddStreamData(int size) {
512
int offset = AuStreamWorkareaSize();
513
514
if (askedReadSize != 0) {
515
// Old save state, numbers already adjusted.
516
int diffsize = size - askedReadSize;
517
// Notify the real read size
518
if (diffsize != 0) {
519
readPos += diffsize;
520
AuBufAvailable += diffsize;
521
}
522
askedReadSize = 0;
523
} else {
524
readPos += size;
525
AuBufAvailable += size;
526
}
527
528
if (Memory::IsValidRange(AuBuf, size)) {
529
sourcebuff.resize(sourcebuff.size() + size);
530
Memory::MemcpyUnchecked(&sourcebuff[sourcebuff.size() - size], AuBuf + offset, size);
531
}
532
533
return 0;
534
}
535
536
// read from stream position srcPos of size bytes into buff
537
// buff, size and srcPos are all pointers
538
u32 AuCtx::AuGetInfoToAddStreamData(u32 bufPtr, u32 sizePtr, u32 srcPosPtr) {
539
int readsize = AuStreamBytesNeeded();
540
int offset = AuStreamWorkareaSize();
541
542
// we can recharge AuBuf from its beginning
543
if (readsize != 0) {
544
if (Memory::IsValidAddress(bufPtr))
545
Memory::WriteUnchecked_U32(AuBuf + offset, bufPtr);
546
if (Memory::IsValidAddress(sizePtr))
547
Memory::WriteUnchecked_U32(readsize, sizePtr);
548
if (Memory::IsValidAddress(srcPosPtr))
549
Memory::WriteUnchecked_U32(readPos, srcPosPtr);
550
} else {
551
if (Memory::IsValidAddress(bufPtr))
552
Memory::WriteUnchecked_U32(0, bufPtr);
553
if (Memory::IsValidAddress(sizePtr))
554
Memory::WriteUnchecked_U32(0, sizePtr);
555
if (Memory::IsValidAddress(srcPosPtr))
556
Memory::WriteUnchecked_U32(0, srcPosPtr);
557
}
558
559
// Just for old save states.
560
askedReadSize = 0;
561
return 0;
562
}
563
564
u32 AuCtx::AuResetPlayPositionByFrame(int frame) {
565
// Note: this doesn't correctly handle padding or slot size, but the PSP doesn't either.
566
uint32_t bytesPerSecond = (MaxOutputSample / 8) * BitRate * 1000;
567
readPos = startPos + (frame * bytesPerSecond) / SamplingRate;
568
// Not sure why, but it seems to consistently seek 1 before, maybe in case it's off slightly.
569
if (frame != 0)
570
readPos -= 1;
571
SumDecodedSamples = frame * MaxOutputSample;
572
AuBufAvailable = 0;
573
sourcebuff.clear();
574
return 0;
575
}
576
577
u32 AuCtx::AuResetPlayPosition() {
578
readPos = startPos;
579
SumDecodedSamples = 0;
580
AuBufAvailable = 0;
581
sourcebuff.clear();
582
return 0;
583
}
584
585
void AuCtx::DoState(PointerWrap &p) {
586
auto s = p.Section("AuContext", 0, 2);
587
if (!s)
588
return;
589
590
Do(p, startPos);
591
Do(p, endPos);
592
Do(p, AuBuf);
593
Do(p, AuBufSize);
594
Do(p, PCMBuf);
595
Do(p, PCMBufSize);
596
Do(p, freq);
597
Do(p, SumDecodedSamples);
598
Do(p, LoopNum);
599
Do(p, Channels);
600
Do(p, MaxOutputSample);
601
Do(p, readPos);
602
int audioType = decoder ? (int)decoder->GetAudioType() : 0;
603
Do(p, audioType);
604
Do(p, BitRate);
605
Do(p, SamplingRate);
606
Do(p, askedReadSize);
607
int dummy = 0;
608
Do(p, dummy);
609
Do(p, FrameNum);
610
611
if (s < 2) {
612
AuBufAvailable = 0;
613
Version = 3;
614
} else {
615
Do(p, Version);
616
Do(p, AuBufAvailable);
617
Do(p, sourcebuff);
618
Do(p, nextOutputHalf);
619
}
620
621
if (p.mode == p.MODE_READ) {
622
decoder = CreateAudioDecoder((PSPAudioType)audioType);
623
}
624
}
625
626