125 lines
4.4 KiB
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;
|
|
}
|