Mercurial > hg > svcore
comparison data/fileio/MP3FileReader.cpp @ 1288:5ef9b4d4bbdb 3.0-integration
Filter out Xing/LAME info frames, rather than letting them go to the mp3 decoder as if they were audio frames. Fixes the 1152-sample zero pad at start of some decoded mp3 files (distinct from decoder delay). The logic here is based on the madplay code.
author | Chris Cannam |
---|---|
date | Thu, 24 Nov 2016 13:32:04 +0000 |
parents | 97f21b03269b |
children | a45312bd9306 |
comparison
equal
deleted
inserted
replaced
1287:97f21b03269b | 1288:5ef9b4d4bbdb |
---|---|
58 m_fileRate = 0; | 58 m_fileRate = 0; |
59 m_fileSize = 0; | 59 m_fileSize = 0; |
60 m_bitrateNum = 0; | 60 m_bitrateNum = 0; |
61 m_bitrateDenom = 0; | 61 m_bitrateDenom = 0; |
62 m_cancelled = false; | 62 m_cancelled = false; |
63 m_mp3FrameCount = 0; | |
63 m_completion = 0; | 64 m_completion = 0; |
64 m_done = false; | 65 m_done = false; |
65 m_reporter = reporter; | 66 m_reporter = reporter; |
66 | 67 |
67 struct stat stat; | 68 struct stat stat; |
145 while ((m_channelCount == 0 || m_fileRate == 0 || m_sampleRate == 0) | 146 while ((m_channelCount == 0 || m_fileRate == 0 || m_sampleRate == 0) |
146 && !m_done) { | 147 && !m_done) { |
147 usleep(10); | 148 usleep(10); |
148 } | 149 } |
149 | 150 |
150 SVDEBUG << "MP3FileReader ctor: exiting with file rate = " << m_fileRate << endl; | 151 SVDEBUG << "MP3FileReader: decoding startup complete, file rate = " << m_fileRate << endl; |
151 } | 152 } |
152 | 153 |
153 if (m_error != "") { | 154 if (m_error != "") { |
154 SVDEBUG << "MP3FileReader::MP3FileReader(\"" << m_path << "\"): ERROR: " << m_error << endl; | 155 SVDEBUG << "MP3FileReader::MP3FileReader(\"" << m_path << "\"): ERROR: " << m_error << endl; |
155 } | 156 } |
294 { | 295 { |
295 DecoderData data; | 296 DecoderData data; |
296 struct mad_decoder decoder; | 297 struct mad_decoder decoder; |
297 | 298 |
298 data.start = (unsigned char const *)mm; | 299 data.start = (unsigned char const *)mm; |
299 data.length = (unsigned long)sz; | 300 data.length = sz; |
300 data.reader = this; | 301 data.reader = this; |
301 | 302 |
302 mad_decoder_init(&decoder, &data, input, 0, 0, output, error, 0); | 303 mad_decoder_init(&decoder, // decoder to initialise |
304 &data, // our own data block for callbacks | |
305 input_callback, // provides (entire) input to mad | |
306 0, // checks header | |
307 filter_callback, // filters frame before decoding | |
308 output_callback, // receives decoded output | |
309 error_callback, // handles decode errors | |
310 0); // "message_func" | |
311 | |
303 mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC); | 312 mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC); |
304 mad_decoder_finish(&decoder); | 313 mad_decoder_finish(&decoder); |
305 | 314 |
315 SVDEBUG << "MP3FileReader: Decoding complete, decoded " << m_mp3FrameCount | |
316 << " mp3 frames" << endl; | |
317 | |
306 m_done = true; | 318 m_done = true; |
307 return true; | 319 return true; |
308 } | 320 } |
309 | 321 |
310 enum mad_flow | 322 enum mad_flow |
311 MP3FileReader::input(void *dp, struct mad_stream *stream) | 323 MP3FileReader::input_callback(void *dp, struct mad_stream *stream) |
312 { | 324 { |
313 DecoderData *data = (DecoderData *)dp; | 325 DecoderData *data = (DecoderData *)dp; |
314 | 326 |
315 if (!data->length) return MAD_FLOW_STOP; | 327 if (!data->length) return MAD_FLOW_STOP; |
316 | 328 |
317 unsigned char const *start = data->start; | 329 unsigned char const *start = data->start; |
318 unsigned long length = data->length; | 330 sv_frame_t length = data->length; |
319 | 331 |
320 #ifdef HAVE_ID3TAG | 332 #ifdef HAVE_ID3TAG |
321 if (length > ID3_TAG_QUERYSIZE) { | 333 while (length > ID3_TAG_QUERYSIZE) { |
322 ssize_t taglen = id3_tag_query(start, ID3_TAG_QUERYSIZE); | 334 ssize_t taglen = id3_tag_query(start, ID3_TAG_QUERYSIZE); |
323 if (taglen > 0) { | 335 if (taglen <= 0) { |
324 SVDEBUG << "MP3FileReader: ID3 tag length to skip: " << taglen << endl; | 336 break; |
325 start += taglen; | 337 } |
326 length -= taglen; | 338 SVDEBUG << "MP3FileReader: ID3 tag length to skip: " << taglen << endl; |
327 } | 339 start += taglen; |
340 length -= taglen; | |
328 } | 341 } |
329 #endif | 342 #endif |
330 | 343 |
331 mad_stream_buffer(stream, start, length); | 344 mad_stream_buffer(stream, start, length); |
332 data->length = 0; | 345 data->length = 0; |
333 | 346 |
334 return MAD_FLOW_CONTINUE; | 347 return MAD_FLOW_CONTINUE; |
335 } | 348 } |
336 | 349 |
337 enum mad_flow | 350 enum mad_flow |
338 MP3FileReader::output(void *dp, | 351 MP3FileReader::filter_callback(void *dp, |
339 struct mad_header const *header, | 352 struct mad_stream const *stream, |
340 struct mad_pcm *pcm) | 353 struct mad_frame *frame) |
354 { | |
355 DecoderData *data = (DecoderData *)dp; | |
356 return data->reader->filter(stream, frame); | |
357 } | |
358 | |
359 enum mad_flow | |
360 MP3FileReader::filter(struct mad_stream const *stream, | |
361 struct mad_frame *) | |
362 { | |
363 struct mad_bitptr ptr = stream->anc_ptr; | |
364 unsigned long fourcc = mad_bit_read(&ptr, 32); | |
365 std::string magic("...."); | |
366 for (int i = 0; i < 4; ++i) { | |
367 magic[3-i] = char((fourcc >> (8*i)) & 0xff); | |
368 } | |
369 if (magic == "Xing" || magic == "Info" || magic == "LAME") { | |
370 SVDEBUG << "MP3FileReader: Discarding metadata frame (magic = \"" | |
371 << magic << "\")" << " at frame " << m_mp3FrameCount << endl; | |
372 return MAD_FLOW_IGNORE; | |
373 } else { | |
374 return MAD_FLOW_CONTINUE; | |
375 } | |
376 } | |
377 | |
378 enum mad_flow | |
379 MP3FileReader::output_callback(void *dp, | |
380 struct mad_header const *header, | |
381 struct mad_pcm *pcm) | |
341 { | 382 { |
342 DecoderData *data = (DecoderData *)dp; | 383 DecoderData *data = (DecoderData *)dp; |
343 return data->reader->accept(header, pcm); | 384 return data->reader->accept(header, pcm); |
344 } | 385 } |
345 | 386 |
347 MP3FileReader::accept(struct mad_header const *header, | 388 MP3FileReader::accept(struct mad_header const *header, |
348 struct mad_pcm *pcm) | 389 struct mad_pcm *pcm) |
349 { | 390 { |
350 int channels = pcm->channels; | 391 int channels = pcm->channels; |
351 int frames = pcm->length; | 392 int frames = pcm->length; |
352 | 393 |
353 if (header) { | 394 if (header) { |
354 m_bitrateNum = m_bitrateNum + double(header->bitrate); | 395 m_bitrateNum = m_bitrateNum + double(header->bitrate); |
355 m_bitrateDenom ++; | 396 m_bitrateDenom ++; |
356 } | 397 } |
357 | 398 |
421 } | 462 } |
422 } | 463 } |
423 | 464 |
424 addSamplesToDecodeCache(m_samplebuffer, frames); | 465 addSamplesToDecodeCache(m_samplebuffer, frames); |
425 | 466 |
467 ++m_mp3FrameCount; | |
468 | |
426 return MAD_FLOW_CONTINUE; | 469 return MAD_FLOW_CONTINUE; |
427 } | 470 } |
428 | 471 |
429 enum mad_flow | 472 enum mad_flow |
430 MP3FileReader::error(void *dp, | 473 MP3FileReader::error_callback(void *dp, |
431 struct mad_stream *stream, | 474 struct mad_stream *stream, |
432 struct mad_frame *) | 475 struct mad_frame *) |
433 { | 476 { |
434 DecoderData *data = (DecoderData *)dp; | 477 DecoderData *data = (DecoderData *)dp; |
435 if (!data->reader->m_decodeErrorShown) { | 478 if (!data->reader->m_decodeErrorShown) { |
436 char buffer[256]; | 479 char buffer[256]; |
437 snprintf(buffer, 255, | 480 snprintf(buffer, 255, |