Mercurial > hg > svcore
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 } |