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