MythTV  0.26-pre
cddecoder.cpp
Go to the documentation of this file.
00001 #define DO_NOT_WANT_PARANOIA_COMPATIBILITY
00002 #include "cddecoder.h"
00003 
00004 // C
00005 #include <cstdlib>
00006 #include <cstring>
00007 
00008 #include <unistd.h>
00009 
00010 // Qt
00011 #include <QIODevice>
00012 #include <QFile>
00013 #include <QObject>
00014 #include <QString>
00015 
00016 // libcdio
00017 #include <cdio/cdda.h>
00018 #include <cdio/logging.h>
00019 
00020 // MythTV
00021 #include <audiooutput.h>
00022 #include <mythcontext.h>
00023 
00024 extern "C" {
00025 #include <libavcodec/avcodec.h>
00026 }
00027 
00028 // MythMusic
00029 #include "constants.h"
00030 #include "metadata.h"
00031 #include "cddb.h"
00032 
00033 #define CDEXT ".cda"
00034 const unsigned kSamplesPerSec = 44100;
00035 
00036 // Handle cdio log output
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 // Open a cdio device
00057 static CdIo_t * openCdio(const QString& name)
00058 {
00059     // Setup log handler
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 // Stack-based cdio device open
00077 class StCdioDevice
00078 {
00079     CdIo_t* m_cdio;
00080 
00081     void* operator new(std::size_t); // Stack only
00082     // No copying
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 // virtual
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     // libcdio needs the drive letter with no path
00128     if (m_devicename.endsWith('\\'))
00129         m_devicename.chop(1);
00130 #endif
00131 }
00132 
00133 // pure virtual
00134 void CdDecoder::stop()
00135 {
00136     m_user_stop = true;
00137 }
00138 
00139 // private
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 //static
00160 QMutex& CdDecoder::getCdioMutex()
00161 {
00162     static QMutex mtx(QMutex::Recursive);
00163     return mtx;
00164 }
00165 
00166 // pure virtual
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()); // From QIODevice*
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         // cdio_get_track_last_lsn is unreliable on discs with data at end
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 /* AC3/DTS passthru */);
00261         output()->Reconfigure(settings);
00262         output()->SetSourceBitrate(m_freq * m_chan * 16);
00263     }
00264 
00265     // 20ms worth
00266     m_bks = (m_freq * m_chan * 2) / 50;
00267     m_bksFrames = m_freq / 50;
00268     // decode 8 bks worth of samples each time we need more
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 // pure virtual
00283 void CdDecoder::seek(double pos)
00284 {
00285     m_seekTime = pos;
00286     if (output())
00287         output()->PauseUntilBuffered();
00288 }
00289 
00290 // private
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 // private virtual
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     // NB block scope required to prevent re-entrancy
00328     {
00329         DecoderEvent e(m_stat);
00330         dispatch(e);
00331     }
00332 
00333     // account for possible frame expansion in aobase (upmix, float conv)
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         // Wait until we need to decode or supply more samples
00397         uint fill = 0, total = 0;
00398         while (!m_finish && !m_user_stop && m_seekTime <= +0.)
00399         {
00400             output()->GetBufferStatus(fill, total);
00401             // Make sure we have decoded samples ready and that the
00402             // audiobuffer is reasonably populated
00403             if (fill < (thresh << 6))
00404                 break;
00405             else
00406             {
00407                 // Wait for half of the buffer to drain
00408                 ::usleep(output()->GetAudioBufferedTime()<<9);
00409             }
00410         }
00411 
00412         // write a block if there's sufficient space for it
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         // Drain our buffer
00426         while (m_output_at >= m_bks)
00427             writeBlock();
00428 
00429         // Drain ao buffer
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     // NB block scope required to step onto next track
00441     {
00442         DecoderEvent e(m_stat);
00443         dispatch(e);
00444     }
00445 
00446     deinit();
00447 
00448     RunEpilog();
00449 }
00450 
00451 //public
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 //public
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 //public
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 //public
00512 Metadata* CdDecoder::getMetadata(int track)
00513 {
00514     m_settracknum = track;
00515     return getMetadata();
00516 }
00517 
00518 //public
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 // Create a TOC
00531 static lsn_t s_lastAudioLsn;
00532 static Cddb::Toc& GetToc(CdIo_t *cdio, Cddb::Toc& toc)
00533 {
00534     // Get lead-in
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; // lead-in
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         //LOG(VB_MEDIA, LOG_INFO, QString("Track %1 msf: %2:%3:%4").
00560         //    arg(t,2).arg(msf.m,2).arg(msf.s,2).arg(msf.f,2) );
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 //virtual
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     // Assume disc changed if max LSN different
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     // NB cdio_get_track_last_lsn is unreliable for the last audio track
00609     // of discs with data tracks beyond
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                     // NB this can be S L O W  but is reliable
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         // cdio_get_cdtext can't take >5 seconds on some CD's without cdtext
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             /* ISRC codes are 12 characters long, in the form CCXXXYYNNNNN
00666              * CC = country code
00667              * XXX = registrant e.g. BMG
00668              * CC = year withou century
00669              * NNNNN = unique ID
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                 // Get disc info
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 // CDTEXT
00720     {
00721         // CDDB lookup
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                 // TODO prompt user to select one
00731                 // In the meantime, select the first non-generic genre
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                 // Create a temporary local alias for future lookups
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 // virtual
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 // pure virtual
00827 bool CdDecoderFactory::supports(const QString &source) const
00828 {
00829     return (source.right(extension().length()).toLower() == extension());
00830 }
00831 
00832 // pure virtual
00833 const QString &CdDecoderFactory::extension() const
00834 {
00835     static QString ext(CDEXT);
00836     return ext;
00837 }
00838 
00839 // pure virtual
00840 const QString &CdDecoderFactory::description() const
00841 {
00842     static QString desc(QObject::tr("Audio CD parser"));
00843     return desc;
00844 }
00845 
00846 // pure virtual
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 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends