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;