00001 #define DO_NOT_WANT_PARANOIA_COMPATIBILITY
00002 #include "cddecoder.h"
00003
00004
00005 #include <cstdlib>
00006 #include <cstring>
00007
00008 #include <unistd.h>
00009
00010
00011 #include <QIODevice>
00012 #include <QFile>
00013 #include <QObject>
00014 #include <QString>
00015
00016
00017 #include <cdio/cdda.h>
00018 #include <cdio/logging.h>
00019
00020
00021 #include <audiooutput.h>
00022 #include <mythcontext.h>
00023
00024 extern "C" {
00025 #include <libavcodec/avcodec.h>
00026 }
00027
00028
00029 #include "constants.h"
00030 #include "metadata.h"
00031 #include "cddb.h"
00032
00033 #define CDEXT ".cda"
00034 const unsigned kSamplesPerSec = 44100;
00035
00036
00037 static void logger(cdio_log_level_t level, const char message[])
00038 {
00039 switch (level)
00040 {
00041 case CDIO_LOG_DEBUG:
00042 break;
00043 case CDIO_LOG_INFO:
00044 LOG(VB_MEDIA, LOG_DEBUG, QString("INFO cdio: %1").arg(message));
00045 break;
00046 case CDIO_LOG_WARN:
00047 LOG(VB_MEDIA, LOG_DEBUG, QString("WARN cdio: %1").arg(message));
00048 break;
00049 case CDIO_LOG_ERROR:
00050 case CDIO_LOG_ASSERT:
00051 LOG(VB_GENERAL, LOG_ERR, QString("ERROR cdio: %1").arg(message));
00052 break;
00053 }
00054 }
00055
00056
00057 static CdIo_t * openCdio(const QString& name)
00058 {
00059
00060 static int s_logging;
00061 if (!s_logging)
00062 {
00063 s_logging = 1;
00064 cdio_log_set_handler(&logger);
00065 }
00066
00067 CdIo_t *cdio = cdio_open(name.toAscii(), DRIVER_DEVICE);
00068 if (!cdio)
00069 {
00070 LOG(VB_MEDIA, LOG_INFO, QString("CdDecoder: cdio_open(%1) failed").
00071 arg(name));
00072 }
00073 return cdio;
00074 }
00075
00076
00077 class StCdioDevice
00078 {
00079 CdIo_t* m_cdio;
00080
00081 void* operator new(std::size_t);
00082
00083 StCdioDevice(const StCdioDevice&);
00084 StCdioDevice& operator =(const StCdioDevice&);
00085
00086 public:
00087 StCdioDevice(const QString& dev) : m_cdio(openCdio(dev)) { }
00088 ~StCdioDevice() { if (m_cdio) cdio_destroy(m_cdio); }
00089
00090 operator CdIo_t*() const { return m_cdio; }
00091 };
00092
00093
00094 CdDecoder::CdDecoder(const QString &file, DecoderFactory *d, QIODevice *i,
00095 AudioOutput *o) :
00096 Decoder(d, i, o),
00097 m_inited(false), m_user_stop(false),
00098 m_devicename(""),
00099 m_stat(DecoderEvent::Error),
00100 m_output_buf(NULL),
00101 m_output_at(0), m_bks(0),
00102 m_bksFrames(0), m_decodeBytes(0),
00103 m_finish(false),
00104 m_freq(0), m_bitrate(0),
00105 m_chan(0),
00106 m_seekTime(-1.),
00107 m_settracknum(-1), m_tracknum(0),
00108 m_cdio(0), m_device(0), m_paranoia( 0),
00109 m_start(CDIO_INVALID_LSN),
00110 m_end(CDIO_INVALID_LSN),
00111 m_curpos(CDIO_INVALID_LSN)
00112 {
00113 setFilename(file);
00114 }
00115
00116
00117 CdDecoder::~CdDecoder()
00118 {
00119 if (m_inited)
00120 deinit();
00121 }
00122
00123 void CdDecoder::setDevice(const QString &dev)
00124 {
00125 m_devicename = dev;
00126 #ifdef WIN32
00127
00128 if (m_devicename.endsWith('\\'))
00129 m_devicename.chop(1);
00130 #endif
00131 }
00132
00133
00134 void CdDecoder::stop()
00135 {
00136 m_user_stop = true;
00137 }
00138
00139
00140 void CdDecoder::writeBlock()
00141 {
00142 while (m_seekTime <= +0.)
00143 {
00144 if(output()->AddFrames(m_output_buf, m_bksFrames, -1))
00145 {
00146 if (m_output_at >= m_bks)
00147 {
00148 m_output_at -= m_bks;
00149 std::memmove(m_output_buf, m_output_buf + m_bks,
00150 m_output_at);
00151 }
00152 break;
00153 }
00154 else
00155 ::usleep(output()->GetAudioBufferedTime()<<9);
00156 }
00157 }
00158
00159
00160 QMutex& CdDecoder::getCdioMutex()
00161 {
00162 static QMutex mtx(QMutex::Recursive);
00163 return mtx;
00164 }
00165
00166
00167 bool CdDecoder::initialize()
00168 {
00169 if (m_inited)
00170 return true;
00171
00172 m_inited = m_user_stop = m_finish = false;
00173 m_freq = m_bitrate = 0L;
00174 m_stat = DecoderEvent::Error;
00175 m_chan = 0;
00176 m_seekTime = -1.;
00177
00178 if (output())
00179 output()->PauseUntilBuffered();
00180
00181 QFile* file = dynamic_cast< QFile* >(input());
00182 if (file)
00183 {
00184 setFilename(file->fileName());
00185 m_tracknum = getFilename().section('.', 0, 0).toUInt();
00186 }
00187
00188 QMutexLocker lock(&getCdioMutex());
00189
00190 m_cdio = openCdio(m_devicename);
00191 if (!m_cdio)
00192 return false;
00193
00194 m_start = cdio_get_track_lsn(m_cdio, m_tracknum);
00195 m_end = cdio_get_track_last_lsn(m_cdio, m_tracknum);
00196 if (CDIO_INVALID_LSN == m_start ||
00197 CDIO_INVALID_LSN == m_end)
00198 {
00199 LOG(VB_MEDIA, LOG_INFO, "CdDecoder: No tracks on " + m_devicename);
00200 cdio_destroy(m_cdio), m_cdio = 0;
00201 return false;
00202 }
00203
00204 LOG(VB_MEDIA, LOG_DEBUG, QString("CdDecoder track=%1 lsn start=%2 end=%3")
00205 .arg(m_tracknum).arg(m_start).arg(m_end));
00206 m_curpos = m_start;
00207
00208 m_device = cdio_cddap_identify_cdio(m_cdio, 0, NULL);
00209 if (NULL == m_device)
00210 {
00211 LOG(VB_GENERAL, LOG_ERR,
00212 QString("Error: CdDecoder: cdio_cddap_identify(%1) failed")
00213 .arg(m_devicename));
00214 cdio_destroy(m_cdio), m_cdio = 0;
00215 return false;
00216 }
00217
00218 cdio_cddap_verbose_set(m_device,
00219 VERBOSE_LEVEL_CHECK(VB_MEDIA, LOG_ANY) ? CDDA_MESSAGE_PRINTIT :
00220 CDDA_MESSAGE_FORGETIT,
00221 VERBOSE_LEVEL_CHECK(VB_MEDIA, LOG_DEBUG) ? CDDA_MESSAGE_PRINTIT :
00222 CDDA_MESSAGE_FORGETIT);
00223
00224 if (DRIVER_OP_SUCCESS == cdio_cddap_open(m_device))
00225 {
00226
00227 lsn_t end2 = cdio_cddap_track_lastsector(m_device, m_tracknum);
00228 if (end2 < m_end)
00229 {
00230 LOG(VB_MEDIA, LOG_INFO, QString("CdDecoder: trim last lsn from %1 to %2")
00231 .arg(m_end).arg(end2));
00232 m_end = end2;
00233 }
00234
00235 m_paranoia = cdio_paranoia_init(m_device);
00236 if (NULL != m_paranoia)
00237 {
00238 cdio_paranoia_modeset(m_paranoia, PARANOIA_MODE_DISABLE);
00239 (void)cdio_paranoia_seek(m_paranoia, m_start, SEEK_SET);
00240 }
00241 else
00242 {
00243 LOG(VB_GENERAL, LOG_ERR, "Warn: CD reading with paranoia is disabled");
00244 }
00245 }
00246 else
00247 {
00248 LOG(VB_GENERAL, LOG_ERR,
00249 QString("Warn: drive '%1' is not cdda capable").
00250 arg(m_devicename));
00251 }
00252
00253 int chnls = cdio_get_track_channels(m_cdio, m_tracknum);
00254 m_chan = chnls > 0 ? chnls : 2;
00255 m_freq = kSamplesPerSec;
00256
00257 if (output())
00258 {
00259 const AudioSettings settings(FORMAT_S16, m_chan,
00260 CODEC_ID_PCM_S16LE, m_freq, false );
00261 output()->Reconfigure(settings);
00262 output()->SetSourceBitrate(m_freq * m_chan * 16);
00263 }
00264
00265
00266 m_bks = (m_freq * m_chan * 2) / 50;
00267 m_bksFrames = m_freq / 50;
00268
00269 m_decodeBytes = m_bks << 3;
00270
00271 m_output_buf = reinterpret_cast< char* >(
00272 ::av_malloc(m_decodeBytes + CDIO_CD_FRAMESIZE_RAW * 2));
00273 m_output_at = 0;
00274
00275 setCDSpeed(2);
00276
00277 m_inited = true;
00278
00279 return m_inited;
00280 }
00281
00282
00283 void CdDecoder::seek(double pos)
00284 {
00285 m_seekTime = pos;
00286 if (output())
00287 output()->PauseUntilBuffered();
00288 }
00289
00290
00291 void CdDecoder::deinit()
00292 {
00293 setCDSpeed(-1);
00294
00295 QMutexLocker lock(&getCdioMutex());
00296
00297 if (m_paranoia)
00298 cdio_paranoia_free(m_paranoia), m_paranoia = 0;
00299 if (m_device)
00300 cdio_cddap_close(m_device), m_device = 0, m_cdio = 0;
00301 if (m_cdio)
00302 cdio_destroy(m_cdio), m_cdio = 0;
00303
00304 if (m_output_buf)
00305 ::av_free(m_output_buf), m_output_buf = NULL;
00306
00307 m_inited = m_user_stop = m_finish = false;
00308 m_freq = m_bitrate = 0L;
00309 m_stat = DecoderEvent::Finished;
00310 m_chan = 0;
00311 setInput(0);
00312 setOutput(0);
00313 }
00314
00315
00316 void CdDecoder::run()
00317 {
00318 RunProlog();
00319
00320 if (!m_inited)
00321 {
00322 RunEpilog();
00323 return;
00324 }
00325
00326 m_stat = DecoderEvent::Decoding;
00327
00328 {
00329 DecoderEvent e(m_stat);
00330 dispatch(e);
00331 }
00332
00333
00334 const std::size_t thresh = m_bks * 6;
00335
00336 while (!m_finish && !m_user_stop)
00337 {
00338 if (m_seekTime >= +0.)
00339 {
00340 m_curpos = m_start + static_cast< lsn_t >(
00341 (m_seekTime * kSamplesPerSec) / CD_FRAMESAMPLES);
00342 if (m_paranoia)
00343 {
00344 QMutexLocker lock(&getCdioMutex());
00345 cdio_paranoia_seek(m_paranoia, m_curpos, SEEK_SET);
00346 }
00347
00348 m_output_at = 0;
00349 m_seekTime = -1.;
00350 }
00351
00352 if (m_output_at < m_bks)
00353 {
00354 while (m_output_at < m_decodeBytes &&
00355 !m_finish && !m_user_stop && m_seekTime <= +0.)
00356 {
00357 if (m_curpos < m_end)
00358 {
00359 QMutexLocker lock(&getCdioMutex());
00360 if (m_paranoia)
00361 {
00362 int16_t *cdbuffer = cdio_paranoia_read_limited(
00363 m_paranoia, 0, 10);
00364 if (cdbuffer)
00365 memcpy(&m_output_buf[m_output_at],
00366 cdbuffer, CDIO_CD_FRAMESIZE_RAW);
00367 }
00368 else
00369 {
00370 driver_return_code_t c = cdio_read_audio_sector(
00371 m_cdio, &m_output_buf[m_output_at],
00372 m_curpos);
00373 if (DRIVER_OP_SUCCESS != c)
00374 {
00375 LOG(VB_MEDIA, LOG_DEBUG,
00376 QString("cdio_read_audio_sector(%1) error %2").
00377 arg(m_curpos).arg(c));
00378 memset( &m_output_buf[m_output_at],
00379 0, CDIO_CD_FRAMESIZE_RAW);
00380 }
00381 }
00382
00383 m_output_at += CDIO_CD_FRAMESIZE_RAW;
00384 ++(m_curpos);
00385 }
00386 else
00387 {
00388 m_finish = true;
00389 }
00390 }
00391 }
00392
00393 if (!output())
00394 continue;
00395
00396
00397 uint fill = 0, total = 0;
00398 while (!m_finish && !m_user_stop && m_seekTime <= +0.)
00399 {
00400 output()->GetBufferStatus(fill, total);
00401
00402
00403 if (fill < (thresh << 6))
00404 break;
00405 else
00406 {
00407
00408 ::usleep(output()->GetAudioBufferedTime()<<9);
00409 }
00410 }
00411
00412
00413 if (!m_user_stop &&
00414 m_output_at >= m_bks &&
00415 fill <= total - thresh)
00416 {
00417 writeBlock();
00418 }
00419 }
00420
00421 if (m_user_stop)
00422 m_inited = false;
00423 else if (output())
00424 {
00425
00426 while (m_output_at >= m_bks)
00427 writeBlock();
00428
00429
00430 output()->Drain();
00431 }
00432
00433 if (m_finish)
00434 m_stat = DecoderEvent::Finished;
00435 else if (m_user_stop)
00436 m_stat = DecoderEvent::Stopped;
00437 else
00438 m_stat = DecoderEvent::Error;
00439
00440
00441 {
00442 DecoderEvent e(m_stat);
00443 dispatch(e);
00444 }
00445
00446 deinit();
00447
00448 RunEpilog();
00449 }
00450
00451
00452 void CdDecoder::setCDSpeed(int speed)
00453 {
00454 QMutexLocker lock(&getCdioMutex());
00455
00456 StCdioDevice cdio(m_devicename);
00457 if (cdio)
00458 {
00459 driver_return_code_t c = cdio_set_speed(cdio, speed >= 0 ? speed : 1);
00460 if (DRIVER_OP_SUCCESS != c)
00461 {
00462 LOG(VB_MEDIA, LOG_INFO,
00463 QString("Error: cdio_set_speed('%1',%2) failed").
00464 arg(m_devicename).arg(speed));
00465 }
00466 }
00467 }
00468
00469
00470 int CdDecoder::getNumTracks()
00471 {
00472 QMutexLocker lock(&getCdioMutex());
00473
00474 StCdioDevice cdio(m_devicename);
00475 if (!cdio)
00476 return 0;
00477
00478 track_t tracks = cdio_get_num_tracks(cdio);
00479 if (CDIO_INVALID_TRACK != tracks)
00480 LOG(VB_MEDIA, LOG_DEBUG, QString("getNumTracks = %1").arg(tracks));
00481 else
00482 tracks = -1;
00483
00484 return tracks;
00485 }
00486
00487
00488 int CdDecoder::getNumCDAudioTracks()
00489 {
00490 QMutexLocker lock(&getCdioMutex());
00491
00492 StCdioDevice cdio(m_devicename);
00493 if (!cdio)
00494 return 0;
00495
00496 int nAudio = 0;
00497 const track_t last = cdio_get_last_track_num(cdio);
00498 if (CDIO_INVALID_TRACK != last)
00499 {
00500 for (track_t t = cdio_get_first_track_num(cdio) ; t <= last; ++t)
00501 {
00502 if (TRACK_FORMAT_AUDIO == cdio_get_track_format(cdio, t))
00503 ++nAudio;
00504 }
00505 LOG(VB_MEDIA, LOG_DEBUG, QString("getNumCDAudioTracks = %1").arg(nAudio));
00506 }
00507
00508 return nAudio;
00509 }
00510
00511
00512 Metadata* CdDecoder::getMetadata(int track)
00513 {
00514 m_settracknum = track;
00515 return getMetadata();
00516 }
00517
00518
00519 Metadata *CdDecoder::getLastMetadata()
00520 {
00521 for(int i = getNumTracks(); i > 0; --i)
00522 {
00523 Metadata *m = getMetadata(i);
00524 if(m)
00525 return m;
00526 }
00527 return NULL;
00528 }
00529
00530
00531 static lsn_t s_lastAudioLsn;
00532 static Cddb::Toc& GetToc(CdIo_t *cdio, Cddb::Toc& toc)
00533 {
00534
00535 const track_t firstTrack = cdio_get_first_track_num(cdio);
00536 lsn_t lsn0 = 0;
00537 msf_t msf;
00538 if (cdio_get_track_msf(cdio, firstTrack, &msf))
00539 lsn0 = (msf.m * 60 + msf.s) * CDIO_CD_FRAMES_PER_SEC + msf.f;
00540
00541 const track_t lastTrack = cdio_get_last_track_num(cdio);
00542 for (track_t t = firstTrack; t <= lastTrack + 1; ++t)
00543 {
00544 #if 0 // This would be better but the msf's returned are way off in libcdio 0.81
00545 if (!cdio_get_track_msf(cdio, t, &msf))
00546 break;
00547 #else
00548 lsn_t lsn = cdio_get_track_lsn(cdio, t);
00549 if (s_lastAudioLsn && lsn > s_lastAudioLsn)
00550 lsn = s_lastAudioLsn;
00551 lsn += lsn0;
00552
00553 std::div_t d = std::div(lsn, CDIO_CD_FRAMES_PER_SEC);
00554 msf.f = d.rem;
00555 d = std::div(d.quot, 60);
00556 msf.s = d.rem;
00557 msf.m = d.quot;
00558 #endif
00559
00560
00561 toc.push_back(Cddb::Msf(msf.m, msf.s, msf.f));
00562
00563 if (TRACK_FORMAT_AUDIO != cdio_get_track_format(cdio, t))
00564 break;
00565 }
00566 return toc;
00567 }
00568
00569
00570 Metadata *CdDecoder::getMetadata()
00571 {
00572 QString artist, album, compilation_artist, title, genre;
00573 int year = 0;
00574 unsigned long length = 0;
00575 track_t tracknum = 0;
00576
00577 if (-1 == m_settracknum)
00578 tracknum = getFilename().toUInt();
00579 else
00580 {
00581 tracknum = m_settracknum;
00582 setFilename(QString("%1" CDEXT).arg(tracknum));
00583 }
00584
00585 QMutexLocker lock(&getCdioMutex());
00586
00587 StCdioDevice cdio(m_devicename);
00588 if (!cdio)
00589 return NULL;
00590
00591 const track_t lastTrack = cdio_get_last_track_num(cdio);
00592 if (CDIO_INVALID_TRACK == lastTrack)
00593 return NULL;
00594
00595 if (TRACK_FORMAT_AUDIO != cdio_get_track_format(cdio, tracknum))
00596 return NULL;
00597
00598
00599 bool isDiscChanged = false;
00600 static lsn_t s_totalSectors;
00601 lsn_t totalSectors = cdio_get_track_lsn(cdio, CDIO_CDROM_LEADOUT_TRACK);
00602 if (s_totalSectors != totalSectors)
00603 {
00604 s_totalSectors = totalSectors;
00605 isDiscChanged = true;
00606 }
00607
00608
00609
00610 lsn_t end = cdio_get_track_last_lsn(cdio, tracknum);
00611 if (isDiscChanged)
00612 {
00613 const track_t audioTracks = getNumCDAudioTracks();
00614 s_lastAudioLsn = cdio_get_track_last_lsn(cdio, audioTracks);
00615
00616 if (audioTracks < lastTrack)
00617 {
00618 cdrom_drive_t *dev = cdio_cddap_identify_cdio(cdio, 0, NULL);
00619 if (NULL != dev)
00620 {
00621 if (DRIVER_OP_SUCCESS == cdio_cddap_open(dev))
00622 {
00623
00624 lsn_t end2 = cdio_cddap_track_lastsector(dev,
00625 getNumCDAudioTracks());
00626 if (CDIO_INVALID_LSN != end2)
00627 s_lastAudioLsn = end2;
00628 }
00629 cdio_cddap_close_no_free_cdio(dev);
00630 }
00631 }
00632 }
00633
00634 if (s_lastAudioLsn && s_lastAudioLsn < end)
00635 end = s_lastAudioLsn;
00636
00637 const lsn_t start = cdio_get_track_lsn(cdio, tracknum);
00638 if (CDIO_INVALID_LSN != start && CDIO_INVALID_LSN != end)
00639 {
00640 length = ((end - start + 1) * 1000 + CDIO_CD_FRAMES_PER_SEC/2) /
00641 CDIO_CD_FRAMES_PER_SEC;
00642 }
00643
00644 bool isCompilation = false;
00645
00646 #define CDTEXT 0 // Disabled - cd-text access on discs without it is S L O W
00647 #if CDTEXT
00648 static int s_iCdtext;
00649 if (isDiscChanged)
00650 s_iCdtext = -1;
00651
00652 if (s_iCdtext)
00653 {
00654
00655 if (s_iCdtext < 0)
00656 LOG(VB_MEDIA, LOG_INFO,
00657 QString("Getting cdtext for track %1...").arg(tracknum));
00658 cdtext_t * cdtext = cdio_get_cdtext(m_cdio, tracknum);
00659 if (NULL != cdtext)
00660 {
00661 genre = cdtext_get_const(CDTEXT_GENRE, cdtext);
00662 artist = cdtext_get_const(CDTEXT_PERFORMER, cdtext);
00663 title = cdtext_get_const(CDTEXT_TITLE, cdtext);
00664 const char* isrc = cdtext_get_const(CDTEXT_ISRC, cdtext);
00665
00666
00667
00668
00669
00670
00671 if (isrc && strlen(isrc) >= 7)
00672 {
00673 year = (isrc[5] - '0') * 10 + (isrc[6] - '0');
00674 year += (year <= 30) ? 2000 : 1900;
00675 }
00676
00677 cdtext_destroy(cdtext);
00678
00679 if (!title.isNull())
00680 {
00681 if (s_iCdtext < 0)
00682 LOG(VB_MEDIA, LOG_INFO, "Found cdtext track title");
00683 s_iCdtext = 1;
00684
00685
00686 cdtext = cdio_get_cdtext(cdio, 0);
00687 if (NULL != cdtext)
00688 {
00689 compilation_artist = cdtext_get_const(
00690 CDTEXT_PERFORMER, cdtext);
00691 if (!compilation_artist.isEmpty() &&
00692 artist != compilation_artist)
00693 isCompilation = true;
00694
00695 album = cdtext_get_const(CDTEXT_TITLE, cdtext);
00696
00697 if (genre.isNull())
00698 genre = cdtext_get_const(CDTEXT_GENRE, cdtext);
00699
00700 cdtext_destroy(cdtext);
00701 }
00702 }
00703 else
00704 {
00705 if (s_iCdtext < 0)
00706 LOG(VB_MEDIA, LOG_INFO, "No cdtext title for track");
00707 s_iCdtext = 0;
00708 }
00709 }
00710 else
00711 {
00712 if (s_iCdtext < 0)
00713 LOG(VB_MEDIA, LOG_INFO, "No cdtext");
00714 s_iCdtext = 0;
00715 }
00716 }
00717
00718 if (title.isEmpty() || artist.isEmpty() || album.isEmpty())
00719 #endif
00720 {
00721
00722 Cddb::Toc toc;
00723 Cddb::Matches r;
00724 if (Cddb::Query(r, GetToc(cdio, toc)))
00725 {
00726 Cddb::Matches::match_t::const_iterator select = r.matches.begin();
00727
00728 if (r.matches.size() > 1)
00729 {
00730
00731
00732 for (Cddb::Matches::match_t::const_iterator it = select;
00733 it != r.matches.end(); ++it)
00734 {
00735 QString g = it->genre.toLower();
00736 if (g != "misc" && g != "data")
00737 {
00738 select = it;
00739 break;
00740 }
00741 }
00742 }
00743
00744 Cddb::Album info;
00745 if (Cddb::Read(info, select->genre, select->discID))
00746 {
00747 isCompilation = info.isCompilation;
00748 if (info.genre.toLower() != "misc")
00749 genre = info.genre;
00750 album = info.title;
00751 compilation_artist = info.artist;
00752 year = info.year;
00753 if (info.tracks.size() >= tracknum)
00754 {
00755 const Cddb::Track& track = info.tracks[tracknum - 1];
00756 title = track.title;
00757 artist = track.artist;
00758 }
00759
00760
00761 if (r.discID != info.discID)
00762 Cddb::Alias(info, r.discID);
00763 }
00764 }
00765 }
00766
00767 if (compilation_artist.toLower().left(7) == "various")
00768 compilation_artist = QObject::tr("Various Artists");
00769
00770 if (artist.isEmpty())
00771 {
00772 artist = compilation_artist;
00773 compilation_artist.clear();
00774 }
00775
00776 if (title.isEmpty())
00777 title = QObject::tr("Track %1").arg(tracknum);
00778
00779 Metadata *m = new Metadata(getFilename(), artist, compilation_artist,
00780 album, title, genre, year, tracknum, length);
00781 if (m)
00782 m->setCompilation(isCompilation);
00783
00784 return m;
00785 }
00786
00787
00788 void CdDecoder::commitMetadata(Metadata *mdata)
00789 {
00790 QMutexLocker lock(&getCdioMutex());
00791
00792 StCdioDevice cdio(m_devicename);
00793 if (!cdio)
00794 return;
00795
00796 Cddb::Toc toc;
00797 GetToc(cdio, toc);
00798
00799 unsigned secs;
00800 Cddb::discid_t discID = Cddb::Discid(secs, toc.data(), toc.size() - 1);
00801
00802 Cddb::Album album(discID, mdata->Genre().toLower().toUtf8());
00803 if (!Cddb::Read(album, album.genre, discID))
00804 album.toc = toc;
00805
00806 album.isCompilation = mdata->Compilation();
00807 if (!mdata->Compilation())
00808 album.artist = mdata->Artist();
00809 else if (mdata->CompilationArtist() != album.artist)
00810 album.artist = mdata->CompilationArtist();
00811
00812 album.title = mdata->Album();
00813 album.year = mdata->Year();
00814
00815 if (album.tracks.size() < m_tracknum)
00816 album.tracks.resize(m_tracknum);
00817
00818 Cddb::Track& track = album.tracks[m_tracknum - 1];
00819 track.title = mdata->Title();
00820 track.artist = mdata->Artist();
00821
00822 Cddb::Write(album);
00823 }
00824
00825
00826
00827 bool CdDecoderFactory::supports(const QString &source) const
00828 {
00829 return (source.right(extension().length()).toLower() == extension());
00830 }
00831
00832
00833 const QString &CdDecoderFactory::extension() const
00834 {
00835 static QString ext(CDEXT);
00836 return ext;
00837 }
00838
00839
00840 const QString &CdDecoderFactory::description() const
00841 {
00842 static QString desc(QObject::tr("Audio CD parser"));
00843 return desc;
00844 }
00845
00846
00847 Decoder *CdDecoderFactory::create(const QString &file, QIODevice *input,
00848 AudioOutput *output, bool deletable)
00849 {
00850 if (deletable)
00851 return new CdDecoder(file, this, input, output);
00852
00853 static CdDecoder *decoder;
00854 if (! decoder) {
00855 decoder = new CdDecoder(file, this, input, output);
00856 } else {
00857 decoder->setInput(input);
00858 decoder->setFilename(file);
00859 decoder->setOutput(output);
00860 }
00861
00862 return decoder;
00863 }
00864