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)
135 static const string context(
"reading chunk offset table of MP4 track");
140 vector<uint64> offsets;
143 uint64 actualTableSize = m_stcoAtom->
dataSize();
148 actualTableSize -= 8;
152 if(calculatedTableSize < actualTableSize) {
154 }
else if(calculatedTableSize > actualTableSize) {
156 actualChunkCount = floor(static_cast<double>(actualTableSize) / static_cast<double>(
chunkOffsetSize()));
159 offsets.reserve(actualChunkCount);
163 for(uint32 i = 0; i < actualChunkCount; ++i) {
164 offsets.push_back(
reader().readUInt32BE());
168 for(uint32 i = 0; i < actualChunkCount; ++i) {
169 offsets.push_back(
reader().readUInt64BE());
319 uint64 Mp4Track::accumulateSampleSizes(
size_t &sampleIndex,
size_t count)
321 if(sampleIndex + count <= m_sampleSizes.size()) {
323 for(
size_t end = sampleIndex + count; sampleIndex < end; ++sampleIndex) {
324 sum += m_sampleSizes[sampleIndex];
327 }
else if(m_sampleSizes.size() == 1) {
328 sampleIndex += count;
329 return static_cast<uint64
>(m_sampleSizes.front()) * count;
344 void Mp4Track::addChunkSizeEntries(std::vector<uint64> &chunkSizeTable,
size_t count,
size_t &sampleIndex, uint32
sampleCount)
346 for(
size_t i = 0; i < count; ++i) {
347 chunkSizeTable.push_back(accumulateSampleSizes(sampleIndex, sampleCount));
360 static const string context(
"reading sample to chunk table of MP4 track");
366 uint64 actualTableSize = m_stscAtom->
dataSize();
367 if(actualTableSize < 20) {
371 actualTableSize -= 8;
374 uint64 calculatedTableSize = actualSampleToChunkEntryCount * 12;
375 if(calculatedTableSize < actualTableSize) {
377 }
else if(calculatedTableSize > actualTableSize) {
379 actualSampleToChunkEntryCount = floor(static_cast<double>(actualTableSize) / 12.0);
382 vector<tuple<uint32, uint32, uint32> > sampleToChunkTable;
383 sampleToChunkTable.reserve(actualSampleToChunkEntryCount);
385 for(uint32 i = 0; i < actualSampleToChunkEntryCount; ++i) {
387 uint32 firstChunk =
reader().readUInt32BE();
388 uint32 samplesPerChunk =
reader().readUInt32BE();
389 uint32 sampleDescriptionIndex =
reader().readUInt32BE();
390 sampleToChunkTable.emplace_back(firstChunk, samplesPerChunk, sampleDescriptionIndex);
392 return sampleToChunkTable;
409 static const string context(
"reading chunk sizes of MP4 track");
417 vector<uint64> chunkSizes;
418 if(!sampleToChunkTable.empty()) {
420 auto tableIterator = sampleToChunkTable.cbegin();
421 chunkSizes.reserve(m_chunkCount);
423 size_t sampleIndex = 0;
424 uint32 previousChunkIndex = get<0>(*tableIterator);
425 if(previousChunkIndex != 1) {
427 previousChunkIndex = 1;
429 uint32 samplesPerChunk = get<1>(*tableIterator);
432 for(
const auto tableEnd = sampleToChunkTable.cend(); tableIterator != tableEnd; ++tableIterator) {
433 uint32 firstChunkIndex = get<0>(*tableIterator);
434 if(firstChunkIndex > previousChunkIndex && firstChunkIndex <= m_chunkCount) {
435 addChunkSizeEntries(chunkSizes, firstChunkIndex - previousChunkIndex, sampleIndex, samplesPerChunk);
438 "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);
441 previousChunkIndex = firstChunkIndex;
442 samplesPerChunk = get<1>(*tableIterator);
444 if(m_chunkCount >= previousChunkIndex) {
445 addChunkSizeEntries(chunkSizes, m_chunkCount + 1 - previousChunkIndex, sampleIndex, samplesPerChunk);
459 static const string context(
"parsing MPEG-4 elementary stream descriptor");
460 using namespace Mpeg4ElementaryStreamObjectIds;
461 unique_ptr<Mpeg4ElementaryStreamInfo> esInfo;
463 reader.stream()->seekg(esDescAtom->
dataOffset());
465 if(reader.readUInt32BE() != 0) {
478 reader.stream()->seekg(esDesc.dataOffset());
479 esInfo = make_unique<Mpeg4ElementaryStreamInfo>();
480 esInfo->id = reader.readUInt16BE();
481 esInfo->esDescFlags = reader.readByte();
482 if(esInfo->dependencyFlag()) {
483 esInfo->dependsOnId = reader.readUInt16BE();
485 if(esInfo->urlFlag()) {
486 esInfo->url = reader.readString(reader.readByte());
488 if(esInfo->ocrFlag()) {
489 esInfo->ocrId = reader.readUInt16BE();
491 for(
Mpeg4Descriptor *esDescChild = esDesc.
denoteFirstChild(static_cast<uint64>(reader.stream()->tellg()) - esDesc.startOffset()); esDescChild; esDescChild = esDescChild->nextSibling()) {
492 esDescChild->parse();
493 switch(esDescChild->id()) {
496 reader.stream()->seekg(esDescChild->dataOffset());
497 esInfo->objectTypeId = reader.readByte();
498 esInfo->decCfgDescFlags = reader.readByte();
499 esInfo->bufferSize = reader.readUInt24BE();
500 esInfo->maxBitrate = reader.readUInt32BE();
501 esInfo->averageBitrate = reader.readUInt32BE();
502 for(
Mpeg4Descriptor *decCfgDescChild = esDescChild->
denoteFirstChild(esDescChild->headerSize() + 13); decCfgDescChild; decCfgDescChild = decCfgDescChild->nextSibling()) {
503 decCfgDescChild->parse();
504 switch(decCfgDescChild->id()) {
507 switch(esInfo->objectTypeId) {
510 esInfo->audioSpecificConfig =
parseAudioSpecificConfig(statusProvider, *reader.stream(), decCfgDescChild->dataOffset(), decCfgDescChild->dataSize());
513 esInfo->videoSpecificConfig =
parseVideoSpecificConfig(statusProvider, reader, decCfgDescChild->dataOffset(), decCfgDescChild->dataSize());
544 static const string context(
"parsing MPEG-4 audio specific config from elementary stream descriptor");
545 using namespace Mpeg4AudioObjectIds;
547 stream.seekg(startOffset);
548 auto buff = make_unique<char []>(
size);
549 stream.read(buff.get(),
size);
550 BitReader bitReader(buff.get(),
size);
551 auto audioCfg = make_unique<Mpeg4AudioSpecificConfig>();
554 auto getAudioObjectType = [&audioCfg, &bitReader] {
555 byte objType = bitReader.readBits<byte>(5);
557 objType = 32 + bitReader.readBits<byte>(6);
561 audioCfg->audioObjectType = getAudioObjectType();
563 if((audioCfg->sampleFrequencyIndex = bitReader.readBits<byte>(4)) == 0xF) {
564 audioCfg->sampleFrequency = bitReader.readBits<uint32>(24);
567 audioCfg->channelConfiguration = bitReader.readBits<byte>(4);
569 switch(audioCfg->audioObjectType) {
572 audioCfg->extensionAudioObjectType = audioCfg->audioObjectType;
573 audioCfg->sbrPresent =
true;
574 if((audioCfg->extensionSampleFrequencyIndex = bitReader.readBits<byte>(4)) == 0xF) {
575 audioCfg->extensionSampleFrequency = bitReader.readBits<uint32>(24);
577 if((audioCfg->audioObjectType = getAudioObjectType()) ==
ErBsac) {
578 audioCfg->extensionChannelConfiguration = bitReader.readBits<byte>(4);
582 switch(audioCfg->extensionAudioObjectType) {
584 audioCfg->psPresent =
true;
589 switch(audioCfg->audioObjectType) {
593 audioCfg->frameLengthFlag = bitReader.readBits<byte>(1);
594 if((audioCfg->dependsOnCoreCoder = bitReader.readBit())) {
595 audioCfg->coreCoderDelay = bitReader.readBits<byte>(14);
597 audioCfg->extensionFlag = bitReader.readBit();
598 if(audioCfg->channelConfiguration == 0) {
601 switch(audioCfg->audioObjectType) {
603 audioCfg->layerNr = bitReader.readBits<byte>(3);
608 if(audioCfg->extensionFlag == 1) {
609 switch(audioCfg->audioObjectType) {
611 audioCfg->numOfSubFrame = bitReader.readBits<byte>(5);
612 audioCfg->layerLength = bitReader.readBits<uint16>(11);
615 audioCfg->resilienceFlags = bitReader.readBits<byte>(3);
620 if(bitReader.readBit() == 1) {
629 switch(audioCfg->audioObjectType) {
633 switch(audioCfg->epConfig = bitReader.readBits<byte>(2)) {
637 bitReader.skipBits(1);
644 if(audioCfg->extensionAudioObjectType !=
Sbr && audioCfg->extensionAudioObjectType !=
Ps && bitReader.bitsAvailable() >= 16) {
645 uint16 syncExtensionType = bitReader.readBits<uint16>(11);
646 if(syncExtensionType == 0x2B7) {
647 if((audioCfg->extensionAudioObjectType = getAudioObjectType()) ==
Sbr) {
648 if((audioCfg->sbrPresent = bitReader.readBit())) {
649 if((audioCfg->extensionSampleFrequencyIndex = bitReader.readBits<byte>(4)) == 0xF) {
650 audioCfg->extensionSampleFrequency = bitReader.readBits<uint32>(24);
652 if(bitReader.bitsAvailable() >= 12) {
653 if((syncExtensionType = bitReader.readBits<uint16>(11)) == 0x548) {
654 audioCfg->psPresent = bitReader.readBits<byte>(1);
658 }
else if(audioCfg->extensionAudioObjectType ==
ErBsac) {
659 if((audioCfg->sbrPresent = bitReader.readBit())) {
660 if((audioCfg->extensionSampleFrequencyIndex = bitReader.readBits<byte>(4)) == 0xF) {
661 audioCfg->extensionSampleFrequency = bitReader.readBits<uint32>(24);
664 audioCfg->extensionChannelConfiguration = bitReader.readBits<byte>(4);
666 }
else if (syncExtensionType == 0x548) {
667 audioCfg->psPresent = bitReader.readBit();
673 const char *what = catchIoFailure();
676 throwIoFailure(what);
693 static const string context(
"parsing MPEG-4 video specific config from elementary stream descriptor");
694 using namespace Mpeg4AudioObjectIds;
695 auto videoCfg = make_unique<Mpeg4VideoSpecificConfig>();
697 reader.stream()->seekg(startOffset);
698 if(size > 3 && (reader.readUInt24BE() == 1)) {
703 switch(reader.readByte()) {
706 videoCfg->profile = reader.readByte();
716 if((buff1 = reader.readUInt24BE()) != 1) {
717 reader.stream()->seekg(-2, ios_base::cur);
718 videoCfg->userData.push_back(buff1 >> 16);
725 if(buff1 != 1 && size > 0) {
726 videoCfg->userData += reader.readString(size);
735 if(reader.readUInt24BE() != 1) {
736 reader.stream()->seekg(-2, ios_base::cur);
772 if(oldMdatOffsets.size() == 0 || oldMdatOffsets.size() != newMdatOffsets.size()) {
775 static const unsigned int stcoDataBegin = 8;
776 uint64 startPos = m_stcoAtom->dataOffset() + stcoDataBegin;
777 uint64 endPos = startPos + m_stcoAtom->dataSize() - stcoDataBegin;
780 vector<int64>::size_type i;
781 vector<int64>::size_type
size;
783 switch(m_stcoAtom->id()) {
786 while((currentPos + 4) <= endPos) {
788 for(i = 0, size = oldMdatOffsets.size(); i <
size; ++i) {
789 if(off > static_cast<uint64>(oldMdatOffsets[i])) {
790 off += (newMdatOffsets[i] - oldMdatOffsets[i]);
801 while((currentPos + 8) <= endPos) {
803 for(i = 0, size = oldMdatOffsets.size(); i <
size; ++i) {
804 if(off > static_cast<uint64>(oldMdatOffsets[i])) {
805 off += (newMdatOffsets[i] - oldMdatOffsets[i]);
840 m_ostream->seekp(m_stcoAtom->dataOffset() + 8);
841 switch(m_stcoAtom->id()) {
843 for(
auto offset : chunkOffsets) {
848 for(
auto offset : chunkOffsets) {
876 writer().writeUInt32BE(offset);
879 writer().writeUInt64BE(offset);
956 return m_trakAtom->totalSize();
965 writer().writeUInt32BE(100);
978 writer().writeUInt24BE(flags);
982 writer().writeUInt32BE(0);
984 writer().writeUInt32BE(0);
985 writer().writeUInt32BE(0);
989 m_istream->seekg(m_tkhdAtom->startOffset() + 52);
991 m_ostream->write(buffer,
sizeof(buffer));
996 writer().writeFixed8BE(1.0);
997 writer().writeUInt16BE(0);
998 for(int32 value : {0x00010000,0,0,0,0x00010000,0,0,0,0x40000000}) {
999 writer().writeInt32BE(value);
1001 writer().writeFixed16BE(1.0);
1002 writer().writeFixed16BE(1.0);
1012 ostream::pos_type mdiaStartOffset =
outputStream().tellp();
1013 writer().writeUInt32BE(0);
1016 writer().writeUInt32BE(36);
1018 writer().writeUInt24BE(0);
1025 for(
size_t charIndex = 0; charIndex <
m_language.length() && charIndex < 3; ++charIndex) {
1027 language |=
static_cast<uint16
>(
m_language[charIndex]) << (0xA - charIndex * 0x5);
1034 writer().writeUInt16BE(language);
1035 writer().writeUInt16BE(0);
1039 writer().writeUInt64BE(0);
1058 for(
int i = 0; i < 3; ++i)
writer().writeUInt32BE(0);
1072 ostream::pos_type minfStartOffset =
outputStream().tellp();
1073 writer().writeUInt32BE(0);
1075 bool dinfAtomWritten =
false;
1096 dinfAtomWritten =
true;
1100 if(!dinfAtomWritten) {
1101 writer().writeUInt32BE(36);
1104 writer().writeUInt32BE(28);
1106 writer().writeUInt32BE(0);
1107 writer().writeUInt32BE(1);
1109 writer().writeUInt32BE(12);
1112 writer().writeUInt24BE(0x000001);
1127 ostream::pos_type stblStartOffset =
outputStream().tellp();
1128 writer().writeUInt32BE(0);
1185 static const string context(
"parsing MP4 track");
1186 using namespace Mp4AtomIds;
1194 if(!(m_tkhdAtom = m_trakAtom->childById(
TrackHeader))) {
1198 if(!(m_mdiaAtom = m_trakAtom->childById(
Media))) {
1202 if(!(m_mdhdAtom = m_mdiaAtom->childById(
MediaHeader))) {
1214 if(!(m_stblAtom = m_minfAtom->childById(
SampleTable))) {
1239 BinaryReader &
reader = m_trakAtom->reader();
1242 m_istream->seekg(m_tkhdAtom->startOffset() + 8);
1243 byte atomVersion = reader.readByte();
1244 uint32 flags = reader.readUInt24BE();
1248 switch(atomVersion) {
1250 m_creationTime = startDate + TimeSpan::fromSeconds(reader.readUInt32BE());
1252 m_id = reader.readUInt32BE();
1255 m_creationTime = startDate + TimeSpan::fromSeconds(reader.readUInt64BE());
1256 m_modificationTime = startDate + TimeSpan::fromSeconds(reader.readUInt64BE());
1257 m_id = reader.readUInt32BE();
1267 m_istream->seekg(m_mdhdAtom->dataOffset());
1268 atomVersion = reader.readByte();
1270 switch(atomVersion) {
1272 m_creationTime = startDate + TimeSpan::fromSeconds(reader.readUInt32BE());
1275 m_duration = TimeSpan::fromSeconds(static_cast<double>(reader.readUInt32BE()) / static_cast<double>(m_timeScale));
1278 m_creationTime = startDate + TimeSpan::fromSeconds(reader.readUInt64BE());
1279 m_modificationTime = startDate + TimeSpan::fromSeconds(reader.readUInt64BE());
1280 m_timeScale = reader.readUInt32BE();
1281 m_duration = TimeSpan::fromSeconds(static_cast<double>(reader.readUInt64BE()) / static_cast<double>(m_timeScale));
1284 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);
1288 uint16 tmp = reader.readUInt16BE();
1291 buff[0] = ((tmp & 0x7C00) >> 0xA) + 0x60;
1292 buff[1] = ((tmp & 0x03E0) >> 0x5) + 0x60;
1293 buff[2] = ((tmp & 0x001F) >> 0x0) + 0x60;
1301 m_istream->seekg(m_hdlrAtom->dataOffset() + 8);
1303 switch(reader.readUInt32BE()) {
1313 case 0x6D657461:
case 0x74657874:
1321 if((tmp =
m_istream->peek()) == m_hdlrAtom->dataSize() - 12 - 4 - 8 - 1) {
1324 m_name = reader.readString(tmp);
1327 m_name = reader.readTerminatedString(m_hdlrAtom->dataSize() - 12 - 4 - 8, 0);
1332 m_istream->seekg(m_stcoAtom->dataOffset() + 4);
1333 m_chunkCount = reader.readUInt32BE();
1336 m_istream->seekg(m_stsdAtom->dataOffset() + 4);
1337 uint32 entryCount = reader.readUInt32BE();
1338 Mp4Atom *esDescParentAtom =
nullptr;
1339 if(entryCount > 0) {
1341 for(
Mp4Atom *codecConfigContainerAtom = m_stsdAtom->
firstChild(); codecConfigContainerAtom; codecConfigContainerAtom = codecConfigContainerAtom->nextSibling()) {
1342 codecConfigContainerAtom->
parse();
1344 m_formatId = interpretIntegerAsString<uint32>(codecConfigContainerAtom->id());
1347 m_istream->seekg(codecConfigContainerAtom->dataOffset());
1348 switch(codecConfigContainerAtom->id()) {
1354 tmp = reader.readUInt16BE();
1370 codecConfigContainerAtom->denoteFirstChild(codecConfigContainerAtom->headerSize() + 28 + 16);
1373 codecConfigContainerAtom->denoteFirstChild(codecConfigContainerAtom->headerSize() + 28 + 32);
1376 codecConfigContainerAtom->denoteFirstChild(codecConfigContainerAtom->headerSize() + 28);
1378 if(!esDescParentAtom) {
1379 esDescParentAtom = codecConfigContainerAtom;
1386 m_istream->seekg(6 + 2 + 16, ios_base::cur);
1392 m_framesPerSample = reader.readUInt16BE();
1393 tmp = reader.readByte();
1397 }
else if(tmp < 32) {
1400 m_depth = reader.readUInt16BE();
1401 codecConfigContainerAtom->denoteFirstChild(codecConfigContainerAtom->headerSize() + 78);
1402 if(!esDescParentAtom) {
1403 esDescParentAtom = codecConfigContainerAtom;
1408 codecConfigContainerAtom->denoteFirstChild(codecConfigContainerAtom->headerSize() + 8);
1409 if(!esDescParentAtom) {
1410 esDescParentAtom = codecConfigContainerAtom;
1422 if(esDescParentAtom) {
1425 m_istream->seekg(avcConfigAtom->dataOffset());
1426 m_avcConfig = make_unique<Media::AvcConfiguration>();
1428 m_avcConfig->parse(reader, avcConfigAtom->dataSize());
1446 m_bitrate =
static_cast<double>(m_esInfo->averageBitrate) / 1000;
1447 m_maxBitrate =
static_cast<double>(m_esInfo->maxBitrate) / 1000;
1448 if(m_esInfo->audioSpecificConfig) {
1451 if(m_esInfo->audioSpecificConfig->sampleFrequencyIndex == 0xF) {
1458 if(m_esInfo->audioSpecificConfig->extensionSampleFrequencyIndex == 0xF) {
1465 m_channelConfig = m_esInfo->audioSpecificConfig->channelConfiguration;
1468 if(m_esInfo->videoSpecificConfig) {
1471 m_format.
sub = m_esInfo->videoSpecificConfig->profile;
1472 if(!m_esInfo->videoSpecificConfig->userData.empty()) {
1474 m_formatId += m_esInfo->videoSpecificConfig->userData;
1482 m_istream->seekg(m_stcoAtom->dataOffset() + 8);
1483 m_istream->seekg(m_chunkOffsetSize == 8 ? reader.readUInt64BE() : reader.readUInt32BE());
1501 m_sampleSizes.clear();
1503 uint64 actualSampleSizeTableSize = m_stszAtom->dataSize();
1504 if(actualSampleSizeTableSize < 12) {
1507 actualSampleSizeTableSize -= 12;
1508 m_istream->seekg(m_stszAtom->dataOffset() + 4);
1510 uint32 constantSize;
1514 fieldSize = reader.readByte();
1517 constantSize = reader.readUInt32BE();
1522 m_sampleSizes.push_back(constantSize);
1526 uint64 calculatedSampleSizeTableSize = ceil((0.125 * fieldSize) *
m_sampleCount);
1527 if(calculatedSampleSizeTableSize < actualSampleSizeTableSize) {
1529 }
else if(calculatedSampleSizeTableSize > actualSampleSizeTableSize) {
1531 actualSampleCount = floor(static_cast<double>(actualSampleSizeTableSize) / (0.125 * fieldSize));
1533 m_sampleSizes.reserve(actualSampleCount);
1537 for(; i <= actualSampleCount; i += 2) {
1538 byte val = reader.readByte();
1539 m_sampleSizes.push_back(val >> 4);
1540 m_sampleSizes.push_back(val & 0xF0);
1541 m_size += (val >> 4) + (val & 0xF0);
1543 if(i <= actualSampleCount + 1) {
1544 m_sampleSizes.push_back(reader.readByte() >> 4);
1545 m_size += m_sampleSizes.back();
1549 for(; i <= actualSampleCount; ++i) {
1550 m_sampleSizes.push_back(reader.readByte());
1551 m_size += m_sampleSizes.back();
1555 for(; i <= actualSampleCount; ++i) {
1556 m_sampleSizes.push_back(reader.readUInt16BE());
1557 m_size += m_sampleSizes.back();
1561 for(; i <= actualSampleCount; ++i) {
1562 m_sampleSizes.push_back(reader.readUInt32BE());
1563 m_size += m_sampleSizes.back();
1573 uint64 totalDuration = 0;
1580 uint32 calculatedDataSize = 0;
1581 if(tfhdAtom->dataSize() < calculatedDataSize) {
1584 m_istream->seekg(tfhdAtom->dataOffset() + 1);
1585 uint32 flags = reader.readUInt24BE();
1586 if(
m_id == reader.readUInt32BE()) {
1587 if(flags & 0x000001) {
1588 calculatedDataSize += 8;
1590 if(flags & 0x000002) {
1591 calculatedDataSize += 4;
1593 if(flags & 0x000008) {
1594 calculatedDataSize += 4;
1596 if(flags & 0x000010) {
1597 calculatedDataSize += 4;
1599 if(flags & 0x000020) {
1600 calculatedDataSize += 4;
1604 uint32 defaultSampleDuration = 0;
1605 uint32 defaultSampleSize = 0;
1607 if(tfhdAtom->dataSize() < calculatedDataSize) {
1610 if(flags & 0x000001) {
1614 if(flags & 0x000002) {
1618 if(flags & 0x000008) {
1619 defaultSampleDuration = reader.readUInt32BE();
1622 if(flags & 0x000010) {
1623 defaultSampleSize = reader.readUInt32BE();
1625 if(flags & 0x000020) {
1631 uint32 calculatedDataSize = 8;
1632 if(trunAtom->dataSize() < calculatedDataSize) {
1635 m_istream->seekg(trunAtom->dataOffset() + 1);
1636 uint32 flags = reader.readUInt24BE();
1637 uint32 sampleCount = reader.readUInt32BE();
1639 if(flags & 0x000001) {
1640 calculatedDataSize += 4;
1642 if(flags & 0x000004) {
1643 calculatedDataSize += 4;
1645 uint32 entrySize = 0;
1646 if(flags & 0x000100) {
1649 if(flags & 0x000200) {
1652 if(flags & 0x000400) {
1655 if(flags & 0x000800) {
1659 if(trunAtom->dataSize() < calculatedDataSize) {
1662 if(flags & 0x000001) {
1666 if(flags & 0x000004) {
1670 if(flags & 0x000100) {
1671 totalDuration += reader.readUInt32BE();
1673 totalDuration += defaultSampleDuration;
1675 if(flags & 0x000200) {
1676 m_sampleSizes.push_back(reader.readUInt32BE());
1677 m_size += m_sampleSizes.back();
1679 m_size += defaultSampleSize;
1681 if(flags & 0x000400) {
1684 if(flags & 0x000800) {
1691 if(m_sampleSizes.empty() && defaultSampleSize) {
1692 m_sampleSizes.push_back(defaultSampleSize);
1707 m_duration = TimeSpan::fromSeconds(static_cast<double>(totalDuration) / static_cast<double>(timeScale));
1712 if(m_bitrate < 0.01 && m_bitrate > -0.01) {
1717 m_istream->seekg(m_stscAtom->dataOffset() + 4);
1718 m_sampleToChunkEntryCount = reader.readUInt32BE();
Contains utility classes helping to read and write streams.