Result<bool, nsresult> FrameParser::VBRHeader::ParseVBRI( BufferReader* aReader) { static const uint32_t TAG = BigEndian::readUint32("VBRI"); static const uint32_t OFFSET = 32 + FrameParser::FrameHeader::SIZE; static const uint32_t FRAME_COUNT_OFFSET = OFFSET + 14; static const uint32_t MIN_FRAME_SIZE = OFFSET + 26; MOZ_ASSERT(aReader); // ParseVBRI assumes that the ByteReader offset points to the beginning of a // frame, therefore as a simple check, we look for the presence of a frame // sync at that position. auto sync = aReader->PeekU16(); if (sync.isOk()) { // To avoid compiler complains 'set but unused'. MOZ_ASSERT((sync.unwrap() & 0xFFE0) == 0xFFE0); } // Seek backward to the original position before leaving this scope. const size_t prevReaderOffset = aReader->Offset(); auto scopeExit = MakeScopeExit([&] { aReader->Seek(prevReaderOffset); }); // VBRI have a fixed relative position, so let's check for it there. if (aReader->Remaining() > MIN_FRAME_SIZE) { aReader->Seek(prevReaderOffset + OFFSET); uint32_t tag, frames; MOZ_TRY_VAR(tag, aReader->ReadU32()); if (tag == TAG) { aReader->Seek(prevReaderOffset + FRAME_COUNT_OFFSET); MOZ_TRY_VAR(frames, aReader->ReadU32()); mNumAudioFrames = Some(frames); mType = VBRI; return true; } } return false; }
Result<Ok, nsresult> Saiz::Parse(Box& aBox) { BoxReader reader(aBox); uint32_t flags; MOZ_TRY_VAR(flags, reader->ReadU32()); uint8_t version = flags >> 24; if (flags & 1) { MOZ_TRY_VAR(mAuxInfoType, reader->ReadU32()); MOZ_TRY_VAR(mAuxInfoTypeParameter, reader->ReadU32()); } uint8_t defaultSampleInfoSize; MOZ_TRY_VAR(defaultSampleInfoSize, reader->ReadU8()); uint32_t count; MOZ_TRY_VAR(count, reader->ReadU32()); if (defaultSampleInfoSize) { if (!mSampleInfoSize.SetLength(count, fallible)) { LOG(Saiz, "OOM"); return Err(NS_ERROR_FAILURE); } memset(mSampleInfoSize.Elements(), defaultSampleInfoSize, mSampleInfoSize.Length()); } else { if (!reader->ReadArray(mSampleInfoSize, count)) { LOG(Saiz, "Incomplete Box (OOM or missing count:%u)", count); return Err(NS_ERROR_FAILURE); } } return Ok(); }
Result<Ok, nsresult> CencSampleEncryptionInfoEntry::Init(BoxReader& aReader) { // Skip a reserved byte. MOZ_TRY(aReader->ReadU8()); uint8_t possiblePatternInfo; MOZ_TRY_VAR(possiblePatternInfo, aReader->ReadU8()); uint8_t flag; MOZ_TRY_VAR(flag, aReader->ReadU8()); MOZ_TRY_VAR(mIVSize, aReader->ReadU8()); // Read the key id. uint8_t key; for (uint32_t i = 0; i < kKeyIdSize; ++i) { MOZ_TRY_VAR(key, aReader->ReadU8()); mKeyId.AppendElement(key); } mIsEncrypted = flag != 0; if (mIsEncrypted) { if (mIVSize != 8 && mIVSize != 16) { return Err(NS_ERROR_FAILURE); } } else if (mIVSize != 0) { return Err(NS_ERROR_FAILURE); } return Ok(); }
Result<Ok, nsresult> Mvhd::Parse(Box& aBox) { BoxReader reader(aBox); uint32_t flags; MOZ_TRY_VAR(flags, reader->ReadU32()); uint8_t version = flags >> 24; if (version == 0) { uint32_t creationTime, modificationTime, duration; MOZ_TRY_VAR(creationTime, reader->ReadU32()); MOZ_TRY_VAR(modificationTime, reader->ReadU32()); MOZ_TRY_VAR(mTimescale, reader->ReadU32()); MOZ_TRY_VAR(duration, reader->ReadU32()); mCreationTime = creationTime; mModificationTime = modificationTime; mDuration = duration; } else if (version == 1) { MOZ_TRY_VAR(mCreationTime, reader->ReadU64()); MOZ_TRY_VAR(mModificationTime, reader->ReadU64()); MOZ_TRY_VAR(mTimescale, reader->ReadU32()); MOZ_TRY_VAR(mDuration, reader->ReadU64()); } else { return Err(NS_ERROR_FAILURE); } return Ok(); }
Result<Ok, nsresult> Sgpd::Parse(Box& aBox) { BoxReader reader(aBox); uint32_t flags; MOZ_TRY_VAR(flags, reader->ReadU32()); const uint8_t version = flags >> 24; flags = flags & 0xffffff; uint32_t type; MOZ_TRY_VAR(type, reader->ReadU32()); mGroupingType = type; const uint32_t entrySize = sizeof(uint32_t) + kKeyIdSize; uint32_t defaultLength = 0; if (version == 1) { MOZ_TRY_VAR(defaultLength, reader->ReadU32()); if (defaultLength < entrySize && defaultLength != 0) { return Err(NS_ERROR_FAILURE); } } uint32_t count; MOZ_TRY_VAR(count, reader->ReadU32()); for (uint32_t i = 0; i < count; ++i) { if (version == 1 && defaultLength == 0) { uint32_t descriptionLength; MOZ_TRY_VAR(descriptionLength, reader->ReadU32()); if (descriptionLength < entrySize) { return Err(NS_ERROR_FAILURE); } } CencSampleEncryptionInfoEntry entry; bool valid = entry.Init(reader).isOk(); if (!valid) { return Err(NS_ERROR_FAILURE); } if (!mEntries.AppendElement(entry, mozilla::fallible)) { LOG(Sgpd, "OOM"); return Err(NS_ERROR_FAILURE); } } return Ok(); }
template<typename Tok> JS::Result<ParseNode*> BinASTParser<Tok>::parseAux(const uint8_t* start, const size_t length) { tokenizer_.emplace(cx_, start, length); Directives directives(options().strictOption); GlobalSharedContext globalsc(cx_, ScopeKind::Global, directives, options().extraWarningsOption); BinParseContext globalpc(cx_, this, &globalsc, /* newDirectives = */ nullptr); if (!globalpc.init()) return cx_->alreadyReportedError(); ParseContext::VarScope varScope(cx_, &globalpc, usedNames_); if (!varScope.init(&globalpc)) return cx_->alreadyReportedError(); MOZ_TRY(tokenizer_->readHeader()); ParseNode* result(nullptr); MOZ_TRY_VAR(result, parseProgram()); Maybe<GlobalScope::Data*> bindings = NewGlobalScopeData(cx_, varScope, alloc_, parseContext_); if (!bindings) return cx_->alreadyReportedError(); globalsc.bindings = *bindings; return result; // Magic conversion to Ok. }
Result<Ok, nsresult> Tfdt::Parse(Box& aBox) { BoxReader reader(aBox); uint32_t flags; MOZ_TRY_VAR(flags, reader->ReadU32()); uint8_t version = flags >> 24; if (version == 0) { uint32_t tmp; MOZ_TRY_VAR(tmp, reader->ReadU32()); mBaseMediaDecodeTime = tmp; } else if (version == 1) { MOZ_TRY_VAR(mBaseMediaDecodeTime, reader->ReadU64()); } return Ok(); }
Result<Ok, nsresult> SinfParser::ParseTenc(Box& aBox) { BoxReader reader(aBox); if (reader->Remaining() < 24) { return Err(NS_ERROR_FAILURE); } MOZ_TRY(reader->ReadU32()); // flags -- ignore uint32_t isEncrypted; MOZ_TRY_VAR(isEncrypted, reader->ReadU24()); MOZ_TRY_VAR(mSinf.mDefaultIVSize, reader->ReadU8()); memcpy(mSinf.mDefaultKeyID, reader->Read(16), 16); return Ok(); }
Result<Ok, nsresult> Tfhd::Parse(Box& aBox) { MOZ_ASSERT(aBox.IsType("tfhd")); MOZ_ASSERT(aBox.Parent()->IsType("traf")); MOZ_ASSERT(aBox.Parent()->Parent()->IsType("moof")); BoxReader reader(aBox); MOZ_TRY_VAR(mFlags, reader->ReadU32()); MOZ_TRY_VAR(mTrackId, reader->ReadU32()); mBaseDataOffset = aBox.Parent()->Parent()->Offset(); if (mFlags & 0x01) { MOZ_TRY_VAR(mBaseDataOffset, reader->ReadU64()); } if (mFlags & 0x02) { MOZ_TRY_VAR(mDefaultSampleDescriptionIndex, reader->ReadU32()); } if (mFlags & 0x08) { MOZ_TRY_VAR(mDefaultSampleDuration, reader->ReadU32()); } if (mFlags & 0x10) { MOZ_TRY_VAR(mDefaultSampleSize, reader->ReadU32()); } if (mFlags & 0x20) { MOZ_TRY_VAR(mDefaultSampleFlags, reader->ReadU32()); } return Ok(); }
Result<Ok, nsresult> Sbgp::Parse(Box& aBox) { BoxReader reader(aBox); uint32_t flags; MOZ_TRY_VAR(flags, reader->ReadU32()); const uint8_t version = flags >> 24; flags = flags & 0xffffff; uint32_t type; MOZ_TRY_VAR(type, reader->ReadU32()); mGroupingType = type; if (version == 1) { MOZ_TRY_VAR(mGroupingTypeParam, reader->ReadU32()); } uint32_t count; MOZ_TRY_VAR(count, reader->ReadU32()); for (uint32_t i = 0; i < count; i++) { uint32_t sampleCount; MOZ_TRY_VAR(sampleCount, reader->ReadU32()); uint32_t groupDescriptionIndex; MOZ_TRY_VAR(groupDescriptionIndex, reader->ReadU32()); SampleToGroupEntry entry(sampleCount, groupDescriptionIndex); if (!mEntries.AppendElement(entry, mozilla::fallible)) { LOG(Sbgp, "OOM"); return Err(NS_ERROR_FAILURE); } } return Ok(); }
Result<Ok, nsresult> Saio::Parse(Box& aBox) { BoxReader reader(aBox); uint32_t flags; MOZ_TRY_VAR(flags, reader->ReadU32()); uint8_t version = flags >> 24; if (flags & 1) { MOZ_TRY_VAR(mAuxInfoType, reader->ReadU32()); MOZ_TRY_VAR(mAuxInfoTypeParameter, reader->ReadU32()); } size_t count; MOZ_TRY_VAR(count, reader->ReadU32()); if (!mOffsets.SetCapacity(count, fallible)) { LOG(Saiz, "OOM"); return Err(NS_ERROR_FAILURE); } if (version == 0) { uint32_t offset; for (size_t i = 0; i < count; i++) { MOZ_TRY_VAR(offset, reader->ReadU32()); MOZ_ALWAYS_TRUE(mOffsets.AppendElement(offset, fallible)); } } else { uint64_t offset; for (size_t i = 0; i < count; i++) { MOZ_TRY_VAR(offset, reader->ReadU64()); MOZ_ALWAYS_TRUE(mOffsets.AppendElement(offset, fallible)); } } return Ok(); }
Result<Ok, nsresult> SinfParser::ParseSchm(Box& aBox) { BoxReader reader(aBox); if (reader->Remaining() < 8) { return Err(NS_ERROR_FAILURE); } MOZ_TRY(reader->ReadU32()); // flags -- ignore MOZ_TRY_VAR(mSinf.mDefaultEncryptionType, reader->ReadU32()); return Ok(); }
Result<Ok, nsresult> Trex::Parse(Box& aBox) { BoxReader reader(aBox); MOZ_TRY_VAR(mFlags, reader->ReadU32()); MOZ_TRY_VAR(mTrackId, reader->ReadU32()); MOZ_TRY_VAR(mDefaultSampleDescriptionIndex, reader->ReadU32()); MOZ_TRY_VAR(mDefaultSampleDuration, reader->ReadU32()); MOZ_TRY_VAR(mDefaultSampleSize, reader->ReadU32()); MOZ_TRY_VAR(mDefaultSampleFlags, reader->ReadU32()); return Ok(); }
template<typename Tok> JS::Result<Ok> BinASTParser<Tok>::parseAndUpdateScopeNames(ParseContext::Scope& scope, DeclarationKind kind) { AutoList guard(*tokenizer_); uint32_t length = 0; MOZ_TRY(tokenizer_->enterList(length, guard)); RootedAtom name(cx_); for (uint32_t i = 0; i < length; ++i) { name = nullptr; MOZ_TRY_VAR(name, tokenizer_->readAtom()); auto ptr = scope.lookupDeclaredNameForAdd(name); if (ptr) return raiseError("Variable redeclaration"); BINJS_TRY(scope.addDeclaredName(parseContext_, ptr, name.get(), kind, tokenizer_->offset())); } MOZ_TRY(guard.done()); return Ok(); }
Result<Ok, nsresult> Edts::Parse(Box& aBox) { Box child = aBox.FirstChild(); if (!child.IsType("elst")) { return Err(NS_ERROR_FAILURE); } BoxReader reader(child); uint32_t flags; MOZ_TRY_VAR(flags, reader->ReadU32()); uint8_t version = flags >> 24; bool emptyEntry = false; uint32_t entryCount; MOZ_TRY_VAR(entryCount, reader->ReadU32()); for (uint32_t i = 0; i < entryCount; i++) { uint64_t segment_duration; int64_t media_time; if (version == 1) { MOZ_TRY_VAR(segment_duration, reader->ReadU64()); MOZ_TRY_VAR(media_time, reader->Read64()); } else { uint32_t tmp; MOZ_TRY_VAR(tmp, reader->ReadU32()); segment_duration = tmp; int32_t tmp2; MOZ_TRY_VAR(tmp2, reader->Read32()); media_time = tmp2; } if (media_time == -1 && i) { LOG(Edts, "Multiple empty edit, not handled"); } else if (media_time == -1) { mEmptyOffset = segment_duration; emptyEntry = true; } else if (i > 1 || (i > 0 && !emptyEntry)) { LOG(Edts, "More than one edit entry, not handled. A/V sync will be wrong"); break; } else { mMediaStart = media_time; } MOZ_TRY(reader->ReadU32()); // media_rate_integer and media_rate_fraction } return Ok(); }
template<typename Tok> JS::Result<Ok> BinASTParser<Tok>::parseAndUpdateCapturedNames(const BinKind kind) { // For the moment, we do not attempt to validate the list of captured names. AutoList guard(*tokenizer_); uint32_t length = 0; MOZ_TRY(tokenizer_->enterList(length, guard)); RootedAtom name(cx_); for (uint32_t i = 0; i < length; ++i) { name = nullptr; MOZ_TRY_VAR(name, tokenizer_->readAtom()); if (kind == BinKind::AssertedParameterScope) { MOZ_ASSERT(parseContext_->isFunctionBox()); if (parseContext_->functionBox()->function()->isNamedLambda()) { if (TryMarkCaptureInScope(parseContext_->namedLambdaScope(), name)) continue; } if (!TryMarkCaptureInScope(parseContext_->functionScope(), name)) return raiseUndeclaredCapture(name); continue; } if (kind == BinKind::AssertedVarScope) { if (TryMarkCaptureInScope(parseContext_->varScope(), name)) continue; } if (!TryMarkCaptureInScope(*parseContext_->innermostScope(), name)) return raiseUndeclaredCapture(name); } MOZ_TRY(guard.done()); return Ok(); }
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(); }
Result<bool, nsresult> FrameParser::VBRHeader::ParseXing( BufferReader* aReader) { static const uint32_t XING_TAG = BigEndian::readUint32("Xing"); static const uint32_t INFO_TAG = BigEndian::readUint32("Info"); enum Flags { NUM_FRAMES = 0x01, NUM_BYTES = 0x02, TOC = 0x04, VBR_SCALE = 0x08 }; MOZ_ASSERT(aReader); // Seek backward to the original position before leaving this scope. const size_t prevReaderOffset = aReader->Offset(); auto scopeExit = MakeScopeExit([&] { aReader->Seek(prevReaderOffset); }); // We have to search for the Xing header as its position can change. for (auto res = aReader->PeekU32(); res.isOk() && res.unwrap() != XING_TAG && res.unwrap() != INFO_TAG;) { aReader->Read(1); res = aReader->PeekU32(); } // Skip across the VBR header ID tag. MOZ_TRY(aReader->ReadU32()); mType = XING; uint32_t flags; MOZ_TRY_VAR(flags, aReader->ReadU32()); if (flags & NUM_FRAMES) { uint32_t frames; MOZ_TRY_VAR(frames, aReader->ReadU32()); mNumAudioFrames = Some(frames); } if (flags & NUM_BYTES) { uint32_t bytes; MOZ_TRY_VAR(bytes, aReader->ReadU32()); mNumBytes = Some(bytes); } if (flags & TOC && aReader->Remaining() >= vbr_header::TOC_SIZE) { if (!mNumBytes) { // We don't have the stream size to calculate offsets, skip the TOC. aReader->Read(vbr_header::TOC_SIZE); } else { mTOC.clear(); mTOC.reserve(vbr_header::TOC_SIZE); uint8_t data; for (size_t i = 0; i < vbr_header::TOC_SIZE; ++i) { MOZ_TRY_VAR(data, aReader->ReadU8()); mTOC.push_back(1.0f / 256.0f * data * mNumBytes.value()); } } } if (flags & VBR_SCALE) { uint32_t scale; MOZ_TRY_VAR(scale, aReader->ReadU32()); mScale = Some(scale); } return mType == XING; }
Result<Ok, nsresult> Tkhd::Parse(Box& aBox) { BoxReader reader(aBox); uint32_t flags; MOZ_TRY_VAR(flags, reader->ReadU32()); uint8_t version = flags >> 24; if (version == 0) { uint32_t creationTime, modificationTime, reserved, duration; MOZ_TRY_VAR(creationTime, reader->ReadU32()); MOZ_TRY_VAR(modificationTime, reader->ReadU32()); MOZ_TRY_VAR(mTrackId, reader->ReadU32()); MOZ_TRY_VAR(reserved, reader->ReadU32()); MOZ_TRY_VAR(duration, reader->ReadU32()); NS_ASSERTION(!reserved, "reserved should be 0"); mCreationTime = creationTime; mModificationTime = modificationTime; mDuration = duration; } else if (version == 1) { uint32_t reserved; MOZ_TRY_VAR(mCreationTime, reader->ReadU64()); MOZ_TRY_VAR(mModificationTime, reader->ReadU64()); MOZ_TRY_VAR(mTrackId, reader->ReadU32()); MOZ_TRY_VAR(reserved, reader->ReadU32()); NS_ASSERTION(!reserved, "reserved should be 0"); MOZ_TRY_VAR(mDuration, reader->ReadU64()); } return Ok(); }