#include "./mpegaudioframe.h" #include "../exceptions.h" #include using namespace std; using namespace IoUtilities; namespace TagParser { /*! * \brief Returns the string representation for the specified \a channelMode. */ const char *mpegChannelModeString(MpegChannelMode channelMode) { switch (channelMode) { case MpegChannelMode::Stereo: return "2 channels: stereo"; case MpegChannelMode::JointStereo: return "2 channels: joint stereo"; case MpegChannelMode::DualChannel: return "2 channels: dual channel"; case MpegChannelMode::SingleChannel: return "1 channel: single channel"; default: return nullptr; } } const uint64 MpegAudioFrame::m_xingHeaderOffset = 0x24; /*! * \class TagParser::MpegAudioFrame * \brief The MpegAudioFrame class is used to parse MPEG audio frames. */ const int MpegAudioFrame::m_bitrateTable[0x2][0x3][0xF] = { { { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448 }, { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384 }, { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 } }, { { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256 }, { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 }, { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 } } }; const uint32 MpegAudioFrame::m_sync = 0xFFE00000u; /*! * \brief Parses the header read using the specified \a reader. * \throws Throws InvalidDataException if the data read from the stream is * no valid frame header. */ void MpegAudioFrame::parseHeader(BinaryReader &reader, Diagnostics &diag) { m_header = reader.readUInt32BE(); if (!isValid()) { diag.emplace_back(DiagLevel::Critical, "Header is invalid.", "parsing MPEG audio frame header"); throw InvalidDataException(); } reader.stream()->seekg(m_xingHeaderOffset - 4, ios_base::cur); m_xingHeader = reader.readUInt64BE(); m_xingHeaderFlags = static_cast(m_xingHeader & 0xffffffffuL); if (isXingHeaderAvailable()) { if (isXingFramefieldPresent()) { m_xingFramefield = reader.readUInt32BE(); } if (isXingBytesfieldPresent()) { m_xingBytesfield = reader.readUInt32BE(); } if (isXingTocFieldPresent()) { reader.stream()->seekg(64, ios_base::cur); } if (isXingQualityIndicatorFieldPresent()) { m_xingQualityIndicator = reader.readUInt32BE(); } } } /*! * \brief Returns the MPEG version if known (1.0, 2.0 or 2.5); otherwise returns 0. */ double MpegAudioFrame::mpegVersion() const { switch (m_header & 0x180000u) { case 0x180000u: return 1.0; case 0x100000u: return 2.0; case 0x0u: return 2.5; default: return 0.0; } } /*! * \brief Returns the MPEG layer if known (1, 2, or 3); otherwise returns 0. */ int MpegAudioFrame::layer() const { switch (m_header & 0x60000u) { case 0x60000u: return 1; case 0x40000u: return 2; case 0x20000u: return 3; default: return 0; } } /*! * \brief Returns the sampeling frequency of the frame if known; otherwise returns 0. */ uint32 MpegAudioFrame::samplingFrequency() const { switch (m_header & 0xc00u) { case 0xc00u: return 0; case 0x800u: switch (m_header & 0x180000u) { case 0x180000u: return 32000; case 0x100000u: return 16000; case 0x0u: return 8000u; } break; case 0x400u: switch (m_header & 0x180000u) { case 0x180000u: return 48000; case 0x100000u: return 24000; case 0x0u: return 12000; } break; case 0x0u: switch (m_header & 0x180000u) { case 0x180000u: return 44100; case 0x100000: return 22050; case 0x0u: return 11025; } break; } return 0; } /*! * \brief Returns the channel mode if known; otherwise returns MpegChannelMode::Unspecifed. */ MpegChannelMode MpegAudioFrame::channelMode() const { if (isValid()) { switch (m_header & 0xc0u) { case 0xc0u: return MpegChannelMode::SingleChannel; case 0x80u: return MpegChannelMode::DualChannel; case 0x40u: return MpegChannelMode::JointStereo; case 0x00: return MpegChannelMode::Stereo; default:; } } return MpegChannelMode::Unspecifed; } /*! * \brief Returns the sample count if known; otherwise returns 0. */ uint32 MpegAudioFrame::sampleCount() const { switch (m_header & 0x60000u) { case 0x60000u: return 384u; case 0x40000u: return 1152u; case 0x20000u: switch (m_header & 0x180000u) { case 0x180000u: return 1152u; case 0x100000u: case 0x0u: return 576u; } default:; } return 0; } /*! * \brief Returns the size if known; otherwise retruns 0. */ uint32 MpegAudioFrame::size() const { switch (m_header & 0x60000u) { case 0x60000u: return static_cast( ((static_cast(bitrate()) * 1024.0 / 8.0) / static_cast(samplingFrequency())) * static_cast(sampleCount()) + static_cast(paddingSize())); case 0x40000u: case 0x20000u: return static_cast( ((static_cast(bitrate()) * 1024.0 / 8.0) / static_cast(samplingFrequency())) * static_cast(sampleCount()) + static_cast(paddingSize())); default: return 0; } } } // namespace TagParser