doc: Add missing \ref in crypt.h.
[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 };