bool Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, uint64_t* aDecodeTime, bool aIsAudio) { if (!aTfhd.IsValid() || !aMvhd.IsValid() || !aMdhd.IsValid() || !aEdts.IsValid()) { LOG(Moof, "Invalid dependencies: aTfhd(%d) aMvhd(%d) aMdhd(%d) aEdts(%d)", aTfhd.IsValid(), aMvhd.IsValid(), aMdhd.IsValid(), !aEdts.IsValid()); return false; } BoxReader reader(aBox); if (!reader->CanReadType<uint32_t>()) { LOG(Moof, "Incomplete Box (missing flags)"); return false; } uint32_t flags = reader->ReadU32(); uint8_t version = flags >> 24; if (!reader->CanReadType<uint32_t>()) { LOG(Moof, "Incomplete Box (missing sampleCount)"); return false; } uint32_t sampleCount = reader->ReadU32(); if (sampleCount == 0) { return true; } size_t need = ((flags & 1) ? sizeof(uint32_t) : 0) + ((flags & 4) ? sizeof(uint32_t) : 0); uint16_t flag[] = { 0x100, 0x200, 0x400, 0x800, 0 }; for (size_t i = 0; flag[i]; i++) { if (flags & flag[i]) { need += sizeof(uint32_t) * sampleCount; } } if (reader->Remaining() < need) { LOG(Moof, "Incomplete Box (have:%lld need:%lld)", reader->Remaining(), need); return false; } uint64_t offset = aTfhd.mBaseDataOffset + (flags & 1 ? reader->ReadU32() : 0); uint32_t firstSampleFlags = flags & 4 ? reader->ReadU32() : aTfhd.mDefaultSampleFlags; uint64_t decodeTime = *aDecodeTime; nsTArray<Interval<Microseconds>> timeRanges; if (!mIndex.SetCapacity(sampleCount, fallible)) { LOG(Moof, "Out of Memory"); return false; } for (size_t i = 0; i < sampleCount; i++) { uint32_t sampleDuration = flags & 0x100 ? reader->ReadU32() : aTfhd.mDefaultSampleDuration; uint32_t sampleSize = flags & 0x200 ? reader->ReadU32() : aTfhd.mDefaultSampleSize; uint32_t sampleFlags = flags & 0x400 ? reader->ReadU32() : i ? aTfhd.mDefaultSampleFlags : firstSampleFlags; int32_t ctsOffset = 0; if (flags & 0x800) { ctsOffset = reader->Read32(); } Sample sample; sample.mByteRange = MediaByteRange(offset, offset + sampleSize); offset += sampleSize; sample.mDecodeTime = aMdhd.ToMicroseconds((int64_t)decodeTime - aEdts.mMediaStart) + aMvhd.ToMicroseconds(aEdts.mEmptyOffset); sample.mCompositionRange = Interval<Microseconds>( aMdhd.ToMicroseconds((int64_t)decodeTime + ctsOffset - aEdts.mMediaStart) + aMvhd.ToMicroseconds(aEdts.mEmptyOffset), aMdhd.ToMicroseconds((int64_t)decodeTime + ctsOffset + sampleDuration - aEdts.mMediaStart) + aMvhd.ToMicroseconds(aEdts.mEmptyOffset)); decodeTime += sampleDuration; // Sometimes audio streams don't properly mark their samples as keyframes, // because every audio sample is a keyframe. sample.mSync = !(sampleFlags & 0x1010000) || aIsAudio; // FIXME: Make this infallible after bug 968520 is done. MOZ_ALWAYS_TRUE(mIndex.AppendElement(sample, fallible)); mMdatRange = mMdatRange.Extents(sample.mByteRange); } mMaxRoundingError += aMdhd.ToMicroseconds(sampleCount); nsTArray<Sample*> ctsOrder; for (int i = 0; i < mIndex.Length(); i++) { ctsOrder.AppendElement(&mIndex[i]); } ctsOrder.Sort(CtsComparator()); for (size_t i = 0; i < ctsOrder.Length(); i++) { if (i + 1 < ctsOrder.Length()) { ctsOrder[i]->mCompositionRange.end = ctsOrder[i + 1]->mCompositionRange.start; } } mTimeRange = Interval<Microseconds>(ctsOrder[0]->mCompositionRange.start, ctsOrder.LastElement()->mCompositionRange.end); *aDecodeTime = decodeTime; return true; }
Result<Ok, nsresult> Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, Mvhd& aMvhd, Mdhd& aMdhd, Edts& aEdts, uint64_t* aDecodeTime, bool aIsAudio) { if (!aTfhd.IsValid() || !aMvhd.IsValid() || !aMdhd.IsValid() || !aEdts.IsValid()) { LOG(Moof, "Invalid dependencies: aTfhd(%d) aMvhd(%d) aMdhd(%d) aEdts(%d)", aTfhd.IsValid(), aMvhd.IsValid(), aMdhd.IsValid(), !aEdts.IsValid()); return Err(NS_ERROR_FAILURE); } BoxReader reader(aBox); if (!reader->CanReadType<uint32_t>()) { LOG(Moof, "Incomplete Box (missing flags)"); return Err(NS_ERROR_FAILURE); } uint32_t flags; MOZ_TRY_VAR(flags, reader->ReadU32()); uint8_t version = flags >> 24; if (!reader->CanReadType<uint32_t>()) { LOG(Moof, "Incomplete Box (missing sampleCount)"); return Err(NS_ERROR_FAILURE); } uint32_t sampleCount; MOZ_TRY_VAR(sampleCount, reader->ReadU32()); if (sampleCount == 0) { return Ok(); } uint64_t offset = aTfhd.mBaseDataOffset; if (flags & 0x01) { uint32_t tmp; MOZ_TRY_VAR(tmp, reader->ReadU32()); offset += tmp; } uint32_t firstSampleFlags = aTfhd.mDefaultSampleFlags; if (flags & 0x04) { MOZ_TRY_VAR(firstSampleFlags, reader->ReadU32()); } uint64_t decodeTime = *aDecodeTime; nsTArray<MP4Interval<Microseconds>> timeRanges; if (!mIndex.SetCapacity(sampleCount, fallible)) { LOG(Moof, "Out of Memory"); return Err(NS_ERROR_FAILURE); } for (size_t i = 0; i < sampleCount; i++) { uint32_t sampleDuration = aTfhd.mDefaultSampleDuration; if (flags & 0x100) { MOZ_TRY_VAR(sampleDuration, reader->ReadU32()); } uint32_t sampleSize = aTfhd.mDefaultSampleSize; if (flags & 0x200) { MOZ_TRY_VAR(sampleSize, reader->ReadU32()); } uint32_t sampleFlags = i ? aTfhd.mDefaultSampleFlags : firstSampleFlags; if (flags & 0x400) { MOZ_TRY_VAR(sampleFlags, reader->ReadU32()); } int32_t ctsOffset = 0; if (flags & 0x800) { MOZ_TRY_VAR(ctsOffset, reader->Read32()); } if (sampleSize) { Sample sample; sample.mByteRange = MediaByteRange(offset, offset + sampleSize); offset += sampleSize; Microseconds decodeOffset, emptyOffset, startCts, endCts; MOZ_TRY_VAR(decodeOffset, aMdhd.ToMicroseconds((int64_t)decodeTime - aEdts.mMediaStart)); MOZ_TRY_VAR(emptyOffset, aMvhd.ToMicroseconds(aEdts.mEmptyOffset)); sample.mDecodeTime = decodeOffset + emptyOffset; MOZ_TRY_VAR(startCts, aMdhd.ToMicroseconds((int64_t)decodeTime + ctsOffset - aEdts.mMediaStart)); MOZ_TRY_VAR(endCts, aMdhd.ToMicroseconds((int64_t)decodeTime + ctsOffset + sampleDuration - aEdts.mMediaStart)); sample.mCompositionRange = MP4Interval<Microseconds>(startCts + emptyOffset, endCts + emptyOffset); // Sometimes audio streams don't properly mark their samples as keyframes, // because every audio sample is a keyframe. sample.mSync = !(sampleFlags & 0x1010000) || aIsAudio; // FIXME: Make this infallible after bug 968520 is done. MOZ_ALWAYS_TRUE(mIndex.AppendElement(sample, fallible)); mMdatRange = mMdatRange.Span(sample.mByteRange); } decodeTime += sampleDuration; } Microseconds roundTime; MOZ_TRY_VAR(roundTime, aMdhd.ToMicroseconds(sampleCount)); mMaxRoundingError += roundTime; *aDecodeTime = decodeTime; return Ok(); }