annotate data/fileio/MP3FileReader.cpp @ 1310:aa1b1fc2d018 mp3-gapless

Stop reporting sync errors only when we really are at eof, i.e. after the input callback has been called again (previously we just tested whether we'd buffered up all the input, which of course we do in one go at the start)
author Chris Cannam
date Tue, 29 Nov 2016 16:45:29 +0000
parents c84629395040
children 079e553dc16e
rev   line source
Chris@148 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@148 2
Chris@148 3 /*
Chris@148 4 Sonic Visualiser
Chris@148 5 An audio file viewer and annotation editor.
Chris@148 6 Centre for Digital Music, Queen Mary, University of London.
Chris@148 7 This file copyright 2006 Chris Cannam.
Chris@148 8
Chris@148 9 This program is free software; you can redistribute it and/or
Chris@148 10 modify it under the terms of the GNU General Public License as
Chris@148 11 published by the Free Software Foundation; either version 2 of the
Chris@148 12 License, or (at your option) any later version. See the file
Chris@148 13 COPYING included with this distribution for more information.
Chris@148 14 */
Chris@148 15
Chris@148 16 #ifdef HAVE_MAD
Chris@148 17
Chris@148 18 #include "MP3FileReader.h"
Chris@392 19 #include "base/ProgressReporter.h"
Chris@357 20
Chris@150 21 #include "system/System.h"
Chris@148 22
Chris@148 23 #include <sys/types.h>
Chris@148 24 #include <sys/stat.h>
Chris@148 25 #include <fcntl.h>
Chris@148 26
Chris@148 27 #include <iostream>
Chris@148 28
Chris@405 29 #include <cstdlib>
Chris@405 30
Chris@271 31 #ifdef HAVE_ID3TAG
Chris@271 32 #include <id3tag.h>
Chris@271 33 #endif
Chris@1168 34
Chris@186 35 #include <QFileInfo>
Chris@148 36
Chris@1218 37 #ifdef _MSC_VER
Chris@1218 38 #include <io.h>
Chris@1218 39 #define open _open
Chris@1218 40 #endif
Chris@1218 41
Chris@1305 42 using std::string;
Chris@1305 43
Chris@1305 44 static sv_frame_t DEFAULT_DECODER_DELAY = 529;
Chris@1305 45
Chris@317 46 MP3FileReader::MP3FileReader(FileSource source, DecodeMode decodeMode,
Chris@1305 47 CacheMode mode, GaplessMode gaplessMode,
Chris@1305 48 sv_samplerate_t targetRate,
Chris@920 49 bool normalised,
Chris@392 50 ProgressReporter *reporter) :
Chris@920 51 CodedAudioFileReader(mode, targetRate, normalised),
Chris@316 52 m_source(source),
Chris@316 53 m_path(source.getLocalFilename()),
Chris@1305 54 m_gaplessMode(gaplessMode),
Chris@1284 55 m_decodeErrorShown(false),
Chris@264 56 m_decodeThread(0)
Chris@148 57 {
Chris@1279 58 SVDEBUG << "MP3FileReader: local path: \"" << m_path
Chris@1279 59 << "\", decode mode: " << decodeMode << " ("
Chris@1279 60 << (decodeMode == DecodeAtOnce ? "DecodeAtOnce" : "DecodeThreaded")
Chris@1279 61 << ")" << endl;
Chris@1279 62
Chris@148 63 m_channelCount = 0;
Chris@297 64 m_fileRate = 0;
Chris@148 65 m_fileSize = 0;
Chris@148 66 m_bitrateNum = 0;
Chris@148 67 m_bitrateDenom = 0;
Chris@148 68 m_cancelled = false;
Chris@1288 69 m_mp3FrameCount = 0;
Chris@265 70 m_completion = 0;
Chris@263 71 m_done = false;
Chris@392 72 m_reporter = reporter;
Chris@148 73
Chris@1305 74 if (m_gaplessMode == Gapless) {
Chris@1307 75 CodedAudioFileReader::setFramesToTrim(DEFAULT_DECODER_DELAY, 0);
Chris@1305 76 }
Chris@1305 77
Chris@148 78 struct stat stat;
Chris@316 79 if (::stat(m_path.toLocal8Bit().data(), &stat) == -1 || stat.st_size == 0) {
Chris@316 80 m_error = QString("File %1 does not exist.").arg(m_path);
Chris@148 81 return;
Chris@148 82 }
Chris@148 83
Chris@148 84 m_fileSize = stat.st_size;
Chris@148 85
Chris@1290 86 m_fileBuffer = 0;
Chris@1290 87 m_fileBufferSize = 0;
Chris@1290 88
Chris@1290 89 m_sampleBuffer = 0;
Chris@1290 90 m_sampleBufferSize = 0;
Chris@977 91
Chris@229 92 int fd = -1;
Chris@316 93 if ((fd = ::open(m_path.toLocal8Bit().data(), O_RDONLY
Chris@231 94 #ifdef _WIN32
Chris@231 95 | O_BINARY
Chris@231 96 #endif
Chris@231 97 , 0)) < 0) {
Chris@316 98 m_error = QString("Failed to open file %1 for reading.").arg(m_path);
Chris@148 99 return;
Chris@148 100 }
Chris@148 101
Chris@148 102 try {
Chris@1290 103 // We need a mysterious MAD_BUFFER_GUARD (== 8) zero bytes at
Chris@1290 104 // end of input, to ensure libmad decodes the last frame
Chris@1290 105 // correctly. Otherwise the decoded audio is truncated.
Chris@1290 106 m_fileBufferSize = m_fileSize + MAD_BUFFER_GUARD;
Chris@1290 107 m_fileBuffer = new unsigned char[m_fileBufferSize];
Chris@1290 108 memset(m_fileBuffer + m_fileSize, 0, MAD_BUFFER_GUARD);
Chris@148 109 } catch (...) {
Chris@290 110 m_error = QString("Out of memory");
Chris@148 111 ::close(fd);
Chris@148 112 return;
Chris@148 113 }
Chris@148 114
Chris@229 115 ssize_t sz = 0;
Chris@1038 116 ssize_t offset = 0;
Chris@229 117 while (offset < m_fileSize) {
Chris@1290 118 sz = ::read(fd, m_fileBuffer + offset, m_fileSize - offset);
Chris@229 119 if (sz < 0) {
Chris@290 120 m_error = QString("Read error for file %1 (after %2 bytes)")
Chris@316 121 .arg(m_path).arg(offset);
Chris@1290 122 delete[] m_fileBuffer;
Chris@229 123 ::close(fd);
Chris@229 124 return;
Chris@230 125 } else if (sz == 0) {
Chris@1290 126 SVCERR << QString("MP3FileReader::MP3FileReader: Warning: reached EOF after only %1 of %2 bytes")
Chris@843 127 .arg(offset).arg(m_fileSize) << endl;
Chris@231 128 m_fileSize = offset;
Chris@1290 129 m_fileBufferSize = m_fileSize + MAD_BUFFER_GUARD;
Chris@1290 130 memset(m_fileBuffer + m_fileSize, 0, MAD_BUFFER_GUARD);
Chris@230 131 break;
Chris@229 132 }
Chris@229 133 offset += sz;
Chris@148 134 }
Chris@148 135
Chris@148 136 ::close(fd);
Chris@148 137
Chris@271 138 loadTags();
Chris@271 139
Chris@263 140 if (decodeMode == DecodeAtOnce) {
Chris@263 141
Chris@392 142 if (m_reporter) {
Chris@392 143 connect(m_reporter, SIGNAL(cancelled()), this, SLOT(cancelled()));
Chris@392 144 m_reporter->setMessage
Chris@392 145 (tr("Decoding %1...").arg(QFileInfo(m_path).fileName()));
Chris@327 146 }
Chris@148 147
Chris@1290 148 if (!decode(m_fileBuffer, m_fileBufferSize)) {
Chris@316 149 m_error = QString("Failed to decode file %1.").arg(m_path);
Chris@263 150 }
Chris@263 151
Chris@1290 152 delete[] m_fileBuffer;
Chris@1290 153 m_fileBuffer = 0;
Chris@148 154
Chris@263 155 if (isDecodeCacheInitialised()) finishDecodeCache();
Chris@398 156 endSerialised();
Chris@263 157
Chris@392 158 } else {
Chris@263 159
Chris@392 160 if (m_reporter) m_reporter->setProgress(100);
Chris@263 161
Chris@263 162 m_decodeThread = new DecodeThread(this);
Chris@263 163 m_decodeThread->start();
Chris@263 164
Chris@386 165 while ((m_channelCount == 0 || m_fileRate == 0 || m_sampleRate == 0)
Chris@386 166 && !m_done) {
Chris@263 167 usleep(10);
Chris@263 168 }
Chris@386 169
Chris@1288 170 SVDEBUG << "MP3FileReader: decoding startup complete, file rate = " << m_fileRate << endl;
Chris@148 171 }
Chris@499 172
Chris@499 173 if (m_error != "") {
Chris@1279 174 SVDEBUG << "MP3FileReader::MP3FileReader(\"" << m_path << "\"): ERROR: " << m_error << endl;
Chris@499 175 }
Chris@148 176 }
Chris@148 177
Chris@148 178 MP3FileReader::~MP3FileReader()
Chris@148 179 {
Chris@263 180 if (m_decodeThread) {
Chris@265 181 m_cancelled = true;
Chris@263 182 m_decodeThread->wait();
Chris@263 183 delete m_decodeThread;
Chris@263 184 }
Chris@148 185 }
Chris@148 186
Chris@263 187 void
Chris@392 188 MP3FileReader::cancelled()
Chris@392 189 {
Chris@392 190 m_cancelled = true;
Chris@392 191 }
Chris@392 192
Chris@392 193 void
Chris@271 194 MP3FileReader::loadTags()
Chris@271 195 {
Chris@271 196 m_title = "";
Chris@271 197
Chris@271 198 #ifdef HAVE_ID3TAG
Chris@271 199
Chris@290 200 id3_file *file = id3_file_open(m_path.toLocal8Bit().data(),
Chris@271 201 ID3_FILE_MODE_READONLY);
Chris@271 202 if (!file) return;
Chris@271 203
Chris@273 204 // We can do this a lot more elegantly, but we'll leave that for
Chris@273 205 // when we implement support for more than just the one tag!
Chris@273 206
Chris@271 207 id3_tag *tag = id3_file_tag(file);
Chris@273 208 if (!tag) {
Chris@1279 209 SVDEBUG << "MP3FileReader::loadTags: No ID3 tag found" << endl;
Chris@273 210 id3_file_close(file);
Chris@273 211 return;
Chris@271 212 }
Chris@271 213
Chris@333 214 m_title = loadTag(tag, "TIT2"); // work title
Chris@333 215 if (m_title == "") m_title = loadTag(tag, "TIT1");
Chris@1287 216 if (m_title == "") SVDEBUG << "MP3FileReader::loadTags: No title found" << endl;
Chris@273 217
Chris@333 218 m_maker = loadTag(tag, "TPE1"); // "lead artist"
Chris@333 219 if (m_maker == "") m_maker = loadTag(tag, "TPE2");
Chris@1287 220 if (m_maker == "") SVDEBUG << "MP3FileReader::loadTags: No artist/maker found" << endl;
Chris@273 221
Chris@632 222 for (unsigned int i = 0; i < tag->nframes; ++i) {
Chris@632 223 if (tag->frames[i]) {
Chris@632 224 QString value = loadTag(tag, tag->frames[i]->id);
Chris@1287 225 if (value != "") {
Chris@1287 226 m_tags[tag->frames[i]->id] = value;
Chris@1287 227 }
Chris@632 228 }
Chris@632 229 }
Chris@632 230
Chris@271 231 id3_file_close(file);
Chris@273 232
Chris@273 233 #else
Chris@1287 234 SVDEBUG << "MP3FileReader::loadTags: ID3 tag support not compiled in" << endl;
Chris@273 235 #endif
Chris@333 236 }
Chris@273 237
Chris@333 238 QString
Chris@333 239 MP3FileReader::loadTag(void *vtag, const char *name)
Chris@333 240 {
Chris@333 241 #ifdef HAVE_ID3TAG
Chris@333 242 id3_tag *tag = (id3_tag *)vtag;
Chris@333 243
Chris@333 244 id3_frame *frame = id3_tag_findframe(tag, name, 0);
Chris@333 245 if (!frame) {
Chris@1287 246 SVDEBUG << "MP3FileReader::loadTag: No \"" << name << "\" frame found in ID3 tag" << endl;
Chris@333 247 return "";
Chris@333 248 }
Chris@333 249
Chris@333 250 if (frame->nfields < 2) {
Chris@1287 251 cerr << "MP3FileReader::loadTag: WARNING: Not enough fields (" << frame->nfields << ") for \"" << name << "\" in ID3 tag" << endl;
Chris@333 252 return "";
Chris@333 253 }
Chris@333 254
Chris@333 255 unsigned int nstrings = id3_field_getnstrings(&frame->fields[1]);
Chris@333 256 if (nstrings == 0) {
Chris@1287 257 SVDEBUG << "MP3FileReader::loadTag: No strings for \"" << name << "\" in ID3 tag" << endl;
Chris@333 258 return "";
Chris@333 259 }
Chris@333 260
Chris@333 261 id3_ucs4_t const *ustr = id3_field_getstrings(&frame->fields[1], 0);
Chris@333 262 if (!ustr) {
Chris@1287 263 SVDEBUG << "MP3FileReader::loadTag: Invalid or absent data for \"" << name << "\" in ID3 tag" << endl;
Chris@333 264 return "";
Chris@333 265 }
Chris@333 266
Chris@333 267 id3_utf8_t *u8str = id3_ucs4_utf8duplicate(ustr);
Chris@333 268 if (!u8str) {
Chris@1287 269 SVDEBUG << "MP3FileReader::loadTag: ERROR: Internal error: Failed to convert UCS4 to UTF8 in ID3 tag" << endl;
Chris@333 270 return "";
Chris@333 271 }
Chris@333 272
Chris@333 273 QString rv = QString::fromUtf8((const char *)u8str);
Chris@333 274 free(u8str);
Chris@334 275
Chris@1287 276 SVDEBUG << "MP3FileReader::loadTag: Tag \"" << name << "\" -> \""
Chris@1287 277 << rv << "\"" << endl;
Chris@334 278
Chris@333 279 return rv;
Chris@333 280
Chris@333 281 #else
Chris@333 282 return "";
Chris@333 283 #endif
Chris@271 284 }
Chris@271 285
Chris@271 286 void
Chris@263 287 MP3FileReader::DecodeThread::run()
Chris@263 288 {
Chris@1290 289 if (!m_reader->decode(m_reader->m_fileBuffer, m_reader->m_fileBufferSize)) {
Chris@290 290 m_reader->m_error = QString("Failed to decode file %1.").arg(m_reader->m_path);
Chris@263 291 }
Chris@263 292
Chris@1290 293 delete[] m_reader->m_fileBuffer;
Chris@1290 294 m_reader->m_fileBuffer = 0;
Chris@297 295
Chris@1290 296 if (m_reader->m_sampleBuffer) {
Chris@929 297 for (int c = 0; c < m_reader->m_channelCount; ++c) {
Chris@1290 298 delete[] m_reader->m_sampleBuffer[c];
Chris@297 299 }
Chris@1290 300 delete[] m_reader->m_sampleBuffer;
Chris@1290 301 m_reader->m_sampleBuffer = 0;
Chris@297 302 }
Chris@297 303
Chris@263 304 if (m_reader->isDecodeCacheInitialised()) m_reader->finishDecodeCache();
Chris@263 305
Chris@263 306 m_reader->m_done = true;
Chris@265 307 m_reader->m_completion = 100;
Chris@297 308
Chris@297 309 m_reader->endSerialised();
Chris@263 310 }
Chris@263 311
Chris@148 312 bool
Chris@1038 313 MP3FileReader::decode(void *mm, sv_frame_t sz)
Chris@148 314 {
Chris@148 315 DecoderData data;
Chris@148 316 struct mad_decoder decoder;
Chris@148 317
Chris@148 318 data.start = (unsigned char const *)mm;
Chris@1288 319 data.length = sz;
Chris@1310 320 data.finished = false;
Chris@148 321 data.reader = this;
Chris@148 322
Chris@1288 323 mad_decoder_init(&decoder, // decoder to initialise
Chris@1288 324 &data, // our own data block for callbacks
Chris@1288 325 input_callback, // provides (entire) input to mad
Chris@1288 326 0, // checks header
Chris@1288 327 filter_callback, // filters frame before decoding
Chris@1288 328 output_callback, // receives decoded output
Chris@1288 329 error_callback, // handles decode errors
Chris@1288 330 0); // "message_func"
Chris@1288 331
Chris@148 332 mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
Chris@148 333 mad_decoder_finish(&decoder);
Chris@148 334
Chris@1288 335 SVDEBUG << "MP3FileReader: Decoding complete, decoded " << m_mp3FrameCount
Chris@1288 336 << " mp3 frames" << endl;
Chris@1288 337
Chris@263 338 m_done = true;
Chris@148 339 return true;
Chris@148 340 }
Chris@148 341
Chris@148 342 enum mad_flow
Chris@1288 343 MP3FileReader::input_callback(void *dp, struct mad_stream *stream)
Chris@148 344 {
Chris@148 345 DecoderData *data = (DecoderData *)dp;
Chris@148 346
Chris@1310 347 if (!data->length) {
Chris@1310 348 data->finished = true;
Chris@1310 349 return MAD_FLOW_STOP;
Chris@1310 350 }
Chris@348 351
Chris@348 352 unsigned char const *start = data->start;
Chris@1288 353 sv_frame_t length = data->length;
Chris@348 354
Chris@348 355 #ifdef HAVE_ID3TAG
Chris@1288 356 while (length > ID3_TAG_QUERYSIZE) {
Chris@1038 357 ssize_t taglen = id3_tag_query(start, ID3_TAG_QUERYSIZE);
Chris@1288 358 if (taglen <= 0) {
Chris@1288 359 break;
Chris@348 360 }
Chris@1288 361 SVDEBUG << "MP3FileReader: ID3 tag length to skip: " << taglen << endl;
Chris@1288 362 start += taglen;
Chris@1288 363 length -= taglen;
Chris@348 364 }
Chris@348 365 #endif
Chris@348 366
Chris@348 367 mad_stream_buffer(stream, start, length);
Chris@148 368 data->length = 0;
Chris@148 369
Chris@148 370 return MAD_FLOW_CONTINUE;
Chris@148 371 }
Chris@148 372
Chris@148 373 enum mad_flow
Chris@1288 374 MP3FileReader::filter_callback(void *dp,
Chris@1288 375 struct mad_stream const *stream,
Chris@1288 376 struct mad_frame *frame)
Chris@1288 377 {
Chris@1288 378 DecoderData *data = (DecoderData *)dp;
Chris@1288 379 return data->reader->filter(stream, frame);
Chris@1288 380 }
Chris@1288 381
Chris@1307 382 static string toMagic(unsigned long fourcc)
Chris@1305 383 {
Chris@1305 384 string magic("....");
Chris@1305 385 for (int i = 0; i < 4; ++i) {
Chris@1305 386 magic[3-i] = char((fourcc >> (8*i)) & 0xff);
Chris@1305 387 }
Chris@1305 388 return magic;
Chris@1305 389 }
Chris@1305 390
Chris@1288 391 enum mad_flow
Chris@1288 392 MP3FileReader::filter(struct mad_stream const *stream,
Chris@1288 393 struct mad_frame *)
Chris@1288 394 {
Chris@1289 395 if (m_mp3FrameCount > 0) {
Chris@1305 396 // only handle info frame if it appears as first mp3 frame
Chris@1289 397 return MAD_FLOW_CONTINUE;
Chris@1305 398 }
Chris@1305 399
Chris@1305 400 if (m_gaplessMode == Gappy) {
Chris@1305 401 // Our non-gapless mode does not even filter out the Xing/LAME
Chris@1305 402 // frame. That's because the main reason non-gapless mode
Chris@1305 403 // exists is for backward compatibility with MP3FileReader
Chris@1305 404 // behaviour before the gapless support was added, so we even
Chris@1305 405 // need to keep the spurious 1152 samples resulting from
Chris@1305 406 // feeding Xing/LAME frame to the decoder as otherwise we'd
Chris@1305 407 // have different output from before.
Chris@1305 408 SVDEBUG << "MP3FileReader: Not gapless mode, not checking Xing/LAME frame"
Chris@1305 409 << endl;
Chris@1305 410 return MAD_FLOW_CONTINUE;
Chris@1305 411 }
Chris@1305 412
Chris@1305 413 struct mad_bitptr ptr = stream->anc_ptr;
Chris@1305 414 string magic = toMagic(mad_bit_read(&ptr, 32));
Chris@1305 415
Chris@1305 416 if (magic == "Xing" || magic == "Info") {
Chris@1305 417
Chris@1305 418 SVDEBUG << "MP3FileReader: Found Xing/LAME metadata frame (magic = \""
Chris@1305 419 << magic << "\")" << endl;
Chris@1305 420
Chris@1305 421 // All we want at this point is the LAME encoder delay and
Chris@1305 422 // padding values. We expect to see the Xing/Info magic (which
Chris@1305 423 // we've already read), then 116 bytes of Xing data, then LAME
Chris@1305 424 // magic, 5 byte version string, 12 bytes of LAME data that we
Chris@1305 425 // aren't currently interested in, then the delays encoded as
Chris@1305 426 // two 12-bit numbers into three bytes.
Chris@1305 427 //
Chris@1305 428 // (See gabriel.mp3-tech.org/mp3infotag.html)
Chris@1305 429
Chris@1305 430 for (int skip = 0; skip < 116; ++skip) {
Chris@1305 431 (void)mad_bit_read(&ptr, 8);
Chris@1305 432 }
Chris@1305 433
Chris@1305 434 magic = toMagic(mad_bit_read(&ptr, 32));
Chris@1305 435
Chris@1305 436 if (magic == "LAME") {
Chris@1305 437
Chris@1305 438 SVDEBUG << "MP3FileReader: Found LAME-specific metadata" << endl;
Chris@1305 439
Chris@1305 440 for (int skip = 0; skip < 5 + 12; ++skip) {
Chris@1305 441 (void)mad_bit_read(&ptr, 8);
Chris@1305 442 }
Chris@1305 443
Chris@1307 444 auto delay = mad_bit_read(&ptr, 12);
Chris@1307 445 auto padding = mad_bit_read(&ptr, 12);
Chris@1305 446
Chris@1305 447 sv_frame_t delayToDrop = DEFAULT_DECODER_DELAY + delay;
Chris@1305 448 sv_frame_t paddingToDrop = padding - DEFAULT_DECODER_DELAY;
Chris@1305 449 if (paddingToDrop < 0) paddingToDrop = 0;
Chris@1305 450
Chris@1305 451 SVDEBUG << "MP3FileReader: LAME encoder delay = " << delay
Chris@1305 452 << ", padding = " << padding << endl;
Chris@1305 453
Chris@1305 454 SVDEBUG << "MP3FileReader: Will be trimming " << delayToDrop
Chris@1306 455 << " samples from start and " << paddingToDrop
Chris@1306 456 << " from end" << endl;
Chris@1305 457
Chris@1307 458 CodedAudioFileReader::setFramesToTrim(delayToDrop, paddingToDrop);
Chris@1305 459
Chris@1305 460 } else {
Chris@1305 461 SVDEBUG << "MP3FileReader: Xing frame has no LAME metadata" << endl;
Chris@1305 462 }
Chris@1305 463
Chris@1305 464 return MAD_FLOW_IGNORE;
Chris@1305 465
Chris@1288 466 } else {
Chris@1305 467 return MAD_FLOW_CONTINUE;
Chris@1288 468 }
Chris@1288 469 }
Chris@1288 470
Chris@1288 471 enum mad_flow
Chris@1288 472 MP3FileReader::output_callback(void *dp,
Chris@1288 473 struct mad_header const *header,
Chris@1288 474 struct mad_pcm *pcm)
Chris@148 475 {
Chris@148 476 DecoderData *data = (DecoderData *)dp;
Chris@148 477 return data->reader->accept(header, pcm);
Chris@148 478 }
Chris@148 479
Chris@148 480 enum mad_flow
Chris@148 481 MP3FileReader::accept(struct mad_header const *header,
Chris@148 482 struct mad_pcm *pcm)
Chris@148 483 {
Chris@148 484 int channels = pcm->channels;
Chris@148 485 int frames = pcm->length;
Chris@1288 486
Chris@148 487 if (header) {
Chris@1038 488 m_bitrateNum = m_bitrateNum + double(header->bitrate);
Chris@148 489 m_bitrateDenom ++;
Chris@148 490 }
Chris@148 491
Chris@148 492 if (frames < 1) return MAD_FLOW_CONTINUE;
Chris@148 493
Chris@148 494 if (m_channelCount == 0) {
Chris@297 495
Chris@297 496 m_fileRate = pcm->samplerate;
Chris@148 497 m_channelCount = channels;
Chris@297 498
Chris@297 499 initialiseDecodeCache();
Chris@297 500
Chris@297 501 if (m_cacheMode == CacheInTemporaryFile) {
Chris@690 502 // SVDEBUG << "MP3FileReader::accept: channel count " << m_channelCount << ", file rate " << m_fileRate << ", about to start serialised section" << endl;
Chris@297 503 startSerialised("MP3FileReader::Decode");
Chris@297 504 }
Chris@148 505 }
Chris@148 506
Chris@148 507 if (m_bitrateDenom > 0) {
Chris@148 508 double bitrate = m_bitrateNum / m_bitrateDenom;
Chris@148 509 double duration = double(m_fileSize * 8) / bitrate;
Chris@148 510 double elapsed = double(m_frameCount) / m_sampleRate;
Chris@375 511 double percent = 100;
Chris@375 512 if (duration > 0.0) percent = ((elapsed * 100.0) / duration);
Chris@357 513 int p = int(percent);
Chris@357 514 if (p < 1) p = 1;
Chris@357 515 if (p > 99) p = 99;
Chris@392 516 if (m_completion != p && m_reporter) {
Chris@357 517 m_completion = p;
Chris@392 518 m_reporter->setProgress(m_completion);
Chris@148 519 }
Chris@148 520 }
Chris@148 521
Chris@1290 522 if (m_cancelled) {
Chris@1290 523 SVDEBUG << "MP3FileReader: Decoding cancelled" << endl;
Chris@1290 524 return MAD_FLOW_STOP;
Chris@1290 525 }
Chris@148 526
Chris@148 527 if (!isDecodeCacheInitialised()) {
Chris@148 528 initialiseDecodeCache();
Chris@148 529 }
Chris@148 530
Chris@1290 531 if (m_sampleBufferSize < size_t(frames)) {
Chris@1290 532 if (!m_sampleBuffer) {
Chris@1290 533 m_sampleBuffer = new float *[channels];
Chris@297 534 for (int c = 0; c < channels; ++c) {
Chris@1290 535 m_sampleBuffer[c] = 0;
Chris@297 536 }
Chris@297 537 }
Chris@297 538 for (int c = 0; c < channels; ++c) {
Chris@1290 539 delete[] m_sampleBuffer[c];
Chris@1290 540 m_sampleBuffer[c] = new float[frames];
Chris@297 541 }
Chris@1290 542 m_sampleBufferSize = frames;
Chris@297 543 }
Chris@148 544
Chris@297 545 int activeChannels = int(sizeof(pcm->samples) / sizeof(pcm->samples[0]));
Chris@297 546
Chris@297 547 for (int ch = 0; ch < channels; ++ch) {
Chris@297 548
Chris@297 549 for (int i = 0; i < frames; ++i) {
Chris@297 550
Chris@148 551 mad_fixed_t sample = 0;
Chris@297 552 if (ch < activeChannels) {
Chris@148 553 sample = pcm->samples[ch][i];
Chris@148 554 }
Chris@148 555 float fsample = float(sample) / float(MAD_F_ONE);
Chris@297 556
Chris@1290 557 m_sampleBuffer[ch][i] = fsample;
Chris@148 558 }
Chris@148 559 }
Chris@148 560
Chris@1290 561 addSamplesToDecodeCache(m_sampleBuffer, frames);
Chris@148 562
Chris@1288 563 ++m_mp3FrameCount;
Chris@1288 564
Chris@148 565 return MAD_FLOW_CONTINUE;
Chris@148 566 }
Chris@148 567
Chris@148 568 enum mad_flow
Chris@1288 569 MP3FileReader::error_callback(void *dp,
Chris@1288 570 struct mad_stream *stream,
Chris@1288 571 struct mad_frame *)
Chris@148 572 {
Chris@1284 573 DecoderData *data = (DecoderData *)dp;
Chris@1290 574
Chris@1290 575 if (stream->error == MAD_ERROR_LOSTSYNC &&
Chris@1310 576 data->finished) {
Chris@1310 577 // We are at end of file, losing sync is expected behaviour,
Chris@1310 578 // don't report it
Chris@1290 579 return MAD_FLOW_CONTINUE;
Chris@1290 580 }
Chris@1290 581
Chris@1284 582 if (!data->reader->m_decodeErrorShown) {
Chris@1284 583 char buffer[256];
Chris@1284 584 snprintf(buffer, 255,
Chris@1284 585 "MP3 decoding error 0x%04x (%s) at byte offset %lu",
Chris@1284 586 stream->error, mad_stream_errorstr(stream),
Chris@1284 587 (unsigned long)(stream->this_frame - data->start));
Chris@1284 588 SVCERR << "Warning: in file \"" << data->reader->m_path << "\": "
Chris@1284 589 << buffer << " (continuing; will not report any further decode errors for this file)" << endl;
Chris@1284 590 data->reader->m_decodeErrorShown = true;
Chris@1279 591 }
Chris@148 592
Chris@148 593 return MAD_FLOW_CONTINUE;
Chris@148 594 }
Chris@148 595
Chris@157 596 void
Chris@290 597 MP3FileReader::getSupportedExtensions(std::set<QString> &extensions)
Chris@157 598 {
Chris@157 599 extensions.insert("mp3");
Chris@157 600 }
Chris@157 601
Chris@316 602 bool
Chris@316 603 MP3FileReader::supportsExtension(QString extension)
Chris@316 604 {
Chris@316 605 std::set<QString> extensions;
Chris@316 606 getSupportedExtensions(extensions);
Chris@316 607 return (extensions.find(extension.toLower()) != extensions.end());
Chris@316 608 }
Chris@316 609
Chris@316 610 bool
Chris@316 611 MP3FileReader::supportsContentType(QString type)
Chris@316 612 {
Chris@316 613 return (type == "audio/mpeg");
Chris@316 614 }
Chris@316 615
Chris@316 616 bool
Chris@317 617 MP3FileReader::supports(FileSource &source)
Chris@316 618 {
Chris@316 619 return (supportsExtension(source.getExtension()) ||
Chris@316 620 supportsContentType(source.getContentType()));
Chris@316 621 }
Chris@316 622
Chris@316 623
Chris@148 624 #endif