audiolib/audio/audio_decoder_mp3.c

179 lines
5.8 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include "audio.h"
#include "audio_internal.h"
#include "audio_demuxer_mp3.h"
#include "deps/mp3/stream.h"
#include "deps/mp3/frame.h"
#include "deps/mp3/synth.h"
typedef struct mad_stream MADStream;
typedef struct mad_frame MADFrame;
typedef struct mad_synth MADSynth;
typedef struct _DecoderMP3Context {
MADStream *stream;
MADFrame *frame;
MADSynth *synth;
AudioBuffer *outputBuffer;
} DecoderMP3Context;
static inline int16_t scale(mad_fixed_t sample) {
/* round */
sample += (1L << (MAD_F_FRACBITS - 16));
/* clip */
if (sample >= MAD_F_ONE)
sample = MAD_F_ONE - 1;
else if (sample < -MAD_F_ONE)
sample = -MAD_F_ONE;
/* quantize */
return sample >> (MAD_F_FRACBITS + 1 - 16);
}
AudioPipelineStatus decoder_mp3_push(AudioPipelineElement *self, AudioBuffer *buffer) {
DecoderMP3Context *context = (DecoderMP3Context *)self->ctx;
int result = 0;
mad_stream_buffer(context->stream, buffer->data, buffer->buf_size);
result = mad_frame_decode(context->frame, context->stream);
if (result == -1) {
fprintf(stderr, "ERROR: frame decoding error 0x%04x (%s)\n",
context->stream->error, mad_stream_errorstr(context->stream));
if (!MAD_RECOVERABLE(context->stream->error)) {
mad_frame_mute(context->frame);
return PipelineError;
}
return PipelineRunning;
}
mad_synth_frame(context->synth, context->frame);
bool relink_needed = false;
if ((self->channels == 0) || (self->channels != context->synth->pcm.channels)) {
self->channels = context->synth->pcm.channels;
relink_needed = true;
}
if ((self->sample_rate == 0) || (self->sample_rate != context->synth->pcm.samplerate)) {
self->sample_rate = context->synth->pcm.samplerate;
relink_needed = true;
}
if (relink_needed) {
AudioPipelineStatus result = self->next->link(self->next, self);
if (result != PipelineStopped) {
fprintf(stderr, "ERROR: Re-link failed\n");
return PipelineError;
}
}
uint16_t numSamples = context->synth->pcm.length;
if ((context->outputBuffer != NULL) && (context->outputBuffer->buf_size < numSamples * self->channels * 2)) {
// realloc buffer
free_audio_buffer(context->outputBuffer);
context->outputBuffer = NULL;
}
if (context->outputBuffer == NULL) {
// allocate output buffer
context->outputBuffer = alloc_audio_buffer(numSamples * self->channels * 2);
if (context->outputBuffer == NULL) {
fprintf(stderr, "ERROR: Cannot allocate output buffer of size %d!\n", numSamples * self->channels * 2);
return PipelineError;
}
}
// Scale samples to 16 bit
mad_fixed_t const *left = context->synth->pcm.samples[0];
mad_fixed_t const *right = context->synth->pcm.samples[1];
uint32_t bufferPos = 0;
while (numSamples--) {
signed int sample;
/* output sample(s) in 16-bit signed little-endian PCM */
sample = scale(*left++);
context->outputBuffer->data[bufferPos++] = (sample >> 0) & 0xff;
context->outputBuffer->data[bufferPos++] = (sample >> 8) & 0xff;
if (context->synth->pcm.channels == 2) {
sample = scale(*right++);
context->outputBuffer->data[bufferPos++] = (sample >> 0) & 0xff;
context->outputBuffer->data[bufferPos++] = (sample >> 8) & 0xff;
}
}
// run next element of the pipeline
uint32_t buf_sz = context->outputBuffer->buf_size;
context->outputBuffer->buf_size = bufferPos;
AudioPipelineStatus ret = self->next->push(self->next, context->outputBuffer);
if ((ret != PipelineRunning) && (ret != PipelineBuffering)) {
return ret;
}
context->outputBuffer->buf_size = buf_sz;
return PipelineRunning;
}
AudioPipelineStatus decoder_mp3_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: MP3 decoder can only link to a data source, not %s!\n", source->describe(source));
return PipelineError;
}
source->next = self;
return PipelineStopped;
}
char *decoder_mp3_describe(AudioPipelineElement *self) {
return "libmad MP3 decoder";
}
void decoder_mp3_destroy(AudioPipelineElement *self) {
DecoderMP3Context *context = (DecoderMP3Context *)self->ctx;
if (context->outputBuffer) {
free_audio_buffer(context->outputBuffer);
}
mad_synth_finish(context->synth);
mad_frame_finish(context->frame);
mad_stream_finish(context->stream);
free(context->synth);
free(context->frame);
free(context->stream);
free(context);
free(self);
}
AudioPipelineElement *audio_decoder_mp3(void) {
AudioPipelineElement *self = calloc(1, sizeof(AudioPipelineElement));
DecoderMP3Context *context = calloc(1, sizeof(DecoderMP3Context));
context->stream = malloc(sizeof(MADStream));
context->frame = malloc(sizeof(MADFrame));
context->synth = malloc(sizeof(MADSynth));
mad_stream_init(context->stream);
mad_frame_init(context->frame);
mad_synth_init(context->synth);
mad_stream_options(context->stream, 0);
self->bits_per_sample = 16;
self->ctx = context;
self->describe = decoder_mp3_describe;
self->start = filter_start_nop;
self->reset = filter_reset_nop;
self->stop = filter_stop_nop;
self->push = decoder_mp3_push;
self->link = decoder_mp3_link;
self->destroy = decoder_mp3_destroy;
self->type = AudioElementDecoder;
return self;
}