#include #include #include #include #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; }