Index: apps/mp3data.c =================================================================== --- apps/mp3data.c (revision 29583) +++ apps/mp3data.c (working copy) @@ -39,6 +39,7 @@ #include "mp3data.h" #include "file.h" #include "buffer.h" +#include "metadata/metadata_common.h" // #define DEBUG_VERBOSE @@ -201,39 +202,73 @@ return true; } +static bool headers_have_same_type(unsigned long header1, + unsigned long header2) +{ + /* Compare MPEG version, layer and sampling frequency. */ + unsigned int mask = 0xfffe0c00; + header1 &= mask; + header2 &= mask; + return header1 ? (header1 == header2) : false; +} + static unsigned long __find_next_frame(int fd, long *offset, long max_offset, unsigned long last_header, - int(*getfunc)(int fd, unsigned char *c)) + int(*getfunc)(int fd, unsigned char *c), + bool single_header) { unsigned long header=0; unsigned char tmp; - int i; - - long pos = 0; - - /* We remember the last header we found, to use as a template to see if - the header we find has the same frequency, layer etc */ - last_header &= 0xffff0c00; + long pos = 0; - /* Fill up header with first 24 bits */ - for(i = 0; i < 3; i++) { - header <<= 8; - if(!getfunc(fd, &tmp)) - return 0; - header |= tmp; - pos++; - } + /* Only keep last_header if it is a valid mp3 frame header. */ + last_header = is_mp3frameheader(last_header) ? last_header : 0; + /* We will search until we find two consecutive MPEG frame headers with + * the same MPEG version, layer and sampling frequency. The first header + * of this pair is assumed to be the first valid MPEG frame header of the + * whole file. */ do { + /* Shift by 1 byte. */ header <<= 8; - if(!getfunc(fd, &tmp)) + if (!getfunc(fd, &tmp)) return 0; header |= tmp; pos++; - if(max_offset > 0 && pos > max_offset) + + /* Abort if max_offset is reached. Stop parsing. */ + if (max_offset > 0 && pos > max_offset) return 0; - } while(!is_mp3frameheader(header) || - (last_header?((header & 0xffff0c00) != last_header):false)); + + if (is_mp3frameheader(header)) { + if (single_header) { + /* We only search for a single valid header. We are finished. */ + break; + } else { + /* The current header is valid. Now gather the frame size, + * seek to this byte position and check if there is another + * valid MPEG frame header of the same type. */ + struct mp3info info; + + /* Gather frame size from given header and seek to next + * frame header. */ + mp3headerinfo(&info, header); + lseek(fd, info.frame_size-4, SEEK_CUR); + + /* Read possible next frame header and seek back to last frame + * headers byte position. */ + last_header = 0; + read_uint32be(fd, (uint32_t*)&last_header); + lseek(fd, -info.frame_size, SEEK_CUR); + + /* The current header is valid and is of the same type as the + * previous one. We are finished. */ + if (headers_have_same_type(last_header, header)) + break; + } + } + + } while (true); *offset = pos - 4; @@ -248,9 +283,10 @@ return read(fd, c, 1); } -unsigned long find_next_frame(int fd, long *offset, long max_offset, unsigned long last_header) +unsigned long find_next_frame(int fd, long *offset, long max_offset, + unsigned long last_header) { - return __find_next_frame(fd, offset, max_offset, last_header, fileread); + return __find_next_frame(fd, offset, max_offset, last_header, fileread, true); } #ifndef __PCTOOL__ @@ -315,7 +351,7 @@ static unsigned long buf_find_next_frame(int fd, long *offset, long max_offset, unsigned long last_header) { - return __find_next_frame(fd, offset, max_offset, last_header, buf_getbyte); + return __find_next_frame(fd, offset, max_offset, last_header, buf_getbyte, true); } static int audiobuflen; @@ -345,7 +381,7 @@ mem_cnt = 0; mem_maxlen = max_offset; - return __find_next_frame(0, offset, max_offset, last_header, mem_getbyte); + return __find_next_frame(0, offset, max_offset, last_header, mem_getbyte, true); } #endif @@ -446,17 +482,20 @@ } /* Seek to next mpeg header and extract relevant information. */ -static int get_next_header_info(int fd, long *bytecount, struct mp3info *info) +static int get_next_header_info(int fd, long *bytecount, struct mp3info *info, + bool single_header) { long tmp; - unsigned long header = find_next_frame(fd, &tmp, 0x20000, 0); + unsigned long header = 0; + + header = __find_next_frame(fd, &tmp, 0x20000, 0, fileread, single_header); if(header == 0) return -1; if(!mp3headerinfo(info, header)) return -2; - /* Next header is tmp bytes away. */ + /* Next frame header is tmp bytes away. */ *bytecount += tmp; return 0; @@ -478,8 +517,8 @@ info->enc_padding = -1; #endif - /* Get the very first MPEG frame. */ - result = get_next_header_info(fd, &bytecount, info); + /* Get the very first single MPEG frame. */ + result = get_next_header_info(fd, &bytecount, info, true); if(result) return result; @@ -514,7 +553,7 @@ bytecount += info->frame_size; /* Now get the next frame to read the real info about the mp3 stream */ - result = get_next_header_info(fd, &bytecount, info); + result = get_next_header_info(fd, &bytecount, info, false); if(result) return result; @@ -528,7 +567,7 @@ bytecount += info->frame_size; /* Now get the next frame to read the real info about the mp3 stream */ - result = get_next_header_info(fd, &bytecount, info); + result = get_next_header_info(fd, &bytecount, info, false); if(result) return result; @@ -537,6 +576,13 @@ else { VDEBUGF("-- No VBR header --\n"); + + /* There was no VBR header found. So, we seek back to beginning and + * search for the first MPEG frame header of the mp3 stream. */ + lseek(fd, -info->frame_size, SEEK_CUR); + result = get_next_header_info(fd, &bytecount, info, false); + if(result) + return result; } return bytecount;