audiolib/audio/audio_decoder_aac.c

125 lines
4.4 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include "audio.h"
#include "audio_internal.h"
#include "audio_demuxer_adts.h"
#include "deps/aac/neaacdec.h"
typedef struct _DecoderAACContext {
AudioBuffer *outputBuffer;
NeAACDecHandle decoder;
NeAACDecFrameInfo frameInfo;
bool initialized;
} DecoderAACContext;
AudioPipelineStatus decoder_aac_push(AudioPipelineElement *self, AudioBuffer *buffer) {
DecoderAACContext *context = (DecoderAACContext *)self->ctx;
void *end;
if (!context->initialized) {
unsigned long samplerate;
unsigned char channels;
char result = NeAACDecInit(context->decoder, buffer->data, buffer->buf_size, &samplerate, &channels);
if (result != 0) {
fprintf(stderr, "ERROR: Failed to initialize AAC decoder, retrying on next frame\n");
return PipelineBuffering;
}
context->initialized = true;
}
decode:
end = NeAACDecDecode2(context->decoder, &context->frameInfo, buffer->data, buffer->buf_size, (void **)&context->outputBuffer->data, context->outputBuffer->buf_size);
if (end == NULL && context->frameInfo.error == 27) {
// sample buffer was too small, reallocate
uint32_t sz = context->outputBuffer->buf_size;
free_audio_buffer(context->outputBuffer);
context->outputBuffer = alloc_audio_buffer(sz * 2);
goto decode;
}
bool relink_needed = (context->frameInfo.channels != self->channels) || (context->frameInfo.samplerate != self->sample_rate);
if (relink_needed) {
self->channels = context->frameInfo.channels;
self->sample_rate = (uint32_t)context->frameInfo.samplerate;
AudioPipelineStatus result = self->next->link(self->next, self);
if (result != PipelineStopped) {
fprintf(stderr, "ERROR: Re-link failed\n");
return PipelineError;
}
}
// run next element of the pipeline
if (context->frameInfo.samples > 0) {
uint32_t buf_sz = context->outputBuffer->buf_size;
context->outputBuffer->buf_size = self->bits_per_sample / 8 * (uint32_t)context->frameInfo.samples;
AudioPipelineStatus ret = self->next->push(self->next, context->outputBuffer);
if ((ret != PipelineRunning) && (ret != PipelineBuffering)) {
return ret;
}
context->outputBuffer->buf_size = buf_sz;
return PipelineRunning;
}
return PipelineBuffering;
}
AudioPipelineStatus decoder_aac_link(AudioPipelineElement *self, AudioPipelineElement *source) {
if ((source->sample_rate != 0) || (source->channels != 0) || (source->bits_per_sample != 0) || (!((source->type == AudioElementSource) || (source->type == AudioElementDemuxer)))) {
fprintf(stderr, "ERROR: AAC decoder can only link to a data source, not %s!\n", source->describe(source));
return PipelineError;
}
source->next = self;
return PipelineStopped;
}
char *decoder_aac_describe(AudioPipelineElement *self) {
return "libfaad2 AAC decoder";
}
void decoder_aac_destroy(AudioPipelineElement *self) {
DecoderAACContext *context = (DecoderAACContext *)self->ctx;
if (context->outputBuffer) {
free_audio_buffer(context->outputBuffer);
}
if (context->decoder) {
NeAACDecClose(context->decoder);
}
free(context);
free(self);
}
AudioPipelineElement *audio_decoder_aac(void) {
AudioPipelineElement *self = calloc(1, sizeof(AudioPipelineElement));
DecoderAACContext *context = calloc(1, sizeof(DecoderAACContext));
context->decoder = NeAACDecOpen();
NeAACDecConfigurationPtr config = NeAACDecGetCurrentConfiguration(context->decoder);
config->defSampleRate = 48000;
config->outputFormat = FAAD_FMT_16BIT;
config->defObjectType = LC;
config->downMatrix = 1; // mix to 2 channels;
NeAACDecSetConfiguration(context->decoder, config);
self->bits_per_sample = 16;
self->channels = 2;
context->outputBuffer = alloc_audio_buffer(1024 * 2 * 2); // 2 bytes per sample, 1024 samples per frame plus scratch space (*2)
self->ctx = context;
self->describe = decoder_aac_describe;
self->start = filter_start_nop;
self->reset = filter_reset_nop;
self->stop = filter_stop_nop;
self->push = decoder_aac_push;
self->link = decoder_aac_link;
self->destroy = decoder_aac_destroy;
self->type = AudioElementDecoder;
return self;
}