1#define DO_NOT_WANT_PARANOIA_COMPATIBILITY
17#include <cdio/logging.h>
25#include <libavcodec/avcodec.h>
30static constexpr const char*
CDEXT {
".cda" };
34static void logger(cdio_log_level_t level,
const char *message)
41 LOG(VB_MEDIA, LOG_DEBUG, QString(
"INFO cdio: %1").arg(message));
44 LOG(VB_MEDIA, LOG_DEBUG, QString(
"WARN cdio: %1").arg(message));
48 LOG(VB_GENERAL, LOG_ERR, QString(
"ERROR cdio: %1").arg(message));
61 cdio_log_set_handler(&
logger);
64 CdIo_t *cdio = cdio_open(name.toLatin1(), DRIVER_DEVICE);
67 LOG(VB_MEDIA, LOG_INFO, QString(
"CdDecoder: cdio_open(%1) failed").
78 void*
operator new(std::size_t);
87 operator CdIo_t*()
const {
return m_cdio; }
141 static QRecursiveMutex
s_mtx;
168 m_start = cdio_get_track_lsn(m_cdio,
m_trackNum);
169 m_end = cdio_get_track_last_lsn(m_cdio,
m_trackNum);
170 if (CDIO_INVALID_LSN == m_start ||
171 CDIO_INVALID_LSN == m_end)
174 cdio_destroy(m_cdio), m_cdio =
nullptr;
178 LOG(VB_MEDIA, LOG_DEBUG, QString(
"CdDecoder track=%1 lsn start=%2 end=%3")
182 m_device = cdio_cddap_identify_cdio(m_cdio, 0,
nullptr);
183 if (
nullptr == m_device)
185 LOG(VB_GENERAL, LOG_ERR,
186 QString(
"Error: CdDecoder: cdio_cddap_identify(%1) failed")
188 cdio_destroy(m_cdio), m_cdio =
nullptr;
192 cdio_cddap_verbose_set(m_device,
194 CDDA_MESSAGE_FORGETIT,
196 CDDA_MESSAGE_FORGETIT);
198 if (DRIVER_OP_SUCCESS == cdio_cddap_open(m_device))
201 lsn_t end2 = cdio_cddap_track_lastsector(m_device,
m_trackNum);
204 LOG(VB_MEDIA, LOG_INFO, QString(
"CdDecoder: trim last lsn from %1 to %2")
205 .arg(m_end).arg(end2));
213 if (
nullptr != m_paranoia)
215 cdio_paranoia_modeset(m_paranoia, PARANOIA_MODE_DISABLE);
216 (void)cdio_paranoia_seek(m_paranoia, m_start, SEEK_SET);
220 LOG(VB_GENERAL, LOG_WARNING,
"CD reading with paranoia is disabled");
225 LOG(VB_GENERAL, LOG_ERR,
226 QString(
"Warn: drive '%1' is not cdda capable").
230 int chnls = cdio_get_track_channels(m_cdio,
m_trackNum);
231 m_chan = chnls > 0 ? chnls : 2;
237 AV_CODEC_ID_PCM_S16LE,
m_freq,
false );
275 cdio_paranoia_free(m_paranoia), m_paranoia =
nullptr;
277 cdio_cddap_close(m_device), m_device =
nullptr, m_cdio =
nullptr;
279 cdio_destroy(m_cdio), m_cdio =
nullptr;
310 const std::size_t thresh =
m_bks * 6;
316 m_curPos = m_start +
static_cast< lsn_t
>(
321 cdio_paranoia_seek(m_paranoia, m_curPos, SEEK_SET);
333 if (m_curPos < m_end)
338 int16_t *cdbuffer = cdio_paranoia_read_limited(
339 m_paranoia,
nullptr, 10);
342 cdbuffer, CDIO_CD_FRAMESIZE_RAW);
346 driver_return_code_t c = cdio_read_audio_sector(
348 if (DRIVER_OP_SUCCESS != c)
350 LOG(VB_MEDIA, LOG_DEBUG,
351 QString(
"cdio_read_audio_sector(%1) error %2").
352 arg(m_curPos).arg(c));
354 0, CDIO_CD_FRAMESIZE_RAW);
382 if (fill < (thresh << 6))
391 fill <= total - thresh)
435 driver_return_code_t c = cdio_set_speed(cdio, speed >= 0 ? speed : 1);
436 if (DRIVER_OP_SUCCESS != c)
438 LOG(VB_MEDIA, LOG_INFO,
439 QString(
"Error: cdio_set_speed('%1',%2) failed").
454 track_t tracks = cdio_get_num_tracks(cdio);
455 if (CDIO_INVALID_TRACK != tracks)
456 LOG(VB_MEDIA, LOG_DEBUG, QString(
"getNumTracks = %1").arg(tracks));
473 const track_t last = cdio_get_last_track_num(cdio);
474 if (CDIO_INVALID_TRACK != last)
476 for (track_t
t = cdio_get_first_track_num(cdio) ;
t <= last; ++
t)
478 if (TRACK_FORMAT_AUDIO == cdio_get_track_format(cdio,
t))
481 LOG(VB_MEDIA, LOG_DEBUG, QString(
"getNumCDAudioTracks = %1").arg(nAudio));
503 QString compilation_artist;
507 std::chrono::milliseconds length = 0s;
508 track_t tracknum = 0;
511 tracknum =
getURL().toUInt();
524 const track_t lastTrack = cdio_get_last_track_num(cdio);
525 if (CDIO_INVALID_TRACK == lastTrack)
528 if (TRACK_FORMAT_AUDIO != cdio_get_track_format(cdio, tracknum))
532 bool isDiscChanged =
false;
533 static lsn_t s_totalSectors;
534 lsn_t totalSectors = cdio_get_track_lsn(cdio, CDIO_CDROM_LEADOUT_TRACK);
535 if (s_totalSectors != totalSectors)
537 s_totalSectors = totalSectors;
538 isDiscChanged =
true;
543 lsn_t end = cdio_get_track_last_lsn(cdio, tracknum);
549 if (audioTracks < lastTrack)
551 cdrom_drive_t *dev = cdio_cddap_identify_cdio(cdio, 0,
nullptr);
554 if (DRIVER_OP_SUCCESS == cdio_cddap_open(dev))
557 lsn_t end2 = cdio_cddap_track_lastsector(dev,
559 if (CDIO_INVALID_LSN != end2)
562 cdio_cddap_close_no_free_cdio(dev);
570 const lsn_t
start = cdio_get_track_lsn(cdio, tracknum);
571 if (CDIO_INVALID_LSN !=
start && CDIO_INVALID_LSN != end)
573 length = std::chrono::milliseconds(((end -
start + 1) * 1000 + CDIO_CD_FRAMES_PER_SEC/2) /
574 CDIO_CD_FRAMES_PER_SEC);
577 bool isCompilation =
false;
582 static int s_iCdtext;
590 LOG(VB_MEDIA, LOG_INFO,
591 QString(
"Getting cdtext for track %1...").arg(tracknum));
592 cdtext_t * cdtext = cdio_get_cdtext(m_cdio, tracknum);
593 if (
nullptr != cdtext)
595 genre = cdtext_get_const(CDTEXT_GENRE, cdtext);
596 artist = cdtext_get_const(CDTEXT_PERFORMER, cdtext);
597 title = cdtext_get_const(CDTEXT_TITLE, cdtext);
598 const char* isrc = cdtext_get_const(CDTEXT_ISRC, cdtext);
605 if (isrc && strlen(isrc) >= 7)
607 year = (isrc[5] -
'0') * 10 + (isrc[6] -
'0');
608 year += (year <= 30) ? 2000 : 1900;
611 cdtext_destroy(cdtext);
616 LOG(VB_MEDIA, LOG_INFO,
"Found cdtext track title");
620 cdtext = cdio_get_cdtext(cdio, 0);
621 if (
nullptr != cdtext)
623 compilation_artist = cdtext_get_const(
624 CDTEXT_PERFORMER, cdtext);
625 if (!compilation_artist.isEmpty() &&
626 artist != compilation_artist)
627 isCompilation =
true;
629 album = cdtext_get_const(CDTEXT_TITLE, cdtext);
632 genre = cdtext_get_const(CDTEXT_GENRE, cdtext);
634 cdtext_destroy(cdtext);
640 LOG(VB_MEDIA, LOG_INFO,
"No cdtext title for track");
647 LOG(VB_MEDIA, LOG_INFO,
"No cdtext");
652 if (title.isEmpty() || artist.isEmpty() || album.isEmpty())
655#ifdef HAVE_MUSICBRAINZ
663 auto *metadata = getMusicBrainz().getMetadata(
m_setTrackNum);
666 metadata->setFilename(
getURL());
673 if (compilation_artist.toLower().left(7) ==
"various")
674 compilation_artist = tr(
"Various Artists");
676 if (artist.isEmpty())
678 artist = compilation_artist;
679 compilation_artist.clear();
683 title = tr(
"Track %1").arg(tracknum);
686 title, genre, year, tracknum, length);
688 m->setCompilation(isCompilation);
693#ifdef HAVE_MUSICBRAINZ
698 return s_musicBrainz;
713 static QString s_ext(
CDEXT);
720 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_)