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, |
