From f43da69cf7e4ff910ffe55af76fd6d15a1b75c81 Mon Sep 17 00:00:00 2001 From: Ron Pedde Date: Sun, 27 Feb 2005 03:34:07 +0000 Subject: [PATCH] Add Timo's wavstreamer --- src/Makefile.am | 3 + src/ssc.c | 4 +- src/wavstreamer.c | 397 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 403 insertions(+), 1 deletion(-) create mode 100644 src/wavstreamer.c diff --git a/src/Makefile.am b/src/Makefile.am index f72b41b3..70be915c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,6 +5,7 @@ BUILT_SOURCES=parser.h AM_YFLAGS=-d sbin_PROGRAMS = mt-daapd +bin_PROGRAMS = wavstreamer if COND_REND_POSIX PRENDSRC=mDNS.c mDNSClientAPI.h mDNSDebug.h mDNSPosix.c mDNSUNP.c rend-posix.c mDNSPlatformFunctions.h rend-unix.c @@ -26,6 +27,8 @@ if COND_FLAC FLACSRC=flac.c endif +wavstreamer_SOURCES = wavstreamer.c + mt_daapd_SOURCES = main.c daapd.h rend.h uici.c uici.h webserver.c \ webserver.h configfile.c configfile.h err.c err.h restart.c restart.h \ daap-proto.c daap-proto.h daap.c daap.h db-gdbm.c db-memory.h \ diff --git a/src/ssc.c b/src/ssc.c index 92b9b819..f63c2f41 100644 --- a/src/ssc.c +++ b/src/ssc.c @@ -80,7 +80,7 @@ char *server_side_convert_path(char *path) int server_side_convert_set(MP3FILE *pmp3) { char *fname, *path, *description, *ext; - + DPRINTF(E_DBG,L_SCAN,"Checking for ssc: %s\n",pmp3->fname); if ((!config.ssc_extensions) || (!config.ssc_extensions[0]) || (!config.ssc_prog) || @@ -93,9 +93,11 @@ int server_side_convert_set(MP3FILE *pmp3) strlen(pmp3->fname) - strlen(SERVER_SIDE_CONVERT_SUFFIX), SERVER_SIDE_CONVERT_SUFFIX) == 0))) { + DPRINTF(E_DBG,L_SCAN,"Nope\n"); return 0; } + DPRINTF(E_DBG,L_SCAN,"Yup\n"); if (((ext = strrchr(pmp3->path, '.')) != NULL) && (strcasestr(config.ssc_extensions, ext))) { fname = (char *)malloc(strlen(pmp3->fname) + diff --git a/src/wavstreamer.c b/src/wavstreamer.c new file mode 100644 index 00000000..1b388002 --- /dev/null +++ b/src/wavstreamer.c @@ -0,0 +1,397 @@ +/* + * -*- c -*- + * + * $Id$ + * + * Read wav file from stdin and patch the info in header and write + * it to stdout. + * + * Copyright (C) 2005 Timo J. Rinne (tri@iki.fi) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +char *av0; + +struct option longopts[] = + { { "help", 0, NULL, 'h' }, + { "samples", 1, NULL, 's' }, + { "length", 1, NULL, 'l' }, + { "offset", 1, NULL, '0' }, + { NULL, 0, NULL, 0 } }; + +#define GET_WAV_INT32(p) ((((unsigned long)((p)[3])) << 24) | \ + (((unsigned long)((p)[2])) << 16) | \ + (((unsigned long)((p)[1])) << 8) | \ + (((unsigned long)((p)[0])))) + +#define GET_WAV_INT16(p) ((((unsigned long)((p)[1])) << 8) | \ + (((unsigned long)((p)[0])))) + +unsigned char *read_hdr(FILE *f, size_t *hdr_len) +{ + unsigned char *hdr; + unsigned long format_data_length; + + hdr = malloc(256); + if (hdr == NULL) + return NULL; + + if (fread(hdr, 44, 1, f) != 1) + goto fail; + + if (strncmp(hdr + 12, "fmt ", 4)) + goto fail; + + format_data_length = GET_WAV_INT32(hdr + 16); + + if ((format_data_length < 16) || (format_data_length > 100)) + goto fail; + + *hdr_len = 44; + + if (format_data_length > 16) { + if (fread(hdr + 44, format_data_length - 16, 1, f) != 1) + goto fail; + *hdr_len += format_data_length - 16; + } + + return hdr; + + fail: + if (hdr != NULL) + free(hdr); + return NULL; +} + +size_t parse_hdr(unsigned char *hdr, size_t hdr_len, + unsigned long *chunk_data_length_ret, + unsigned long *format_data_length_ret, + unsigned long *compression_code_ret, + unsigned long *channel_count_ret, + unsigned long *sample_rate_ret, + unsigned long *sample_bit_length_ret, + unsigned long *data_length_ret) +{ + unsigned long chunk_data_length; + unsigned long format_data_length; + unsigned long compression_code; + unsigned long channel_count; + unsigned long sample_rate; + unsigned long sample_bit_length; + unsigned long data_length; + + if (strncmp(hdr + 0, "RIFF", 4) || + strncmp(hdr + 8, "WAVE", 4) || + strncmp(hdr + 12, "fmt ", 4)) + return 0; + + format_data_length = GET_WAV_INT32(hdr + 16); + + if (strncmp(hdr + 20 + format_data_length, "data", 4)) + return 0; + + chunk_data_length = GET_WAV_INT32(hdr + 4); + compression_code = GET_WAV_INT16(hdr + 20); + channel_count = GET_WAV_INT16(hdr + 22); + sample_rate = GET_WAV_INT32(hdr + 24); + sample_bit_length = GET_WAV_INT16(hdr + 34); + data_length = GET_WAV_INT32(hdr + 20 + format_data_length + 4); + + if ((format_data_length != 16) || + (compression_code != 1) || + (channel_count < 1) || + (sample_rate == 0) || + (sample_rate > 512000) || + (sample_bit_length < 2)) + return 0; + + *chunk_data_length_ret = chunk_data_length; + *format_data_length_ret = format_data_length; + *compression_code_ret = compression_code; + *channel_count_ret = channel_count; + *sample_rate_ret = sample_rate; + *sample_bit_length_ret = sample_bit_length; + *data_length_ret = data_length; + + return 20 + format_data_length + 8; +} + +size_t patch_hdr(unsigned char *hdr, size_t hdr_len, + unsigned long sec, unsigned long us, + unsigned long samples, + size_t *data_length_ret) +{ + unsigned long chunk_data_length; + unsigned long format_data_length; + unsigned long compression_code; + unsigned long channel_count; + unsigned long sample_rate; + unsigned long sample_bit_length; + unsigned long data_length; + unsigned long bytes_per_sample; + + if (parse_hdr(hdr, hdr_len, + &chunk_data_length, + &format_data_length, + &compression_code, + &channel_count, + &sample_rate, + &sample_bit_length, + &data_length) != hdr_len) + return 0; + + if (hdr_len != (20 + format_data_length + 8)) + return 0; + + if (format_data_length > 16) { + memmove(hdr + 20 + 16, hdr + 20 + format_data_length, 8); + hdr[16] = 16; + hdr[17] = 0; + hdr[18] = 0; + hdr[19] = 0; + format_data_length = 16; + hdr_len = 44; + } + + bytes_per_sample = channel_count * ((sample_bit_length + 7) / 8); + + if (samples == 0) + { + samples = sample_rate * sec; + samples += ((sample_rate / 100) * (us / 10)) / 1000; + } + + if (samples > 0) { + data_length = samples * bytes_per_sample; + chunk_data_length = data_length + 36; + } else { + chunk_data_length = 0xffffffff; + data_length = chunk_data_length - 36; + } + + if (data_length_ret != NULL) + *data_length_ret = data_length; + + hdr[4] = chunk_data_length % 0x100; + hdr[5] = (chunk_data_length >> 8) % 0x100; + hdr[6] = (chunk_data_length >> 16) % 0x100; + hdr[7] = (chunk_data_length >> 24) % 0x100; + + hdr[40] = data_length % 0x100; + hdr[41] = (data_length >> 8) % 0x100; + hdr[42] = (data_length >> 16) % 0x100; + hdr[43] = (data_length >> 24) % 0x100; + + return hdr_len; +} + +static void usage(int exitval); + +static void usage(int exitval) +{ + fprintf(stderr, + "Usage: %s [ options ] [input-file]\n", av0); + fprintf(stderr, + "\n"); + fprintf(stderr, + "Options:\n"); + fprintf(stderr, + "-l len | --length=len Length of the sound file in seconds.\n"); + fprintf(stderr, + "-s len | --samples=len Length of the sound file in samples.\n"); + fprintf(stderr, + "-o offset | --offset=offset Number of bytes to discard from the stream.\n"); + fprintf(stderr, + "\n"); + fprintf(stderr, + "--samples and --length are mutually exclusive.\n"); + + exit(exitval); +} + +int main(int argc, char **argv) +{ + int c; + unsigned long sec = 0, us = 0, samples = 0; + unsigned long offset = 0; + unsigned long skip = 0; + char *end; + FILE *f; + unsigned char *hdr; + size_t hdr_len; + size_t data_len; + unsigned char buf[0x1000]; + size_t buf_len; + + if (strchr(argv[0], '/')) + av0 = strrchr(argv[0], '/') + 1; + else + av0 = argv[0]; + + while ((c = getopt_long(argc, argv, "+hl:o:s:", longopts, NULL)) != EOF) + switch(c) + { + case 'h': + usage(0); + /*NOTREACHED*/ + break; + + case 'l': + sec = strtoul(optarg, &end, 10); + if ((*optarg == '-') || (end == optarg) || ((*end != '\0') && (*end != '.'))) { + fprintf(stderr, "%s: Invalid -l argument.\n", av0); + exit(-1); + } else if (*end == '.') { + char tmp[7]; + int i; + + memset(tmp, '0', sizeof (tmp) - 1); + tmp[sizeof (tmp) - 1] = '\0'; + for (i = 0; (i < (sizeof (tmp) - 1)) && (isdigit(end[i+1])); i++) + tmp[i] = end[i+1]; + us = strtoul(tmp, NULL, 10); + } else { + us = 0; + } + if ((sec == 0) && (us == 0)) { + fprintf(stderr, "%s: Invalid -l argument (zero is not acceptable).\n", av0); + exit(-1); + } + if (samples != 0) { + fprintf(stderr, "%s: Parameters -s and -l are mutually exclusive.\n", av0); + exit(-1); + } + break; + + case 's': + samples = strtoul(optarg, &end, 10); + if ((*optarg == '-') || (end == optarg) || (*end != '\0')) { + fprintf(stderr, "%s: Invalid -s argument.\n", av0); + exit(-1); + } + if (samples == 0) { + fprintf(stderr, "%s: Invalid -s argument (zero is not acceptable).\n", av0); + exit(-1); + } + if ((sec != 0) || (us != 0)) { + fprintf(stderr, "%s: Parameters -l and -s are mutually exclusive.\n", av0); + exit(-1); + } + break; + + case 'o': + offset = strtoul(optarg, &end, 10); + if ((*optarg == '-') || (end == optarg) || (*end != '\0')) { + fprintf(stderr, "%s: Invalid -o argument.\n", av0); + exit(-1); + } + break; + + default: + fprintf(stderr, "%s: Bad command line option -%c.\n", av0, optopt); + usage(-1); + } + + argc -= optind; + argv += optind; + + if (argc == 0) { + f = stdin; + } else if (argc == 1) { + f = fopen(argv[0], "rb"); + if (f == NULL) { + fprintf(stderr, "%s: Can't open file %s for reading.\n", av0, argv[0]); + exit(1); + } + } else { + fprintf(stderr, "%s: Too many command line arguments.\n", av0); + usage(-1); + } + + hdr = read_hdr(f, &hdr_len); + if (hdr == NULL) { + fprintf(stderr, "%s: Can't read wav header.\n", av0); + exit(2); + } + if ((hdr_len = patch_hdr(hdr, hdr_len, sec, us, samples, &data_len)) == 0) { + free(hdr); + fprintf(stderr, "%s: Can't parse (or patch) wav header.\n", av0); + exit(2); + } + + if (offset > hdr_len + data_len) { + fprintf(stderr, "%s: Offset is beyond EOF.\n", av0); + exit(3); + } + + if ((offset > 0) && (offset < hdr_len)) { + memmove(hdr, hdr + offset, hdr_len - offset); + hdr_len -= offset; + offset = 0; + } + + if (offset > 0) { + offset -= hdr_len; + } else { + if (fwrite(hdr, hdr_len, 1, stdout) != 1) { + fprintf(stderr, "%s: Write failed.\n", av0); + exit(4); + } + } + + free(hdr); + hdr = NULL; + hdr_len = 0; + + if (offset > 0) { + data_len -= offset; + while (offset > 0) { + buf_len = (offset > sizeof (buf)) ? sizeof (buf) : offset; + if (fread(buf, buf_len, 1, f) != 1) { + fprintf(stderr, "%s: Read failed.\n", av0); + exit(5); + } + offset -= buf_len; + } + } + + while (data_len > 0) { + buf_len = (data_len > sizeof (buf)) ? sizeof (buf) : data_len; + if (fread(buf, buf_len, 1, f) != 1) { + fprintf(stderr, "%s: Read failed.\n", av0); + exit(5); + } + if (fwrite(buf, buf_len, 1, stdout) != 1) { + fprintf(stderr, "%s: Write failed.\n", av0); + exit(4); + } + data_len -= buf_len; + } + + if (f != stdout) { + fclose(f); + } + exit(0); +} +