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