Ticket #9362: 40-mythmusic-cdio-cddecoder.diff

File 40-mythmusic-cdio-cddecoder.diff, 31.3 KB (added by anonymous, 13 years ago)
  • mythplugins/mythmusic/mythmusic/decoder.cpp

     
    181181    {
    182182        factories = new QList<DecoderFactory*>;
    183183
    184 #ifndef USING_MINGW
    185184        Decoder::registerFactory(new CdDecoderFactory);
    186 #endif // USING_MINGW
    187185        Decoder::registerFactory(new avfDecoderFactory);
    188186    }
    189187}
  • mythplugins/mythmusic/mythmusic/cddecoder.h

     
    99#include <vector>
    1010#endif
    1111
    12 #if defined(__linux__) || defined(__FreeBSD__)
     12#ifdef HAVE_CDAUDIO
    1313#include <cdaudio.h>
     14#endif
     15
     16#ifdef HAVE_CDIO
     17# include <cdio/cdda.h>
     18# include <cdio/paranoia.h>
     19#elif defined HAVE_PARANOIA
    1420extern "C" {
    15 #include <cdda_interface.h>
    16 #include <cdda_paranoia.h>
     21# include <cdda_interface.h>
     22# include <cdda_paranoia.h>
    1723}
    1824#endif
    1925
     
    2329{
    2430  public:
    2531    CdDecoder(const QString &file, DecoderFactory *, QIODevice *, AudioOutput *);
    26     virtual ~CdDecoder(void);
     32    virtual ~CdDecoder();
    2733
    28     bool initialize();
    29     double lengthInSeconds();
    30     void seek(double);
    31     void stop();
     34    // Decoder implementation
     35    virtual bool initialize();
     36    virtual void seek(double);
     37    virtual void stop();
    3238
    33     int getNumTracks(void);
    34     int getNumCDAudioTracks(void);
     39    // Decoder overrides
     40    virtual Metadata *getMetadata(void);
     41    virtual void commitMetadata(Metadata *mdata);
    3542
    3643    // The following need to allocate a new Metadata object each time,
    3744    // because their callers (e.g. databasebox.cpp) free the returned value
    3845    Metadata *getMetadata(int track);
    39     Metadata *getMetadata(void);
    40     Metadata *getLastMetadata(void);
     46    Metadata *getLastMetadata();
    4147
    42     void commitMetadata(Metadata *mdata);
    43     void      setDevice(const QString &dev)  { devicename = dev; }
     48#if CONFIG_DARWIN
     49    double lengthInSeconds();
     50#endif
     51    int getNumTracks();
     52    int getNumCDAudioTracks();
     53
     54    void      setDevice(const QString &dev);
     55#ifndef HAVE_CDIO
     56    void      setDevice(const QString &dev)  { this->devicename = dev; }
     57#endif
    4458    void      setCDSpeed(int speed);
    4559
    4660  private:
    4761    void run();
    4862
    49     void writeBlock(void);
     63    void writeBlock();
    5064    void deinit();
    5165
    5266    bool inited, user_stop;
     
    6478    vector<int>        m_tracks;        ///< Start block offset of each track
    6579    vector<Metadata*>  m_mData;         ///< After lookup, details of each trk
    6680#endif
     81#ifdef HAVE_CDIO
     82    static QMutex& getCdioMutex();
     83#endif
    6784
    68     int stat;
     85    DecoderEvent::Type stat;
    6986    char *output_buf;
    70     ulong output_at;
     87    std::size_t output_at;
    7188
    72     unsigned int bks, bksFrames, decodeBytes;
     89    std::size_t bks, bksFrames, decodeBytes;
    7390    bool finish;
    7491    long freq, bitrate;
    7592    int chan;
     
    7895    int settracknum;
    7996    int tracknum;
    8097
    81 #if defined(__linux__) || defined(__FreeBSD__)
     98#ifdef HAVE_CDIO
     99    CdIo_t *cdio;
     100    cdrom_drive_t *device;
     101    cdrom_paranoia_t *paranoia;
     102    lsn_t start, end, curpos;
     103#elif defined HAVE_PARANOIA
    82104    cdrom_drive *device;
    83105    cdrom_paranoia *paranoia;
     106    long int start, end, curpos;
    84107#endif
    85 
    86     long int start, end, curpos;
    87108};
    88109
    89110#endif
  • mythplugins/mythmusic/mythmusic/cddecoder-cdio.cpp

     
     1#define DO_NOT_WANT_PARANOIA_COMPATIBILITY
     2#include "cddecoder.h"
     3
     4// C
     5#include <cstdlib>
     6#include <cstring>
     7
     8#include <unistd.h>
     9
     10// Qt
     11#include <QIODevice>
     12#include <QFile>
     13#include <QObject>
     14#include <QString>
     15
     16// libcdio
     17#include <cdio/cdda.h>
     18
     19// MythTV
     20#include <audiooutput.h>
     21#include <mythcontext.h>
     22
     23extern "C" {
     24#include <libavcodec/avcodec.h>
     25}
     26
     27// MythMusic
     28#include "constants.h"
     29#include "metadata.h"
     30#include "cddb.h"
     31
     32#define CDEXT ".cda"
     33const unsigned kSamplesPerSec = 44100;
     34
     35
     36// Open a cdio device
     37static CdIo_t * openCdio(const QString& name)
     38{
     39    CdIo_t *cdio = cdio_open(name.toAscii(), DRIVER_DEVICE);
     40    if (!cdio)
     41    {
     42        VERBOSE(VB_MEDIA, QString("CdDecoder: cdio_open(%1) failed").
     43            arg(name));
     44    }
     45    return cdio;
     46}
     47
     48// Stack-based cdio device open
     49class StCdioDevice
     50{
     51    CdIo_t* m_cdio;
     52
     53    void* operator new(std::size_t); // Stack only
     54    // No copying
     55    StCdioDevice(const StCdioDevice&);
     56    StCdioDevice& operator =(const StCdioDevice&);
     57
     58public:
     59    StCdioDevice(const QString& dev) : m_cdio(openCdio(dev)) { }
     60    ~StCdioDevice() { if (m_cdio) cdio_destroy(m_cdio); }
     61
     62    operator CdIo_t*() const { return m_cdio; }
     63};
     64
     65
     66CdDecoder::CdDecoder(const QString &file, DecoderFactory *d, QIODevice *i,
     67                     AudioOutput *o) :
     68    Decoder(d, i, o),
     69    inited(false),   user_stop(false),
     70    devicename(""),
     71    stat(DecoderEvent::Error),
     72    output_buf(NULL),
     73    output_at(0),    bks(0),
     74    bksFrames(0),    decodeBytes(0),
     75    finish(false),
     76    freq(0),         bitrate(0),
     77    chan(0),
     78    seekTime(-1.),
     79    settracknum(-1), tracknum(0),
     80    cdio(0),        device(0), paranoia( 0),
     81    start(CDIO_INVALID_LSN),
     82    end(CDIO_INVALID_LSN),
     83    curpos(CDIO_INVALID_LSN)
     84{
     85    setFilename(file);
     86}
     87
     88// virtual
     89CdDecoder::~CdDecoder()
     90{
     91    if (this->inited)
     92        deinit();
     93}
     94
     95void CdDecoder::setDevice(const QString &dev)
     96{
     97    this->devicename = dev;
     98#ifdef WIN32
     99    // libcdio needs the drive letter with no path
     100    if (this->devicename.endsWith('\\'))
     101        this->devicename.chop(1);
     102#endif
     103}
     104
     105// pure virtual
     106void CdDecoder::stop()
     107{
     108    this->user_stop = true;
     109}
     110
     111void CdDecoder::writeBlock()
     112{
     113    while (this->seekTime <= +0.)
     114    {
     115        if(output()->AddFrames(this->output_buf, this->bksFrames, -1))
     116        {
     117            if (this->output_at >= this->bks)
     118            {
     119                this->output_at -= this->bks;
     120                std::memmove(this->output_buf, this->output_buf + this->bks,
     121                    this->output_at);
     122            }
     123            break;
     124        }
     125        else
     126            ::usleep(output()->GetAudioBufferedTime()<<9);
     127    }
     128}
     129
     130//static
     131QMutex& CdDecoder::getCdioMutex()
     132{
     133    static QMutex mtx(QMutex::Recursive);
     134    return mtx;
     135}
     136
     137// pure virtual
     138bool CdDecoder::initialize()
     139{
     140    if (this->inited)
     141        return true;
     142
     143    this->inited = this->user_stop = this->finish = false;
     144    this->freq = this->bitrate = 0L;
     145    this->stat = DecoderEvent::Error;
     146    this->chan = 0;
     147    this->seekTime = -1.;
     148
     149    if (output())
     150        output()->PauseUntilBuffered();
     151
     152    QFile* file = dynamic_cast< QFile* >(input()); // From QIODevice*
     153    if (file)
     154    {
     155        setFilename(file->fileName());
     156        this->tracknum = getFilename().section('.', 0, 0).toUInt();
     157    }
     158
     159    QMutexLocker lock(&getCdioMutex());
     160
     161    this->cdio = openCdio(this->devicename);
     162    if (!this->cdio)
     163        return false;
     164
     165    this->start = cdio_get_track_lsn(this->cdio, this->tracknum);
     166    this->end = cdio_get_track_last_lsn(this->cdio, this->tracknum);
     167    if (CDIO_INVALID_LSN  == this->start ||
     168        CDIO_INVALID_LSN  == this->end)
     169    {
     170        VERBOSE(VB_MEDIA, "CdDecoder: No tracks on " + this->devicename);
     171        cdio_destroy(this->cdio), this->cdio = 0;
     172        return false;
     173    }
     174
     175    VERBOSE(VB_MEDIA+VB_EXTRA, QString("CdDecoder track=%1 lsn start=%2 end=%3").
     176        arg(this->tracknum).arg(this->start).arg(this->end));
     177    this->curpos = this->start;
     178
     179    this->device = cdio_cddap_identify_cdio(this->cdio, 0, NULL);
     180    if (NULL == this->device)
     181    {
     182        VERBOSE(VB_IMPORTANT,
     183            QString("Error: CdDecoder: cdio_cddap_identify(%1) failed").
     184            arg(this->devicename));
     185        cdio_destroy(this->cdio), this->cdio = 0;
     186        return false;
     187    }
     188
     189    cdio_cddap_verbose_set(this->device,
     190        VERBOSE_LEVEL_CHECK(VB_MEDIA) ? CDDA_MESSAGE_PRINTIT :
     191            CDDA_MESSAGE_FORGETIT,
     192        VERBOSE_LEVEL_CHECK(VB_MEDIA+VB_EXTRA) ? CDDA_MESSAGE_PRINTIT :
     193            CDDA_MESSAGE_FORGETIT);
     194
     195    if (DRIVER_OP_SUCCESS == cdio_cddap_open(this->device))
     196    {
     197        // cdio_get_track_last_lsn is unreliable on discs with data at end
     198        lsn_t end2 = cdio_cddap_track_lastsector(this->device, this->tracknum);
     199        if (end2 < this->end)
     200        {
     201            VERBOSE(VB_MEDIA, QString("CdDecoder: trim last lsn from %1 to %2").
     202                arg(this->end).arg(end2));
     203            this->end = end2;
     204        }
     205
     206        this->paranoia = cdio_paranoia_init(this->device);
     207        if (NULL != this->paranoia)
     208        {
     209            cdio_paranoia_modeset(this->paranoia, PARANOIA_MODE_DISABLE);
     210            (void)cdio_paranoia_seek(this->paranoia, this->start, SEEK_SET);
     211        }
     212        else
     213        {
     214            VERBOSE(VB_IMPORTANT, "Warn: CD reading with paranoia is disabled");
     215        }
     216    }
     217    else
     218    {
     219        VERBOSE(VB_IMPORTANT,
     220            QString("Warn: drive '%1' is not cdda capable").
     221            arg(this->devicename));
     222    }
     223
     224    int chnls = cdio_get_track_channels(this->cdio, this->tracknum);
     225    this->chan = chnls > 0 ? chnls : 2;
     226    this->freq = kSamplesPerSec;
     227
     228    if (output())
     229    {
     230        const AudioSettings settings(FORMAT_S16, this->chan,
     231            CODEC_ID_PCM_S16LE, this->freq, false /* AC3/DTS passthru */);
     232        output()->Reconfigure(settings);
     233        output()->SetSourceBitrate(this->freq * this->chan * 16);
     234    }
     235
     236    // 20ms worth
     237    this->bks = (this->freq * this->chan * 2) / 50;
     238    this->bksFrames = this->freq / 50;
     239    // decode 8 bks worth of samples each time we need more
     240    this->decodeBytes = this->bks << 3;
     241
     242    this->output_buf = reinterpret_cast< char* >(
     243        ::av_malloc(this->decodeBytes + CDIO_CD_FRAMESIZE_RAW * 2));
     244    this->output_at = 0;
     245
     246    setCDSpeed(2);
     247
     248    return this->inited = true;
     249}
     250
     251// pure virtual
     252void CdDecoder::seek(double pos)
     253{
     254    this->seekTime = pos;
     255    if (output())
     256        output()->PauseUntilBuffered();
     257}
     258
     259// private
     260void CdDecoder::deinit()
     261{
     262    setCDSpeed(-1);
     263
     264    QMutexLocker lock(&getCdioMutex());
     265
     266    if (this->paranoia)
     267        cdio_paranoia_free(this->paranoia), this->paranoia = 0;
     268    if (this->device)
     269        cdio_cddap_close(this->device), this->device = 0, this->cdio = 0;
     270    if (this->cdio)
     271        cdio_destroy(this->cdio), this->cdio = 0;
     272
     273    if (this->output_buf)
     274        ::av_free(this->output_buf), this->output_buf = NULL;
     275
     276    this->inited = this->user_stop = this->finish = false;
     277    this->freq = this->bitrate = 0L;
     278    this->stat = DecoderEvent::Finished;
     279    this->chan = 0;
     280    setInput(0);
     281    setOutput(0);
     282}
     283
     284// private
     285void CdDecoder::run()
     286{
     287    if (!this->inited)
     288        return;
     289
     290    this->stat = DecoderEvent::Decoding;
     291    // NB block scope required to prevent re-entrancy
     292    {
     293        DecoderEvent e(this->stat);
     294        dispatch(e);
     295    }
     296
     297    // account for possible frame expansion in aobase (upmix, float conv)
     298    const std::size_t thresh = this->bks * 6;
     299
     300    while (!this->finish && !this->user_stop)
     301    {
     302        if (this->seekTime >= +0.)
     303        {
     304            this->curpos = this->start + static_cast< lsn_t >(
     305                (this->seekTime * kSamplesPerSec) / CD_FRAMESAMPLES);
     306            if (this->paranoia)
     307            {
     308                QMutexLocker lock(&getCdioMutex());
     309                cdio_paranoia_seek(this->paranoia, this->curpos, SEEK_SET);
     310            }
     311
     312            this->output_at = 0;
     313            this->seekTime = -1.;
     314        }
     315
     316        if (this->output_at < this->bks)
     317        {
     318            while (this->output_at < this->decodeBytes &&
     319                   !this->finish && !this->user_stop && this->seekTime <= +0.)
     320            {
     321                if (this->curpos < this->end)
     322                {
     323                    QMutexLocker lock(&getCdioMutex());
     324                    if (this->paranoia)
     325                    {
     326                        int16_t *cdbuffer = cdio_paranoia_read(
     327                                                this->paranoia, 0);
     328                        if (cdbuffer)
     329                            memcpy(&this->output_buf[this->output_at],
     330                                cdbuffer, CDIO_CD_FRAMESIZE_RAW);
     331                    }
     332                    else
     333                    {
     334                        driver_return_code_t c = cdio_read_audio_sector(
     335                            this->cdio, &this->output_buf[this->output_at],
     336                            this->curpos);
     337                        if (DRIVER_OP_SUCCESS != c)
     338                        {
     339                            VERBOSE(VB_MEDIA+VB_EXTRA,
     340                                QString("cdio_read_audio_sector(%1) error %2").
     341                                arg(this->curpos).arg(c));
     342                            memset( &this->output_buf[this->output_at],
     343                                0, CDIO_CD_FRAMESIZE_RAW);
     344                        }
     345                    }
     346
     347                    this->output_at += CDIO_CD_FRAMESIZE_RAW;
     348                    ++(this->curpos);
     349                }
     350                else
     351                {
     352                    this->finish = true;
     353                }
     354            }
     355        }
     356
     357        if (!output())
     358            continue;
     359
     360        // Wait until we need to decode or supply more samples
     361        uint fill = 0, total = 0;
     362        while (!this->finish && !this->user_stop && this->seekTime <= +0.)
     363        {
     364            output()->GetBufferStatus(fill, total);
     365            // Make sure we have decoded samples ready and that the
     366            // audiobuffer is reasonably populated
     367            if (fill < (thresh << 6))
     368                break;
     369            else
     370            {
     371                // Wait for half of the buffer to drain
     372                ::usleep(output()->GetAudioBufferedTime()<<9);
     373            }
     374        }
     375
     376        // write a block if there's sufficient space for it
     377        if (!this->user_stop &&
     378            this->output_at >= this->bks &&
     379            fill <= total - thresh)
     380        {
     381            writeBlock();
     382        }
     383    }
     384
     385    if (this->user_stop)
     386        this->inited = false;
     387    else if (output())
     388    {
     389        // Drain our buffer
     390        while (this->output_at >= this->bks)
     391            writeBlock();
     392
     393        // Drain ao buffer
     394        output()->Drain();
     395    }
     396
     397    if (this->finish)
     398        this->stat = DecoderEvent::Finished;
     399    else if (this->user_stop)
     400        this->stat = DecoderEvent::Stopped;
     401    else
     402        this->stat = DecoderEvent::Error;
     403
     404    // NB block scope required to step onto next track
     405    {
     406        DecoderEvent e(this->stat);
     407        dispatch(e);
     408    }
     409
     410    deinit();
     411}
     412
     413//public
     414void CdDecoder::setCDSpeed(int speed)
     415{
     416    QMutexLocker lock(&getCdioMutex());
     417
     418    StCdioDevice cdio(this->devicename);
     419    if (cdio)
     420    {
     421        driver_return_code_t c = cdio_set_speed(cdio, speed >= 0 ? speed : 1);
     422        if (DRIVER_OP_SUCCESS != c)
     423        {
     424            VERBOSE(VB_MEDIA,
     425                QString("Error: cdio_set_speed('%1',%2) failed").
     426                arg(this->devicename).arg(speed));
     427        }
     428    }
     429}
     430
     431//public
     432int CdDecoder::getNumTracks()
     433{
     434    QMutexLocker lock(&getCdioMutex());
     435
     436    StCdioDevice cdio(this->devicename);
     437    if (!cdio)
     438        return 0;
     439
     440    track_t tracks = cdio_get_num_tracks(cdio);
     441    if (CDIO_INVALID_TRACK != tracks)
     442        VERBOSE(VB_MEDIA+VB_EXTRA, QString("getNumTracks = %1").arg(tracks));
     443    else
     444        tracks = -1;
     445
     446    return tracks;
     447}
     448
     449//public
     450int CdDecoder::getNumCDAudioTracks()
     451{
     452    QMutexLocker lock(&getCdioMutex());
     453
     454    StCdioDevice cdio(this->devicename);
     455    if (!cdio)
     456        return 0;
     457
     458    int nAudio = 0;
     459    const track_t last = cdio_get_last_track_num(cdio);
     460    if (CDIO_INVALID_TRACK != last)
     461    {
     462        for (track_t t = cdio_get_first_track_num(cdio) ; t <= last; ++t)
     463        {
     464            if (TRACK_FORMAT_AUDIO == cdio_get_track_format(cdio, t))
     465                ++nAudio;
     466        }
     467        VERBOSE(VB_MEDIA+VB_EXTRA, QString("getNumCDAudioTracks = %1").arg(nAudio));
     468    }
     469    else
     470      nAudio = -1;
     471
     472    return nAudio;
     473}
     474
     475//public
     476Metadata* CdDecoder::getMetadata(int track)
     477{
     478    this->settracknum = track;
     479    return getMetadata();
     480}
     481
     482//public
     483Metadata *CdDecoder::getLastMetadata()
     484{
     485    for(int i = getNumTracks(); i > 0; --i)
     486    {
     487        Metadata *m = getMetadata(i);
     488        if(m)
     489            return m;
     490    }
     491    return NULL;
     492}
     493
     494// Create a TOC
     495static lsn_t s_lastAudioLsn;
     496static Cddb::Toc& GetToc(CdIo_t *cdio, Cddb::Toc& toc)
     497{
     498    // Get lead-in
     499    const track_t firstTrack = cdio_get_first_track_num(cdio);
     500    lsn_t lsn0 = 0;
     501    msf_t msf;
     502    if (cdio_get_track_msf(cdio, firstTrack, &msf))
     503        lsn0 = (msf.m * 60 + msf.s) * CDIO_CD_FRAMES_PER_SEC + msf.f;
     504
     505    const track_t lastTrack = cdio_get_last_track_num(cdio);
     506    for (track_t t = firstTrack; t <= lastTrack + 1; ++t)
     507    {
     508#if 0 // This would be better but the msf's returned are way off in libcdio 0.81
     509        if (!cdio_get_track_msf(cdio, t, &msf))
     510            break;
     511#else
     512        lsn_t lsn = cdio_get_track_lsn(cdio, t);
     513        if (s_lastAudioLsn && lsn > s_lastAudioLsn)
     514            lsn = s_lastAudioLsn;
     515        lsn += lsn0; // lead-in
     516       
     517        std::div_t d = std::div(lsn, CDIO_CD_FRAMES_PER_SEC);
     518        msf.f = d.rem;
     519        d = std::div(d.quot, 60);
     520        msf.s = d.rem;
     521        msf.m = d.quot;
     522#endif
     523        //VERBOSE(VB_MEDIA, QString("Track %1 msf: %2:%3:%4").
     524        //    arg(t,2).arg(msf.m,2).arg(msf.s,2).arg(msf.f,2) );
     525        toc.push_back(Cddb::Msf(msf.m, msf.s, msf.f));
     526
     527        if (TRACK_FORMAT_AUDIO != cdio_get_track_format(cdio, t))
     528            break;
     529    }
     530    return toc;
     531}
     532
     533//virtual
     534Metadata *CdDecoder::getMetadata()
     535{
     536    QString artist, album, compilation_artist, title, genre;
     537    int year = 0;
     538    unsigned long length = 0;
     539    track_t tracknum = 0;
     540
     541    if (-1 == this->settracknum)
     542        tracknum = getFilename().toUInt();
     543    else
     544    {
     545        tracknum = this->settracknum;
     546        setFilename(QString("%1" CDEXT).arg(tracknum));
     547    }
     548
     549    QMutexLocker lock(&getCdioMutex());
     550
     551    StCdioDevice cdio(this->devicename);
     552    if (!cdio)
     553        return NULL;
     554
     555    const track_t lastTrack = cdio_get_last_track_num(cdio);
     556    if (CDIO_INVALID_TRACK == lastTrack)
     557        return NULL;
     558
     559    if (TRACK_FORMAT_AUDIO != cdio_get_track_format(cdio, tracknum))
     560        return NULL;
     561
     562    // Assume disc changed if max LSN different
     563    bool isDiscChanged = false;
     564    static lsn_t s_totalSectors;
     565    lsn_t totalSectors = cdio_get_track_lsn(cdio, CDIO_CDROM_LEADOUT_TRACK);
     566    if (s_totalSectors != totalSectors)
     567    {
     568        s_totalSectors = totalSectors;
     569        isDiscChanged = true;
     570    }
     571
     572    // NB cdio_get_track_last_lsn is unreliable for the last audio track
     573    // of discs with data tracks beyond
     574    lsn_t end = cdio_get_track_last_lsn(cdio, tracknum);
     575    if (isDiscChanged)
     576    {
     577        const track_t audioTracks = getNumCDAudioTracks();
     578        s_lastAudioLsn = cdio_get_track_last_lsn(cdio, audioTracks);
     579
     580        if (audioTracks < lastTrack)
     581        {
     582            cdrom_drive_t *dev = cdio_cddap_identify_cdio(cdio, 0, NULL);
     583            if (NULL != dev)
     584            {
     585                if (DRIVER_OP_SUCCESS == cdio_cddap_open(dev))
     586                {
     587                    // NB this can be S L O W  but is reliable
     588                    lsn_t end2 = cdio_cddap_track_lastsector(dev,
     589                        getNumCDAudioTracks());
     590                    if (CDIO_INVALID_LSN != end2)
     591                        s_lastAudioLsn = end2;
     592                }
     593                cdio_cddap_close_no_free_cdio(dev);
     594            }
     595        }
     596    }
     597
     598    if (s_lastAudioLsn && s_lastAudioLsn < end)
     599        end = s_lastAudioLsn;
     600
     601    const lsn_t start = cdio_get_track_lsn(cdio, tracknum);
     602    if (CDIO_INVALID_LSN != start && CDIO_INVALID_LSN != end)
     603    {
     604        length = ((end - start + 1) * 1000 + CDIO_CD_FRAMES_PER_SEC/2) /
     605            CDIO_CD_FRAMES_PER_SEC;
     606    }
     607
     608    bool isCompilation = false;
     609
     610#define CDTEXT 0 // Disabled - cd-text access on discs without it is S L O W
     611#if CDTEXT
     612    static int s_iCdtext;
     613    if (isDiscChanged)
     614        s_iCdtext = -1;
     615
     616    if (s_iCdtext)
     617    {
     618        // cdio_get_cdtext can't take >5 seconds on some CD's without cdtext
     619        if (s_iCdtext < 0)
     620            VERBOSE(VB_MEDIA,
     621                QString("Getting cdtext for track %1...").arg(tracknum));
     622        cdtext_t * cdtext = cdio_get_cdtext(cdio, tracknum);
     623        if (NULL != cdtext)
     624        {
     625            genre = cdtext_get_const(CDTEXT_GENRE, cdtext);
     626            artist = cdtext_get_const(CDTEXT_PERFORMER, cdtext);
     627            title = cdtext_get_const(CDTEXT_TITLE, cdtext);
     628            const char* isrc = cdtext_get_const(CDTEXT_ISRC, cdtext);
     629            /* ISRC codes are 12 characters long, in the form CCXXXYYNNNNN
     630             * CC = country code
     631             * XXX = registrant e.g. BMG
     632             * CC = year withou century
     633             * NNNNN = unique ID
     634             */
     635            if (isrc && strlen(isrc) >= 7)
     636            {
     637                year = (isrc[5] - '0') * 10 + (isrc[6] - '0');
     638                year += (year <= 30) ? 2000 : 1900;
     639            }
     640
     641            cdtext_destroy(cdtext);
     642
     643            if (!title.isNull())
     644            {
     645                if (s_iCdtext < 0)
     646                    VERBOSE(VB_MEDIA, "Found cdtext track title");
     647                s_iCdtext = 1;
     648
     649                // Get disc info
     650                cdtext = cdio_get_cdtext(cdio, 0);
     651                if (NULL != cdtext)
     652                {
     653                    compilation_artist = cdtext_get_const(
     654                        CDTEXT_PERFORMER, cdtext);
     655                    if (!compilation_artist.isEmpty() &&
     656                            artist != compilation_artist)
     657                        isCompilation = true;
     658
     659                    album = cdtext_get_const(CDTEXT_TITLE, cdtext);
     660
     661                    if (genre.isNull())
     662                        genre = cdtext_get_const(CDTEXT_GENRE, cdtext);
     663
     664                    cdtext_destroy(cdtext);
     665                }
     666            }
     667            else
     668            {
     669                if (s_iCdtext < 0)
     670                    VERBOSE(VB_MEDIA, "No cdtext title for track");
     671                s_iCdtext = 0;
     672            }
     673        }
     674        else
     675        {
     676            if (s_iCdtext < 0)
     677                VERBOSE(VB_MEDIA, "No cdtext");
     678            s_iCdtext = 0;
     679        }
     680    }
     681
     682    if (title.isEmpty() || artist.isEmpty() || album.isEmpty())
     683#endif // CDTEXT
     684    {
     685        // CDDB lookup
     686        Cddb::Toc toc;
     687        Cddb::Matches r;
     688        if (Cddb::Query(r, GetToc(cdio, toc)))
     689        {
     690            Cddb::Matches::match_t::const_iterator select = r.matches.begin();
     691
     692            if (r.matches.size() > 1)
     693            {
     694                // TODO prompt user to select one
     695                // In the meantime, select the first non-generic genre
     696                for (Cddb::Matches::match_t::const_iterator it = select;
     697                    it != r.matches.end(); ++it)
     698                {
     699                    QString g = it->genre.toLower();
     700                    if (g != "misc" && g != "data")
     701                    {
     702                        select = it;
     703                        break;
     704                    }
     705                }
     706            }
     707
     708            Cddb::Album info;
     709            if (Cddb::Read(info, select->genre, select->discID))
     710            {
     711                isCompilation = info.isCompilation;
     712                if (info.genre.toLower() != "misc")
     713                    genre = info.genre;
     714                album = info.title;
     715                compilation_artist = info.artist;
     716                year = info.year;
     717                if (info.tracks.size() >= tracknum)
     718                {
     719                    const Cddb::Track& track = info.tracks[tracknum - 1];
     720                    title = track.title;
     721                    artist = track.artist;
     722                }
     723
     724                // Create a temporary local alias for future lookups
     725                if (r.discID != info.discID)
     726                    Cddb::Alias(info, r.discID);
     727            }
     728        }
     729    }
     730
     731    if (compilation_artist.toLower().left(7) == "various")
     732        compilation_artist = QObject::tr("Various Artists");
     733
     734    if (artist.isEmpty())
     735    {
     736        artist = compilation_artist;
     737        compilation_artist.clear();
     738    }
     739
     740    if (title.isEmpty())
     741        title = QObject::tr("Track %1").arg(tracknum);
     742
     743    Metadata *m = new Metadata(getFilename(), artist, compilation_artist,
     744        album, title, genre, year, tracknum, length);
     745    if (m)
     746        m->setCompilation(isCompilation);
     747
     748    return m;
     749}
     750
     751// virtual
     752void CdDecoder::commitMetadata(Metadata *mdata)
     753{
     754    QMutexLocker lock(&getCdioMutex());
     755
     756    StCdioDevice cdio(this->devicename);
     757    if (!cdio)
     758        return;
     759
     760    Cddb::Toc toc;
     761    GetToc(cdio, toc);
     762
     763    unsigned secs;
     764    Cddb::discid_t discID = Cddb::Discid(secs, toc.data(), toc.size() - 1);
     765
     766    Cddb::Album album(discID, mdata->Genre().toLower().toUtf8());
     767    if (!Cddb::Read(album, album.genre, discID))
     768        album.toc = toc;
     769
     770    album.isCompilation = mdata->Compilation();
     771    if (!mdata->Compilation())
     772        album.artist = mdata->Artist();
     773    else if (mdata->CompilationArtist() != album.artist)
     774        album.artist = mdata->CompilationArtist();
     775
     776    album.title = mdata->Album();
     777    album.year = mdata->Year();
     778
     779    if (album.tracks.size() < this->tracknum)
     780        album.tracks.resize(this->tracknum);
     781
     782    Cddb::Track& track = album.tracks[this->tracknum - 1];
     783    track.title = mdata->Title();
     784    track.artist = mdata->Artist();
     785
     786    Cddb::Write(album);
     787}
     788
     789
     790// pure virtual
     791bool CdDecoderFactory::supports(const QString &source) const
     792{
     793    return (source.right(extension().length()).toLower() == extension());
     794}
     795
     796// pure virtual
     797const QString &CdDecoderFactory::extension() const
     798{
     799    static QString ext(CDEXT);
     800    return ext;
     801}
     802
     803// pure virtual
     804const QString &CdDecoderFactory::description() const
     805{
     806    static QString desc(QObject::tr("Audio CD parser"));
     807    return desc;
     808}
     809
     810// pure virtual
     811Decoder *CdDecoderFactory::create(const QString &file, QIODevice *input,
     812                                  AudioOutput *output, bool deletable)
     813{
     814   if (deletable)
     815        return new CdDecoder(file, this, input, output);
     816
     817    static CdDecoder *decoder;
     818    if (! decoder) {
     819        decoder = new CdDecoder(file, this, input, output);
     820    } else {
     821        decoder->setInput(input);
     822        decoder->setFilename(file);
     823        decoder->setOutput(output);
     824    }
     825
     826    return decoder;
     827}
  • mythplugins/mythmusic/mythmusic/cddecoder.cpp

     
    3737    m_lastTrack(0),  m_leadout(0),
    3838    m_lengthInSecs(0.0)
    3939#endif
    40     stat(0),         output_buf(NULL),
     40    stat(DecoderEvent::Error),
     41    output_buf(NULL),
    4142    output_at(0),    bks(0),
    4243    bksFrames(0),    decodeBytes(0),
    4344    finish(false),
     
    4546    chan(0),
    4647    totalTime(0.0),  seekTime(-1.0),
    4748    settracknum(-1), tracknum(0),
    48 #if defined(__linux__) || defined(__FreeBSD__)
     49#ifdef HAVE_PARANOIA
    4950    device(NULL),    paranoia(NULL),
    5051#endif
    5152    start(0),        end(0),
     
    8586{
    8687    inited = user_stop = finish = FALSE;
    8788    freq = bitrate = 0;
    88     stat = chan = 0;
     89    stat = DecoderEvent::Error;
     90    chan = 0;
    8991    seekTime = -1.0;
    9092
    9193    if (output())
     
    9698    filename = ((QFile *)input())->fileName();
    9799    tracknum = filename.section('.', 0, 0).toUInt();
    98100
     101#ifdef HAVE_PARANOIA
    99102    QByteArray devname = devicename.toAscii();
    100103    device = cdda_identify(devname.constData(), 0, NULL);
    101104    if (!device)
     
    148151    setCDSpeed(2);
    149152    inited = TRUE;
    150153    return TRUE;
     154#else
     155    return FALSE;
     156#endif
    151157}
    152158
    153159void CdDecoder::seek(double pos)
     
    159165
    160166void CdDecoder::deinit()
    161167{
     168#ifdef HAVE_PARANOIA
    162169    setCDSpeed(-1);
    163170    if (paranoia)
    164171        paranoia_free(paranoia);
     
    171178
    172179    device = NULL;
    173180    paranoia = NULL;
     181#endif
    174182
    175183    inited = user_stop = finish = FALSE;
    176184    freq = bitrate = 0;
    177     stat = chan = 0;
     185    stat = DecoderEvent::Error;
     186    chan = 0;
    178187    setInput(0);
    179188    setOutput(0);
    180189}
    181190
     191#ifdef HAVE_PARANOIA
    182192static void paranoia_cb(long inpos, int function)
    183193{
    184194    inpos = inpos; function = function;
    185195}
     196#endif
    186197
    187198void CdDecoder::run()
    188199{
     
    205216        if (seekTime >= 0.0)
    206217        {
    207218            curpos = (int)(((seekTime * 44100) / CD_FRAMESAMPLES) + start);
     219#ifdef HAVE_PARANOIA
    208220            paranoia_seek(paranoia, curpos, SEEK_SET);
     221#endif
    209222            output_at = 0;
    210223            seekTime = -1.0;
    211224        }
     
    219232
    220233                if (curpos <= end)
    221234                {
     235#ifdef HAVE_PARANOIA
    222236                    cdbuffer = paranoia_read(paranoia, paranoia_cb);
    223237
    224238                    memcpy((char *)(output_buf + output_at), (char *)cdbuffer,
    225239                           CD_FRAMESIZE_RAW);
     240#endif
    226241
    227242                    output_at += CD_FRAMESIZE_RAW;
    228243                }
     
    286301
    287302int CdDecoder::getNumTracks(void)
    288303{
     304#ifdef HAVE_CDAUDIO
    289305    QByteArray devname = devicename.toAscii();
    290306    int cd = cd_init_device(const_cast<char*>(devname.constData()));
    291307
     
    309325    cd_finish(cd);
    310326
    311327    return retval;
     328#else
     329    return 0;
     330#endif
    312331}
    313332
    314333int CdDecoder::getNumCDAudioTracks(void)
    315334{
     335#ifdef HAVE_CDAUDIO
    316336    QByteArray devname = devicename.toAscii();
    317337    int cd = cd_init_device(const_cast<char*>(devname.constData()));
    318338
     
    343363    cd_finish(cd);
    344364
    345365    return retval;
     366#else
     367    return 0;
     368#endif
    346369}
    347370
    348371Metadata* CdDecoder::getMetadata(int track)
     
    372395    QString artist, album, compilation_artist, title, genre;
    373396    int year = 0, tracknum = 0, length = 0;
    374397
     398#ifdef HAVE_CDAUDIO
    375399    QByteArray devname = devicename.toAscii();
    376400    int cd = cd_init_device(const_cast<char*>(devname.constData()));
    377401
     
    466490    length = length < 0 ? 0 : length;
    467491    length *= 1000;
    468492
     493    cd_finish(cd);
     494#endif // defined HAVE_CDAUDIO
     495
    469496    Metadata *retdata = new Metadata(filename, artist, compilation_artist,
    470497                                     album, title, genre, year, tracknum, length);
    471498
    472     retdata->determineIfCompilation(true);
     499    if (retdata)
     500        retdata->determineIfCompilation(true);
    473501
    474     cd_finish(cd);
    475502    return retdata;
    476503}
    477504
     505#ifdef HAVE_CDAUDIO
    478506static void set_cstring(char *dest, const char *src, size_t dest_buf_size)
    479507{
    480508    if (dest_buf_size < 1)
     
    482510    strncpy(dest, src, dest_buf_size - 1);
    483511    dest[dest_buf_size - 1] = 0;
    484512}
     513#endif
    485514
    486515void CdDecoder::commitMetadata(Metadata *mdata)
    487516{
     517#ifdef HAVE_CDAUDIO
    488518    QByteArray devname = devicename.toAscii();
    489519    int cd = cd_init_device(const_cast<char*>(devname.constData()));
    490520
     
    566596    cddb_write_data(cd, &discdata);
    567597
    568598    cd_finish(cd);
     599#else
     600    (void)mdata;
     601#endif
    569602}
    570603
    571604bool CdDecoderFactory::supports(const QString &source) const