kwave  18.07.70
Kwave::MP3Decoder Class Reference

#include <MP3Decoder.h>

Inheritance diagram for Kwave::MP3Decoder:
Inheritance graph
Collaboration diagram for Kwave::MP3Decoder:
Collaboration graph

Public Member Functions

 MP3Decoder ()
 
virtual ~MP3Decoder ()
 
virtual Kwave::Decoderinstance ()
 
virtual bool open (QWidget *widget, QIODevice &source)
 
virtual bool decode (QWidget *widget, Kwave::MultiWriter &dst)
 
virtual void close ()
 
enum mad_flow fillInput (struct mad_stream *stream)
 
enum mad_flow processOutput (void *data, struct mad_header const *header, struct mad_pcm *pcm)
 
enum mad_flow handleError (void *data, struct mad_stream *stream, struct mad_frame *frame)
 
- Public Member Functions inherited from Kwave::Decoder
 Decoder ()
 
virtual ~Decoder ()
 
virtual Kwave::MetaDataListmetaData ()
 
- Public Member Functions inherited from Kwave::CodecBase
 CodecBase ()
 
virtual ~CodecBase ()
 
virtual bool supports (const QMimeType &mimetype)
 
virtual bool supports (const QString &mimetype_name)
 
virtual QStringList extensions (const QString &mimetype_name) const
 
virtual const QList< CodecBase::MimeTypemimeTypes ()
 
virtual const QList< Kwave::Compression::TypecompressionTypes ()
 
virtual void addMimeType (const char *name, const QString &description, const char *patterns)
 
virtual void addCompression (Kwave::Compression::Type compression)
 
virtual QString mimeTypeOf (const QUrl &url)
 

Private Member Functions

bool parseMp3Header (const Mp3_Headerinfo &header, QWidget *widget)
 
bool parseID3Tags (ID3_Tag &tag)
 
QString parseId3Frame2String (const ID3_Frame *frame)
 

Private Attributes

ID3_PropertyMap m_property_map
 
QIODevice * m_source
 
Kwave::MultiWriterm_dest
 
unsigned char * m_buffer
 
int m_buffer_size
 
size_t m_prepended_bytes
 
size_t m_appended_bytes
 
unsigned int m_failures
 
QWidget * m_parent_widget
 

Additional Inherited Members

- Signals inherited from Kwave::Decoder
void sourceProcessed (quint64 pos)
 
- Protected Attributes inherited from Kwave::Decoder
Kwave::MetaDataList m_meta_data
 

Detailed Description

Definition at line 40 of file MP3Decoder.h.

Constructor & Destructor Documentation

◆ MP3Decoder()

Kwave::MP3Decoder::MP3Decoder ( )

Constructor

Definition at line 48 of file MP3Decoder.cpp.

References REGISTER_COMPRESSION_TYPES, and REGISTER_MIME_TYPES.

Referenced by instance().

49  :Kwave::Decoder(),
51  m_source(Q_NULLPTR),
52  m_dest(Q_NULLPTR),
53  m_buffer(Q_NULLPTR),
54  m_buffer_size(0),
57  m_failures(0),
58  m_parent_widget(Q_NULLPTR)
59 {
62 }
ID3_PropertyMap m_property_map
Definition: MP3Decoder.h:106
size_t m_appended_bytes
Definition: MP3Decoder.h:124
unsigned char * m_buffer
Definition: MP3Decoder.h:115
#define REGISTER_MIME_TYPES
Kwave::MultiWriter * m_dest
Definition: MP3Decoder.h:112
unsigned int m_failures
Definition: MP3Decoder.h:127
QWidget * m_parent_widget
Definition: MP3Decoder.h:130
#define REGISTER_COMPRESSION_TYPES
QIODevice * m_source
Definition: MP3Decoder.h:109
size_t m_prepended_bytes
Definition: MP3Decoder.h:121
Here is the caller graph for this function:

◆ ~MP3Decoder()

Kwave::MP3Decoder::~MP3Decoder ( )
virtual

Destructor

Definition at line 65 of file MP3Decoder.cpp.

References close(), m_buffer, and m_source.

66 {
67  if (m_source) close();
68  if (m_buffer) free(m_buffer);
69 }
virtual void close()
Definition: MP3Decoder.cpp:733
unsigned char * m_buffer
Definition: MP3Decoder.h:115
QIODevice * m_source
Definition: MP3Decoder.h:109
Here is the call graph for this function:

Member Function Documentation

◆ close()

void Kwave::MP3Decoder::close ( )
virtual

Closes the source.

Implements Kwave::Decoder.

Definition at line 733 of file MP3Decoder.cpp.

References m_source.

Referenced by ~MP3Decoder().

734 {
735  m_source = Q_NULLPTR;
736 }
QIODevice * m_source
Definition: MP3Decoder.h:109
Here is the caller graph for this function:

◆ decode()

bool Kwave::MP3Decoder::decode ( QWidget *  widget,
Kwave::MultiWriter dst 
)
virtual

Decodes a stream of bytes into a MultiWriter

Parameters
widgeta widget that can be used for displaying message boxes or dialogs
dstMultiWriter that receives the audio data
Returns
true if succeeded, false on errors

Implements Kwave::Decoder.

Definition at line 702 of file MP3Decoder.cpp.

References _error_adapter(), _input_adapter(), _output_adapter(), m_dest, m_failures, m_parent_widget, m_prepended_bytes, and m_source.

703 {
704  Q_ASSERT(m_source);
705  if (!m_source) return false;
706  m_source->seek(m_prepended_bytes); // skip id3v2 tag
707 
708  // set target of the decoding
709  m_dest = &dst;
710  m_failures = 0;
711  m_parent_widget = widget;
712 
713  // setup the decoder
714  struct mad_decoder decoder;
715  mad_decoder_init(&decoder, this,
717  Q_NULLPTR /* header */,
718  Q_NULLPTR /* filter */,
721  Q_NULLPTR /* message */);
722 
723  // decode through libmad...
724  int result = mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
725 
726  // release the decoder
727  mad_decoder_finish(&decoder);
728 
729  return (result == 0);
730 }
static enum mad_flow _error_adapter(void *data, struct mad_stream *stream, struct mad_frame *frame)
Definition: MP3Decoder.cpp:493
static enum mad_flow _output_adapter(void *data, struct mad_header const *header, struct mad_pcm *pcm)
Definition: MP3Decoder.cpp:482
Kwave::MultiWriter * m_dest
Definition: MP3Decoder.h:112
unsigned int m_failures
Definition: MP3Decoder.h:127
QWidget * m_parent_widget
Definition: MP3Decoder.h:130
static enum mad_flow _input_adapter(void *data, struct mad_stream *stream)
Definition: MP3Decoder.cpp:474
QIODevice * m_source
Definition: MP3Decoder.h:109
size_t m_prepended_bytes
Definition: MP3Decoder.h:121
Here is the call graph for this function:

◆ fillInput()

enum mad_flow Kwave::MP3Decoder::fillInput ( struct mad_stream *  stream)

Callback for filling libmad's input buffer

Definition at line 566 of file MP3Decoder.cpp.

References Kwave::MultiWriter::isCanceled(), m_appended_bytes, m_buffer, m_buffer_size, m_dest, m_source, and Kwave::toUint().

Referenced by _input_adapter().

567 {
568  Q_ASSERT(m_source);
569  if (!m_source) return MAD_FLOW_STOP;
570 
571  // check if the user pressed cancel
572  if (m_dest->isCanceled()) return MAD_FLOW_STOP;
573 
574  // preserve the remaining bytes from the last pass
575  size_t rest = stream->bufend - stream->next_frame;
576  if (rest) memmove(m_buffer, stream->next_frame, rest);
577 
578  // clip source at "eof-appended_bytes"
579  size_t bytes_to_read = m_buffer_size - rest;
580  if (m_source->pos() + bytes_to_read > m_source->size() - m_appended_bytes)
581  bytes_to_read = Kwave::toUint(
582  m_source->size() - m_appended_bytes - m_source->pos());
583 
584  // abort if nothing more to read, even if there are
585  // some "left-overs" from the previous pass
586  if (!bytes_to_read) return MAD_FLOW_STOP;
587 
588  // read from source to fill up the buffer
589  size_t size = rest;
590  if (bytes_to_read) size += m_source->read(
591  reinterpret_cast<char *>(m_buffer) + rest, bytes_to_read);
592  if (!size) return MAD_FLOW_STOP; // no more data
593 
594  // buffer is filled -> process it
595  mad_stream_buffer(stream, m_buffer, size);
596 
597  return MAD_FLOW_CONTINUE;
598 }
size_t m_appended_bytes
Definition: MP3Decoder.h:124
unsigned char * m_buffer
Definition: MP3Decoder.h:115
bool isCanceled() const
Definition: MultiWriter.h:64
Kwave::MultiWriter * m_dest
Definition: MP3Decoder.h:112
QIODevice * m_source
Definition: MP3Decoder.h:109
unsigned int toUint(T x)
Definition: Utils.h:109
Here is the call graph for this function:
Here is the caller graph for this function:

◆ handleError()

enum mad_flow Kwave::MP3Decoder::handleError ( void *  data,
struct mad_stream *  stream,
struct mad_frame *  frame 
)

Callback for handling stream errors

Definition at line 503 of file MP3Decoder.cpp.

References _, m_buffer, m_failures, m_parent_widget, Kwave::MessageBox::warningContinueCancel(), and Kwave::MessageBox::warningYesNo().

Referenced by _error_adapter().

505 {
506  if (m_failures >= 2) return MAD_FLOW_CONTINUE; // ignore errors
507  if (stream->error == MAD_ERROR_NONE) return MAD_FLOW_CONTINUE; // ???
508 
509  QString error;
510  switch (stream->error) {
511  case MAD_ERROR_BUFLEN:
512  case MAD_ERROR_BUFPTR:
513  case MAD_ERROR_NOMEM:
514  error = i18n("Out of memory");
515  break;
516  case MAD_ERROR_BADCRC:
517  error = i18n("Checksum error");
518  break;
519  case MAD_ERROR_LOSTSYNC:
520  error = i18n("Synchronization lost");
521  break;
522  case MAD_ERROR_BADLAYER:
523  case MAD_ERROR_BADBITRATE:
524  case MAD_ERROR_BADSAMPLERATE:
525  case MAD_ERROR_BADEMPHASIS:
526  case MAD_ERROR_BADBITALLOC:
527  case MAD_ERROR_BADSCALEFACTOR:
528  case MAD_ERROR_BADFRAMELEN:
529  case MAD_ERROR_BADBIGVALUES:
530  case MAD_ERROR_BADBLOCKTYPE:
531  case MAD_ERROR_BADSCFSI:
532  case MAD_ERROR_BADDATAPTR:
533  case MAD_ERROR_BADPART3LEN:
534  case MAD_ERROR_BADHUFFTABLE:
535  case MAD_ERROR_BADHUFFDATA:
536  case MAD_ERROR_BADSTEREO:
537  error = i18n("File contains invalid data");
538  break;
539  default:
540  QString err_hex = QString::number(
541  static_cast<int>(stream->error), 16).toUpper();
542  error = i18n("Unknown error 0x%1. Damaged file?", err_hex);
543  }
544 
545  long unsigned int pos = stream->this_frame - m_buffer;
546  int result = 0;
547  error = i18n("An error occurred while decoding the file:\n'%1',\n"
548  "at position %2.", error, pos);
549  if (!m_failures) {
550  m_failures = 1;
552  error + _("\n") + i18n("Do you still want to continue?"));
553  if (result != KMessageBox::Continue) return MAD_FLOW_BREAK;
554  } else if (m_failures == 1) {
556  error + _("\n") +
557  i18n("Do you want to continue and ignore all following errors?"));
558  m_failures++;
559  if (result != KMessageBox::Yes) return MAD_FLOW_BREAK;
560  }
561 
562  return MAD_FLOW_CONTINUE;
563 }
unsigned char * m_buffer
Definition: MP3Decoder.h:115
static int warningYesNo(QWidget *widget, QString message, QString caption=QString(), const QString buttonYes=QString(), const QString buttonNo=QString(), const QString &dontAskAgainName=QString())
Definition: MessageBox.cpp:93
static int warningContinueCancel(QWidget *widget, QString message, QString caption=QString(), const QString buttonContinue=QString(), const QString buttonCancel=QString(), const QString &dontAskAgainName=QString())
Definition: MessageBox.cpp:115
unsigned int m_failures
Definition: MP3Decoder.h:127
QWidget * m_parent_widget
Definition: MP3Decoder.h:130
#define _(m)
Definition: memcpy.c:66
Here is the call graph for this function:
Here is the caller graph for this function:

◆ instance()

Kwave::Decoder * Kwave::MP3Decoder::instance ( )
virtual

Returns a new instance of the decoder

Implements Kwave::Decoder.

Definition at line 72 of file MP3Decoder.cpp.

References MP3Decoder().

73 {
74  return new MP3Decoder();
75 }
Here is the call graph for this function:

◆ open()

bool Kwave::MP3Decoder::open ( QWidget *  widget,
QIODevice &  source 
)
virtual

Opens the source and decodes the header information.

Parameters
widgeta widget that can be used for displaying message boxes or dialogs
sourcefile or other source with a stream of bytes
Returns
true if succeeded, false on errors
Bug:
: id3lib crashes in this line on some MP3 files

Implements Kwave::Decoder.

Definition at line 411 of file MP3Decoder.cpp.

References _, Kwave::INF_MIMETYPE, m_appended_bytes, m_buffer, m_buffer_size, m_prepended_bytes, m_source, Kwave::Decoder::metaData(), parseID3Tags(), parseMp3Header(), Kwave::MetaDataList::replace(), Kwave::FileInfo::set(), Kwave::MessageBox::sorry(), and Kwave::toUint().

412 {
413  qDebug("MP3Decoder::open()");
414  metaData().clear();
415  Q_ASSERT(!m_source);
416  if (m_source) qWarning("MP3Decoder::open(), already open !");
417 
418  /* open the file in readonly mode with seek enabled */
419  if (src.isSequential()) return false;
420  if (!src.open(QIODevice::ReadOnly)) {
421  qWarning("unable to open source in read-only mode!");
422  return false;
423  }
424 
425  /* read all available ID3 tags */
426  ID3_Tag tag;
427  ID3_QIODeviceReader adapter(src);
428  tag.Link(adapter, static_cast<flags_t>(ID3TT_ALL));
429 
430  qDebug("NumFrames = %u", Kwave::toUint(tag.NumFrames()));
432  if (tag.GetSpec() != ID3V2_UNKNOWN) {
433  qDebug("Size = %u", Kwave::toUint(tag.Size()));
434  }
435  qDebug("HasLyrics = %d", tag.HasLyrics());
436  qDebug("HasV1Tag = %d", tag.HasV1Tag());
437  qDebug("HasV2Tag = %d", tag.HasV2Tag());
438 
439  m_prepended_bytes = tag.GetPrependedBytes();
440  m_appended_bytes = tag.GetAppendedBytes();
441  qDebug("prepended=%lu, appended=%lu", m_prepended_bytes, m_appended_bytes);
442 
443  const Mp3_Headerinfo *mp3hdr = tag.GetMp3HeaderInfo();
444  if (!mp3hdr) {
446  i18n("The opened file is no MPEG file or it is damaged.\n"
447  "No header information has been found."));
448  return false;
449  }
450 
451  /* parse the MP3 header */
452  if (!parseMp3Header(*mp3hdr, widget)) return false;
453 
454  /* parse the ID3 tags */
455  if (!parseID3Tags(tag)) return false;
456 
457  /* accept the source */
458  m_source = &src;
459  Kwave::FileInfo info(metaData());
460  info.set(Kwave::INF_MIMETYPE, _("audio/mpeg"));
462 
463  // allocate a transfer buffer with 128 kB
464  if (m_buffer) free(m_buffer);
465  m_buffer_size = (128 << 10);
466 
467  m_buffer = static_cast<unsigned char *>(malloc(m_buffer_size));
468  if (!m_buffer) return false; // out of memory :-(
469 
470  return true;
471 }
size_t m_appended_bytes
Definition: MP3Decoder.h:124
static int sorry(QWidget *widget, QString message, QString caption=QString())
Definition: MessageBox.cpp:85
unsigned char * m_buffer
Definition: MP3Decoder.h:115
virtual void replace(const MetaDataList &list)
virtual Kwave::MetaDataList & metaData()
Definition: Decoder.h:78
bool parseID3Tags(ID3_Tag &tag)
Definition: MP3Decoder.cpp:211
#define _(m)
Definition: memcpy.c:66
QIODevice * m_source
Definition: MP3Decoder.h:109
bool parseMp3Header(const Mp3_Headerinfo &header, QWidget *widget)
Definition: MP3Decoder.cpp:78
unsigned int toUint(T x)
Definition: Utils.h:109
size_t m_prepended_bytes
Definition: MP3Decoder.h:121
Here is the call graph for this function:

◆ parseId3Frame2String()

QString Kwave::MP3Decoder::parseId3Frame2String ( const ID3_Frame *  frame)
private

parse a ID3 frame into a string

Parameters
framea ID3 frame
Returns
QString with the content

Definition at line 399 of file MP3Decoder.cpp.

References _.

Referenced by parseID3Tags().

400 {
401  QString s;
402  char *text = ID3_GetString(frame, ID3FN_TEXT);
403  if (text && strlen(text)) {
404  s = _(text);
405  ID3_FreeString(text);
406  }
407  return s;
408 }
#define _(m)
Definition: memcpy.c:66
Here is the caller graph for this function:

◆ parseID3Tags()

bool Kwave::MP3Decoder::parseID3Tags ( ID3_Tag &  tag)
private

parse all known ID3 tags

Definition at line 211 of file MP3Decoder.cpp.

References _, Kwave::FileInfo::contains(), DBG, Kwave::ID3_PropertyMap::ENC_COMMENT, Kwave::ID3_PropertyMap::ENC_GENRE_TYPE, Kwave::ID3_PropertyMap::ENC_LENGTH, Kwave::ID3_PropertyMap::ENC_NONE, Kwave::ID3_PropertyMap::ENC_TERMS_OF_USE, Kwave::ID3_PropertyMap::ENC_TEXT, Kwave::ID3_PropertyMap::ENC_TEXT_PARTINSET, Kwave::ID3_PropertyMap::ENC_TEXT_SLASH, Kwave::ID3_PropertyMap::ENC_TEXT_TIMESTAMP, Kwave::ID3_PropertyMap::ENC_TEXT_URL, Kwave::ID3_PropertyMap::ENC_TRACK_NUM, Kwave::ID3_PropertyMap::encoding(), Kwave::GenreType::fromID3(), Kwave::FileInfo::get(), Kwave::INF_CD, Kwave::INF_CDS, Kwave::INF_CREATION_DATE, Kwave::INF_TRACK, Kwave::INF_TRACKS, m_property_map, Kwave::Decoder::metaData(), Kwave::GenreType::name(), parseId3Frame2String(), Kwave::ID3_PropertyMap::property(), Kwave::FileInfo::rate(), Kwave::MetaDataList::replace(), Kwave::FileInfo::set(), Kwave::FileInfo::setLength(), and Kwave::string2date().

Referenced by open().

212 {
213  if (tag.NumFrames() < 1) return true; // no tags, nothing to do
214 
215  QDate creation_date;
216  QTime creation_time;
217  int year = -1;
218  int month = -1;
219  int day = -1;
220 
221  ID3_Tag::Iterator *it = tag.CreateIterator();
222  ID3_Frame *frame = Q_NULLPTR;
223  Kwave::FileInfo info(metaData());
224  while (it && (frame = it->GetNext())) {
225  const ID3_FrameID id = frame->GetID();
226  const Kwave::FileProperty property = m_property_map.property(id);
228  switch (encoding) {
230  {
231  QString s = parseId3Frame2String(frame);
232  int cd = 0;
233  int cds = 0;
234  if (s.contains(QLatin1Char('/'))) {
235  int i = s.indexOf(QLatin1Char('/'));
236  cd = s.left(i).toInt();
237  cds = s.mid(i + 1).toInt();
238  } else {
239  cd = s.toInt();
240  }
241  if (cd > 0) info.set(Kwave::INF_CD , QVariant(cd));
242  if (cds > 0) info.set(Kwave::INF_CDS, QVariant(cds));
243  break;
244  }
246  {
247  QString s = parseId3Frame2String(frame);
248  int track = 0;
249  int tracks = 0;
250  if (s.contains(QLatin1Char('/'))) {
251  int i = s.indexOf(QLatin1Char('/'));
252  track = s.left(i).toInt();
253  tracks = s.mid(i + 1).toInt();
254  } else {
255  track = s.toInt();
256  }
257  if (track > 0) info.set(Kwave::INF_TRACK , QVariant(track));
258  if (tracks > 0) info.set(Kwave::INF_TRACKS, QVariant(tracks));
259  break;
260  }
262  // the same as ENC_COMMENT, but without "Description"
263  /* FALLTHROUGH */
265  {
266  QString s = parseId3Frame2String(frame);
267 
268  // optionally prepend language
269  char *lang = ID3_GetString(frame, ID3FN_LANGUAGE);
270  if (lang) {
271  s = _("[") + _(lang) + _("] ") + s;
272  ID3_FreeString(lang);
273  }
274 
275  // append to already existing tag, separated by a slash
276  if (info.contains(property))
277  s = info.get(property).toString() + _(" / ") + s;
278  info.set(property, QVariant(s));
279  break;
280  }
282  {
283  QString s = parseId3Frame2String(frame);
284  int genre = Kwave::GenreType::fromID3(s);
285  if (genre >= 0)
286  s = Kwave::GenreType::name(genre, false);
287  info.set(property, QVariant(s));
288  break;
289  }
291  {
292  // length in ms -> convert this to samples
293  QString s = parseId3Frame2String(frame);
294  const double rate = info.rate();
295  bool ok = false;
296  const double ms = s.toDouble(&ok) + 0.5;
297  if (ok && (rate > 0)) {
298  // NOTE: this overwrites the length found in the header!
299  sample_index_t length = static_cast<sample_index_t>(
300  (rate * ms) / 1000.0);
301  info.setLength(length);
302  }
303  break;
304  }
306  {
307  if (!creation_date.isValid()) {
308  QString s = parseId3Frame2String(frame);
309  switch (id)
310  {
311  case ID3FID_RECORDINGDATES:
312  // should be a ISO 8601 timestamp or similar
313  s = Kwave::string2date(s);
314  if (s.length())
315  creation_date =
316  QDate::fromString(s, Qt::ISODate);
317  break;
318  case ID3FID_DATE: {
319  // DDMM
320  unsigned int ddmm = s.toUInt();
321  day = ddmm / 100;
322  month = ddmm % 100;
323  break;
324  }
325  case ID3FID_YEAR: /* FALLTHROUGH */
326  case ID3FID_ORIGYEAR:
327  // YYYY
328  year = s.toUInt();
329  break;
330  default:
331  break;
332  }
333  }
334 
335  if (creation_time.isValid()) {
336  switch (id)
337  {
338  case ID3FID_TIME:
339  creation_time = QTime::fromString(_("hhmm"));
340  break;
341  default:
342  break;
343  }
344  }
345  break;
346  }
348  {
349  // append to already existing tag, separated by a slash
350  QString s = parseId3Frame2String(frame);
351  if (info.contains(property))
352  s = info.get(property).toString() + _(" / ") + s;
353  info.set(property, QVariant(s));
354  break;
355  }
356  case ID3_PropertyMap::ENC_TEXT_URL: /* FALLTHROUGH */
358  info.set(property, QVariant(parseId3Frame2String(frame)));
359  break;
360  case ID3_PropertyMap::ENC_NONE: /* FALLTHROUGH */
361  default:
362  {
363  QString s = parseId3Frame2String(frame);
364  qWarning("unsupported ID3 tag: %d, descr: '%s', text: '%s'",
365  id, frame->GetDescription(), DBG(s));
366  break;
367  }
368  }
369  }
370 
371  /*
372  * try to build a valid creation date/time
373  */
374  if (!creation_date.isValid()) {
375  // no complete creation date - try to reassemble from found y/m/d
376  creation_date = QDate(year, month, day);
377  }
378  if (creation_date.isValid() && creation_time.isValid()) {
379  // full date + time
380  QDateTime dt(creation_date, creation_time);
381  info.set(Kwave::INF_CREATION_DATE, dt.toString(
382  _("yyyy-MM-ddTHH:mm:ss")));
383  } else if (creation_date.isValid()) {
384  // date without time
385  info.set(Kwave::INF_CREATION_DATE, creation_date.toString(
386  _("yyyy-MM-dd")));
387  } else if (year > 0) {
388  // only year
389  creation_date = QDate(year, 1, 1);
390  info.set(Kwave::INF_CREATION_DATE, creation_date.toString(_("yyyy")));
391  }
392 
394 
395  return true;
396 }
ID3_PropertyMap m_property_map
Definition: MP3Decoder.h:106
QString parseId3Frame2String(const ID3_Frame *frame)
Definition: MP3Decoder.cpp:399
static QString name(int id, bool localized)
Definition: GenreType.cpp:34
quint64 sample_index_t
Definition: Sample.h:28
QString Q_DECL_EXPORT string2date(const QString &s)
Definition: Utils.cpp:126
virtual void replace(const MetaDataList &list)
virtual Kwave::MetaDataList & metaData()
Definition: Decoder.h:78
Encoding encoding(const ID3_FrameID id) const
#define _(m)
Definition: memcpy.c:66
#define DBG(qs)
Definition: String.h:55
Kwave::FileProperty property(const ID3_FrameID id) const
static int fromID3(const QString &tag)
Definition: GenreType.cpp:45
FileProperty
Definition: FileInfo.h:45
Here is the call graph for this function:
Here is the caller graph for this function:

◆ parseMp3Header()

bool Kwave::MP3Decoder::parseMp3Header ( const Mp3_Headerinfo &  header,
QWidget *  widget 
)
private

parse MP3 headers

Definition at line 78 of file MP3Decoder.cpp.

References _, Kwave::INF_BITRATE_NOMINAL, Kwave::INF_COMPRESSION, Kwave::INF_COPYRIGHTED, Kwave::INF_MPEG_EMPHASIS, Kwave::INF_MPEG_LAYER, Kwave::INF_MPEG_MODEEXT, Kwave::INF_MPEG_VERSION, Kwave::INF_ORIGINAL, Kwave::INF_PRIVATE, Kwave::Decoder::metaData(), Kwave::Compression::MPEG_LAYER_I, Kwave::Compression::MPEG_LAYER_II, Kwave::Compression::MPEG_LAYER_III, Kwave::MetaDataList::replace(), SAMPLE_BITS, Kwave::FileInfo::set(), Kwave::FileInfo::setBits(), Kwave::FileInfo::setLength(), Kwave::FileInfo::setRate(), Kwave::FileInfo::setTracks(), and Kwave::MessageBox::warningContinueCancel().

Referenced by open().

80 {
81  Kwave::FileInfo info(metaData());
82 
83  /* first of all check CRC, it might be senseless if the file is broken */
84  qDebug("crc = 0x%08X", header.crc);
85  if ((header.crc == MP3CRC_MISMATCH) || (header.crc == MP3CRC_ERROR_SIZE)) {
86 
87  if (header.layer == MPEGLAYER_II) {
88  qWarning("WARNING: file is MPEG layer II, CRC calculation "
89  "in id3lib is probably wrong - CRC check skipped");
90  } else {
92  i18n("The file has an invalid checksum.\n"
93  "Do you still want to continue?"),
94  QString(), QString(), QString(),
95  _("accept_mp3_invalid_checksum"))
96  != KMessageBox::Continue) return false;
97  }
98  }
99 
100  /* MPEG layer */
101  switch (header.layer) {
102  case MPEGLAYER_I:
103  info.set(Kwave::INF_COMPRESSION,
105  info.set(Kwave::INF_MPEG_LAYER, QVariant(1));
106  break;
107  case MPEGLAYER_II:
108  info.set(Kwave::INF_COMPRESSION,
110  info.set(Kwave::INF_MPEG_LAYER, QVariant(2));
111  break;
112  case MPEGLAYER_III:
113  info.set(Kwave::INF_COMPRESSION,
115  info.set(Kwave::INF_MPEG_LAYER, QVariant(3));
116  break;
117  default:
118  qWarning("unknown mpeg layer '%d'", header.layer);
119  }
120 
121  /* MPEG version */
122  switch (header.version) {
123  case MPEGVERSION_1:
124  info.set(Kwave::INF_MPEG_VERSION, QVariant(1));
125  break;
126  case MPEGVERSION_2:
127  info.set(Kwave::INF_MPEG_VERSION, QVariant(2));
128  break;
129  case MPEGVERSION_2_5:
130  info.set(Kwave::INF_MPEG_VERSION, QVariant(2.5));
131  break;
132  default:
133  qWarning("unknown mpeg version '%d'", header.version);
134  }
135 
136  /* bit rate */
137  if (header.bitrate > 0) info.set(Kwave::INF_BITRATE_NOMINAL,
138  QVariant(header.bitrate));
139  // NOTE: this is an enum value in libid3, but can also be treated
140  // as unsigned integer without problems!
141 
142  /* channel mode */
143  unsigned int tracks = 0;
144  switch (header.channelmode) {
145  case MP3CHANNELMODE_SINGLE_CHANNEL:
146  tracks = 1;
147  break;
148  case MP3CHANNELMODE_STEREO:
149  tracks = 2;
150  break;
151  case MP3CHANNELMODE_JOINT_STEREO:
152  tracks = 2;
153  break;
154  case MP3CHANNELMODE_DUAL_CHANNEL:
155  tracks = 2;
156  break;
157  default:
158  QString mode;
159  mode = mode.setNum(header.channelmode, 16);
161  i18n("The file contains an invalid channel mode 0x"
162  "%1\nAssuming Mono...", mode))
163  != KMessageBox::Continue) return false;
164  }
165  info.setTracks(tracks);
166 
167  /* MPEG Mode Extension */
168  // only in "Joint Stereo" mode, then depends on Layer
169  //
170  // Layer I+II | Layer III
171  // | Intensity stereo MS Stereo
172  //--------------------------------------------------
173  // 0 - bands 4 to 31 | off off -> 4
174  // 1 - bands 8 to 31 | on off -> 5
175  // 2 - bands 12 to 31 | off on -> 6
176  // 3 - bands 16 to 31 | on on -> 7
177  if (header.channelmode == MP3CHANNELMODE_JOINT_STEREO) {
178  int modeext = header.modeext;
179  if (header.layer >= 3) modeext += 4;
180  info.set(Kwave::INF_MPEG_MODEEXT, modeext);
181  } else {
182  int modeext = header.modeext;
183  info.set(Kwave::INF_MPEG_MODEEXT, modeext);
184  }
185 
186  /* Emphasis mode */
187  // 0 = none
188  // 1 = 50/15ms
189  // 2 = reserved
190  // 3 = CCIT J.17
191  if (header.emphasis > 0)
192  info.set(Kwave::INF_MPEG_EMPHASIS, header.emphasis);
193 
194 // qDebug("framesize=%d", header.framesize);
195 // qDebug("frames = %u", header.frames);
196 
197  if (header.privatebit) info.set(Kwave::INF_PRIVATE, header.privatebit);
198  if (header.copyrighted) info.set(Kwave::INF_COPYRIGHTED, header.copyrighted);
199  if (header.original) info.set(Kwave::INF_ORIGINAL, header.original);
200 
201  info.setRate(header.frequency); // sample rate
202  info.setBits(SAMPLE_BITS); // fake Kwave's default resolution
203  info.setLength(header.time * header.frequency);
204 
206 
207  return true;
208 }
virtual void replace(const MetaDataList &list)
virtual Kwave::MetaDataList & metaData()
Definition: Decoder.h:78
static int warningContinueCancel(QWidget *widget, QString message, QString caption=QString(), const QString buttonContinue=QString(), const QString buttonCancel=QString(), const QString &dontAskAgainName=QString())
Definition: MessageBox.cpp:115
#define _(m)
Definition: memcpy.c:66
#define SAMPLE_BITS
Definition: Sample.h:43
Here is the call graph for this function:
Here is the caller graph for this function:

◆ processOutput()

enum mad_flow Kwave::MP3Decoder::processOutput ( void *  data,
struct mad_header const *  header,
struct mad_pcm *  pcm 
)

Calback for processing libmad's output

Definition at line 675 of file MP3Decoder.cpp.

References audio_linear_dither(), m_dest, SAMPLE_BITS, and Kwave::MultiTrackSink< SINK, INITIALIZE >::tracks().

Referenced by _output_adapter().

677 {
678  static Kwave::audio_dither dither;
679  qint32 sample;
680  Kwave::SampleArray buffer(pcm->length);
681 
682  // loop over all tracks
683  const unsigned int tracks = m_dest->tracks();
684  for (unsigned int track = 0; track < tracks; ++track) {
685  unsigned int nsamples = pcm->length;
686  mad_fixed_t const *p = pcm->samples[track];
687  unsigned int ofs = 0;
688 
689  // and render samples into Kwave's internal format
690  while (nsamples--) {
691  sample = static_cast<qint32>(audio_linear_dither(SAMPLE_BITS,
692  static_cast<mad_fixed_t>(*p++), &dither));
693  buffer[ofs++] = static_cast<sample_t>(sample);
694  }
695  *(*m_dest)[track] << buffer;
696  }
697 
698  return MAD_FLOW_CONTINUE;
699 }
virtual unsigned int tracks() const Q_DECL_OVERRIDE
static qint32 audio_linear_dither(unsigned int bits, mad_fixed_t sample, Kwave::audio_dither *dither)
Definition: MP3Decoder.cpp:626
Kwave::MultiWriter * m_dest
Definition: MP3Decoder.h:112
#define SAMPLE_BITS
Definition: Sample.h:43
qint32 sample_t
Definition: Sample.h:37
Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ m_appended_bytes

size_t Kwave::MP3Decoder::m_appended_bytes
private

number of appended bytes / id3v1 tag

Definition at line 124 of file MP3Decoder.h.

Referenced by fillInput(), and open().

◆ m_buffer

unsigned char* Kwave::MP3Decoder::m_buffer
private

buffer for libmad

Definition at line 115 of file MP3Decoder.h.

Referenced by fillInput(), handleError(), open(), and ~MP3Decoder().

◆ m_buffer_size

int Kwave::MP3Decoder::m_buffer_size
private

size of m_buffer in bytes

Definition at line 118 of file MP3Decoder.h.

Referenced by fillInput(), and open().

◆ m_dest

Kwave::MultiWriter* Kwave::MP3Decoder::m_dest
private

destination of the audio data

Definition at line 112 of file MP3Decoder.h.

Referenced by decode(), fillInput(), and processOutput().

◆ m_failures

unsigned int Kwave::MP3Decoder::m_failures
private

number of failures

Definition at line 127 of file MP3Decoder.h.

Referenced by decode(), and handleError().

◆ m_parent_widget

QWidget* Kwave::MP3Decoder::m_parent_widget
private

widget used for displaying error messages

Definition at line 130 of file MP3Decoder.h.

Referenced by decode(), and handleError().

◆ m_prepended_bytes

size_t Kwave::MP3Decoder::m_prepended_bytes
private

number of prepended bytes / id3v2 tag

Definition at line 121 of file MP3Decoder.h.

Referenced by decode(), and open().

◆ m_property_map

ID3_PropertyMap Kwave::MP3Decoder::m_property_map
private

property - to - ID3 mapping

Definition at line 106 of file MP3Decoder.h.

Referenced by parseID3Tags().

◆ m_source

QIODevice* Kwave::MP3Decoder::m_source
private

source of the raw mp3 data

Definition at line 109 of file MP3Decoder.h.

Referenced by close(), decode(), fillInput(), open(), and ~MP3Decoder().


The documentation for this class was generated from the following files: