Skip to content

Commit

Permalink
ajm mp3: fix resampling (shadps4-emu#1500)
Browse files Browse the repository at this point in the history
  • Loading branch information
vladmikhalin authored and fpiesche committed Nov 12, 2024
1 parent c07322a commit 5ed69b6
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 18 deletions.
40 changes: 22 additions & 18 deletions src/core/libraries/ajm/ajm_mp3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ static constexpr std::array<std::array<s32, 15>, 2> BitrateTable = {{

static constexpr std::array<s32, 2> UnkTable = {0x48, 0x90};

SwrContext* swr_context{};

static AVSampleFormat AjmToAVSampleFormat(AjmFormatEncoding format) {
switch (format) {
case AjmFormatEncoding::S16:
Expand All @@ -49,26 +47,28 @@ AVFrame* AjmMp3Decoder::ConvertAudioFrame(AVFrame* frame) {
return frame;
}

auto pcm16_frame = av_frame_clone(frame);
pcm16_frame->format = format;
AVFrame* new_frame = av_frame_alloc();
new_frame->pts = frame->pts;
new_frame->pkt_dts = frame->pkt_dts < 0 ? 0 : frame->pkt_dts;
new_frame->format = format;
new_frame->ch_layout = frame->ch_layout;
new_frame->sample_rate = frame->sample_rate;

if (swr_context) {
swr_free(&swr_context);
swr_context = nullptr;
}
AVChannelLayout in_ch_layout = frame->ch_layout;
AVChannelLayout out_ch_layout = pcm16_frame->ch_layout;
swr_alloc_set_opts2(&swr_context, &out_ch_layout, AVSampleFormat(pcm16_frame->format),
AVChannelLayout out_ch_layout = new_frame->ch_layout;
swr_alloc_set_opts2(&m_swr_context, &out_ch_layout, AVSampleFormat(new_frame->format),
frame->sample_rate, &in_ch_layout, AVSampleFormat(frame->format),
frame->sample_rate, 0, nullptr);
swr_init(swr_context);
const auto res = swr_convert_frame(swr_context, pcm16_frame, frame);
swr_init(m_swr_context);
const auto res = swr_convert_frame(m_swr_context, new_frame, frame);
if (res < 0) {
LOG_ERROR(Lib_AvPlayer, "Could not convert to S16: {}", av_err2str(res));
av_frame_free(&new_frame);
av_frame_free(&frame);
return nullptr;
}
av_frame_free(&frame);
return pcm16_frame;
return new_frame;
}

AjmMp3Decoder::AjmMp3Decoder(AjmFormatEncoding format)
Expand All @@ -78,6 +78,7 @@ AjmMp3Decoder::AjmMp3Decoder(AjmFormatEncoding format)
}

AjmMp3Decoder::~AjmMp3Decoder() {
swr_free(&m_swr_context);
avcodec_free_context(&m_codec_context);
}

Expand Down Expand Up @@ -108,6 +109,11 @@ std::tuple<u32, u32> AjmMp3Decoder::ProcessData(std::span<u8>& in_buf, SparseOut
u32 frames_decoded = 0;
u32 samples_decoded = 0;

auto max_samples =
max_samples_per_channel.has_value()
? max_samples_per_channel.value() * m_codec_context->ch_layout.nb_channels
: std::numeric_limits<u32>::max();

if (pkt->size) {
// Send the packet with the compressed data to the decoder
pkt->pts = m_parser->pts;
Expand All @@ -121,6 +127,7 @@ std::tuple<u32, u32> AjmMp3Decoder::ProcessData(std::span<u8>& in_buf, SparseOut
AVFrame* frame = av_frame_alloc();
ret = avcodec_receive_frame(m_codec_context, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
av_frame_free(&frame);
break;
} else if (ret < 0) {
UNREACHABLE_MSG("Error during decoding");
Expand All @@ -135,11 +142,6 @@ std::tuple<u32, u32> AjmMp3Decoder::ProcessData(std::span<u8>& in_buf, SparseOut
gapless.skipped_samples += skipped_samples;
}

const auto max_samples =
max_samples_per_channel.has_value()
? max_samples_per_channel.value() * frame->ch_layout.nb_channels
: std::numeric_limits<u32>::max();

switch (m_format) {
case AjmFormatEncoding::S16:
samples_decoded +=
Expand All @@ -157,6 +159,8 @@ std::tuple<u32, u32> AjmMp3Decoder::ProcessData(std::span<u8>& in_buf, SparseOut
UNREACHABLE();
}

max_samples -= samples_decoded;

av_frame_free(&frame);
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/core/libraries/ajm/ajm_mp3.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

extern "C" {
#include <libavcodec/avcodec.h>
struct SwrContext;
}

namespace Libraries::Ajm {
Expand Down Expand Up @@ -82,6 +83,7 @@ class AjmMp3Decoder : public AjmCodec {
const AVCodec* m_codec = nullptr;
AVCodecContext* m_codec_context = nullptr;
AVCodecParserContext* m_parser = nullptr;
SwrContext* m_swr_context = nullptr;
};

} // namespace Libraries::Ajm

0 comments on commit 5ed69b6

Please sign in to comment.