1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
Index: apps/mp3data.h
===================================================================
--- apps/mp3data.h  (revision 29537)
+++ apps/mp3data.h  (working copy)
@@ -57,17 +57,29 @@

 #define MAX_XING_HEADER_SIZE 576

-unsigned long find_next_frame(int fd, long *offset, long max_offset,
-                              unsigned long last_header);
-unsigned long mem_find_next_frame(int startpos, long *offset, long max_offset,
-                                  unsigned long last_header);
-int get_mp3file_info(int fd, struct mp3info *info);
-int count_mp3_frames(int fd, int startpos, int filesize,
+unsigned long find_next_frame(int fd, 
+                              long *offset, 
+                              long max_offset,
+                              unsigned long reference_header);
+unsigned long mem_find_next_frame(int startpos, 
+                                  long *offset, 
+                                  long max_offset, 
+                                  unsigned long reference_header);
+int get_mp3file_info(int fd, 
+                     struct mp3info *info);
+int count_mp3_frames(int fd, 
+                     int startpos, 
+                     int filesize,
                      void (*progressfunc)(int));
-int create_xing_header(int fd, long startpos, long filesize,
-                       unsigned char *buf, unsigned long num_frames,
-                       unsigned long rec_time, unsigned long header_template,
-                       void (*progressfunc)(int), bool generate_toc);
+int create_xing_header(int fd, 
+                       long startpos, 
+                       long filesize,
+                       unsigned char *buf, 
+                       unsigned long num_frames,
+                       unsigned long rec_time, 
+                       unsigned long header_template,
+                       void (*progressfunc)(int), 
+                       bool generate_toc);

 extern unsigned long bytes2int(unsigned long b0,
                                unsigned long b1,
Index: apps/plugin.h
===================================================================
--- apps/plugin.h  (revision 29537)
+++ apps/plugin.h  (working copy)
@@ -818,7 +818,7 @@
             unsigned long rec_time, unsigned long header_template,
             void (*progressfunc)(int), bool generate_toc);
     unsigned long (*find_next_frame)(int fd, long *offset,
-            long max_offset, unsigned long last_header);
+            long max_offset, unsigned long reference_header);

 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
     unsigned short (*peak_meter_scale_value)(unsigned short val,
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. If header1 is zero
+     * it is assumed the headers are of same type. */
+    unsigned int mask = 0xfffe0c00;
+    header1 &= mask;
+    header2 &= mask;
+    return header1 ? (header1 == header2) : true;
+}
+
 static unsigned long __find_next_frame(int fd, long *offset, long max_offset,
-                                       unsigned long last_header,
-                                       int(*getfunc)(int fd, unsigned char *c))
+                                       unsigned long reference_header,
+                                       int(*getfunc)(int fd, unsigned char *c),
+                                       bool single_header)
 {
     unsigned long header=0;
     unsigned char tmp;
-    int i;
+    long pos      = 0;

-    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;
-    
-    /* Fill up header with first 24 bits */
-    for(i = 0; i < 3; i++) {
-        header <<= 8;
-        if(!getfunc(fd, &tmp))
-            return 0;
-        header |= tmp;
-        pos++;
-    }
-
+    /* 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 stream. */
     do {
+        /* Read 1 new 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 that has the same
+                 * type as the reference_header. We are finished. */
+                if (headers_have_same_type(reference_header, header))
+                    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. */
+                reference_header = 0;
+                read_uint32be(fd, (uint32_t*)&reference_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(header, reference_header))
+                    break;
+            }
+        }
+  
+    } while (true);

     *offset = pos - 4;

@@ -248,9 +283,13 @@
     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 reference_header)
 {
-    return __find_next_frame(fd, offset, max_offset, last_header, fileread);
+    return __find_next_frame(fd, offset, max_offset, reference_header, 
+                             fileread, true);
 }

 #ifndef __PCTOOL__
@@ -312,10 +351,9 @@
     fnf_read_index = 0;
 }

-static unsigned long buf_find_next_frame(int fd, long *offset, long max_offset,
-                                         unsigned long last_header)
+static unsigned long buf_find_next_frame(int fd, long *offset, long max_offset)
 {
-    return __find_next_frame(fd, offset, max_offset, last_header, buf_getbyte);
+    return __find_next_frame(fd, offset, max_offset, 0, buf_getbyte, true);
 }

 static int audiobuflen;
@@ -337,15 +375,18 @@
         return 1;
 }

-unsigned long mem_find_next_frame(int startpos, long *offset, long max_offset,
-                                  unsigned long last_header)
+unsigned long mem_find_next_frame(int startpos, 
+                                  long *offset, 
+                                  long max_offset,
+                                  unsigned long reference_header)
 {
     audiobuflen = audiobufend - audiobuf;
     mem_pos = startpos;
     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, reference_header, 
+                             mem_getbyte, true);
 }
 #endif

@@ -446,17 +487,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 +522,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 +558,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 +572,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 +581,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;
@@ -574,7 +625,7 @@
     num_frames = 0;
     cnt = 0;

-    while((header = buf_find_next_frame(fd, &bytes, -1, header_template))) {
+    while((header = buf_find_next_frame(fd, &bytes, header_template))) {
         mp3headerinfo(&info, header);

         if(!header_template)
@@ -649,7 +700,7 @@
             /* Advance from the last seek point to this one */
             for(j = 0;j < pos - last_pos;j++)
             {
-                header = buf_find_next_frame(fd, &bytes, -1, header_template);
+                header = buf_find_next_frame(fd, &bytes, header_template);
                 filepos += bytes;
                 mp3headerinfo(&info, header);
                 buf_seek(fd, info.frame_size-4);