diff options
author | Solomon Peachy <pizza@shaftnet.org> | 2021-06-12 21:06:55 -0400 |
---|---|---|
committer | Solomon Peachy <pizza@shaftnet.org> | 2021-06-13 12:13:03 -0400 |
commit | 756c0d2ac82515ea8389c69f5f87ca395daca63d (patch) | |
tree | b835234ad7c6a084c4bda5c9d2db10bd0750c5d8 /lib/rbcodec/metadata/mp3data.c | |
parent | c067b344e8da0c9b6a9b785100661f598f64a5d3 (diff) | |
download | rockbox-756c0d2ac82515ea8389c69f5f87ca395daca63d.tar.gz rockbox-756c0d2ac82515ea8389c69f5f87ca395daca63d.zip |
FS#13299: Simplify VBR frame parsing in the metadata decoder.
The old code would seek forward by the frame length, expecting to see a
frame header there, perform a validity check, and then seek back to the
current header.
Unfortunately this doesn't handle situations where there is extra padding
between the frames, leading us to potentially read garbage, causing the
validity tests to fail and rejecting the file outright.
Instead, keep track of the previous valid header/position, and if we find
"valid" headers in a row return the first after seeking back to it.
This change allows the file referenced in FS13299 to be properly parsed, but
further work is needed to get the file to be playable. (file reports itself
as layer 1, variable bit rate, variable sample rate!)
Change-Id: I85f61a6360cc041a172db4b7a6b5516e5b60ceee
Diffstat (limited to 'lib/rbcodec/metadata/mp3data.c')
-rw-r--r-- | lib/rbcodec/metadata/mp3data.c | 55 |
1 files changed, 18 insertions, 37 deletions
diff --git a/lib/rbcodec/metadata/mp3data.c b/lib/rbcodec/metadata/mp3data.c index 83605126d6..8c800c798a 100644 --- a/lib/rbcodec/metadata/mp3data.c +++ b/lib/rbcodec/metadata/mp3data.c | |||
@@ -212,27 +212,18 @@ static bool headers_have_same_type(unsigned long header1, | |||
212 | return header1 ? (header1 == header2) : true; | 212 | return header1 ? (header1 == header2) : true; |
213 | } | 213 | } |
214 | 214 | ||
215 | /* Helper function to read 4-byte in big endian format. */ | ||
216 | static void read_uint32be_mp3data(int fd, unsigned long *data) | ||
217 | { | ||
218 | #ifdef ROCKBOX_BIG_ENDIAN | ||
219 | (void)read(fd, (char*)data, 4); | ||
220 | #else | ||
221 | (void)read(fd, (char*)data, 4); | ||
222 | *data = betoh32(*data); | ||
223 | #endif | ||
224 | } | ||
225 | |||
226 | static unsigned long __find_next_frame(int fd, long *offset, long max_offset, | 215 | static unsigned long __find_next_frame(int fd, long *offset, long max_offset, |
227 | unsigned long reference_header, | 216 | unsigned long reference_header, |
228 | int(*getfunc)(int fd, unsigned char *c), | 217 | int(*getfunc)(int fd, unsigned char *c), |
229 | bool single_header) | 218 | bool single_header) |
230 | { | 219 | { |
231 | unsigned long header=0; | 220 | uint32_t header=0; |
221 | uint32_t ref_header=0; | ||
222 | long ref_header_pos=0; | ||
232 | unsigned char tmp; | 223 | unsigned char tmp; |
233 | long pos = 0; | 224 | long pos = 0; |
234 | 225 | ||
235 | /* We will search until we find two consecutive MPEG frame headers with | 226 | /* We will search until we find two consecutive MPEG frame headers with |
236 | * the same MPEG version, layer and sampling frequency. The first header | 227 | * the same MPEG version, layer and sampling frequency. The first header |
237 | * of this pair is assumed to be the first valid MPEG frame header of the | 228 | * of this pair is assumed to be the first valid MPEG frame header of the |
238 | * whole stream. */ | 229 | * whole stream. */ |
@@ -243,43 +234,33 @@ static unsigned long __find_next_frame(int fd, long *offset, long max_offset, | |||
243 | return 0; | 234 | return 0; |
244 | header |= tmp; | 235 | header |= tmp; |
245 | pos++; | 236 | pos++; |
246 | 237 | ||
247 | /* Abort if max_offset is reached. Stop parsing. */ | 238 | /* Abort if max_offset is reached. Stop parsing. */ |
248 | if (max_offset > 0 && pos > max_offset) | 239 | if (max_offset > 0 && pos > max_offset) |
249 | return 0; | 240 | return 0; |
250 | 241 | ||
251 | if (is_mp3frameheader(header)) { | 242 | if (is_mp3frameheader(header)) { |
252 | if (single_header) { | 243 | if (single_header) { |
253 | /* We search for one _single_ valid header that has the same | 244 | /* We search for one _single_ valid header that has the same |
254 | * type as the reference_header (if reference_header != 0). | 245 | * type as the reference_header (if reference_header != 0). |
255 | * In this case we are finished. */ | 246 | * In this case we are finished. */ |
256 | if (headers_have_same_type(reference_header, header)) | 247 | if (headers_have_same_type(reference_header, header)) |
257 | break; | 248 | break; |
258 | } else { | 249 | } else { |
259 | /* The current header is valid. Now gather the frame size, | 250 | /* The current header is valid. Compare it against the last |
260 | * seek to this byte position and check if there is another | 251 | one we found. NOTE: ref_header MUST come second! */ |
261 | * valid MPEG frame header of the same type. */ | 252 | if (headers_have_same_type(header, ref_header)) { |
262 | struct mp3info info; | 253 | /* Found a match, return the header and offset of the FIRST */ |
263 | 254 | header = ref_header; | |
264 | /* Gather frame size from given header and seek to next | 255 | lseek(fd, ref_header_pos, SEEK_SET); |
265 | * frame header. */ | ||
266 | mp3headerinfo(&info, header); | ||
267 | lseek(fd, info.frame_size-4, SEEK_CUR); | ||
268 | |||
269 | /* Read possible next frame header and seek back to last frame | ||
270 | * headers byte position. */ | ||
271 | reference_header = 0; | ||
272 | read_uint32be_mp3data(fd, &reference_header); | ||
273 | // | ||
274 | lseek(fd, -info.frame_size, SEEK_CUR); | ||
275 | |||
276 | /* If the current header is of the same type as the previous | ||
277 | * header we are finished. */ | ||
278 | if (headers_have_same_type(header, reference_header)) | ||
279 | break; | 256 | break; |
257 | } | ||
258 | /* Otherwise look for another.. */ | ||
259 | ref_header = header; | ||
260 | ref_header_pos = lseek(fd, 0, SEEK_CUR); | ||
280 | } | 261 | } |
281 | } | 262 | } |
282 | 263 | ||
283 | } while (true); | 264 | } while (true); |
284 | 265 | ||
285 | *offset = pos - 4; | 266 | *offset = pos - 4; |