Mercurial > hg > svcore
comparison data/fileio/MP3FileReader.cpp @ 263:71dfc6ab3b54
* Threaded mp3/ogg file reading. Not activated yet, as it doesn't work
in context (SV needs to know the duration of its main model at the outset)
author | Chris Cannam |
---|---|
date | Thu, 24 May 2007 16:20:22 +0000 |
parents | 0031495aba07 |
children | 260032c26c4f |
comparison
equal
deleted
inserted
replaced
262:524bcd89743b | 263:71dfc6ab3b54 |
---|---|
27 | 27 |
28 #include <QApplication> | 28 #include <QApplication> |
29 #include <QFileInfo> | 29 #include <QFileInfo> |
30 #include <QProgressDialog> | 30 #include <QProgressDialog> |
31 | 31 |
32 MP3FileReader::MP3FileReader(QString path, bool showProgress, CacheMode mode) : | 32 MP3FileReader::MP3FileReader(QString path, DecodeMode decodeMode, CacheMode mode) : |
33 CodedAudioFileReader(mode), | 33 CodedAudioFileReader(mode), |
34 m_path(path) | 34 m_path(path) |
35 { | 35 { |
36 m_frameCount = 0; | 36 m_frameCount = 0; |
37 m_channelCount = 0; | 37 m_channelCount = 0; |
39 m_fileSize = 0; | 39 m_fileSize = 0; |
40 m_bitrateNum = 0; | 40 m_bitrateNum = 0; |
41 m_bitrateDenom = 0; | 41 m_bitrateDenom = 0; |
42 m_frameCount = 0; | 42 m_frameCount = 0; |
43 m_cancelled = false; | 43 m_cancelled = false; |
44 m_done = false; | |
45 m_progress = 0; | |
44 | 46 |
45 struct stat stat; | 47 struct stat stat; |
46 if (::stat(path.toLocal8Bit().data(), &stat) == -1 || stat.st_size == 0) { | 48 if (::stat(path.toLocal8Bit().data(), &stat) == -1 || stat.st_size == 0) { |
47 m_error = QString("File %1 does not exist.").arg(path); | 49 m_error = QString("File %1 does not exist.").arg(path); |
48 return; | 50 return; |
58 , 0)) < 0) { | 60 , 0)) < 0) { |
59 m_error = QString("Failed to open file %1 for reading.").arg(path); | 61 m_error = QString("Failed to open file %1 for reading.").arg(path); |
60 return; | 62 return; |
61 } | 63 } |
62 | 64 |
63 unsigned char *filebuffer = 0; | 65 m_filebuffer = 0; |
64 | 66 |
65 try { | 67 try { |
66 filebuffer = new unsigned char[m_fileSize]; | 68 m_filebuffer = new unsigned char[m_fileSize]; |
67 } catch (...) { | 69 } catch (...) { |
68 m_error = QString("Out of memory"); | 70 m_error = QString("Out of memory"); |
69 ::close(fd); | 71 ::close(fd); |
70 return; | 72 return; |
71 } | 73 } |
72 | 74 |
73 ssize_t sz = 0; | 75 ssize_t sz = 0; |
74 size_t offset = 0; | 76 size_t offset = 0; |
75 while (offset < m_fileSize) { | 77 while (offset < m_fileSize) { |
76 sz = ::read(fd, filebuffer + offset, m_fileSize - offset); | 78 sz = ::read(fd, m_filebuffer + offset, m_fileSize - offset); |
77 if (sz < 0) { | 79 if (sz < 0) { |
78 m_error = QString("Read error for file %1 (after %2 bytes)") | 80 m_error = QString("Read error for file %1 (after %2 bytes)") |
79 .arg(path).arg(offset); | 81 .arg(path).arg(offset); |
80 delete[] filebuffer; | 82 delete[] m_filebuffer; |
81 ::close(fd); | 83 ::close(fd); |
82 return; | 84 return; |
83 } else if (sz == 0) { | 85 } else if (sz == 0) { |
84 std::cerr << QString("MP3FileReader::MP3FileReader: Warning: reached EOF after only %1 of %2 bytes") | 86 std::cerr << QString("MP3FileReader::MP3FileReader: Warning: reached EOF after only %1 of %2 bytes") |
85 .arg(offset).arg(m_fileSize).toStdString() << std::endl; | 87 .arg(offset).arg(m_fileSize).toStdString() << std::endl; |
89 offset += sz; | 91 offset += sz; |
90 } | 92 } |
91 | 93 |
92 ::close(fd); | 94 ::close(fd); |
93 | 95 |
94 if (showProgress) { | 96 if (decodeMode == DecodeAtOnce) { |
97 | |
95 m_progress = new QProgressDialog | 98 m_progress = new QProgressDialog |
96 (QObject::tr("Decoding %1...").arg(QFileInfo(path).fileName()), | 99 (QObject::tr("Decoding %1...").arg(QFileInfo(path).fileName()), |
97 QObject::tr("Stop"), 0, 100); | 100 QObject::tr("Stop"), 0, 100); |
98 m_progress->hide(); | 101 m_progress->hide(); |
99 } | 102 |
100 | 103 if (!decode(m_filebuffer, m_fileSize)) { |
101 if (!decode(filebuffer, m_fileSize)) { | 104 m_error = QString("Failed to decode file %1.").arg(path); |
102 m_error = QString("Failed to decode file %1.").arg(path); | 105 } |
103 delete[] filebuffer; | 106 |
104 return; | 107 delete[] m_filebuffer; |
105 } | 108 m_filebuffer = 0; |
106 | 109 |
107 if (isDecodeCacheInitialised()) finishDecodeCache(); | 110 if (isDecodeCacheInitialised()) finishDecodeCache(); |
108 | 111 |
109 if (showProgress) { | |
110 delete m_progress; | 112 delete m_progress; |
111 m_progress = 0; | 113 m_progress = 0; |
112 } | 114 |
113 | 115 } else { |
114 delete[] filebuffer; | 116 |
117 m_decodeThread = new DecodeThread(this); | |
118 m_decodeThread->start(); | |
119 | |
120 while (m_channelCount == 0 && !m_done) { | |
121 usleep(10); | |
122 } | |
123 } | |
115 } | 124 } |
116 | 125 |
117 MP3FileReader::~MP3FileReader() | 126 MP3FileReader::~MP3FileReader() |
118 { | 127 { |
119 } | 128 if (m_decodeThread) { |
129 m_decodeThread->wait(); | |
130 delete m_decodeThread; | |
131 } | |
132 } | |
133 | |
134 void | |
135 MP3FileReader::DecodeThread::run() | |
136 { | |
137 if (!m_reader->decode(m_reader->m_filebuffer, m_reader->m_fileSize)) { | |
138 m_reader->m_error = QString("Failed to decode file %1.").arg(m_reader->m_path); | |
139 } | |
140 | |
141 delete[] m_reader->m_filebuffer; | |
142 m_reader->m_filebuffer = 0; | |
143 | |
144 if (m_reader->isDecodeCacheInitialised()) m_reader->finishDecodeCache(); | |
145 | |
146 m_reader->m_done = true; | |
147 } | |
120 | 148 |
121 bool | 149 bool |
122 MP3FileReader::decode(void *mm, size_t sz) | 150 MP3FileReader::decode(void *mm, size_t sz) |
123 { | 151 { |
124 DecoderData data; | 152 DecoderData data; |
130 | 158 |
131 mad_decoder_init(&decoder, &data, input, 0, 0, output, error, 0); | 159 mad_decoder_init(&decoder, &data, input, 0, 0, output, error, 0); |
132 mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC); | 160 mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC); |
133 mad_decoder_finish(&decoder); | 161 mad_decoder_finish(&decoder); |
134 | 162 |
163 m_done = true; | |
135 return true; | 164 return true; |
136 } | 165 } |
137 | 166 |
138 enum mad_flow | 167 enum mad_flow |
139 MP3FileReader::input(void *dp, struct mad_stream *stream) | 168 MP3FileReader::input(void *dp, struct mad_stream *stream) |
178 if (m_bitrateDenom > 0) { | 207 if (m_bitrateDenom > 0) { |
179 double bitrate = m_bitrateNum / m_bitrateDenom; | 208 double bitrate = m_bitrateNum / m_bitrateDenom; |
180 double duration = double(m_fileSize * 8) / bitrate; | 209 double duration = double(m_fileSize * 8) / bitrate; |
181 double elapsed = double(m_frameCount) / m_sampleRate; | 210 double elapsed = double(m_frameCount) / m_sampleRate; |
182 double percent = ((elapsed * 100.0) / duration); | 211 double percent = ((elapsed * 100.0) / duration); |
183 int progress = int(percent); | 212 if (m_progress) { |
184 if (progress < 1) progress = 1; | 213 int progress = int(percent); |
185 if (progress > 99) progress = 99; | 214 if (progress < 1) progress = 1; |
186 if (progress > m_progress->value()) { | 215 if (progress > 99) progress = 99; |
187 m_progress->setValue(progress); | 216 if (progress > m_progress->value()) { |
188 m_progress->show(); | 217 m_progress->setValue(progress); |
189 m_progress->raise(); | 218 m_progress->show(); |
190 qApp->processEvents(); | 219 m_progress->raise(); |
191 if (m_progress->wasCanceled()) { | 220 qApp->processEvents(); |
192 m_cancelled = true; | 221 if (m_progress->wasCanceled()) { |
222 m_cancelled = true; | |
223 } | |
193 } | 224 } |
194 } | 225 } |
195 } | 226 } |
196 | 227 |
197 if (m_cancelled) return MAD_FLOW_STOP; | 228 if (m_cancelled) return MAD_FLOW_STOP; |