ajm: raw aac support (#85)

This commit is contained in:
Nikita Savyolov 2024-11-15 20:17:06 +03:00 committed by GitHub
parent 315864aaae
commit 59eef074ee
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 86 additions and 16 deletions

View File

@ -15,6 +15,7 @@ extern "C" {
#include <libatrac9/libatrac9.h>
#include <libavcodec/avcodec.h>
#include <libavcodec/codec_internal.h>
#include <libavcodec/defs.h>
#include <libavcodec/packet.h>
#include <libavformat/avformat.h>
#include <libavutil/mem.h>
@ -69,6 +70,8 @@ void reset(Instance *instance) {
instance->gapless.totalSamples = 0;
instance->gapless.totalSkippedSamples = 0;
instance->processedSamples = 0;
instance->aac.framesSkipped = 0;
}
void resetAt9(Instance *instance) {
@ -162,6 +165,11 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
instance.maxChannels =
AJMChannels(((args->flags & ~7) & (0xFF & ~0b11)) >> 3);
instance.outputFormat = AJMFormat((args->flags & ~7) & 0b11);
if (codecId == AJM_CODEC_AAC) {
instance.aac.isHeaac = ((args->flags & ~7) & 0x100000000) != 0;
instance.aac.isFrameSkipEnabled =
((args->flags & ~7) & 0x200000000) == 0;
}
if (codecId == AJM_CODEC_At9) {
instance.at9.handle = Atrac9GetHandle();
if (instance.outputFormat == AJM_FORMAT_S16) {
@ -195,12 +203,14 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
std::abort();
}
instance.avCodec = codec;
instance.codecCtx = codecCtx;
}
ORBIS_LOG_ERROR(__FUNCTION__, request, args->result, args->unk0,
args->flags, args->codec, args->instanceId,
(std::uint32_t)instance.outputFormat);
(std::uint16_t)instance.outputFormat,
(std::uint16_t)instance.maxChannels);
} else {
args->instanceId = codecOffset + device->unimplementedInstanceId++;
@ -291,7 +301,8 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
? maxChannels
: instance.at9.inputChannels;
// TODO: check max channels
ORBIS_LOG_TODO("CONTROL_INITIALIZE", instance.at9.inputChannels,
ORBIS_LOG_TODO("CONTROL_INITIALIZE AT9",
instance.at9.inputChannels,
instance.at9.sampleRate, instance.at9.frameSamples,
instance.at9.superFrameSize, maxChannels,
outputChannels, initializeBuffer->configData,
@ -306,6 +317,41 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
AACHeaderType(initializeBuffer->headerIndex);
instance.aac.sampleRate =
AACFreq[initializeBuffer->sampleRateIndex];
if (instance.aac.headerType == AAC_RAW) {
avcodec_free_context(&instance.codecCtx);
AVCodecContext *codecCtx =
avcodec_alloc_context3(instance.avCodec);
if (!codecCtx) {
ORBIS_LOG_FATAL(
"Failed to allocate codec context for raw aac");
std::abort();
}
orbis::uint32_t outputChannels =
instance.maxChannels == AJM_CHANNEL_DEFAULT
? 2
: instance.maxChannels;
AVChannelLayout chLayout;
av_channel_layout_default(&chLayout, outputChannels);
codecCtx->ch_layout = chLayout;
codecCtx->sample_rate = instance.aac.sampleRate;
if (int err =
avcodec_open2(codecCtx, instance.avCodec, nullptr);
err < 0) {
ORBIS_LOG_FATAL("Could not open codec for raw aac", err);
std::abort();
}
instance.codecCtx = codecCtx;
}
ORBIS_LOG_TODO("CONTROL_INITIALIZE AAC",
(std::int16_t)instance.aac.headerType,
instance.aac.sampleRate,
(std::int16_t)instance.maxChannels,
(orbis::uint32_t)instance.outputFormat);
}
}
if (ctrl->getFlags() & SIDEBAND_GAPLESS_DECODE) {
@ -471,7 +517,7 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
if (err != ERR_SUCCESS) {
rx::hexdump(
std::span(instance.inputBuffer).subspan(totalDecodedBytes));
ORBIS_LOG_FATAL("Could not decode frame", err,
ORBIS_LOG_FATAL("Could not decode AT9 frame", err,
instance.at9.estimatedSizeUsed,
instance.at9.superFrameSize,
instance.at9.frameSamples, instance.at9.handle,
@ -509,7 +555,9 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
}
ret = avcodec_receive_frame(instance.codecCtx, frame);
if (ret < 0) {
ORBIS_LOG_FATAL("Error during decoding");
ORBIS_LOG_FATAL("Error during decoding MP3");
rx::hexdump(
std::span(instance.inputBuffer).subspan(totalDecodedBytes));
std::abort();
}
outputBufferSize = av_samples_get_buffer_size(
@ -529,7 +577,9 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
ffcodec(instance.codecCtx->codec)
->cb.decode(instance.codecCtx, frame, &gotFrame, pkt);
if (len < 0) {
ORBIS_LOG_FATAL("Error during decoding");
ORBIS_LOG_FATAL("Error during decoding AAC");
rx::hexdump(
std::span(instance.inputBuffer).subspan(totalDecodedBytes));
std::abort();
}
outputBufferSize = av_samples_get_buffer_size(
@ -555,15 +605,11 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
totalDecodedBytes += inputFrameSize;
if (instance.gapless.skipSamples > 0 ||
instance.gapless.totalSamples > 0) {
if (instance.gapless.totalSkippedSamples <
instance.gapless.skipSamples ||
instance.processedSamples > instance.gapless.totalSamples) {
instance.gapless.totalSkippedSamples += samplesCount;
continue;
}
if (instance.isNeedToSkipOutput()) {
instance.gapless.totalSkippedSamples += samplesCount;
continue;
}
// at least three codecs outputs in float
// and mp3 support sample rate resample (TODO), so made resampling
// with swr
@ -636,8 +682,8 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
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, outputWritten,
// instance.processedSamples);
auto *stream = reinterpret_cast<AJMSidebandStream *>(
runJob.pSideband + currentSize);
stream->inputSize = totalDecodedBytes;
@ -647,7 +693,10 @@ 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,
// (std::uint16_t)instance.lastDecode.channels,
// (std::uint16_t)instance.outputFormat,
// instance.lastDecode.sampleRate);
auto *format = reinterpret_cast<AJMSidebandFormat *>(
runJob.pSideband + currentSize);
format->channels = AJMChannels(instance.lastDecode.channels);
@ -685,6 +734,8 @@ static orbis::ErrorCode ajm_ioctl(orbis::File *file, std::uint64_t request,
// TODO
auto *info = reinterpret_cast<AJMAACCodecInfoSideband *>(
runJob.pSideband + currentSize);
info->heaac = instance.codecCtx->profile == FF_PROFILE_AAC_HE ||
instance.codecCtx->profile == FF_PROFILE_AAC_HE_V2;
currentSize += sizeof(AJMAACCodecInfoSideband);
}
}

View File

@ -265,6 +265,9 @@ struct At9Instance {
struct AACInstance {
AACHeaderType headerType;
orbis::uint32_t sampleRate;
orbis::uint32_t isHeaac;
orbis::uint32_t isFrameSkipEnabled;
orbis::uint32_t framesSkipped;
};
struct AJMSidebandGaplessDecode {
@ -333,6 +336,7 @@ struct Instance {
orbis::kvector<std::byte> inputBuffer;
orbis::kvector<std::byte> outputBuffer;
const AVCodec *avCodec;
AVCodecContext *codecCtx;
SwrContext *resampler;
orbis::uint32_t lastBatchId;
@ -341,6 +345,21 @@ struct Instance {
orbis::uint32_t processedSamples;
AJMSidebandFormat lastDecode;
bool isNeedToSkipOutput() {
if (codec == AJM_CODEC_AAC && aac.isFrameSkipEnabled &&
aac.framesSkipped < 2) {
aac.framesSkipped += 1;
return true;
}
if (gapless.skipSamples > 0 || gapless.totalSamples > 0) {
if (gapless.totalSkippedSamples < gapless.skipSamples ||
processedSamples > gapless.totalSamples) {
return true;
}
}
return false;
}
~Instance() {
if (resampler) {
swr_free(&resampler);