Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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();
}
Ejemplo n.º 3
0
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();
}
Ejemplo n.º 4
0
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();
}
Ejemplo n.º 5
0
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();
}
Ejemplo n.º 6
0
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.
}
Ejemplo n.º 7
0
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();
}
Ejemplo n.º 8
0
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();
}
Ejemplo n.º 9
0
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();
}
Ejemplo n.º 10
0
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();
}
Ejemplo n.º 11
0
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();
}
Ejemplo n.º 12
0
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();
}
Ejemplo n.º 13
0
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();
}
Ejemplo n.º 14
0
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();
}
Ejemplo n.º 15
0
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();
}
Ejemplo n.º 16
0
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();
}
Ejemplo n.º 17
0
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();
}
Ejemplo n.º 18
0
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;
}
Ejemplo n.º 19
0
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();
}