added channel config to AbstractTrack and the implementations

This commit is contained in:
Martchus 2015-07-31 01:09:41 +02:00
parent b2d64fc681
commit 9f12607a0d
10 changed files with 106 additions and 26 deletions

View File

@ -1,3 +1,6 @@
#include "mp4/mp4ids.h"
#include "mpegaudio/mpegaudioframe.h"
#include "abstracttrack.h"
#include "exceptions.h"
#include "mediaformat.h"
@ -45,6 +48,7 @@ AbstractTrack::AbstractTrack(istream &inputStream, ostream &outputStream, uint64
m_bitsPerSample(0),
m_bytesPerSecond(0),
m_channelCount(0),
m_channelConfig(0),
m_sampleCount(0),
m_quality(0),
m_depth(0),
@ -99,6 +103,21 @@ const char *AbstractTrack::mediaTypeName() const
}
}
/*!
* \brief Returns a string with the channel configuration if available; otherwise returns nullptr.
*/
const char *AbstractTrack::channelConfigString() const
{
switch(m_format.general) {
case GeneralMediaFormat::Aac:
return Mpeg4ChannelConfigs::channelConfigString(m_channelConfig);
case GeneralMediaFormat::Mpeg1Audio: case GeneralMediaFormat::Mpeg2Audio:
return mpegChannelModeString(static_cast<MpegChannelMode>(m_channelConfig));
default:
return nullptr;
}
}
/*!
* \brief Returns a label for the track.
*/

View File

@ -69,10 +69,12 @@ public:
const ChronoUtilities::DateTime &creationTime() const;
const ChronoUtilities::DateTime &modificationTime() const;
const std::string &language() const;
uint32 sampleRate() const;
uint32 extensionSampleRate() const;
uint32 samplingFrequency() const;
uint32 extensionSamplingFrequency() const;
uint16 bitsPerSample() const;
uint16 channelCount() const;
byte channelConfig() const;
const char *channelConfigString() const;
uint64 sampleCount() const;
int quality() const;
const Size &pixelSize() const;
@ -126,6 +128,7 @@ protected:
uint16 m_bitsPerSample;
uint32 m_bytesPerSecond;
uint16 m_channelCount;
byte m_channelConfig;
uint16 m_chunkSize;
uint64 m_sampleCount;
int m_quality;
@ -366,7 +369,7 @@ inline const std::string &AbstractTrack::language() const
/*!
* \brief Returns the number of samples per second if known; otherwise returns 0.
*/
inline uint32 AbstractTrack::sampleRate() const
inline uint32 AbstractTrack::samplingFrequency() const
{
return m_sampleRate;
}
@ -375,7 +378,7 @@ inline uint32 AbstractTrack::sampleRate() const
* \brief Returns the number of samples per second if known; otherwise returns 0.
* \remarks This sample rate value takes extensions like SBR into account.
*/
inline uint32 AbstractTrack::extensionSampleRate() const
inline uint32 AbstractTrack::extensionSamplingFrequency() const
{
return m_extensionSampleRate;
}
@ -398,6 +401,17 @@ inline uint16 AbstractTrack::channelCount() const
return m_channelCount;
}
/*!
* \brief Returns the channel configuration.
*
* This is the MPEG-4 channel config for MPEG-4 audio.
* \sa Mpeg4ChannelConfigs::channelConfigString()
*/
inline byte AbstractTrack::channelConfig() const
{
return m_channelConfig;
}
/*!
* \brief Returns the number of samples if known; otherwise returns 0.
*/

View File

@ -21,10 +21,15 @@ namespace Media {
void AdtsFrame::parseHeader(IoUtilities::BinaryReader &reader)
{
m_header1 = reader.readUInt16BE();
if(!isValid()) {
// check whether syncword is present
if((m_header1 & 0xFFF6u) != 0xFFF0u) {
throw InvalidDataException();
}
m_header2 = hasCrc() ? reader.readUInt56BE() : (reader.readUInt40BE() << 2);
// check whether frame length is ok
if(totalSize() < headerSize()) {
throw InvalidDataException();
}
}
} // namespace Media

View File

@ -21,9 +21,11 @@ public:
bool isMpeg4() const;
bool hasCrc() const;
byte mpeg4AudioObjectId() const;
byte mpeg4SampleRateIndex() const;
byte mpeg4SamplingFrequencyIndex() const;
byte mpeg4ChannelConfig() const;
uint16 length() const;
uint16 totalSize() const;
byte headerSize() const;
uint16 dataSize() const;
uint16 bufferFullness() const;
byte frameCount() const;
uint16 crc() const;
@ -45,7 +47,7 @@ inline AdtsFrame::AdtsFrame() :
*/
inline bool AdtsFrame::isValid() const
{
return (m_header1 & 0xFFF6u) == 0xFFF0u;
return ((m_header1 & 0xFFF6u) == 0xFFF0u) && (totalSize() >= headerSize());
}
/*!
@ -57,11 +59,11 @@ inline bool AdtsFrame::isMpeg4() const
}
/*!
* \brief Returns whether a CRC-16 checksum is present.
* \brief Returns whether a CRC-16 checksum is present ("protection absent" bit is NOT set).
*/
inline bool AdtsFrame::hasCrc() const
{
return m_header1 & 0x1u;
return (m_header1 & 0x1u) == 0;
}
/*!
@ -78,7 +80,7 @@ inline byte AdtsFrame::mpeg4AudioObjectId() const
* \brief Returns the MPEG-4 sample rate index.
* \sa Media::mpeg4SampleRateTable
*/
inline byte AdtsFrame::mpeg4SampleRateIndex() const
inline byte AdtsFrame::mpeg4SamplingFrequencyIndex() const
{
return (m_header2 >> 0x32) & 0xFu;
}
@ -94,13 +96,29 @@ inline byte AdtsFrame::mpeg4ChannelConfig() const
}
/*!
* \brief Returns the length of the frame (including the header) in bytes.
* \brief Returns the size of the frame (including the header) in bytes.
*/
inline uint16 AdtsFrame::length() const
inline uint16 AdtsFrame::totalSize() const
{
return (m_header2 >> 0x1D) & 0x1FFFu;
}
/*!
* \brief Retruns the header size in bytes (9 if CRC is present; otherwise 7).
*/
inline byte AdtsFrame::headerSize() const
{
return hasCrc() ? 9 : 7;
}
/*!
* \brief Returns the data size (total size minus header size) in bytes.
*/
inline uint16 AdtsFrame::dataSize() const
{
return totalSize() - headerSize();
}
/*!
* \brief Returns the buffer fullness.
*/

View File

@ -31,8 +31,8 @@ void AdtsStream::internalParseHeader()
// parse frame header
m_firstFrame.parseHeader(m_reader);
m_format = Mpeg4AudioObjectIds::idToMediaFormat(m_firstFrame.mpeg4AudioObjectId());
m_channelCount = Mpeg4ChannelConfigs::channelCount(m_firstFrame.mpeg4ChannelConfig());
byte sampleRateIndex = m_firstFrame.mpeg4SampleRateIndex();
m_channelCount = Mpeg4ChannelConfigs::channelCount(m_channelConfig = m_firstFrame.mpeg4ChannelConfig());
byte sampleRateIndex = m_firstFrame.mpeg4SamplingFrequencyIndex();
m_sampleRate = sampleRateIndex < sizeof(mpeg4SampleRateTable) ? mpeg4SampleRateTable[sampleRateIndex] : 0;
}

View File

@ -286,6 +286,9 @@ uint32 mpeg4SampleRateTable[] = {
namespace Mpeg4ChannelConfigs {
/*!
* \brief Returns the string representation for the specified MPEG-4 channel config.
*/
const char *channelConfigString(byte config)
{
switch(config) {
@ -306,10 +309,13 @@ const char *channelConfigString(byte config)
case FrontCenterFrontLeftFrontRightSideLeftSideRightBackLeftBackRightLFEChannel:
return "8 channels: front-center, front-left, front-right, side-left, side-right, back-left, back-right, LFE-channel";
default:
return "unknown";
return nullptr;
}
}
/*!
* \brief Returns the channel count for the specified MPEG-4 channel config.
*/
byte channelCount(byte config)
{
switch(config) {

View File

@ -1378,6 +1378,7 @@ void Mp4Track::internalParseHeader()
} else {
addNotification(NotificationType::Warning, "Audio specific config has invalid extension sample frequency index.", context);
}
m_channelConfig = m_esInfo->audioSpecificConfig->channelConfiguration;
}
if(m_esInfo->videoSpecificConfig) {
// check the video specific config for useful information

View File

@ -8,6 +8,20 @@ using namespace IoUtilities;
namespace Media {
/*!
* \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";
case MpegChannelMode::Unspecifed: return nullptr;
}
}
const uint64 MpegAudioFrame::m_xingHeaderOffset = 0x24;
/*!
@ -35,6 +49,9 @@ const uint32 MpegAudioFrame::m_sync = 0xFFE00000u;
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<XingHeaderFlags>(m_xingHeader & 0xffffffffuL);
@ -52,9 +69,6 @@ void MpegAudioFrame::parseHeader(BinaryReader &reader)
m_xingQualityIndicator = reader.readUInt32BE();
}
}
if(!isValid()) {
throw InvalidDataException();
}
}
/*!
@ -92,9 +106,9 @@ int MpegAudioFrame::layer() const
}
/*!
* \brief Returns the sampel rate of the frame if known; otherwise returns 0.
* \brief Returns the sampeling frequency of the frame if known; otherwise returns 0.
*/
uint32 MpegAudioFrame::sampelRate() const
uint32 MpegAudioFrame::samplingFrequency() const
{
switch (m_header & 0xc00u) {
case 0xc00u:
@ -186,10 +200,10 @@ uint32 MpegAudioFrame::size() const
{
switch (m_header & 0x60000u) {
case 0x60000u:
return static_cast<uint32>(((static_cast<double>(bitrate()) * 1024.0 / 8.0) / static_cast<double>(sampelRate())) * static_cast<double>(sampleCount()) + static_cast<double>(paddingSize()));
return static_cast<uint32>(((static_cast<double>(bitrate()) * 1024.0 / 8.0) / static_cast<double>(samplingFrequency())) * static_cast<double>(sampleCount()) + static_cast<double>(paddingSize()));
case 0x40000u:
case 0x20000u:
return static_cast<uint32>(((static_cast<double>(bitrate()) * 1024.0 / 8.0) / static_cast<double>(sampelRate())) * static_cast<double>(sampleCount()) + static_cast<double>(paddingSize()));
return static_cast<uint32>(((static_cast<double>(bitrate()) * 1024.0 / 8.0) / static_cast<double>(samplingFrequency())) * static_cast<double>(sampleCount()) + static_cast<double>(paddingSize()));
default:
return 0;
}

View File

@ -25,6 +25,8 @@ enum class MpegChannelMode
Unspecifed /**< used to indicate that the channel mode is unknown */
};
LIB_EXPORT const char *mpegChannelModeString(MpegChannelMode channelMode);
enum class XingHeaderFlags
{
None = 0x0u, /**< No Xing frames are present */
@ -46,7 +48,7 @@ public:
int layer() const;
bool isProtectedByCrc() const;
uint32 bitrate() const;
uint32 sampelRate() const;
uint32 samplingFrequency() const;
uint32 paddingSize() const;
MpegChannelMode channelMode() const;
bool hasCopyright() const;

View File

@ -25,7 +25,8 @@ void MpegAudioFrameStream::addInfo(const MpegAudioFrame &frame, AbstractTrack &t
track.m_version = frame.mpegVersion();
track.m_format = MediaFormat(GeneralMediaFormat::Mpeg1Audio, frame.layer());
track.m_channelCount = frame.channelMode() == MpegChannelMode::SingleChannel ? 1 : 2;
track.m_sampleRate = frame.sampelRate();
track.m_channelConfig = static_cast<byte>(frame.channelMode());
track.m_sampleRate = frame.samplingFrequency();
}
void MpegAudioFrameStream::internalParseHeader()
@ -55,7 +56,7 @@ void MpegAudioFrameStream::internalParseHeader()
}
}
m_bitrate = frame.isXingFramefieldPresent()
? ((static_cast<double>(m_size) * 8.0) / (static_cast<double>(frame.xingFrameCount() * frame.sampleCount()) / static_cast<double>(frame.sampelRate())) / 1024.0)
? ((static_cast<double>(m_size) * 8.0) / (static_cast<double>(frame.xingFrameCount() * frame.sampleCount()) / static_cast<double>(frame.samplingFrequency())) / 1024.0)
: frame.bitrate();
m_bytesPerSecond = m_bitrate * 125;
m_duration = TimeSpan::fromSeconds(static_cast<double>(m_size) / (m_bitrate * 128.0));