comparison data/fileio/MP3FileReader.cpp @ 1348:b3cb0edc25cd 3.0-integration

Update WAV/MP3/BZipFileDevice code to avoid using local 8-bit encoding
author Chris Cannam
date Fri, 06 Jan 2017 16:40:11 +0000
parents 75ad55315db4
children 330bcc92507d
comparison
equal deleted inserted replaced
1347:281a8c9d4886 1348:b3cb0edc25cd
75 75
76 if (m_gaplessMode == GaplessMode::Gapless) { 76 if (m_gaplessMode == GaplessMode::Gapless) {
77 CodedAudioFileReader::setFramesToTrim(DEFAULT_DECODER_DELAY, 0); 77 CodedAudioFileReader::setFramesToTrim(DEFAULT_DECODER_DELAY, 0);
78 } 78 }
79 79
80 SVDEBUG << "Codec for locale is " << (const char *)(QTextCodec::codecForLocale()->name().data()) << endl; 80 m_fileSize = 0;
81
82 struct stat stat;
83 if (::stat(m_path.toLocal8Bit().data(), &stat) == -1 || stat.st_size == 0) {
84 m_error = QString("File %1 does not exist.").arg(m_path);
85 SVDEBUG << "MP3FileReader: " << m_error << endl;
86 return;
87 }
88
89 m_fileSize = stat.st_size;
90 81
91 m_fileBuffer = 0; 82 m_fileBuffer = 0;
92 m_fileBufferSize = 0; 83 m_fileBufferSize = 0;
93 84
94 m_sampleBuffer = 0; 85 m_sampleBuffer = 0;
95 m_sampleBufferSize = 0; 86 m_sampleBufferSize = 0;
96 87
97 int fd = -1; 88 QFile qfile(m_path);
98 if ((fd = ::open(m_path.toLocal8Bit().data(), O_RDONLY 89 if (!qfile.open(QIODevice::ReadOnly)) {
99 #ifdef _WIN32
100 | O_BINARY
101 #endif
102 , 0)) < 0) {
103 m_error = QString("Failed to open file %1 for reading.").arg(m_path); 90 m_error = QString("Failed to open file %1 for reading.").arg(m_path);
104 SVDEBUG << "MP3FileReader: " << m_error << endl; 91 SVDEBUG << "MP3FileReader: " << m_error << endl;
105 return; 92 return;
106 } 93 }
107 94
95 m_fileSize = qfile.size();
96
108 try { 97 try {
109 // We need a mysterious MAD_BUFFER_GUARD (== 8) zero bytes at 98 // We need a mysterious MAD_BUFFER_GUARD (== 8) zero bytes at
110 // end of input, to ensure libmad decodes the last frame 99 // end of input, to ensure libmad decodes the last frame
111 // correctly. Otherwise the decoded audio is truncated. 100 // correctly. Otherwise the decoded audio is truncated.
112 m_fileBufferSize = m_fileSize + MAD_BUFFER_GUARD; 101 m_fileBufferSize = m_fileSize + MAD_BUFFER_GUARD;
113 m_fileBuffer = new unsigned char[m_fileBufferSize]; 102 m_fileBuffer = new unsigned char[m_fileBufferSize];
114 memset(m_fileBuffer + m_fileSize, 0, MAD_BUFFER_GUARD); 103 memset(m_fileBuffer + m_fileSize, 0, MAD_BUFFER_GUARD);
115 } catch (...) { 104 } catch (...) {
116 m_error = QString("Out of memory"); 105 m_error = QString("Out of memory");
117 SVDEBUG << "MP3FileReader: " << m_error << endl; 106 SVDEBUG << "MP3FileReader: " << m_error << endl;
118 ::close(fd);
119 return; 107 return;
120 } 108 }
121 109
122 ssize_t sz = 0; 110 auto amountRead = qfile.read(reinterpret_cast<char *>(m_fileBuffer),
123 ssize_t offset = 0; 111 m_fileSize);
124 while (offset < m_fileSize) { 112
125 sz = ::read(fd, m_fileBuffer + offset, m_fileSize - offset); 113 if (amountRead < m_fileSize) {
126 if (sz < 0) { 114 SVCERR << QString("MP3FileReader::MP3FileReader: Warning: reached EOF after only %1 of %2 bytes")
127 m_error = QString("Read error for file %1 (after %2 bytes)") 115 .arg(amountRead).arg(m_fileSize) << endl;
128 .arg(m_path).arg(offset); 116 memset(m_fileBuffer + amountRead, 0, m_fileSize - amountRead);
129 delete[] m_fileBuffer; 117 m_fileSize = amountRead;
130 ::close(fd); 118 }
131 SVDEBUG << "MP3FileReader: " << m_error << endl; 119
132 return; 120 loadTags(qfile.handle());
133 } else if (sz == 0) { 121
134 SVCERR << QString("MP3FileReader::MP3FileReader: Warning: reached EOF after only %1 of %2 bytes") 122 qfile.close();
135 .arg(offset).arg(m_fileSize) << endl;
136 m_fileSize = offset;
137 m_fileBufferSize = m_fileSize + MAD_BUFFER_GUARD;
138 memset(m_fileBuffer + m_fileSize, 0, MAD_BUFFER_GUARD);
139 break;
140 }
141 offset += sz;
142 }
143
144 ::close(fd);
145
146 loadTags();
147 123
148 if (decodeMode == DecodeAtOnce) { 124 if (decodeMode == DecodeAtOnce) {
149 125
150 if (m_reporter) { 126 if (m_reporter) {
151 connect(m_reporter, SIGNAL(cancelled()), this, SLOT(cancelled())); 127 connect(m_reporter, SIGNAL(cancelled()), this, SLOT(cancelled()));
197 { 173 {
198 m_cancelled = true; 174 m_cancelled = true;
199 } 175 }
200 176
201 void 177 void
202 MP3FileReader::loadTags() 178 MP3FileReader::loadTags(int fd)
203 { 179 {
204 m_title = ""; 180 m_title = "";
205 181
206 #ifdef HAVE_ID3TAG 182 #ifdef HAVE_ID3TAG
207 183
208 id3_file *file = id3_file_open(m_path.toLocal8Bit().data(), 184 id3_file *file = id3_file_fdopen(fd, ID3_FILE_MODE_READONLY);
209 ID3_FILE_MODE_READONLY);
210 if (!file) return; 185 if (!file) return;
211 186
212 // We can do this a lot more elegantly, but we'll leave that for 187 // We can do this a lot more elegantly, but we'll leave that for
213 // when we implement support for more than just the one tag! 188 // when we implement support for more than just the one tag!
214 189
234 m_tags[tag->frames[i]->id] = value; 209 m_tags[tag->frames[i]->id] = value;
235 } 210 }
236 } 211 }
237 } 212 }
238 213
239 id3_file_close(file); 214 // We don't id3_file_close(file) because that closes the fd, which
215 // was only lent to us
240 216
241 #else 217 #else
242 SVDEBUG << "MP3FileReader::loadTags: ID3 tag support not compiled in" << endl; 218 SVDEBUG << "MP3FileReader::loadTags: ID3 tag support not compiled in" << endl;
243 #endif 219 #endif
244 } 220 }