7 #include "../avc/avcconfiguration.h" 9 #include "../mpegaudio/mpegaudioframe.h" 10 #include "../mpegaudio/mpegaudioframestream.h" 12 #include "../exceptions.h" 13 #include "../mediaformat.h" 15 #include <c++utilities/conversion/stringbuilder.h> 16 #include <c++utilities/io/binaryreader.h> 17 #include <c++utilities/io/binarywriter.h> 18 #include <c++utilities/io/bitreader.h> 19 #include <c++utilities/io/catchiofailure.h> 40 Mpeg4AudioSpecificConfig::Mpeg4AudioSpecificConfig() :
42 sampleFrequencyIndex(0xF),
44 channelConfiguration(0),
45 extensionAudioObjectType(0),
48 extensionSampleFrequencyIndex(0xF),
49 extensionSampleFrequency(0),
50 extensionChannelConfiguration(0),
51 frameLengthFlag(false),
52 dependsOnCoreCoder(false),
92 m_trakAtom(&trakAtom),
105 m_framesPerSample(1),
106 m_chunkOffsetSize(4),
108 m_sampleToChunkEntryCount(0)
150 static const string context(
"reading chunk offset table of MP4 track");
155 vector<uint64> offsets;
158 uint64 actualTableSize = m_stcoAtom->
dataSize();
163 actualTableSize -= 8;
167 if(calculatedTableSize < actualTableSize) {
169 }
else if(calculatedTableSize > actualTableSize) {
171 actualChunkCount = floor(static_cast<double>(actualTableSize) / static_cast<double>(
chunkOffsetSize()));
174 offsets.reserve(actualChunkCount);
178 for(uint32 i = 0; i < actualChunkCount; ++i) {
179 offsets.push_back(
reader().readUInt32BE());
183 for(uint32 i = 0; i < actualChunkCount; ++i) {
184 offsets.push_back(
reader().readUInt64BE());
194 uint64 totalDuration = 0;
201 uint32 calculatedDataSize = 0;
202 if(tfhdAtom->dataSize() < calculatedDataSize) {
206 const uint32 flags =
reader().readUInt24BE();
208 if(flags & 0x000001) {
209 calculatedDataSize += 8;
211 if(flags & 0x000002) {
212 calculatedDataSize += 4;
214 if(flags & 0x000008) {
215 calculatedDataSize += 4;
217 if(flags & 0x000010) {
218 calculatedDataSize += 4;
220 if(flags & 0x000020) {
221 calculatedDataSize += 4;
226 uint32 defaultSampleDuration = 0;
227 uint32 defaultSampleSize = 0;
229 if(tfhdAtom->dataSize() < calculatedDataSize) {
232 if(flags & 0x000001) {
236 if(flags & 0x000002) {
240 if(flags & 0x000008) {
241 defaultSampleDuration =
reader().readUInt32BE();
244 if(flags & 0x000010) {
245 defaultSampleSize =
reader().readUInt32BE();
247 if(flags & 0x000020) {
253 uint32 calculatedDataSize = 8;
254 if(trunAtom->dataSize() < calculatedDataSize) {
258 uint32 flags =
reader().readUInt24BE();
261 if(flags & 0x000001) {
262 calculatedDataSize += 4;
264 if(flags & 0x000004) {
265 calculatedDataSize += 4;
267 uint32 entrySize = 0;
268 if(flags & 0x000100) {
271 if(flags & 0x000200) {
274 if(flags & 0x000400) {
277 if(flags & 0x000800) {
281 if(trunAtom->dataSize() < calculatedDataSize) {
284 if(flags & 0x000001) {
288 if(flags & 0x000004) {
292 if(flags & 0x000100) {
293 totalDuration +=
reader().readUInt32BE();
295 totalDuration += defaultSampleDuration;
297 if(flags & 0x000200) {
298 m_sampleSizes.push_back(
reader().readUInt32BE());
299 m_size += m_sampleSizes.back();
301 m_size += defaultSampleSize;
303 if(flags & 0x000400) {
306 if(flags & 0x000800) {
313 if(m_sampleSizes.empty() && defaultSampleSize) {
314 m_sampleSizes.push_back(defaultSampleSize);
329 uint64 Mp4Track::accumulateSampleSizes(
size_t &sampleIndex,
size_t count)
331 if(sampleIndex + count <= m_sampleSizes.size()) {
333 for(
size_t end = sampleIndex + count; sampleIndex < end; ++sampleIndex) {
334 sum += m_sampleSizes[sampleIndex];
337 }
else if(m_sampleSizes.size() == 1) {
338 sampleIndex += count;
339 return static_cast<uint64
>(m_sampleSizes.front()) * count;
354 void Mp4Track::addChunkSizeEntries(std::vector<uint64> &chunkSizeTable,
size_t count,
size_t &sampleIndex, uint32
sampleCount)
356 for(
size_t i = 0; i < count; ++i) {
357 chunkSizeTable.push_back(accumulateSampleSizes(sampleIndex, sampleCount));
370 static const string context(
"reading sample to chunk table of MP4 track");
376 uint64 actualTableSize = m_stscAtom->
dataSize();
377 if(actualTableSize < 20) {
381 actualTableSize -= 8;
384 uint64 calculatedTableSize = actualSampleToChunkEntryCount * 12;
385 if(calculatedTableSize < actualTableSize) {
387 }
else if(calculatedTableSize > actualTableSize) {
389 actualSampleToChunkEntryCount = floor(static_cast<double>(actualTableSize) / 12.0);
392 vector<tuple<uint32, uint32, uint32> > sampleToChunkTable;
393 sampleToChunkTable.reserve(actualSampleToChunkEntryCount);
395 for(uint32 i = 0; i < actualSampleToChunkEntryCount; ++i) {
397 uint32 firstChunk =
reader().readUInt32BE();
398 uint32 samplesPerChunk =
reader().readUInt32BE();
399 uint32 sampleDescriptionIndex =
reader().readUInt32BE();
400 sampleToChunkTable.emplace_back(firstChunk, samplesPerChunk, sampleDescriptionIndex);
402 return sampleToChunkTable;
419 static const string context(
"reading chunk sizes of MP4 track");
427 vector<uint64> chunkSizes;
428 if(!sampleToChunkTable.empty()) {
430 auto tableIterator = sampleToChunkTable.cbegin();
431 chunkSizes.reserve(m_chunkCount);
433 size_t sampleIndex = 0;
434 uint32 previousChunkIndex = get<0>(*tableIterator);
435 if(previousChunkIndex != 1) {
437 previousChunkIndex = 1;
439 uint32 samplesPerChunk = get<1>(*tableIterator);
442 for(
const auto tableEnd = sampleToChunkTable.cend(); tableIterator != tableEnd; ++tableIterator) {
443 uint32 firstChunkIndex = get<0>(*tableIterator);
444 if(firstChunkIndex > previousChunkIndex && firstChunkIndex <= m_chunkCount) {
445 addChunkSizeEntries(chunkSizes, firstChunkIndex - previousChunkIndex, sampleIndex, samplesPerChunk);
448 "The first chunk index of a \"sample to chunk\" entry must be greather than the first chunk of the previous entry and not greather than the chunk count.", context);
451 previousChunkIndex = firstChunkIndex;
452 samplesPerChunk = get<1>(*tableIterator);
454 if(m_chunkCount >= previousChunkIndex) {
455 addChunkSizeEntries(chunkSizes, m_chunkCount + 1 - previousChunkIndex, sampleIndex, samplesPerChunk);
469 static const string context(
"parsing MPEG-4 elementary stream descriptor");
470 using namespace Mpeg4ElementaryStreamObjectIds;
471 unique_ptr<Mpeg4ElementaryStreamInfo> esInfo;
473 reader.stream()->seekg(esDescAtom->
dataOffset());
475 if(reader.readUInt32BE() != 0) {
488 reader.stream()->seekg(esDesc.dataOffset());
489 esInfo = make_unique<Mpeg4ElementaryStreamInfo>();
490 esInfo->id = reader.readUInt16BE();
491 esInfo->esDescFlags = reader.readByte();
492 if(esInfo->dependencyFlag()) {
493 esInfo->dependsOnId = reader.readUInt16BE();
495 if(esInfo->urlFlag()) {
496 esInfo->url = reader.readString(reader.readByte());
498 if(esInfo->ocrFlag()) {
499 esInfo->ocrId = reader.readUInt16BE();
501 for(
Mpeg4Descriptor *esDescChild = esDesc.
denoteFirstChild(static_cast<uint64>(reader.stream()->tellg()) - esDesc.startOffset()); esDescChild; esDescChild = esDescChild->nextSibling()) {
502 esDescChild->parse();
503 switch(esDescChild->id()) {
506 reader.stream()->seekg(esDescChild->dataOffset());
507 esInfo->objectTypeId = reader.readByte();
508 esInfo->decCfgDescFlags = reader.readByte();
509 esInfo->bufferSize = reader.readUInt24BE();
510 esInfo->maxBitrate = reader.readUInt32BE();
511 esInfo->averageBitrate = reader.readUInt32BE();
512 for(
Mpeg4Descriptor *decCfgDescChild = esDescChild->
denoteFirstChild(esDescChild->headerSize() + 13); decCfgDescChild; decCfgDescChild = decCfgDescChild->nextSibling()) {
513 decCfgDescChild->parse();
514 switch(decCfgDescChild->id()) {
517 switch(esInfo->objectTypeId) {
520 esInfo->audioSpecificConfig =
parseAudioSpecificConfig(statusProvider, *reader.stream(), decCfgDescChild->dataOffset(), decCfgDescChild->dataSize());
523 esInfo->videoSpecificConfig =
parseVideoSpecificConfig(statusProvider, reader, decCfgDescChild->dataOffset(), decCfgDescChild->dataSize());
554 static const string context(
"parsing MPEG-4 audio specific config from elementary stream descriptor");
555 using namespace Mpeg4AudioObjectIds;
557 stream.seekg(startOffset);
558 auto buff = make_unique<char []>(
size);
559 stream.read(buff.get(),
size);
560 BitReader bitReader(buff.get(),
size);
561 auto audioCfg = make_unique<Mpeg4AudioSpecificConfig>();
564 auto getAudioObjectType = [&audioCfg, &bitReader] {
565 byte objType = bitReader.readBits<byte>(5);
567 objType = 32 + bitReader.readBits<byte>(6);
571 audioCfg->audioObjectType = getAudioObjectType();
573 if((audioCfg->sampleFrequencyIndex = bitReader.readBits<byte>(4)) == 0xF) {
574 audioCfg->sampleFrequency = bitReader.readBits<uint32>(24);
577 audioCfg->channelConfiguration = bitReader.readBits<byte>(4);
579 switch(audioCfg->audioObjectType) {
582 audioCfg->extensionAudioObjectType = audioCfg->audioObjectType;
583 audioCfg->sbrPresent =
true;
584 if((audioCfg->extensionSampleFrequencyIndex = bitReader.readBits<byte>(4)) == 0xF) {
585 audioCfg->extensionSampleFrequency = bitReader.readBits<uint32>(24);
587 if((audioCfg->audioObjectType = getAudioObjectType()) ==
ErBsac) {
588 audioCfg->extensionChannelConfiguration = bitReader.readBits<byte>(4);
592 switch(audioCfg->extensionAudioObjectType) {
594 audioCfg->psPresent =
true;
599 switch(audioCfg->audioObjectType) {
603 audioCfg->frameLengthFlag = bitReader.readBits<byte>(1);
604 if((audioCfg->dependsOnCoreCoder = bitReader.readBit())) {
605 audioCfg->coreCoderDelay = bitReader.readBits<byte>(14);
607 audioCfg->extensionFlag = bitReader.readBit();
608 if(audioCfg->channelConfiguration == 0) {
611 switch(audioCfg->audioObjectType) {
613 audioCfg->layerNr = bitReader.readBits<byte>(3);
618 if(audioCfg->extensionFlag == 1) {
619 switch(audioCfg->audioObjectType) {
621 audioCfg->numOfSubFrame = bitReader.readBits<byte>(5);
622 audioCfg->layerLength = bitReader.readBits<uint16>(11);
625 audioCfg->resilienceFlags = bitReader.readBits<byte>(3);
630 if(bitReader.readBit() == 1) {
639 switch(audioCfg->audioObjectType) {
643 switch(audioCfg->epConfig = bitReader.readBits<byte>(2)) {
647 bitReader.skipBits(1);
654 if(audioCfg->extensionAudioObjectType !=
Sbr && audioCfg->extensionAudioObjectType !=
Ps && bitReader.bitsAvailable() >= 16) {
655 uint16 syncExtensionType = bitReader.readBits<uint16>(11);
656 if(syncExtensionType == 0x2B7) {
657 if((audioCfg->extensionAudioObjectType = getAudioObjectType()) ==
Sbr) {
658 if((audioCfg->sbrPresent = bitReader.readBit())) {
659 if((audioCfg->extensionSampleFrequencyIndex = bitReader.readBits<byte>(4)) == 0xF) {
660 audioCfg->extensionSampleFrequency = bitReader.readBits<uint32>(24);
662 if(bitReader.bitsAvailable() >= 12) {
663 if((syncExtensionType = bitReader.readBits<uint16>(11)) == 0x548) {
664 audioCfg->psPresent = bitReader.readBits<byte>(1);
668 }
else if(audioCfg->extensionAudioObjectType ==
ErBsac) {
669 if((audioCfg->sbrPresent = bitReader.readBit())) {
670 if((audioCfg->extensionSampleFrequencyIndex = bitReader.readBits<byte>(4)) == 0xF) {
671 audioCfg->extensionSampleFrequency = bitReader.readBits<uint32>(24);
674 audioCfg->extensionChannelConfiguration = bitReader.readBits<byte>(4);
676 }
else if (syncExtensionType == 0x548) {
677 audioCfg->psPresent = bitReader.readBit();
683 const char *what = catchIoFailure();
686 throwIoFailure(what);
703 static const string context(
"parsing MPEG-4 video specific config from elementary stream descriptor");
704 using namespace Mpeg4AudioObjectIds;
705 auto videoCfg = make_unique<Mpeg4VideoSpecificConfig>();
707 reader.stream()->seekg(startOffset);
708 if(size > 3 && (reader.readUInt24BE() == 1)) {
713 switch(reader.readByte()) {
716 videoCfg->profile = reader.readByte();
726 if((buff1 = reader.readUInt24BE()) != 1) {
727 reader.stream()->seekg(-2, ios_base::cur);
728 videoCfg->userData.push_back(buff1 >> 16);
735 if(buff1 != 1 && size > 0) {
736 videoCfg->userData += reader.readString(size);
745 if(reader.readUInt24BE() != 1) {
746 reader.stream()->seekg(-2, ios_base::cur);
782 if(oldMdatOffsets.size() == 0 || oldMdatOffsets.size() != newMdatOffsets.size()) {
785 static const unsigned int stcoDataBegin = 8;
786 uint64 startPos = m_stcoAtom->dataOffset() + stcoDataBegin;
787 uint64 endPos = startPos + m_stcoAtom->dataSize() - stcoDataBegin;
790 vector<int64>::size_type i;
791 vector<int64>::size_type
size;
793 switch(m_stcoAtom->id()) {
796 while((currentPos + 4) <= endPos) {
798 for(i = 0, size = oldMdatOffsets.size(); i <
size; ++i) {
799 if(off > static_cast<uint64>(oldMdatOffsets[i])) {
800 off += (newMdatOffsets[i] - oldMdatOffsets[i]);
811 while((currentPos + 8) <= endPos) {
813 for(i = 0, size = oldMdatOffsets.size(); i <
size; ++i) {
814 if(off > static_cast<uint64>(oldMdatOffsets[i])) {
815 off += (newMdatOffsets[i] - oldMdatOffsets[i]);
850 m_ostream->seekp(m_stcoAtom->dataOffset() + 8);
851 switch(m_stcoAtom->id()) {
853 for(
auto offset : chunkOffsets) {
858 for(
auto offset : chunkOffsets) {
886 writer().writeUInt32BE(offset);
889 writer().writeUInt64BE(offset);
940 m_tkhdAtom->makeBuffer();
943 trefAtom->makeBuffer();
946 edtsAtom->makeBuffer();
950 vmhdAtom->makeBuffer();
953 smhdAtom->makeBuffer();
956 hmhdAtom->makeBuffer();
959 nmhdAtom->makeBuffer();
962 dinfAtom->makeBuffer();
965 stblAtom->makeBuffer();
977 uint64
size = 8 + 100;
980 size += trefAtom->totalSize();
984 size += edtsAtom->totalSize();
987 size += 8 + 44 + (33 +
m_name.size()) + 8;
989 bool dinfAtomWritten =
false;
992 size += vmhdAtom->totalSize();
995 size += smhdAtom->totalSize();
998 size += hmhdAtom->totalSize();
1001 size += nmhdAtom->totalSize();
1004 size += dinfAtom->totalSize();
1005 dinfAtomWritten =
true;
1008 size += stblAtom->totalSize();
1011 if(!dinfAtomWritten) {
1028 ostream::pos_type trakStartOffset =
outputStream().tellp();
1053 writer().writeUInt32BE(100);
1066 writer().writeUInt24BE(flags);
1070 writer().writeUInt32BE(0);
1072 writer().writeUInt32BE(0);
1073 writer().writeUInt32BE(0);
1076 if(m_tkhdAtom->buffer()) {
1077 m_ostream->write(m_tkhdAtom->buffer().get() + 52, 48);
1080 m_istream->seekg(m_tkhdAtom->startOffset() + 52);
1081 m_istream->read(buffer,
sizeof(buffer));
1082 m_ostream->write(buffer,
sizeof(buffer));
1086 writer().writeInt16BE(0);
1087 writer().writeInt16BE(0);
1088 writer().writeFixed8BE(1.0);
1089 writer().writeUInt16BE(0);
1090 for(
const int32 value : {0x00010000,0,0,0,0x00010000,0,0,0,0x40000000}) {
1091 writer().writeInt32BE(value);
1093 writer().writeFixed16BE(1.0);
1094 writer().writeFixed16BE(1.0);
1104 ostream::pos_type mdiaStartOffset =
outputStream().tellp();
1105 writer().writeUInt32BE(0);
1108 writer().writeUInt32BE(44);
1111 writer().writeUInt24BE(0);
1118 for(
size_t charIndex = 0; charIndex != 3; ++charIndex) {
1120 if(langChar >=
'a' && langChar <=
'z') {
1121 language |=
static_cast<uint16
>(langChar - 0x60) << (0xA - charIndex * 0x5);
1131 writer().writeUInt16BE(language);
1132 writer().writeUInt16BE(0);
1136 writer().writeUInt64BE(0);
1155 for(
int i = 0; i < 3; ++i)
writer().writeUInt32BE(0);
1169 ostream::pos_type minfStartOffset =
outputStream().tellp();
1170 writer().writeUInt32BE(0);
1172 bool dinfAtomWritten =
false;
1193 dinfAtomWritten =
true;
1197 if(!dinfAtomWritten) {
1198 writer().writeUInt32BE(36);
1201 writer().writeUInt32BE(28);
1203 writer().writeUInt32BE(0);
1204 writer().writeUInt32BE(1);
1206 writer().writeUInt32BE(12);
1209 writer().writeUInt24BE(0x000001);
1213 bool stblAtomWritten =
false;
1217 stblAtomWritten =
true;
1220 if(!stblAtomWritten) {
1234 ostream::pos_type stblStartOffset =
outputStream().tellp();
1235 writer().writeUInt32BE(0);
1293 static const string context(
"parsing MP4 track");
1294 using namespace Mp4AtomIds;
1302 if(!(m_tkhdAtom = m_trakAtom->childById(
TrackHeader))) {
1306 if(!(m_mdiaAtom = m_trakAtom->childById(
Media))) {
1310 if(!(m_mdhdAtom = m_mdiaAtom->childById(
MediaHeader))) {
1322 if(!(m_stblAtom = m_minfAtom->childById(
SampleTable))) {
1347 BinaryReader &
reader = m_trakAtom->reader();
1350 m_istream->seekg(m_tkhdAtom->startOffset() + 8);
1351 byte atomVersion = reader.readByte();
1352 uint32 flags = reader.readUInt24BE();
1356 switch(atomVersion) {
1358 m_creationTime = startDate + TimeSpan::fromSeconds(reader.readUInt32BE());
1360 m_id = reader.readUInt32BE();
1363 m_creationTime = startDate + TimeSpan::fromSeconds(reader.readUInt64BE());
1364 m_modificationTime = startDate + TimeSpan::fromSeconds(reader.readUInt64BE());
1365 m_id = reader.readUInt32BE();
1375 m_istream->seekg(m_mdhdAtom->dataOffset());
1376 atomVersion = reader.readByte();
1378 switch(atomVersion) {
1380 m_creationTime = startDate + TimeSpan::fromSeconds(reader.readUInt32BE());
1383 m_duration = TimeSpan::fromSeconds(static_cast<double>(reader.readUInt32BE()) / static_cast<double>(m_timeScale));
1386 m_creationTime = startDate + TimeSpan::fromSeconds(reader.readUInt64BE());
1387 m_modificationTime = startDate + TimeSpan::fromSeconds(reader.readUInt64BE());
1388 m_timeScale = reader.readUInt32BE();
1389 m_duration = TimeSpan::fromSeconds(static_cast<double>(reader.readUInt64BE()) / static_cast<double>(m_timeScale));
1392 addNotification(
NotificationType::Warning,
"Version of \"mdhd\"-atom not supported. It will be ignored. Creation time, modification time, time scale and duration might not be determined.", context);
1396 uint16 tmp = reader.readUInt16BE();
1398 const char buff[] = {
1399 static_cast<char>(((tmp & 0x7C00) >> 0xA) + 0x60),
1400 static_cast<char>(((tmp & 0x03E0) >> 0x5) + 0x60),
1401 static_cast<char>(((tmp & 0x001F) >> 0x0) + 0x60),
1410 m_istream->seekg(m_hdlrAtom->dataOffset() + 8);
1412 switch(reader.readUInt32BE()) {
1422 case 0x6D657461:
case 0x74657874:
1430 if((tmp =
m_istream->peek()) == m_hdlrAtom->dataSize() - 12 - 4 - 8 - 1) {
1433 m_name = reader.readString(tmp);
1436 m_name = reader.readTerminatedString(m_hdlrAtom->dataSize() - 12 - 4 - 8, 0);
1441 m_istream->seekg(m_stcoAtom->dataOffset() + 4);
1442 m_chunkCount = reader.readUInt32BE();
1445 m_istream->seekg(m_stsdAtom->dataOffset() + 4);
1446 uint32 entryCount = reader.readUInt32BE();
1447 Mp4Atom *esDescParentAtom =
nullptr;
1448 if(entryCount > 0) {
1450 for(
Mp4Atom *codecConfigContainerAtom = m_stsdAtom->
firstChild(); codecConfigContainerAtom; codecConfigContainerAtom = codecConfigContainerAtom->nextSibling()) {
1451 codecConfigContainerAtom->
parse();
1453 m_formatId = interpretIntegerAsString<uint32>(codecConfigContainerAtom->id());
1456 m_istream->seekg(codecConfigContainerAtom->dataOffset());
1457 switch(codecConfigContainerAtom->id()) {
1463 tmp = reader.readUInt16BE();
1479 codecConfigContainerAtom->denoteFirstChild(codecConfigContainerAtom->headerSize() + 28 + 16);
1482 codecConfigContainerAtom->denoteFirstChild(codecConfigContainerAtom->headerSize() + 28 + 32);
1485 codecConfigContainerAtom->denoteFirstChild(codecConfigContainerAtom->headerSize() + 28);
1487 if(!esDescParentAtom) {
1488 esDescParentAtom = codecConfigContainerAtom;
1495 m_istream->seekg(6 + 2 + 16, ios_base::cur);
1501 m_framesPerSample = reader.readUInt16BE();
1502 tmp = reader.readByte();
1506 }
else if(tmp < 32) {
1509 m_depth = reader.readUInt16BE();
1510 codecConfigContainerAtom->denoteFirstChild(codecConfigContainerAtom->headerSize() + 78);
1511 if(!esDescParentAtom) {
1512 esDescParentAtom = codecConfigContainerAtom;
1517 codecConfigContainerAtom->denoteFirstChild(codecConfigContainerAtom->headerSize() + 8);
1518 if(!esDescParentAtom) {
1519 esDescParentAtom = codecConfigContainerAtom;
1531 if(esDescParentAtom) {
1534 m_istream->seekg(avcConfigAtom->dataOffset());
1535 m_avcConfig = make_unique<Media::AvcConfiguration>();
1537 m_avcConfig->parse(reader, avcConfigAtom->dataSize());
1555 m_bitrate =
static_cast<double>(m_esInfo->averageBitrate) / 1000;
1556 m_maxBitrate =
static_cast<double>(m_esInfo->maxBitrate) / 1000;
1557 if(m_esInfo->audioSpecificConfig) {
1560 if(m_esInfo->audioSpecificConfig->sampleFrequencyIndex == 0xF) {
1567 if(m_esInfo->audioSpecificConfig->extensionSampleFrequencyIndex == 0xF) {
1574 m_channelConfig = m_esInfo->audioSpecificConfig->channelConfiguration;
1577 if(m_esInfo->videoSpecificConfig) {
1580 m_format.
sub = m_esInfo->videoSpecificConfig->profile;
1581 if(!m_esInfo->videoSpecificConfig->userData.empty()) {
1583 m_formatId += m_esInfo->videoSpecificConfig->userData;
1591 m_istream->seekg(m_stcoAtom->dataOffset() + 8);
1592 m_istream->seekg(m_chunkOffsetSize == 8 ? reader.readUInt64BE() : reader.readUInt32BE());
1610 m_sampleSizes.clear();
1612 uint64 actualSampleSizeTableSize = m_stszAtom->dataSize();
1613 if(actualSampleSizeTableSize < 12) {
1616 actualSampleSizeTableSize -= 12;
1617 m_istream->seekg(m_stszAtom->dataOffset() + 4);
1619 uint32 constantSize;
1623 fieldSize = reader.readByte();
1626 constantSize = reader.readUInt32BE();
1631 m_sampleSizes.push_back(constantSize);
1635 uint64 calculatedSampleSizeTableSize = ceil((0.125 * fieldSize) *
m_sampleCount);
1636 if(calculatedSampleSizeTableSize < actualSampleSizeTableSize) {
1638 }
else if(calculatedSampleSizeTableSize > actualSampleSizeTableSize) {
1640 actualSampleCount = floor(static_cast<double>(actualSampleSizeTableSize) / (0.125 * fieldSize));
1642 m_sampleSizes.reserve(actualSampleCount);
1646 for(; i <= actualSampleCount; i += 2) {
1647 byte val = reader.readByte();
1648 m_sampleSizes.push_back(val >> 4);
1649 m_sampleSizes.push_back(val & 0xF0);
1650 m_size += (val >> 4) + (val & 0xF0);
1652 if(i <= actualSampleCount + 1) {
1653 m_sampleSizes.push_back(reader.readByte() >> 4);
1654 m_size += m_sampleSizes.back();
1658 for(; i <= actualSampleCount; ++i) {
1659 m_sampleSizes.push_back(reader.readByte());
1660 m_size += m_sampleSizes.back();
1664 for(; i <= actualSampleCount; ++i) {
1665 m_sampleSizes.push_back(reader.readUInt16BE());
1666 m_size += m_sampleSizes.back();
1670 for(; i <= actualSampleCount; ++i) {
1671 m_sampleSizes.push_back(reader.readUInt32BE());
1672 m_size += m_sampleSizes.back();
1682 uint64 totalDuration = 0;
1689 uint32 calculatedDataSize = 0;
1690 if(tfhdAtom->dataSize() < calculatedDataSize) {
1693 m_istream->seekg(tfhdAtom->dataOffset() + 1);
1694 uint32 flags = reader.readUInt24BE();
1695 if(
m_id == reader.readUInt32BE()) {
1696 if(flags & 0x000001) {
1697 calculatedDataSize += 8;
1699 if(flags & 0x000002) {
1700 calculatedDataSize += 4;
1702 if(flags & 0x000008) {
1703 calculatedDataSize += 4;
1705 if(flags & 0x000010) {
1706 calculatedDataSize += 4;
1708 if(flags & 0x000020) {
1709 calculatedDataSize += 4;
1713 uint32 defaultSampleDuration = 0;
1714 uint32 defaultSampleSize = 0;
1716 if(tfhdAtom->dataSize() < calculatedDataSize) {
1719 if(flags & 0x000001) {
1723 if(flags & 0x000002) {
1727 if(flags & 0x000008) {
1728 defaultSampleDuration = reader.readUInt32BE();
1731 if(flags & 0x000010) {
1732 defaultSampleSize = reader.readUInt32BE();
1734 if(flags & 0x000020) {
1740 uint32 calculatedDataSize = 8;
1741 if(trunAtom->dataSize() < calculatedDataSize) {
1744 m_istream->seekg(trunAtom->dataOffset() + 1);
1745 uint32 flags = reader.readUInt24BE();
1746 uint32 sampleCount = reader.readUInt32BE();
1748 if(flags & 0x000001) {
1749 calculatedDataSize += 4;
1751 if(flags & 0x000004) {
1752 calculatedDataSize += 4;
1754 uint32 entrySize = 0;
1755 if(flags & 0x000100) {
1758 if(flags & 0x000200) {
1761 if(flags & 0x000400) {
1764 if(flags & 0x000800) {
1768 if(trunAtom->dataSize() < calculatedDataSize) {
1771 if(flags & 0x000001) {
1775 if(flags & 0x000004) {
1779 if(flags & 0x000100) {
1780 totalDuration += reader.readUInt32BE();
1782 totalDuration += defaultSampleDuration;
1784 if(flags & 0x000200) {
1785 m_sampleSizes.push_back(reader.readUInt32BE());
1786 m_size += m_sampleSizes.back();
1788 m_size += defaultSampleSize;
1790 if(flags & 0x000400) {
1793 if(flags & 0x000800) {
1800 if(m_sampleSizes.empty() && defaultSampleSize) {
1801 m_sampleSizes.push_back(defaultSampleSize);
1816 m_duration = TimeSpan::fromSeconds(static_cast<double>(totalDuration) / static_cast<double>(timeScale));
1821 if(m_bitrate < 0.01 && m_bitrate > -0.01) {
1826 m_istream->seekg(m_stscAtom->dataOffset() + 4);
1827 m_sampleToChunkEntryCount = reader.readUInt32BE();
Contains utility classes helping to read and write streams.