Bug 1098126 - Add CENC support to MoofParser; r=edwin
authorAnthony Jones <ajones@mozilla.com>
Tue, 16 Dec 2014 18:10:45 +1300
changeset 219895 73275f4fe25290906c974c4e48b2a247e0d63ea9
parent 219894 4d13ae62208053f9fce5a6fe60be3b6e2f854a2f
child 219896 0cb3299f2a30e637494a55d0a5ac0ff9077c3ae6
push id10419
push usercbook@mozilla.com
push dateTue, 16 Dec 2014 12:45:27 +0000
treeherderfx-team@ec87657146eb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersedwin
bugs1098126
milestone37.0a1
Bug 1098126 - Add CENC support to MoofParser; r=edwin
dom/media/MediaResource.h
media/libstagefright/binding/Box.cpp
media/libstagefright/binding/Index.cpp
media/libstagefright/binding/MoofParser.cpp
media/libstagefright/binding/include/mp4_demuxer/AtomType.h
media/libstagefright/binding/include/mp4_demuxer/Box.h
media/libstagefright/binding/include/mp4_demuxer/ByteReader.h
media/libstagefright/binding/include/mp4_demuxer/Index.h
media/libstagefright/binding/include/mp4_demuxer/MoofParser.h
media/libstagefright/binding/mp4_demuxer.cpp
media/libstagefright/moz.build
--- a/dom/media/MediaResource.h
+++ b/dom/media/MediaResource.h
@@ -160,16 +160,18 @@ public:
   {
     if (IsNull()) {
       return aByteRange;
     }
     return MediaByteRange(std::min(mStart, aByteRange.mStart),
                           std::max(mEnd, aByteRange.mEnd));
   }
 
+  int64_t Length() { return mEnd - mStart; }
+
   int64_t mStart, mEnd;
 };
 
 // Represents a section of contiguous media, with a start and end offset, and
 // a timestamp representing the start time.
 class TimestampedMediaByteRange : public MediaByteRange {
 public:
   TimestampedMediaByteRange() : MediaByteRange(), mStartTime(-1) {}
--- a/media/libstagefright/binding/Box.cpp
+++ b/media/libstagefright/binding/Box.cpp
@@ -8,17 +8,17 @@
 #include "mp4_demuxer/mp4_demuxer.h"
 #include "mozilla/Endian.h"
 
 using namespace mozilla;
 
 namespace mp4_demuxer {
 
 Box::Box(BoxContext* aContext, uint64_t aOffset, const Box* aParent)
-  : mContext(aContext), mType(0), mParent(aParent)
+  : mContext(aContext), mParent(aParent)
 {
   uint8_t header[8];
   MediaByteRange headerRange(aOffset, aOffset + sizeof(header));
   if (mParent && !mParent->mRange.Contains(headerRange)) {
     return;
   }
 
   const MediaByteRange* byteRange;
@@ -64,17 +64,17 @@ Box::Box(BoxContext* aContext, uint64_t 
       !byteRange->Contains(boxRange)) {
     return;
   }
   mRange = boxRange;
   mType = BigEndian::readUint32(&header[4]);
 }
 
 Box::Box()
-  : mContext(nullptr), mType(0)
+  : mContext(nullptr)
 {}
 
 Box
 Box::Next() const
 {
   MOZ_ASSERT(IsAvailable());
   return Box(mContext, mRange.mEnd, mParent);
 }
--- a/media/libstagefright/binding/Index.cpp
+++ b/media/libstagefright/binding/Index.cpp
@@ -1,12 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "mp4_demuxer/ByteReader.h"
 #include "mp4_demuxer/Index.h"
 #include "mp4_demuxer/Interval.h"
 #include "mp4_demuxer/MoofParser.h"
 #include "media/stagefright/MediaSource.h"
 #include "MediaResource.h"
 
 #include <algorithm>
 #include <limits>
@@ -79,90 +80,107 @@ SampleIterator::SampleIterator(Index* aI
   : mIndex(aIndex)
   , mCurrentMoof(0)
   , mCurrentSample(0)
 {
 }
 
 MP4Sample* SampleIterator::GetNext()
 {
-  nsAutoPtr<MP4Sample> sample(Get());
-  if (!sample) {
+  Sample* s(Get());
+  if (!s) {
     return nullptr;
   }
 
+  Next();
+
+  nsAutoPtr<MP4Sample> sample(new MP4Sample());
+  sample->decode_timestamp = s->mDecodeTime;
+  sample->composition_timestamp = s->mCompositionRange.start;
+  sample->duration = s->mCompositionRange.Length();
+  sample->byte_offset = s->mByteRange.mStart;
+  sample->is_sync_point = s->mSync;
+  sample->size = s->mByteRange.Length();
+
   // Do the blocking read
   sample->data = sample->extra_buffer = new uint8_t[sample->size];
 
   size_t bytesRead;
-  mIndex->mSource->ReadAt(sample->byte_offset, sample->data, sample->size,
-                          &bytesRead);
+  if (!mIndex->mSource->ReadAt(sample->byte_offset, sample->data, sample->size,
+                               &bytesRead) || bytesRead != sample->size) {
+    return nullptr;
+  }
 
-  // Lets just return what we've got so that we propagate the error
-  sample->size = bytesRead;
-
-  Next();
+  if (!s->mCencRange.IsNull()) {
+    // The size comes from an 8 bit field
+    nsAutoTArray<uint8_t, 256> cenc;
+    cenc.SetLength(s->mCencRange.Length());
+    if (!mIndex->mSource->ReadAt(s->mCencRange.mStart, &cenc[0], cenc.Length(),
+                                 &bytesRead) || bytesRead != cenc.Length()) {
+      return nullptr;
+    }
+    ByteReader reader(cenc);
+    sample->crypto.valid = true;
+    reader.ReadArray(sample->crypto.iv, 16);
+    if (reader.Remaining()) {
+      uint16_t count = reader.ReadU16();
+      for (size_t i = 0; i < count; i++) {
+        sample->crypto.plain_sizes.AppendElement(reader.ReadU16());
+        sample->crypto.encrypted_sizes.AppendElement(reader.ReadU32());
+      }
+    }
+  }
 
   return sample.forget();
 }
 
-MP4Sample* SampleIterator::Get()
+Sample* SampleIterator::Get()
 {
   if (!mIndex->mMoofParser) {
     return nullptr;
   }
 
   nsTArray<Moof>& moofs = mIndex->mMoofParser->mMoofs;
   while (true) {
     if (mCurrentMoof == moofs.Length()) {
       if (!mIndex->mMoofParser->BlockingReadNextMoof()) {
-        return nsAutoPtr<MP4Sample>();
+        return nullptr;
       }
       MOZ_ASSERT(mCurrentMoof < moofs.Length());
     }
     if (mCurrentSample < moofs[mCurrentMoof].mIndex.Length()) {
       break;
     }
     mCurrentSample = 0;
     ++mCurrentMoof;
   }
-  Sample& s = moofs[mCurrentMoof].mIndex[mCurrentSample];
-  nsAutoPtr<MP4Sample> sample(new MP4Sample());
-  sample->decode_timestamp = s.mDecodeTime;
-  sample->composition_timestamp = s.mCompositionRange.start;
-  sample->duration = s.mCompositionRange.end - s.mCompositionRange.start;
-  sample->byte_offset = s.mByteRange.mStart;
-  sample->is_sync_point = s.mSync;
-
-  sample->size = s.mByteRange.mEnd - s.mByteRange.mStart;
-
-  return sample.forget();
+  return &moofs[mCurrentMoof].mIndex[mCurrentSample];
 }
 
 void SampleIterator::Next()
 {
   ++mCurrentSample;
 }
 
 void SampleIterator::Seek(Microseconds aTime)
 {
   size_t syncMoof = 0;
   size_t syncSample = 0;
   mCurrentMoof = 0;
   mCurrentSample = 0;
-  while (true) {
-    nsAutoPtr<MP4Sample> sample(Get());
-    if (sample->composition_timestamp > aTime) {
+  Sample* sample;
+  while (!!(sample = Get())) {
+    if (sample->mCompositionRange.start > aTime) {
       break;
     }
-    if (sample->is_sync_point) {
+    if (sample->mSync) {
       syncMoof = mCurrentMoof;
       syncSample = mCurrentSample;
     }
-    if (sample->composition_timestamp == aTime) {
+    if (sample->mCompositionRange.start == aTime) {
       break;
     }
     Next();
   }
   mCurrentMoof = syncMoof;
   mCurrentSample = syncSample;
 }
 
--- a/media/libstagefright/binding/MoofParser.cpp
+++ b/media/libstagefright/binding/MoofParser.cpp
@@ -168,16 +168,81 @@ MoofParser::ParseMvex(Box& aBox)
 Moof::Moof(Box& aBox, Trex& aTrex, Mdhd& aMdhd, Edts& aEdts) :
     mRange(aBox.Range()), mMaxRoundingError(0)
 {
   for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
     if (box.IsType("traf")) {
       ParseTraf(box, aTrex, aMdhd, aEdts);
     }
   }
+  ProcessCenc();
+}
+
+bool
+Moof::GetAuxInfo(AtomType aType, nsTArray<MediaByteRange>* aByteRanges)
+{
+  aByteRanges->Clear();
+
+  Saiz* saiz = nullptr;
+  for (int i = 0; ; i++) {
+    if (i == mSaizs.Length()) {
+      return false;
+    }
+    if (mSaizs[i].mAuxInfoType == aType) {
+      saiz = &mSaizs[i];
+      break;
+    }
+  }
+  Saio* saio = nullptr;
+  for (int i = 0; ; i++) {
+    if (i == mSaios.Length()) {
+      return false;
+    }
+    if (mSaios[i].mAuxInfoType == aType) {
+      saio = &mSaios[i];
+      break;
+    }
+  }
+
+  if (saio->mOffsets.Length() == 1) {
+    aByteRanges->SetCapacity(saiz->mSampleInfoSize.Length());
+    uint64_t offset = mRange.mStart + saio->mOffsets[0];
+    for (size_t i = 0; i < saiz->mSampleInfoSize.Length(); i++) {
+      aByteRanges->AppendElement(
+        MediaByteRange(offset, offset + saiz->mSampleInfoSize[i]));
+      offset += saiz->mSampleInfoSize[i];
+    }
+    return true;
+  }
+
+  if (saio->mOffsets.Length() == saiz->mSampleInfoSize.Length()) {
+    aByteRanges->SetCapacity(saiz->mSampleInfoSize.Length());
+    for (size_t i = 0; i < saio->mOffsets.Length(); i++) {
+      uint64_t offset = mRange.mStart + saio->mOffsets[i];
+      aByteRanges->AppendElement(
+        MediaByteRange(offset, offset + saiz->mSampleInfoSize[i]));
+    }
+    return true;
+  }
+
+  return false;
+}
+
+bool
+Moof::ProcessCenc()
+{
+  nsTArray<MediaByteRange> cencRanges;
+  if (!GetAuxInfo(AtomType("cenc"), &cencRanges) ||
+      cencRanges.Length() != mIndex.Length()) {
+    return false;
+  }
+  for (int i = 0; i < cencRanges.Length(); i++) {
+    mIndex[i].mCencRange = cencRanges[i];
+  }
+  return true;
 }
 
 void
 Moof::ParseTraf(Box& aBox, Trex& aTrex, Mdhd& aMdhd, Edts& aEdts)
 {
   Tfhd tfhd(aTrex);
   Tfdt tfdt;
   for (Box box = aBox.FirstChild(); box.IsAvailable(); box = box.Next()) {
@@ -186,16 +251,20 @@ Moof::ParseTraf(Box& aBox, Trex& aTrex, 
     } else if (box.IsType("tfdt")) {
       if (!aTrex.mTrackId || tfhd.mTrackId == aTrex.mTrackId) {
         tfdt = Tfdt(box);
       }
     } else if (box.IsType("trun")) {
       if (!aTrex.mTrackId || tfhd.mTrackId == aTrex.mTrackId) {
         ParseTrun(box, tfhd, tfdt, aMdhd, aEdts);
       }
+    } else if (box.IsType("saiz")) {
+      mSaizs.AppendElement(Saiz(box));
+    } else if (box.IsType("saio")) {
+      mSaios.AppendElement(Saio(box));
     }
   }
 }
 
 void
 Moof::FixRounding(const Moof& aMoof) {
   Microseconds gap = aMoof.mTimeRange.start - mTimeRange.end;
   if (gap > 0 && gap <= mMaxRoundingError) {
@@ -280,17 +349,17 @@ Moof::ParseTrun(Box& aBox, Tfhd& aTfhd, 
   mMaxRoundingError += aMdhd.ToMicroseconds(sampleCount);
 
   nsTArray<Sample*> ctsOrder;
   for (int i = 0; i < mIndex.Length(); i++) {
     ctsOrder.AppendElement(&mIndex[i]);
   }
   ctsOrder.Sort(CtsComparator());
 
-  for (int i = 0; i < ctsOrder.Length(); i++) {
+  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);
 }
 
@@ -412,9 +481,53 @@ Edts::Edts(Box& aBox)
     mMediaStart = reader->Read64();
   } else {
     segment_duration = reader->ReadU32();
     mMediaStart = reader->Read32();
   }
   NS_ASSERTION(segment_duration == 0, "Can't handle edits with fixed durations");
   reader->DiscardRemaining();
 }
+
+Saiz::Saiz(Box& aBox) : mAuxInfoType("sinf"), mAuxInfoTypeParameter(0)
+{
+  BoxReader reader(aBox);
+  uint32_t flags = reader->ReadU32();
+  uint8_t version = flags >> 24;
+
+  if (flags & 1) {
+    mAuxInfoType = reader->ReadU32();
+    mAuxInfoTypeParameter = reader->ReadU32();
+  }
+  uint8_t defaultSampleInfoSize = reader->ReadU8();
+  uint32_t count = reader->ReadU32();
+  if (defaultSampleInfoSize) {
+    for (int i = 0; i < count; i++) {
+      mSampleInfoSize.AppendElement(defaultSampleInfoSize);
+    }
+  } else {
+    reader->ReadArray(mSampleInfoSize, count);
+  }
 }
+
+Saio::Saio(Box& aBox) : mAuxInfoType("sinf"), mAuxInfoTypeParameter(0)
+{
+  BoxReader reader(aBox);
+  uint32_t flags = reader->ReadU32();
+  uint8_t version = flags >> 24;
+
+  if (flags & 1) {
+    mAuxInfoType = reader->ReadU32();
+    mAuxInfoTypeParameter = reader->ReadU32();
+  }
+  size_t count = reader->ReadU32();
+  mOffsets.SetCapacity(count);
+  if (version == 0) {
+    for (size_t i = 0; i < count; i++) {
+      mOffsets.AppendElement(reader->ReadU32());
+    }
+  } else {
+    for (size_t i = 0; i < count; i++) {
+      mOffsets.AppendElement(reader->ReadU64());
+    }
+  }
+}
+}
new file mode 100644
--- /dev/null
+++ b/media/libstagefright/binding/include/mp4_demuxer/AtomType.h
@@ -0,0 +1,30 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef ATOM_TYPE_H_
+#define ATOM_TYPE_H_
+
+#include <stdint.h>
+#include "mozilla/Endian.h"
+
+using namespace mozilla;
+
+namespace mp4_demuxer {
+
+class AtomType
+{
+public:
+  AtomType() : mType(0) { }
+  AtomType(uint32_t aType) : mType(aType) { }
+  AtomType(const char* aType) : mType(BigEndian::readUint32(aType)) { }
+  bool operator==(const AtomType& aType) const { return mType == aType.mType; }
+
+private:
+  uint32_t mType;
+};
+}
+
+#endif
--- a/media/libstagefright/binding/include/mp4_demuxer/Box.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/Box.h
@@ -6,16 +6,17 @@
 
 #ifndef BOX_H_
 #define BOX_H_
 
 #include <stdint.h>
 #include "nsTArray.h"
 #include "MediaResource.h"
 #include "mozilla/Endian.h"
+#include "mp4_demuxer/AtomType.h"
 #include "mp4_demuxer/ByteReader.h"
 
 using namespace mozilla;
 
 namespace mp4_demuxer {
 
 class Stream;
 
@@ -37,34 +38,29 @@ public:
   Box(BoxContext* aContext, uint64_t aOffset, const Box* aParent = nullptr);
   Box();
 
   bool IsAvailable() const { return !mRange.IsNull(); }
   uint64_t Offset() const { return mRange.mStart; }
   uint64_t Length() const { return mRange.mEnd - mRange.mStart; }
   uint64_t NextOffset() const { return mRange.mEnd; }
   const MediaByteRange& Range() const { return mRange; }
-
   const Box* Parent() const { return mParent; }
-
-  bool IsType(const char* aType) const
-  {
-    return mType == BigEndian::readUint32(aType);
-  }
+  bool IsType(const char* aType) const { return mType == AtomType(aType); }
 
   Box Next() const;
   Box FirstChild() const;
   void Read(nsTArray<uint8_t>* aDest);
 
 private:
   bool Contains(MediaByteRange aRange) const;
   BoxContext* mContext;
   mozilla::MediaByteRange mRange;
   uint64_t mChildOffset;
-  uint32_t mType;
+  AtomType mType;
   const Box* mParent;
 };
 
 class BoxReader
 {
 public:
   explicit BoxReader(Box& aBox)
   {
--- a/media/libstagefright/binding/include/mp4_demuxer/ByteReader.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/ByteReader.h
@@ -18,16 +18,22 @@ public:
   explicit ByteReader(const mozilla::Vector<uint8_t>& aData)
     : mPtr(&aData[0]), mRemaining(aData.length())
   {
   }
   ByteReader(const uint8_t* aData, size_t aSize)
     : mPtr(aData), mRemaining(aSize)
   {
   }
+  template<size_t S>
+  ByteReader(const nsAutoTArray<uint8_t, S>& aData)
+    : mPtr(&aData[0]), mRemaining(aData.Length())
+  {
+  }
+
   void SetData(const nsTArray<uint8_t>& aData)
   {
     MOZ_ASSERT(!mPtr && !mRemaining);
     mPtr = &aData[0];
     mRemaining = aData.Length();
   }
 
   ~ByteReader()
--- a/media/libstagefright/binding/include/mp4_demuxer/Index.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/Index.h
@@ -19,17 +19,17 @@ class Index;
 class SampleIterator
 {
 public:
   SampleIterator(Index* aIndex);
   MP4Sample* GetNext();
   void Seek(Microseconds aTime);
 
 private:
-  MP4Sample* Get();
+  Sample* Get();
   void Next();
   nsRefPtr<Index> mIndex;
   size_t mCurrentMoof;
   size_t mCurrentSample;
 };
 
 class Index
 {
--- a/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h
@@ -1,15 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MOOF_PARSER_H_
 #define MOOF_PARSER_H_
 
+#include "mp4_demuxer/AtomType.h"
 #include "mp4_demuxer/mp4_demuxer.h"
 #include "MediaResource.h"
 
 namespace mp4_demuxer {
 
 class Stream;
 class Box;
 class BoxContext;
@@ -104,35 +105,75 @@ public:
   explicit Edts(Box& aBox);
 
   int64_t mMediaStart;
 };
 
 struct Sample
 {
   mozilla::MediaByteRange mByteRange;
+  mozilla::MediaByteRange mCencRange;
   Microseconds mDecodeTime;
   Interval<Microseconds> mCompositionRange;
   bool mSync;
 };
 
+class Saiz
+{
+public:
+  Saiz(Box& aBox);
+
+  AtomType mAuxInfoType;
+  uint32_t mAuxInfoTypeParameter;
+  nsTArray<uint8_t> mSampleInfoSize;
+};
+
+class Saio
+{
+public:
+  Saio(Box& aBox);
+
+  AtomType mAuxInfoType;
+  uint32_t mAuxInfoTypeParameter;
+  nsTArray<uint64_t> mOffsets;
+};
+
+class AuxInfo {
+public:
+  AuxInfo(int64_t aMoofOffset, Saiz& aSaiz, Saio& aSaio);
+  bool GetByteRanges(nsTArray<MediaByteRange>* aByteRanges);
+
+private:
+
+  int64_t mMoofOffset;
+  Saiz& mSaiz;
+  Saio& mSaio;
+};
+
 class Moof
 {
 public:
   Moof(Box& aBox, Trex& aTrex, Mdhd& aMdhd, Edts& aEdts);
+  bool GetAuxInfo(AtomType aType, nsTArray<MediaByteRange>* aByteRanges);
   void FixRounding(const Moof& aMoof);
 
   mozilla::MediaByteRange mRange;
   mozilla::MediaByteRange mMdatRange;
   Interval<Microseconds> mTimeRange;
   nsTArray<Sample> mIndex;
 
+  nsTArray<Saiz> mSaizs;
+  nsTArray<Saio> mSaios;
+
 private:
   void ParseTraf(Box& aBox, Trex& aTrex, Mdhd& aMdhd, Edts& aEdts);
   void ParseTrun(Box& aBox, Tfhd& aTfhd, Tfdt& aTfdt, Mdhd& aMdhd, Edts& aEdts);
+  void ParseSaiz(Box& aBox);
+  void ParseSaio(Box& aBox);
+  bool ProcessCenc();
   uint64_t mMaxRoundingError;
 };
 
 class MoofParser
 {
 public:
   MoofParser(Stream* aSource, uint32_t aTrackId)
     : mSource(aSource), mOffset(0), mTrex(aTrackId)
--- a/media/libstagefright/binding/mp4_demuxer.cpp
+++ b/media/libstagefright/binding/mp4_demuxer.cpp
@@ -180,17 +180,25 @@ MP4Demuxer::SeekVideo(Microseconds aTime
       aTime, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
   }
 }
 
 MP4Sample*
 MP4Demuxer::DemuxAudioSample()
 {
   if (mPrivate->mAudioIterator) {
-    return mPrivate->mAudioIterator->GetNext();
+    nsAutoPtr<MP4Sample> sample(mPrivate->mAudioIterator->GetNext());
+    if (sample) {
+      if (sample->crypto.valid) {
+        sample->crypto.mode = mAudioConfig.crypto.mode;
+        sample->crypto.iv_size = mAudioConfig.crypto.iv_size;
+        sample->crypto.key.AppendElements(mAudioConfig.crypto.key);
+      }
+    }
+    return sample.forget();
   }
 
   nsAutoPtr<MP4Sample> sample(new MP4Sample());
   status_t status =
     mPrivate->mAudio->read(&sample->mMediaBuffer, &mPrivate->mAudioOptions);
   mPrivate->mAudioOptions.clearSeekTo();
 
   if (status < 0) {
@@ -204,16 +212,21 @@ MP4Demuxer::DemuxAudioSample()
 
 MP4Sample*
 MP4Demuxer::DemuxVideoSample()
 {
   if (mPrivate->mVideoIterator) {
     nsAutoPtr<MP4Sample> sample(mPrivate->mVideoIterator->GetNext());
     if (sample) {
       sample->prefix_data = mVideoConfig.annex_b;
+      if (sample->crypto.valid) {
+        sample->crypto.mode = mVideoConfig.crypto.mode;
+        sample->crypto.iv_size = mVideoConfig.crypto.iv_size;
+        sample->crypto.key.AppendElements(mVideoConfig.crypto.key);
+      }
     }
     return sample.forget();
   }
 
   nsAutoPtr<MP4Sample> sample(new MP4Sample());
   status_t status =
     mPrivate->mVideo->read(&sample->mMediaBuffer, &mPrivate->mVideoOptions);
   mPrivate->mVideoOptions.clearSeekTo();
--- a/media/libstagefright/moz.build
+++ b/media/libstagefright/moz.build
@@ -45,16 +45,17 @@ if CONFIG['OS_TARGET'] != 'Android':
         'system/core/libcutils/strdup16to8.c',
         'system/core/liblog/logd_write.c',
         'system/core/liblog/logprint.c',
     ]
 
 EXPORTS.mp4_demuxer += [
     'binding/include/mp4_demuxer/Adts.h',
     'binding/include/mp4_demuxer/AnnexB.h',
+    'binding/include/mp4_demuxer/AtomType.h',
     'binding/include/mp4_demuxer/BufferStream.h',
     'binding/include/mp4_demuxer/ByteReader.h',
     'binding/include/mp4_demuxer/DecoderData.h',
     'binding/include/mp4_demuxer/Interval.h',
     'binding/include/mp4_demuxer/MoofParser.h',
     'binding/include/mp4_demuxer/mp4_demuxer.h',
 ]