mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-01-04 06:06:00 +00:00
ajm: Attempt to add gapless support
This commit is contained in:
parent
32f5dafaf7
commit
18c883d8b2
|
@ -1,15 +1,16 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <numeric>
|
||||
#include <semaphore>
|
||||
#include <boost/container/small_vector.hpp>
|
||||
#include <magic_enum.hpp>
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "core/libraries/ajm/ajm.h"
|
||||
#include "core/libraries/ajm/ajm_at9.h"
|
||||
#include "core/libraries/ajm/ajm_error.h"
|
||||
|
@ -40,9 +41,7 @@ struct BatchInfo {
|
|||
u16 instance{};
|
||||
u16 offset_in_qwords{}; // Needed for AjmBatchError?
|
||||
bool waiting{};
|
||||
bool finished{};
|
||||
std::mutex mtx;
|
||||
std::condition_variable cv;
|
||||
std::binary_semaphore finished{0};
|
||||
int result{};
|
||||
};
|
||||
|
||||
|
@ -377,11 +376,11 @@ int PS4_SYSV_ABI sceAjmBatchStartBuffer(u32 context, const u8* batch, u32 batch_
|
|||
// Perform operation requested by control flags.
|
||||
const auto control_flags = job_flags.value().control_flags;
|
||||
if (True(control_flags & AjmJobControlFlags::Reset)) {
|
||||
LOG_TRACE(Lib_Ajm, "Resetting instance {}", instance);
|
||||
LOG_INFO(Lib_Ajm, "Resetting instance {}", instance);
|
||||
p_instance->Reset();
|
||||
}
|
||||
if (True(control_flags & AjmJobControlFlags::Initialize)) {
|
||||
LOG_TRACE(Lib_Ajm, "Initializing instance {}", instance);
|
||||
LOG_INFO(Lib_Ajm, "Initializing instance {}", instance);
|
||||
ASSERT_MSG(input_control_buffer.has_value(),
|
||||
"Initialize called without control buffer");
|
||||
const auto& in_buffer = input_control_buffer.value();
|
||||
|
@ -417,6 +416,17 @@ int PS4_SYSV_ABI sceAjmBatchStartBuffer(u32 context, const u8* batch, u32 batch_
|
|||
if (True(sideband_flags & AjmJobSidebandFlags::GaplessDecode)) {
|
||||
LOG_ERROR(Lib_Ajm, "SIDEBAND_GAPLESS_DECODE is not implemented");
|
||||
p_gapless_decode = &AjmBufferExtract<AjmSidebandGaplessDecode>(p_sideband);
|
||||
if (input_control_buffer) {
|
||||
memcpy(&p_instance->gapless, input_control_buffer->p_address,
|
||||
sizeof(AjmSidebandGaplessDecode));
|
||||
LOG_INFO(Lib_Ajm,
|
||||
"Setting gapless params instance = {}, total_samples = {}, "
|
||||
"skip_samples = {}",
|
||||
instance, p_instance->gapless.total_samples,
|
||||
p_instance->gapless.skip_samples);
|
||||
} else {
|
||||
LOG_ERROR(Lib_Ajm, "Requesting gapless structure!");
|
||||
}
|
||||
*p_gapless_decode = AjmSidebandGaplessDecode{};
|
||||
}
|
||||
const auto run_flags = job_flags.value().run_flags;
|
||||
|
@ -461,7 +471,7 @@ int PS4_SYSV_ABI sceAjmBatchStartBuffer(u32 context, const u8* batch, u32 batch_
|
|||
p_result->internal_result = 0;
|
||||
}
|
||||
|
||||
batch_info->finished = true;
|
||||
batch_info->finished.release();
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
@ -480,14 +490,14 @@ int PS4_SYSV_ABI sceAjmBatchWait(const u32 context, const u32 batch_id, const u3
|
|||
if (batch->waiting) {
|
||||
return ORBIS_AJM_ERROR_BUSY;
|
||||
}
|
||||
batch->waiting = true;
|
||||
|
||||
{
|
||||
std::unique_lock lk{batch->mtx};
|
||||
if (!batch->cv.wait_for(lk, std::chrono::milliseconds(timeout),
|
||||
[&] { return batch->finished; })) {
|
||||
return ORBIS_AJM_ERROR_IN_PROGRESS;
|
||||
}
|
||||
batch->waiting = true;
|
||||
SCOPE_EXIT {
|
||||
batch->waiting = false;
|
||||
};
|
||||
|
||||
if (!batch->finished.try_acquire_for(std::chrono::milliseconds(timeout))) {
|
||||
return ORBIS_AJM_ERROR_IN_PROGRESS;
|
||||
}
|
||||
|
||||
dev->batches.erase(dev->batches.begin() + batch_id);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <vector>
|
||||
#include <fmt/format.h>
|
||||
#include "common/assert.h"
|
||||
#include "core/libraries/ajm/ajm_at9.h"
|
||||
|
@ -25,17 +26,25 @@ AjmAt9Decoder::~AjmAt9Decoder() {
|
|||
}
|
||||
|
||||
void AjmAt9Decoder::Reset() {
|
||||
num_frames = 0;
|
||||
decoded_samples = 0;
|
||||
gapless = {};
|
||||
|
||||
Atrac9ReleaseHandle(handle);
|
||||
handle = Atrac9GetHandle();
|
||||
Atrac9InitDecoder(handle, config_data);
|
||||
|
||||
Atrac9CodecInfo codec_info;
|
||||
Atrac9GetCodecInfo(handle, &codec_info);
|
||||
bytes_remain = codec_info.superframeSize;
|
||||
}
|
||||
|
||||
void AjmAt9Decoder::Initialize(const void* buffer, u32 buffer_size) {
|
||||
Atrac9ReleaseHandle(handle);
|
||||
handle = Atrac9GetHandle();
|
||||
ASSERT_MSG(buffer_size == sizeof(AjmDecAt9InitializeParameters),
|
||||
"Incorrect At9 initialization buffer size {}", buffer_size);
|
||||
const auto params = reinterpret_cast<const AjmDecAt9InitializeParameters*>(buffer);
|
||||
std::memcpy(config_data, params->config_data, SCE_AT9_CONFIG_DATA_SIZE);
|
||||
Atrac9InitDecoder(handle, config_data);
|
||||
AjmAt9Decoder::Reset();
|
||||
}
|
||||
|
||||
void AjmAt9Decoder::GetCodecInfo(void* out_info) {
|
||||
|
@ -51,36 +60,48 @@ void AjmAt9Decoder::GetCodecInfo(void* out_info) {
|
|||
|
||||
std::tuple<u32, u32, u32> AjmAt9Decoder::Decode(const u8* in_buf, u32 in_size, u8* out_buf,
|
||||
u32 out_size) {
|
||||
if (in_size <= 0 || out_size <= 0) {
|
||||
return std::tuple(in_size, out_size, 0);
|
||||
}
|
||||
|
||||
const auto decoder_handle = static_cast<Atrac9Handle*>(handle);
|
||||
Atrac9CodecInfo codec_info;
|
||||
Atrac9GetCodecInfo(handle, &codec_info);
|
||||
|
||||
int bytes_used = 0;
|
||||
int frame_count = 0;
|
||||
int bytes_remain = codec_info.superframeSize;
|
||||
|
||||
const auto ShouldDecode = [&] {
|
||||
if (in_size <= 0 || out_size <= 0) {
|
||||
return false;
|
||||
}
|
||||
if (gapless.total_samples != 0 && gapless.total_samples < decoded_samples) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const auto written_size = codec_info.channels * codec_info.frameSamples * sizeof(u16);
|
||||
for (frame_count = 0;
|
||||
frame_count < decoder_handle->Config.FramesPerSuperframe && in_size > 0 && out_size > 0;
|
||||
frame_count++) {
|
||||
u32 ret = Atrac9Decode(decoder_handle, in_buf, (short*)out_buf, &bytes_used);
|
||||
std::vector<s16> pcm_buffer(written_size >> 1);
|
||||
while (ShouldDecode()) {
|
||||
u32 ret = Atrac9Decode(decoder_handle, in_buf, pcm_buffer.data(), &bytes_used);
|
||||
ASSERT_MSG(ret == At9Status::ERR_SUCCESS, "Atrac9Decode failed ret = {:#x}", ret);
|
||||
in_buf += bytes_used;
|
||||
in_size -= bytes_used;
|
||||
num_frames++;
|
||||
bytes_remain -= bytes_used;
|
||||
out_buf += written_size;
|
||||
out_size -= written_size;
|
||||
decoded_samples += decoder_handle->Config.FrameSamples;
|
||||
if (gapless.skip_samples != 0) {
|
||||
gapless.skip_samples -= decoder_handle->Config.FrameSamples;
|
||||
} else {
|
||||
memcpy(out_buf, pcm_buffer.data(), written_size);
|
||||
out_buf += written_size;
|
||||
out_size -= written_size;
|
||||
decoded_samples += decoder_handle->Config.FrameSamples;
|
||||
}
|
||||
if ((num_frames % codec_info.framesInSuperframe) == 0) {
|
||||
in_buf += bytes_remain;
|
||||
in_size -= bytes_remain;
|
||||
bytes_remain = codec_info.superframeSize;
|
||||
}
|
||||
}
|
||||
|
||||
in_size -= bytes_remain;
|
||||
|
||||
LOG_TRACE(Lib_Ajm, "Decoded {} samples, frame count: {}", decoded_samples, frame_count);
|
||||
return std::tuple(in_size, out_size, frame_count);
|
||||
LOG_TRACE(Lib_Ajm, "Decoded {} samples, frame count: {}", decoded_samples, frame_index);
|
||||
return std::tuple(in_size, out_size, num_frames);
|
||||
}
|
||||
|
||||
} // namespace Libraries::Ajm
|
||||
|
|
|
@ -62,10 +62,13 @@ struct AjmSidebandGaplessDecode {
|
|||
|
||||
struct AjmInstance {
|
||||
AjmCodecType codec_type;
|
||||
u32 decoded_samples{};
|
||||
AjmFormatEncoding fmt{};
|
||||
u32 num_channels{};
|
||||
u32 index{};
|
||||
u32 bytes_remain{};
|
||||
u32 num_frames{};
|
||||
u32 decoded_samples{};
|
||||
AjmSidebandGaplessDecode gapless{};
|
||||
|
||||
explicit AjmInstance() = default;
|
||||
virtual ~AjmInstance() = default;
|
||||
|
|
|
@ -74,11 +74,11 @@ void AjmMp3Decoder::Reset() {
|
|||
int ret = avcodec_open2(c, codec, nullptr);
|
||||
ASSERT_MSG(ret >= 0, "Could not open codec");
|
||||
decoded_samples = 0;
|
||||
num_frames = 0;
|
||||
}
|
||||
|
||||
std::tuple<u32, u32, u32> AjmMp3Decoder::Decode(const u8* buf, u32 in_size, u8* out_buf,
|
||||
u32 out_size) {
|
||||
u32 num_frames = 0;
|
||||
AVPacket* pkt = av_packet_alloc();
|
||||
while (in_size > 0 && out_size > 0) {
|
||||
int ret = av_parser_parse2(parser, c, &pkt->data, &pkt->size, buf, in_size, AV_NOPTS_VALUE,
|
||||
|
|
|
@ -582,7 +582,7 @@ int PS4_SYSV_ABI sceHttpUriUnescape() {
|
|||
}
|
||||
|
||||
int PS4_SYSV_ABI sceHttpWaitRequest() {
|
||||
LOG_ERROR(Lib_Http, "(STUBBED) called");
|
||||
// LOG_ERROR(Lib_Http, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue