1 // this file is a modified version for deadbeef player
2 /***************************************************************************
3 * __________ __ ___.
4 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
5 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
6 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
7 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
8 * \/ \/ \/ \/ \/
9 * $Id$
10 *
11 * Copyright (C) 2007 Dave Chapman
12 *
13 * ASF parsing code based on libasf by Juho Vähä-Herttua
14 * http://code.google.com/p/libasf/ libasf itself was based on the ASF
15 * parser in VLC - http://www.videolan.org/
16 *
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License
19 * as published by the Free Software Foundation; either version 2
20 * of the License, or (at your option) any later version.
21 *
22 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
23 * KIND, either express or implied.
24 *
25 ****************************************************************************/
26 #include <inttypes.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include "asf.h"
30 #include "../../deadbeef.h"
31 extern DB_functions_t *deadbeef;
32 //#define trace(...) { fprintf (stderr, __VA_ARGS__); }
33 #define trace(fmt,...)
34 #define DEBUGF trace
35
36 #define SKIP_BYTES(fd,x) {\
37 if (x > 0) {\
38 char buf[x];\
39 deadbeef->fread (buf, x, 1, fd);\
40 }\
41 }
42
43 /* Read an unaligned 32-bit little endian long from buffer. */
get_long_le(void * buf)44 static unsigned long get_long_le(void* buf)
45 {
46 unsigned char* p = (unsigned char*) buf;
47
48 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
49 }
50
51 /* Read an unaligned 16-bit little endian short from buffer. */
get_short_le(void * buf)52 static unsigned short get_short_le(void* buf)
53 {
54 unsigned char* p = (unsigned char*) buf;
55
56 return p[0] | (p[1] << 8);
57 }
58
59 #define GETLEN2b(bits) (((bits) == 0x03) ? 4 : bits)
60
61 #define GETVALUE2b(bits, data) \
62 (((bits) != 0x03) ? ((bits) != 0x02) ? ((bits) != 0x01) ? \
63 0 : *(data) : get_short_le(data) : get_long_le(data))
64
asf_read_packet(uint8_t ** audiobuf,int * audiobufsize,int * packetlength,asf_waveformatex_t * wfx,DB_FILE * fp)65 int asf_read_packet(uint8_t** audiobuf, int* audiobufsize, int* packetlength,
66 asf_waveformatex_t* wfx, DB_FILE *fp)
67 {
68 uint8_t *audiobuf_mem = *audiobuf;
69 uint8_t tmp8, packet_flags, packet_property;
70 int stream_id;
71 int ec_length, opaque_data, ec_length_type;
72 int datalen;
73 uint8_t data[18];
74 uint8_t* datap;
75 uint32_t length;
76 uint32_t padding_length;
77 /* rockbox: comment 'set but unused' variables
78 uint32_t send_time;
79 uint16_t duration;
80 uint32_t media_object_number;
81 uint32_t media_object_offset;
82 */
83 uint16_t payload_count;
84 int payload_length_type;
85 uint32_t payload_hdrlen;
86 int payload_datalen;
87 int multiple;
88 uint32_t replicated_length;
89 uint32_t bytesread = 0;
90 uint8_t* buf;
91 size_t bufsize;
92 int i;
93 /*DEBUGF("Reading new packet at %d bytes ", (int)ci->curpos);*/
94
95 if (deadbeef->fread (&tmp8, 1, 1, fp) == 0) {
96 return ASF_ERROR_EOF;
97 }
98 bytesread++;
99
100 /* TODO: We need a better way to detect endofstream */
101 if (tmp8 != 0x82) {
102 DEBUGF("Read failed: packet did not sync\n");
103 return -1;
104 }
105
106
107 if (tmp8 & 0x80) {
108 ec_length = tmp8 & 0x0f;
109 opaque_data = (tmp8 >> 4) & 0x01;
110 ec_length_type = (tmp8 >> 5) & 0x03;
111
112 if (ec_length_type != 0x00 || opaque_data != 0 || ec_length != 0x02) {
113 DEBUGF("incorrect error correction flags\n");
114 return ASF_ERROR_INVALID_VALUE;
115 }
116
117 /* Skip ec_data */
118 SKIP_BYTES(fp, ec_length);
119 bytesread += ec_length;
120 } else {
121 ec_length = 0;
122 }
123
124 if (deadbeef->fread(&packet_flags, 1, 1, fp) == 0) { return ASF_ERROR_EOF; }
125 if (deadbeef->fread(&packet_property, 1, 1, fp) == 0) { return ASF_ERROR_EOF; }
126 bytesread += 2;
127
128 datalen = GETLEN2b((packet_flags >> 1) & 0x03) +
129 GETLEN2b((packet_flags >> 3) & 0x03) +
130 GETLEN2b((packet_flags >> 5) & 0x03) + 6;
131
132 #if 0
133 if (datalen > sizeof(data)) {
134 DEBUGF("Unexpectedly long datalen in data - %d\n",datalen);
135 return ASF_ERROR_OUTOFMEM;
136 }
137 #endif
138
139 if (deadbeef->fread (data, datalen, 1, fp) == 0) {
140 return ASF_ERROR_EOF;
141 }
142
143 bytesread += datalen;
144
145 datap = data;
146 length = GETVALUE2b((packet_flags >> 5) & 0x03, datap);
147 datap += GETLEN2b((packet_flags >> 5) & 0x03);
148 /* sequence value is not used */
149 GETVALUE2b((packet_flags >> 1) & 0x03, datap);
150 datap += GETLEN2b((packet_flags >> 1) & 0x03);
151 padding_length = GETVALUE2b((packet_flags >> 3) & 0x03, datap);
152 datap += GETLEN2b((packet_flags >> 3) & 0x03);
153 /* send_time = get_long_le(datap); */
154 datap += 4;
155 /* duration = get_short_le(datap); */
156 datap += 2;
157 /*DEBUGF("and duration %d ms\n", duration);*/
158
159 /* this is really idiotic, packet length can (and often will) be
160 * undefined and we just have to use the header packet size as the size
161 * value */
162 if (!((packet_flags >> 5) & 0x03)) {
163 length = wfx->packet_size;
164 }
165
166 /* this is also really idiotic, if packet length is smaller than packet
167 * size, we need to manually add the additional bytes into padding length
168 */
169 if (length < wfx->packet_size) {
170 padding_length += wfx->packet_size - length;
171 length = wfx->packet_size;
172 }
173
174 if (length > wfx->packet_size) {
175 DEBUGF("packet with too big length value\n");
176 return ASF_ERROR_INVALID_LENGTH;
177 }
178
179 /* check if we have multiple payloads */
180 if (packet_flags & 0x01) {
181 if (deadbeef->fread(&tmp8, 1, 1, fp) == 0) {
182 return ASF_ERROR_EOF;
183 }
184 payload_count = tmp8 & 0x3f;
185 payload_length_type = (tmp8 >> 6) & 0x03;
186 bytesread++;
187 } else {
188 payload_count = 1;
189 payload_length_type = 0x02; /* not used */
190 }
191
192 if (length < bytesread) {
193 DEBUGF("header exceeded packet size, invalid file - length=%d, bytesread=%d\n",(int)length,(int)bytesread);
194 /* FIXME: should this be checked earlier? */
195 return ASF_ERROR_INVALID_LENGTH;
196 }
197
198
199 /* We now parse the individual payloads, and move all payloads
200 belonging to our audio stream to a contiguous block, starting at
201 the location of the first payload.
202 */
203
204 *audiobuf = NULL;
205 *audiobufsize = 0;
206 *packetlength = length - bytesread;
207
208 buf = audiobuf_mem;
209 int64_t ret = deadbeef->fread (buf, 1, length-bytesread, fp);
210 #define MIN(x,y) ((x)<(y)) ? (x) : (y)
211 if (ret >= 0) {
212 bufsize = MIN((size_t)ret, length);
213 }
214 else {
215 bufsize = 0;
216 }
217 if (bufsize == 0) {
218 buf = NULL;
219 }
220
221 bufsize = length;
222 datap = buf;
223
224 #define ASF_MAX_REQUEST (1L<<15) /* 32KB */
225 if (bufsize != length && length >= ASF_MAX_REQUEST) {
226 /* This should only happen with packets larger than 32KB (the
227 guard buffer size). All the streams I've seen have
228 relatively small packets less than about 8KB), but I don't
229 know what is expected.
230 */
231 DEBUGF("Could not read packet (requested %d bytes, received %d), curpos=%d, aborting\n",
232 (int)length,(int)bufsize,(int)deadbeef->ftell(fp));
233 return -1;
234 }
235
236 for (i=0; i<payload_count; i++) {
237 stream_id = datap[0]&0x7f;
238 datap++;
239 bytesread++;
240
241 payload_hdrlen = GETLEN2b(packet_property & 0x03) +
242 GETLEN2b((packet_property >> 2) & 0x03) +
243 GETLEN2b((packet_property >> 4) & 0x03);
244
245 //DEBUGF("payload_hdrlen = %d\n",payload_hdrlen);
246 #if 0
247 /* TODO */
248 if (payload_hdrlen > size) {
249 return ASF_ERROR_INVALID_LENGTH;
250 }
251 #endif
252 if (payload_hdrlen > sizeof(data)) {
253 DEBUGF("Unexpectedly long datalen in data - %d\n",datalen);
254 return ASF_ERROR_OUTOFMEM;
255 }
256
257 bytesread += payload_hdrlen;
258 /* media_object_number = GETVALUE2b((packet_property >> 4) & 0x03, datap); */
259 datap += GETLEN2b((packet_property >> 4) & 0x03);
260 /* media_object_offset = GETVALUE2b((packet_property >> 2) & 0x03, datap); */
261 datap += GETLEN2b((packet_property >> 2) & 0x03);
262 replicated_length = GETVALUE2b(packet_property & 0x03, datap);
263 datap += GETLEN2b(packet_property & 0x03);
264
265 /* TODO: Validate replicated_length */
266 /* TODO: Is the content of this important for us? */
267 datap += replicated_length;
268 bytesread += replicated_length;
269
270 multiple = packet_flags & 0x01;
271
272
273 if (multiple) {
274 int x;
275
276 x = GETLEN2b(payload_length_type);
277
278 if (x != 2) {
279 /* in multiple payloads datalen should be a word */
280 return ASF_ERROR_INVALID_VALUE;
281 }
282
283 #if 0
284 if (skip + tmp > datalen) {
285 /* not enough data */
286 return ASF_ERROR_INVALID_LENGTH;
287 }
288 #endif
289 payload_datalen = GETVALUE2b(payload_length_type, datap);
290 datap += x;
291 bytesread += x;
292 } else {
293 payload_datalen = length - bytesread - padding_length;
294 }
295
296 if (replicated_length==1)
297 datap++;
298
299 if (stream_id == wfx->audiostream)
300 {
301 if (*audiobuf == NULL) {
302 /* The first payload can stay where it is */
303 *audiobuf = datap;
304 *audiobufsize = payload_datalen;
305 } else {
306 /* The second and subsequent payloads in this packet
307 that belong to the audio stream need to be moved to be
308 contiguous with the first payload.
309 */
310 memmove(*audiobuf + *audiobufsize, datap, payload_datalen);
311 *audiobufsize += payload_datalen;
312 }
313 }
314 datap += payload_datalen;
315 bytesread += payload_datalen;
316 }
317
318 if (*audiobuf != NULL)
319 return 1;
320 else
321 return 0;
322 }
323
324
asf_get_timestamp(int * duration,DB_FILE * fp)325 int asf_get_timestamp(int *duration, DB_FILE *fp)
326 {
327 uint8_t tmp8, packet_flags, packet_property;
328 int ec_length, opaque_data, ec_length_type;
329 int datalen;
330 uint8_t data[18];
331 uint8_t* datap;
332 /* rockbox: comment 'set but unused' variables
333 uint32_t length;
334 uint32_t padding_length;
335 */
336 uint32_t send_time;
337 static int packet_count = 0;
338
339 uint32_t bytesread = 0;
340 packet_count++;
341 if (deadbeef->fread(&tmp8, 1, 1, fp) == 0) {
342 DEBUGF("ASF ERROR (EOF?)\n");
343 return ASF_ERROR_EOF;
344 }
345 bytesread++;
346
347 /* TODO: We need a better way to detect endofstream */
348 if (tmp8 != 0x82) {
349 DEBUGF("Get timestamp: Detected end of stream\n");
350 return ASF_ERROR_EOF;
351 }
352
353
354 if (tmp8 & 0x80) {
355 ec_length = tmp8 & 0x0f;
356 opaque_data = (tmp8 >> 4) & 0x01;
357 ec_length_type = (tmp8 >> 5) & 0x03;
358
359 if (ec_length_type != 0x00 || opaque_data != 0 || ec_length != 0x02) {
360 DEBUGF("incorrect error correction flags\n");
361 return ASF_ERROR_INVALID_VALUE;
362 }
363
364 /* Skip ec_data */
365 SKIP_BYTES(fp, ec_length);
366 bytesread += ec_length;
367 } else {
368 ec_length = 0;
369 }
370
371 if (deadbeef->fread(&packet_flags, 1, 1, fp) == 0) {
372 DEBUGF("Detected end of stream 2\n");
373 return ASF_ERROR_EOF;
374 }
375
376 if (deadbeef->fread(&packet_property, 1, 1, fp) == 0) {
377 DEBUGF("Detected end of stream3\n");
378 return ASF_ERROR_EOF;
379 }
380 bytesread += 2;
381
382 datalen = GETLEN2b((packet_flags >> 1) & 0x03) +
383 GETLEN2b((packet_flags >> 3) & 0x03) +
384 GETLEN2b((packet_flags >> 5) & 0x03) + 6;
385
386 if (deadbeef->fread(data, datalen, 1, fp) == 0) {
387 DEBUGF("Detected end of stream4\n");
388 return ASF_ERROR_EOF;
389 }
390
391 bytesread += datalen;
392
393 datap = data;
394 /* length = GETVALUE2b((packet_flags >> 5) & 0x03, datap); */
395 datap += GETLEN2b((packet_flags >> 5) & 0x03);
396
397 /* sequence value is not used */
398 GETVALUE2b((packet_flags >> 1) & 0x03, datap);
399 datap += GETLEN2b((packet_flags >> 1) & 0x03);
400 /* padding_length = GETVALUE2b((packet_flags >> 3) & 0x03, datap); */
401 datap += GETLEN2b((packet_flags >> 3) & 0x03);
402 send_time = get_long_le(datap);
403 datap += 4;
404 *duration = get_short_le(datap);
405
406 /*the asf_get_timestamp function advances us 12-13 bytes past the packet start,
407 need to undo this here so that we stay synced with the packet*/
408 deadbeef->fseek (fp, -bytesread, SEEK_CUR);
409
410 return send_time;
411 }
412
413 /*entry point for seeks*/
asf_seek(int ms,asf_waveformatex_t * wfx,DB_FILE * fp,int64_t first_frame_offset,int * skip_ms)414 int asf_seek(int ms, asf_waveformatex_t* wfx, DB_FILE *fp, int64_t first_frame_offset, int *skip_ms)
415 {
416 int time, duration, delta, temp, count=0;
417
418 /*estimate packet number from bitrate*/
419 int64_t datasize = deadbeef->fgetlength (fp) - first_frame_offset;
420
421 int initial_packet = (deadbeef->ftell (fp) - first_frame_offset) / wfx->packet_size;
422 int packet_num = (((int64_t)ms)*(wfx->bitrate>>3))/wfx->packet_size/1000;
423 int last_packet = datasize / wfx->packet_size;
424
425 if (packet_num > last_packet) {
426 packet_num = last_packet;
427 }
428
429 /*calculate byte address of the start of that packet*/
430 int64_t packet_offset = packet_num*wfx->packet_size;
431 trace ("initial_packet: %d\n", initial_packet);
432 trace ("packet_num: %d\n", packet_num);
433 trace ("last_packet: %d\n", last_packet);
434 trace ("packet_offset: %lld\n", packet_offset);
435
436 /*seek to estimated packet*/
437 deadbeef->fseek (fp, first_frame_offset+packet_offset, SEEK_SET);
438 temp = ms;
439 while (1)
440 {
441 /*for very large files it can be difficult and unimportant to find the exact packet*/
442 count++;
443
444 /*check the time stamp of our packet*/
445 int64_t pos = deadbeef->ftell (fp);
446 time = asf_get_timestamp(&duration, fp) - wfx->first_frame_timestamp;
447 // DEBUGF("time %d ms with duration %d\n", time, duration);
448
449 if (time < 0) {
450 /*unknown error, try to recover*/
451 DEBUGF("UKNOWN SEEK ERROR\n");
452 deadbeef->fseek (fp, first_frame_offset+initial_packet*wfx->packet_size, SEEK_SET);
453 *skip_ms = 0;
454 /*seek failed so return time stamp of the initial packet*/
455 return -1;
456 }
457
458 DEBUGF("time: %d, duration: %d (ms: %d)\n", time, duration, ms);
459 if (time <= ms && (time+duration>=ms || count > 10)) {
460 int mn = (int)(ms * 0.001f / 60);
461 int sc = ms * 0.001f - mn * 60;
462 int pmn = (int)(time * 0.001f / 60);
463 int psc = time * 0.001f - pmn * 60;
464 DEBUGF("Found our packet! Now at %d packet, time %d (%d:%d), ms %d (%d:%d), duration %d, count %d\n", packet_num, time, pmn, psc, ms, mn, sc, duration, count);
465 deadbeef->fseek (fp, pos, SEEK_SET);
466 *skip_ms = ms > time ? ms - time : 0;
467 return time;
468 } else {
469 /*seek again*/
470 delta = ms-time;
471 /*estimate new packet number from bitrate and our current position*/
472 temp += delta;
473 packet_num = ((temp/1000)*(wfx->bitrate>>3) - (wfx->packet_size>>1))/wfx->packet_size; //round down!
474 packet_offset = packet_num*wfx->packet_size;
475 deadbeef->fseek (fp, first_frame_offset+packet_offset, SEEK_SET);
476 }
477 }
478 }
479
480