comparison data/fileio/MP3FileReader.cpp @ 1290:fa574c909c3d 3.0-integration

Add MAD_BUFFER_GUARD padding at end of mp3 buffer, in order to ensure last frame is decoded successfully (otherwise the decoded audio is truncated). Another thing learned from madplay.
author Chris Cannam
date Thu, 24 Nov 2016 17:06:31 +0000
parents a45312bd9306
children 9f9f55a8af92
comparison
equal deleted inserted replaced
1289:a45312bd9306 1290:fa574c909c3d
71 return; 71 return;
72 } 72 }
73 73
74 m_fileSize = stat.st_size; 74 m_fileSize = stat.st_size;
75 75
76 m_filebuffer = 0; 76 m_fileBuffer = 0;
77 m_samplebuffer = 0; 77 m_fileBufferSize = 0;
78 m_samplebuffersize = 0; 78
79 m_sampleBuffer = 0;
80 m_sampleBufferSize = 0;
79 81
80 int fd = -1; 82 int fd = -1;
81 if ((fd = ::open(m_path.toLocal8Bit().data(), O_RDONLY 83 if ((fd = ::open(m_path.toLocal8Bit().data(), O_RDONLY
82 #ifdef _WIN32 84 #ifdef _WIN32
83 | O_BINARY 85 | O_BINARY
86 m_error = QString("Failed to open file %1 for reading.").arg(m_path); 88 m_error = QString("Failed to open file %1 for reading.").arg(m_path);
87 return; 89 return;
88 } 90 }
89 91
90 try { 92 try {
91 m_filebuffer = new unsigned char[m_fileSize]; 93 // We need a mysterious MAD_BUFFER_GUARD (== 8) zero bytes at
94 // end of input, to ensure libmad decodes the last frame
95 // correctly. Otherwise the decoded audio is truncated.
96 m_fileBufferSize = m_fileSize + MAD_BUFFER_GUARD;
97 m_fileBuffer = new unsigned char[m_fileBufferSize];
98 memset(m_fileBuffer + m_fileSize, 0, MAD_BUFFER_GUARD);
92 } catch (...) { 99 } catch (...) {
93 m_error = QString("Out of memory"); 100 m_error = QString("Out of memory");
94 ::close(fd); 101 ::close(fd);
95 return; 102 return;
96 } 103 }
97 104
98 ssize_t sz = 0; 105 ssize_t sz = 0;
99 ssize_t offset = 0; 106 ssize_t offset = 0;
100 while (offset < m_fileSize) { 107 while (offset < m_fileSize) {
101 sz = ::read(fd, m_filebuffer + offset, m_fileSize - offset); 108 sz = ::read(fd, m_fileBuffer + offset, m_fileSize - offset);
102 if (sz < 0) { 109 if (sz < 0) {
103 m_error = QString("Read error for file %1 (after %2 bytes)") 110 m_error = QString("Read error for file %1 (after %2 bytes)")
104 .arg(m_path).arg(offset); 111 .arg(m_path).arg(offset);
105 delete[] m_filebuffer; 112 delete[] m_fileBuffer;
106 ::close(fd); 113 ::close(fd);
107 return; 114 return;
108 } else if (sz == 0) { 115 } else if (sz == 0) {
109 cerr << QString("MP3FileReader::MP3FileReader: Warning: reached EOF after only %1 of %2 bytes") 116 SVCERR << QString("MP3FileReader::MP3FileReader: Warning: reached EOF after only %1 of %2 bytes")
110 .arg(offset).arg(m_fileSize) << endl; 117 .arg(offset).arg(m_fileSize) << endl;
111 m_fileSize = offset; 118 m_fileSize = offset;
119 m_fileBufferSize = m_fileSize + MAD_BUFFER_GUARD;
120 memset(m_fileBuffer + m_fileSize, 0, MAD_BUFFER_GUARD);
112 break; 121 break;
113 } 122 }
114 offset += sz; 123 offset += sz;
115 } 124 }
116 125
124 connect(m_reporter, SIGNAL(cancelled()), this, SLOT(cancelled())); 133 connect(m_reporter, SIGNAL(cancelled()), this, SLOT(cancelled()));
125 m_reporter->setMessage 134 m_reporter->setMessage
126 (tr("Decoding %1...").arg(QFileInfo(m_path).fileName())); 135 (tr("Decoding %1...").arg(QFileInfo(m_path).fileName()));
127 } 136 }
128 137
129 if (!decode(m_filebuffer, m_fileSize)) { 138 if (!decode(m_fileBuffer, m_fileBufferSize)) {
130 m_error = QString("Failed to decode file %1.").arg(m_path); 139 m_error = QString("Failed to decode file %1.").arg(m_path);
131 } 140 }
132 141
133 delete[] m_filebuffer; 142 delete[] m_fileBuffer;
134 m_filebuffer = 0; 143 m_fileBuffer = 0;
135 144
136 if (isDecodeCacheInitialised()) finishDecodeCache(); 145 if (isDecodeCacheInitialised()) finishDecodeCache();
137 endSerialised(); 146 endSerialised();
138 147
139 } else { 148 } else {
265 } 274 }
266 275
267 void 276 void
268 MP3FileReader::DecodeThread::run() 277 MP3FileReader::DecodeThread::run()
269 { 278 {
270 if (!m_reader->decode(m_reader->m_filebuffer, m_reader->m_fileSize)) { 279 if (!m_reader->decode(m_reader->m_fileBuffer, m_reader->m_fileBufferSize)) {
271 m_reader->m_error = QString("Failed to decode file %1.").arg(m_reader->m_path); 280 m_reader->m_error = QString("Failed to decode file %1.").arg(m_reader->m_path);
272 } 281 }
273 282
274 delete[] m_reader->m_filebuffer; 283 delete[] m_reader->m_fileBuffer;
275 m_reader->m_filebuffer = 0; 284 m_reader->m_fileBuffer = 0;
276 285
277 if (m_reader->m_samplebuffer) { 286 if (m_reader->m_sampleBuffer) {
278 for (int c = 0; c < m_reader->m_channelCount; ++c) { 287 for (int c = 0; c < m_reader->m_channelCount; ++c) {
279 delete[] m_reader->m_samplebuffer[c]; 288 delete[] m_reader->m_sampleBuffer[c];
280 } 289 }
281 delete[] m_reader->m_samplebuffer; 290 delete[] m_reader->m_sampleBuffer;
282 m_reader->m_samplebuffer = 0; 291 m_reader->m_sampleBuffer = 0;
283 } 292 }
284 293
285 if (m_reader->isDecodeCacheInitialised()) m_reader->finishDecodeCache(); 294 if (m_reader->isDecodeCacheInitialised()) m_reader->finishDecodeCache();
286 295
287 m_reader->m_done = true; 296 m_reader->m_done = true;
428 m_completion = p; 437 m_completion = p;
429 m_reporter->setProgress(m_completion); 438 m_reporter->setProgress(m_completion);
430 } 439 }
431 } 440 }
432 441
433 if (m_cancelled) return MAD_FLOW_STOP; 442 if (m_cancelled) {
443 SVDEBUG << "MP3FileReader: Decoding cancelled" << endl;
444 return MAD_FLOW_STOP;
445 }
434 446
435 if (!isDecodeCacheInitialised()) { 447 if (!isDecodeCacheInitialised()) {
436 initialiseDecodeCache(); 448 initialiseDecodeCache();
437 } 449 }
438 450
439 if (int(m_samplebuffersize) < frames) { 451 if (m_sampleBufferSize < size_t(frames)) {
440 if (!m_samplebuffer) { 452 if (!m_sampleBuffer) {
441 m_samplebuffer = new float *[channels]; 453 m_sampleBuffer = new float *[channels];
442 for (int c = 0; c < channels; ++c) { 454 for (int c = 0; c < channels; ++c) {
443 m_samplebuffer[c] = 0; 455 m_sampleBuffer[c] = 0;
444 } 456 }
445 } 457 }
446 for (int c = 0; c < channels; ++c) { 458 for (int c = 0; c < channels; ++c) {
447 delete[] m_samplebuffer[c]; 459 delete[] m_sampleBuffer[c];
448 m_samplebuffer[c] = new float[frames]; 460 m_sampleBuffer[c] = new float[frames];
449 } 461 }
450 m_samplebuffersize = frames; 462 m_sampleBufferSize = frames;
451 } 463 }
452 464
453 int activeChannels = int(sizeof(pcm->samples) / sizeof(pcm->samples[0])); 465 int activeChannels = int(sizeof(pcm->samples) / sizeof(pcm->samples[0]));
454 466
455 for (int ch = 0; ch < channels; ++ch) { 467 for (int ch = 0; ch < channels; ++ch) {
460 if (ch < activeChannels) { 472 if (ch < activeChannels) {
461 sample = pcm->samples[ch][i]; 473 sample = pcm->samples[ch][i];
462 } 474 }
463 float fsample = float(sample) / float(MAD_F_ONE); 475 float fsample = float(sample) / float(MAD_F_ONE);
464 476
465 m_samplebuffer[ch][i] = fsample; 477 m_sampleBuffer[ch][i] = fsample;
466 } 478 }
467 } 479 }
468 480
469 addSamplesToDecodeCache(m_samplebuffer, frames); 481 addSamplesToDecodeCache(m_sampleBuffer, frames);
470 482
471 ++m_mp3FrameCount; 483 ++m_mp3FrameCount;
472 484
473 return MAD_FLOW_CONTINUE; 485 return MAD_FLOW_CONTINUE;
474 } 486 }
477 MP3FileReader::error_callback(void *dp, 489 MP3FileReader::error_callback(void *dp,
478 struct mad_stream *stream, 490 struct mad_stream *stream,
479 struct mad_frame *) 491 struct mad_frame *)
480 { 492 {
481 DecoderData *data = (DecoderData *)dp; 493 DecoderData *data = (DecoderData *)dp;
494
495 if (stream->error == MAD_ERROR_LOSTSYNC &&
496 data->length == 0) {
497 // We are at end of file, losing sync is expected behaviour
498 return MAD_FLOW_CONTINUE;
499 }
500
482 if (!data->reader->m_decodeErrorShown) { 501 if (!data->reader->m_decodeErrorShown) {
483 char buffer[256]; 502 char buffer[256];
484 snprintf(buffer, 255, 503 snprintf(buffer, 255,
485 "MP3 decoding error 0x%04x (%s) at byte offset %lu", 504 "MP3 decoding error 0x%04x (%s) at byte offset %lu",
486 stream->error, mad_stream_errorstr(stream), 505 stream->error, mad_stream_errorstr(stream),