From: Andre Noll Date: Sun, 30 Nov 2008 20:45:38 +0000 (+0100) Subject: Rename filter source files. X-Git-Tag: v0.3.4~97 X-Git-Url: http://git.tue.mpg.de/?a=commitdiff_plain;h=dd0b1f12758ac877de6834b34f8c7f9291d4311d;p=paraslash.git Rename filter source files. Some filters already had the _filter postfix, others had not. Rename the latter just to be consistent. --- diff --git a/Makefile.in b/Makefile.in index 5dd08d6d..8ac8b65b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -161,15 +161,15 @@ ortp_recv.o: ortp_recv.c ortp_send.o: ortp_send.c $(CC) -c $(CPPFLAGS) $(DEBUG_CPPFLAGS) @ortp_cppflags@ $< -oggdec.o: oggdec.c +oggdec_filter.o: oggdec_filter.c $(CC) -c $(CPPFLAGS) $(DEBUG_CPPFLAGS) @oggvorbis_cppflags@ $< ogg_afh.o: ogg_afh.c $(CC) -c $(CPPFLAGS) $(DEBUG_CPPFLAGS) @oggvorbis_cppflags@ $< -mp3dec.o: mp3dec.c +mp3dec_filter.o: mp3dec_filter.c $(CC) -c $(CPPFLAGS) $(DEBUG_CPPFLAGS) @mad_cppflags@ $< -aacdec.o: aacdec.c +aacdec_filter.o: aacdec_filter.c $(CC) -c $(CPPFLAGS) $(DEBUG_CPPFLAGS) @faad_cppflags@ $< aac_common.o: aac_common.c diff --git a/aacdec.c b/aacdec.c deleted file mode 100644 index 38f69e88..00000000 --- a/aacdec.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (C) 2006-2008 Andre Noll - * - * Licensed under the GPL v2. For licencing details see COPYING. - */ -/* - * based in parts on libfaad, Copyright (C) 2003-2005 M. Bakker, - * Ahead Software AG - */ - -/** \file aacdec.c paraslash's aac (m4a) decoder */ - -#include "para.h" - -#include "list.h" -#include "sched.h" -#include "filter.h" -#include "error.h" -#include "string.h" -#include "aac.h" - -/** the output buffer size */ -#define AAC_OUTBUF_SIZE (32 * 1024) - -/** give up decoding after that many errors */ -#define MAX_ERRORS 20 - -/** - * data specific to the aacdec filter - * - * \sa filter, filter_node - */ -struct private_aacdec_data { - /** the return value of aac_open */ - NeAACDecHandle handle; - /** info about the currently decoded frame */ - NeAACDecFrameInfo frame_info; - /** whether this instance of the aac decoder is already initialized */ - int initialized; - /** - * return value of aac_find_esds(). Used to call the right aacdec - * init function - */ - unsigned long decoder_length; - /** number of times the decoder returned an error */ - unsigned error_count; - /** number of bytes already consumed from the imput stream */ - size_t consumed_total; - /** return value of aac_find_entry_point */ - size_t entry; -}; - -static ssize_t aacdec(char *input_buffer, size_t len, struct filter_node *fn) -{ - struct private_aacdec_data *padd = fn->private_data; - struct filter_chain *fc = fn->fc; - int i, ret; - unsigned char *p, *outbuffer; - unsigned char *inbuf = (unsigned char*)input_buffer; - size_t skip, consumed = 0; - - if (fn->loaded > fn->bufsize * 3 / 5) - return 0; - if (len < 2048 && !*fc->input_error) - return 0; - - if (!padd->initialized) { - unsigned long rate = 0; - unsigned char channels = 0; - ret = aac_find_esds(inbuf, len, &skip, &padd->decoder_length); - if (ret < 0) { - PARA_INFO_LOG("%s\n", para_strerror(-ret)); - ret = NeAACDecInit(padd->handle, inbuf, - len, &rate, &channels); - PARA_INFO_LOG("decoder init: %d\n", ret); - if (ret < 0) { - ret = -E_AACDEC_INIT; - goto out; - } - consumed = ret; - } else { - PARA_INFO_LOG("decoder len: %lu\n", - padd->decoder_length); - consumed += skip; - p = inbuf + consumed; - ret = -E_AACDEC_INIT; - if (NeAACDecInit2(padd->handle, p, - padd->decoder_length, &rate, - &channels) < 0) - goto out; - } - fc->samplerate = rate; - fc->channels = channels; - PARA_INFO_LOG("rate: %u, channels: %d\n", - fc->samplerate, fc->channels); - padd->initialized = 1; - } - if (padd->decoder_length > 0) { - consumed = 0; - if (!padd->entry) { - ret = aac_find_entry_point(inbuf + consumed, - len - consumed, &skip); - if (ret < 0) { - ret = len; - goto out; - } - consumed += skip; - padd->entry = ret; - PARA_INFO_LOG("entry: %zu\n", padd->entry); - } - ret = len; - if (padd->consumed_total + len < padd->entry) - goto out; - if (padd->consumed_total < padd->entry) - consumed = padd->entry - padd->consumed_total; - } - for (; consumed < len; consumed++) - if ((inbuf[consumed] & 0xfe) == 0x20) - break; - if (consumed >= len) - goto success; - p = inbuf + consumed; - outbuffer = NeAACDecDecode(padd->handle, &padd->frame_info, p, - len - consumed); - if (padd->frame_info.error) { - ret = -E_AAC_DECODE; - if (padd->error_count++ > MAX_ERRORS) - goto out; - PARA_ERROR_LOG("frame_error: %d, consumed: %zu + %zd + %lu\n", - padd->frame_info.error, padd->consumed_total, - consumed, padd->frame_info.bytesconsumed); - PARA_ERROR_LOG("%s\n", NeAACDecGetErrorMessage( - padd->frame_info.error)); - consumed++; /* catch 21 */ - goto success; - } - padd->error_count = 0; - consumed += padd->frame_info.bytesconsumed; - ret = consumed; - if (!padd->frame_info.samples) - goto out; - ret = -E_AAC_OVERRUN; - if (padd->frame_info.samples * 2 + fn->loaded > fn->bufsize) - goto out; - for (i = 0; i < padd->frame_info.samples; i++) { - short *s = (short *)outbuffer; - write_int16_host_endian(fn->buf + fn->loaded, s[i]); - fn->loaded += 2; - } -success: - ret = consumed; -out: - if (ret > 0) - padd->consumed_total += ret; - return ret; -} - -static void aacdec_open(struct filter_node *fn) -{ - struct private_aacdec_data *padd = para_calloc(sizeof(*padd)); - - fn->private_data = padd; - fn->bufsize = AAC_OUTBUF_SIZE; - fn->buf = para_calloc(fn->bufsize); - padd->handle = aac_open(); -} - -static void aacdec_close(struct filter_node *fn) -{ - struct private_aacdec_data *padd = fn->private_data; - - NeAACDecClose(padd->handle); - free(fn->buf); - fn->buf = NULL; - free(padd); - fn->private_data = NULL; -} - -/** - * the init function of the aacdec filter - * - * \param f pointer to the filter struct to initialize - * - * \sa filter::init - */ -void aacdec_filter_init(struct filter *f) -{ - f->open = aacdec_open; - f->convert = aacdec; - f->close = aacdec_close; -} diff --git a/aacdec_filter.c b/aacdec_filter.c new file mode 100644 index 00000000..956f338d --- /dev/null +++ b/aacdec_filter.c @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2006-2008 Andre Noll + * + * Licensed under the GPL v2. For licencing details see COPYING. + */ +/* + * based in parts on libfaad, Copyright (C) 2003-2005 M. Bakker, + * Ahead Software AG + */ + +/** \file aacdec_filter.c paraslash's aac (m4a) decoder. */ + +#include "para.h" + +#include "list.h" +#include "sched.h" +#include "filter.h" +#include "error.h" +#include "string.h" +#include "aac.h" + +/** the output buffer size */ +#define AAC_OUTBUF_SIZE (32 * 1024) + +/** give up decoding after that many errors */ +#define MAX_ERRORS 20 + +/** + * data specific to the aacdec filter + * + * \sa filter, filter_node + */ +struct private_aacdec_data { + /** the return value of aac_open */ + NeAACDecHandle handle; + /** info about the currently decoded frame */ + NeAACDecFrameInfo frame_info; + /** whether this instance of the aac decoder is already initialized */ + int initialized; + /** + * return value of aac_find_esds(). Used to call the right aacdec + * init function + */ + unsigned long decoder_length; + /** number of times the decoder returned an error */ + unsigned error_count; + /** number of bytes already consumed from the imput stream */ + size_t consumed_total; + /** return value of aac_find_entry_point */ + size_t entry; +}; + +static ssize_t aacdec(char *input_buffer, size_t len, struct filter_node *fn) +{ + struct private_aacdec_data *padd = fn->private_data; + struct filter_chain *fc = fn->fc; + int i, ret; + unsigned char *p, *outbuffer; + unsigned char *inbuf = (unsigned char*)input_buffer; + size_t skip, consumed = 0; + + if (fn->loaded > fn->bufsize * 3 / 5) + return 0; + if (len < 2048 && !*fc->input_error) + return 0; + + if (!padd->initialized) { + unsigned long rate = 0; + unsigned char channels = 0; + ret = aac_find_esds(inbuf, len, &skip, &padd->decoder_length); + if (ret < 0) { + PARA_INFO_LOG("%s\n", para_strerror(-ret)); + ret = NeAACDecInit(padd->handle, inbuf, + len, &rate, &channels); + PARA_INFO_LOG("decoder init: %d\n", ret); + if (ret < 0) { + ret = -E_AACDEC_INIT; + goto out; + } + consumed = ret; + } else { + PARA_INFO_LOG("decoder len: %lu\n", + padd->decoder_length); + consumed += skip; + p = inbuf + consumed; + ret = -E_AACDEC_INIT; + if (NeAACDecInit2(padd->handle, p, + padd->decoder_length, &rate, + &channels) < 0) + goto out; + } + fc->samplerate = rate; + fc->channels = channels; + PARA_INFO_LOG("rate: %u, channels: %d\n", + fc->samplerate, fc->channels); + padd->initialized = 1; + } + if (padd->decoder_length > 0) { + consumed = 0; + if (!padd->entry) { + ret = aac_find_entry_point(inbuf + consumed, + len - consumed, &skip); + if (ret < 0) { + ret = len; + goto out; + } + consumed += skip; + padd->entry = ret; + PARA_INFO_LOG("entry: %zu\n", padd->entry); + } + ret = len; + if (padd->consumed_total + len < padd->entry) + goto out; + if (padd->consumed_total < padd->entry) + consumed = padd->entry - padd->consumed_total; + } + for (; consumed < len; consumed++) + if ((inbuf[consumed] & 0xfe) == 0x20) + break; + if (consumed >= len) + goto success; + p = inbuf + consumed; + outbuffer = NeAACDecDecode(padd->handle, &padd->frame_info, p, + len - consumed); + if (padd->frame_info.error) { + ret = -E_AAC_DECODE; + if (padd->error_count++ > MAX_ERRORS) + goto out; + PARA_ERROR_LOG("frame_error: %d, consumed: %zu + %zd + %lu\n", + padd->frame_info.error, padd->consumed_total, + consumed, padd->frame_info.bytesconsumed); + PARA_ERROR_LOG("%s\n", NeAACDecGetErrorMessage( + padd->frame_info.error)); + consumed++; /* catch 21 */ + goto success; + } + padd->error_count = 0; + consumed += padd->frame_info.bytesconsumed; + ret = consumed; + if (!padd->frame_info.samples) + goto out; + ret = -E_AAC_OVERRUN; + if (padd->frame_info.samples * 2 + fn->loaded > fn->bufsize) + goto out; + for (i = 0; i < padd->frame_info.samples; i++) { + short *s = (short *)outbuffer; + write_int16_host_endian(fn->buf + fn->loaded, s[i]); + fn->loaded += 2; + } +success: + ret = consumed; +out: + if (ret > 0) + padd->consumed_total += ret; + return ret; +} + +static void aacdec_open(struct filter_node *fn) +{ + struct private_aacdec_data *padd = para_calloc(sizeof(*padd)); + + fn->private_data = padd; + fn->bufsize = AAC_OUTBUF_SIZE; + fn->buf = para_calloc(fn->bufsize); + padd->handle = aac_open(); +} + +static void aacdec_close(struct filter_node *fn) +{ + struct private_aacdec_data *padd = fn->private_data; + + NeAACDecClose(padd->handle); + free(fn->buf); + fn->buf = NULL; + free(padd); + fn->private_data = NULL; +} + +/** + * the init function of the aacdec filter + * + * \param f pointer to the filter struct to initialize + * + * \sa filter::init + */ +void aacdec_filter_init(struct filter *f) +{ + f->open = aacdec_open; + f->convert = aacdec; + f->close = aacdec_close; +} diff --git a/compress.c b/compress.c deleted file mode 100644 index d6f7520d..00000000 --- a/compress.c +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2005-2008 Andre Noll - * - * Licensed under the GPL v2. For licencing details see COPYING. - */ - -/** \file compress.c Paraslash's dynamic audio range compressor. */ - -/* - * Uses ideas of AudioCompress, (C) 2002-2004 M. Hari Nezumi - */ - -#include "para.h" -#include "compress_filter.cmdline.h" -#include "list.h" -#include "sched.h" -#include "filter.h" -#include "string.h" -#include "error.h" - -/** The size of the output data buffer. */ -#define COMPRESS_CHUNK_SIZE 40960 - -extern char *stat_item_values[NUM_STAT_ITEMS]; - -/** Data specific to the compress filter. */ -struct private_compress_data { - /** The current multiplier. */ - unsigned current_gain; - /** Points to the configuration data for this instance of the compress filter. */ - struct compress_filter_args_info *conf; - /** Maximal admissible gain. */ - unsigned max_gain; - /** Number of samples already seen. */ - unsigned num_samples; - /** Absolute value of the maximal sample in the current block. */ - unsigned peak; -}; - -static ssize_t compress(char *inbuf, size_t inbuf_len, struct filter_node *fn) -{ - size_t i, length = PARA_MIN((inbuf_len / 2) * 2, - (fn->bufsize - fn->loaded) / 2 * 2); - struct private_compress_data *pcd = fn->private_data; - int16_t *ip = (int16_t *)inbuf, *op = (int16_t *)(fn->buf + fn->loaded); - unsigned gain_shift = pcd->conf->inertia_arg + pcd->conf->damp_arg, - mask = (1 << pcd->conf->blocksize_arg) - 1; - - if (!length) - return 0; - for (i = 0; i < length / 2; i++) { - /* be careful in that heat, my dear */ - int sample = *ip++, adjusted_sample = (PARA_ABS(sample) * - pcd->current_gain) >> gain_shift; - if (unlikely(adjusted_sample > 32767)) { /* clip */ - PARA_NOTICE_LOG("clip: sample: %d, adjusted sample: %d\n", - sample, adjusted_sample); - adjusted_sample = 32767; - pcd->current_gain = (3 * pcd->current_gain + - (1 << pcd->conf->inertia_arg)) / 4; - pcd->peak = 0; - } else - pcd->peak = PARA_MAX(pcd->peak, adjusted_sample); - *op++ = sample >= 0? adjusted_sample : -adjusted_sample; - if (likely(++pcd->num_samples & mask)) - continue; -// PARA_DEBUG_LOG("gain: %u, peak: %u\n", pcd->current_gain, -// pcd->peak); - if (pcd->peak < pcd->conf->target_level_arg) { - if (pcd->current_gain < pcd->max_gain) - pcd->current_gain++; - } else - pcd->current_gain = PARA_MAX(pcd->current_gain - 2, - 1 << pcd->conf->inertia_arg); - pcd->peak = 0; - } - fn->loaded += length; - return length; -} - -static void close_compress(struct filter_node *fn) -{ - free(fn->private_data); - free(fn->buf); -} - -/** TODO: Add sanity checks */ -static int compress_parse_config(int argc, char **argv, void **config) -{ - int ret; - struct compress_filter_args_info *compress_conf - = para_calloc(sizeof(*compress_conf)); - - ret = -E_COMPRESS_SYNTAX; - if (compress_cmdline_parser(argc, argv, compress_conf)) - goto err; - *config = compress_conf; - return 1; -err: - free(compress_conf); - return ret; -} - -static void open_compress(struct filter_node *fn) -{ - struct private_compress_data *pcd = para_calloc( - sizeof(struct private_compress_data)); - pcd->conf = fn->conf; - fn->private_data = pcd; - fn->bufsize = COMPRESS_CHUNK_SIZE; - fn->buf = para_malloc(fn->bufsize); - pcd->current_gain = 1 << pcd->conf->inertia_arg; - pcd->max_gain = 1 << (pcd->conf->inertia_arg + pcd->conf->aggressiveness_arg); -} - -/** - * The init function of the compress filter. - * - * \param f Pointer to the struct to initialize. - */ -void compress_filter_init(struct filter *f) -{ - f->open = open_compress; - f->close = close_compress; - f->convert = compress; - f->print_help = compress_cmdline_parser_print_help; - f->parse_config = compress_parse_config; -} diff --git a/compress_filter.c b/compress_filter.c new file mode 100644 index 00000000..6034ce79 --- /dev/null +++ b/compress_filter.c @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2005-2008 Andre Noll + * + * Licensed under the GPL v2. For licencing details see COPYING. + */ + +/** \file compress_filter.c Paraslash's dynamic audio range compressor. */ + +/* + * Uses ideas of AudioCompress, (C) 2002-2004 M. Hari Nezumi + */ + +#include "para.h" +#include "compress_filter.cmdline.h" +#include "list.h" +#include "sched.h" +#include "filter.h" +#include "string.h" +#include "error.h" + +/** The size of the output data buffer. */ +#define COMPRESS_CHUNK_SIZE 40960 + +extern char *stat_item_values[NUM_STAT_ITEMS]; + +/** Data specific to the compress filter. */ +struct private_compress_data { + /** The current multiplier. */ + unsigned current_gain; + /** Points to the configuration data for this instance of the compress filter. */ + struct compress_filter_args_info *conf; + /** Maximal admissible gain. */ + unsigned max_gain; + /** Number of samples already seen. */ + unsigned num_samples; + /** Absolute value of the maximal sample in the current block. */ + unsigned peak; +}; + +static ssize_t compress(char *inbuf, size_t inbuf_len, struct filter_node *fn) +{ + size_t i, length = PARA_MIN((inbuf_len / 2) * 2, + (fn->bufsize - fn->loaded) / 2 * 2); + struct private_compress_data *pcd = fn->private_data; + int16_t *ip = (int16_t *)inbuf, *op = (int16_t *)(fn->buf + fn->loaded); + unsigned gain_shift = pcd->conf->inertia_arg + pcd->conf->damp_arg, + mask = (1 << pcd->conf->blocksize_arg) - 1; + + if (!length) + return 0; + for (i = 0; i < length / 2; i++) { + /* be careful in that heat, my dear */ + int sample = *ip++, adjusted_sample = (PARA_ABS(sample) * + pcd->current_gain) >> gain_shift; + if (unlikely(adjusted_sample > 32767)) { /* clip */ + PARA_NOTICE_LOG("clip: sample: %d, adjusted sample: %d\n", + sample, adjusted_sample); + adjusted_sample = 32767; + pcd->current_gain = (3 * pcd->current_gain + + (1 << pcd->conf->inertia_arg)) / 4; + pcd->peak = 0; + } else + pcd->peak = PARA_MAX(pcd->peak, adjusted_sample); + *op++ = sample >= 0? adjusted_sample : -adjusted_sample; + if (likely(++pcd->num_samples & mask)) + continue; +// PARA_DEBUG_LOG("gain: %u, peak: %u\n", pcd->current_gain, +// pcd->peak); + if (pcd->peak < pcd->conf->target_level_arg) { + if (pcd->current_gain < pcd->max_gain) + pcd->current_gain++; + } else + pcd->current_gain = PARA_MAX(pcd->current_gain - 2, + 1 << pcd->conf->inertia_arg); + pcd->peak = 0; + } + fn->loaded += length; + return length; +} + +static void close_compress(struct filter_node *fn) +{ + free(fn->private_data); + free(fn->buf); +} + +/** TODO: Add sanity checks */ +static int compress_parse_config(int argc, char **argv, void **config) +{ + int ret; + struct compress_filter_args_info *compress_conf + = para_calloc(sizeof(*compress_conf)); + + ret = -E_COMPRESS_SYNTAX; + if (compress_cmdline_parser(argc, argv, compress_conf)) + goto err; + *config = compress_conf; + return 1; +err: + free(compress_conf); + return ret; +} + +static void open_compress(struct filter_node *fn) +{ + struct private_compress_data *pcd = para_calloc( + sizeof(struct private_compress_data)); + pcd->conf = fn->conf; + fn->private_data = pcd; + fn->bufsize = COMPRESS_CHUNK_SIZE; + fn->buf = para_malloc(fn->bufsize); + pcd->current_gain = 1 << pcd->conf->inertia_arg; + pcd->max_gain = 1 << (pcd->conf->inertia_arg + pcd->conf->aggressiveness_arg); +} + +/** + * The init function of the compress filter. + * + * \param f Pointer to the struct to initialize. + */ +void compress_filter_init(struct filter *f) +{ + f->open = open_compress; + f->close = close_compress; + f->convert = compress; + f->print_help = compress_cmdline_parser_print_help; + f->parse_config = compress_parse_config; +} diff --git a/configure.ac b/configure.ac index cb6ecd65..7cba9450 100644 --- a/configure.ac +++ b/configure.ac @@ -81,7 +81,7 @@ AC_CHECK_FUNCS([atexit dup2 memchr memmove memset \ all_errlist_objs="server mp3_afh afh_common vss command net string signal time daemon stat crypt http_send close_on_fork ipc acl afh fade amp_filter dccp_send fd user_list chunk_queue afs osl aft mood score attribute blob ringbuffer -playlist sha1 rbtree sched audiod grab_client filter_chain wav compress +playlist sha1 rbtree sched audiod grab_client filter_chain wav_filter compress_filter http_recv dccp_recv recv_common write_common file_write audiod_command client_common recv stdout filter stdin audioc write client fsck exec send_common" @@ -96,7 +96,7 @@ receivers=" http dccp" senders=" http dccp" filter_cmdline_objs="filter.cmdline compress_filter.cmdline amp_filter.cmdline" -filter_errlist_objs="filter_chain wav compress filter string stdin stdout sched fd amp_filter" +filter_errlist_objs="filter_chain wav_filter compress_filter filter string stdin stdout sched fd amp_filter" filter_ldflags="" filters=" compress wav amp" @@ -108,7 +108,7 @@ audiod_cmdline_objs="audiod.cmdline grab_client.cmdline compress_filter.cmdline http_recv.cmdline dccp_recv.cmdline file_write.cmdline client.cmdline audiod_command_list amp_filter.cmdline" audiod_errlist_objs="audiod signal string daemon stat net - time grab_client filter_chain wav compress amp_filter http_recv dccp_recv + time grab_client filter_chain wav_filter compress_filter amp_filter http_recv dccp_recv recv_common fd sched write_common file_write audiod_command crypt client_common" audiod_ldflags="" @@ -316,7 +316,7 @@ AC_CHECK_LIB([ogg], [ogg_stream_init], [], [ have_ogg="no" ]) AC_CHECK_LIB([vorbis], [vorbis_info_init], [], [ have_ogg="no" ]) AC_CHECK_HEADERS([ogg/ogg.h vorbis/codec.h], [], [ have_ogg="no" ]) if test "$have_ogg" = "yes"; then - all_errlist_objs="$all_errlist_objs oggdec ogg_afh" + all_errlist_objs="$all_errlist_objs oggdec_filter ogg_afh" AC_DEFINE(HAVE_OGGVORBIS, 1, define to 1 to turn on ogg vorbis support) filters="$filters oggdec" if test "$OSTYPE" = "Darwin"; then @@ -331,8 +331,8 @@ if test "$have_ogg" = "yes"; then audiod_cmdline_objs="$audiod_cmdline_objs oggdec_filter.cmdline" server_errlist_objs="$server_errlist_objs ogg_afh" - filter_errlist_objs="$filter_errlist_objs oggdec" - audiod_errlist_objs="$audiod_errlist_objs oggdec" + filter_errlist_objs="$filter_errlist_objs oggdec_filter" + audiod_errlist_objs="$audiod_errlist_objs oggdec_filter" afh_errlist_objs="$afh_errlist_objs ogg_afh" audiod_audio_formats="ogg" @@ -366,10 +366,10 @@ AC_CHECK_HEADER(neaacdec.h, [], have_faad=no) AC_CHECK_LIB([faad], [NeAACDecOpen], [], have_faad=no) if test "$have_faad" = "yes"; then AC_DEFINE(HAVE_FAAD, 1, define to 1 if you want to build the aacdec filter) - all_errlist_objs="$all_errlist_objs aac_common aacdec aac_afh" - filter_errlist_objs="$filter_errlist_objs aacdec aac_common" + all_errlist_objs="$all_errlist_objs aac_common aacdec_filter aac_afh" + filter_errlist_objs="$filter_errlist_objs aacdec_filter aac_common" afh_errlist_objs="$afh_errlist_objs aac_common aac_afh" - audiod_errlist_objs="$audiod_errlist_objs aacdec aac_common" + audiod_errlist_objs="$audiod_errlist_objs aacdec_filter aac_common" server_errlist_objs="$server_errlist_objs aac_afh aac_common" server_ldflags="$server_ldflags $faad_libs -lfaad" filter_ldflags="$filter_ldflags $faad_libs -lfaad" @@ -412,9 +412,9 @@ AC_CHECK_LIB([mad], [mad_stream_init], [], [ ]) if test "$have_mad" = "yes"; then AC_DEFINE(HAVE_MAD, 1, define to 1 if you want to build the mp3dec filter) - all_errlist_objs="$all_errlist_objs mp3dec" - filter_errlist_objs="$filter_errlist_objs mp3dec" - audiod_errlist_objs="$audiod_errlist_objs mp3dec" + all_errlist_objs="$all_errlist_objs mp3dec_filter" + filter_errlist_objs="$filter_errlist_objs mp3dec_filter" + audiod_errlist_objs="$audiod_errlist_objs mp3dec_filter" filter_ldflags="$filter_ldflags $mad_libs -lmad" audiod_ldflags="$audiod_ldflags $mad_libs -lmad" audiod_audio_formats="$audiod_audio_formats mp3" diff --git a/error.h b/error.h index cacc83e9..92aaff5d 100644 --- a/error.h +++ b/error.h @@ -13,7 +13,7 @@ DEFINE_ERRLIST_OBJECT_ENUM; /* these do not need error handling (yet) */ #define SERVER_ERRORS -#define WAV_ERRORS +#define WAV_FILTER_ERRORS #define TIME_ERRORS #define CLOSE_ON_FORK_ERRORS #define DAEMON_ERRORS @@ -32,7 +32,7 @@ DEFINE_ERRLIST_OBJECT_ENUM; extern const char **para_errlist[]; -#define COMPRESS_ERRORS \ +#define COMPRESS_FILTER_ERRORS \ PARA_ERROR(COMPRESS_SYNTAX, "syntax error in compress filter config"), \ @@ -251,7 +251,7 @@ extern const char **para_errlist[]; PARA_ERROR(UNKNOWN_STAT_ITEM, "status item not recognized"), \ -#define OGGDEC_ERRORS \ +#define OGGDEC_FILTER_ERRORS \ PARA_ERROR(OGGDEC_READ, "read from media returned an error"), \ PARA_ERROR(OGGDEC_NOTVORBIS, "bitstream is not vorbis data"), \ PARA_ERROR(OGGDEC_VERSION, "vorbis version mismatch"), \ @@ -271,7 +271,7 @@ extern const char **para_errlist[]; PARA_ERROR(GC_VERSION_GIVEN, ""), /* not really an error */ \ -#define MP3DEC_ERRORS \ +#define MP3DEC_FILTER_ERRORS \ PARA_ERROR(MAD_FRAME_DECODE, "mad frame decode error"), \ PARA_ERROR(MP3DEC_OVERRUN, "mp3 output buffer overrun"), \ @@ -398,7 +398,7 @@ extern const char **para_errlist[]; PARA_ERROR(WRITE_COMMON_SYNTAX, "syntax error in write option"), \ -#define AACDEC_ERRORS \ +#define AACDEC_FILTER_ERRORS \ PARA_ERROR(AACDEC_INIT, "failed to init aac decoder"), \ PARA_ERROR(AAC_DECODE, "aac decode error"), \ PARA_ERROR(AAC_OVERRUN, "aac output buffer overrun"), \ diff --git a/filter.h b/filter.h index 2a75b186..3425ae85 100644 --- a/filter.h +++ b/filter.h @@ -143,7 +143,7 @@ struct filter_callback { * Note: As several instances of the same filter may be running at the same * time, all these filter functions must be reentrant; no static non-constant * variables may be used. - * \sa mp3dec.c, oggdec.c, wav.c, compress.c, filter_node + * \sa mp3dec_filter.c, oggdec_filter.c, wav_filter.c, compress_filter.c, filter_node */ struct filter { /** The name of the filter. */ diff --git a/mp3dec.c b/mp3dec.c deleted file mode 100644 index 599d8a90..00000000 --- a/mp3dec.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) 2005-2008 Andre Noll - * - * Licensed under the GPL v2. For licencing details see COPYING. - */ - -/** \file mp3dec.c Paraslash's mp3 decoder. */ - -#include "para.h" -#include "list.h" -#include "sched.h" -#include "filter.h" -#include "error.h" -#include -#include "string.h" - -/** The output buffer size. */ -#define MP3_OUTBUF_SIZE (128 * 1024) - -/** Convert a sample value from libmad to a signed short. */ -#define MAD_TO_SHORT(f) (f) >= MAD_F_ONE? SHRT_MAX :\ - (f) <= -MAD_F_ONE? -SHRT_MAX : (signed short) ((f) >> (MAD_F_FRACBITS - 15)) - -/** Data specific to the mp3dec filter. */ -struct private_mp3dec_data { - /** Information on the current mp3 stream. */ - struct mad_stream stream; - /** Information about the frame which is currently decoded. */ - struct mad_frame frame; - /** Contains the PCM output. */ - struct mad_synth synth; -}; - -static ssize_t mp3dec(char *inbuffer, size_t len, struct filter_node *fn) -{ - int i, ret; - struct private_mp3dec_data *pmd = fn->private_data; - size_t copy = PARA_MIN(len, 4096); - - if (fn->loaded > fn->bufsize * 4 / 5) - return 0; - mad_stream_buffer(&pmd->stream, (unsigned char *) inbuffer, copy); - pmd->stream.error = 0; -next_frame: - ret = mad_header_decode(&pmd->frame.header, &pmd->stream); - if (ret < 0) { - if (pmd->stream.error != MAD_ERROR_BUFLEN && - pmd->stream.error != MAD_ERROR_LOSTSYNC) - PARA_DEBUG_LOG("header decode: %s\n", - mad_stream_errorstr(&pmd->stream)); - goto out; - } - fn->fc->samplerate = pmd->frame.header.samplerate; - fn->fc->channels = MAD_NCHANNELS(&pmd->frame.header); - ret = mad_frame_decode(&pmd->frame, &pmd->stream); - if (ret) { - if (MAD_RECOVERABLE(pmd->stream.error) || - pmd->stream.error == MAD_ERROR_BUFLEN) { - PARA_DEBUG_LOG("frame decode: %s\n", - mad_stream_errorstr(&pmd->stream)); - goto out; - } - PARA_ERROR_LOG("frame decode: %s\n", - mad_stream_errorstr(&pmd->stream)); - return -E_MAD_FRAME_DECODE; - } - mad_synth_frame(&pmd->synth, &pmd->frame); - - for (i = 0; i < pmd->synth.pcm.length; i++) { - int s = MAD_TO_SHORT(pmd->synth.pcm.samples[0][i]); - write_int16_host_endian(fn->buf + fn->loaded, s); - fn->loaded += 2; - if (MAD_NCHANNELS(&pmd->frame.header) == 2) { /* stereo */ - s = MAD_TO_SHORT(pmd->synth.pcm.samples[1][i]); - write_int16_host_endian(fn->buf + fn->loaded, s); - fn->loaded += 2; - } - if (fn->loaded != fn->bufsize) /* output buffer not full */ - continue; - PARA_ERROR_LOG("output buffer full: %zd\n", fn->loaded); - return -E_MP3DEC_OVERRUN; - } - if (fn->loaded <= fn->bufsize * 4 / 5) - goto next_frame; -out: - if (pmd->stream.next_frame) { /* we still have some data */ - size_t off = pmd->stream.bufend - pmd->stream.next_frame; -// PARA_INFO_LOG("off: %zd, rate: %u, returning %zd\n", off, -// fn->fc->samplerate, copy - off); - return copy - off; - } - return copy; -} - -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(fn->buf); - fn->buf = NULL; - free(pmd); - fn->private_data = NULL; -} - -static void mp3dec_open(struct filter_node *fn) -{ - struct private_mp3dec_data *pmd = para_calloc(sizeof(*pmd)); - - fn->private_data = pmd; - mad_stream_init(&pmd->stream); - mad_frame_init(&pmd->frame); - mad_synth_init(&pmd->synth); - fn->loaded = 0; - fn->bufsize = MP3_OUTBUF_SIZE; - fn->buf = para_calloc(fn->bufsize); -} - -/** - * The init function of the mp3dec filter. - * - * \param f Pointer to the filter struct to initialize. - * - * \sa filter::init. - */ -void mp3dec_filter_init(struct filter *f) -{ - f->open = mp3dec_open; - f->convert = mp3dec; - f->close = mp3dec_close; -} diff --git a/mp3dec_filter.c b/mp3dec_filter.c new file mode 100644 index 00000000..50e530e1 --- /dev/null +++ b/mp3dec_filter.c @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2005-2008 Andre Noll + * + * Licensed under the GPL v2. For licencing details see COPYING. + */ + +/** \file mp3dec_filter.c Paraslash's mp3 decoder. */ + +#include "para.h" +#include "list.h" +#include "sched.h" +#include "filter.h" +#include "error.h" +#include +#include "string.h" + +/** The output buffer size. */ +#define MP3_OUTBUF_SIZE (128 * 1024) + +/** Convert a sample value from libmad to a signed short. */ +#define MAD_TO_SHORT(f) (f) >= MAD_F_ONE? SHRT_MAX :\ + (f) <= -MAD_F_ONE? -SHRT_MAX : (signed short) ((f) >> (MAD_F_FRACBITS - 15)) + +/** Data specific to the mp3dec filter. */ +struct private_mp3dec_data { + /** Information on the current mp3 stream. */ + struct mad_stream stream; + /** Information about the frame which is currently decoded. */ + struct mad_frame frame; + /** Contains the PCM output. */ + struct mad_synth synth; +}; + +static ssize_t mp3dec(char *inbuffer, size_t len, struct filter_node *fn) +{ + int i, ret; + struct private_mp3dec_data *pmd = fn->private_data; + size_t copy = PARA_MIN(len, 4096); + + if (fn->loaded > fn->bufsize * 4 / 5) + return 0; + mad_stream_buffer(&pmd->stream, (unsigned char *) inbuffer, copy); + pmd->stream.error = 0; +next_frame: + ret = mad_header_decode(&pmd->frame.header, &pmd->stream); + if (ret < 0) { + if (pmd->stream.error != MAD_ERROR_BUFLEN && + pmd->stream.error != MAD_ERROR_LOSTSYNC) + PARA_DEBUG_LOG("header decode: %s\n", + mad_stream_errorstr(&pmd->stream)); + goto out; + } + fn->fc->samplerate = pmd->frame.header.samplerate; + fn->fc->channels = MAD_NCHANNELS(&pmd->frame.header); + ret = mad_frame_decode(&pmd->frame, &pmd->stream); + if (ret) { + if (MAD_RECOVERABLE(pmd->stream.error) || + pmd->stream.error == MAD_ERROR_BUFLEN) { + PARA_DEBUG_LOG("frame decode: %s\n", + mad_stream_errorstr(&pmd->stream)); + goto out; + } + PARA_ERROR_LOG("frame decode: %s\n", + mad_stream_errorstr(&pmd->stream)); + return -E_MAD_FRAME_DECODE; + } + mad_synth_frame(&pmd->synth, &pmd->frame); + + for (i = 0; i < pmd->synth.pcm.length; i++) { + int s = MAD_TO_SHORT(pmd->synth.pcm.samples[0][i]); + write_int16_host_endian(fn->buf + fn->loaded, s); + fn->loaded += 2; + if (MAD_NCHANNELS(&pmd->frame.header) == 2) { /* stereo */ + s = MAD_TO_SHORT(pmd->synth.pcm.samples[1][i]); + write_int16_host_endian(fn->buf + fn->loaded, s); + fn->loaded += 2; + } + if (fn->loaded != fn->bufsize) /* output buffer not full */ + continue; + PARA_ERROR_LOG("output buffer full: %zd\n", fn->loaded); + return -E_MP3DEC_OVERRUN; + } + if (fn->loaded <= fn->bufsize * 4 / 5) + goto next_frame; +out: + if (pmd->stream.next_frame) { /* we still have some data */ + size_t off = pmd->stream.bufend - pmd->stream.next_frame; +// PARA_INFO_LOG("off: %zd, rate: %u, returning %zd\n", off, +// fn->fc->samplerate, copy - off); + return copy - off; + } + return copy; +} + +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(fn->buf); + fn->buf = NULL; + free(pmd); + fn->private_data = NULL; +} + +static void mp3dec_open(struct filter_node *fn) +{ + struct private_mp3dec_data *pmd = para_calloc(sizeof(*pmd)); + + fn->private_data = pmd; + mad_stream_init(&pmd->stream); + mad_frame_init(&pmd->frame); + mad_synth_init(&pmd->synth); + fn->loaded = 0; + fn->bufsize = MP3_OUTBUF_SIZE; + fn->buf = para_calloc(fn->bufsize); +} + +/** + * The init function of the mp3dec filter. + * + * \param f Pointer to the filter struct to initialize. + * + * \sa filter::init. + */ +void mp3dec_filter_init(struct filter *f) +{ + f->open = mp3dec_open; + f->convert = mp3dec; + f->close = mp3dec_close; +} diff --git a/oggdec.c b/oggdec.c deleted file mode 100644 index b4befd01..00000000 --- a/oggdec.c +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (C) 2005-2008 Andre Noll - * - * Licensed under the GPL v2. For licencing details see COPYING. - */ - -/** \file oggdec.c Paraslash's ogg vorbis decoder. */ - -#include "para.h" - -#include "oggdec_filter.cmdline.h" -#include "list.h" -#include "sched.h" -#include "filter.h" -#include "error.h" -#include "string.h" - -#include - -/** Determine byte sex. */ -#ifdef WORDS_BIGENDIAN -#define ENDIAN 1 -#else -#define ENDIAN 0 -#endif - -/** Data specific to the oggdec filter. */ -struct private_oggdec_data { - /** Describes an ogg vorbis file. */ - OggVorbis_File *vf; - /** The input buffer. */ - char *inbuf; - /** The length of \a inbuf. */ - size_t inbuf_len; - /** The number of bytes consumed from the input buffer. */ - size_t converted; -}; - -static size_t cb_read(void *buf, size_t size, size_t nmemb, void *datasource) -{ - struct filter_node *fn = datasource; - struct private_oggdec_data *pod = fn->private_data; - size_t ret, have = pod->inbuf_len - pod->converted; - char *p = pod->inbuf + pod->converted; - -// PARA_DEBUG_LOG("pod = %p\n", pod); -// PARA_DEBUG_LOG("vorbis requests %d bytes, have %d\n", size * nmemb, have); - if (pod->inbuf_len < size) { - if (*fn->fc->input_error) - return 0; - errno = EAGAIN; - return (size_t)-1; - } - ret = PARA_MIN(nmemb, have / size) * size; - memcpy(buf, p, ret); - pod->converted += ret; - return ret; -} - -/* - * Custom data seeking function. - * - * Since we want the data source to be treated as unseekable at all - * times, the provided seek callback always returns -1 (failure). - */ -static int cb_seek(__a_unused void *datasource, __a_unused ogg_int64_t offset, - __a_unused int whence) -{ - return -1; -} - -static int cb_close(__a_unused void *datasource) -{ - return 0; -} - -static const ov_callbacks ovc = { - .read_func = cb_read, - .seek_func = cb_seek, - .close_func = cb_close, - /* - * The tell function need not be provided if the data IO abstraction is - * not seekable - */ - .tell_func = NULL -}; - -static void ogg_open(struct filter_node *fn) -{ - struct private_oggdec_data *pod = para_calloc( - sizeof(struct private_oggdec_data)); - struct oggdec_filter_args_info *conf = fn->conf; - - fn->private_data = pod; - fn->bufsize = conf->bufsize_arg * 1024; - fn->buf = para_malloc(fn->bufsize); -} - -static void ogg_close(struct filter_node *fn) -{ - struct private_oggdec_data *pod = fn->private_data; - if (pod->vf) { - PARA_DEBUG_LOG("ov_clearing %p, pod = %p\n", pod->vf, pod); - ov_clear(pod->vf); - free(pod->vf); - pod->vf = NULL; - } else - PARA_DEBUG_LOG("nothing to close in fc %p, pod = %p\n", pod->vf, pod); - free(fn->buf); - fn->buf = NULL; - free(fn->private_data); - fn->private_data = NULL; -} - -static ssize_t ogg_convert(char *inbuffer, size_t len, struct filter_node *fn) -{ - ssize_t ret; - struct private_oggdec_data *pod = fn->private_data; - struct oggdec_filter_args_info *conf = fn->conf; - /* make the buffer known to the read callback cb_read() */ - pod->inbuf = inbuffer; - pod->inbuf_len = len; - pod->converted = 0; - - if (!pod->vf) { - int ib = 1024 * conf->initial_buffer_arg; /* initial buffer */ - if (len fc->input_error) { - PARA_DEBUG_LOG("initial input buffer %zd/%d, " - "waiting for more data\n", len, ib); - return 0; - } - pod->vf = para_malloc(sizeof(struct OggVorbis_File)); - PARA_NOTICE_LOG("input buffer: %zd, opening ov callbacks\n", len); - ret = ov_open_callbacks(fn, pod->vf, - NULL, /* no initial buffer */ - 0, /* no initial bytes */ - ovc); /* the ov_open_callbacks */ - if (ret == OV_EREAD) - return -E_OGGDEC_READ; - if (ret == OV_ENOTVORBIS) - return -E_OGGDEC_NOTVORBIS; - if (ret == OV_EVERSION) - return -E_OGGDEC_VERSION; - if (ret == OV_EBADHEADER) - return -E_OGGDEC_BADHEADER; - if (ret < 0) - return -E_OGGDEC_FAULT; - fn->fc->channels = ov_info(pod->vf, 0)->channels; - fn->fc->samplerate = ov_info(pod->vf, 0)->rate; - PARA_NOTICE_LOG("%d channels, %d Hz\n", fn->fc->channels, - fn->fc->samplerate); - } - while (fn->loaded < fn->bufsize) { - int length = fn->bufsize - fn->loaded; - long read_ret = ov_read(pod->vf, fn->buf + fn->loaded, length, - ENDIAN, 2 /* 16 bit */, 1 /* signed */, NULL); - if (read_ret == OV_HOLE || !read_ret) - return pod->converted; - if (read_ret < 0) - return -E_OGGDEC_BADLINK; - fn->loaded += read_ret; - } - return pod->converted; -} - -static int oggdec_parse_config(int argc, char **argv, void **config) -{ - int ret; - struct oggdec_filter_args_info *ogg_conf; - - ogg_conf = para_calloc(sizeof(*ogg_conf)); - ret = -E_OGGDEC_SYNTAX; - if (oggdec_cmdline_parser(argc, argv, ogg_conf)) - goto err; - ret = -ERRNO_TO_PARA_ERROR(EINVAL); - if (ogg_conf->bufsize_arg < 0) - goto err; - if (ogg_conf->bufsize_arg >= INT_MAX / 1024) - goto err; - if (ogg_conf->initial_buffer_arg < 0) - goto err; - if (ogg_conf->initial_buffer_arg >= INT_MAX / 1024) - goto err; - *config = ogg_conf; - return 1; -err: - free(ogg_conf); - return ret; -} - -/** - * The init function of the ogg vorbis decoder. - * - * \param f Its fields are filled in by the function. - */ -void oggdec_filter_init(struct filter *f) -{ - f->open = ogg_open; - f->close = ogg_close; - f->convert = ogg_convert; - f->print_help = oggdec_cmdline_parser_print_help; - f->parse_config = oggdec_parse_config; -} diff --git a/oggdec_filter.c b/oggdec_filter.c new file mode 100644 index 00000000..689fc7aa --- /dev/null +++ b/oggdec_filter.c @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2005-2008 Andre Noll + * + * Licensed under the GPL v2. For licencing details see COPYING. + */ + +/** \file oggdec_filter.c Paraslash's ogg vorbis decoder. */ + +#include "para.h" + +#include "oggdec_filter.cmdline.h" +#include "list.h" +#include "sched.h" +#include "filter.h" +#include "error.h" +#include "string.h" + +#include + +/** Determine byte sex. */ +#ifdef WORDS_BIGENDIAN +#define ENDIAN 1 +#else +#define ENDIAN 0 +#endif + +/** Data specific to the oggdec filter. */ +struct private_oggdec_data { + /** Describes an ogg vorbis file. */ + OggVorbis_File *vf; + /** The input buffer. */ + char *inbuf; + /** The length of \a inbuf. */ + size_t inbuf_len; + /** The number of bytes consumed from the input buffer. */ + size_t converted; +}; + +static size_t cb_read(void *buf, size_t size, size_t nmemb, void *datasource) +{ + struct filter_node *fn = datasource; + struct private_oggdec_data *pod = fn->private_data; + size_t ret, have = pod->inbuf_len - pod->converted; + char *p = pod->inbuf + pod->converted; + +// PARA_DEBUG_LOG("pod = %p\n", pod); +// PARA_DEBUG_LOG("vorbis requests %d bytes, have %d\n", size * nmemb, have); + if (pod->inbuf_len < size) { + if (*fn->fc->input_error) + return 0; + errno = EAGAIN; + return (size_t)-1; + } + ret = PARA_MIN(nmemb, have / size) * size; + memcpy(buf, p, ret); + pod->converted += ret; + return ret; +} + +/* + * Custom data seeking function. + * + * Since we want the data source to be treated as unseekable at all + * times, the provided seek callback always returns -1 (failure). + */ +static int cb_seek(__a_unused void *datasource, __a_unused ogg_int64_t offset, + __a_unused int whence) +{ + return -1; +} + +static int cb_close(__a_unused void *datasource) +{ + return 0; +} + +static const ov_callbacks ovc = { + .read_func = cb_read, + .seek_func = cb_seek, + .close_func = cb_close, + /* + * The tell function need not be provided if the data IO abstraction is + * not seekable + */ + .tell_func = NULL +}; + +static void ogg_open(struct filter_node *fn) +{ + struct private_oggdec_data *pod = para_calloc( + sizeof(struct private_oggdec_data)); + struct oggdec_filter_args_info *conf = fn->conf; + + fn->private_data = pod; + fn->bufsize = conf->bufsize_arg * 1024; + fn->buf = para_malloc(fn->bufsize); +} + +static void ogg_close(struct filter_node *fn) +{ + struct private_oggdec_data *pod = fn->private_data; + if (pod->vf) { + PARA_DEBUG_LOG("ov_clearing %p, pod = %p\n", pod->vf, pod); + ov_clear(pod->vf); + free(pod->vf); + pod->vf = NULL; + } else + PARA_DEBUG_LOG("nothing to close in fc %p, pod = %p\n", pod->vf, pod); + free(fn->buf); + fn->buf = NULL; + free(fn->private_data); + fn->private_data = NULL; +} + +static ssize_t ogg_convert(char *inbuffer, size_t len, struct filter_node *fn) +{ + ssize_t ret; + struct private_oggdec_data *pod = fn->private_data; + struct oggdec_filter_args_info *conf = fn->conf; + /* make the buffer known to the read callback cb_read() */ + pod->inbuf = inbuffer; + pod->inbuf_len = len; + pod->converted = 0; + + if (!pod->vf) { + int ib = 1024 * conf->initial_buffer_arg; /* initial buffer */ + if (len fc->input_error) { + PARA_DEBUG_LOG("initial input buffer %zd/%d, " + "waiting for more data\n", len, ib); + return 0; + } + pod->vf = para_malloc(sizeof(struct OggVorbis_File)); + PARA_NOTICE_LOG("input buffer: %zd, opening ov callbacks\n", len); + ret = ov_open_callbacks(fn, pod->vf, + NULL, /* no initial buffer */ + 0, /* no initial bytes */ + ovc); /* the ov_open_callbacks */ + if (ret == OV_EREAD) + return -E_OGGDEC_READ; + if (ret == OV_ENOTVORBIS) + return -E_OGGDEC_NOTVORBIS; + if (ret == OV_EVERSION) + return -E_OGGDEC_VERSION; + if (ret == OV_EBADHEADER) + return -E_OGGDEC_BADHEADER; + if (ret < 0) + return -E_OGGDEC_FAULT; + fn->fc->channels = ov_info(pod->vf, 0)->channels; + fn->fc->samplerate = ov_info(pod->vf, 0)->rate; + PARA_NOTICE_LOG("%d channels, %d Hz\n", fn->fc->channels, + fn->fc->samplerate); + } + while (fn->loaded < fn->bufsize) { + int length = fn->bufsize - fn->loaded; + long read_ret = ov_read(pod->vf, fn->buf + fn->loaded, length, + ENDIAN, 2 /* 16 bit */, 1 /* signed */, NULL); + if (read_ret == OV_HOLE || !read_ret) + return pod->converted; + if (read_ret < 0) + return -E_OGGDEC_BADLINK; + fn->loaded += read_ret; + } + return pod->converted; +} + +static int oggdec_parse_config(int argc, char **argv, void **config) +{ + int ret; + struct oggdec_filter_args_info *ogg_conf; + + ogg_conf = para_calloc(sizeof(*ogg_conf)); + ret = -E_OGGDEC_SYNTAX; + if (oggdec_cmdline_parser(argc, argv, ogg_conf)) + goto err; + ret = -ERRNO_TO_PARA_ERROR(EINVAL); + if (ogg_conf->bufsize_arg < 0) + goto err; + if (ogg_conf->bufsize_arg >= INT_MAX / 1024) + goto err; + if (ogg_conf->initial_buffer_arg < 0) + goto err; + if (ogg_conf->initial_buffer_arg >= INT_MAX / 1024) + goto err; + *config = ogg_conf; + return 1; +err: + free(ogg_conf); + return ret; +} + +/** + * The init function of the ogg vorbis decoder. + * + * \param f Its fields are filled in by the function. + */ +void oggdec_filter_init(struct filter *f) +{ + f->open = ogg_open; + f->close = ogg_close; + f->convert = ogg_convert; + f->print_help = oggdec_cmdline_parser_print_help; + f->parse_config = oggdec_parse_config; +} diff --git a/server.c b/server.c index 91568764..459f4462 100644 --- a/server.c +++ b/server.c @@ -23,8 +23,8 @@ * The gory details, listed by topic: * * - Audio format handlers: \ref send_common.c \ref mp3_afh.c, \ref ogg_afh.c, \ref aac_afh.c, - * - Decoders: \ref mp3dec.c, \ref oggdec.c, \ref aacdec.c, - * - Volume normalizer: \ref compress.c, + * - Decoders: \ref mp3dec_filter.c, \ref oggdec_filter.c, \ref aacdec_filter.c, + * - Volume normalizer: \ref compress_filter.c, * - Output: \ref alsa_write.c, \ref osx_write.c, * - http: \ref http_recv.c, \ref http_send.c, * - ortp: \ref ortp_recv.c, \ref ortp_send.c, diff --git a/wav.c b/wav.c deleted file mode 100644 index ad3458d1..00000000 --- a/wav.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) 2005-2008 Andre Noll - * - * Licensed under the GPL v2. For licencing details see COPYING. - */ - -/** \file wav.c a filter that inserts a wave header */ - -#include "para.h" - -#include "list.h" -#include "sched.h" -#include "filter.h" -#include "string.h" - -/** size of the output buffer */ -#define WAV_OUTBUF_SIZE 81920 -/** a wav header is always 44 bytes */ -#define WAV_HEADER_LEN 44 -/** always write 16 bit header */ -#define BITS 16 - -/** - * write a 32 bit unsigned value to a buffer - * - * \param buf the buffer to write to - * \param x the value to write - */ -#define WRITE_U32(buf, x) (buf)[0] = (unsigned char)((x) & 0xff);\ - (buf)[1] = (unsigned char)(((x) >> 8) & 0xff);\ - (buf)[2] = (unsigned char)(((x) >> 16) & 0xff);\ - (buf)[3] = (unsigned char)(((x) >> 24) & 0xff); - -/** - * write a 16 bit unsigned value to a buffer - * - * \param buf the buffer to write to - * \param x the value to write - */ -#define WRITE_U16(buf, x) (buf)[0] = (unsigned char)((x) & 0xff); - -static void make_wav_header(unsigned int channels, unsigned int samplerate, - struct filter_node *fn) -{ - - char *headbuf = fn->buf; - unsigned int size = 0x7fffffff; - int bytespersec = channels * samplerate * BITS / 8; - int align = channels * BITS / 8; - - assert(channels); - PARA_DEBUG_LOG("writing wave header: %d channels, %d KHz\n", channels, samplerate); - memset(headbuf, 0, WAV_HEADER_LEN); - memcpy(headbuf, "RIFF", 4); - WRITE_U32(headbuf + 4, size - 8); - memcpy(headbuf + 8, "WAVE", 4); - memcpy(headbuf + 12, "fmt ", 4); - WRITE_U32(headbuf + 16, 16); - WRITE_U16(headbuf + 20, 1); /* format */ - WRITE_U16(headbuf + 22, channels); - WRITE_U32(headbuf + 24, samplerate); - WRITE_U32(headbuf + 28, bytespersec); - WRITE_U16(headbuf + 32, align); - WRITE_U16(headbuf + 34, BITS); - memcpy(headbuf + 36, "data", 4); - WRITE_U32(headbuf + 40, size - 44); -} - -static ssize_t wav_convert(char *inbuf, size_t len, struct filter_node *fn) -{ - size_t copy; - int *bof = fn->private_data; - - if (*bof) { - if (!len) - return 0; - make_wav_header(fn->fc->channels, fn->fc->samplerate, fn); - fn->loaded = WAV_HEADER_LEN; - *bof = 0; -// return 0; - } - copy = PARA_MIN(len, fn->bufsize - fn->loaded); - memmove(fn->buf + fn->loaded, inbuf, copy); - fn->loaded += copy; -// PARA_DEBUG_LOG("len = %d, copy = %d\n", len, copy); - return copy; -} - -static void wav_close(struct filter_node *fn) -{ - free(fn->buf); - fn->buf = NULL; - free(fn->private_data); - fn->private_data = NULL; -} - -static void wav_open(struct filter_node *fn) -{ - int *bof; - - fn->bufsize = WAV_OUTBUF_SIZE; - fn->buf = para_malloc(fn->bufsize); - fn->private_data = para_malloc(sizeof(int)); - bof = fn->private_data; - fn->loaded = 0; - *bof = 1; - PARA_INFO_LOG("wav filter node: %p, output buffer: %p, loaded: %zd\n", - fn, fn->buf, fn->loaded); -} - -/** - * the init function of the wav filter - * - * \param f struct to initialize - */ -void wav_filter_init(struct filter *f) -{ - f->convert = wav_convert; - f->close = wav_close; - f->open = wav_open; -} diff --git a/wav_filter.c b/wav_filter.c new file mode 100644 index 00000000..242cb4bb --- /dev/null +++ b/wav_filter.c @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2005-2008 Andre Noll + * + * Licensed under the GPL v2. For licencing details see COPYING. + */ + +/** \file wav_filter.c A filter that inserts a wave header. */ + +#include "para.h" + +#include "list.h" +#include "sched.h" +#include "filter.h" +#include "string.h" + +/** size of the output buffer */ +#define WAV_OUTBUF_SIZE 81920 +/** a wav header is always 44 bytes */ +#define WAV_HEADER_LEN 44 +/** always write 16 bit header */ +#define BITS 16 + +/** + * write a 32 bit unsigned value to a buffer + * + * \param buf the buffer to write to + * \param x the value to write + */ +#define WRITE_U32(buf, x) (buf)[0] = (unsigned char)((x) & 0xff);\ + (buf)[1] = (unsigned char)(((x) >> 8) & 0xff);\ + (buf)[2] = (unsigned char)(((x) >> 16) & 0xff);\ + (buf)[3] = (unsigned char)(((x) >> 24) & 0xff); + +/** + * write a 16 bit unsigned value to a buffer + * + * \param buf the buffer to write to + * \param x the value to write + */ +#define WRITE_U16(buf, x) (buf)[0] = (unsigned char)((x) & 0xff); + +static void make_wav_header(unsigned int channels, unsigned int samplerate, + struct filter_node *fn) +{ + + char *headbuf = fn->buf; + unsigned int size = 0x7fffffff; + int bytespersec = channels * samplerate * BITS / 8; + int align = channels * BITS / 8; + + assert(channels); + PARA_DEBUG_LOG("writing wave header: %d channels, %d KHz\n", channels, samplerate); + memset(headbuf, 0, WAV_HEADER_LEN); + memcpy(headbuf, "RIFF", 4); + WRITE_U32(headbuf + 4, size - 8); + memcpy(headbuf + 8, "WAVE", 4); + memcpy(headbuf + 12, "fmt ", 4); + WRITE_U32(headbuf + 16, 16); + WRITE_U16(headbuf + 20, 1); /* format */ + WRITE_U16(headbuf + 22, channels); + WRITE_U32(headbuf + 24, samplerate); + WRITE_U32(headbuf + 28, bytespersec); + WRITE_U16(headbuf + 32, align); + WRITE_U16(headbuf + 34, BITS); + memcpy(headbuf + 36, "data", 4); + WRITE_U32(headbuf + 40, size - 44); +} + +static ssize_t wav_convert(char *inbuf, size_t len, struct filter_node *fn) +{ + size_t copy; + int *bof = fn->private_data; + + if (*bof) { + if (!len) + return 0; + make_wav_header(fn->fc->channels, fn->fc->samplerate, fn); + fn->loaded = WAV_HEADER_LEN; + *bof = 0; +// return 0; + } + copy = PARA_MIN(len, fn->bufsize - fn->loaded); + memmove(fn->buf + fn->loaded, inbuf, copy); + fn->loaded += copy; +// PARA_DEBUG_LOG("len = %d, copy = %d\n", len, copy); + return copy; +} + +static void wav_close(struct filter_node *fn) +{ + free(fn->buf); + fn->buf = NULL; + free(fn->private_data); + fn->private_data = NULL; +} + +static void wav_open(struct filter_node *fn) +{ + int *bof; + + fn->bufsize = WAV_OUTBUF_SIZE; + fn->buf = para_malloc(fn->bufsize); + fn->private_data = para_malloc(sizeof(int)); + bof = fn->private_data; + fn->loaded = 0; + *bof = 1; + PARA_INFO_LOG("wav filter node: %p, output buffer: %p, loaded: %zd\n", + fn, fn->buf, fn->loaded); +} + +/** + * the init function of the wav filter + * + * \param f struct to initialize + */ +void wav_filter_init(struct filter *f) +{ + f->convert = wav_convert; + f->close = wav_close; + f->open = wav_open; +}