diff options
Diffstat (limited to 'apps/mp3data.c')
-rw-r--r-- | apps/mp3data.c | 130 |
1 files changed, 91 insertions, 39 deletions
diff --git a/apps/mp3data.c b/apps/mp3data.c index bb42c94fc6..89af49849f 100644 --- a/apps/mp3data.c +++ b/apps/mp3data.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include "mp3data.h" | 39 | #include "mp3data.h" |
40 | #include "file.h" | 40 | #include "file.h" |
41 | #include "buffer.h" | 41 | #include "buffer.h" |
42 | #include "metadata/metadata_common.h" | ||
42 | 43 | ||
43 | // #define DEBUG_VERBOSE | 44 | // #define DEBUG_VERBOSE |
44 | 45 | ||
@@ -201,39 +202,74 @@ static bool mp3headerinfo(struct mp3info *info, unsigned long header) | |||
201 | return true; | 202 | return true; |
202 | } | 203 | } |
203 | 204 | ||
205 | static bool headers_have_same_type(unsigned long header1, | ||
206 | unsigned long header2) | ||
207 | { | ||
208 | /* Compare MPEG version, layer and sampling frequency. If header1 is zero | ||
209 | * it is assumed the headers are of same type. */ | ||
210 | unsigned int mask = 0xfffe0c00; | ||
211 | header1 &= mask; | ||
212 | header2 &= mask; | ||
213 | return header1 ? (header1 == header2) : true; | ||
214 | } | ||
215 | |||
204 | static unsigned long __find_next_frame(int fd, long *offset, long max_offset, | 216 | static unsigned long __find_next_frame(int fd, long *offset, long max_offset, |
205 | unsigned long last_header, | 217 | unsigned long reference_header, |
206 | int(*getfunc)(int fd, unsigned char *c)) | 218 | int(*getfunc)(int fd, unsigned char *c), |
219 | bool single_header) | ||
207 | { | 220 | { |
208 | unsigned long header=0; | 221 | unsigned long header=0; |
209 | unsigned char tmp; | 222 | unsigned char tmp; |
210 | int i; | 223 | long pos = 0; |
211 | |||
212 | long pos = 0; | ||
213 | |||
214 | /* We remember the last header we found, to use as a template to see if | ||
215 | the header we find has the same frequency, layer etc */ | ||
216 | last_header &= 0xffff0c00; | ||
217 | |||
218 | /* Fill up header with first 24 bits */ | ||
219 | for(i = 0; i < 3; i++) { | ||
220 | header <<= 8; | ||
221 | if(!getfunc(fd, &tmp)) | ||
222 | return 0; | ||
223 | header |= tmp; | ||
224 | pos++; | ||
225 | } | ||
226 | 224 | ||
225 | /* We will search until we find two consecutive MPEG frame headers with | ||
226 | * the same MPEG version, layer and sampling frequency. The first header | ||
227 | * of this pair is assumed to be the first valid MPEG frame header of the | ||
228 | * whole stream. */ | ||
227 | do { | 229 | do { |
230 | /* Read 1 new byte. */ | ||
228 | header <<= 8; | 231 | header <<= 8; |
229 | if(!getfunc(fd, &tmp)) | 232 | if (!getfunc(fd, &tmp)) |
230 | return 0; | 233 | return 0; |
231 | header |= tmp; | 234 | header |= tmp; |
232 | pos++; | 235 | pos++; |
233 | if(max_offset > 0 && pos > max_offset) | 236 | |
237 | /* Abort if max_offset is reached. Stop parsing. */ | ||
238 | if (max_offset > 0 && pos > max_offset) | ||
234 | return 0; | 239 | return 0; |
235 | } while(!is_mp3frameheader(header) || | 240 | |
236 | (last_header?((header & 0xffff0c00) != last_header):false)); | 241 | if (is_mp3frameheader(header)) { |
242 | if (single_header) { | ||
243 | /* We search for one _single_ valid header that has the same | ||
244 | * type as the reference_header (if reference_header != 0). | ||
245 | * In this case we are finished. */ | ||
246 | if (headers_have_same_type(reference_header, header)) | ||
247 | break; | ||
248 | } else { | ||
249 | /* The current header is valid. Now gather the frame size, | ||
250 | * seek to this byte position and check if there is another | ||
251 | * valid MPEG frame header of the same type. */ | ||
252 | struct mp3info info; | ||
253 | |||
254 | /* Gather frame size from given header and seek to next | ||
255 | * frame header. */ | ||
256 | mp3headerinfo(&info, header); | ||
257 | lseek(fd, info.frame_size-4, SEEK_CUR); | ||
258 | |||
259 | /* Read possible next frame header and seek back to last frame | ||
260 | * headers byte position. */ | ||
261 | reference_header = 0; | ||
262 | read_uint32be(fd, (uint32_t*)&reference_header); | ||
263 | lseek(fd, -info.frame_size, SEEK_CUR); | ||
264 | |||
265 | /* If the current header is of the same type as the previous | ||
266 | * header we are finished. */ | ||
267 | if (headers_have_same_type(header, reference_header)) | ||
268 | break; | ||
269 | } | ||
270 | } | ||
271 | |||
272 | } while (true); | ||
237 | 273 | ||
238 | *offset = pos - 4; | 274 | *offset = pos - 4; |
239 | 275 | ||
@@ -248,9 +284,13 @@ static int fileread(int fd, unsigned char *c) | |||
248 | return read(fd, c, 1); | 284 | return read(fd, c, 1); |
249 | } | 285 | } |
250 | 286 | ||
251 | unsigned long find_next_frame(int fd, long *offset, long max_offset, unsigned long last_header) | 287 | unsigned long find_next_frame(int fd, |
288 | long *offset, | ||
289 | long max_offset, | ||
290 | unsigned long reference_header) | ||
252 | { | 291 | { |
253 | return __find_next_frame(fd, offset, max_offset, last_header, fileread); | 292 | return __find_next_frame(fd, offset, max_offset, reference_header, |
293 | fileread, true); | ||
254 | } | 294 | } |
255 | 295 | ||
256 | #ifndef __PCTOOL__ | 296 | #ifndef __PCTOOL__ |
@@ -312,10 +352,9 @@ static void buf_init(void) | |||
312 | fnf_read_index = 0; | 352 | fnf_read_index = 0; |
313 | } | 353 | } |
314 | 354 | ||
315 | static unsigned long buf_find_next_frame(int fd, long *offset, long max_offset, | 355 | static unsigned long buf_find_next_frame(int fd, long *offset, long max_offset) |
316 | unsigned long last_header) | ||
317 | { | 356 | { |
318 | return __find_next_frame(fd, offset, max_offset, last_header, buf_getbyte); | 357 | return __find_next_frame(fd, offset, max_offset, 0, buf_getbyte, true); |
319 | } | 358 | } |
320 | 359 | ||
321 | static int audiobuflen; | 360 | static int audiobuflen; |
@@ -337,15 +376,18 @@ static int mem_getbyte(int dummy, unsigned char *c) | |||
337 | return 1; | 376 | return 1; |
338 | } | 377 | } |
339 | 378 | ||
340 | unsigned long mem_find_next_frame(int startpos, long *offset, long max_offset, | 379 | unsigned long mem_find_next_frame(int startpos, |
341 | unsigned long last_header) | 380 | long *offset, |
381 | long max_offset, | ||
382 | unsigned long reference_header) | ||
342 | { | 383 | { |
343 | audiobuflen = audiobufend - audiobuf; | 384 | audiobuflen = audiobufend - audiobuf; |
344 | mem_pos = startpos; | 385 | mem_pos = startpos; |
345 | mem_cnt = 0; | 386 | mem_cnt = 0; |
346 | mem_maxlen = max_offset; | 387 | mem_maxlen = max_offset; |
347 | 388 | ||
348 | return __find_next_frame(0, offset, max_offset, last_header, mem_getbyte); | 389 | return __find_next_frame(0, offset, max_offset, reference_header, |
390 | mem_getbyte, true); | ||
349 | } | 391 | } |
350 | #endif | 392 | #endif |
351 | 393 | ||
@@ -446,17 +488,20 @@ static void get_vbri_info(struct mp3info *info, unsigned char *buf) | |||
446 | } | 488 | } |
447 | 489 | ||
448 | /* Seek to next mpeg header and extract relevant information. */ | 490 | /* Seek to next mpeg header and extract relevant information. */ |
449 | static int get_next_header_info(int fd, long *bytecount, struct mp3info *info) | 491 | static int get_next_header_info(int fd, long *bytecount, struct mp3info *info, |
492 | bool single_header) | ||
450 | { | 493 | { |
451 | long tmp; | 494 | long tmp; |
452 | unsigned long header = find_next_frame(fd, &tmp, 0x20000, 0); | 495 | unsigned long header = 0; |
496 | |||
497 | header = __find_next_frame(fd, &tmp, 0x20000, 0, fileread, single_header); | ||
453 | if(header == 0) | 498 | if(header == 0) |
454 | return -1; | 499 | return -1; |
455 | 500 | ||
456 | if(!mp3headerinfo(info, header)) | 501 | if(!mp3headerinfo(info, header)) |
457 | return -2; | 502 | return -2; |
458 | 503 | ||
459 | /* Next header is tmp bytes away. */ | 504 | /* Next frame header is tmp bytes away. */ |
460 | *bytecount += tmp; | 505 | *bytecount += tmp; |
461 | 506 | ||
462 | return 0; | 507 | return 0; |
@@ -478,8 +523,8 @@ int get_mp3file_info(int fd, struct mp3info *info) | |||
478 | info->enc_padding = -1; | 523 | info->enc_padding = -1; |
479 | #endif | 524 | #endif |
480 | 525 | ||
481 | /* Get the very first MPEG frame. */ | 526 | /* Get the very first single MPEG frame. */ |
482 | result = get_next_header_info(fd, &bytecount, info); | 527 | result = get_next_header_info(fd, &bytecount, info, true); |
483 | if(result) | 528 | if(result) |
484 | return result; | 529 | return result; |
485 | 530 | ||
@@ -514,7 +559,7 @@ int get_mp3file_info(int fd, struct mp3info *info) | |||
514 | bytecount += info->frame_size; | 559 | bytecount += info->frame_size; |
515 | 560 | ||
516 | /* Now get the next frame to read the real info about the mp3 stream */ | 561 | /* Now get the next frame to read the real info about the mp3 stream */ |
517 | result = get_next_header_info(fd, &bytecount, info); | 562 | result = get_next_header_info(fd, &bytecount, info, false); |
518 | if(result) | 563 | if(result) |
519 | return result; | 564 | return result; |
520 | 565 | ||
@@ -528,7 +573,7 @@ int get_mp3file_info(int fd, struct mp3info *info) | |||
528 | bytecount += info->frame_size; | 573 | bytecount += info->frame_size; |
529 | 574 | ||
530 | /* Now get the next frame to read the real info about the mp3 stream */ | 575 | /* Now get the next frame to read the real info about the mp3 stream */ |
531 | result = get_next_header_info(fd, &bytecount, info); | 576 | result = get_next_header_info(fd, &bytecount, info, false); |
532 | if(result) | 577 | if(result) |
533 | return result; | 578 | return result; |
534 | 579 | ||
@@ -537,6 +582,13 @@ int get_mp3file_info(int fd, struct mp3info *info) | |||
537 | else | 582 | else |
538 | { | 583 | { |
539 | VDEBUGF("-- No VBR header --\n"); | 584 | VDEBUGF("-- No VBR header --\n"); |
585 | |||
586 | /* There was no VBR header found. So, we seek back to beginning and | ||
587 | * search for the first MPEG frame header of the mp3 stream. */ | ||
588 | lseek(fd, -info->frame_size, SEEK_CUR); | ||
589 | result = get_next_header_info(fd, &bytecount, info, false); | ||
590 | if(result) | ||
591 | return result; | ||
540 | } | 592 | } |
541 | 593 | ||
542 | return bytecount; | 594 | return bytecount; |
@@ -574,7 +626,7 @@ int count_mp3_frames(int fd, int startpos, int filesize, | |||
574 | num_frames = 0; | 626 | num_frames = 0; |
575 | cnt = 0; | 627 | cnt = 0; |
576 | 628 | ||
577 | while((header = buf_find_next_frame(fd, &bytes, -1, header_template))) { | 629 | while((header = buf_find_next_frame(fd, &bytes, header_template))) { |
578 | mp3headerinfo(&info, header); | 630 | mp3headerinfo(&info, header); |
579 | 631 | ||
580 | if(!header_template) | 632 | if(!header_template) |
@@ -649,7 +701,7 @@ int create_xing_header(int fd, long startpos, long filesize, | |||
649 | /* Advance from the last seek point to this one */ | 701 | /* Advance from the last seek point to this one */ |
650 | for(j = 0;j < pos - last_pos;j++) | 702 | for(j = 0;j < pos - last_pos;j++) |
651 | { | 703 | { |
652 | header = buf_find_next_frame(fd, &bytes, -1, header_template); | 704 | header = buf_find_next_frame(fd, &bytes, header_template); |
653 | filepos += bytes; | 705 | filepos += bytes; |
654 | mp3headerinfo(&info, header); | 706 | mp3headerinfo(&info, header); |
655 | buf_seek(fd, info.frame_size-4); | 707 | buf_seek(fd, info.frame_size-4); |