mirror of
https://github.com/RPCSX/rpcsx.git
synced 2025-12-06 07:12:14 +01:00
rpcsx: simplify and correct reset for ajm at9
This commit is contained in:
parent
c2fa3895a1
commit
e45eabc7d8
|
|
@ -7,7 +7,9 @@
|
|||
#include "orbis/thread/Thread.hpp"
|
||||
#include "orbis/utils/Logs.hpp"
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <rx/atScopeExit.hpp>
|
||||
#include <rx/hexdump.hpp>
|
||||
extern "C" {
|
||||
|
|
@ -24,15 +26,25 @@ extern "C" {
|
|||
|
||||
struct AjmFile : orbis::File {};
|
||||
|
||||
namespace ajm {
|
||||
orbis::uint32_t batchId = 1;
|
||||
struct AjmDevice : IoDevice {
|
||||
// TODO: remove when moving input and temp buffers to instance
|
||||
orbis::shared_mutex mtx;
|
||||
// TODO: move to intsance
|
||||
orbis::kvector<std::byte> inputBuffer;
|
||||
orbis::uint32_t inputSize = 0;
|
||||
orbis::kvector<std::byte> tempBuffer;
|
||||
|
||||
orbis::uint32_t at9InstanceId = 0;
|
||||
orbis::uint32_t mp3InstanceId = 0;
|
||||
orbis::uint32_t aacInstanceId = 0;
|
||||
orbis::uint32_t unimplementedInstanceId = 0;
|
||||
orbis::kmap<orbis::int32_t, Instance> instanceMap;
|
||||
} // namespace ajm
|
||||
orbis::uint32_t batchId = 1; // temp
|
||||
|
||||
orbis::uint32_t at9InstanceId = 0;
|
||||
orbis::uint32_t mp3InstanceId = 0;
|
||||
orbis::uint32_t aacInstanceId = 0;
|
||||
orbis::uint32_t unimplementedInstanceId = 0;
|
||||
orbis::kmap<orbis::int32_t, Instance> instanceMap;
|
||||
orbis::ErrorCode open(orbis::Ref<orbis::File> *file, const char *path,
|
||||
std::uint32_t flags, std::uint32_t mode,
|
||||
orbis::Thread *thread) override;
|
||||
};
|
||||
|
||||
AVSampleFormat ajmToAvFormat(AJMFormat ajmFormat) {
|
||||
switch (ajmFormat) {
|
||||
|
|
@ -47,9 +59,49 @@ AVSampleFormat ajmToAvFormat(AJMFormat ajmFormat) {
|
|||
}
|
||||
}
|
||||
|
||||
void reset(Instance *instance) {
|
||||
instance->gapless.skipSamples = 0;
|
||||
instance->gapless.totalSamples = 0;
|
||||
instance->gapless.totalSkippedSamples = 0;
|
||||
instance->processedSamples = 0;
|
||||
}
|
||||
|
||||
void resetAt9(Instance *instance) {
|
||||
if (instance->at9.configData) {
|
||||
Atrac9ReleaseHandle(instance->at9.handle);
|
||||
instance->at9.estimatedSizeUsed = 0;
|
||||
instance->at9.superFrameSize = 0;
|
||||
instance->at9.framesInSuperframe = 0;
|
||||
instance->at9.frameSamples = 0;
|
||||
instance->at9.sampleRate = 0;
|
||||
instance->at9.superFrameDataIdx = 0;
|
||||
instance->at9.inputChannels = 0;
|
||||
instance->at9.superFrameDataLeft = 0;
|
||||
instance->at9.handle = Atrac9GetHandle();
|
||||
int err = Atrac9InitDecoder(instance->at9.handle,
|
||||
(uint8_t *)&instance->at9.configData);
|
||||
if (err < 0) {
|
||||
ORBIS_LOG_FATAL("AT9 Init Decoder error", err);
|
||||
std::abort();
|
||||
}
|
||||
Atrac9CodecInfo pCodecInfo;
|
||||
Atrac9GetCodecInfo(instance->at9.handle, &pCodecInfo);
|
||||
|
||||
instance->at9.frameSamples = pCodecInfo.frameSamples;
|
||||
instance->at9.inputChannels = pCodecInfo.channels;
|
||||
instance->at9.framesInSuperframe = pCodecInfo.framesInSuperframe;
|
||||
instance->at9.superFrameDataIdx = 0;
|
||||
instance->at9.superFrameSize = pCodecInfo.superframeSize;
|
||||
instance->at9.superFrameDataLeft = pCodecInfo.superframeSize;
|
||||
instance->at9.sampleRate = pCodecInfo.samplingRate;
|
||||
}
|
||||
}
|
||||
|
||||
static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
|
||||
void *argp, orbis::Thread *thread) {
|
||||
|
||||
auto device = static_cast<AjmDevice *>(file->device.get());
|
||||
std::lock_guard lock(device->mtx);
|
||||
// 0xc0288900 - finalize
|
||||
// 0xc0288903 - module register
|
||||
// 0xc0288904 - module unregister
|
||||
|
|
@ -67,14 +119,16 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
|
|||
orbis::uint32_t instanceId;
|
||||
};
|
||||
auto args = reinterpret_cast<InstanceDestroyArgs *>(argp);
|
||||
auto it = ajm::instanceMap.find(args->instanceId);
|
||||
if (it != ajm::instanceMap.end()) {
|
||||
auto &instance = ajm::instanceMap[args->instanceId];
|
||||
auto it = device->instanceMap.find(args->instanceId);
|
||||
if (it != device->instanceMap.end()) {
|
||||
auto &instance = device->instanceMap[args->instanceId];
|
||||
if (instance.resampler) {
|
||||
swr_free(&instance.resampler);
|
||||
}
|
||||
if (instance.codecCtx) {
|
||||
avcodec_free_context(&instance.codecCtx);
|
||||
}
|
||||
ajm::instanceMap.erase(args->instanceId);
|
||||
device->instanceMap.erase(it);
|
||||
}
|
||||
args->result = 0;
|
||||
}
|
||||
|
|
@ -98,11 +152,11 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
|
|||
if (codecId >= 0 && codecId <= 2) {
|
||||
args->result = 0;
|
||||
if (codecId == AJM_CODEC_At9) {
|
||||
args->instanceId = codecOffset + ajm::at9InstanceId++;
|
||||
args->instanceId = codecOffset + device->at9InstanceId++;
|
||||
} else if (codecId == AJM_CODEC_MP3) {
|
||||
args->instanceId = codecOffset + ajm::mp3InstanceId++;
|
||||
args->instanceId = codecOffset + device->mp3InstanceId++;
|
||||
} else if (codecId == AJM_CODEC_AAC) {
|
||||
args->instanceId = codecOffset + ajm::aacInstanceId++;
|
||||
args->instanceId = codecOffset + device->aacInstanceId++;
|
||||
}
|
||||
Instance instance;
|
||||
instance.codec = codecId;
|
||||
|
|
@ -111,6 +165,15 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
|
|||
instance.outputFormat = AJMFormat((args->flags & ~7) & 0b11);
|
||||
if (codecId == AJM_CODEC_At9) {
|
||||
instance.at9.handle = Atrac9GetHandle();
|
||||
if (instance.outputFormat == AJM_FORMAT_S16) {
|
||||
instance.at9.outputFormat = kAtrac9FormatS16;
|
||||
} else if (instance.outputFormat == AJM_FORMAT_S32) {
|
||||
instance.at9.outputFormat = kAtrac9FormatS32;
|
||||
} else if (instance.outputFormat == AJM_FORMAT_FLOAT) {
|
||||
instance.at9.outputFormat = kAtrac9FormatF32;
|
||||
} else {
|
||||
// TODO: throw error
|
||||
}
|
||||
}
|
||||
if (codecId == AJM_CODEC_AAC || codecId == AJM_CODEC_MP3) {
|
||||
const AVCodec *codec = avcodec_find_decoder(
|
||||
|
|
@ -132,12 +195,12 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
|
|||
|
||||
instance.codecCtx = codecCtx;
|
||||
}
|
||||
ajm::instanceMap.insert({
|
||||
device->instanceMap.insert({
|
||||
args->instanceId,
|
||||
instance,
|
||||
});
|
||||
} else {
|
||||
args->instanceId = codecOffset + ajm::unimplementedInstanceId++;
|
||||
args->instanceId = codecOffset + device->unimplementedInstanceId++;
|
||||
}
|
||||
ORBIS_LOG_ERROR(__FUNCTION__, request, args->result, args->unk0,
|
||||
args->flags, args->codec, args->instanceId);
|
||||
|
|
@ -153,12 +216,12 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
|
|||
};
|
||||
auto args = reinterpret_cast<StartBatchBufferArgs *>(argp);
|
||||
args->result = 0;
|
||||
args->batchId = ajm::batchId;
|
||||
ORBIS_LOG_ERROR(__FUNCTION__, request, args->result, args->unk0,
|
||||
args->pBatch, args->batchSize, args->priority,
|
||||
args->batchError, args->batchId);
|
||||
ajm::batchId += 1;
|
||||
thread->where();
|
||||
args->batchId = device->batchId;
|
||||
// ORBIS_LOG_ERROR(__FUNCTION__, request, args->result, args->unk0,
|
||||
// args->pBatch, args->batchSize, args->priority,
|
||||
// args->batchError, args->batchId);
|
||||
device->batchId += 1;
|
||||
// thread->where();
|
||||
|
||||
auto ptr = args->pBatch;
|
||||
auto endPtr = args->pBatch + args->batchSize;
|
||||
|
|
@ -169,16 +232,17 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
|
|||
auto jobPtr = ptr + sizeof(InstructionHeader);
|
||||
auto endJobPtr = ptr + header->len;
|
||||
// TODO: handle unimplemented codecs, so auto create instance for now
|
||||
auto &instance = ajm::instanceMap[instanceId];
|
||||
ORBIS_LOG_TODO("instance info", instanceId);
|
||||
auto &instance = device->instanceMap[instanceId];
|
||||
RunJob runJob{};
|
||||
device->inputSize = 0;
|
||||
while (jobPtr < endJobPtr) {
|
||||
auto typed = (OpcodeHeader *)jobPtr;
|
||||
switch (typed->getOpcode()) {
|
||||
case Opcode::ReturnAddress: {
|
||||
ReturnAddress *ra = (ReturnAddress *)jobPtr;
|
||||
ORBIS_LOG_ERROR(__FUNCTION__, request, "return address", ra->opcode,
|
||||
ra->unk, ra->returnAddress);
|
||||
// ReturnAddress *ra = (ReturnAddress *)jobPtr;
|
||||
// ORBIS_LOG_ERROR(__FUNCTION__, request, "return address",
|
||||
// ra->opcode,
|
||||
// ra->unk, ra->returnAddress);
|
||||
jobPtr += sizeof(ReturnAddress);
|
||||
break;
|
||||
}
|
||||
|
|
@ -193,13 +257,10 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
|
|||
ctrl->commandId, ctrl->flagsHi, ctrl->flagsLo,
|
||||
ctrl->sidebandInputSize, ctrl->sidebandOutputSize);
|
||||
if (ctrl->getFlags() & CONTROL_RESET) {
|
||||
// instance.outputChannels = AJMChannels(0);
|
||||
// instance.outputFormat = AJMFormat(0);
|
||||
instance.gaplessSkipSamples = 0;
|
||||
instance.gaplessTotalSamples = 0;
|
||||
instance.gaplessTotalSkippedSamples = 0;
|
||||
instance.processedSamples = 0;
|
||||
ORBIS_LOG_TODO("CONTROL_RESET");
|
||||
reset(&instance);
|
||||
if (instance.codec == AJM_CODEC_At9) {
|
||||
resetAt9(&instance);
|
||||
}
|
||||
}
|
||||
|
||||
if (ctrl->getFlags() & CONTROL_INITIALIZE) {
|
||||
|
|
@ -210,35 +271,9 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
|
|||
};
|
||||
InitalizeBuffer *initializeBuffer =
|
||||
(InitalizeBuffer *)ctrl->pSidebandInput;
|
||||
Atrac9ReleaseHandle(instance.at9.handle);
|
||||
instance.at9.estimatedSizeUsed = 0;
|
||||
instance.at9.superFrameSize = 0;
|
||||
instance.at9.framesInSuperframe = 0;
|
||||
instance.at9.frameSamples = 0;
|
||||
instance.at9.sampleRate = 0;
|
||||
instance.at9.superFrameDataIdx = 0;
|
||||
instance.at9.inputChannels = 0;
|
||||
instance.at9.superFrameDataLeft = 0;
|
||||
instance.at9.handle = Atrac9GetHandle();
|
||||
int err = Atrac9InitDecoder(
|
||||
instance.at9.handle,
|
||||
reinterpret_cast<uint8_t *>(&initializeBuffer->configData));
|
||||
if (err < 0) {
|
||||
ORBIS_LOG_FATAL("AT9 Init Decoder error", err);
|
||||
rx::hexdump({(std::byte *)ctrl->pSidebandInput,
|
||||
ctrl->sidebandInputSize});
|
||||
std::abort();
|
||||
}
|
||||
Atrac9CodecInfo pCodecInfo;
|
||||
Atrac9GetCodecInfo(instance.at9.handle, &pCodecInfo);
|
||||
|
||||
instance.at9.frameSamples = pCodecInfo.frameSamples;
|
||||
instance.at9.inputChannels = pCodecInfo.channels;
|
||||
instance.at9.framesInSuperframe = pCodecInfo.framesInSuperframe;
|
||||
instance.at9.superFrameDataIdx = 0;
|
||||
instance.at9.superFrameSize = pCodecInfo.superframeSize;
|
||||
instance.at9.superFrameDataLeft = pCodecInfo.superframeSize;
|
||||
instance.at9.sampleRate = pCodecInfo.samplingRate;
|
||||
instance.at9.configData = initializeBuffer->configData;
|
||||
reset(&instance);
|
||||
resetAt9(&instance);
|
||||
|
||||
orbis::uint32_t maxChannels =
|
||||
instance.maxChannels == AJM_CHANNEL_DEFAULT
|
||||
|
|
@ -248,48 +283,12 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
|
|||
instance.at9.inputChannels > maxChannels
|
||||
? maxChannels
|
||||
: instance.at9.inputChannels;
|
||||
if (instance.resampler) {
|
||||
swr_free(&instance.resampler);
|
||||
instance.resampler = NULL;
|
||||
}
|
||||
if (instance.at9.inputChannels != outputChannels ||
|
||||
instance.outputFormat != AJM_FORMAT_S16) {
|
||||
instance.resampler = swr_alloc();
|
||||
if (!instance.resampler) {
|
||||
ORBIS_LOG_FATAL("Could not allocate resampler context");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
AVChannelLayout inputChLayout;
|
||||
av_channel_layout_default(&inputChLayout,
|
||||
instance.at9.inputChannels);
|
||||
|
||||
AVChannelLayout outputChLayout;
|
||||
av_channel_layout_default(&outputChLayout, outputChannels);
|
||||
|
||||
av_opt_set_chlayout(instance.resampler, "in_chlayout",
|
||||
&inputChLayout, 0);
|
||||
av_opt_set_chlayout(instance.resampler, "out_chlayout",
|
||||
&outputChLayout, 0);
|
||||
av_opt_set_int(instance.resampler, "in_sample_rate",
|
||||
pCodecInfo.samplingRate, 0);
|
||||
av_opt_set_int(instance.resampler, "out_sample_rate",
|
||||
pCodecInfo.samplingRate, 0);
|
||||
av_opt_set_sample_fmt(instance.resampler, "in_sample_fmt",
|
||||
ajmToAvFormat(AJM_FORMAT_S16), 0);
|
||||
av_opt_set_sample_fmt(instance.resampler, "out_sample_fmt",
|
||||
ajmToAvFormat(instance.outputFormat), 0);
|
||||
if (swr_init(instance.resampler) < 0) {
|
||||
ORBIS_LOG_FATAL(
|
||||
"Failed to initialize the resampling context");
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
ORBIS_LOG_TODO("CONTROL_INITIALIZE", pCodecInfo.channels,
|
||||
pCodecInfo.samplingRate, pCodecInfo.frameSamples,
|
||||
pCodecInfo.superframeSize, maxChannels,
|
||||
// TODO: check max channels
|
||||
ORBIS_LOG_TODO("CONTROL_INITIALIZE", instance.at9.inputChannels,
|
||||
instance.at9.sampleRate, instance.at9.frameSamples,
|
||||
instance.at9.superFrameSize, maxChannels,
|
||||
outputChannels, initializeBuffer->configData,
|
||||
&initializeBuffer->configData);
|
||||
(orbis::uint32_t)instance.outputFormat);
|
||||
} else if (instance.codec == AJM_CODEC_AAC) {
|
||||
struct InitalizeBuffer {
|
||||
orbis::uint32_t headerIndex;
|
||||
|
|
@ -312,40 +311,44 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
|
|||
InitalizeBuffer *initializeBuffer =
|
||||
(InitalizeBuffer *)ctrl->pSidebandInput;
|
||||
if (initializeBuffer->totalSamples > 0) {
|
||||
instance.gaplessTotalSamples = initializeBuffer->totalSamples;
|
||||
instance.gapless.totalSamples = initializeBuffer->totalSamples;
|
||||
}
|
||||
if (initializeBuffer->skipSamples > 0) {
|
||||
instance.gaplessSkipSamples = initializeBuffer->skipSamples;
|
||||
instance.gapless.skipSamples = initializeBuffer->skipSamples;
|
||||
}
|
||||
ORBIS_LOG_TODO("SIDEBAND_GAPLESS_DECODE",
|
||||
instance.gaplessSkipSamples,
|
||||
instance.gaplessTotalSamples);
|
||||
instance.gapless.skipSamples,
|
||||
instance.gapless.totalSamples);
|
||||
}
|
||||
jobPtr += sizeof(BatchJobControlBufferRa);
|
||||
break;
|
||||
}
|
||||
case Opcode::RunBufferRa: {
|
||||
BatchJobInputBufferRa *job = (BatchJobInputBufferRa *)jobPtr;
|
||||
ORBIS_LOG_ERROR(__FUNCTION__, request, "BatchJobInputBufferRa",
|
||||
job->opcode, job->szInputSize, job->pInput);
|
||||
runJob.pInput = job->pInput;
|
||||
runJob.inputSize = job->szInputSize;
|
||||
// ORBIS_LOG_ERROR(__FUNCTION__, request, "BatchJobInputBufferRa",
|
||||
// job->opcode, job->szInputSize, job->pInput);
|
||||
// We don't support split buffers for now, so ignore new buffers
|
||||
if (device->inputSize == 0) {
|
||||
std::memcpy(device->inputBuffer.data(), job->pInput,
|
||||
job->szInputSize);
|
||||
device->inputSize += job->szInputSize;
|
||||
}
|
||||
// rx::hexdump({(std::byte*) job->pInput, job->szInputSize});
|
||||
jobPtr += sizeof(BatchJobInputBufferRa);
|
||||
break;
|
||||
}
|
||||
case Opcode::Flags: {
|
||||
BatchJobFlagsRa *job = (BatchJobFlagsRa *)jobPtr;
|
||||
ORBIS_LOG_ERROR(__FUNCTION__, request, "BatchJobFlagsRa",
|
||||
job->flagsHi, job->flagsLo);
|
||||
runJob.flags = ((uint64_t)job->flagsHi << 0x1a) | job->flagsLo;
|
||||
// ORBIS_LOG_ERROR(__FUNCTION__, request, "BatchJobFlagsRa",
|
||||
// job->flagsHi, job->flagsLo);
|
||||
runJob.flags = ((orbis::uint64_t)job->flagsHi << 0x1a) | job->flagsLo;
|
||||
jobPtr += sizeof(BatchJobFlagsRa);
|
||||
break;
|
||||
}
|
||||
case Opcode::JobBufferOutputRa: {
|
||||
BatchJobOutputBufferRa *job = (BatchJobOutputBufferRa *)jobPtr;
|
||||
ORBIS_LOG_ERROR(__FUNCTION__, request, "BatchJobOutputBufferRa",
|
||||
job->opcode, job->outputSize, job->pOutput);
|
||||
// ORBIS_LOG_ERROR(__FUNCTION__, request, "BatchJobOutputBufferRa",
|
||||
// job->opcode, job->outputSize, job->pOutput);
|
||||
runJob.pOutput = job->pOutput;
|
||||
runJob.outputSize = job->outputSize;
|
||||
jobPtr += sizeof(BatchJobOutputBufferRa);
|
||||
|
|
@ -353,8 +356,8 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
|
|||
}
|
||||
case Opcode::JobBufferSidebandRa: {
|
||||
BatchJobSidebandBufferRa *job = (BatchJobSidebandBufferRa *)jobPtr;
|
||||
ORBIS_LOG_ERROR(__FUNCTION__, request, "BatchJobSidebandBufferRa",
|
||||
job->opcode, job->sidebandSize, job->pSideband);
|
||||
// ORBIS_LOG_ERROR(__FUNCTION__, request, "BatchJobSidebandBufferRa",
|
||||
// job->opcode, job->sidebandSize, job->pSideband);
|
||||
runJob.pSideband = job->pSideband;
|
||||
runJob.sidebandSize = job->sidebandSize;
|
||||
jobPtr += sizeof(BatchJobSidebandBufferRa);
|
||||
|
|
@ -373,13 +376,14 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
|
|||
if (runJob.flags & SIDEBAND_STREAM) {
|
||||
AJMSidebandStream *stream =
|
||||
reinterpret_cast<AJMSidebandStream *>(runJob.pSideband + 8);
|
||||
stream->inputSize = runJob.inputSize;
|
||||
stream->inputSize = device->inputSize;
|
||||
stream->outputSize = runJob.outputSize;
|
||||
}
|
||||
} else if (!runJob.control) {
|
||||
orbis::uint32_t maxChannels =
|
||||
instance.maxChannels == AJM_CHANNEL_DEFAULT ? 2
|
||||
: instance.maxChannels;
|
||||
// orbis::uint32_t maxChannels =
|
||||
// instance.maxChannels == AJM_CHANNEL_DEFAULT ? 2
|
||||
// :
|
||||
// instance.maxChannels;
|
||||
AJMSidebandResult *result =
|
||||
reinterpret_cast<AJMSidebandResult *>(runJob.pSideband);
|
||||
result->result = 0;
|
||||
|
|
@ -388,37 +392,41 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
|
|||
orbis::uint32_t inputReaded = 0;
|
||||
orbis::uint32_t outputWritten = 0;
|
||||
orbis::uint32_t framesProcessed = 0;
|
||||
orbis::uint32_t channels = 0;
|
||||
orbis::uint32_t sampleRate = 0;
|
||||
if (runJob.inputSize != 0 && runJob.outputSize != 0) {
|
||||
while (inputReaded < runJob.inputSize &&
|
||||
outputWritten < runJob.outputSize) {
|
||||
// TODO: initialize if not
|
||||
if (instance.at9.frameSamples == 0 &&
|
||||
instance.codec == AJM_CODEC_At9) {
|
||||
orbis::uint32_t samplesCount = 0;
|
||||
if (device->inputSize != 0 && runJob.outputSize != 0) {
|
||||
do {
|
||||
if (instance.codec == AJM_CODEC_At9 &&
|
||||
instance.at9.frameSamples == 0) {
|
||||
break;
|
||||
}
|
||||
if (inputReaded >= device->inputSize ||
|
||||
outputWritten >= runJob.outputSize) {
|
||||
break;
|
||||
}
|
||||
if (instance.codec == AJM_CODEC_At9) {
|
||||
orbis::uint32_t outputChannels =
|
||||
instance.at9.inputChannels > maxChannels
|
||||
? maxChannels
|
||||
: instance.at9.inputChannels;
|
||||
orbis::int32_t outputBufferSize = av_samples_get_buffer_size(
|
||||
nullptr, outputChannels, instance.at9.frameSamples,
|
||||
ajmToAvFormat(instance.resampler ? AJM_FORMAT_S16
|
||||
: instance.outputFormat),
|
||||
0);
|
||||
|
||||
orbis::uint8_t *tempBuffer =
|
||||
instance.resampler ? (uint8_t *)av_malloc(outputBufferSize)
|
||||
: reinterpret_cast<orbis::uint8_t *>(
|
||||
runJob.pOutput + outputWritten);
|
||||
AVFrame *frame = av_frame_alloc();
|
||||
rx::atScopeExit _free_frame([&] { av_frame_free(&frame); });
|
||||
|
||||
orbis::uint32_t readed = 0;
|
||||
orbis::uint32_t outputBufferSize = 0;
|
||||
if (instance.codec == AJM_CODEC_At9) {
|
||||
orbis::int32_t bytesUsed = 0;
|
||||
int err =
|
||||
Atrac9Decode(instance.at9.handle, runJob.pInput + inputReaded,
|
||||
tempBuffer, kAtrac9FormatS16, &bytesUsed);
|
||||
outputBufferSize = av_samples_get_buffer_size(
|
||||
nullptr, instance.at9.inputChannels,
|
||||
instance.at9.frameSamples,
|
||||
ajmToAvFormat(instance.outputFormat), 0);
|
||||
int err = Atrac9Decode(instance.at9.handle,
|
||||
&device->inputBuffer[inputReaded],
|
||||
device->tempBuffer.data(),
|
||||
instance.at9.outputFormat, &bytesUsed);
|
||||
if (err != ERR_SUCCESS) {
|
||||
ORBIS_LOG_FATAL("Could not decode frame", err);
|
||||
rx::hexdump({(std::byte *)&device->inputBuffer[inputReaded],
|
||||
device->inputSize});
|
||||
ORBIS_LOG_FATAL("Could not decode frame", err,
|
||||
instance.at9.estimatedSizeUsed,
|
||||
instance.at9.superFrameSize,
|
||||
instance.at9.frameSamples, instance.at9.handle,
|
||||
inputReaded, outputWritten);
|
||||
std::abort();
|
||||
}
|
||||
instance.at9.estimatedSizeUsed =
|
||||
|
|
@ -432,80 +440,27 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
|
|||
instance.at9.superFrameDataIdx = 0;
|
||||
instance.at9.superFrameDataLeft = instance.at9.superFrameSize;
|
||||
}
|
||||
|
||||
ORBIS_LOG_TODO("used size", bytesUsed,
|
||||
instance.at9.estimatedSizeUsed);
|
||||
// TODO: possible memory leak because "genius" code to avoiding
|
||||
// memory copying
|
||||
framesProcessed += 1;
|
||||
if (instance.gaplessSkipSamples > 0 ||
|
||||
instance.gaplessTotalSamples > 0) {
|
||||
if (instance.gaplessSkipSamples >
|
||||
instance.gaplessTotalSkippedSamples) {
|
||||
instance.gaplessTotalSkippedSamples +=
|
||||
instance.at9.frameSamples;
|
||||
inputReaded += instance.at9.estimatedSizeUsed;
|
||||
ORBIS_LOG_TODO("skip frame",
|
||||
instance.gaplessTotalSkippedSamples);
|
||||
continue;
|
||||
} else if (instance.processedSamples >
|
||||
instance.gaplessTotalSamples) {
|
||||
instance.gaplessTotalSkippedSamples +=
|
||||
instance.at9.frameSamples;
|
||||
inputReaded += instance.at9.estimatedSizeUsed;
|
||||
ORBIS_LOG_TODO(
|
||||
"skip output", instance.gaplessTotalSkippedSamples,
|
||||
instance.processedSamples, instance.gaplessTotalSamples);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (instance.resampler) {
|
||||
auto outputBuffer = reinterpret_cast<orbis::uint8_t *>(
|
||||
runJob.pOutput + outputWritten);
|
||||
|
||||
int nb_samples =
|
||||
swr_convert(instance.resampler, &outputBuffer,
|
||||
instance.at9.frameSamples, &tempBuffer,
|
||||
instance.at9.frameSamples);
|
||||
if (nb_samples < 0) {
|
||||
ORBIS_LOG_FATAL("Error while resampling", nb_samples);
|
||||
std::abort();
|
||||
}
|
||||
av_freep(&tempBuffer);
|
||||
}
|
||||
channels = instance.at9.inputChannels;
|
||||
sampleRate = instance.at9.sampleRate;
|
||||
inputReaded += instance.at9.estimatedSizeUsed;
|
||||
// outputWritten += std::max((orbis::uint32_t)outputBufferSize,
|
||||
// runJob.outputSize);
|
||||
outputWritten += outputBufferSize;
|
||||
instance.processedSamples += instance.at9.frameSamples;
|
||||
samplesCount = instance.at9.frameSamples;
|
||||
readed = instance.at9.estimatedSizeUsed;
|
||||
instance.lastDecode.channels =
|
||||
AJMChannels(instance.at9.inputChannels);
|
||||
instance.lastDecode.sampleRate = instance.at9.sampleRate;
|
||||
// ORBIS_LOG_TODO("at9 decode", instance.at9.estimatedSizeUsed,
|
||||
// instance.at9.superFrameDataLeft,
|
||||
// instance.at9.superFrameDataIdx,
|
||||
// instance.at9.framesInSuperframe);
|
||||
} else if (instance.codec == AJM_CODEC_MP3) {
|
||||
ORBIS_LOG_FATAL("Pre get mp3 data size info", runJob.inputSize,
|
||||
runJob.outputSize, runJob.sidebandSize,
|
||||
runJob.flags);
|
||||
auto realInputSize =
|
||||
get_mp3_data_size((uint8_t *)(runJob.pInput + inputReaded));
|
||||
if (realInputSize == 0) {
|
||||
realInputSize = runJob.inputSize;
|
||||
auto frameSize = get_mp3_data_size(
|
||||
(orbis::uint8_t *)(&device->inputBuffer[inputReaded]));
|
||||
if (frameSize == 0) {
|
||||
frameSize = device->inputSize;
|
||||
} else {
|
||||
realInputSize = std::min(realInputSize, runJob.inputSize);
|
||||
frameSize = std::min(frameSize, device->inputSize);
|
||||
}
|
||||
|
||||
if (inputReaded + realInputSize > runJob.inputSize) {
|
||||
break;
|
||||
}
|
||||
|
||||
// rx::hexdump(
|
||||
// {(std::byte *)(runJob.pInput + inputReaded),
|
||||
// realInputSize});
|
||||
|
||||
AVPacket *pkt = av_packet_alloc();
|
||||
rx::atScopeExit _free_pkt([&] { av_packet_free(&pkt); });
|
||||
AVFrame *frame = av_frame_alloc();
|
||||
rx::atScopeExit _free_frame([&] { av_frame_free(&frame); });
|
||||
pkt->data = (orbis::uint8_t *)(runJob.pInput + inputReaded);
|
||||
pkt->size = realInputSize;
|
||||
pkt->data = (orbis::uint8_t *)(&device->inputBuffer[inputReaded]);
|
||||
pkt->size = frameSize;
|
||||
int ret = avcodec_send_packet(instance.codecCtx, pkt);
|
||||
if (ret < 0) {
|
||||
ORBIS_LOG_FATAL("Error sending packet for decoding", ret);
|
||||
|
|
@ -516,49 +471,62 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
|
|||
ORBIS_LOG_FATAL("Error during decoding");
|
||||
std::abort();
|
||||
}
|
||||
outputBufferSize = av_samples_get_buffer_size(
|
||||
nullptr, frame->ch_layout.nb_channels, frame->nb_samples,
|
||||
ajmToAvFormat(instance.outputFormat), 0);
|
||||
samplesCount = frame->nb_samples;
|
||||
readed = frameSize;
|
||||
instance.lastDecode.channels =
|
||||
AJMChannels(frame->ch_layout.nb_channels);
|
||||
instance.lastDecode.sampleRate = frame->sample_rate;
|
||||
} else if (instance.codec == AJM_CODEC_AAC) {
|
||||
AVPacket *pkt = av_packet_alloc();
|
||||
rx::atScopeExit _free_pkt([&] { av_packet_free(&pkt); });
|
||||
pkt->data = (orbis::uint8_t *)(&device->inputBuffer[inputReaded]);
|
||||
pkt->size = device->inputSize;
|
||||
|
||||
if (instance.gaplessSkipSamples > 0 ||
|
||||
instance.gaplessTotalSamples > 0) {
|
||||
if (instance.gaplessSkipSamples >
|
||||
instance.gaplessTotalSkippedSamples) {
|
||||
instance.gaplessTotalSkippedSamples += frame->nb_samples;
|
||||
inputReaded += realInputSize;
|
||||
ORBIS_LOG_TODO("skip frame",
|
||||
instance.gaplessTotalSkippedSamples);
|
||||
break;
|
||||
} else if (instance.processedSamples >
|
||||
instance.gaplessTotalSamples) {
|
||||
instance.gaplessTotalSkippedSamples += frame->nb_samples;
|
||||
inputReaded += realInputSize;
|
||||
ORBIS_LOG_TODO(
|
||||
"skip output", instance.gaplessTotalSkippedSamples,
|
||||
instance.processedSamples, instance.gaplessTotalSamples);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto resampler = swr_alloc();
|
||||
rx::atScopeExit _free_resampler([&] { swr_free(&resampler); });
|
||||
if (!resampler) {
|
||||
ORBIS_LOG_FATAL("Could not allocate resampler context");
|
||||
// HACK: to avoid writing a bunch of useless calls
|
||||
// we simply call this method directly (but it can be very
|
||||
// unstable)
|
||||
int gotFrame;
|
||||
int len =
|
||||
ffcodec(instance.codecCtx->codec)
|
||||
->cb.decode(instance.codecCtx, frame, &gotFrame, pkt);
|
||||
if (len < 0) {
|
||||
ORBIS_LOG_FATAL("Error during decoding");
|
||||
std::abort();
|
||||
}
|
||||
outputBufferSize = av_samples_get_buffer_size(
|
||||
nullptr, frame->ch_layout.nb_channels, frame->nb_samples,
|
||||
ajmToAvFormat(instance.outputFormat), 0);
|
||||
samplesCount = frame->nb_samples;
|
||||
readed = len;
|
||||
instance.lastDecode.channels =
|
||||
AJMChannels(frame->ch_layout.nb_channels);
|
||||
instance.lastDecode.sampleRate = frame->sample_rate;
|
||||
}
|
||||
framesProcessed += 1;
|
||||
inputReaded += readed;
|
||||
|
||||
orbis::uint32_t outputChannels =
|
||||
(orbis::uint32_t)frame->ch_layout.nb_channels > maxChannels
|
||||
? maxChannels
|
||||
: frame->ch_layout.nb_channels;
|
||||
|
||||
AVChannelLayout inputChLayout;
|
||||
av_channel_layout_default(&inputChLayout,
|
||||
if (instance.gapless.skipSamples > 0 ||
|
||||
instance.gapless.totalSamples > 0) {
|
||||
if (instance.gapless.skipSamples >
|
||||
instance.gapless.totalSkippedSamples ||
|
||||
instance.processedSamples > instance.gapless.totalSamples) {
|
||||
instance.gapless.totalSkippedSamples += samplesCount;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// at least three codecs outputs in float
|
||||
// and mp3 support sample rate resample (TODO), so made resampling
|
||||
// with swr
|
||||
if (instance.codec != AJM_CODEC_At9) {
|
||||
auto resampler = swr_alloc();
|
||||
AVChannelLayout chLayout;
|
||||
av_channel_layout_default(&chLayout,
|
||||
frame->ch_layout.nb_channels);
|
||||
|
||||
AVChannelLayout outputChLayout;
|
||||
av_channel_layout_default(&outputChLayout, outputChannels);
|
||||
|
||||
av_opt_set_chlayout(resampler, "in_chlayout", &inputChLayout, 0);
|
||||
av_opt_set_chlayout(resampler, "out_chlayout", &outputChLayout,
|
||||
0);
|
||||
av_opt_set_chlayout(resampler, "in_chlayout", &chLayout, 0);
|
||||
av_opt_set_chlayout(resampler, "out_chlayout", &chLayout, 0);
|
||||
av_opt_set_int(resampler, "in_sample_rate", frame->sample_rate,
|
||||
0);
|
||||
av_opt_set_int(resampler, "out_sample_rate", frame->sample_rate,
|
||||
|
|
@ -571,168 +539,29 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
|
|||
ORBIS_LOG_FATAL("Failed to initialize the resampling context");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
uint8_t *outputBuffer = NULL;
|
||||
rx::atScopeExit _free_outputBuffer(
|
||||
[&] { av_freep(&outputBuffer); });
|
||||
int outputBufferSize = av_samples_alloc(
|
||||
&outputBuffer, NULL, frame->ch_layout.nb_channels,
|
||||
frame->nb_samples, ajmToAvFormat(instance.outputFormat), 0);
|
||||
if (outputBufferSize < 0) {
|
||||
ORBIS_LOG_FATAL("Could not allocate output buffer");
|
||||
std::abort();
|
||||
}
|
||||
ORBIS_LOG_TODO("output buffer info", frame->ch_layout.nb_channels,
|
||||
frame->nb_samples, (int32_t)instance.outputFormat,
|
||||
outputBufferSize,
|
||||
instance.gaplessTotalSkippedSamples,
|
||||
instance.processedSamples);
|
||||
|
||||
if (outputWritten + outputBufferSize > runJob.outputSize) {
|
||||
ORBIS_LOG_TODO("overwriting", outputWritten, outputBufferSize,
|
||||
outputWritten + outputBufferSize,
|
||||
runJob.outputSize);
|
||||
break;
|
||||
}
|
||||
|
||||
orbis::uint8_t *outputBuffer =
|
||||
reinterpret_cast<orbis::uint8_t *>(device->tempBuffer.data());
|
||||
int nb_samples =
|
||||
swr_convert(resampler, &outputBuffer, frame->nb_samples,
|
||||
(const uint8_t **)frame->data, frame->nb_samples);
|
||||
(const orbis::uint8_t **)frame->extended_data,
|
||||
frame->nb_samples);
|
||||
if (nb_samples < 0) {
|
||||
ORBIS_LOG_FATAL("Error while converting");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
memcpy(runJob.pOutput + outputWritten, outputBuffer,
|
||||
outputBufferSize);
|
||||
channels = frame->ch_layout.nb_channels;
|
||||
sampleRate = frame->sample_rate;
|
||||
inputReaded += realInputSize;
|
||||
outputWritten += outputBufferSize;
|
||||
instance.processedSamples += frame->nb_samples;
|
||||
framesProcessed += 1;
|
||||
// av_freep(&outputBuffer);
|
||||
// swr_free(&resampler);
|
||||
// av_frame_free(&frame);
|
||||
// av_packet_free(&pkt);
|
||||
} else if (instance.codec == AJM_CODEC_AAC) {
|
||||
AVPacket *pkt = av_packet_alloc();
|
||||
rx::atScopeExit _free_pkt([&] { av_packet_free(&pkt); });
|
||||
AVFrame *frame = av_frame_alloc();
|
||||
rx::atScopeExit _free_frame([&] { av_frame_free(&frame); });
|
||||
pkt->data = (uint8_t *)runJob.pInput + inputReaded;
|
||||
pkt->size = runJob.inputSize;
|
||||
|
||||
// HACK: to avoid writing a bunch of useless calls
|
||||
// we simply call this method directly (but it can be very
|
||||
// unstable)
|
||||
int gotFrame;
|
||||
int len =
|
||||
ffcodec(instance.codecCtx->codec)
|
||||
->cb.decode(instance.codecCtx, frame, &gotFrame, pkt);
|
||||
|
||||
orbis::uint32_t outputChannels =
|
||||
(orbis::uint32_t)frame->ch_layout.nb_channels > maxChannels
|
||||
? maxChannels
|
||||
: frame->ch_layout.nb_channels;
|
||||
|
||||
ORBIS_LOG_TODO("aac decode", len, gotFrame,
|
||||
frame->ch_layout.nb_channels, frame->sample_rate,
|
||||
instance.aac.sampleRate, outputChannels,
|
||||
(orbis::uint32_t)instance.maxChannels);
|
||||
|
||||
if (instance.gaplessSkipSamples > 0 ||
|
||||
instance.gaplessTotalSamples > 0) {
|
||||
if (instance.gaplessSkipSamples >
|
||||
instance.gaplessTotalSkippedSamples) {
|
||||
instance.gaplessTotalSkippedSamples += frame->nb_samples;
|
||||
inputReaded += len;
|
||||
ORBIS_LOG_TODO("skip frame",
|
||||
instance.gaplessTotalSkippedSamples);
|
||||
break;
|
||||
} else if (instance.processedSamples >
|
||||
instance.gaplessTotalSamples) {
|
||||
instance.gaplessTotalSkippedSamples += frame->nb_samples;
|
||||
inputReaded += len;
|
||||
ORBIS_LOG_TODO(
|
||||
"skip output", instance.gaplessTotalSkippedSamples,
|
||||
instance.processedSamples, instance.gaplessTotalSamples);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto resampler = swr_alloc();
|
||||
rx::atScopeExit _free_resampler([&] { swr_free(&resampler); });
|
||||
if (!resampler) {
|
||||
ORBIS_LOG_FATAL("Could not allocate resampler context");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
AVChannelLayout inputChLayout;
|
||||
av_channel_layout_default(&inputChLayout,
|
||||
frame->ch_layout.nb_channels);
|
||||
|
||||
AVChannelLayout outputChLayout;
|
||||
av_channel_layout_default(&outputChLayout, outputChannels);
|
||||
|
||||
av_opt_set_chlayout(resampler, "in_chlayout", &inputChLayout, 0);
|
||||
av_opt_set_chlayout(resampler, "out_chlayout", &outputChLayout,
|
||||
0);
|
||||
av_opt_set_int(resampler, "in_sample_rate",
|
||||
instance.aac.sampleRate, 0);
|
||||
av_opt_set_int(resampler, "out_sample_rate",
|
||||
instance.aac.sampleRate, 0);
|
||||
av_opt_set_sample_fmt(resampler, "in_sample_fmt",
|
||||
ajmToAvFormat(AJM_FORMAT_FLOAT), 0);
|
||||
av_opt_set_sample_fmt(resampler, "out_sample_fmt",
|
||||
ajmToAvFormat(instance.outputFormat), 0);
|
||||
if (swr_init(resampler) < 0) {
|
||||
ORBIS_LOG_FATAL("Failed to initialize the resampling context");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
uint8_t *outputBuffer = NULL;
|
||||
rx::atScopeExit _free_outputBuffer(
|
||||
[&] { av_freep(&outputBuffer); });
|
||||
int outputBufferSize = av_samples_alloc(
|
||||
&outputBuffer, NULL, outputChannels, frame->nb_samples,
|
||||
ajmToAvFormat(instance.outputFormat), 0);
|
||||
if (outputBufferSize < 0) {
|
||||
ORBIS_LOG_FATAL("Could not allocate output buffer");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
int nb_samples =
|
||||
swr_convert(resampler, &outputBuffer, frame->nb_samples,
|
||||
frame->extended_data, frame->nb_samples);
|
||||
if (nb_samples < 0) {
|
||||
ORBIS_LOG_FATAL("Error while converting");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
memcpy(runJob.pOutput + outputWritten, outputBuffer,
|
||||
outputBufferSize);
|
||||
channels = frame->ch_layout.nb_channels;
|
||||
sampleRate = frame->sample_rate;
|
||||
inputReaded += len;
|
||||
outputWritten += outputBufferSize;
|
||||
framesProcessed += 1;
|
||||
instance.processedSamples += frame->nb_samples;
|
||||
// av_frame_free(&frame);
|
||||
// av_packet_free(&pkt);
|
||||
// swr_free(&resampler);
|
||||
}
|
||||
if (!(runJob.flags & RUN_MULTIPLE_FRAMES)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
memcpy(runJob.pOutput + outputWritten, device->tempBuffer.data(),
|
||||
outputBufferSize);
|
||||
outputWritten += outputBufferSize;
|
||||
instance.processedSamples += samplesCount;
|
||||
} while ((runJob.flags & RUN_MULTIPLE_FRAMES) != 0);
|
||||
}
|
||||
|
||||
orbis::int64_t currentSize = sizeof(AJMSidebandResult);
|
||||
|
||||
if (runJob.flags & SIDEBAND_STREAM) {
|
||||
ORBIS_LOG_TODO("SIDEBAND_STREAM", currentSize, inputReaded,
|
||||
outputWritten, instance.processedSamples);
|
||||
// ORBIS_LOG_TODO("SIDEBAND_STREAM", currentSize, inputReaded,
|
||||
// outputWritten, instance.processedSamples);
|
||||
AJMSidebandStream *stream = reinterpret_cast<AJMSidebandStream *>(
|
||||
runJob.pSideband + currentSize);
|
||||
stream->inputSize = inputReaded;
|
||||
|
|
@ -742,28 +571,29 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
|
|||
}
|
||||
|
||||
if (runJob.flags & SIDEBAND_FORMAT) {
|
||||
ORBIS_LOG_TODO("SIDEBAND_FORMAT", currentSize);
|
||||
// ORBIS_LOG_TODO("SIDEBAND_FORMAT", currentSize);
|
||||
AJMSidebandFormat *format = reinterpret_cast<AJMSidebandFormat *>(
|
||||
runJob.pSideband + currentSize);
|
||||
format->channels = AJMChannels(channels);
|
||||
format->sampleRate = sampleRate;
|
||||
format->sampleFormat = AJM_FORMAT_FLOAT;
|
||||
format->channels = AJMChannels(instance.lastDecode.channels);
|
||||
format->sampleRate = instance.lastDecode.sampleRate;
|
||||
format->sampleFormat = instance.outputFormat;
|
||||
// TODO: channel mask and bitrate
|
||||
currentSize += sizeof(AJMSidebandFormat);
|
||||
}
|
||||
|
||||
if (runJob.flags & SIDEBAND_GAPLESS_DECODE) {
|
||||
ORBIS_LOG_TODO("SIDEBAND_GAPLESS_DECODE", currentSize);
|
||||
// ORBIS_LOG_TODO("SIDEBAND_GAPLESS_DECODE", currentSize);
|
||||
AJMSidebandGaplessDecode *gapless =
|
||||
reinterpret_cast<AJMSidebandGaplessDecode *>(runJob.pSideband +
|
||||
currentSize);
|
||||
gapless->skipSamples = instance.gaplessSkipSamples;
|
||||
gapless->totalSamples = instance.gaplessTotalSamples;
|
||||
gapless->totalSkippedSamples = instance.gaplessTotalSkippedSamples;
|
||||
gapless->skipSamples = instance.gapless.skipSamples;
|
||||
gapless->totalSamples = instance.gapless.totalSamples;
|
||||
gapless->totalSkippedSamples = instance.gapless.totalSkippedSamples;
|
||||
currentSize += sizeof(AJMSidebandGaplessDecode);
|
||||
}
|
||||
|
||||
if (runJob.flags & RUN_GET_CODEC_INFO) {
|
||||
ORBIS_LOG_TODO("RUN_GET_CODEC_INFO");
|
||||
// ORBIS_LOG_TODO("RUN_GET_CODEC_INFO");
|
||||
if (instance.codec == AJM_CODEC_At9) {
|
||||
AJMAt9CodecInfoSideband *info =
|
||||
reinterpret_cast<AJMAt9CodecInfoSideband *>(runJob.pSideband +
|
||||
|
|
@ -788,7 +618,7 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
|
|||
}
|
||||
|
||||
if (runJob.flags & RUN_MULTIPLE_FRAMES) {
|
||||
ORBIS_LOG_TODO("RUN_MULTIPLE_FRAMES", currentSize);
|
||||
// ORBIS_LOG_TODO("RUN_MULTIPLE_FRAMES", framesProcessed);
|
||||
AJMSidebandMultipleFrames *multipleFrames =
|
||||
reinterpret_cast<AJMSidebandMultipleFrames *>(runJob.pSideband +
|
||||
currentSize);
|
||||
|
|
@ -807,9 +637,9 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
|
|||
};
|
||||
auto args = reinterpret_cast<Args *>(argp);
|
||||
args->unk0 = 0;
|
||||
ORBIS_LOG_ERROR(__FUNCTION__, request, args->unk0, args->unk1,
|
||||
args->batchId, args->timeout, args->batchError);
|
||||
thread->where();
|
||||
// ORBIS_LOG_ERROR(__FUNCTION__, request, args->unk0, args->unk1,
|
||||
// args->batchId, args->timeout, args->batchError);
|
||||
// thread->where();
|
||||
} else {
|
||||
ORBIS_LOG_FATAL("Unhandled AJM ioctl", request);
|
||||
thread->where();
|
||||
|
|
@ -821,17 +651,18 @@ static const orbis::FileOps fileOps = {
|
|||
.ioctl = ajm_ioctl,
|
||||
};
|
||||
|
||||
struct AjmDevice : IoDevice {
|
||||
orbis::ErrorCode open(orbis::Ref<orbis::File> *file, const char *path,
|
||||
std::uint32_t flags, std::uint32_t mode,
|
||||
orbis::Thread *thread) override {
|
||||
auto newFile = orbis::knew<AjmFile>();
|
||||
newFile->ops = &fileOps;
|
||||
newFile->device = this;
|
||||
orbis::ErrorCode AjmDevice::open(orbis::Ref<orbis::File> *file,
|
||||
const char *path, std::uint32_t flags,
|
||||
std::uint32_t mode, orbis::Thread *thread) {
|
||||
auto newFile = orbis::knew<AjmFile>();
|
||||
newFile->ops = &fileOps;
|
||||
newFile->device = this;
|
||||
|
||||
*file = newFile;
|
||||
return {};
|
||||
}
|
||||
};
|
||||
inputBuffer.reserve(32 * 1024);
|
||||
tempBuffer.reserve(32 * 1024);
|
||||
|
||||
*file = newFile;
|
||||
return {};
|
||||
}
|
||||
|
||||
IoDevice *createAjmCharacterDevice() { return orbis::knew<AjmDevice>(); }
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "libatrac9/libatrac9.h"
|
||||
#include "orbis-config.hpp"
|
||||
#include "orbis/utils/Logs.hpp"
|
||||
// #include "orbis/utils/Logs.hpp"
|
||||
#include <cstdint>
|
||||
extern "C" {
|
||||
#include <libavcodec/avcodec.h>
|
||||
|
|
@ -29,7 +30,7 @@ struct OpcodeHeader {
|
|||
orbis::uint32_t opcode;
|
||||
|
||||
Opcode getOpcode() const {
|
||||
ORBIS_LOG_ERROR(__FUNCTION__, opcode);
|
||||
// ORBIS_LOG_ERROR(__FUNCTION__, opcode);
|
||||
if (auto loType = static_cast<Opcode>(opcode & 0xf);
|
||||
loType == Opcode::ReturnAddress || loType == Opcode::Flags) {
|
||||
return loType;
|
||||
|
|
@ -49,23 +50,21 @@ static_assert(sizeof(ReturnAddress) == 0x10);
|
|||
struct BatchJobControlBufferRa {
|
||||
orbis::uint32_t opcode;
|
||||
orbis::uint32_t sidebandInputSize;
|
||||
std::byte* pSidebandInput;
|
||||
std::byte *pSidebandInput;
|
||||
orbis::uint32_t flagsHi;
|
||||
orbis::uint32_t flagsLo;
|
||||
orbis::uint32_t commandId;
|
||||
orbis::uint32_t sidebandOutputSize;
|
||||
std::byte* pSidebandOutput;
|
||||
std::byte *pSidebandOutput;
|
||||
|
||||
std::uint64_t getFlags() {
|
||||
return ((uint64_t)flagsHi << 0x1a) | flagsLo;
|
||||
}
|
||||
std::uint64_t getFlags() { return ((uint64_t)flagsHi << 0x1a) | flagsLo; }
|
||||
};
|
||||
static_assert(sizeof(BatchJobControlBufferRa) == 0x28);
|
||||
|
||||
struct BatchJobInputBufferRa {
|
||||
orbis::uint32_t opcode;
|
||||
orbis::uint32_t szInputSize;
|
||||
std::byte* pInput;
|
||||
std::byte *pInput;
|
||||
};
|
||||
static_assert(sizeof(BatchJobInputBufferRa) == 0x10);
|
||||
|
||||
|
|
@ -79,25 +78,23 @@ static_assert(sizeof(BatchJobFlagsRa) == 0x8);
|
|||
struct BatchJobOutputBufferRa {
|
||||
orbis::uint32_t opcode;
|
||||
orbis::uint32_t outputSize;
|
||||
std::byte* pOutput;
|
||||
std::byte *pOutput;
|
||||
};
|
||||
static_assert(sizeof(BatchJobOutputBufferRa) == 0x10);
|
||||
|
||||
struct BatchJobSidebandBufferRa {
|
||||
orbis::uint32_t opcode;
|
||||
orbis::uint32_t sidebandSize;
|
||||
std::byte* pSideband;
|
||||
std::byte *pSideband;
|
||||
};
|
||||
static_assert(sizeof(BatchJobSidebandBufferRa) == 0x10);
|
||||
|
||||
struct RunJob {
|
||||
orbis::uint64_t flags;
|
||||
orbis::uint32_t inputSize;
|
||||
std::byte* pInput;
|
||||
orbis::uint32_t outputSize;
|
||||
std::byte* pOutput;
|
||||
std::byte *pOutput;
|
||||
orbis::uint32_t sidebandSize;
|
||||
std::byte* pSideband;
|
||||
std::byte *pSideband;
|
||||
bool control;
|
||||
};
|
||||
|
||||
|
|
@ -198,10 +195,10 @@ uint32_t get_mp3_data_size(const uint8_t *data) {
|
|||
((bps * static_cast<float>(bitrate)) / static_cast<float>(samprate)) +
|
||||
((pad) ? slot_size : 0);
|
||||
|
||||
ORBIS_LOG_TODO("get_mp3_data_size", (uint16_t)ver, (uint16_t)lyr,
|
||||
(uint16_t)pad, (uint16_t)brx, (uint16_t)srx, bitrate, samprate,
|
||||
samples, (uint16_t)slot_size, bps, fsize,
|
||||
static_cast<uint16_t>(fsize));
|
||||
// ORBIS_LOG_TODO(__FUNCTION__, (uint16_t)ver, (uint16_t)lyr,
|
||||
// (uint16_t)pad, (uint16_t)brx, (uint16_t)srx, bitrate, samprate,
|
||||
// samples, (uint16_t)slot_size, bps, fsize,
|
||||
// static_cast<uint16_t>(fsize));
|
||||
|
||||
// Frame sizes are truncated integers
|
||||
return static_cast<uint16_t>(fsize);
|
||||
|
|
@ -245,6 +242,8 @@ struct At9Instance {
|
|||
orbis::uint32_t superFrameSize{};
|
||||
orbis::uint32_t estimatedSizeUsed{};
|
||||
orbis::uint32_t sampleRate{};
|
||||
Atrac9Format outputFormat{};
|
||||
orbis::uint32_t configData;
|
||||
};
|
||||
|
||||
struct AACInstance {
|
||||
|
|
@ -252,20 +251,10 @@ struct AACInstance {
|
|||
orbis::uint32_t sampleRate;
|
||||
};
|
||||
|
||||
struct Instance {
|
||||
AJMCodecs codec;
|
||||
AJMChannels maxChannels;
|
||||
AJMFormat outputFormat;
|
||||
At9Instance at9;
|
||||
AACInstance aac;
|
||||
AVCodecContext *codecCtx;
|
||||
SwrContext *resampler;
|
||||
orbis::uint32_t lastBatchId;
|
||||
// TODO: use AJMSidebandGaplessDecode for these variables
|
||||
orbis::uint32_t gaplessTotalSamples;
|
||||
orbis::uint16_t gaplessSkipSamples;
|
||||
orbis::uint16_t gaplessTotalSkippedSamples;
|
||||
orbis::uint32_t processedSamples;
|
||||
struct AJMSidebandGaplessDecode {
|
||||
orbis::uint32_t totalSamples;
|
||||
orbis::uint16_t skipSamples;
|
||||
orbis::uint16_t totalSkippedSamples;
|
||||
};
|
||||
|
||||
struct AJMSidebandResult {
|
||||
|
|
@ -293,13 +282,6 @@ struct AJMSidebandFormat {
|
|||
uint32_t unk1;
|
||||
};
|
||||
|
||||
|
||||
struct AJMSidebandGaplessDecode {
|
||||
orbis::uint32_t totalSamples;
|
||||
orbis::uint16_t skipSamples;
|
||||
orbis::uint16_t totalSkippedSamples;
|
||||
};
|
||||
|
||||
struct AJMAt9CodecInfoSideband {
|
||||
orbis::uint32_t superFrameSize;
|
||||
orbis::uint32_t framesInSuperFrame;
|
||||
|
|
@ -325,6 +307,21 @@ struct AJMAACCodecInfoSideband {
|
|||
orbis::uint32_t unk0;
|
||||
};
|
||||
|
||||
struct Instance {
|
||||
AJMCodecs codec;
|
||||
AJMChannels maxChannels;
|
||||
AJMFormat outputFormat;
|
||||
At9Instance at9;
|
||||
AACInstance aac;
|
||||
AVCodecContext *codecCtx;
|
||||
SwrContext *resampler;
|
||||
orbis::uint32_t lastBatchId;
|
||||
// TODO: use AJMSidebandGaplessDecode for these variables
|
||||
AJMSidebandGaplessDecode gapless;
|
||||
orbis::uint32_t processedSamples;
|
||||
AJMSidebandFormat lastDecode;
|
||||
};
|
||||
|
||||
enum ControlFlags {
|
||||
CONTROL_INITIALIZE = 0x4000,
|
||||
CONTROL_RESET = 0x2000,
|
||||
|
|
|
|||
Loading…
Reference in a new issue