mixer: fade: Handle empty mood strings gracefully.
[paraslash.git] / wma_afh.c
1 /* Copyright (C) 2009 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
2
3 /** \file wma_afh.c The audio format handler for WMA files. */
4
5 #include <sys/types.h>
6 #include <regex.h>
7 #include <iconv.h>
8
9 #include "para.h"
10 #include "error.h"
11 #include "afh.h"
12 #include "portable_io.h"
13 #include "string.h"
14 #include "wma.h"
15 #include "fd.h"
16
17 #define FOR_EACH_FRAME(_f, _buf, _size, _ps) for (_f = (_buf); \
18 _f + (_ps) < (_buf) + (_size); \
19 _f += (_ps))
20
21 /*
22 * Must be called on a frame boundary, e.g. start + header_len.
23 * \return Frame count, superframe count via *num_superframes.
24 */
25 static int count_frames(const char *buf, int buf_size, uint32_t packet_size,
26 int *num_superframes)
27 {
28 int fc = 0, sfc = 0; /* frame count, superframe count */
29 const uint8_t *p;
30
31
32 FOR_EACH_FRAME(p, (uint8_t *)buf, buf_size, packet_size) {
33 fc += p[WMA_FRAME_SKIP] & 0x0f;
34 sfc++;
35 }
36 PARA_INFO_LOG("%d frames, %d superframes\n", fc, sfc);
37 *num_superframes = sfc;
38 return fc;
39 }
40
41 /*
42 * put_utf8() and get_str16() below are based on macros in libavutil/common.h
43 * of the mplayer source code, copyright (c) 2006 Michael Niedermayer
44 * <michaelni@gmx.at>.
45 */
46
47 /*
48 * Convert a 32-bit Unicode character to its UTF-8 encoded form.
49 *
50 * Writes up to 4 bytes for values in the valid UTF-8 range and up to 7 bytes
51 * in the general case, depending on the length of the converted Unicode
52 * character.
53 *
54 * \param result Where the converted UTF-8 bytes are written.
55 */
56 static int put_utf8(uint32_t val, char *result)
57 {
58 char *out = result;
59 int bytes, shift;
60 uint32_t in = val;
61
62 if (in < 0x80) {
63 *out++ = in;
64 return 1;
65 }
66 bytes = DIV_ROUND_UP(wma_log2(in), 5);
67 shift = (bytes - 1) * 6;
68 *out++ = (256 - (256 >> bytes)) | (in >> shift);
69 while (shift >= 6) {
70 shift -= 6;
71 *out++ = 0x80 | ((in >> shift) & 0x3f);
72 }
73 return out - result;
74 }
75
76 static char *get_str16(const char *in, int len)
77 {
78 const char *p = in;
79 int out_size = 0, out_len = 0;
80 char *out = NULL;
81
82 len /= 2;
83 while (len--) {
84 uint32_t x;
85 if (out_len + 7 + 1 >= out_size) {
86 out_size = 2 * out_size + 50;
87 out = para_realloc(out, out_size);
88 }
89 x = read_u16(p);
90 p += 2;
91 out_len += put_utf8(x, out + out_len);
92 if (x == 0)
93 return out;
94 }
95 if (out)
96 out[out_len] = '\0';
97 return out;
98 }
99
100 static const char content_description_header[] = {
101 0x33, 0x26, 0xb2, 0x75, 0x8E, 0x66, 0xCF, 0x11,
102 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c
103 };
104
105 static const char extended_content_header[] = {
106 0x40, 0xA4, 0xD0, 0xD2, 0x07, 0xE3, 0xD2, 0x11,
107 0x97, 0xF0, 0x00, 0xA0, 0xC9, 0x5E, 0xA8, 0x50
108 };
109
110 static const char year_tag_header[] = { /* WM/Year */
111 0x57, 0x00, 0x4d, 0x00, 0x2f, 0x00, 0x59, 0x00,
112 0x65, 0x00, 0x61, 0x00, 0x72, 0x00
113 };
114
115 static const char album_tag_header[] = { /* WM/AlbumTitle */
116 0x57, 0x00, 0x4d, 0x00, 0x2f, 0x00, 0x41, 0x00,
117 0x6c, 0x00, 0x62, 0x00, 0x75, 0x00, 0x6d, 0x00,
118 0x54, 0x00, 0x69, 0x00, 0x74, 0x00, 0x6c, 0x00,
119 0x65, 0x00
120 };
121
122 static void read_asf_tags(const char *buf, int buf_size, struct taginfo *ti)
123 {
124 const char *p, *end = buf + buf_size, *q;
125 uint16_t len1, len2, len3, len4;
126
127 p = search_pattern(content_description_header,
128 sizeof(content_description_header), buf, buf_size);
129 if (!p || p + 34 >= end) {
130 PARA_NOTICE_LOG("content description header not found\n");
131 goto next;
132 }
133 p += 24;
134 len1 = read_u16(p);
135 p += 2;
136 len2 = read_u16(p);
137 p += 2;
138 len3 = read_u16(p);
139 p += 2;
140 len4 = read_u16(p);
141 p += 2;
142 /* ignore length of the rating information */
143 p += 2;
144 if (p + len1 >= end)
145 goto next;
146 ti->title = get_str16(p, len1);
147 p += len1;
148 if (p + len2 >= end)
149 goto next;
150 ti->artist = get_str16(p, len2);
151 p += len2 + len3;
152 if (p + len4 >= end)
153 goto next;
154 ti->comment = get_str16(p, len4);
155 next:
156 p = search_pattern(extended_content_header, sizeof(extended_content_header),
157 buf, buf_size);
158 if (!p) {
159 PARA_NOTICE_LOG("extended content header not found\n");
160 return;
161 }
162 q = search_pattern(year_tag_header, sizeof(year_tag_header),
163 p, end - p);
164 if (q) {
165 const char *r = q + sizeof(year_tag_header) + 6;
166 if (r < end)
167 ti->year = get_str16(r, end - r);
168 }
169 q = search_pattern(album_tag_header, sizeof(album_tag_header),
170 p, end - p);
171 if (q) {
172 const char *r = q + sizeof(album_tag_header) + 6;
173 if (r < end)
174 ti->album = get_str16(r, end - r);
175 }
176 }
177
178 static void set_chunk_tv(int frames_per_chunk, int frequency,
179 struct timeval *result)
180 {
181 uint64_t x = (uint64_t)frames_per_chunk * 2048 * 1000 * 1000
182 / frequency;
183
184 result->tv_sec = x / 1000 / 1000;
185 result->tv_usec = x % (1000 * 1000);
186 PARA_INFO_LOG("chunk time: %lums\n", tv2ms(result));
187 }
188
189 /* Must be called on a frame boundary. */
190 static int wma_make_chunk_table(char *buf, size_t buf_size, uint32_t packet_size,
191 struct afh_info *afhi)
192 {
193 const uint8_t *f, *start = (uint8_t *)buf;
194 int j, frames_per_chunk;
195 size_t ct_size = 250;
196 int ret, count = 0, num_frames, num_superframes;
197
198 afhi->chunk_table = para_malloc(ct_size * sizeof(uint32_t));
199 afhi->chunk_table[0] = 0;
200 afhi->chunk_table[1] = afhi->header_len;
201
202 num_frames = count_frames(buf, buf_size, packet_size,
203 &num_superframes);
204 ret = -E_NO_WMA;
205 if (num_frames == 0 || num_superframes == 0)
206 goto fail;
207 afhi->seconds_total = num_frames * 2048 /* FIXME */
208 / afhi->frequency;
209 frames_per_chunk = num_frames / num_superframes / 2;
210 PARA_INFO_LOG("%d frames per chunk\n", frames_per_chunk);
211 j = 1;
212 FOR_EACH_FRAME(f, start, buf_size, packet_size) {
213 count += f[WMA_FRAME_SKIP] & 0x0f;
214 while (count > j * frames_per_chunk) {
215 j++;
216 if (j >= ct_size) {
217 ct_size *= 2;
218 afhi->chunk_table = para_realloc(
219 afhi->chunk_table,
220 ct_size * sizeof(uint32_t));
221 }
222 afhi->chunk_table[j] = f - start + afhi->header_len
223 + packet_size;
224 }
225 }
226 afhi->chunks_total = j;
227 set_max_chunk_size(afhi);
228 set_chunk_tv(frames_per_chunk, afhi->frequency, &afhi->chunk_tv);
229 return 1;
230 fail:
231 free(afhi->chunk_table);
232 return ret;
233 }
234
235 static int wma_get_file_info(char *map, size_t numbytes, __a_unused int fd,
236 struct afh_info *afhi)
237 {
238 int ret;
239 struct asf_header_info ahi;
240
241 ret = read_asf_header(map, numbytes, &ahi);
242 if (ret < 0)
243 return ret;
244 if (ret == 0)
245 return -E_NO_WMA;
246 afhi->bitrate = ahi.bit_rate / 1000;
247 if (ahi.sample_rate == 0)
248 return -E_NO_WMA;
249 afhi->frequency = ahi.sample_rate;
250 afhi->channels = ahi.channels;
251 afhi->header_len = ahi.header_len;
252
253 afhi->techinfo = make_message("%s%s%s%s%s",
254 ahi.use_exp_vlc? "exp vlc" : "",
255 (ahi.use_bit_reservoir && ahi.use_exp_vlc)? ", " : "",
256 ahi.use_bit_reservoir? "bit reservoir" : "",
257 (ahi.use_variable_block_len &&
258 (ahi.use_exp_vlc || ahi.use_bit_reservoir)? ", " : ""),
259 ahi.use_variable_block_len? "vbl" : ""
260 );
261 wma_make_chunk_table(map + ahi.header_len, numbytes - ahi.header_len,
262 ahi.packet_size, afhi);
263 read_asf_tags(map, ahi.header_len, &afhi->tags);
264 return 0;
265 }
266
267 struct asf_object {
268 char *ptr;
269 uint64_t size;
270 };
271
272 struct tag_object_nums {
273 int content_descr_obj_num;
274 int extended_content_descr_obj_num;
275 };
276
277 struct afs_top_level_header_object {
278 uint64_t size;
279 uint32_t num_objects;
280 uint8_t reserved1, reserved2;
281 struct asf_object *objects;
282 };
283
284 #define CHECK_HEADER(_p, _h) (memcmp((_p), (_h), sizeof((_h))) == 0)
285
286 static int read_asf_objects(const char *src, size_t size, uint32_t num_objects,
287 struct asf_object *objs, struct tag_object_nums *ton)
288 {
289 int i;
290 const char *p;
291
292 for (i = 0, p = src; i < num_objects; p += objs[i++].size) {
293 if (p + 24 > src + size)
294 return -E_NO_WMA;
295 objs[i].ptr = (char *)p;
296 objs[i].size = read_u64(p + 16);
297 if (p + objs[i].size > src + size)
298 return -E_NO_WMA;
299
300 if (CHECK_HEADER(p, content_description_header))
301 ton->content_descr_obj_num = i;
302 else if (CHECK_HEADER(p, extended_content_header))
303 ton->extended_content_descr_obj_num = i;
304 }
305 return 1;
306 }
307
308 static const char top_level_header_object_guid[] = {
309 0x30, 0x26, 0xb2, 0x75, 0x8e, 0x66, 0xcf, 0x11,
310 0xa6, 0xd9, 0x00, 0xaa, 0x00, 0x62, 0xce, 0x6c
311 };
312
313 static int convert_utf8_to_utf16(char *src, char **dst)
314 {
315 iconv_t cd;
316 size_t sz, inbytes, outbytes, inbytesleft, outbytesleft;
317 char *inbuf, *outbuf;
318 int ret;
319
320 if (!src || !*src) {
321 *dst = para_calloc(2);
322 return 0;
323 }
324 /*
325 * Without specifying LE (little endian), iconv includes a byte order
326 * mark (e.g. 0xFFFE) at the beginning.
327 */
328 cd = iconv_open("UTF-16LE", "UTF-8");
329 if (cd == (iconv_t)-1) {
330 *dst = NULL;
331 return -ERRNO_TO_PARA_ERROR(errno);
332 }
333 inbuf = src;
334 /* even though src is in UTF-8, strlen() should DTRT */
335 inbytes = inbytesleft = strlen(src);
336 outbytes = outbytesleft = 4 * inbytes + 2; /* hope that's enough */
337 *dst = outbuf = para_malloc(outbytes);
338 sz = iconv(cd, ICONV_CAST &inbuf, &inbytesleft, &outbuf, &outbytesleft);
339 if (sz == (size_t)-1) {
340 ret = -ERRNO_TO_PARA_ERROR(errno);
341 free(*dst);
342 *dst = NULL;
343 goto out;
344 }
345 assert(outbytes >= outbytesleft);
346 assert(outbytes - outbytesleft < INT_MAX - 2);
347 ret = outbytes - outbytesleft;
348 outbuf = para_realloc(*dst, ret + 2);
349 outbuf[ret] = outbuf[ret + 1] = '\0';
350 ret += 2;
351 *dst = outbuf;
352 PARA_INFO_LOG("converted %s to %d UTF-16 bytes\n", src, ret);
353 out:
354 if (iconv_close(cd) < 0)
355 PARA_WARNING_LOG("iconv_close: %s\n", strerror(errno));
356 return ret;
357 }
358
359 /* The content description object contains artist, title, comment. */
360 static int make_cdo(struct taginfo *tags, const struct asf_object *cdo,
361 struct asf_object *result)
362 {
363 const char *cr, *rating; /* orig data */
364 uint16_t orig_cr_bytes, orig_rating_bytes;
365 /* pointers to new UTF-16 tags */
366 char *artist = NULL, *title = NULL, *comment = NULL;
367 /* number of bytes in UTF-16 for the new tags */
368 int artist_bytes, title_bytes, comment_bytes, ret;
369 char *p, null[2] = "\0\0";
370
371 result->ptr = NULL;
372 result->size = 0;
373 ret = convert_utf8_to_utf16(tags->artist, &artist);
374 if (ret < 0)
375 return ret;
376 assert(artist);
377 artist_bytes = ret;
378 ret = convert_utf8_to_utf16(tags->title, &title);
379 if (ret < 0)
380 goto out;
381 assert(title);
382 title_bytes = ret;
383 ret = convert_utf8_to_utf16(tags->comment, &comment);
384 if (ret < 0)
385 goto out;
386 assert(comment);
387 comment_bytes = ret;
388
389 if (cdo) {
390 uint16_t orig_title_bytes, orig_artist_bytes, orig_comment_bytes;
391 /*
392 * Sizes of the five fields (stored as 16-bit numbers) are
393 * located after the header (16 bytes) and the cdo size (8
394 * bytes).
395 */
396 orig_title_bytes = read_u16(cdo->ptr + 24);
397 orig_artist_bytes = read_u16(cdo->ptr + 26);
398 orig_cr_bytes = read_u16(cdo->ptr + 28);
399 orig_comment_bytes = read_u16(cdo->ptr + 30);
400 orig_rating_bytes = read_u16(cdo->ptr + 32);
401 cr = cdo->ptr + 34 + orig_title_bytes + orig_artist_bytes;
402 rating = cr + orig_cr_bytes + orig_comment_bytes;
403 } else {
404 orig_cr_bytes = 2;
405 orig_rating_bytes = 2;
406 cr = null;
407 rating = null;
408 }
409
410 /* compute size of result cdo */
411 result->size = 16 + 8 + 5 * 2 + title_bytes + artist_bytes
412 + orig_cr_bytes + comment_bytes + orig_rating_bytes;
413 PARA_DEBUG_LOG("cdo is %zu bytes\n", (size_t)result->size);
414 p = result->ptr = para_malloc(result->size);
415 memcpy(p, content_description_header, 16);
416 p += 16;
417 write_u64(p, result->size);
418 p += 8;
419 write_u16(p, title_bytes);
420 p += 2;
421 write_u16(p, artist_bytes);
422 p += 2;
423 write_u16(p, orig_cr_bytes);
424 p += 2;
425 write_u16(p, comment_bytes);
426 p += 2;
427 write_u16(p, orig_rating_bytes);
428 p += 2;
429 memcpy(p, title, title_bytes);
430 p += title_bytes;
431 memcpy(p, artist, artist_bytes);
432 p += artist_bytes;
433 memcpy(p, cr, orig_cr_bytes);
434 p += orig_cr_bytes;
435 memcpy(p, comment, comment_bytes);
436 p += comment_bytes;
437 memcpy(p, rating, orig_rating_bytes);
438 p += orig_rating_bytes;
439 assert(p - result->ptr == result->size);
440 ret = 1;
441 out:
442 free(artist);
443 free(title);
444 free(comment);
445 return ret;
446 }
447
448 /* The extended content description object contains album and year. */
449 static int make_ecdo(struct taginfo *tags, struct asf_object *result)
450 {
451 int ret;
452 char *p, *album = NULL, *year = NULL, null[2] = "\0\0";
453 int album_bytes, year_bytes;
454
455 result->ptr = NULL;
456 result->size = 0;
457 ret = convert_utf8_to_utf16(tags->album, &album);
458 if (ret < 0)
459 return ret;
460 assert(album);
461 album_bytes = ret;
462 ret = convert_utf8_to_utf16(tags->year, &year);
463 if (ret < 0)
464 goto out;
465 assert(year);
466 year_bytes = ret;
467 result->size = 16 + 8 + 2; /* GUID, size, count */
468 /* name_length + name + null + data type + val length + val */
469 result->size += 2 + sizeof(album_tag_header) + 2 + 2 + 2 + album_bytes;
470 result->size += 2 + sizeof(year_tag_header) + 2 + 2 + 2 + year_bytes;
471
472 p = result->ptr = para_malloc(result->size);
473 memcpy(p, extended_content_header, 16);
474 p += 16;
475 write_u64(p, result->size);
476 p += 8;
477 write_u16(p, 2); /* count */
478 p += 2;
479
480 /* album */
481 write_u16(p, sizeof(album_tag_header) + 2);
482 p += 2;
483 memcpy(p, album_tag_header, sizeof(album_tag_header));
484 p += sizeof(album_tag_header);
485 memcpy(p, null, 2);
486 p += 2;
487 write_u16(p, 0); /* data type (UTF-16) */
488 p += 2;
489 write_u16(p, album_bytes);
490 p += 2;
491 memcpy(p, album, album_bytes);
492 p += album_bytes;
493
494 /* year */
495 write_u16(p, sizeof(year_tag_header));
496 p += 2;
497 memcpy(p, year_tag_header, sizeof(year_tag_header));
498 p += sizeof(year_tag_header);
499 memcpy(p, null, 2);
500 p += 2;
501 write_u16(p, 0); /* data type (UTF-16) */
502 p += 2;
503 write_u16(p, year_bytes);
504 p += 2;
505 memcpy(p, year, year_bytes);
506 p += year_bytes;
507 assert(p - result->ptr == result->size);
508 ret = 1;
509 out:
510 free(album);
511 free(year);
512 return ret;
513 }
514
515 static int write_output_file(int fd, const char *map, size_t mapsize,
516 struct afs_top_level_header_object *top, struct tag_object_nums *ton,
517 struct asf_object *cdo, struct asf_object *ecdo)
518 {
519 int i, ret;
520 uint64_t sz; /* of the new header object */
521 uint32_t num_objects;
522 char tmp[8];
523
524 sz = 16 + 8 + 4 + 1 + 1; /* top-level header object */
525 for (i = 0; i < top->num_objects; i++) {
526 if (i == ton->content_descr_obj_num)
527 continue;
528 if (i == ton->extended_content_descr_obj_num)
529 continue;
530 sz += top->objects[i].size;
531 }
532 sz += cdo->size;
533 sz += ecdo->size;
534 num_objects = top->num_objects;
535 if (ton->content_descr_obj_num < 0)
536 num_objects++;
537 if (ton->extended_content_descr_obj_num < 0)
538 num_objects++;
539 ret = xwrite(fd, top_level_header_object_guid, 16);
540 if (ret < 0)
541 goto out;
542 write_u64(tmp, sz);
543 ret = xwrite(fd, tmp, 8);
544 if (ret < 0)
545 goto out;
546 write_u32(tmp, num_objects);
547 ret = xwrite(fd, tmp, 4);
548 if (ret < 0)
549 goto out;
550 write_u8(tmp, top->reserved1);
551 ret = xwrite(fd, tmp, 1);
552 if (ret < 0)
553 goto out;
554 write_u8(tmp, top->reserved2);
555 ret = xwrite(fd, tmp, 1);
556 if (ret < 0)
557 goto out;
558 /*
559 * Write cto and ecto as objects 0 and 1 if they did not exist in the
560 * original file.
561 */
562 if (ton->content_descr_obj_num < 0) {
563 ret = xwrite(fd, cdo->ptr, cdo->size);
564 if (ret < 0)
565 goto out;
566 }
567 if (ton->extended_content_descr_obj_num < 0) {
568 ret = xwrite(fd, ecdo->ptr, ecdo->size);
569 if (ret < 0)
570 goto out;
571 }
572
573 for (i = 0; i < top->num_objects; i++) {
574 char *buf = top->objects[i].ptr;
575 sz = top->objects[i].size;
576 if (i == ton->content_descr_obj_num) {
577 buf = cdo->ptr;
578 sz = cdo->size;
579 } else if (i == ton->extended_content_descr_obj_num) {
580 buf = ecdo->ptr;
581 sz = ecdo->size;
582 }
583 ret = xwrite(fd, buf, sz);
584 if (ret < 0)
585 goto out;
586 }
587 ret = xwrite(fd, map + top->size, mapsize - top->size);
588 out:
589 return ret;
590 }
591
592 static int wma_rewrite_tags(const char *map, size_t mapsize,
593 struct taginfo *tags, int fd,
594 __a_unused const char *filename)
595 {
596 struct afs_top_level_header_object top;
597 struct tag_object_nums ton = {-1, -1};
598 const char *p = map;
599 /* (extended) content description object */
600 struct asf_object cdo = {.ptr = NULL}, ecdo = {.ptr = NULL};
601 int ret;
602
603 /* guid + size + num_objects + 2 * reserved */
604 if (mapsize < 16 + 8 + 4 + 1 + 1)
605 return -E_NO_WMA;
606 if (memcmp(map, top_level_header_object_guid, 16))
607 return -E_NO_WMA;
608 p += 16;
609 top.size = read_u64(p);
610 PARA_INFO_LOG("header_size: %lu\n", (long unsigned)top.size);
611 if (top.size >= mapsize)
612 return -E_NO_WMA;
613 p += 8;
614 top.num_objects = read_u32(p);
615 PARA_NOTICE_LOG("%u header objects\n", top.num_objects);
616 if (top.num_objects > top.size / 24)
617 return -E_NO_WMA;
618 p += 4;
619 top.reserved1 = read_u8(p);
620 p++;
621 top.reserved2 = read_u8(p);
622 if (top.reserved2 != 2)
623 return -E_NO_WMA;
624 p++; /* objects start at p */
625 top.objects = para_malloc(top.num_objects * sizeof(struct asf_object));
626 ret = read_asf_objects(p, top.size - (p - map), top.num_objects,
627 top.objects, &ton);
628 if (ret < 0)
629 goto out;
630 ret = make_cdo(tags, ton.content_descr_obj_num >= 0?
631 top.objects + ton.content_descr_obj_num : NULL, &cdo);
632 if (ret < 0)
633 goto out;
634 ret = make_ecdo(tags, &ecdo);
635 if (ret < 0)
636 goto out;
637 ret = write_output_file(fd, map, mapsize, &top, &ton, &cdo,
638 &ecdo);
639 out:
640 free(cdo.ptr);
641 free(ecdo.ptr);
642 free(top.objects);
643 return ret;
644 }
645
646 static const char * const wma_suffixes[] = {"wma", NULL};
647
648 /**
649 * The audio format handler for Windows Media Audio.
650 *
651 * Only WMA version 2 is supported. This audio format handler does not depend
652 * on any third party libraries and is therefore always compiled in.
653 */
654 const struct audio_format_handler wma_afh = {
655 .get_file_info = wma_get_file_info,
656 .suffixes = wma_suffixes,
657 .rewrite_tags = wma_rewrite_tags,
658 };