/* SPDX-License-Identifier: GPL-2.0 */ /** \file mp3dec_filter.c Paraslash's mp3 decoder, based on libmad. */ /** \cond doxygen_ignore */ #include #include #include "filter_cmd.lsg.h" #include "para.h" #include "list.h" #include "sched.h" #include "buffer_tree.h" #include "filter.h" #include "error.h" #include "string.h" /* Convert a sample value from libmad to a signed short. */ static signed short mad_to_short(mad_fixed_t val) { if (val >= MAD_F_ONE) return SHRT_MAX; if (val <= -MAD_F_ONE) return -SHRT_MAX; return val >> (MAD_F_FRACBITS - 15); } struct private_mp3dec_data { /* Information about the current mp3 stream. */ struct mad_stream stream; /** Information about the frame being decoded. */ struct mad_frame frame; /* Contains the PCM output. */ struct mad_synth synth; /* The number of channels of the current stream. */ unsigned int channels; /* Current sample rate in Hz. */ unsigned int sample_rate; }; /* Returns negative on serious errors. */ static int handle_decode_error(struct private_mp3dec_data *pmd) { if (!MAD_RECOVERABLE(pmd->stream.error) && pmd->stream.error != MAD_ERROR_BUFLEN) { PARA_ERROR_LOG("%s\n", mad_stream_errorstr(&pmd->stream)); return -E_MAD_FRAME_DECODE; } PARA_DEBUG_LOG("%s\n", mad_stream_errorstr(&pmd->stream)); return 0; } static void consume(struct btr_node *btrn, struct mad_stream *s, size_t max) { size_t used; if (!s->next_frame) used = max; else { /* we still have some data */ used = s->next_frame - s->buffer; assert(used <= max); } btr_consume(btrn, used); } static void mp3dec_close(struct filter_node *fn) { struct private_mp3dec_data *pmd = fn->private_data; mad_synth_finish(&pmd->synth); mad_frame_finish(&pmd->frame); mad_stream_finish(&pmd->stream); free(pmd); fn->private_data = NULL; } #define MP3DEC_MAX_FRAME 8192 static int mp3dec_post_monitor(__a_unused struct sched *s, void *context) { struct filter_node *fn = context; int i, ret; struct private_mp3dec_data *pmd = fn->private_data; struct btr_node *btrn = fn->btrn; size_t loaded = 0, len; char *inbuffer, *outbuffer; next_buffer: pmd->stream.error = 0; ret = btr_node_status(btrn, fn->min_iqs, BTR_NT_INTERNAL); if (ret < 0) goto err; if (ret == 0) return 0; btr_merge(btrn, fn->min_iqs); len = btr_next_buffer(btrn, &inbuffer); /* * Decode at most 8K in one go to give the post_monitor() functions of * other buffer tree nodes a chance to run. This is necessary to avoid * buffer underruns on slow machines. */ len = PARA_MIN(len, (size_t)MP3DEC_MAX_FRAME); mad_stream_buffer(&pmd->stream, (unsigned char *)inbuffer, len); next_frame: ret = mad_header_decode(&pmd->frame.header, &pmd->stream); if (ret < 0) { consume(btrn, &pmd->stream, len); if (pmd->stream.error == MAD_ERROR_BUFLEN) { if (fn->min_iqs > 0 && btr_no_parent(btrn)) { ret = -E_EOF; goto err; } fn->min_iqs += 100; ret = -E_MP3DEC_CORRUPT; if (fn->min_iqs > MP3DEC_MAX_FRAME) goto err; } if (loaded == 0) goto next_buffer; return 0; } pmd->sample_rate = pmd->frame.header.samplerate; pmd->channels = MAD_NCHANNELS(&pmd->frame.header); decode: ret = mad_frame_decode(&pmd->frame, &pmd->stream); if (ret != 0) { ret = handle_decode_error(pmd); if (ret < 0) goto err; mad_stream_sync(&pmd->stream); if (pmd->stream.error == MAD_ERROR_BUFLEN) { ret = -E_EOF; if (btr_no_parent(btrn)) goto err; fn->min_iqs += 100; ret = -E_MP3DEC_CORRUPT; if (fn->min_iqs > MP3DEC_MAX_FRAME) goto err; consume(btrn, &pmd->stream, len); return 0; } if (pmd->stream.error != MAD_ERROR_BADDATAPTR) goto decode; consume(btrn, &pmd->stream, len); return 0; } fn->min_iqs = 0; mad_synth_frame(&pmd->synth, &pmd->frame); outbuffer = arr_alloc(pmd->synth.pcm.length, 2 * pmd->channels); loaded = 0; for (i = 0; i < pmd->synth.pcm.length; i++) { int sample = mad_to_short(pmd->synth.pcm.samples[0][i]); write_int16_host_endian(outbuffer + loaded, sample); loaded += 2; if (pmd->channels == 2) { /* stereo */ sample = mad_to_short(pmd->synth.pcm.samples[1][i]); write_int16_host_endian(outbuffer + loaded, sample); loaded += 2; } } btr_add_output(outbuffer, loaded, btrn); goto next_frame; err: assert(ret < 0); btr_remove_node(&fn->btrn); return ret; } static void mp3dec_open(struct filter_node *fn) { struct private_mp3dec_data *pmd = zalloc(sizeof(*pmd)); fn->private_data = pmd; mad_stream_init(&pmd->stream); mad_frame_init(&pmd->frame); mad_synth_init(&pmd->synth); if (FILTER_CMD_OPT_GIVEN(MP3DEC, IGNORE_CRC, fn->lpr)) mad_stream_options(&pmd->stream, MAD_OPTION_IGNORECRC); } static int mp3dec_execute(const struct btr_node *btrn, const char *cmd, char **result) { struct filter_node *fn = btr_context(btrn); struct private_mp3dec_data *pmd = fn->private_data; return decoder_execute(cmd, pmd->sample_rate, pmd->channels, result); } /** \endcond * The filter methods of the mp3 decoder. * * The ->execute method just calls \ref decoder_execute() to provide * standard decoder information such as the sample rate. Also, \ref * generic_filter_pre_monitor() is used as the ->pre_monitor method. */ const struct filter lsg_filter_cmd_com_mp3dec_user_data = { .open = mp3dec_open, .close = mp3dec_close, .pre_monitor = generic_filter_pre_monitor, .post_monitor = mp3dec_post_monitor, .execute = mp3dec_execute, };