1#define DO_NOT_WANT_PARANOIA_COMPATIBILITY
11#if QT_VERSION >= QT_VERSION_CHECK(6,0,0)
12#include <QtSystemDetection>
21#include <cdio/logging.h>
29#include <libavcodec/avcodec.h>
34static constexpr const char*
CDEXT {
".cda" };
38static void logger(cdio_log_level_t level,
const char *message)
45 LOG(VB_MEDIA, LOG_DEBUG, QString(
"INFO cdio: %1").arg(message));
48 LOG(VB_MEDIA, LOG_DEBUG, QString(
"WARN cdio: %1").arg(message));
52 LOG(VB_GENERAL, LOG_ERR, QString(
"ERROR cdio: %1").arg(message));
65 cdio_log_set_handler(&
logger);
68 CdIo_t *cdio = cdio_open(name.toLatin1(), DRIVER_DEVICE);
71 LOG(VB_MEDIA, LOG_INFO, QString(
"CdDecoder: cdio_open(%1) failed").
82 void*
operator new(std::size_t);
91 operator CdIo_t*()
const {
return m_cdio; }
145 static QRecursiveMutex
s_mtx;
172 m_start = cdio_get_track_lsn(m_cdio,
m_trackNum);
173 m_end = cdio_get_track_last_lsn(m_cdio,
m_trackNum);
174 if (CDIO_INVALID_LSN == m_start ||
175 CDIO_INVALID_LSN == m_end)
178 cdio_destroy(m_cdio), m_cdio =
nullptr;
182 LOG(VB_MEDIA, LOG_DEBUG, QString(
"CdDecoder track=%1 lsn start=%2 end=%3")
186 m_device = cdio_cddap_identify_cdio(m_cdio, 0,
nullptr);
187 if (
nullptr == m_device)
189 LOG(VB_GENERAL, LOG_ERR,
190 QString(
"Error: CdDecoder: cdio_cddap_identify(%1) failed")
192 cdio_destroy(m_cdio), m_cdio =
nullptr;
196 cdio_cddap_verbose_set(m_device,
198 CDDA_MESSAGE_FORGETIT,
200 CDDA_MESSAGE_FORGETIT);
202 if (DRIVER_OP_SUCCESS == cdio_cddap_open(m_device))
205 lsn_t end2 = cdio_cddap_track_lastsector(m_device,
m_trackNum);
208 LOG(VB_MEDIA, LOG_INFO, QString(
"CdDecoder: trim last lsn from %1 to %2")
209 .arg(m_end).arg(end2));
217 if (
nullptr != m_paranoia)
219 cdio_paranoia_modeset(m_paranoia, PARANOIA_MODE_DISABLE);
220 (void)cdio_paranoia_seek(m_paranoia, m_start, SEEK_SET);
224 LOG(VB_GENERAL, LOG_WARNING,
"CD reading with paranoia is disabled");
229 LOG(VB_GENERAL, LOG_ERR,
230 QString(
"Warn: drive '%1' is not cdda capable").
234 int chnls = cdio_get_track_channels(m_cdio,
m_trackNum);
235 m_chan = chnls > 0 ? chnls : 2;
241 AV_CODEC_ID_PCM_S16LE,
m_freq,
false );
279 cdio_paranoia_free(m_paranoia), m_paranoia =
nullptr;
281 cdio_cddap_close(m_device), m_device =
nullptr, m_cdio =
nullptr;
283 cdio_destroy(m_cdio), m_cdio =
nullptr;
314 const std::size_t thresh =
m_bks * 6;
320 m_curPos = m_start +
static_cast< lsn_t
>(
325 cdio_paranoia_seek(m_paranoia, m_curPos, SEEK_SET);
337 if (m_curPos < m_end)
342 int16_t *cdbuffer = cdio_paranoia_read_limited(
343 m_paranoia,
nullptr, 10);
346 cdbuffer, CDIO_CD_FRAMESIZE_RAW);
350 driver_return_code_t c = cdio_read_audio_sector(
352 if (DRIVER_OP_SUCCESS != c)
354 LOG(VB_MEDIA, LOG_DEBUG,
355 QString(
"cdio_read_audio_sector(%1) error %2").
356 arg(m_curPos).arg(c));
358 0, CDIO_CD_FRAMESIZE_RAW);
386 if (fill < (thresh << 6))
395 fill <= total - thresh)
439 driver_return_code_t c = cdio_set_speed(cdio, speed >= 0 ? speed : 1);
440 if (DRIVER_OP_SUCCESS != c)
442 LOG(VB_MEDIA, LOG_INFO,
443 QString(
"Error: cdio_set_speed('%1',%2) failed").
458 track_t tracks = cdio_get_num_tracks(cdio);
459 if (CDIO_INVALID_TRACK != tracks)
460 LOG(VB_MEDIA, LOG_DEBUG, QString(
"getNumTracks = %1").arg(tracks));
477 const track_t last = cdio_get_last_track_num(cdio);
478 if (CDIO_INVALID_TRACK != last)
480 for (track_t
t = cdio_get_first_track_num(cdio) ;
t <= last; ++
t)
482 if (TRACK_FORMAT_AUDIO == cdio_get_track_format(cdio,
t))
485 LOG(VB_MEDIA, LOG_DEBUG, QString(
"getNumCDAudioTracks = %1").arg(nAudio));
507 QString compilation_artist;
511 std::chrono::milliseconds length = 0s;
512 track_t tracknum = 0;
515 tracknum =
getURL().toUInt();
528 const track_t lastTrack = cdio_get_last_track_num(cdio);
529 if (CDIO_INVALID_TRACK == lastTrack)
532 if (TRACK_FORMAT_AUDIO != cdio_get_track_format(cdio, tracknum))
536 bool isDiscChanged =
false;
537 static lsn_t s_totalSectors;
538 lsn_t totalSectors = cdio_get_track_lsn(cdio, CDIO_CDROM_LEADOUT_TRACK);
539 if (s_totalSectors != totalSectors)
541 s_totalSectors = totalSectors;
542 isDiscChanged =
true;
547 lsn_t end = cdio_get_track_last_lsn(cdio, tracknum);
553 if (audioTracks < lastTrack)
555 cdrom_drive_t *dev = cdio_cddap_identify_cdio(cdio, 0,
nullptr);
558 if (DRIVER_OP_SUCCESS == cdio_cddap_open(dev))
561 lsn_t end2 = cdio_cddap_track_lastsector(dev,
563 if (CDIO_INVALID_LSN != end2)
566 cdio_cddap_close_no_free_cdio(dev);
574 const lsn_t
start = cdio_get_track_lsn(cdio, tracknum);
575 if (CDIO_INVALID_LSN !=
start && CDIO_INVALID_LSN != end)
577 length = std::chrono::milliseconds(((end -
start + 1) * 1000 + CDIO_CD_FRAMES_PER_SEC/2) /
578 CDIO_CD_FRAMES_PER_SEC);
581 bool isCompilation =
false;
586 static int s_iCdtext;
594 LOG(VB_MEDIA, LOG_INFO,
595 QString(
"Getting cdtext for track %1...").arg(tracknum));
596 cdtext_t * cdtext = cdio_get_cdtext(m_cdio, tracknum);
597 if (
nullptr != cdtext)
599 genre = cdtext_get_const(CDTEXT_GENRE, cdtext);
600 artist = cdtext_get_const(CDTEXT_PERFORMER, cdtext);
601 title = cdtext_get_const(CDTEXT_TITLE, cdtext);
602 const char* isrc = cdtext_get_const(CDTEXT_ISRC, cdtext);
609 if (isrc && strlen(isrc) >= 7)
611 year = (isrc[5] -
'0') * 10 + (isrc[6] -
'0');
612 year += (year <= 30) ? 2000 : 1900;
615 cdtext_destroy(cdtext);
620 LOG(VB_MEDIA, LOG_INFO,
"Found cdtext track title");
624 cdtext = cdio_get_cdtext(cdio, 0);
625 if (
nullptr != cdtext)
627 compilation_artist = cdtext_get_const(
628 CDTEXT_PERFORMER, cdtext);
629 if (!compilation_artist.isEmpty() &&
630 artist != compilation_artist)
631 isCompilation =
true;
633 album = cdtext_get_const(CDTEXT_TITLE, cdtext);
636 genre = cdtext_get_const(CDTEXT_GENRE, cdtext);
638 cdtext_destroy(cdtext);
644 LOG(VB_MEDIA, LOG_INFO,
"No cdtext title for track");
651 LOG(VB_MEDIA, LOG_INFO,
"No cdtext");
656 if (title.isEmpty() || artist.isEmpty() || album.isEmpty())
659#ifdef HAVE_MUSICBRAINZ
667 auto *metadata = getMusicBrainz().getMetadata(
m_setTrackNum);
670 metadata->setFilename(
getURL());
677 if (compilation_artist.toLower().left(7) ==
"various")
678 compilation_artist = tr(
"Various Artists");
680 if (artist.isEmpty())
682 artist = compilation_artist;
683 compilation_artist.clear();
687 title = tr(
"Track %1").arg(tracknum);
690 title, genre, year, tracknum, length);
692 m->setCompilation(isCompilation);
697#ifdef HAVE_MUSICBRAINZ
702 return s_musicBrainz;
717 static QString s_ext(
CDEXT);
724 static QString s_desc(tr(
"Audio CD parser"));
static lsn_t s_lastAudioLsn
static CdIo_t * openCdio(const QString &name)
static constexpr long kSamplesPerSec
static constexpr const char * CDEXT
static void logger(cdio_log_level_t level, const char *message)
virtual void Drain(void)=0
virtual void PauseUntilBuffered(void)=0
virtual void Reconfigure(const AudioSettings &settings)=0
virtual void GetBufferStatus(uint &fill, uint &total)
virtual void SetSourceBitrate(int)
const QString & description() const override
bool supports(const QString &source) const override
Decoder * create(const QString &file, AudioOutput *output, bool deletable) override
const QString & extension() const override
void setDevice(const QString &dev)
CdDecoder(const QString &file, DecoderFactory *d, AudioOutput *o)
void setCDSpeed(int speed)
bool initialize() override
void seek(double pos) override
MusicMetadata * getMetadata(void)
void run() override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
std::size_t m_decodeBytes
static QRecursiveMutex & getCdioMutex()
int getNumCDAudioTracks()
DecoderEvent::Type m_stat
static const Type kStopped
static const Type kDecoding
static const Type kFinished
QString getURL(void) const
void setURL(const QString &url)
void setOutput(AudioOutput *o)
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
static void usleep(std::chrono::microseconds time)
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
void dispatch(const MythEvent &event)
Dispatch an event to all listeners.
StCdioDevice & operator=(const StCdioDevice &)
StCdioDevice(const StCdioDevice &)
StCdioDevice(const QString &dev)
static const iso6937table * d
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
#define LOG(_MASK_, _LEVEL_, _QSTRING_)