#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 Media::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) { m_header = reader.readUInt32BE(); if(!isValid()) { 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; } } }