1 /* Copyright (C) 2010 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
3 /* This file is based on speexdec.c, by Jean-Marc Valin, see below. */
5 /* Copyright (C) 2002-2006 Jean-Marc Valin
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions
12 - Redistributions of source code must retain the above copyright
13 notice, this list of conditions and the following disclaimer.
15 - Redistributions in binary form must reproduce the above copyright
16 notice, this list of conditions and the following disclaimer in the
17 documentation and/or other materials provided with the distribution.
19 - Neither the name of the Xiph.org Foundation nor the names of its
20 contributors may be used to endorse or promote products derived from
21 this software without specific prior written permission.
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
27 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 /** \file spx_afh.c Audio format handler for ogg/speex files. */
39 #include <speex/speex.h>
40 #include <speex/speex_header.h>
41 #include <speex/speex_stereo.h>
46 #include "portable_io.h"
49 #include "ogg_afh_common.h"
51 struct private_spx_data {
52 struct spx_header_info shi;
55 static bool copy_if_tag_type(const char *tag, int taglen, const char *type,
58 char *q = key_value_copy(tag, taglen, type);
66 static int spx_get_comments(unsigned char *comments, int length,
69 char *c = (char *)comments;
70 uint32_t len, nb_fields;
75 return -E_SPX_COMMENT;
80 return -E_SPX_COMMENT;
81 tags->comment = safe_strdup(c, len);
85 return -E_SPX_COMMENT;
86 nb_fields = read_u32(c);
87 PARA_DEBUG_LOG("%u comment(s)\n", nb_fields);
89 for (i = 0; i < nb_fields; i++, c += len) {
93 return -E_SPX_COMMENT;
97 return -E_SPX_COMMENT;
98 if (copy_if_tag_type(c, len, "author", &tags->artist))
100 if (copy_if_tag_type(c, len, "artist", &tags->artist))
102 if (copy_if_tag_type(c, len, "title", &tags->title))
104 if (copy_if_tag_type(c, len, "album", &tags->album))
106 if (copy_if_tag_type(c, len, "year", &tags->year))
108 if (copy_if_tag_type(c, len, "comment", &tags->comment))
110 tag = safe_strdup(c, len);
111 PARA_NOTICE_LOG("unrecognized comment: %s\n", tag);
117 static int spx_packet_callback(ogg_packet *packet, int packet_num,
118 __a_unused int serial, struct afh_info *afhi,
121 struct private_spx_data *psd = private_data;
124 if (packet_num == 0) {
125 ret = spx_process_header(packet->packet, packet->bytes,
129 afhi->channels = psd->shi.channels;
130 afhi->frequency = psd->shi.sample_rate;
131 afhi->bitrate = psd->shi.bitrate / 1000;
132 afhi->techinfo = make_message("%s, v%d", psd->shi.mode->modeName,
133 psd->shi.mode->bitstream_version);
136 if (packet_num == 1) {
137 ret = spx_get_comments(packet->packet, packet->bytes,
141 return 0; /* header complete */
147 static int spx_get_file_info(char *map, size_t numbytes, __a_unused int fd,
148 struct afh_info *afhi)
150 struct private_spx_data psd;
151 struct oac_callback_info spx_callback_info = {
152 .packet_callback = spx_packet_callback,
153 .private_data = &psd,
156 memset(&psd, 0, sizeof(psd));
157 return oac_get_file_info(map, numbytes, afhi, &spx_callback_info);
160 static size_t spx_make_meta_packet(struct taginfo *tags, char **result)
164 size_t comment_len = strlen(tags->comment),
165 artist_len = strlen(tags->artist),
166 title_len = strlen(tags->title),
167 album_len = strlen(tags->album),
168 year_len = strlen(tags->year);
169 uint32_t comment_sz = comment_len,
170 artist_sz = artist_len + strlen("artist="),
171 title_sz = title_len + strlen("title="),
172 album_sz = album_len + strlen("album="),
173 year_sz = year_len + strlen("year=");
176 sz = 4 /* comment length (always present) */
178 + 4; /* number of tags */
196 PARA_DEBUG_LOG("meta packet size: %zu bytes\n", sz);
197 /* terminating zero byte for the last sprintf() */
198 buf = p = para_malloc(sz + 1);
199 write_u32(p, comment_sz);
201 strcpy(p, tags->comment);
203 write_u32(p, num_tags);
206 write_u32(p, artist_sz);
208 sprintf(p, "artist=%s", tags->artist);
212 write_u32(p, title_sz);
214 sprintf(p, "title=%s", tags->title);
218 write_u32(p, album_sz);
220 sprintf(p, "album=%s", tags->album);
224 write_u32(p, year_sz);
226 sprintf(p, "year=%s", tags->year);
229 assert(p == buf + sz);
234 static int spx_rewrite_tags(const char *map, size_t mapsize,
235 struct taginfo *tags, int output_fd,
236 __a_unused const char *filename)
242 meta_sz = spx_make_meta_packet(tags, &meta_packet);
243 ret = oac_rewrite_tags(map, mapsize, output_fd, meta_packet, meta_sz);
248 static const char * const speex_suffixes[] = {"spx", "speex", NULL};
251 * The ogg/speex audio format handler.
253 * This codec is considered obsolete because the opus codec surpasses its
254 * performance in all areas. It is only compiled in if both the ogg and the
255 * speex library are installed.
257 const struct audio_format_handler spx_afh = {
258 .get_file_info = spx_get_file_info,
259 .suffixes = speex_suffixes,
260 .rewrite_tags = spx_rewrite_tags,