summaryrefslogtreecommitdiff
path: root/apps/codecs/libcook/rm2wav.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/codecs/libcook/rm2wav.c')
-rw-r--r--apps/codecs/libcook/rm2wav.c584
1 files changed, 584 insertions, 0 deletions
diff --git a/apps/codecs/libcook/rm2wav.c b/apps/codecs/libcook/rm2wav.c
new file mode 100644
index 0000000000..4ef1ec4f66
--- /dev/null
+++ b/apps/codecs/libcook/rm2wav.c
@@ -0,0 +1,584 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2008 Dave Chapman
11 * Copyright (C) 2009 Mohamed Tarek
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22#include <stdio.h>
23#include <string.h>
24#include <stdint.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <fcntl.h>
28#include <unistd.h>
29
30#include "rm2wav.h"
31
32#define MAX_PATH 260
33#define PKT_HEADER_SIZE 12
34#define RAW_AUDIO_DATA packet_length-PKT_HEADER_SIZE
35
36
37#if 0
38#define DEBUG
39#define DEBUGF printf
40#else
41#define DEBUGF(...)
42#endif
43
44/* ASF codec IDs */
45#define CODEC_ID_WMAV1 0x160
46#define CODEC_ID_WMAV2 0x161
47
48static unsigned char wav_header[44]={
49 'R','I','F','F',// 0 - ChunkID
50 0,0,0,0, // 4 - ChunkSize (filesize-8)
51 'W','A','V','E',// 8 - Format
52 'f','m','t',' ',// 12 - SubChunkID
53 16,0,0,0, // 16 - SubChunk1ID // 16 for PCM
54 1,0, // 20 - AudioFormat (1=Uncompressed)
55 2,0, // 22 - NumChannels
56 0,0,0,0, // 24 - SampleRate in Hz
57 0,0,0,0, // 28 - Byte Rate (SampleRate*NumChannels*(BitsPerSample/8)
58 4,0, // 32 - BlockAlign (== NumChannels * BitsPerSample/8)
59 16,0, // 34 - BitsPerSample
60 'd','a','t','a',// 36 - Subchunk2ID
61 0,0,0,0 // 40 - Subchunk2Size
62};
63
64int open_wav(char* filename) {
65 int fd,res;
66
67 fd=open(filename,O_CREAT|O_WRONLY|O_TRUNC,S_IRUSR|S_IWUSR);
68 if (fd >= 0) {
69 res = write(fd,wav_header,sizeof(wav_header));
70 }
71
72 return(fd);
73}
74
75void close_wav(int fd, RMContext *rmctx) {
76 int x,res;
77 int filesize;
78 int bytes_per_sample = 2;
79 int samples_per_frame = rmctx->samples_pf_pc;
80 int nb_channels = rmctx->nb_channels;
81 int sample_rate = rmctx->sample_rate;
82 int nb_frames = rmctx->audio_framesize/rmctx->block_align * rmctx->nb_packets - 2; // first 2 frames have no valid audio; skipped in output
83
84 filesize= samples_per_frame*bytes_per_sample*nb_frames +44;
85 printf("Filesize = %d\n",filesize);
86
87 // ChunkSize
88 x=filesize-8;
89 wav_header[4]=(x&0xff);
90 wav_header[5]=(x&0xff00)>>8;
91 wav_header[6]=(x&0xff0000)>>16;
92 wav_header[7]=(x&0xff000000)>>24;
93
94 // Number of channels
95 wav_header[22]=nb_channels;
96
97 // Samplerate
98 wav_header[24]=sample_rate&0xff;
99 wav_header[25]=(sample_rate&0xff00)>>8;
100 wav_header[26]=(sample_rate&0xff0000)>>16;
101 wav_header[27]=(sample_rate&0xff000000)>>24;
102
103 // ByteRate
104 x=sample_rate*bytes_per_sample*nb_channels;
105 wav_header[28]=(x&0xff);
106 wav_header[29]=(x&0xff00)>>8;
107 wav_header[30]=(x&0xff0000)>>16;
108 wav_header[31]=(x&0xff000000)>>24;
109
110 // BlockAlign
111 wav_header[32]=rmctx->block_align;//2*rmctx->nb_channels;
112
113 // Bits per sample
114 wav_header[34]=16;
115
116 // Subchunk2Size
117 x=filesize-44;
118 wav_header[40]=(x&0xff);
119 wav_header[41]=(x&0xff00)>>8;
120 wav_header[42]=(x&0xff0000)>>16;
121 wav_header[43]=(x&0xff000000)>>24;
122
123 lseek(fd,0,SEEK_SET);
124 res = write(fd,wav_header,sizeof(wav_header));
125 close(fd);
126}
127
128/* Some Rockbox-like functions (these should be implemented in metadata_common.[ch] */
129struct cook_extradata {
130 uint32_t cook_version;
131 uint16_t samples_pf_pc; /* samples per frame per channel */
132 uint16_t nb_subbands; /* number of subbands in the frequency domain */
133
134 /* extra 8 bytes for stereo data */
135 uint32_t unused;
136 uint16_t js_subband_start; /* joint stereo subband start */
137 uint16_t js_vlc_bits;
138};
139
140static int read_uint8(int fd, uint8_t* buf)
141{
142 unsigned char tmp[1];
143 int res;
144
145 res=read(fd, tmp, 1);
146 *buf = tmp[0];
147 return res;
148}
149
150static int read_uint16be(int fd, uint16_t* buf)
151{
152 unsigned char tmp[2];
153 int res;
154
155 res=read(fd, tmp, 2);
156 *buf = (tmp[0] << 8) | tmp[1];
157 return res;
158}
159
160static int read_uint32be(int fd, uint32_t* buf)
161{
162 unsigned char tmp[4];
163 int res;
164
165 res=read(fd, tmp, 4);
166 *buf = (tmp[0] << 24) | (tmp[1] << 16) | (tmp[2] << 8) | tmp[3];
167 return res;
168}
169
170off_t filesize(int fd)
171{
172 struct stat buf;
173
174 if (fstat(fd,&buf) == -1) {
175 return -1;
176 } else {
177 return buf.st_size;
178 }
179}
180
181int read_cook_extradata(int fd, RMContext *rmctx) {
182 read_uint32be(fd, &rmctx->cook_version);
183 read_uint16be(fd, &rmctx->samples_pf_pc);
184 read_uint16be(fd, &rmctx->nb_subbands);
185 if(rmctx->extradata_size == 16) {
186 read_uint32be(fd, &rmctx->unused);
187 read_uint16be(fd, &rmctx->js_subband_start);
188 read_uint16be(fd, &rmctx->js_vlc_bits);
189 }
190 return rmctx->extradata_size; /* for 'skipped' */
191}
192
193void print_cook_extradata(RMContext *rmctx) {
194
195 printf(" cook_version = 0x%08x\n", rmctx->cook_version);
196 printf(" samples_per_frame_per_channel = %d\n", rmctx->samples_pf_pc);
197 printf(" number_of_subbands_in_freq_domain = %d\n", rmctx->nb_subbands);
198 if(rmctx->extradata_size == 16) {
199 printf(" joint_stereo_subband_start = %d\n",rmctx->js_subband_start);
200 printf(" joint_stereo_vlc_bits = %d\n", rmctx->js_vlc_bits);
201 }
202}
203
204
205struct real_object_t
206{
207 uint32_t fourcc;
208 uint32_t size;
209 uint16_t version;
210};
211
212#define FOURCC(a,b,c,d) (((a)<<24) | ((b) << 16) | ((c) << 8) | (d))
213
214static int real_read_object_header(int fd, struct real_object_t* obj)
215{
216 int n;
217
218 if ((n = read_uint32be(fd, &obj->fourcc)) <= 0) return n;
219 if ((n = read_uint32be(fd, &obj->size)) <= 0) return n;
220 if ((n = read_uint16be(fd, &obj->version)) <= 0) return n;
221
222 return 1;
223}
224
225static char* fourcc2str(uint32_t f)
226{
227 static char res[5];
228
229 res[0] = (f & 0xff000000) >> 24;
230 res[1] = (f & 0xff0000) >> 16;
231 res[2] = (f & 0xff00) >> 8;
232 res[3] = (f & 0xff);
233 res[4] = 0;
234
235 return res;
236}
237
238static int read_str(int fd, char* buf)
239{
240 uint8_t len;
241 int res;
242
243 res = read(fd, &len, 1);
244 res = read(fd, buf, len);
245 buf[len]=0;
246
247 return len+1;
248}
249
250static int real_read_audio_stream_info(int fd, RMContext *rmctx)
251{
252 int skipped = 0;
253 uint32_t version;
254 struct real_object_t obj;
255 memset(&obj,0,sizeof(obj));
256 uint32_t header_size;
257 uint16_t flavor;
258 uint32_t coded_framesize;
259 uint32_t unknown1;
260 uint32_t unknown2;
261 uint32_t unknown3;
262 uint16_t unknown4;
263 uint16_t unknown5;
264 uint16_t unknown6;
265 uint16_t unknown7;
266 uint32_t unknown8;
267 uint8_t interleaver_id_length;
268 uint32_t interleaver_id;
269 uint8_t fourcc_length;
270 uint32_t fourcc = 0;
271 uint8_t unknown9;
272 uint16_t unknown10;
273 uint8_t unknown11;
274
275 read_uint32be(fd, &version);
276 skipped += 4;
277
278 printf(" version=0x%04x\n",((version >> 16) & 0xff));
279 if (((version >> 16) & 0xff) == 3) {
280 /* Very old version */
281 } else {
282 real_read_object_header(fd, &obj);
283 skipped += 10;
284 read_uint32be(fd, &header_size);
285 skipped += 4;
286 /* obj.size will be filled with an unknown value, replaced with header_size */
287 printf(" Object: %s, size: %d bytes, version: 0x%04x\n",fourcc2str(obj.fourcc),header_size,obj.version);
288
289 read_uint16be(fd, &flavor);
290 read_uint32be(fd, &coded_framesize);
291 read_uint32be(fd, &unknown1);
292 read_uint32be(fd, &unknown2);
293 read_uint32be(fd, &unknown3);
294 read_uint16be(fd, &rmctx->sub_packet_h);
295 read_uint16be(fd, &rmctx->block_align);
296 read_uint16be(fd, &rmctx->sub_packet_size);
297 read_uint16be(fd, &unknown4);
298 skipped += 26;
299 if (((version >> 16) & 0xff) == 5)
300 {
301 read_uint16be(fd, &unknown5);
302 read_uint16be(fd, &unknown6);
303 read_uint16be(fd, &unknown7);
304 skipped += 6;
305 }
306 read_uint16be(fd, &rmctx->sample_rate);
307 read_uint32be(fd, &unknown8);
308 read_uint16be(fd, &rmctx->nb_channels);
309 skipped += 8;
310 if (((version >> 16) & 0xff) == 4)
311 {
312 read_uint8(fd, &interleaver_id_length);
313 read_uint32be(fd, &interleaver_id);
314 read_uint8(fd, &fourcc_length);
315 read_uint32be(fd, &fourcc);
316 skipped += 10;
317 }
318 if (((version >> 16) & 0xff) == 5)
319 {
320 read_uint32be(fd, &interleaver_id);
321 read_uint32be(fd, &fourcc);
322 skipped += 8;
323 }
324 read_uint8(fd,&unknown9);
325 read_uint16be(fd,&unknown10);
326 skipped += 3;
327 if (((version >> 16) & 0xff) == 5)
328 {
329 read_uint8(fd, &unknown11);
330 skipped += 1;
331 }
332
333 read_uint32be(fd, &rmctx->extradata_size);
334 skipped += 4;
335 if(!strncmp(fourcc2str(fourcc),"cook",4))
336 skipped += read_cook_extradata(fd, rmctx);
337
338
339 printf(" flavor = %d\n",flavor);
340 printf(" coded_frame_size = %d\n",coded_framesize);
341 printf(" sub_packet_h = %d\n",rmctx->sub_packet_h);
342 printf(" frame_size = %d\n",rmctx->block_align);
343 printf(" sub_packet_size = %d\n",rmctx->sub_packet_size);
344 printf(" sample_rate= %d\n",rmctx->sample_rate);
345 printf(" channels= %d\n",rmctx->nb_channels);
346 printf(" fourcc = %s\n",fourcc2str(fourcc));
347 printf(" codec_extra_data_length = %d\n",rmctx->extradata_size);
348 printf(" codec_extradata :\n");
349 print_cook_extradata(rmctx);
350
351 }
352
353 return skipped;
354}
355
356int real_parse_header(int fd, RMContext *rmctx)
357{
358 struct real_object_t obj;
359 memset(&obj,0,sizeof(obj));
360 int res;
361 int skipped;
362 off_t curpos;
363
364 uint32_t unknown1;
365 uint32_t unknown2;
366
367 uint32_t max_bitrate;
368 uint32_t avg_bitrate = 0;
369 uint32_t max_packet_size;
370 uint32_t avg_packet_size;
371 uint32_t packet_count;
372 uint32_t duration;
373 uint32_t preroll;
374 uint32_t index_offset;
375 uint32_t data_offset;
376 uint16_t num_streams;
377 uint16_t flags = 0;
378
379 uint16_t stream_id;
380 uint32_t start_time;
381 char desc[256];
382 char mimetype[256];
383 uint32_t codec_data_size;
384 uint32_t v;
385
386 char title[256];
387 char author[256];
388 char copyright[256];
389 char comment[256];
390
391 uint32_t next_data_off;
392 uint8_t header_end;
393
394 curpos = lseek(fd, 0, SEEK_SET);
395 res = real_read_object_header(fd, &obj);
396
397 if (obj.fourcc == FOURCC('.','r','a',0xfd))
398 {
399 /* Very old .ra format - not yet supported */
400 return -1;
401 }
402 else if (obj.fourcc != FOURCC('.','R','M','F'))
403 {
404 return -1;
405 }
406
407 read_uint32be(fd, &unknown1);
408 read_uint32be(fd, &unknown2);
409
410 printf("Object: %s, size: %d bytes, version: 0x%04x, pos: %d\n",fourcc2str(obj.fourcc),(int)obj.size,obj.version,(int)curpos);
411 printf(" unknown1=%d (0x%08x)\n",unknown1,unknown1);
412 printf(" unknown2=%d (0x%08x)\n",unknown2,unknown2);
413
414 res = real_read_object_header(fd, &obj);
415 header_end = 0;
416 while(res)
417 {
418 printf("Object: %s, size: %d bytes, version: 0x%04x, pos: %d\n",fourcc2str(obj.fourcc),(int)obj.size,obj.version,(int)curpos);
419 skipped = 10;
420 if(obj.fourcc == FOURCC('I','N','D','X'))
421 break;
422 switch (obj.fourcc)
423 {
424 case FOURCC('P','R','O','P'): /* File properties */
425 read_uint32be(fd, &max_bitrate);
426 read_uint32be(fd, &rmctx->bit_rate); /*avg bitrate*/
427 read_uint32be(fd, &max_packet_size);
428 read_uint32be(fd, &avg_packet_size);
429 read_uint32be(fd, &packet_count);
430 read_uint32be(fd, &duration);
431 read_uint32be(fd, &preroll);
432 read_uint32be(fd, &index_offset);
433 read_uint32be(fd, &data_offset);
434 read_uint16be(fd, &num_streams);
435 read_uint16be(fd, &rmctx->flags);
436 skipped += 40;
437
438 printf(" max_bitrate = %d\n",max_bitrate);
439 printf(" avg_bitrate = %d\n",avg_bitrate);
440 printf(" max_packet_size = %d\n",max_packet_size);
441 printf(" avg_packet_size = %d\n",avg_packet_size);
442 printf(" packet_count = %d\n",packet_count);
443 printf(" duration = %d\n",duration);
444 printf(" preroll = %d\n",preroll);
445 printf(" index_offset = %d\n",index_offset);
446 printf(" data_offset = %d\n",data_offset);
447 printf(" num_streams = %d\n",num_streams);
448 printf(" flags=0x%04x\n",flags);
449 break;
450
451 case FOURCC('C','O','N','T'):
452 /* Four strings - Title, Author, Copyright, Comment */
453 skipped += read_str(fd,title);
454 skipped += read_str(fd,author);
455 skipped += read_str(fd,copyright);
456 skipped += read_str(fd,comment);
457
458 printf(" title=\"%s\"\n",title);
459 printf(" author=\"%s\"\n",author);
460 printf(" copyright=\"%s\"\n",copyright);
461 printf(" comment=\"%s\"\n",comment);
462 break;
463
464 case FOURCC('M','D','P','R'): /* Media properties */
465 read_uint16be(fd,&stream_id);
466 skipped += 2;
467 read_uint32be(fd,&max_bitrate);
468 skipped += 4;
469 read_uint32be(fd,&avg_bitrate);
470 skipped += 4;
471 read_uint32be(fd,&max_packet_size);
472 skipped += 4;
473 read_uint32be(fd,&avg_packet_size);
474 skipped += 4;
475 read_uint32be(fd,&start_time);
476 skipped += 4;
477 read_uint32be(fd,&preroll);
478 skipped += 4;
479 read_uint32be(fd,&duration);
480 skipped += 4;
481 skipped += read_str(fd,desc);
482 skipped += read_str(fd,mimetype);
483 read_uint32be(fd,&codec_data_size);
484 skipped += 4;
485 //From ffmpeg: codec_pos = url_ftell(pb);
486 read_uint32be(fd,&v);
487 skipped += 4;
488
489 printf(" stream_id = 0x%04x\n",stream_id);
490 printf(" max_bitrate = %d\n",max_bitrate);
491 printf(" avg_bitrate = %d\n",avg_bitrate);
492 printf(" max_packet_size = %d\n",max_packet_size);
493 printf(" avg_packet_size = %d\n",avg_packet_size);
494 printf(" start_time = %d\n",start_time);
495 printf(" preroll = %d\n",preroll);
496 printf(" duration = %d\n",duration);
497 printf(" desc=\"%s\"\n",desc);
498 printf(" mimetype=\"%s\"\n",mimetype);
499 printf(" codec_data_size = %d\n",codec_data_size);
500 printf(" v=\"%s\"\n", fourcc2str(v));
501
502 if (v == FOURCC('.','r','a',0xfd))
503 {
504 skipped += real_read_audio_stream_info(fd, rmctx);
505 }
506
507 break;
508
509 case FOURCC('D','A','T','A'):
510
511 read_uint32be(fd,&rmctx->nb_packets);
512 skipped += 4;
513 read_uint32be(fd,&next_data_off);
514 skipped += 4;
515 if (!rmctx->nb_packets && (rmctx->flags & 4))
516 rmctx->nb_packets = 3600 * 25;
517 printf(" data_nb_packets = %d\n",rmctx->nb_packets);
518 printf(" next DATA offset = %d\n",next_data_off);
519 header_end = 1;
520 break;
521 }
522 if(header_end) break;
523 curpos = lseek(fd, obj.size - skipped, SEEK_CUR);
524 res = real_read_object_header(fd, &obj);
525 }
526
527
528 return 0;
529}
530
531void rm_get_packet(int fd,RMContext *rmctx, RMPacket *pkt)
532{
533 uint8_t unknown,packet_group;
534 uint16_t x, place;
535 uint16_t sps = rmctx->sub_packet_size;
536 uint16_t h = rmctx->sub_packet_h;
537 uint16_t y = rmctx->sub_packet_cnt;
538 uint16_t w = rmctx->audio_framesize;
539 do
540 {
541 y = rmctx->sub_packet_cnt;
542 read_uint16be(fd,&pkt->version);
543 read_uint16be(fd,&pkt->length);
544 read_uint16be(fd,&pkt->stream_number);
545 read_uint32be(fd,&pkt->timestamp);
546 DEBUGF(" version = %d\n"
547 " length = %d\n"
548 " stream = %d\n"
549 " timestmp= %d\n",pkt->version,pkt->length,pkt->stream_number,pkt->timestamp);
550
551 //getchar();
552 if(pkt->version == 0)
553 {
554 read_uint8(fd,&packet_group);
555 read_uint8(fd,&pkt->flags);
556 }
557 if(pkt->version == 1)
558 read_uint8(fd,&unknown);
559
560 if (pkt->flags & 2) /* keyframe */
561 y = rmctx->sub_packet_cnt = 0;
562 if (!y) /* if keyframe update playback elapsed time */
563 rmctx->audiotimestamp = pkt->timestamp;
564
565 for(x = 0 ; x < w/sps; x++)
566 {
567 place = sps*(h*x+((h+1)/2)*(y&1)+(y>>1));
568 read(fd,pkt->data+place, sps);
569 //DEBUGF("place = %d data[place] = %d\n",place,pkt->data[place]);
570 }
571 rmctx->audio_pkt_cnt++;
572 }while(++(rmctx->sub_packet_cnt) < h);
573
574 //return pkt->data;
575}
576#ifdef DEBUG
577void dump_rm_context(RMContext *rmctx)
578{
579 DEBUGF("block_align = %d\n", rmctx->block_align);
580 DEBUGF("nb_channels = %d\n", rmctx->nb_channels);
581 DEBUGF("sample_rate = %d\n", rmctx->sample_rate);
582 DEBUGF("bit_rate = %d\n", rmctx->bit_rate );
583}
584#endif