added channel config to AbstractTrack and the implementations
This commit is contained in:
parent
b2d64fc681
commit
9f12607a0d
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
Loading…
Reference in New Issue