summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndree Buschmann <AndreeBuschmann@t-online.de>2011-03-16 18:45:03 +0000
committerAndree Buschmann <AndreeBuschmann@t-online.de>2011-03-16 18:45:03 +0000
commit25246f7e477eebe1cfd25741ba4744cc3b577684 (patch)
tree63a893259b1183177e7166acd65b6e9926690fb4
parent8c46ddf9d719fb29f483dc21993167907953f39c (diff)
downloadrockbox-25246f7e477eebe1cfd25741ba4744cc3b577684.tar.gz
rockbox-25246f7e477eebe1cfd25741ba4744cc3b577684.zip
More robust implementation of MPEG frame header search. The parser will not only search for the very first byte sequence that looks like a valid MPEG frame header. It will search for a valid MPEG frame header sequence, decode it, and probe if there is a consecutive MPEG frame header of the same type (MPEG version, layer, sampling frequency) at the expected position. This approach will reduce false detection of MPEG frame headers in case of errorous metadata or garbaged files. Fixes FS#12007.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29603 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/mp3data.c130
-rw-r--r--apps/mp3data.h32
-rw-r--r--apps/plugin.h2
3 files changed, 114 insertions, 50 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
205static 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
204static unsigned long __find_next_frame(int fd, long *offset, long max_offset, 216static 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
251unsigned long find_next_frame(int fd, long *offset, long max_offset, unsigned long last_header) 287unsigned 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
315static unsigned long buf_find_next_frame(int fd, long *offset, long max_offset, 355static 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
321static int audiobuflen; 360static 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
340unsigned long mem_find_next_frame(int startpos, long *offset, long max_offset, 379unsigned 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. */
449static int get_next_header_info(int fd, long *bytecount, struct mp3info *info) 491static 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);
diff --git a/apps/mp3data.h b/apps/mp3data.h
index 0fccd62827..edda352aab 100644
--- a/apps/mp3data.h
+++ b/apps/mp3data.h
@@ -57,17 +57,29 @@ struct mp3info {
57 57
58#define MAX_XING_HEADER_SIZE 576 58#define MAX_XING_HEADER_SIZE 576
59 59
60unsigned long find_next_frame(int fd, long *offset, long max_offset, 60unsigned long find_next_frame(int fd,
61 unsigned long last_header); 61 long *offset,
62unsigned long mem_find_next_frame(int startpos, long *offset, long max_offset, 62 long max_offset,
63 unsigned long last_header); 63 unsigned long reference_header);
64int get_mp3file_info(int fd, struct mp3info *info); 64unsigned long mem_find_next_frame(int startpos,
65int count_mp3_frames(int fd, int startpos, int filesize, 65 long *offset,
66 long max_offset,
67 unsigned long reference_header);
68int get_mp3file_info(int fd,
69 struct mp3info *info);
70int count_mp3_frames(int fd,
71 int startpos,
72 int filesize,
66 void (*progressfunc)(int)); 73 void (*progressfunc)(int));
67int create_xing_header(int fd, long startpos, long filesize, 74int create_xing_header(int fd,
68 unsigned char *buf, unsigned long num_frames, 75 long startpos,
69 unsigned long rec_time, unsigned long header_template, 76 long filesize,
70 void (*progressfunc)(int), bool generate_toc); 77 unsigned char *buf,
78 unsigned long num_frames,
79 unsigned long rec_time,
80 unsigned long header_template,
81 void (*progressfunc)(int),
82 bool generate_toc);
71 83
72extern unsigned long bytes2int(unsigned long b0, 84extern unsigned long bytes2int(unsigned long b0,
73 unsigned long b1, 85 unsigned long b1,
diff --git a/apps/plugin.h b/apps/plugin.h
index de720d41eb..13b66e1202 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -819,7 +819,7 @@ struct plugin_api {
819 unsigned long rec_time, unsigned long header_template, 819 unsigned long rec_time, unsigned long header_template,
820 void (*progressfunc)(int), bool generate_toc); 820 void (*progressfunc)(int), bool generate_toc);
821 unsigned long (*find_next_frame)(int fd, long *offset, 821 unsigned long (*find_next_frame)(int fd, long *offset,
822 long max_offset, unsigned long last_header); 822 long max_offset, unsigned long reference_header);
823 823
824#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) 824#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
825 unsigned short (*peak_meter_scale_value)(unsigned short val, 825 unsigned short (*peak_meter_scale_value)(unsigned short val,