From c6a1b0e7432278fbbaf96304146db332148ab68e Mon Sep 17 00:00:00 2001 From: kaienfr Date: Mon, 14 Apr 2014 13:23:10 +0200 Subject: [PATCH] Provide a new method AuCtx::AuCreateCodecContextFromSource() This method can automatically read audio information from file (as channels, sample rate etc) via ffmpeg, and create accurate ffmpeg's codec context. Especially used for unknown audio format but supported by ffmpeg. --- Core/HLE/sceMp3.cpp | 5 +++ Core/HW/SimpleAudioDec.cpp | 84 +++++++++++++++++++++++++++++++++++++- Core/HW/SimpleAudioDec.h | 2 +- 3 files changed, 89 insertions(+), 2 deletions(-) diff --git a/Core/HLE/sceMp3.cpp b/Core/HLE/sceMp3.cpp index b4e56d32aa..25339506c7 100644 --- a/Core/HLE/sceMp3.cpp +++ b/Core/HLE/sceMp3.cpp @@ -326,6 +326,11 @@ int sceMp3Init(u32 mp3) { INFO_LOG(ME, "sceMp3Init(): channels=%i, samplerate=%iHz, bitrate=%ikbps", ctx->Channels, ctx->SamplingRate, ctx->BitRate); + // Read information from source via ffmpeg and re-create codec context + // This is an automatic method without knowledge in audio file format + // ctx->AuCreateCodecContextFromSource(); + // INFO_LOG(ME, "sceMp3Init() ffmpeg: channels=%i, samplerate=%iHz, bitrate=%ikbps", ctx->Channels, ctx->SamplingRate, ctx->BitRate); + // for mp3, if required freq is 48000, reset resampling Frequency to 48000 seems get better sound quality (e.g. Miku Custom BGM) if (ctx->freq == 48000){ ctx->decoder->setResampleFrequency(ctx->freq); diff --git a/Core/HW/SimpleAudioDec.cpp b/Core/HW/SimpleAudioDec.cpp index de561ece54..ca0471cada 100644 --- a/Core/HW/SimpleAudioDec.cpp +++ b/Core/HW/SimpleAudioDec.cpp @@ -458,4 +458,86 @@ int AuCtx::AuGetVersion(){ int AuCtx::AuGetFrameNum(){ return FrameNum; -} \ No newline at end of file +} + +static int _Readbuffer(void *opaque, uint8_t *buf, int buf_size) { + auto ctx = (AuCtx *)opaque; + int toread = std::min((int)ctx->AuBufSize, buf_size); + memcpy(buf, Memory::GetPointer(ctx->AuBuf), toread); + return toread; +} + +static void closeAvioCtxandFormatCtx(AVIOContext* pAVIOCtx, AVFormatContext* pFormatCtx){ + if (pAVIOCtx && pAVIOCtx->buffer) + av_free(pAVIOCtx->buffer); + if (pAVIOCtx) + av_free(pAVIOCtx); + if (pFormatCtx) + avformat_close_input(&pFormatCtx); +} + +// you need at least have initialized AuBuf, AuBufSize and decoder +bool AuCtx::AuCreateCodecContextFromSource(){ + u8* tempbuf = (u8*)av_malloc(AuBufSize); + + auto pFormatCtx = avformat_alloc_context(); + auto pAVIOCtx = avio_alloc_context(tempbuf, AuBufSize, 0, (void*)this, _Readbuffer, NULL, NULL); + pFormatCtx->pb = pAVIOCtx; + + int ret; + // Load audio buffer + if ((ret = avformat_open_input((AVFormatContext**)&pFormatCtx, NULL, NULL, NULL)) != 0) { + ERROR_LOG(ME, "avformat_open_input: Cannot open input %d", ret); + closeAvioCtxandFormatCtx(pAVIOCtx,pFormatCtx); + return false; + } + + if ((ret = avformat_find_stream_info(pFormatCtx, NULL)) < 0) { + ERROR_LOG(ME, "avformat_find_stream_info: Cannot find stream information %d", ret); + closeAvioCtxandFormatCtx(pAVIOCtx, pFormatCtx); + return false; + } + // reset decoder context + if (decoder->codecCtx_){ + avcodec_close(decoder->codecCtx_); + av_free(decoder->codecCtx_); + } + decoder->codecCtx_ = pFormatCtx->streams[ret]->codec; + + if (decoder->codec_){ + decoder->codec_ = 0; + } + // select the audio stream + ret = av_find_best_stream(pFormatCtx, AVMEDIA_TYPE_AUDIO, -1, -1, &decoder->codec_, 0); + if (ret < 0) { + if (ret == AVERROR_DECODER_NOT_FOUND) { + ERROR_LOG(HLE, "av_find_best_stream: No appropriate decoder found"); + } + else { + ERROR_LOG(HLE, "av_find_best_stream: Cannot find an audio stream in the input file %d", ret); + } + closeAvioCtxandFormatCtx(pAVIOCtx, pFormatCtx); + return false; + } + + // close and free AVIO and AVFormat + // closeAvioCtxandFormatCtx(pAVIOCtx, pFormatCtx); + + // open codec + if ((ret = avcodec_open2(decoder->codecCtx_, decoder->codec_, NULL)) < 0) { + avcodec_close(decoder->codecCtx_); + av_free(decoder->codecCtx_); + decoder->codecCtx_ = 0; + decoder->codec_ = 0; + ERROR_LOG(ME, "avcodec_open2: Cannot open audio decoder %d", ret); + return false; + } + + // set audio informations + SamplingRate = decoder->codecCtx_->sample_rate; + Channels = decoder->codecCtx_->channels; + BitRate = decoder->codecCtx_->bit_rate/1000; + freq = SamplingRate; + + return true; +} diff --git a/Core/HW/SimpleAudioDec.h b/Core/HW/SimpleAudioDec.h index 321602cc84..f636199f7e 100644 --- a/Core/HW/SimpleAudioDec.h +++ b/Core/HW/SimpleAudioDec.h @@ -63,7 +63,6 @@ public: int srcPos; // bytes consumed in source during the last decoding int wanted_resample_freq; // wanted resampling rate/frequency -private: #ifdef USE_FFMPEG AVFrame *frame_; AVCodec *codec_; @@ -178,6 +177,7 @@ public: u32 AuResetPlayPositionByFrame(int position); int AuGetVersion(); int AuGetFrameNum(); + bool AuCreateCodecContextFromSource(); void DoState(PointerWrap &p) { auto s = p.Section("AuContext", 0, 1);