X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=spx_afh.c;fp=spx_afh.c;h=472c2c80fc38f013200c84a885aa3afd2ec780d9;hp=0000000000000000000000000000000000000000;hb=90560de0d7e4d825772270f9ac7cbefbb38aad97;hpb=063328d833daa7e06589645e05d4d2e02f55e911 diff --git a/spx_afh.c b/spx_afh.c new file mode 100644 index 00000000..472c2c80 --- /dev/null +++ b/spx_afh.c @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2010 Andre Noll + * + * Licensed under the GPL v2. For licencing details see COPYING. + */ + +/* This file is based on speexdec.c, by Jean-Marc Valin, see below. */ + +/* Copyright (C) 2002-2006 Jean-Marc Valin + File: speexdec.c + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/** \file spx_afh.c Audio format handler for ogg/speex files. */ + +#include +#include +#include +#include +#include +#include + +#include "para.h" +#include "afh.h" +#include "error.h" +#include "portable_io.h" +#include "string.h" +#include "spx.h" +#include "ogg_afh_common.h" + +struct private_spx_data { + struct spx_header_info shi; +}; + + +static char *copy_comment(const char *src, int len) +{ + char *p = para_malloc(len + 1); + + if (len > 0) + memcpy(p, src, len); + p[len] = '\0'; + PARA_DEBUG_LOG("%s\n", p); + return p; +} + +static bool copy_if_tag_type(const char *tag, int taglen, const char *type, + char **p) +{ + int len = strlen(type); + + if (taglen <= len) + return false; + if (strncasecmp(tag, type, len)) + return false; + if (tag[len] != '=') + return false; + free(*p); + *p = copy_comment(tag + len + 1, taglen - len - 1); + return true; +} + +static int spx_get_comments(unsigned char *comments, int length, + struct taginfo *tags) +{ + char *c = (char *)comments; + uint32_t len, nb_fields; + int i; + char *end; + + if (length < 8) + return -E_SPX_COMMENT; + end = c + length; + len = read_u32(c); + c += 4; + if (c + len > end) + return -E_SPX_COMMENT; + tags->comment = copy_comment(c, len); + + c += len; + if (c + 4 > end) + return -E_SPX_COMMENT; + nb_fields = read_u32(c); + PARA_DEBUG_LOG("%d comment(s)\n", nb_fields); + c += 4; + for (i = 0; i < nb_fields; i++, c += len) { + char *tag; + + if (c + 4 > end) + return -E_SPX_COMMENT; + len = read_u32(c); + c += 4; + if (c + len > end) + return -E_SPX_COMMENT; + if (copy_if_tag_type(c, len, "author", &tags->artist)) + continue; + if (copy_if_tag_type(c, len, "artist", &tags->artist)) + continue; + if (copy_if_tag_type(c, len, "title", &tags->title)) + continue; + if (copy_if_tag_type(c, len, "album", &tags->album)) + continue; + if (copy_if_tag_type(c, len, "year", &tags->year)) + continue; + if (copy_if_tag_type(c, len, "comment", &tags->comment)) + continue; + tag = copy_comment(c, len); + PARA_NOTICE_LOG("unrecognized comment: %s\n", tag); + free(tag); + } + return 1; +} + +static const char* speex_suffixes[] = {"spx", "speex", NULL}; + +static int spx_packet_callback(ogg_packet *packet, int packet_num, + struct afh_info *afhi, void *private_data) +{ + struct private_spx_data *psd = private_data; + int ret; + + if (packet_num == 0) { + ret = spx_process_header(packet->packet, packet->bytes, + &psd->shi); + if (ret < 0) + return ret; + afhi->channels = psd->shi.channels; + afhi->frequency = psd->shi.sample_rate; + afhi->bitrate = psd->shi.bitrate / 1000; + afhi->techinfo = make_message("%s, v%d", psd->shi.mode->modeName, + psd->shi.mode->bitstream_version); + return 1; + } + if (packet_num == 1) { + ret = spx_get_comments(packet->packet, packet->bytes, + &afhi->tags); + if (ret < 0) + return ret; + return 0; /* header complete */ + } + /* never reached */ + return 0; +} + +static int spx_get_file_info(char *map, size_t numbytes, __a_unused int fd, + struct afh_info *afhi) +{ + struct private_spx_data psd; + struct ogg_afh_callback_info spx_callback_info = { + .packet_callback = spx_packet_callback, + .private_data = &psd, + }; + + memset(&psd, 0, sizeof(psd)); + return ogg_get_file_info(map, numbytes, afhi, &spx_callback_info); +} + +/** + * The init function of the ogg/speex audio format handler. + * + * \param afh Pointer to the struct to initialize. + */ +void spx_afh_init(struct audio_format_handler *afh) +{ + afh->get_file_info = spx_get_file_info, + afh->suffixes = speex_suffixes; +}