diff options
Diffstat (limited to 'lib/rbcodec/codecs/librm')
-rw-r--r-- | lib/rbcodec/codecs/librm/SOURCES | 1 | ||||
-rw-r--r-- | lib/rbcodec/codecs/librm/bytestream.h | 37 | ||||
-rw-r--r-- | lib/rbcodec/codecs/librm/librm.make | 18 | ||||
-rw-r--r-- | lib/rbcodec/codecs/librm/rm.c | 592 | ||||
-rw-r--r-- | lib/rbcodec/codecs/librm/rm.h | 102 |
5 files changed, 750 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/librm/SOURCES b/lib/rbcodec/codecs/librm/SOURCES new file mode 100644 index 0000000000..e0ff169fae --- /dev/null +++ b/lib/rbcodec/codecs/librm/SOURCES | |||
@@ -0,0 +1 @@ | |||
rm.c | |||
diff --git a/lib/rbcodec/codecs/librm/bytestream.h b/lib/rbcodec/codecs/librm/bytestream.h new file mode 100644 index 0000000000..c2a968a4bd --- /dev/null +++ b/lib/rbcodec/codecs/librm/bytestream.h | |||
@@ -0,0 +1,37 @@ | |||
1 | #ifndef RM_BYTESTREAM_H | ||
2 | #define RM_BYTESTREAM_H | ||
3 | |||
4 | #include <inttypes.h> | ||
5 | |||
6 | static inline void advance_buffer(uint8_t **buf, int val) | ||
7 | { | ||
8 | *buf += val; | ||
9 | } | ||
10 | |||
11 | static inline uint8_t rm_get_uint8(uint8_t *buf) | ||
12 | { | ||
13 | return (uint8_t)buf[0]; | ||
14 | } | ||
15 | |||
16 | static inline uint16_t rm_get_uint16be(uint8_t *buf) | ||
17 | { | ||
18 | return (uint16_t)((buf[0] << 8)|buf[1]); | ||
19 | } | ||
20 | |||
21 | static inline uint32_t rm_get_uint32be(uint8_t *buf) | ||
22 | { | ||
23 | return (uint32_t)((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]); | ||
24 | } | ||
25 | |||
26 | static inline uint16_t rm_get_uint16le(uint8_t *buf) | ||
27 | { | ||
28 | return (uint16_t)((buf[1] << 8)|buf[0]); | ||
29 | } | ||
30 | |||
31 | static inline uint32_t rm_get_uint32le(uint8_t *buf) | ||
32 | { | ||
33 | return (uint32_t)((buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]); | ||
34 | } | ||
35 | |||
36 | #endif /* RM_BYTESTREAM_H */ | ||
37 | |||
diff --git a/lib/rbcodec/codecs/librm/librm.make b/lib/rbcodec/codecs/librm/librm.make new file mode 100644 index 0000000000..3c736abec9 --- /dev/null +++ b/lib/rbcodec/codecs/librm/librm.make | |||
@@ -0,0 +1,18 @@ | |||
1 | # __________ __ ___. | ||
2 | # Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
3 | # Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
4 | # Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
5 | # Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
6 | # \/ \/ \/ \/ \/ | ||
7 | # $Id: librm.make 20151 2009-03-01 09:04:15Z amiconn $ | ||
8 | # | ||
9 | |||
10 | # librm | ||
11 | RMLIB := $(CODECDIR)/librm.a | ||
12 | RMLIB_SRC := $(call preprocess, $(RBCODECLIB_DIR)/codecs/librm/SOURCES) | ||
13 | RMLIB_OBJ := $(call c2obj, $(RMLIB_SRC)) | ||
14 | OTHER_SRC += $(RMLIB_SRC) | ||
15 | |||
16 | $(RMLIB): $(RMLIB_OBJ) | ||
17 | $(SILENT)$(shell rm -f $@) | ||
18 | $(call PRINTS,AR $(@F))$(AR) rcs $@ $^ >/dev/null | ||
diff --git a/lib/rbcodec/codecs/librm/rm.c b/lib/rbcodec/codecs/librm/rm.c new file mode 100644 index 0000000000..eabbe5d92a --- /dev/null +++ b/lib/rbcodec/codecs/librm/rm.c | |||
@@ -0,0 +1,592 @@ | |||
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 | |||
25 | #include "rm.h" | ||
26 | #ifdef ROCKBOX | ||
27 | #include "codeclib.h" | ||
28 | #endif | ||
29 | |||
30 | #define SWAP(a, b) do{uint8_t SWAP_tmp= b; b= a; a= SWAP_tmp;}while(0) | ||
31 | |||
32 | #ifdef TEST | ||
33 | #include <fcntl.h> | ||
34 | #include <unistd.h> | ||
35 | #include "inttypes.h" | ||
36 | #include <sys/stat.h> | ||
37 | |||
38 | int filesize(int fd) | ||
39 | { | ||
40 | struct stat buf; | ||
41 | |||
42 | if (fstat(fd,&buf) == -1) { | ||
43 | return -1; | ||
44 | } else { | ||
45 | return (int)buf.st_size; | ||
46 | } | ||
47 | } | ||
48 | |||
49 | static int read_uint8(int fd, uint8_t* buf) | ||
50 | { | ||
51 | unsigned char tmp[1]; | ||
52 | int res; | ||
53 | |||
54 | res=read(fd, tmp, 1); | ||
55 | *buf = tmp[0]; | ||
56 | return res; | ||
57 | } | ||
58 | |||
59 | static int read_uint16be(int fd, uint16_t* buf) | ||
60 | { | ||
61 | unsigned char tmp[2]; | ||
62 | int res; | ||
63 | |||
64 | res=read(fd, tmp, 2); | ||
65 | *buf = (tmp[0] << 8) | tmp[1]; | ||
66 | return res; | ||
67 | } | ||
68 | |||
69 | static int read_uint32be(int fd, uint32_t* buf) | ||
70 | { | ||
71 | unsigned char tmp[4]; | ||
72 | int res; | ||
73 | |||
74 | res=read(fd, tmp, 4); | ||
75 | *buf = (tmp[0] << 24) | (tmp[1] << 16) | (tmp[2] << 8) | tmp[3]; | ||
76 | return res; | ||
77 | } | ||
78 | |||
79 | |||
80 | static void print_cook_extradata(RMContext *rmctx) { | ||
81 | |||
82 | DEBUGF(" cook_version = 0x%08x\n", rm_get_uint32be(rmctx->codec_extradata)); | ||
83 | DEBUGF(" samples_per_frame_per_channel = %d\n", rm_get_uint16be(&rmctx->codec_extradata[4])); | ||
84 | DEBUGF(" number_of_subbands_in_freq_domain = %d\n", rm_get_uint16be(&rmctx->codec_extradata[6])); | ||
85 | if(rmctx->extradata_size == 16) { | ||
86 | DEBUGF(" joint_stereo_subband_start = %d\n",rm_get_uint16be(&rmctx->codec_extradata[12])); | ||
87 | DEBUGF(" joint_stereo_vlc_bits = %d\n", rm_get_uint16be(&rmctx->codec_extradata[14])); | ||
88 | } | ||
89 | } | ||
90 | |||
91 | |||
92 | struct real_object_t | ||
93 | { | ||
94 | uint32_t fourcc; | ||
95 | uint32_t size; | ||
96 | uint16_t version; | ||
97 | }; | ||
98 | |||
99 | #define FOURCC(a,b,c,d) (((a)<<24) | ((b) << 16) | ((c) << 8) | (d)) | ||
100 | |||
101 | static int real_read_object_header(int fd, struct real_object_t* obj) | ||
102 | { | ||
103 | int n; | ||
104 | |||
105 | if ((n = read_uint32be(fd, &obj->fourcc)) <= 0) return n; | ||
106 | if ((n = read_uint32be(fd, &obj->size)) <= 0) return n; | ||
107 | if ((n = read_uint16be(fd, &obj->version)) <= 0) return n; | ||
108 | |||
109 | return 1; | ||
110 | } | ||
111 | |||
112 | static char* fourcc2str(uint32_t f) | ||
113 | { | ||
114 | static char res[5]; | ||
115 | |||
116 | res[0] = (f & 0xff000000) >> 24; | ||
117 | res[1] = (f & 0xff0000) >> 16; | ||
118 | res[2] = (f & 0xff00) >> 8; | ||
119 | res[3] = (f & 0xff); | ||
120 | res[4] = 0; | ||
121 | |||
122 | return res; | ||
123 | } | ||
124 | |||
125 | static int read_str(int fd, char* buf) | ||
126 | { | ||
127 | uint8_t len; | ||
128 | int res; | ||
129 | |||
130 | res = read(fd, &len, 1); | ||
131 | res = read(fd, buf, len); | ||
132 | buf[len]=0; | ||
133 | |||
134 | return len+1; | ||
135 | } | ||
136 | |||
137 | static int real_read_audio_stream_info(int fd, RMContext *rmctx) | ||
138 | { | ||
139 | int skipped = 0; | ||
140 | uint32_t version; | ||
141 | struct real_object_t obj; | ||
142 | memset(&obj,0,sizeof(obj)); | ||
143 | uint32_t header_size; | ||
144 | uint16_t flavor; | ||
145 | uint32_t coded_framesize; | ||
146 | uint32_t unknown1; | ||
147 | uint32_t unknown2; | ||
148 | uint32_t unknown3; | ||
149 | uint16_t unknown4; | ||
150 | uint16_t unknown5; | ||
151 | uint16_t unknown6; | ||
152 | uint16_t unknown7; | ||
153 | uint32_t unknown8; | ||
154 | uint8_t interleaver_id_length; | ||
155 | uint32_t interleaver_id; | ||
156 | uint8_t fourcc_length; | ||
157 | uint32_t fourcc = 0; | ||
158 | uint8_t unknown9; | ||
159 | uint16_t unknown10; | ||
160 | uint8_t unknown11; | ||
161 | |||
162 | read_uint32be(fd, &version); | ||
163 | skipped += 4; | ||
164 | |||
165 | DEBUGF(" version=0x%04x\n",((version >> 16) & 0xff)); | ||
166 | if (((version >> 16) & 0xff) == 3) { | ||
167 | /* Very old version */ | ||
168 | } else { | ||
169 | real_read_object_header(fd, &obj); | ||
170 | skipped += 10; | ||
171 | read_uint32be(fd, &header_size); | ||
172 | skipped += 4; | ||
173 | /* obj.size will be filled with an unknown value, replaced with header_size */ | ||
174 | DEBUGF(" Object: %s, size: %d bytes, version: 0x%04x\n",fourcc2str(obj.fourcc),header_size,obj.version); | ||
175 | |||
176 | read_uint16be(fd, &flavor); | ||
177 | read_uint32be(fd, &coded_framesize); | ||
178 | read_uint32be(fd, &unknown1); | ||
179 | read_uint32be(fd, &unknown2); | ||
180 | read_uint32be(fd, &unknown3); | ||
181 | read_uint16be(fd, &rmctx->sub_packet_h); | ||
182 | read_uint16be(fd, &rmctx->block_align); | ||
183 | read_uint16be(fd, &rmctx->sub_packet_size); | ||
184 | read_uint16be(fd, &unknown4); | ||
185 | skipped += 26; | ||
186 | if (((version >> 16) & 0xff) == 5) | ||
187 | { | ||
188 | read_uint16be(fd, &unknown5); | ||
189 | read_uint16be(fd, &unknown6); | ||
190 | read_uint16be(fd, &unknown7); | ||
191 | skipped += 6; | ||
192 | } | ||
193 | read_uint16be(fd, &rmctx->sample_rate); | ||
194 | read_uint32be(fd, &unknown8); | ||
195 | read_uint16be(fd, &rmctx->nb_channels); | ||
196 | skipped += 8; | ||
197 | if (((version >> 16) & 0xff) == 4) | ||
198 | { | ||
199 | read_uint8(fd, &interleaver_id_length); | ||
200 | read_uint32be(fd, &interleaver_id); | ||
201 | read_uint8(fd, &fourcc_length); | ||
202 | read_uint32be(fd, &fourcc); | ||
203 | skipped += 10; | ||
204 | } | ||
205 | if (((version >> 16) & 0xff) == 5) | ||
206 | { | ||
207 | read_uint32be(fd, &interleaver_id); | ||
208 | read_uint32be(fd, &fourcc); | ||
209 | skipped += 8; | ||
210 | } | ||
211 | read_uint8(fd,&unknown9); | ||
212 | read_uint16be(fd,&unknown10); | ||
213 | skipped += 3; | ||
214 | if (((version >> 16) & 0xff) == 5) | ||
215 | { | ||
216 | read_uint8(fd, &unknown11); | ||
217 | skipped += 1; | ||
218 | } | ||
219 | |||
220 | switch(fourcc) { | ||
221 | case FOURCC('c','o','o','k'): | ||
222 | rmctx->codec_type = CODEC_COOK; | ||
223 | read_uint32be(fd, &rmctx->extradata_size); | ||
224 | skipped += 4; | ||
225 | read(fd, rmctx->codec_extradata, rmctx->extradata_size); | ||
226 | skipped += rmctx->extradata_size; | ||
227 | break; | ||
228 | |||
229 | case FOURCC('a','t','r','c'): | ||
230 | rmctx->codec_type = CODEC_ATRAC; | ||
231 | read_uint32be(fd, &rmctx->extradata_size); | ||
232 | skipped += 4; | ||
233 | read(fd, rmctx->codec_extradata, rmctx->extradata_size); | ||
234 | skipped += rmctx->extradata_size; | ||
235 | break; | ||
236 | |||
237 | case FOURCC('r','a','a','c'): | ||
238 | case FOURCC('r','a','c','p'): | ||
239 | rmctx->codec_type = CODEC_AAC; | ||
240 | read_uint32be(fd, &rmctx->extradata_size); | ||
241 | skipped += 4; | ||
242 | read(fd, rmctx->codec_extradata, rmctx->extradata_size); | ||
243 | skipped += rmctx->extradata_size; | ||
244 | break; | ||
245 | |||
246 | case FOURCC('d','n','e','t'): | ||
247 | rmctx->codec_type = CODEC_AC3; | ||
248 | break; | ||
249 | |||
250 | default: /* Not a supported codec */ | ||
251 | return -1; | ||
252 | } | ||
253 | |||
254 | |||
255 | DEBUGF(" flavor = %d\n",flavor); | ||
256 | DEBUGF(" coded_frame_size = %d\n",coded_framesize); | ||
257 | DEBUGF(" sub_packet_h = %d\n",rmctx->sub_packet_h); | ||
258 | DEBUGF(" frame_size = %d\n",rmctx->block_align); | ||
259 | DEBUGF(" sub_packet_size = %d\n",rmctx->sub_packet_size); | ||
260 | DEBUGF(" sample_rate= %d\n",rmctx->sample_rate); | ||
261 | DEBUGF(" channels= %d\n",rmctx->nb_channels); | ||
262 | DEBUGF(" fourcc = %s\n",fourcc2str(fourcc)); | ||
263 | DEBUGF(" codec_extra_data_length = %d\n",rmctx->extradata_size); | ||
264 | if(rmctx->codec_type == CODEC_COOK) { | ||
265 | DEBUGF(" cook_extradata :\n"); | ||
266 | print_cook_extradata(rmctx); | ||
267 | } | ||
268 | |||
269 | } | ||
270 | |||
271 | return skipped; | ||
272 | } | ||
273 | |||
274 | int real_parse_header(int fd, RMContext *rmctx) | ||
275 | { | ||
276 | struct real_object_t obj; | ||
277 | memset(&obj,0,sizeof(obj)); | ||
278 | int res; | ||
279 | int skipped; | ||
280 | off_t curpos; | ||
281 | |||
282 | uint32_t unknown1; | ||
283 | uint32_t unknown2; | ||
284 | |||
285 | uint32_t max_bitrate; | ||
286 | uint32_t avg_bitrate = 0; | ||
287 | uint32_t max_packet_size; | ||
288 | uint32_t avg_packet_size; | ||
289 | uint32_t packet_count; | ||
290 | uint32_t duration; | ||
291 | uint32_t preroll; | ||
292 | uint32_t index_offset; | ||
293 | uint16_t num_streams; | ||
294 | uint16_t flags = 0; | ||
295 | |||
296 | uint16_t stream_id; | ||
297 | uint32_t start_time; | ||
298 | char desc[256]; | ||
299 | char mimetype[256]; | ||
300 | uint32_t codec_data_size; | ||
301 | uint32_t v; | ||
302 | |||
303 | char title[256]; | ||
304 | char author[256]; | ||
305 | char copyright[256]; | ||
306 | char comment[256]; | ||
307 | |||
308 | uint32_t next_data_off; | ||
309 | uint8_t header_end; | ||
310 | |||
311 | curpos = lseek(fd, 0, SEEK_SET); | ||
312 | res = real_read_object_header(fd, &obj); | ||
313 | |||
314 | if (obj.fourcc == FOURCC('.','r','a',0xfd)) | ||
315 | { | ||
316 | /* Very old .ra format - not yet supported */ | ||
317 | return -1; | ||
318 | } | ||
319 | else if (obj.fourcc != FOURCC('.','R','M','F')) | ||
320 | { | ||
321 | return -1; | ||
322 | } | ||
323 | |||
324 | read_uint32be(fd, &unknown1); | ||
325 | read_uint32be(fd, &unknown2); | ||
326 | |||
327 | DEBUGF("Object: %s, size: %d bytes, version: 0x%04x, pos: %d\n",fourcc2str(obj.fourcc),(int)obj.size,obj.version,(int)curpos); | ||
328 | DEBUGF(" unknown1=%d (0x%08x)\n",unknown1,unknown1); | ||
329 | DEBUGF(" unknown2=%d (0x%08x)\n",unknown2,unknown2); | ||
330 | |||
331 | res = real_read_object_header(fd, &obj); | ||
332 | header_end = 0; | ||
333 | while(res) | ||
334 | { | ||
335 | DEBUGF("Object: %s, size: %d bytes, version: 0x%04x, pos: %d\n",fourcc2str(obj.fourcc),(int)obj.size,obj.version,(int)curpos); | ||
336 | skipped = 10; | ||
337 | if(obj.fourcc == FOURCC('I','N','D','X')) | ||
338 | break; | ||
339 | switch (obj.fourcc) | ||
340 | { | ||
341 | case FOURCC('P','R','O','P'): /* File properties */ | ||
342 | read_uint32be(fd, &max_bitrate); | ||
343 | read_uint32be(fd, &rmctx->bit_rate); /*avg bitrate*/ | ||
344 | read_uint32be(fd, &max_packet_size); | ||
345 | read_uint32be(fd, &avg_packet_size); | ||
346 | read_uint32be(fd, &packet_count); | ||
347 | read_uint32be(fd, &rmctx->duration); | ||
348 | read_uint32be(fd, &preroll); | ||
349 | read_uint32be(fd, &index_offset); | ||
350 | read_uint32be(fd, &rmctx->data_offset); | ||
351 | read_uint16be(fd, &num_streams); | ||
352 | read_uint16be(fd, &rmctx->flags); | ||
353 | skipped += 40; | ||
354 | |||
355 | DEBUGF(" max_bitrate = %d\n",max_bitrate); | ||
356 | DEBUGF(" avg_bitrate = %d\n",avg_bitrate); | ||
357 | DEBUGF(" max_packet_size = %d\n",max_packet_size); | ||
358 | DEBUGF(" avg_packet_size = %d\n",avg_packet_size); | ||
359 | DEBUGF(" packet_count = %d\n",packet_count); | ||
360 | DEBUGF(" duration = %d\n",rmctx->duration); | ||
361 | DEBUGF(" preroll = %d\n",preroll); | ||
362 | DEBUGF(" index_offset = %d\n",index_offset); | ||
363 | DEBUGF(" data_offset = %d\n",rmctx->data_offset); | ||
364 | DEBUGF(" num_streams = %d\n",num_streams); | ||
365 | DEBUGF(" flags=0x%04x\n",flags); | ||
366 | break; | ||
367 | |||
368 | case FOURCC('C','O','N','T'): | ||
369 | /* Four strings - Title, Author, Copyright, Comment */ | ||
370 | skipped += read_str(fd,title); | ||
371 | skipped += read_str(fd,author); | ||
372 | skipped += read_str(fd,copyright); | ||
373 | skipped += read_str(fd,comment); | ||
374 | |||
375 | DEBUGF(" title=\"%s\"\n",title); | ||
376 | DEBUGF(" author=\"%s\"\n",author); | ||
377 | DEBUGF(" copyright=\"%s\"\n",copyright); | ||
378 | DEBUGF(" comment=\"%s\"\n",comment); | ||
379 | break; | ||
380 | |||
381 | case FOURCC('M','D','P','R'): /* Media properties */ | ||
382 | read_uint16be(fd,&stream_id); | ||
383 | skipped += 2; | ||
384 | read_uint32be(fd,&max_bitrate); | ||
385 | skipped += 4; | ||
386 | read_uint32be(fd,&avg_bitrate); | ||
387 | skipped += 4; | ||
388 | read_uint32be(fd,&max_packet_size); | ||
389 | skipped += 4; | ||
390 | read_uint32be(fd,&avg_packet_size); | ||
391 | skipped += 4; | ||
392 | read_uint32be(fd,&start_time); | ||
393 | skipped += 4; | ||
394 | read_uint32be(fd,&preroll); | ||
395 | skipped += 4; | ||
396 | read_uint32be(fd,&duration); | ||
397 | skipped += 4; | ||
398 | skipped += read_str(fd,desc); | ||
399 | skipped += read_str(fd,mimetype); | ||
400 | read_uint32be(fd,&codec_data_size); | ||
401 | skipped += 4; | ||
402 | //From ffmpeg: codec_pos = url_ftell(pb); | ||
403 | read_uint32be(fd,&v); | ||
404 | skipped += 4; | ||
405 | |||
406 | DEBUGF(" stream_id = 0x%04x\n",stream_id); | ||
407 | DEBUGF(" max_bitrate = %d\n",max_bitrate); | ||
408 | DEBUGF(" avg_bitrate = %d\n",avg_bitrate); | ||
409 | DEBUGF(" max_packet_size = %d\n",max_packet_size); | ||
410 | DEBUGF(" avg_packet_size = %d\n",avg_packet_size); | ||
411 | DEBUGF(" start_time = %d\n",start_time); | ||
412 | DEBUGF(" preroll = %d\n",preroll); | ||
413 | DEBUGF(" duration = %d\n",duration); | ||
414 | DEBUGF(" desc=\"%s\"\n",desc); | ||
415 | DEBUGF(" mimetype=\"%s\"\n",mimetype); | ||
416 | DEBUGF(" codec_data_size = %d\n",codec_data_size); | ||
417 | DEBUGF(" v=\"%s\"\n", fourcc2str(v)); | ||
418 | |||
419 | if (v == FOURCC('.','r','a',0xfd)) | ||
420 | { | ||
421 | skipped += real_read_audio_stream_info(fd, rmctx); | ||
422 | } | ||
423 | |||
424 | break; | ||
425 | |||
426 | case FOURCC('D','A','T','A'): | ||
427 | |||
428 | read_uint32be(fd,&rmctx->nb_packets); | ||
429 | skipped += 4; | ||
430 | read_uint32be(fd,&next_data_off); | ||
431 | skipped += 4; | ||
432 | if (!rmctx->nb_packets && (rmctx->flags & 4)) | ||
433 | rmctx->nb_packets = 3600 * 25; | ||
434 | |||
435 | /*** | ||
436 | * nb_packets correction : | ||
437 | * in some samples, number of packets may not exactly form | ||
438 | * an integer number of scrambling units. This is corrected | ||
439 | * by constructing a partially filled unit out of the few | ||
440 | * remaining samples at the end of decoding. | ||
441 | ***/ | ||
442 | if(rmctx->nb_packets % rmctx->sub_packet_h) | ||
443 | rmctx->nb_packets += rmctx->sub_packet_h - (rmctx->nb_packets % rmctx->sub_packet_h); | ||
444 | |||
445 | DEBUGF(" data_nb_packets = %d\n",rmctx->nb_packets); | ||
446 | DEBUGF(" next DATA offset = %d\n",next_data_off); | ||
447 | header_end = 1; | ||
448 | break; | ||
449 | } | ||
450 | if(header_end) break; | ||
451 | curpos = lseek(fd, obj.size - skipped, SEEK_CUR); | ||
452 | res = real_read_object_header(fd, &obj); | ||
453 | } | ||
454 | |||
455 | |||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | void rm_get_packet_fd(int fd,RMContext *rmctx, RMPacket *pkt) | ||
460 | { | ||
461 | uint8_t unknown,packet_group; | ||
462 | uint16_t x; | ||
463 | uint16_t sps = rmctx->sub_packet_size; | ||
464 | uint16_t h = rmctx->sub_packet_h; | ||
465 | uint16_t y = rmctx->sub_packet_cnt; | ||
466 | uint16_t w = rmctx->audio_framesize; | ||
467 | int res; | ||
468 | do | ||
469 | { | ||
470 | y = rmctx->sub_packet_cnt; | ||
471 | read_uint16be(fd,&pkt->version); | ||
472 | read_uint16be(fd,&pkt->length); | ||
473 | read_uint16be(fd,&pkt->stream_number); | ||
474 | read_uint32be(fd,&pkt->timestamp); | ||
475 | DEBUGF(" version = %d\n" | ||
476 | " length = %d\n" | ||
477 | " stream = %d\n" | ||
478 | " timestmp= %d\n",pkt->version,pkt->length,pkt->stream_number,pkt->timestamp); | ||
479 | |||
480 | if(pkt->version == 0) | ||
481 | { | ||
482 | read_uint8(fd,&packet_group); | ||
483 | read_uint8(fd,&pkt->flags); | ||
484 | } | ||
485 | if(pkt->version == 1) | ||
486 | read_uint8(fd,&unknown); | ||
487 | |||
488 | if (pkt->flags & 2) /* keyframe */ | ||
489 | y = rmctx->sub_packet_cnt = 0; | ||
490 | if (!y) /* if keyframe update playback elapsed time */ | ||
491 | rmctx->audiotimestamp = pkt->timestamp; | ||
492 | |||
493 | for(x = 0 ; x < w/sps; x++) | ||
494 | { | ||
495 | res = read(fd,pkt->data+(sps*(h*x+((h+1)/2)*(y&1)+(y>>1))), sps); | ||
496 | } | ||
497 | rmctx->audio_pkt_cnt++; | ||
498 | }while(++(rmctx->sub_packet_cnt) < h); | ||
499 | |||
500 | } | ||
501 | #endif /*TEST*/ | ||
502 | |||
503 | int rm_get_packet(uint8_t **src,RMContext *rmctx, RMPacket *pkt) | ||
504 | { | ||
505 | int consumed = 0; | ||
506 | /* rockbox: comment 'set but unused' variables | ||
507 | uint8_t unknown; | ||
508 | */ | ||
509 | uint16_t x, place; | ||
510 | uint16_t sps = rmctx->sub_packet_size; | ||
511 | uint16_t h = rmctx->sub_packet_h; | ||
512 | uint16_t y = rmctx->sub_packet_cnt; | ||
513 | uint16_t w = rmctx->audio_framesize; | ||
514 | do | ||
515 | { | ||
516 | y = rmctx->sub_packet_cnt; | ||
517 | pkt->version = rm_get_uint16be(*src); | ||
518 | |||
519 | /* Simple error checking */ | ||
520 | if(pkt->version != 0 && pkt->version != 1) | ||
521 | { | ||
522 | DEBUGF("parsing packets failed\n"); | ||
523 | return -1; | ||
524 | } | ||
525 | |||
526 | pkt->length = rm_get_uint16be(*src+2); | ||
527 | pkt->stream_number = rm_get_uint16be(*src+4); | ||
528 | pkt->timestamp = rm_get_uint32be(*src+6); | ||
529 | /*DEBUGF(" version = %d\n" | ||
530 | " length = %d\n" | ||
531 | " stream = %d\n" | ||
532 | " timestamp= %d\n\n",pkt->version,pkt->length,pkt->stream_number,pkt->timestamp);*/ | ||
533 | /* unknown =*/ rm_get_uint8(*src+10); | ||
534 | pkt->flags = rm_get_uint8(*src+11); | ||
535 | |||
536 | if(pkt->version == 1) | ||
537 | /* unknown = */ rm_get_uint8(*src+10); | ||
538 | |||
539 | if (pkt->flags & 2) /* keyframe */ | ||
540 | y = rmctx->sub_packet_cnt = 0; | ||
541 | if (!y) | ||
542 | rmctx->audiotimestamp = pkt->timestamp; | ||
543 | |||
544 | /* Skip packet header */ | ||
545 | advance_buffer(src, PACKET_HEADER_SIZE); | ||
546 | consumed += PACKET_HEADER_SIZE; | ||
547 | if (rmctx->codec_type == CODEC_COOK || rmctx->codec_type == CODEC_ATRAC) { | ||
548 | for(x = 0 ; x < w/sps; x++) | ||
549 | { | ||
550 | place = sps*(h*x+((h+1)/2)*(y&1)+(y>>1)); | ||
551 | pkt->frames[place/sps] = *src; | ||
552 | advance_buffer(src,sps); | ||
553 | consumed += sps; | ||
554 | } | ||
555 | } | ||
556 | else if (rmctx->codec_type == CODEC_AAC) { | ||
557 | rmctx->sub_packet_cnt = (rm_get_uint16be(*src) & 0xf0) >> 4; | ||
558 | advance_buffer(src, 2); | ||
559 | consumed += 2; | ||
560 | if (rmctx->sub_packet_cnt) { | ||
561 | for(x = 0; x < rmctx->sub_packet_cnt; x++) { | ||
562 | rmctx->sub_packet_lengths[x] = rm_get_uint16be(*src); | ||
563 | advance_buffer(src, 2); | ||
564 | consumed += 2; | ||
565 | } | ||
566 | rmctx->audio_pkt_cnt = --rmctx->sub_packet_cnt; | ||
567 | } | ||
568 | } | ||
569 | |||
570 | else if (rmctx->codec_type == CODEC_AC3) { | ||
571 | /* The byte order of the data is reversed from standard AC3 */ | ||
572 | for(x = 0; x < pkt->length - PACKET_HEADER_SIZE; x+=2) { | ||
573 | SWAP((*src)[0], (*src)[1]); | ||
574 | *src += 2; | ||
575 | } | ||
576 | *src -= x; | ||
577 | } | ||
578 | rmctx->audio_pkt_cnt++; | ||
579 | }while(++(rmctx->sub_packet_cnt) < h); | ||
580 | |||
581 | return consumed; | ||
582 | } | ||
583 | |||
584 | #ifdef DEBUG | ||
585 | void dump_rm_context(RMContext *rmctx) | ||
586 | { | ||
587 | DEBUGF("block_align = %d\n", rmctx->block_align); | ||
588 | DEBUGF("nb_channels = %d\n", rmctx->nb_channels); | ||
589 | DEBUGF("sample_rate = %d\n", rmctx->sample_rate); | ||
590 | DEBUGF("bit_rate = %d\n", rmctx->bit_rate ); | ||
591 | } | ||
592 | #endif | ||
diff --git a/lib/rbcodec/codecs/librm/rm.h b/lib/rbcodec/codecs/librm/rm.h new file mode 100644 index 0000000000..c4a4e3a77e --- /dev/null +++ b/lib/rbcodec/codecs/librm/rm.h | |||
@@ -0,0 +1,102 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2009 Mohamed Tarek | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #ifndef _RM_H | ||
22 | #define _RM_H | ||
23 | |||
24 | #include <stdio.h> | ||
25 | #include <inttypes.h> | ||
26 | #include "bytestream.h" | ||
27 | |||
28 | #define MAX_EXTRADATA_SIZE 16 | ||
29 | #define DATA_HEADER_SIZE 18 | ||
30 | #define PACKET_HEADER_SIZE 12 | ||
31 | |||
32 | enum codecs { | ||
33 | CODEC_COOK, | ||
34 | CODEC_AAC, | ||
35 | CODEC_AC3, | ||
36 | CODEC_ATRAC | ||
37 | }; | ||
38 | |||
39 | typedef struct rm_packet | ||
40 | { | ||
41 | uint8_t *frames[100]; /* Pointers to ordered audio frames in buffer */ | ||
42 | uint16_t version; | ||
43 | uint16_t length; | ||
44 | uint32_t timestamp; | ||
45 | uint16_t stream_number; | ||
46 | uint8_t flags; | ||
47 | |||
48 | #ifdef TEST | ||
49 | uint8_t data[30000]; /* Reordered data. No malloc, hence the size */ | ||
50 | #endif | ||
51 | }RMPacket; | ||
52 | |||
53 | typedef struct rm_context | ||
54 | { | ||
55 | /* Demux Context */ | ||
56 | int old_format; | ||
57 | int current_stream; | ||
58 | int remaining_len; | ||
59 | int audio_stream_num; /*< Stream number for audio packets*/ | ||
60 | int audio_pkt_cnt; /* Output packet counter*/ | ||
61 | |||
62 | /* Stream Variables */ | ||
63 | uint32_t data_offset; | ||
64 | uint32_t duration; | ||
65 | uint32_t audiotimestamp; /* Audio packet timestamp*/ | ||
66 | uint16_t sub_packet_cnt; /* Subpacket counter, used while reading */ | ||
67 | uint16_t sub_packet_size, sub_packet_h, coded_framesize; /* Descrambling parameters from container */ | ||
68 | uint16_t audio_framesize; /* Audio frame size from container */ | ||
69 | uint16_t sub_packet_lengths[16]; /* Length of each subpacket */ | ||
70 | |||
71 | /* Codec Context */ | ||
72 | enum codecs codec_type; | ||
73 | uint16_t block_align; | ||
74 | uint32_t nb_packets; | ||
75 | int frame_number; | ||
76 | uint16_t sample_rate; | ||
77 | uint16_t nb_channels; | ||
78 | uint32_t bit_rate; | ||
79 | uint16_t flags; | ||
80 | |||
81 | /*codec extradata*/ | ||
82 | uint32_t extradata_size; | ||
83 | uint8_t codec_extradata[MAX_EXTRADATA_SIZE]; | ||
84 | |||
85 | } RMContext; | ||
86 | |||
87 | int real_parse_header(int fd, RMContext *rmctx); | ||
88 | |||
89 | /* Get a (sub_packet_h*frames_per_packet) number of audio frames from a memory buffer */ | ||
90 | int rm_get_packet(uint8_t **src,RMContext *rmctx, RMPacket *pkt); | ||
91 | |||
92 | #ifdef TEST | ||
93 | |||
94 | int filesize(int fd); | ||
95 | void advance_buffer(uint8_t **buf, int val); | ||
96 | |||
97 | /* Get a (sub_packet_h*frames_per_packet) number of audio frames from a file descriptor */ | ||
98 | void rm_get_packet_fd(int fd,RMContext *rmctx, RMPacket *pkt); | ||
99 | |||
100 | #endif /* TEST */ | ||
101 | |||
102 | #endif /* _RM_H */ | ||