parse audio specific config for AAC tracks in MKV container (exposed API

in Mp4Track to do that)
renamed sampleRate to samplingFrequency
This commit is contained in:
Martchus 2015-08-13 03:23:28 +02:00
parent 8dc85941eb
commit 3d6c7f33d9
10 changed files with 145 additions and 124 deletions

View File

@ -43,8 +43,8 @@ AbstractTrack::AbstractTrack(istream &inputStream, ostream &outputStream, uint64
m_id(0), m_id(0),
m_bitrate(0.0), m_bitrate(0.0),
m_maxBitrate(0.0), m_maxBitrate(0.0),
m_sampleRate(0), m_samplingFrequency(0),
m_extensionSampleRate(0), m_extensionSamplingFrequency(0),
m_bitsPerSample(0), m_bitsPerSample(0),
m_bytesPerSecond(0), m_bytesPerSecond(0),
m_channelCount(0), m_channelCount(0),

View File

@ -123,8 +123,8 @@ protected:
ChronoUtilities::DateTime m_creationTime; ChronoUtilities::DateTime m_creationTime;
ChronoUtilities::DateTime m_modificationTime; ChronoUtilities::DateTime m_modificationTime;
std::string m_language; std::string m_language;
uint32 m_sampleRate; uint32 m_samplingFrequency;
uint32 m_extensionSampleRate; uint32 m_extensionSamplingFrequency;
uint16 m_bitsPerSample; uint16 m_bitsPerSample;
uint32 m_bytesPerSecond; uint32 m_bytesPerSecond;
uint16 m_channelCount; uint16 m_channelCount;
@ -371,7 +371,7 @@ inline const std::string &AbstractTrack::language() const
*/ */
inline uint32 AbstractTrack::samplingFrequency() const inline uint32 AbstractTrack::samplingFrequency() const
{ {
return m_sampleRate; return m_samplingFrequency;
} }
/*! /*!
@ -380,7 +380,7 @@ inline uint32 AbstractTrack::samplingFrequency() const
*/ */
inline uint32 AbstractTrack::extensionSamplingFrequency() const inline uint32 AbstractTrack::extensionSamplingFrequency() const
{ {
return m_extensionSampleRate; return m_extensionSamplingFrequency;
} }
/*! /*!

View File

@ -33,7 +33,7 @@ void AdtsStream::internalParseHeader()
m_format = Mpeg4AudioObjectIds::idToMediaFormat(m_firstFrame.mpeg4AudioObjectId()); m_format = Mpeg4AudioObjectIds::idToMediaFormat(m_firstFrame.mpeg4AudioObjectId());
m_channelCount = Mpeg4ChannelConfigs::channelCount(m_channelConfig = m_firstFrame.mpeg4ChannelConfig()); m_channelCount = Mpeg4ChannelConfigs::channelCount(m_channelConfig = m_firstFrame.mpeg4ChannelConfig());
byte sampleRateIndex = m_firstFrame.mpeg4SamplingFrequencyIndex(); byte sampleRateIndex = m_firstFrame.mpeg4SamplingFrequencyIndex();
m_sampleRate = sampleRateIndex < sizeof(mpeg4SamplingFrequencyTable) ? mpeg4SamplingFrequencyTable[sampleRateIndex] : 0; m_samplingFrequency = sampleRateIndex < sizeof(mpeg4SamplingFrequencyTable) ? mpeg4SamplingFrequencyTable[sampleRateIndex] : 0;
} }
} // namespace Media } // namespace Media

View File

@ -86,8 +86,8 @@ const char *matroskaIdName(uint32 matroskaId)
case TrackAudio: return "audio track"; case TrackAudio: return "audio track";
case TrackVideo: return "video track"; case TrackVideo: return "video track";
case ContentEncodings: return "content encodings"; case ContentEncodings: return "content encodings";
case CodecID: return "content id"; case CodecID: return "codec id";
case CodecPrivate: return "code private"; case CodecPrivate: return "codec private";
case CodecName: return "codec name"; case CodecName: return "codec name";
case TrackName: return "track name"; case TrackName: return "track name";
case TrackLanguage: return "track language"; case TrackLanguage: return "track language";

View File

@ -6,6 +6,7 @@
#include "../avi/bitmapinfoheader.h" #include "../avi/bitmapinfoheader.h"
#include "../wav/waveaudiostream.h" #include "../wav/waveaudiostream.h"
#include "../mp4/mp4ids.h" #include "../mp4/mp4ids.h"
#include "../mp4/mp4track.h"
#include "../mediaformat.h" #include "../mediaformat.h"
#include "../exceptions.h" #include "../exceptions.h"
@ -285,7 +286,14 @@ void MatroskaTrack::internalParseHeader()
m_channelCount = subElement->readUInteger(); m_channelCount = subElement->readUInteger();
break; break;
case MatroskaIds::SamplingFrequency: case MatroskaIds::SamplingFrequency:
m_sampleRate = subElement->readFloat(); if(!m_samplingFrequency) {
m_samplingFrequency = subElement->readFloat();
}
break;
case MatroskaIds::OutputSamplingFrequency:
if(!m_extensionSamplingFrequency) {
m_extensionSamplingFrequency = subElement->readFloat();
}
break; break;
default: default:
; ;
@ -307,9 +315,6 @@ void MatroskaTrack::internalParseHeader()
break; break;
case MatroskaIds::CodecID: case MatroskaIds::CodecID:
m_format = codecIdToMediaFormat(m_formatId = trackInfoElement->readString()); m_format = codecIdToMediaFormat(m_formatId = trackInfoElement->readString());
if(m_formatName.empty()) {
m_formatName = m_format ? string(m_format.name()) : m_formatId;
}
break; break;
case MatroskaIds::CodecName: case MatroskaIds::CodecName:
m_formatName = trackInfoElement->readString(); m_formatName = trackInfoElement->readString();
@ -377,6 +382,27 @@ void MatroskaTrack::internalParseHeader()
} }
} }
break; break;
case GeneralMediaFormat::Aac:
if((codecPrivateElement = m_trackElement->childById(MatroskaIds::CodecPrivate))) {
auto audioSpecificConfig = Mp4Track::parseAudioSpecificConfig(*this, *m_istream, codecPrivateElement->dataOffset(), codecPrivateElement->dataSize());
m_format += Mpeg4AudioObjectIds::idToMediaFormat(audioSpecificConfig->audioObjectType, audioSpecificConfig->sbrPresent, audioSpecificConfig->psPresent);
if(audioSpecificConfig->sampleFrequencyIndex == 0xF) {
//m_samplingFrequency = audioSpecificConfig->sampleFrequency;
} else if(audioSpecificConfig->sampleFrequencyIndex < sizeof(mpeg4SamplingFrequencyTable)) {
//m_samplingFrequency = mpeg4SamplingFrequencyTable[audioSpecificConfig->sampleFrequencyIndex];
} else {
addNotification(NotificationType::Warning, "Audio specific config has invalid sample frequency index.", context);
}
if(audioSpecificConfig->extensionSampleFrequencyIndex == 0xF) {
//m_extensionSamplingFrequency = audioSpecificConfig->extensionSampleFrequency;
} else if(audioSpecificConfig->extensionSampleFrequencyIndex < sizeof(mpeg4SamplingFrequencyTable)) {
//m_extensionSamplingFrequency = mpeg4SamplingFrequencyTable[audioSpecificConfig->extensionSampleFrequencyIndex];
} else {
addNotification(NotificationType::Warning, "Audio specific config has invalid extension sample frequency index.", context);
}
m_channelConfig = audioSpecificConfig->channelConfiguration;
}
break;
default: default:
; ;
} }

View File

@ -438,54 +438,51 @@ vector<uint64> Mp4Track::readChunkSizes()
* - Returns an empty configuration for non-AVC tracks. * - Returns an empty configuration for non-AVC tracks.
* - Notifications might be added. * - Notifications might be added.
*/ */
AvcConfiguration Mp4Track::parseAvcConfiguration(Mp4Atom *avcConfigAtom) AvcConfiguration Mp4Track::parseAvcConfiguration(StatusProvider &statusProvider, BinaryReader &reader, uint64 startOffset, uint64 size)
{ {
AvcConfiguration config; AvcConfiguration config;
if(avcConfigAtom) { try {
try { if(size >= 5) {
auto configSize = avcConfigAtom->dataSize(); // skip first byte (is always 1)
if(avcConfigAtom && configSize >= 5) { reader.stream()->seekg(startOffset + 1);
// skip first byte (is always 1) // read profile, IDC level, NALU size length
m_istream->seekg(avcConfigAtom->dataOffset() + 1); config.profileIdc = reader.readByte();
// read profile, IDC level, NALU size length config.profileCompat = reader.readByte();
config.profileIdc = m_reader.readByte(); config.levelIdc = reader.readByte();
config.profileCompat = m_reader.readByte(); config.naluSizeLength = reader.readByte() & 0x03;
config.levelIdc = m_reader.readByte(); // read SPS infos
config.naluSizeLength = m_reader.readByte() & 0x03; if((size -= 5) >= 3) {
// read SPS infos byte entryCount = reader.readByte() & 0x0f;
if((configSize -= 5) >= 3) { uint16 entrySize;
byte entryCount = m_reader.readByte() & 0x0f; while(entryCount && size) {
uint16 entrySize; if((entrySize = reader.readUInt16BE()) <= size) {
while(entryCount && configSize) { // TODO: read entry
if((entrySize = m_reader.readUInt16BE()) <= configSize) { size -= entrySize;
} else {
throw TruncatedDataException();
}
--entryCount;
}
// read PPS infos
if((size -= 5) >= 3) {
entryCount = reader.readByte();
while(entryCount && size) {
if((entrySize = reader.readUInt16BE()) <= size) {
// TODO: read entry // TODO: read entry
configSize -= entrySize; size -= entrySize;
} else { } else {
throw TruncatedDataException(); throw TruncatedDataException();
} }
--entryCount; --entryCount;
} }
// read PPS infos // TODO: read trailer
if((configSize -= 5) >= 3) { return config;
entryCount = m_reader.readByte();
while(entryCount && configSize) {
if((entrySize = m_reader.readUInt16BE()) <= configSize) {
// TODO: read entry
configSize -= entrySize;
} else {
throw TruncatedDataException();
}
--entryCount;
}
// TODO: read trailer
return config;
}
} }
} }
throw TruncatedDataException();
} catch (TruncatedDataException &) {
addNotification(NotificationType::Critical, "AVC configuration is truncated.", "parsing AVC configuration");
} }
throw TruncatedDataException();
} catch (TruncatedDataException &) {
statusProvider.addNotification(NotificationType::Critical, "AVC configuration is truncated.", "parsing AVC configuration");
} }
return config; return config;
} }
@ -496,51 +493,51 @@ AvcConfiguration Mp4Track::parseAvcConfiguration(Mp4Atom *avcConfigAtom)
* - Notifications might be added. * - Notifications might be added.
* \sa mpeg4ElementaryStreamInfo() * \sa mpeg4ElementaryStreamInfo()
*/ */
std::unique_ptr<Mpeg4ElementaryStreamInfo> Mp4Track::parseMpeg4ElementaryStreamInfo(Mp4Atom *esDescAtom) std::unique_ptr<Mpeg4ElementaryStreamInfo> Mp4Track::parseMpeg4ElementaryStreamInfo(StatusProvider &statusProvider, IoUtilities::BinaryReader &reader, Mp4Atom *esDescAtom)
{ {
static const string context("parsing MPEG-4 elementary stream descriptor"); static const string context("parsing MPEG-4 elementary stream descriptor");
using namespace Mpeg4ElementaryStreamObjectIds; using namespace Mpeg4ElementaryStreamObjectIds;
unique_ptr<Mpeg4ElementaryStreamInfo> esInfo; unique_ptr<Mpeg4ElementaryStreamInfo> esInfo;
if(esDescAtom->dataSize() >= 12) { if(esDescAtom->dataSize() >= 12) {
m_istream->seekg(esDescAtom->dataOffset()); reader.stream()->seekg(esDescAtom->dataOffset());
// read version/flags // read version/flags
if(m_reader.readUInt32BE() != 0) { if(reader.readUInt32BE() != 0) {
addNotification(NotificationType::Warning, "Unknown version/flags.", context); statusProvider.addNotification(NotificationType::Warning, "Unknown version/flags.", context);
} }
// read extended descriptor // read extended descriptor
Mpeg4Descriptor esDesc(esDescAtom->container(), m_istream->tellg(), esDescAtom->dataSize() - 4); Mpeg4Descriptor esDesc(esDescAtom->container(), reader.stream()->tellg(), esDescAtom->dataSize() - 4);
try { try {
esDesc.parse(); esDesc.parse();
// check ID // check ID
if(esDesc.id() != Mpeg4DescriptorIds::ElementaryStreamDescr) { if(esDesc.id() != Mpeg4DescriptorIds::ElementaryStreamDescr) {
addNotification(NotificationType::Critical, "Invalid descriptor found.", context); statusProvider.addNotification(NotificationType::Critical, "Invalid descriptor found.", context);
throw Failure(); throw Failure();
} }
// read stream info // read stream info
m_istream->seekg(esDesc.dataOffset()); reader.stream()->seekg(esDesc.dataOffset());
esInfo = make_unique<Mpeg4ElementaryStreamInfo>(); esInfo = make_unique<Mpeg4ElementaryStreamInfo>();
esInfo->id = m_reader.readUInt16BE(); esInfo->id = reader.readUInt16BE();
esInfo->esDescFlags = m_reader.readByte(); esInfo->esDescFlags = reader.readByte();
if(esInfo->dependencyFlag()) { if(esInfo->dependencyFlag()) {
esInfo->dependsOnId = m_reader.readUInt16BE(); esInfo->dependsOnId = reader.readUInt16BE();
} }
if(esInfo->urlFlag()) { if(esInfo->urlFlag()) {
esInfo->url = m_reader.readString(m_reader.readByte()); esInfo->url = reader.readString(reader.readByte());
} }
if(esInfo->ocrFlag()) { if(esInfo->ocrFlag()) {
esInfo->ocrId = m_reader.readUInt16BE(); esInfo->ocrId = reader.readUInt16BE();
} }
for(Mpeg4Descriptor *esDescChild = esDesc.denoteFirstChild(static_cast<uint64>(m_istream->tellg()) - esDesc.startOffset()); esDescChild; esDescChild = esDescChild->nextSibling()) { for(Mpeg4Descriptor *esDescChild = esDesc.denoteFirstChild(static_cast<uint64>(reader.stream()->tellg()) - esDesc.startOffset()); esDescChild; esDescChild = esDescChild->nextSibling()) {
esDescChild->parse(); esDescChild->parse();
switch(esDescChild->id()) { switch(esDescChild->id()) {
case Mpeg4DescriptorIds::DecoderConfigDescr: case Mpeg4DescriptorIds::DecoderConfigDescr:
// read decoder config descriptor // read decoder config descriptor
m_istream->seekg(esDescChild->dataOffset()); reader.stream()->seekg(esDescChild->dataOffset());
esInfo->objectTypeId = m_reader.readByte(); esInfo->objectTypeId = reader.readByte();
esInfo->decCfgDescFlags = m_reader.readByte(); esInfo->decCfgDescFlags = reader.readByte();
esInfo->bufferSize = m_reader.readUInt24BE(); esInfo->bufferSize = reader.readUInt24BE();
esInfo->maxBitrate = m_reader.readUInt32BE(); esInfo->maxBitrate = reader.readUInt32BE();
esInfo->averageBitrate = m_reader.readUInt32BE(); esInfo->averageBitrate = reader.readUInt32BE();
for(Mpeg4Descriptor *decCfgDescChild = esDescChild->denoteFirstChild(esDescChild->headerSize() + 13); decCfgDescChild; decCfgDescChild = decCfgDescChild->nextSibling()) { for(Mpeg4Descriptor *decCfgDescChild = esDescChild->denoteFirstChild(esDescChild->headerSize() + 13); decCfgDescChild; decCfgDescChild = decCfgDescChild->nextSibling()) {
decCfgDescChild->parse(); decCfgDescChild->parse();
switch(decCfgDescChild->id()) { switch(decCfgDescChild->id()) {
@ -549,10 +546,10 @@ std::unique_ptr<Mpeg4ElementaryStreamInfo> Mp4Track::parseMpeg4ElementaryStreamI
switch(esInfo->objectTypeId) { switch(esInfo->objectTypeId) {
case Aac: case Mpeg2AacMainProfile: case Mpeg2AacLowComplexityProfile: case Aac: case Mpeg2AacMainProfile: case Mpeg2AacLowComplexityProfile:
case Mpeg2AacScaleableSamplingRateProfile: case Mpeg2Audio: case Mpeg1Audio: case Mpeg2AacScaleableSamplingRateProfile: case Mpeg2Audio: case Mpeg1Audio:
esInfo->audioSpecificConfig = parseAudioSpecificConfig(decCfgDescChild); esInfo->audioSpecificConfig = parseAudioSpecificConfig(statusProvider, *reader.stream(), decCfgDescChild->dataOffset(), decCfgDescChild->dataSize());
break; break;
case Mpeg4Visual: case Mpeg4Visual:
esInfo->videoSpecificConfig = parseVideoSpecificConfig(decCfgDescChild); esInfo->videoSpecificConfig = parseVideoSpecificConfig(statusProvider, reader, decCfgDescChild->dataOffset(), decCfgDescChild->dataSize());
break; break;
default: default:
; // TODO: cover more object types ; // TODO: cover more object types
@ -567,10 +564,10 @@ std::unique_ptr<Mpeg4ElementaryStreamInfo> Mp4Track::parseMpeg4ElementaryStreamI
} }
} }
} catch (Failure &) { } catch (Failure &) {
addNotification(NotificationType::Critical, "The MPEG-4 descriptor element structure is invalid.", context); statusProvider.addNotification(NotificationType::Critical, "The MPEG-4 descriptor element structure is invalid.", context);
} }
} else { } else {
addNotification(NotificationType::Warning, "Elementary stream descriptor atom (esds) is truncated.", context); statusProvider.addNotification(NotificationType::Warning, "Elementary stream descriptor atom (esds) is truncated.", context);
} }
return esInfo; return esInfo;
} }
@ -581,16 +578,15 @@ std::unique_ptr<Mpeg4ElementaryStreamInfo> Mp4Track::parseMpeg4ElementaryStreamI
* - Notifications might be added. * - Notifications might be added.
* \sa mpeg4ElementaryStreamInfo() * \sa mpeg4ElementaryStreamInfo()
*/ */
unique_ptr<Mpeg4AudioSpecificConfig> Mp4Track::parseAudioSpecificConfig(Mpeg4Descriptor *decSpecInfoDesc) unique_ptr<Mpeg4AudioSpecificConfig> Mp4Track::parseAudioSpecificConfig(StatusProvider &statusProvider, istream &stream, uint64 startOffset, uint64 size)
{ {
static const string context("parsing MPEG-4 audio specific config from elementary stream descriptor"); static const string context("parsing MPEG-4 audio specific config from elementary stream descriptor");
using namespace Mpeg4AudioObjectIds; using namespace Mpeg4AudioObjectIds;
// read config into buffer and construct BitReader for bitwise reading // read config into buffer and construct BitReader for bitwise reading
m_istream->seekg(decSpecInfoDesc->dataOffset()); stream.seekg(startOffset);
//cout << "audio cfg @" << decSpecInfoDesc->dataOffset() << endl; auto buff = make_unique<char []>(size);
auto buff = make_unique<char []>(decSpecInfoDesc->dataSize()); stream.read(buff.get(), size);
m_istream->read(buff.get(), decSpecInfoDesc->dataSize()); BitReader bitReader(buff.get(), size);
BitReader bitReader(buff.get(), decSpecInfoDesc->dataSize());
auto audioCfg = make_unique<Mpeg4AudioSpecificConfig>(); auto audioCfg = make_unique<Mpeg4AudioSpecificConfig>();
try { try {
// read audio object type // read audio object type
@ -703,15 +699,15 @@ unique_ptr<Mpeg4AudioSpecificConfig> Mp4Track::parseAudioSpecificConfig(Mpeg4Des
} }
} }
} catch(ios_base::failure &) { } catch(ios_base::failure &) {
if(m_istream->fail()) { if(stream.fail()) {
// IO error caused by input stream // IO error caused by input stream
throw; throw;
} else { } else {
// IO error caused by bitReader // IO error caused by bitReader
addNotification(NotificationType::Critical, "Audio specific configuration is truncated.", context); statusProvider.addNotification(NotificationType::Critical, "Audio specific configuration is truncated.", context);
} }
} catch(NotImplementedException &) { } catch(NotImplementedException &) {
addNotification(NotificationType::Information, "Not implemented for the format of audio track.", context); statusProvider.addNotification(NotificationType::Information, "Not implemented for the format of audio track.", context);
} }
return audioCfg; return audioCfg;
} }
@ -722,24 +718,23 @@ unique_ptr<Mpeg4AudioSpecificConfig> Mp4Track::parseAudioSpecificConfig(Mpeg4Des
* - Notifications might be added. * - Notifications might be added.
* \sa mpeg4ElementaryStreamInfo() * \sa mpeg4ElementaryStreamInfo()
*/ */
std::unique_ptr<Mpeg4VideoSpecificConfig> Mp4Track::parseVideoSpecificConfig(Mpeg4Descriptor *decSpecInfoDesc) std::unique_ptr<Mpeg4VideoSpecificConfig> Mp4Track::parseVideoSpecificConfig(StatusProvider &statusProvider, BinaryReader &reader, uint64 startOffset, uint64 size)
{ {
static const string context("parsing MPEG-4 video specific config from elementary stream descriptor"); static const string context("parsing MPEG-4 video specific config from elementary stream descriptor");
using namespace Mpeg4AudioObjectIds; using namespace Mpeg4AudioObjectIds;
auto videoCfg = make_unique<Mpeg4VideoSpecificConfig>(); auto videoCfg = make_unique<Mpeg4VideoSpecificConfig>();
// seek to start // seek to start
m_istream->seekg(decSpecInfoDesc->dataOffset()); reader.stream()->seekg(startOffset);
uint64 bytesRemaining = decSpecInfoDesc->dataSize(); if(size > 3 && (reader.readUInt24BE() == 1)) {
if(bytesRemaining > 3 && (m_reader.readUInt24BE() == 1)) { size -= 3;
bytesRemaining -= 3;
uint32 buff1; uint32 buff1;
while(bytesRemaining) { while(size) {
--bytesRemaining; --size;
switch(m_reader.readByte()) { // read start code switch(reader.readByte()) { // read start code
case Mpeg4VideoCodes::VisualObjectSequenceStart: case Mpeg4VideoCodes::VisualObjectSequenceStart:
if(bytesRemaining) { if(size) {
videoCfg->profile = m_reader.readByte(); videoCfg->profile = reader.readByte();
--bytesRemaining; --size;
} }
break; break;
case Mpeg4VideoCodes::VideoObjectLayerStart: case Mpeg4VideoCodes::VideoObjectLayerStart:
@ -747,19 +742,19 @@ std::unique_ptr<Mpeg4VideoSpecificConfig> Mp4Track::parseVideoSpecificConfig(Mpe
break; break;
case Mpeg4VideoCodes::UserDataStart: case Mpeg4VideoCodes::UserDataStart:
buff1 = 0; buff1 = 0;
while(bytesRemaining >= 3) { while(size >= 3) {
if((buff1 = m_reader.readUInt24BE()) != 1) { if((buff1 = reader.readUInt24BE()) != 1) {
m_istream->seekg(-2, ios_base::cur); reader.stream()->seekg(-2, ios_base::cur);
videoCfg->userData.push_back(buff1 >> 16); videoCfg->userData.push_back(buff1 >> 16);
--bytesRemaining; --size;
} else { } else {
bytesRemaining -= 3; size -= 3;
break; break;
} }
} }
if(buff1 != 1 && bytesRemaining > 0) { if(buff1 != 1 && size > 0) {
videoCfg->userData += m_reader.readString(bytesRemaining); videoCfg->userData += reader.readString(size);
bytesRemaining = 0; size = 0;
} }
break; break;
default: default:
@ -767,18 +762,18 @@ std::unique_ptr<Mpeg4VideoSpecificConfig> Mp4Track::parseVideoSpecificConfig(Mpe
} }
// skip stuff we're not interested in to get the start of the // skip stuff we're not interested in to get the start of the
// next video object // next video object
while(bytesRemaining >= 3) { while(size >= 3) {
if(m_reader.readUInt24BE() != 1) { if(reader.readUInt24BE() != 1) {
m_istream->seekg(-2, ios_base::cur); reader.stream()->seekg(-2, ios_base::cur);
--bytesRemaining; --size;
} else { } else {
bytesRemaining -= 3; size -= 3;
break; break;
} }
} }
} }
} else { } else {
addNotification(NotificationType::Critical, "\"Visual Object Sequence Header\" not found.", context); statusProvider.addNotification(NotificationType::Critical, "\"Visual Object Sequence Header\" not found.", context);
} }
return videoCfg; return videoCfg;
} }
@ -1285,10 +1280,10 @@ void Mp4Track::internalParseHeader()
m_channelCount = reader.readUInt16BE(); m_channelCount = reader.readUInt16BE();
m_bitsPerSample = reader.readUInt16BE(); m_bitsPerSample = reader.readUInt16BE();
m_istream->seekg(4, ios_base::cur); // skip reserved bytes (again) m_istream->seekg(4, ios_base::cur); // skip reserved bytes (again)
if(!m_sampleRate) { if(!m_samplingFrequency) {
m_sampleRate = reader.readUInt32BE() >> 16; m_samplingFrequency = reader.readUInt32BE() >> 16;
if(codecConfigContainerAtom->id() != FourccIds::DolbyMpl) { if(codecConfigContainerAtom->id() != FourccIds::DolbyMpl) {
m_sampleRate >>= 16; m_samplingFrequency >>= 16;
} }
} else { } else {
m_istream->seekg(4, ios_base::cur); m_istream->seekg(4, ios_base::cur);
@ -1357,7 +1352,7 @@ void Mp4Track::internalParseHeader()
} }
if(esDescAtom) { if(esDescAtom) {
try { try {
if((m_esInfo = parseMpeg4ElementaryStreamInfo(esDescAtom))) { if((m_esInfo = parseMpeg4ElementaryStreamInfo(*this, m_reader, esDescAtom))) {
m_format += Mpeg4ElementaryStreamObjectIds::streamObjectTypeFormat(m_esInfo->objectTypeId); m_format += Mpeg4ElementaryStreamObjectIds::streamObjectTypeFormat(m_esInfo->objectTypeId);
m_bitrate = static_cast<double>(m_esInfo->averageBitrate) / 1000; m_bitrate = static_cast<double>(m_esInfo->averageBitrate) / 1000;
m_maxBitrate = static_cast<double>(m_esInfo->maxBitrate) / 1000; m_maxBitrate = static_cast<double>(m_esInfo->maxBitrate) / 1000;
@ -1365,16 +1360,16 @@ void Mp4Track::internalParseHeader()
// check the audio specific config for useful information // check the audio specific config for useful information
m_format += Mpeg4AudioObjectIds::idToMediaFormat(m_esInfo->audioSpecificConfig->audioObjectType, m_esInfo->audioSpecificConfig->sbrPresent, m_esInfo->audioSpecificConfig->psPresent); m_format += Mpeg4AudioObjectIds::idToMediaFormat(m_esInfo->audioSpecificConfig->audioObjectType, m_esInfo->audioSpecificConfig->sbrPresent, m_esInfo->audioSpecificConfig->psPresent);
if(m_esInfo->audioSpecificConfig->sampleFrequencyIndex == 0xF) { if(m_esInfo->audioSpecificConfig->sampleFrequencyIndex == 0xF) {
m_sampleRate = m_esInfo->audioSpecificConfig->sampleFrequency; m_samplingFrequency = m_esInfo->audioSpecificConfig->sampleFrequency;
} else if(m_esInfo->audioSpecificConfig->sampleFrequencyIndex < sizeof(mpeg4SamplingFrequencyTable)) { } else if(m_esInfo->audioSpecificConfig->sampleFrequencyIndex < sizeof(mpeg4SamplingFrequencyTable)) {
m_sampleRate = mpeg4SamplingFrequencyTable[m_esInfo->audioSpecificConfig->sampleFrequencyIndex]; m_samplingFrequency = mpeg4SamplingFrequencyTable[m_esInfo->audioSpecificConfig->sampleFrequencyIndex];
} else { } else {
addNotification(NotificationType::Warning, "Audio specific config has invalid sample frequency index.", context); addNotification(NotificationType::Warning, "Audio specific config has invalid sample frequency index.", context);
} }
if(m_esInfo->audioSpecificConfig->extensionSampleFrequencyIndex == 0xF) { if(m_esInfo->audioSpecificConfig->extensionSampleFrequencyIndex == 0xF) {
m_extensionSampleRate = m_esInfo->audioSpecificConfig->extensionSampleFrequency; m_extensionSamplingFrequency = m_esInfo->audioSpecificConfig->extensionSampleFrequency;
} else if(m_esInfo->audioSpecificConfig->extensionSampleFrequencyIndex < sizeof(mpeg4SamplingFrequencyTable)) { } else if(m_esInfo->audioSpecificConfig->extensionSampleFrequencyIndex < sizeof(mpeg4SamplingFrequencyTable)) {
m_extensionSampleRate = mpeg4SamplingFrequencyTable[m_esInfo->audioSpecificConfig->extensionSampleFrequencyIndex]; m_extensionSamplingFrequency = mpeg4SamplingFrequencyTable[m_esInfo->audioSpecificConfig->extensionSampleFrequencyIndex];
} else { } else {
addNotification(NotificationType::Warning, "Audio specific config has invalid extension sample frequency index.", context); addNotification(NotificationType::Warning, "Audio specific config has invalid extension sample frequency index.", context);
} }

View File

@ -133,10 +133,10 @@ public:
const Mpeg4ElementaryStreamInfo *mpeg4ElementaryStreamInfo() const; const Mpeg4ElementaryStreamInfo *mpeg4ElementaryStreamInfo() const;
// methods to parse configuration details from the track header // methods to parse configuration details from the track header
AvcConfiguration parseAvcConfiguration(Mp4Atom *avcConfigAtom); static AvcConfiguration parseAvcConfiguration(StatusProvider &statusProvider, IoUtilities::BinaryReader &reader, uint64 startOffset, uint64 size);
std::unique_ptr<Mpeg4ElementaryStreamInfo> parseMpeg4ElementaryStreamInfo(Mp4Atom *esDescAtom); static std::unique_ptr<Mpeg4ElementaryStreamInfo> parseMpeg4ElementaryStreamInfo(StatusProvider &statusProvider, IoUtilities::BinaryReader &reader, Mp4Atom *esDescAtom);
std::unique_ptr<Mpeg4AudioSpecificConfig> parseAudioSpecificConfig(Mpeg4Descriptor *decSpecInfoDesc); static std::unique_ptr<Mpeg4AudioSpecificConfig> parseAudioSpecificConfig(StatusProvider &statusProvider, std::istream &stream, uint64 startOffset, uint64 size);
std::unique_ptr<Mpeg4VideoSpecificConfig> parseVideoSpecificConfig(Mpeg4Descriptor *decSpecInfoDesc); static std::unique_ptr<Mpeg4VideoSpecificConfig> parseVideoSpecificConfig(StatusProvider &statusProvider, IoUtilities::BinaryReader &reader, uint64 startOffset, uint64 size);
// methods to read the "index" (chunk offsets and sizes) // methods to read the "index" (chunk offsets and sizes)
std::vector<uint64> readChunkOffsets(); std::vector<uint64> readChunkOffsets();

View File

@ -26,7 +26,7 @@ void MpegAudioFrameStream::addInfo(const MpegAudioFrame &frame, AbstractTrack &t
track.m_format = MediaFormat(GeneralMediaFormat::Mpeg1Audio, frame.layer()); track.m_format = MediaFormat(GeneralMediaFormat::Mpeg1Audio, frame.layer());
track.m_channelCount = frame.channelMode() == MpegChannelMode::SingleChannel ? 1 : 2; track.m_channelCount = frame.channelMode() == MpegChannelMode::SingleChannel ? 1 : 2;
track.m_channelConfig = static_cast<byte>(frame.channelMode()); track.m_channelConfig = static_cast<byte>(frame.channelMode());
track.m_sampleRate = frame.samplingFrequency(); track.m_samplingFrequency = frame.samplingFrequency();
} }
void MpegAudioFrameStream::internalParseHeader() void MpegAudioFrameStream::internalParseHeader()

View File

@ -78,7 +78,7 @@ void OggStream::internalParseHeader()
VorbisIdentificationHeader ind; VorbisIdentificationHeader ind;
ind.parseHeader(iterator); ind.parseHeader(iterator);
m_channelCount = ind.channels(); m_channelCount = ind.channels();
m_sampleRate = ind.sampleRate(); m_samplingFrequency = ind.sampleRate();
if(ind.nominalBitrate()) { if(ind.nominalBitrate()) {
m_bitrate = ind.nominalBitrate(); m_bitrate = ind.nominalBitrate();
} else if(ind.maxBitrate() == ind.minBitrate()) { } else if(ind.maxBitrate() == ind.minBitrate()) {
@ -96,7 +96,7 @@ void OggStream::internalParseHeader()
auto lastPage = find_if(pages.crbegin(), pages.crend(), pred); auto lastPage = find_if(pages.crbegin(), pages.crend(), pred);
if(firstPage != pages.cend() && lastPage != pages.crend()) { if(firstPage != pages.cend() && lastPage != pages.crend()) {
m_sampleCount = lastPage->absoluteGranulePosition() - firstPage->absoluteGranulePosition(); m_sampleCount = lastPage->absoluteGranulePosition() - firstPage->absoluteGranulePosition();
m_duration = TimeSpan::fromSeconds(static_cast<double>(m_sampleCount) / m_sampleRate); m_duration = TimeSpan::fromSeconds(static_cast<double>(m_sampleCount) / m_samplingFrequency);
} }
} }
hasIdentificationHeader = true; hasIdentificationHeader = true;

View File

@ -86,7 +86,7 @@ void WaveAudioStream::addInfo(const WaveFormatHeader &waveHeader, AbstractTrack
{ {
track.m_format = waveHeader.format(); track.m_format = waveHeader.format();
track.m_channelCount = waveHeader.channelCount; track.m_channelCount = waveHeader.channelCount;
track.m_sampleRate = waveHeader.sampleRate; track.m_samplingFrequency = waveHeader.sampleRate;
track.m_bytesPerSecond = waveHeader.bytesPerSecond; track.m_bytesPerSecond = waveHeader.bytesPerSecond;
track.m_chunkSize = waveHeader.chunkSize; track.m_chunkSize = waveHeader.chunkSize;
track.m_bitsPerSample = waveHeader.bitsPerSample; track.m_bitsPerSample = waveHeader.bitsPerSample;
@ -114,7 +114,7 @@ void WaveAudioStream::internalParseHeader()
if(m_reader.readUInt32BE() == 0x64617461u) { if(m_reader.readUInt32BE() == 0x64617461u) {
m_size = m_reader.readUInt32LE(); m_size = m_reader.readUInt32LE();
m_sampleCount = m_size / m_chunkSize; m_sampleCount = m_size / m_chunkSize;
m_duration = ChronoUtilities::TimeSpan::fromSeconds(static_cast<double>(m_sampleCount) / static_cast<double>(m_sampleRate)); m_duration = ChronoUtilities::TimeSpan::fromSeconds(static_cast<double>(m_sampleCount) / static_cast<double>(m_samplingFrequency));
} else { } else {
throw NoDataFoundException(); throw NoDataFoundException();
} }