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/io/binaryreader.h> 16 #include <c++utilities/io/binarywriter.h> 17 #include <c++utilities/io/bitreader.h> 18 #include <c++utilities/io/catchiofailure.h> 39 Mpeg4AudioSpecificConfig::Mpeg4AudioSpecificConfig() :
41 sampleFrequencyIndex(0xF),
43 channelConfiguration(0),
44 extensionAudioObjectType(0),
47 extensionSampleFrequencyIndex(0xF),
48 extensionSampleFrequency(0),
49 extensionChannelConfiguration(0),
50 frameLengthFlag(false),
51 dependsOnCoreCoder(false),
91 m_trakAtom(&trakAtom),
104 m_framesPerSample(1),
105 m_chunkOffsetSize(4),
107 m_sampleToChunkEntryCount(0)
134 static const string context(
"reading chunk offset table of MP4 track");
139 vector<uint64> offsets;
142 uint64 actualTableSize = m_stcoAtom->
dataSize();
147 actualTableSize -= 8;
151 if(calculatedTableSize < actualTableSize) {
153 }
else if(calculatedTableSize > actualTableSize) {
155 actualChunkCount = floor(static_cast<double>(actualTableSize) / static_cast<double>(
chunkOffsetSize()));
158 offsets.reserve(actualChunkCount);
162 for(uint32 i = 0; i < actualChunkCount; ++i) {
163 offsets.push_back(
reader().readUInt32BE());
167 for(uint32 i = 0; i < actualChunkCount; ++i) {
168 offsets.push_back(
reader().readUInt64BE());
318 uint64 Mp4Track::accumulateSampleSizes(
size_t &sampleIndex,
size_t count)
320 if(sampleIndex + count <= m_sampleSizes.size()) {
322 for(
size_t end = sampleIndex + count; sampleIndex < end; ++sampleIndex) {
323 sum += m_sampleSizes[sampleIndex];
326 }
else if(m_sampleSizes.size() == 1) {
327 sampleIndex += count;
328 return static_cast<uint64
>(m_sampleSizes.front()) * count;
343 void Mp4Track::addChunkSizeEntries(std::vector<uint64> &chunkSizeTable,
size_t count,
size_t &sampleIndex, uint32
sampleCount)
345 for(
size_t i = 0; i < count; ++i) {
346 chunkSizeTable.push_back(accumulateSampleSizes(sampleIndex, sampleCount));
359 static const string context(
"reading sample to chunk table of MP4 track");
365 uint64 actualTableSize = m_stscAtom->
dataSize();
366 if(actualTableSize < 20) {
370 actualTableSize -= 8;
373 uint64 calculatedTableSize = actualSampleToChunkEntryCount * 12;
374 if(calculatedTableSize < actualTableSize) {
376 }
else if(calculatedTableSize > actualTableSize) {
378 actualSampleToChunkEntryCount = floor(static_cast<double>(actualTableSize) / 12.0);
381 vector<tuple<uint32, uint32, uint32> > sampleToChunkTable;
382 sampleToChunkTable.reserve(actualSampleToChunkEntryCount);
384 for(uint32 i = 0; i < actualSampleToChunkEntryCount; ++i) {
386 uint32 firstChunk =
reader().readUInt32BE();
387 uint32 samplesPerChunk =
reader().readUInt32BE();
388 uint32 sampleDescriptionIndex =
reader().readUInt32BE();
389 sampleToChunkTable.emplace_back(firstChunk, samplesPerChunk, sampleDescriptionIndex);
391 return sampleToChunkTable;
408 static const string context(
"reading chunk sizes of MP4 track");
416 vector<uint64> chunkSizes;
417 if(!sampleToChunkTable.empty()) {
419 auto tableIterator = sampleToChunkTable.cbegin();
420 chunkSizes.reserve(m_chunkCount);
422 size_t sampleIndex = 0;
423 uint32 previousChunkIndex = get<0>(*tableIterator);
424 if(previousChunkIndex != 1) {
426 previousChunkIndex = 1;
428 uint32 samplesPerChunk = get<1>(*tableIterator);
431 for(
const auto tableEnd = sampleToChunkTable.cend(); tableIterator != tableEnd; ++tableIterator) {
432 uint32 firstChunkIndex = get<0>(*tableIterator);
433 if(firstChunkIndex > previousChunkIndex && firstChunkIndex <= m_chunkCount) {
434 addChunkSizeEntries(chunkSizes, firstChunkIndex - previousChunkIndex, sampleIndex, samplesPerChunk);
437 "The first chunk index of a \"sample to chunk\" entry must be greather then the first chunk of the previous entry and not greather then the chunk count.", context);
440 previousChunkIndex = firstChunkIndex;
441 samplesPerChunk = get<1>(*tableIterator);
443 if(m_chunkCount >= previousChunkIndex) {
444 addChunkSizeEntries(chunkSizes, m_chunkCount + 1 - previousChunkIndex, sampleIndex, samplesPerChunk);
458 static const string context(
"parsing MPEG-4 elementary stream descriptor");
459 using namespace Mpeg4ElementaryStreamObjectIds;
460 unique_ptr<Mpeg4ElementaryStreamInfo> esInfo;
462 reader.stream()->seekg(esDescAtom->
dataOffset());
464 if(reader.readUInt32BE() != 0) {
477 reader.stream()->seekg(esDesc.dataOffset());
478 esInfo = make_unique<Mpeg4ElementaryStreamInfo>();
479 esInfo->id = reader.readUInt16BE();
480 esInfo->esDescFlags = reader.readByte();
481 if(esInfo->dependencyFlag()) {
482 esInfo->dependsOnId = reader.readUInt16BE();
484 if(esInfo->urlFlag()) {
485 esInfo->url = reader.readString(reader.readByte());
487 if(esInfo->ocrFlag()) {
488 esInfo->ocrId = reader.readUInt16BE();
490 for(
Mpeg4Descriptor *esDescChild = esDesc.
denoteFirstChild(static_cast<uint64>(reader.stream()->tellg()) - esDesc.startOffset()); esDescChild; esDescChild = esDescChild->nextSibling()) {
491 esDescChild->parse();
492 switch(esDescChild->id()) {
495 reader.stream()->seekg(esDescChild->dataOffset());
496 esInfo->objectTypeId = reader.readByte();
497 esInfo->decCfgDescFlags = reader.readByte();
498 esInfo->bufferSize = reader.readUInt24BE();
499 esInfo->maxBitrate = reader.readUInt32BE();
500 esInfo->averageBitrate = reader.readUInt32BE();
501 for(
Mpeg4Descriptor *decCfgDescChild = esDescChild->
denoteFirstChild(esDescChild->headerSize() + 13); decCfgDescChild; decCfgDescChild = decCfgDescChild->nextSibling()) {
502 decCfgDescChild->parse();
503 switch(decCfgDescChild->id()) {
506 switch(esInfo->objectTypeId) {
509 esInfo->audioSpecificConfig =
parseAudioSpecificConfig(statusProvider, *reader.stream(), decCfgDescChild->dataOffset(), decCfgDescChild->dataSize());
512 esInfo->videoSpecificConfig =
parseVideoSpecificConfig(statusProvider, reader, decCfgDescChild->dataOffset(), decCfgDescChild->dataSize());
543 static const string context(
"parsing MPEG-4 audio specific config from elementary stream descriptor");
544 using namespace Mpeg4AudioObjectIds;
546 stream.seekg(startOffset);
547 auto buff = make_unique<char []>(
size);
548 stream.read(buff.get(),
size);
549 BitReader bitReader(buff.get(),
size);
550 auto audioCfg = make_unique<Mpeg4AudioSpecificConfig>();
553 auto getAudioObjectType = [&audioCfg, &bitReader] {
554 byte objType = bitReader.readBits<byte>(5);
556 objType = 32 + bitReader.readBits<byte>(6);
560 audioCfg->audioObjectType = getAudioObjectType();
562 if((audioCfg->sampleFrequencyIndex = bitReader.readBits<byte>(4)) == 0xF) {
563 audioCfg->sampleFrequency = bitReader.readBits<uint32>(24);
566 audioCfg->channelConfiguration = bitReader.readBits<byte>(4);
568 switch(audioCfg->audioObjectType) {
571 audioCfg->extensionAudioObjectType = audioCfg->audioObjectType;
572 audioCfg->sbrPresent =
true;
573 if((audioCfg->extensionSampleFrequencyIndex = bitReader.readBits<byte>(4)) == 0xF) {
574 audioCfg->extensionSampleFrequency = bitReader.readBits<uint32>(24);
576 if((audioCfg->audioObjectType = getAudioObjectType()) ==
ErBsac) {
577 audioCfg->extensionChannelConfiguration = bitReader.readBits<byte>(4);
581 switch(audioCfg->extensionAudioObjectType) {
583 audioCfg->psPresent =
true;
588 switch(audioCfg->audioObjectType) {
592 audioCfg->frameLengthFlag = bitReader.readBits<byte>(1);
593 if((audioCfg->dependsOnCoreCoder = bitReader.readBit())) {
594 audioCfg->coreCoderDelay = bitReader.readBits<byte>(14);
596 audioCfg->extensionFlag = bitReader.readBit();
597 if(audioCfg->channelConfiguration == 0) {
600 switch(audioCfg->audioObjectType) {
602 audioCfg->layerNr = bitReader.readBits<byte>(3);
607 if(audioCfg->extensionFlag == 1) {
608 switch(audioCfg->audioObjectType) {
610 audioCfg->numOfSubFrame = bitReader.readBits<byte>(5);
611 audioCfg->layerLength = bitReader.readBits<uint16>(11);
614 audioCfg->resilienceFlags = bitReader.readBits<byte>(3);
619 if(bitReader.readBit() == 1) {
628 switch(audioCfg->audioObjectType) {
632 switch(audioCfg->epConfig = bitReader.readBits<byte>(2)) {
636 bitReader.skipBits(1);
643 if(audioCfg->extensionAudioObjectType !=
Sbr && audioCfg->extensionAudioObjectType !=
Ps && bitReader.bitsAvailable() >= 16) {
644 uint16 syncExtensionType = bitReader.readBits<uint16>(11);
645 if(syncExtensionType == 0x2B7) {
646 if((audioCfg->extensionAudioObjectType = getAudioObjectType()) ==
Sbr) {
647 if((audioCfg->sbrPresent = bitReader.readBit())) {
648 if((audioCfg->extensionSampleFrequencyIndex = bitReader.readBits<byte>(4)) == 0xF) {
649 audioCfg->extensionSampleFrequency = bitReader.readBits<uint32>(24);
651 if(bitReader.bitsAvailable() >= 12) {
652 if((syncExtensionType = bitReader.readBits<uint16>(11)) == 0x548) {
653 audioCfg->psPresent = bitReader.readBits<byte>(1);
657 }
else if(audioCfg->extensionAudioObjectType ==
ErBsac) {
658 if((audioCfg->sbrPresent = bitReader.readBit())) {
659 if((audioCfg->extensionSampleFrequencyIndex = bitReader.readBits<byte>(4)) == 0xF) {
660 audioCfg->extensionSampleFrequency = bitReader.readBits<uint32>(24);
663 audioCfg->extensionChannelConfiguration = bitReader.readBits<byte>(4);
665 }
else if (syncExtensionType == 0x548) {
666 audioCfg->psPresent = bitReader.readBit();
672 const char *what = catchIoFailure();
675 throwIoFailure(what);
692 static const string context(
"parsing MPEG-4 video specific config from elementary stream descriptor");
693 using namespace Mpeg4AudioObjectIds;
694 auto videoCfg = make_unique<Mpeg4VideoSpecificConfig>();
696 reader.stream()->seekg(startOffset);
697 if(size > 3 && (reader.readUInt24BE() == 1)) {
702 switch(reader.readByte()) {
705 videoCfg->profile = reader.readByte();
715 if((buff1 = reader.readUInt24BE()) != 1) {
716 reader.stream()->seekg(-2, ios_base::cur);
717 videoCfg->userData.push_back(buff1 >> 16);
724 if(buff1 != 1 && size > 0) {
725 videoCfg->userData += reader.readString(size);
734 if(reader.readUInt24BE() != 1) {
735 reader.stream()->seekg(-2, ios_base::cur);
771 if(oldMdatOffsets.size() == 0 || oldMdatOffsets.size() != newMdatOffsets.size()) {
774 static const unsigned int stcoDataBegin = 8;
775 uint64 startPos = m_stcoAtom->dataOffset() + stcoDataBegin;
776 uint64 endPos = startPos + m_stcoAtom->dataSize() - stcoDataBegin;
779 vector<int64>::size_type i;
780 vector<int64>::size_type
size;
782 switch(m_stcoAtom->id()) {
785 while((currentPos + 4) <= endPos) {
787 for(i = 0, size = oldMdatOffsets.size(); i <
size; ++i) {
788 if(off > static_cast<uint64>(oldMdatOffsets[i])) {
789 off += (newMdatOffsets[i] - oldMdatOffsets[i]);
800 while((currentPos + 8) <= endPos) {
802 for(i = 0, size = oldMdatOffsets.size(); i <
size; ++i) {
803 if(off > static_cast<uint64>(oldMdatOffsets[i])) {
804 off += (newMdatOffsets[i] - oldMdatOffsets[i]);
839 m_ostream->seekp(m_stcoAtom->dataOffset() + 8);
840 switch(m_stcoAtom->id()) {
842 for(
auto offset : chunkOffsets) {
847 for(
auto offset : chunkOffsets) {
875 writer().writeUInt32BE(offset);
878 writer().writeUInt64BE(offset);
955 return m_trakAtom->totalSize();
964 writer().writeUInt32BE(100);
977 writer().writeUInt24BE(flags);
981 writer().writeUInt32BE(0);
983 writer().writeUInt32BE(0);
984 writer().writeUInt32BE(0);
988 m_istream->seekg(m_tkhdAtom->startOffset() + 52);
990 m_ostream->write(buffer,
sizeof(buffer));
995 writer().writeFixed8BE(1.0);
996 writer().writeUInt16BE(0);
997 for(int32 value : {0x00010000,0,0,0,0x00010000,0,0,0,0x40000000}) {
998 writer().writeInt32BE(value);
1000 writer().writeFixed16BE(1.0);
1001 writer().writeFixed16BE(1.0);
1011 ostream::pos_type mdiaStartOffset =
outputStream().tellp();
1012 writer().writeUInt32BE(0);
1015 writer().writeUInt32BE(36);
1017 writer().writeUInt24BE(0);
1024 for(
size_t charIndex = 0; charIndex <
m_language.length() && charIndex < 3; ++charIndex) {
1026 language |=
static_cast<uint16
>(
m_language[charIndex]) << (0xA - charIndex * 0x5);
1033 writer().writeUInt16BE(language);
1034 writer().writeUInt16BE(0);
1038 writer().writeUInt64BE(0);
1057 for(
int i = 0; i < 3; ++i)
writer().writeUInt32BE(0);
1071 ostream::pos_type minfStartOffset =
outputStream().tellp();
1072 writer().writeUInt32BE(0);
1074 bool dinfAtomWritten =
false;
1095 dinfAtomWritten =
true;
1099 if(!dinfAtomWritten) {
1100 writer().writeUInt32BE(36);
1103 writer().writeUInt32BE(28);
1105 writer().writeUInt32BE(0);
1106 writer().writeUInt32BE(1);
1108 writer().writeUInt32BE(12);
1111 writer().writeUInt24BE(0x000001);
1126 ostream::pos_type stblStartOffset =
outputStream().tellp();
1127 writer().writeUInt32BE(0);
1184 static const string context(
"parsing MP4 track");
1185 using namespace Mp4AtomIds;
1193 if(!(m_tkhdAtom = m_trakAtom->childById(
TrackHeader))) {
1197 if(!(m_mdiaAtom = m_trakAtom->childById(
Media))) {
1201 if(!(m_mdhdAtom = m_mdiaAtom->childById(
MediaHeader))) {
1213 if(!(m_stblAtom = m_minfAtom->childById(
SampleTable))) {
1238 BinaryReader &
reader = m_trakAtom->reader();
1241 m_istream->seekg(m_tkhdAtom->startOffset() + 8);
1242 byte atomVersion = reader.readByte();
1243 uint32 flags = reader.readUInt24BE();
1247 switch(atomVersion) {
1249 m_creationTime = startDate + TimeSpan::fromSeconds(reader.readUInt32BE());
1251 m_id = reader.readUInt32BE();
1254 m_creationTime = startDate + TimeSpan::fromSeconds(reader.readUInt64BE());
1255 m_modificationTime = startDate + TimeSpan::fromSeconds(reader.readUInt64BE());
1256 m_id = reader.readUInt32BE();
1266 m_istream->seekg(m_mdhdAtom->dataOffset());
1267 atomVersion = reader.readByte();
1269 switch(atomVersion) {
1271 m_creationTime = startDate + TimeSpan::fromSeconds(reader.readUInt32BE());
1274 m_duration = TimeSpan::fromSeconds(static_cast<double>(reader.readUInt32BE()) / static_cast<double>(m_timeScale));
1277 m_creationTime = startDate + TimeSpan::fromSeconds(reader.readUInt64BE());
1278 m_modificationTime = startDate + TimeSpan::fromSeconds(reader.readUInt64BE());
1279 m_timeScale = reader.readUInt32BE();
1280 m_duration = TimeSpan::fromSeconds(static_cast<double>(reader.readUInt64BE()) / static_cast<double>(m_timeScale));
1283 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);
1287 uint16 tmp = reader.readUInt16BE();
1290 buff[0] = ((tmp & 0x7C00) >> 0xA) + 0x60;
1291 buff[1] = ((tmp & 0x03E0) >> 0x5) + 0x60;
1292 buff[2] = ((tmp & 0x001F) >> 0x0) + 0x60;
1300 m_istream->seekg(m_hdlrAtom->dataOffset() + 8);
1302 switch(reader.readUInt32BE()) {
1312 case 0x6D657461:
case 0x74657874:
1320 if((tmp =
m_istream->peek()) == m_hdlrAtom->dataSize() - 12 - 4 - 8 - 1) {
1323 m_name = reader.readString(tmp);
1326 m_name = reader.readTerminatedString(m_hdlrAtom->dataSize() - 12 - 4 - 8, 0);
1331 m_istream->seekg(m_stcoAtom->dataOffset() + 4);
1332 m_chunkCount = reader.readUInt32BE();
1335 m_istream->seekg(m_stsdAtom->dataOffset() + 4);
1336 uint32 entryCount = reader.readUInt32BE();
1337 Mp4Atom *esDescParentAtom =
nullptr;
1338 if(entryCount > 0) {
1340 for(
Mp4Atom *codecConfigContainerAtom = m_stsdAtom->
firstChild(); codecConfigContainerAtom; codecConfigContainerAtom = codecConfigContainerAtom->nextSibling()) {
1341 codecConfigContainerAtom->
parse();
1343 m_formatId = interpretIntegerAsString<uint32>(codecConfigContainerAtom->id());
1346 m_istream->seekg(codecConfigContainerAtom->dataOffset());
1347 switch(codecConfigContainerAtom->id()) {
1353 tmp = reader.readUInt16BE();
1369 codecConfigContainerAtom->denoteFirstChild(codecConfigContainerAtom->headerSize() + 28 + 16);
1372 codecConfigContainerAtom->denoteFirstChild(codecConfigContainerAtom->headerSize() + 28 + 32);
1375 codecConfigContainerAtom->denoteFirstChild(codecConfigContainerAtom->headerSize() + 28);
1377 if(!esDescParentAtom) {
1378 esDescParentAtom = codecConfigContainerAtom;
1385 m_istream->seekg(6 + 2 + 16, ios_base::cur);
1391 m_framesPerSample = reader.readUInt16BE();
1392 tmp = reader.readByte();
1396 }
else if(tmp < 32) {
1399 m_depth = reader.readUInt16BE();
1400 codecConfigContainerAtom->denoteFirstChild(codecConfigContainerAtom->headerSize() + 78);
1401 if(!esDescParentAtom) {
1402 esDescParentAtom = codecConfigContainerAtom;
1407 codecConfigContainerAtom->denoteFirstChild(codecConfigContainerAtom->headerSize() + 8);
1408 if(!esDescParentAtom) {
1409 esDescParentAtom = codecConfigContainerAtom;
1421 if(esDescParentAtom) {
1424 m_istream->seekg(avcConfigAtom->dataOffset());
1425 m_avcConfig = make_unique<Media::AvcConfiguration>();
1427 m_avcConfig->parse(reader, avcConfigAtom->dataSize());
1445 m_bitrate =
static_cast<double>(m_esInfo->averageBitrate) / 1000;
1446 m_maxBitrate =
static_cast<double>(m_esInfo->maxBitrate) / 1000;
1447 if(m_esInfo->audioSpecificConfig) {
1450 if(m_esInfo->audioSpecificConfig->sampleFrequencyIndex == 0xF) {
1457 if(m_esInfo->audioSpecificConfig->extensionSampleFrequencyIndex == 0xF) {
1464 m_channelConfig = m_esInfo->audioSpecificConfig->channelConfiguration;
1467 if(m_esInfo->videoSpecificConfig) {
1470 m_format.
sub = m_esInfo->videoSpecificConfig->profile;
1471 if(!m_esInfo->videoSpecificConfig->userData.empty()) {
1472 m_formatId +=
" / " + m_esInfo->videoSpecificConfig->userData;
1480 m_istream->seekg(m_stcoAtom->dataOffset() + 8);
1481 m_istream->seekg(m_chunkOffsetSize == 8 ? reader.readUInt64BE() : reader.readUInt32BE());
1499 m_sampleSizes.clear();
1501 uint64 actualSampleSizeTableSize = m_stszAtom->dataSize();
1502 if(actualSampleSizeTableSize < 12) {
1505 actualSampleSizeTableSize -= 12;
1506 m_istream->seekg(m_stszAtom->dataOffset() + 4);
1508 uint32 constantSize;
1512 fieldSize = reader.readByte();
1515 constantSize = reader.readUInt32BE();
1520 m_sampleSizes.push_back(constantSize);
1524 uint64 calculatedSampleSizeTableSize = ceil((0.125 * fieldSize) *
m_sampleCount);
1525 if(calculatedSampleSizeTableSize < actualSampleSizeTableSize) {
1527 }
else if(calculatedSampleSizeTableSize > actualSampleSizeTableSize) {
1529 actualSampleCount = floor(static_cast<double>(actualSampleSizeTableSize) / (0.125 * fieldSize));
1531 m_sampleSizes.reserve(actualSampleCount);
1535 for(; i <= actualSampleCount; i += 2) {
1536 byte val = reader.readByte();
1537 m_sampleSizes.push_back(val >> 4);
1538 m_sampleSizes.push_back(val & 0xF0);
1539 m_size += (val >> 4) + (val & 0xF0);
1541 if(i <= actualSampleCount + 1) {
1542 m_sampleSizes.push_back(reader.readByte() >> 4);
1543 m_size += m_sampleSizes.back();
1547 for(; i <= actualSampleCount; ++i) {
1548 m_sampleSizes.push_back(reader.readByte());
1549 m_size += m_sampleSizes.back();
1553 for(; i <= actualSampleCount; ++i) {
1554 m_sampleSizes.push_back(reader.readUInt16BE());
1555 m_size += m_sampleSizes.back();
1559 for(; i <= actualSampleCount; ++i) {
1560 m_sampleSizes.push_back(reader.readUInt32BE());
1561 m_size += m_sampleSizes.back();
1571 uint64 totalDuration = 0;
1578 uint32 calculatedDataSize = 0;
1579 if(tfhdAtom->dataSize() < calculatedDataSize) {
1582 m_istream->seekg(tfhdAtom->dataOffset() + 1);
1583 uint32 flags = reader.readUInt24BE();
1584 if(
m_id == reader.readUInt32BE()) {
1585 if(flags & 0x000001) {
1586 calculatedDataSize += 8;
1588 if(flags & 0x000002) {
1589 calculatedDataSize += 4;
1591 if(flags & 0x000008) {
1592 calculatedDataSize += 4;
1594 if(flags & 0x000010) {
1595 calculatedDataSize += 4;
1597 if(flags & 0x000020) {
1598 calculatedDataSize += 4;
1602 uint32 defaultSampleDuration = 0;
1603 uint32 defaultSampleSize = 0;
1605 if(tfhdAtom->dataSize() < calculatedDataSize) {
1608 if(flags & 0x000001) {
1612 if(flags & 0x000002) {
1616 if(flags & 0x000008) {
1617 defaultSampleDuration = reader.readUInt32BE();
1620 if(flags & 0x000010) {
1621 defaultSampleSize = reader.readUInt32BE();
1623 if(flags & 0x000020) {
1629 uint32 calculatedDataSize = 8;
1630 if(trunAtom->dataSize() < calculatedDataSize) {
1633 m_istream->seekg(trunAtom->dataOffset() + 1);
1634 uint32 flags = reader.readUInt24BE();
1635 uint32 sampleCount = reader.readUInt32BE();
1637 if(flags & 0x000001) {
1638 calculatedDataSize += 4;
1640 if(flags & 0x000004) {
1641 calculatedDataSize += 4;
1643 uint32 entrySize = 0;
1644 if(flags & 0x000100) {
1647 if(flags & 0x000200) {
1650 if(flags & 0x000400) {
1653 if(flags & 0x000800) {
1657 if(trunAtom->dataSize() < calculatedDataSize) {
1660 if(flags & 0x000001) {
1664 if(flags & 0x000004) {
1668 if(flags & 0x000100) {
1669 totalDuration += reader.readUInt32BE();
1671 totalDuration += defaultSampleDuration;
1673 if(flags & 0x000200) {
1674 m_sampleSizes.push_back(reader.readUInt32BE());
1675 m_size += m_sampleSizes.back();
1677 m_size += defaultSampleSize;
1679 if(flags & 0x000400) {
1682 if(flags & 0x000800) {
1689 if(m_sampleSizes.empty() && defaultSampleSize) {
1690 m_sampleSizes.push_back(defaultSampleSize);
1705 m_duration = TimeSpan::fromSeconds(static_cast<double>(totalDuration) / static_cast<double>(timeScale));
1710 if(m_bitrate < 0.01 && m_bitrate > -0.01) {
1715 m_istream->seekg(m_stscAtom->dataOffset() + 4);
1716 m_sampleToChunkEntryCount = reader.readUInt32BE();
Contains utility classes helping to read and write streams.