comparison data/fileio/MP3FileReader.cpp @ 1527:710e6250a401 zoom

Merge from default branch
author Chris Cannam
date Mon, 17 Sep 2018 13:51:14 +0100
parents aadfb395e933
children 70e172e6cc59
comparison
equal deleted inserted replaced
1324:d4a28d1479a8 1527:710e6250a401
30 30
31 #ifdef HAVE_ID3TAG 31 #ifdef HAVE_ID3TAG
32 #include <id3tag.h> 32 #include <id3tag.h>
33 #endif 33 #endif
34 34
35 #ifdef _WIN32
36 #include <io.h>
37 #include <fcntl.h>
38 #else
39 #include <fcntl.h>
40 #include <unistd.h>
41 #endif
42
35 #include <QFileInfo> 43 #include <QFileInfo>
36 44
37 #ifdef _MSC_VER 45 #include <QTextCodec>
38 #include <io.h>
39 #define open _open
40 #endif
41 46
42 using std::string; 47 using std::string;
43 48
44 static sv_frame_t DEFAULT_DECODER_DELAY = 529; 49 static sv_frame_t DEFAULT_DECODER_DELAY = 529;
45 50
73 78
74 if (m_gaplessMode == GaplessMode::Gapless) { 79 if (m_gaplessMode == GaplessMode::Gapless) {
75 CodedAudioFileReader::setFramesToTrim(DEFAULT_DECODER_DELAY, 0); 80 CodedAudioFileReader::setFramesToTrim(DEFAULT_DECODER_DELAY, 0);
76 } 81 }
77 82
78 struct stat stat; 83 m_fileSize = 0;
79 if (::stat(m_path.toLocal8Bit().data(), &stat) == -1 || stat.st_size == 0) {
80 m_error = QString("File %1 does not exist.").arg(m_path);
81 return;
82 }
83
84 m_fileSize = stat.st_size;
85 84
86 m_fileBuffer = 0; 85 m_fileBuffer = 0;
87 m_fileBufferSize = 0; 86 m_fileBufferSize = 0;
88 87
89 m_sampleBuffer = 0; 88 m_sampleBuffer = 0;
90 m_sampleBufferSize = 0; 89 m_sampleBufferSize = 0;
91 90
92 int fd = -1; 91 QFile qfile(m_path);
93 if ((fd = ::open(m_path.toLocal8Bit().data(), O_RDONLY 92 if (!qfile.open(QIODevice::ReadOnly)) {
94 #ifdef _WIN32 93 m_error = QString("Failed to open file %1 for reading.").arg(m_path);
95 | O_BINARY 94 SVDEBUG << "MP3FileReader: " << m_error << endl;
96 #endif 95 return;
97 , 0)) < 0) { 96 }
98 m_error = QString("Failed to open file %1 for reading.").arg(m_path); 97
99 return; 98 m_fileSize = qfile.size();
100 } 99
101
102 try { 100 try {
103 // We need a mysterious MAD_BUFFER_GUARD (== 8) zero bytes at 101 // We need a mysterious MAD_BUFFER_GUARD (== 8) zero bytes at
104 // end of input, to ensure libmad decodes the last frame 102 // end of input, to ensure libmad decodes the last frame
105 // correctly. Otherwise the decoded audio is truncated. 103 // correctly. Otherwise the decoded audio is truncated.
104 SVDEBUG << "file size = " << m_fileSize << ", buffer guard = " << MAD_BUFFER_GUARD << endl;
106 m_fileBufferSize = m_fileSize + MAD_BUFFER_GUARD; 105 m_fileBufferSize = m_fileSize + MAD_BUFFER_GUARD;
107 m_fileBuffer = new unsigned char[m_fileBufferSize]; 106 m_fileBuffer = new unsigned char[m_fileBufferSize];
108 memset(m_fileBuffer + m_fileSize, 0, MAD_BUFFER_GUARD); 107 memset(m_fileBuffer + m_fileSize, 0, MAD_BUFFER_GUARD);
109 } catch (...) { 108 } catch (...) {
110 m_error = QString("Out of memory"); 109 m_error = QString("Out of memory");
111 ::close(fd); 110 SVDEBUG << "MP3FileReader: " << m_error << endl;
112 return; 111 return;
113 } 112 }
114 113
115 ssize_t sz = 0; 114 auto amountRead = qfile.read(reinterpret_cast<char *>(m_fileBuffer),
116 ssize_t offset = 0; 115 m_fileSize);
117 while (offset < m_fileSize) { 116
118 sz = ::read(fd, m_fileBuffer + offset, m_fileSize - offset); 117 if (amountRead < m_fileSize) {
119 if (sz < 0) { 118 SVCERR << QString("MP3FileReader::MP3FileReader: Warning: reached EOF after only %1 of %2 bytes")
120 m_error = QString("Read error for file %1 (after %2 bytes)") 119 .arg(amountRead).arg(m_fileSize) << endl;
121 .arg(m_path).arg(offset); 120 memset(m_fileBuffer + amountRead, 0, m_fileSize - amountRead);
122 delete[] m_fileBuffer; 121 m_fileSize = amountRead;
123 ::close(fd); 122 }
124 return; 123
125 } else if (sz == 0) { 124 loadTags(qfile.handle());
126 SVCERR << QString("MP3FileReader::MP3FileReader: Warning: reached EOF after only %1 of %2 bytes") 125
127 .arg(offset).arg(m_fileSize) << endl; 126 qfile.close();
128 m_fileSize = offset;
129 m_fileBufferSize = m_fileSize + MAD_BUFFER_GUARD;
130 memset(m_fileBuffer + m_fileSize, 0, MAD_BUFFER_GUARD);
131 break;
132 }
133 offset += sz;
134 }
135
136 ::close(fd);
137
138 loadTags();
139 127
140 if (decodeMode == DecodeAtOnce) { 128 if (decodeMode == DecodeAtOnce) {
141 129
142 if (m_reporter) { 130 if (m_reporter) {
143 connect(m_reporter, SIGNAL(cancelled()), this, SLOT(cancelled())); 131 connect(m_reporter, SIGNAL(cancelled()), this, SLOT(cancelled()));
146 } 134 }
147 135
148 if (!decode(m_fileBuffer, m_fileBufferSize)) { 136 if (!decode(m_fileBuffer, m_fileBufferSize)) {
149 m_error = QString("Failed to decode file %1.").arg(m_path); 137 m_error = QString("Failed to decode file %1.").arg(m_path);
150 } 138 }
139
140 if (m_sampleBuffer) {
141 for (int c = 0; c < m_channelCount; ++c) {
142 delete[] m_sampleBuffer[c];
143 }
144 delete[] m_sampleBuffer;
145 m_sampleBuffer = 0;
146 }
151 147
152 delete[] m_fileBuffer; 148 delete[] m_fileBuffer;
153 m_fileBuffer = 0; 149 m_fileBuffer = 0;
154 150
155 if (isDecodeCacheInitialised()) finishDecodeCache(); 151 if (isDecodeCacheInitialised()) finishDecodeCache();
189 { 185 {
190 m_cancelled = true; 186 m_cancelled = true;
191 } 187 }
192 188
193 void 189 void
194 MP3FileReader::loadTags() 190 MP3FileReader::loadTags(int fd)
195 { 191 {
196 m_title = ""; 192 m_title = "";
197 193
198 #ifdef HAVE_ID3TAG 194 #ifdef HAVE_ID3TAG
199 195
200 id3_file *file = id3_file_open(m_path.toLocal8Bit().data(), 196 #ifdef _WIN32
201 ID3_FILE_MODE_READONLY); 197 int id3fd = _dup(fd);
198 #else
199 int id3fd = dup(fd);
200 #endif
201
202 id3_file *file = id3_file_fdopen(id3fd, ID3_FILE_MODE_READONLY);
202 if (!file) return; 203 if (!file) return;
203 204
204 // We can do this a lot more elegantly, but we'll leave that for 205 // We can do this a lot more elegantly, but we'll leave that for
205 // when we implement support for more than just the one tag! 206 // when we implement support for more than just the one tag!
206 207
207 id3_tag *tag = id3_file_tag(file); 208 id3_tag *tag = id3_file_tag(file);
208 if (!tag) { 209 if (!tag) {
209 SVDEBUG << "MP3FileReader::loadTags: No ID3 tag found" << endl; 210 SVDEBUG << "MP3FileReader::loadTags: No ID3 tag found" << endl;
210 id3_file_close(file); 211 id3_file_close(file); // also closes our dup'd fd
211 return; 212 return;
212 } 213 }
213 214
214 m_title = loadTag(tag, "TIT2"); // work title 215 m_title = loadTag(tag, "TIT2"); // work title
215 if (m_title == "") m_title = loadTag(tag, "TIT1"); 216 if (m_title == "") m_title = loadTag(tag, "TIT1");
226 m_tags[tag->frames[i]->id] = value; 227 m_tags[tag->frames[i]->id] = value;
227 } 228 }
228 } 229 }
229 } 230 }
230 231
231 id3_file_close(file); 232 id3_file_close(file); // also closes our dup'd fd
232 233
233 #else 234 #else
234 SVDEBUG << "MP3FileReader::loadTags: ID3 tag support not compiled in" << endl; 235 SVDEBUG << "MP3FileReader::loadTags: ID3 tag support not compiled in" << endl;
235 #endif 236 #endif
236 } 237 }
477 return data->reader->accept(header, pcm); 478 return data->reader->accept(header, pcm);
478 } 479 }
479 480
480 enum mad_flow 481 enum mad_flow
481 MP3FileReader::accept(struct mad_header const *header, 482 MP3FileReader::accept(struct mad_header const *header,
482 struct mad_pcm *pcm) 483 struct mad_pcm *pcm)
483 { 484 {
484 int channels = pcm->channels; 485 int channels = pcm->channels;
485 int frames = pcm->length; 486 int frames = pcm->length;
486 487
487 if (header) { 488 if (header) {
493 494
494 if (m_channelCount == 0) { 495 if (m_channelCount == 0) {
495 496
496 m_fileRate = pcm->samplerate; 497 m_fileRate = pcm->samplerate;
497 m_channelCount = channels; 498 m_channelCount = channels;
499
500 SVDEBUG << "MP3FileReader::accept: file rate = " << pcm->samplerate
501 << ", channel count = " << channels << ", about to init "
502 << "decode cache" << endl;
498 503
499 initialiseDecodeCache(); 504 initialiseDecodeCache();
500 505
501 if (m_cacheMode == CacheInTemporaryFile) { 506 if (m_cacheMode == CacheInTemporaryFile) {
502 // SVDEBUG << "MP3FileReader::accept: channel count " << m_channelCount << ", file rate " << m_fileRate << ", about to start serialised section" << endl; 507 // SVDEBUG << "MP3FileReader::accept: channel count " << m_channelCount << ", file rate " << m_fileRate << ", about to start serialised section" << endl;
523 SVDEBUG << "MP3FileReader: Decoding cancelled" << endl; 528 SVDEBUG << "MP3FileReader: Decoding cancelled" << endl;
524 return MAD_FLOW_STOP; 529 return MAD_FLOW_STOP;
525 } 530 }
526 531
527 if (!isDecodeCacheInitialised()) { 532 if (!isDecodeCacheInitialised()) {
533 SVDEBUG << "MP3FileReader::accept: fallback case: file rate = " << pcm->samplerate
534 << ", channel count = " << channels << ", about to init "
535 << "decode cache" << endl;
528 initialiseDecodeCache(); 536 initialiseDecodeCache();
529 } 537 }
530 538
531 if (m_sampleBufferSize < size_t(frames)) { 539 if (m_sampleBufferSize < size_t(frames)) {
532 if (!m_sampleBuffer) { 540 if (!m_sampleBuffer) {
546 554
547 for (int ch = 0; ch < channels; ++ch) { 555 for (int ch = 0; ch < channels; ++ch) {
548 556
549 for (int i = 0; i < frames; ++i) { 557 for (int i = 0; i < frames; ++i) {
550 558
551 mad_fixed_t sample = 0; 559 mad_fixed_t sample = 0;
552 if (ch < activeChannels) { 560 if (ch < activeChannels) {
553 sample = pcm->samples[ch][i]; 561 sample = pcm->samples[ch][i];
554 } 562 }
555 float fsample = float(sample) / float(MAD_F_ONE); 563 float fsample = float(sample) / float(MAD_F_ONE);
556 564
557 m_sampleBuffer[ch][i] = fsample; 565 m_sampleBuffer[ch][i] = fsample;
558 } 566 }
559 } 567 }
560 568
561 addSamplesToDecodeCache(m_sampleBuffer, frames); 569 addSamplesToDecodeCache(m_sampleBuffer, frames);
562 570
563 ++m_mp3FrameCount; 571 ++m_mp3FrameCount;
582 } 590 }
583 591
584 if (!data->reader->m_decodeErrorShown) { 592 if (!data->reader->m_decodeErrorShown) {
585 char buffer[256]; 593 char buffer[256];
586 snprintf(buffer, 255, 594 snprintf(buffer, 255,
587 "MP3 decoding error 0x%04x (%s) at byte offset %lu", 595 "MP3 decoding error 0x%04x (%s) at byte offset %lld",
588 stream->error, mad_stream_errorstr(stream), ix); 596 stream->error, mad_stream_errorstr(stream), (long long int)ix);
589 SVCERR << "Warning: in file \"" << data->reader->m_path << "\": " 597 SVCERR << "Warning: in file \"" << data->reader->m_path << "\": "
590 << buffer << " (continuing; will not report any further decode errors for this file)" << endl; 598 << buffer << " (continuing; will not report any further decode errors for this file)" << endl;
591 data->reader->m_decodeErrorShown = true; 599 data->reader->m_decodeErrorShown = true;
592 } 600 }
593 601