Bug 1156689: Part5. Add MP4Metadata class. r=kentuckyfriedtakahe
authorJean-Yves Avenard <jyavenard@mozilla.com>
Fri, 01 May 2015 15:26:50 +1000
changeset 273340 e6a5d030152c399a96a2cb3a545afbf429422afe
parent 273339 4b6149e01e96fc44ada6695359e2a0189f160684
child 273341 cfb189bc93684ce7bbf40b39f24f2af6dfef697b
push id863
push userraliiev@mozilla.com
push dateMon, 03 Aug 2015 13:22:43 +0000
treeherdermozilla-release@f6321b14228d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskentuckyfriedtakahe
bugs1156689
milestone40.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1156689: Part5. Add MP4Metadata class. r=kentuckyfriedtakahe This allows to abstract the calls to libstagefright and allow future replacement with our own code.
media/libstagefright/binding/MP4Metadata.cpp
media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h
media/libstagefright/binding/include/mp4_demuxer/mp4_demuxer.h
media/libstagefright/binding/mp4_demuxer.cpp
media/libstagefright/moz.build
new file mode 100644
--- /dev/null
+++ b/media/libstagefright/binding/MP4Metadata.cpp
@@ -0,0 +1,267 @@
+/* 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 "include/MPEG4Extractor.h"
+#include "media/stagefright/DataSource.h"
+#include "media/stagefright/MediaDefs.h"
+#include "media/stagefright/MediaSource.h"
+#include "media/stagefright/MetaData.h"
+#include "mozilla/Monitor.h"
+#include "mp4_demuxer/MP4Metadata.h"
+
+#include <limits>
+#include <stdint.h>
+
+using namespace stagefright;
+
+namespace mp4_demuxer
+{
+
+struct StageFrightPrivate
+{
+  StageFrightPrivate()
+    : mCanSeek(false) {}
+  sp<MediaExtractor> mMetadataExtractor;
+
+  bool mCanSeek;
+};
+
+class DataSourceAdapter : public DataSource
+{
+public:
+  explicit DataSourceAdapter(Stream* aSource) : mSource(aSource) {}
+
+  ~DataSourceAdapter() {}
+
+  virtual status_t initCheck() const { return NO_ERROR; }
+
+  virtual ssize_t readAt(off64_t offset, void* data, size_t size)
+  {
+    MOZ_ASSERT(((ssize_t)size) >= 0);
+    size_t bytesRead;
+    if (!mSource->ReadAt(offset, data, size, &bytesRead))
+      return ERROR_IO;
+
+    if (bytesRead == 0)
+      return ERROR_END_OF_STREAM;
+
+    MOZ_ASSERT(((ssize_t)bytesRead) > 0);
+    return bytesRead;
+  }
+
+  virtual status_t getSize(off64_t* size)
+  {
+    if (!mSource->Length(size))
+      return ERROR_UNSUPPORTED;
+    return NO_ERROR;
+  }
+
+  virtual uint32_t flags() { return kWantsPrefetching | kIsHTTPBasedSource; }
+
+  virtual status_t reconnectAtOffset(off64_t offset) { return NO_ERROR; }
+
+private:
+  nsRefPtr<Stream> mSource;
+};
+
+static inline void
+ConvertIndex(nsTArray<Index::Indice>& aDest,
+             const stagefright::Vector<stagefright::MediaSource::Indice>& aIndex)
+{
+  for (size_t i = 0; i < aIndex.size(); i++) {
+    Index::Indice indice;
+    const stagefright::MediaSource::Indice& s_indice = aIndex[i];
+    indice.start_offset = s_indice.start_offset;
+    indice.end_offset = s_indice.end_offset;
+    indice.start_composition = s_indice.start_composition;
+    indice.end_composition = s_indice.end_composition;
+    indice.sync = s_indice.sync;
+    aDest.AppendElement(indice);
+  }
+}
+
+MP4Metadata::MP4Metadata(Stream* aSource)
+  : mPrivate(new StageFrightPrivate)
+  , mSource(aSource)
+{
+  mPrivate->mMetadataExtractor =
+    new MPEG4Extractor(new DataSourceAdapter(mSource));
+  mPrivate->mCanSeek =
+    mPrivate->mMetadataExtractor->flags() & MediaExtractor::CAN_SEEK;
+  sp<MetaData> metaData = mPrivate->mMetadataExtractor->getMetaData();
+
+  UpdateCrypto(metaData.get());
+}
+
+MP4Metadata::~MP4Metadata()
+{
+}
+
+uint32_t
+MP4Metadata::GetNumberTracks(mozilla::TrackInfo::TrackType aType) const
+{
+  size_t tracks = mPrivate->mMetadataExtractor->countTracks();
+  uint32_t total = 0;
+  for (size_t i = 0; i < tracks; i++) {
+    sp<MetaData> metaData = mPrivate->mMetadataExtractor->getTrackMetaData(i);
+
+    const char* mimeType;
+    if (metaData == nullptr || !metaData->findCString(kKeyMIMEType, &mimeType)) {
+      continue;
+    }
+    switch (aType) {
+      case mozilla::TrackInfo::kAudioTrack:
+        if (!strncmp(mimeType, "audio/", 6)) {
+          total++;
+        }
+        break;
+      case mozilla::TrackInfo::kVideoTrack:
+        if (!strncmp(mimeType, "video/", 6)) {
+          total++;
+        }
+        break;
+      default:
+        break;
+    }
+  }
+  return total;
+}
+
+mozilla::UniquePtr<mozilla::TrackInfo>
+MP4Metadata::GetTrackInfo(mozilla::TrackInfo::TrackType aType,
+                          size_t aTrackNumber) const
+{
+  size_t tracks = mPrivate->mMetadataExtractor->countTracks();
+  if (!tracks) {
+    return nullptr;
+  }
+  int32_t index = -1;
+  const char* mimeType;
+  sp<MetaData> metaData;
+
+  size_t i = 0;
+  while (i < tracks) {
+    metaData = mPrivate->mMetadataExtractor->getTrackMetaData(i);
+
+    if (metaData == nullptr || !metaData->findCString(kKeyMIMEType, &mimeType)) {
+      continue;
+    }
+    switch (aType) {
+      case mozilla::TrackInfo::kAudioTrack:
+        if (!strncmp(mimeType, "audio/", 6)) {
+          index++;
+        }
+        break;
+      case mozilla::TrackInfo::kVideoTrack:
+        if (!strncmp(mimeType, "video/", 6)) {
+          index++;
+        }
+        break;
+      default:
+        break;
+    }
+    if (index == aTrackNumber) {
+      break;
+    }
+    i++;
+  }
+  if (index < 0) {
+    return nullptr;
+  }
+
+  sp<MediaSource> track = mPrivate->mMetadataExtractor->getTrack(index);
+  if (!track.get() || track->start() != OK) {
+    return nullptr;
+  }
+
+  UniquePtr<mozilla::TrackInfo> e;
+
+  switch (aType) {
+    case mozilla::TrackInfo::kAudioTrack:
+    {
+      auto info = mozilla::MakeUnique<MP4AudioInfo>();
+      info->Update(metaData.get(), mimeType);
+      e = Move(info);
+    }
+      break;
+    case mozilla::TrackInfo::kVideoTrack:
+    {
+      auto info = mozilla::MakeUnique<MP4VideoInfo>();
+      info->Update(metaData.get(), mimeType);
+      e = Move(info);
+    }
+      break;
+    default:
+      break;
+  }
+
+  track->stop();
+  if (e) {
+    metaData = mPrivate->mMetadataExtractor->getMetaData();
+    int64_t movieDuration;
+    if (!e->mDuration &&
+        metaData->findInt64(kKeyMovieDuration, &movieDuration)) {
+      // No duration in track, use movie extend header box one.
+      e->mDuration = movieDuration;
+    }
+  }
+
+  return e;
+}
+
+bool
+MP4Metadata::CanSeek() const
+{
+  return mPrivate->mCanSeek;
+}
+
+void
+MP4Metadata::UpdateCrypto(const MetaData* aMetaData)
+{
+  const void* data;
+  size_t size;
+  uint32_t type;
+
+  // There's no point in checking that the type matches anything because it
+  // isn't set consistently in the MPEG4Extractor.
+  if (!aMetaData->findData(kKeyPssh, &type, &data, &size)) {
+    return;
+  }
+  mCrypto.Update(reinterpret_cast<const uint8_t*>(data), size);
+}
+
+bool
+MP4Metadata::ReadTrackIndex(nsTArray<Index::Indice>& aDest, mozilla::TrackID aTrackID)
+{
+  size_t numTracks = mPrivate->mMetadataExtractor->countTracks();
+  int32_t trackNumber = GetTrackNumber(aTrackID);
+  if (trackNumber < 0) {
+    return false;
+  }
+  sp<MediaSource> track = mPrivate->mMetadataExtractor->getTrack(trackNumber);
+  if (!track.get() || track->start() != OK) {
+    return false;
+  }
+  ConvertIndex(aDest, track->exportIndex());
+
+  track->stop();
+
+  return true;
+}
+
+int32_t
+MP4Metadata::GetTrackNumber(mozilla::TrackID aTrackID)
+{
+  size_t numTracks = mPrivate->mMetadataExtractor->countTracks();
+  for (size_t i = 0; i < numTracks; i++) {
+    sp<MetaData> metaData = mPrivate->mMetadataExtractor->getTrackMetaData(i);
+    int32_t value;
+    if (metaData->findInt32(kKeyTrackID, &value) && value == aTrackID) {
+      return i;
+    }
+  }
+  return -1;
+}
+
+} // namespace mp4_demuxer
new file mode 100644
--- /dev/null
+++ b/media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h
@@ -0,0 +1,53 @@
+/* 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 MP4METADATA_H_
+#define MP4METADATA_H_
+
+#include "mozilla/Monitor.h"
+#include "mozilla/UniquePtr.h"
+#include "mp4_demuxer/Index.h"
+#include "mp4_demuxer/DecoderData.h"
+#include "nsAutoPtr.h"
+#include "nsTArray.h"
+#include "MediaInfo.h"
+
+namespace mozilla { class MediaByteRange; }
+
+namespace stagefright { class MetaData; }
+
+namespace mp4_demuxer
+{
+
+struct StageFrightPrivate;
+
+class MP4Metadata
+{
+public:
+  explicit MP4Metadata(Stream* aSource);
+  ~MP4Metadata();
+
+  uint32_t GetNumberTracks(mozilla::TrackInfo::TrackType aType) const;
+  mozilla::UniquePtr<mozilla::TrackInfo> GetTrackInfo(mozilla::TrackInfo::TrackType aType,
+                                                      size_t aTrackNumber) const;
+  bool CanSeek() const;
+
+  const CryptoFile& Crypto() const
+  {
+    return mCrypto;
+  }
+
+  bool ReadTrackIndex(nsTArray<Index::Indice>& aDest, mozilla::TrackID aTrackID);
+
+private:
+  int32_t GetTrackNumber(mozilla::TrackID aTrackID);
+  void UpdateCrypto(const stagefright::MetaData* aMetaData);
+  nsAutoPtr<StageFrightPrivate> mPrivate;
+  CryptoFile mCrypto;
+  nsRefPtr<Stream> mSource;
+};
+
+} // namespace mp4_demuxer
+
+#endif // MP4METADATA_H_
--- a/media/libstagefright/binding/include/mp4_demuxer/mp4_demuxer.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/mp4_demuxer.h
@@ -1,30 +1,31 @@
 /* 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 MP4_DEMUXER_H_
 #define MP4_DEMUXER_H_
 
-#include "nsAutoPtr.h"
-#include "nsTArray.h"
+#include "MediaInfo.h"
+#include "MediaResource.h"
+#include "mozilla/Monitor.h"
+#include "mozilla/UniquePtr.h"
 #include "mp4_demuxer/DecoderData.h"
 #include "mp4_demuxer/Interval.h"
 #include "mp4_demuxer/Stream.h"
 #include "nsISupportsImpl.h"
-#include "mozilla/Monitor.h"
-
-namespace mozilla { class MediaByteRange; }
+#include "nsTArray.h"
 
 namespace mp4_demuxer
 {
-
+class Index;
+class MP4Metadata;
+class SampleIterator;
 using mozilla::Monitor;
-struct StageFrightPrivate;
 typedef int64_t Microseconds;
 
 class MP4Demuxer
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MP4Demuxer)
 
   explicit MP4Demuxer(Stream* aSource, Monitor* aMonitor);
@@ -39,19 +40,19 @@ public:
   void SeekAudio(Microseconds aTime);
   void SeekVideo(Microseconds aTime);
 
   // DemuxAudioSample and DemuxVideoSample functions
   // return nullptr on end of stream or error.
   already_AddRefed<mozilla::MediaRawData> DemuxAudioSample();
   already_AddRefed<mozilla::MediaRawData> DemuxVideoSample();
 
-  const CryptoFile& Crypto() { return mCrypto; }
-  const mozilla::AudioInfo& AudioConfig() { return mAudioConfig; }
-  const mozilla::VideoInfo& VideoConfig() { return mVideoConfig; }
+  const CryptoFile& Crypto() const;
+  const mozilla::AudioInfo& AudioConfig() const { return *mAudioConfig->GetAsAudioInfo(); }
+  const mozilla::VideoInfo& VideoConfig() const { return *mVideoConfig->GetAsVideoInfo(); }
 
   void UpdateIndex(const nsTArray<mozilla::MediaByteRange>& aByteRanges);
 
   void ConvertByteRangesToTime(
     const nsTArray<mozilla::MediaByteRange>& aByteRanges,
     nsTArray<Interval<Microseconds>>* aIntervals);
 
   int64_t GetEvictionOffset(Microseconds aTime);
@@ -59,24 +60,25 @@ public:
   // Returns timestamp of next keyframe, or -1 if demuxer can't
   // report this.
   Microseconds GetNextKeyframeTime();
 
 protected:
   ~MP4Demuxer();
 
 private:
-  void UpdateCrypto(const stagefright::MetaData* aMetaData);
-  MP4AudioInfo mAudioConfig;
-  MP4VideoInfo mVideoConfig;
-  CryptoFile mCrypto;
+  mozilla::UniquePtr<mozilla::TrackInfo> mAudioConfig;
+  mozilla::UniquePtr<mozilla::TrackInfo> mVideoConfig;
 
-  nsAutoPtr<StageFrightPrivate> mPrivate;
   nsRefPtr<Stream> mSource;
   nsTArray<mozilla::MediaByteRange> mCachedByteRanges;
   nsTArray<Interval<Microseconds>> mCachedTimeRanges;
   Monitor* mMonitor;
   Microseconds mNextKeyframeTime;
+  mozilla::UniquePtr<MP4Metadata> mMetadata;
+  mozilla::UniquePtr<SampleIterator> mAudioIterator;
+  mozilla::UniquePtr<SampleIterator> mVideoIterator;
+  nsTArray<nsRefPtr<Index>> mIndexes;
 };
 
-} // namespace mozilla
+} // namespace mp4_demuxer
 
 #endif // MP4_DEMUXER_H_
--- a/media/libstagefright/binding/mp4_demuxer.cpp
+++ b/media/libstagefright/binding/mp4_demuxer.cpp
@@ -1,326 +1,203 @@
 /* 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 "include/MPEG4Extractor.h"
-#include "media/stagefright/DataSource.h"
-#include "media/stagefright/MediaDefs.h"
-#include "media/stagefright/MediaSource.h"
-#include "media/stagefright/MetaData.h"
+#include "mp4_demuxer/Index.h"
+#include "mp4_demuxer/MP4Metadata.h"
 #include "mp4_demuxer/mp4_demuxer.h"
-#include "mp4_demuxer/Index.h"
-#include "MediaResource.h"
 
 #include <stdint.h>
 #include <algorithm>
 #include <limits>
 
-using namespace stagefright;
-
 namespace mp4_demuxer
 {
 
-struct StageFrightPrivate
-{
-  StageFrightPrivate() : mCanSeek(false) {}
-  sp<MediaSource> mAudio;
-  nsAutoPtr<SampleIterator> mAudioIterator;
-
-  sp<MediaSource> mVideo;
-  nsAutoPtr<SampleIterator> mVideoIterator;
-
-  nsTArray<nsRefPtr<Index>> mIndexes;
-
-  bool mCanSeek;
-};
-
-class DataSourceAdapter : public DataSource
-{
-public:
-  explicit DataSourceAdapter(Stream* aSource) : mSource(aSource) {}
-
-  ~DataSourceAdapter() {}
-
-  virtual status_t initCheck() const { return NO_ERROR; }
-
-  virtual ssize_t readAt(off64_t offset, void* data, size_t size)
-  {
-    MOZ_ASSERT(((ssize_t)size) >= 0);
-    size_t bytesRead;
-    if (!mSource->ReadAt(offset, data, size, &bytesRead))
-      return ERROR_IO;
-
-    if (bytesRead == 0)
-      return ERROR_END_OF_STREAM;
-
-    MOZ_ASSERT(((ssize_t)bytesRead) > 0);
-    return bytesRead;
-  }
-
-  virtual status_t getSize(off64_t* size)
-  {
-    if (!mSource->Length(size))
-      return ERROR_UNSUPPORTED;
-    return NO_ERROR;
-  }
-
-  virtual uint32_t flags() { return kWantsPrefetching | kIsHTTPBasedSource; }
-
-  virtual status_t reconnectAtOffset(off64_t offset) { return NO_ERROR; }
-
-private:
-  nsRefPtr<Stream> mSource;
-};
-
 MP4Demuxer::MP4Demuxer(Stream* source, Monitor* aMonitor)
-  : mPrivate(new StageFrightPrivate())
-  , mSource(source)
+  : mSource(source)
   , mMonitor(aMonitor)
   , mNextKeyframeTime(-1)
 {
 }
 
 MP4Demuxer::~MP4Demuxer()
 {
-  if (mPrivate->mAudio.get()) {
-    mPrivate->mAudio->stop();
-  }
-  if (mPrivate->mVideo.get()) {
-    mPrivate->mVideo->stop();
-  }
-}
-
-static void
-ConvertIndex(nsTArray<Index::Indice>& aDest,
-             const stagefright::Vector<stagefright::MediaSource::Indice>& aIndex)
-{
-  for (size_t i = 0; i < aIndex.size(); i++) {
-    Index::Indice indice;
-    const stagefright::MediaSource::Indice& s_indice = aIndex[i];
-    indice.start_offset = s_indice.start_offset;
-    indice.end_offset = s_indice.end_offset;
-    indice.start_composition = s_indice.start_composition;
-    indice.end_composition = s_indice.end_composition;
-    indice.sync = s_indice.sync;
-    aDest.AppendElement(indice);
-  }
 }
 
 bool
 MP4Demuxer::Init()
 {
   mMonitor->AssertCurrentThreadOwns();
-  sp<MediaExtractor> e = new MPEG4Extractor(new DataSourceAdapter(mSource));
+
+  mMetadata = mozilla::MakeUnique<MP4Metadata>(mSource);
 
   // Read the number of tracks. If we can't find any, make sure to bail now before
   // attempting any new reads to make the retry system work.
-  size_t trackCount = e->countTracks();
-  if (trackCount == 0) {
+  if (!mMetadata->GetNumberTracks(mozilla::TrackInfo::kAudioTrack) &&
+      !mMetadata->GetNumberTracks(mozilla::TrackInfo::kVideoTrack)) {
     return false;
   }
 
-  for (size_t i = 0; i < trackCount; i++) {
-    sp<MetaData> metaData = e->getTrackMetaData(i);
+  auto audioInfo = mMetadata->GetTrackInfo(mozilla::TrackInfo::kAudioTrack, 0);
+  if (audioInfo) {
+    mAudioConfig = mozilla::Move(audioInfo);
+    nsTArray<Index::Indice> indices;
+    if (!mMetadata->ReadTrackIndex(indices, mAudioConfig->mTrackId)) {
+      return false;
+    }
+    nsRefPtr<Index> index =
+      new Index(indices,
+                mSource,
+                mAudioConfig->mTrackId,
+                /* aIsAudio = */ true,
+                mMonitor);
+    mIndexes.AppendElement(index);
+    mAudioIterator = mozilla::MakeUnique<SampleIterator>(index);
+  }
 
-    const char* mimeType;
-    if (metaData == nullptr || !metaData->findCString(kKeyMIMEType, &mimeType)) {
-      continue;
+  auto videoInfo = mMetadata->GetTrackInfo(mozilla::TrackInfo::kVideoTrack, 0);
+  if (videoInfo) {
+    mVideoConfig = mozilla::Move(videoInfo);
+    nsTArray<Index::Indice> indices;
+    if (!mMetadata->ReadTrackIndex(indices, mVideoConfig->mTrackId)) {
+      return false;
     }
 
-    if (!mPrivate->mAudio.get() && !strncmp(mimeType, "audio/", 6)) {
-      sp<MediaSource> track = e->getTrack(i);
-      if (track->start() != OK) {
-        return false;
-      }
-      mPrivate->mAudio = track;
-      mAudioConfig.Update(metaData.get(), mimeType);
-
-      nsTArray<Index::Indice> indices;
-      ConvertIndex(indices, mPrivate->mAudio->exportIndex());
-      nsRefPtr<Index> index =
-        new Index(indices,
-                  mSource,
-                  mAudioConfig.mTrackId,
-                  /* aIsAudio = */ true,
-                  mMonitor);
-      mPrivate->mIndexes.AppendElement(index);
-      mPrivate->mAudioIterator = new SampleIterator(index);
-    } else if (!mPrivate->mVideo.get() && !strncmp(mimeType, "video/", 6)) {
-      sp<MediaSource> track = e->getTrack(i);
-      if (track->start() != OK) {
-        return false;
-      }
-      mPrivate->mVideo = track;
-      mVideoConfig.Update(metaData.get(), mimeType);
-
-      nsTArray<Index::Indice> indices;
-      ConvertIndex(indices, mPrivate->mVideo->exportIndex());
+    nsRefPtr<Index> index =
+      new Index(indices,
+                mSource,
+                mVideoConfig->mTrackId,
+                /* aIsAudio = */ false,
+                mMonitor);
+    mIndexes.AppendElement(index);
+    mVideoIterator = mozilla::MakeUnique<SampleIterator>(index);
+  }
 
-      nsRefPtr<Index> index =
-        new Index(indices,
-                  mSource,
-                  mVideoConfig.mTrackId,
-                  /* aIsAudio = */ false,
-                  mMonitor);
-      mPrivate->mIndexes.AppendElement(index);
-      mPrivate->mVideoIterator = new SampleIterator(index);
-    }
-  }
-  sp<MetaData> metaData = e->getMetaData();
-  UpdateCrypto(metaData.get());
-
-  int64_t movieDuration;
-  if (!mVideoConfig.mDuration && !mAudioConfig.mDuration &&
-      metaData->findInt64(kKeyMovieDuration, &movieDuration)) {
-    // No duration were found in either tracks, use movie extend header box one.
-    mVideoConfig.mDuration = mAudioConfig.mDuration = movieDuration;
-  }
-  mPrivate->mCanSeek = e->flags() & MediaExtractor::CAN_SEEK;
-
-  return mPrivate->mAudio.get() || mPrivate->mVideo.get();
-}
-
-void
-MP4Demuxer::UpdateCrypto(const MetaData* aMetaData)
-{
-  const void* data;
-  size_t size;
-  uint32_t type;
-
-  // There's no point in checking that the type matches anything because it
-  // isn't set consistently in the MPEG4Extractor.
-  if (!aMetaData->findData(kKeyPssh, &type, &data, &size)) {
-    return;
-  }
-  mCrypto.Update(reinterpret_cast<const uint8_t*>(data), size);
+  return mAudioIterator || mVideoIterator;
 }
 
 bool
 MP4Demuxer::HasValidAudio()
 {
   mMonitor->AssertCurrentThreadOwns();
-  return mPrivate->mAudio.get() && mAudioConfig.IsValid();
+  return mAudioIterator && mAudioConfig && mAudioConfig->IsValid();
 }
 
 bool
 MP4Demuxer::HasValidVideo()
 {
   mMonitor->AssertCurrentThreadOwns();
-  return mPrivate->mVideo.get() && mVideoConfig.IsValid();
+  return mVideoIterator && mVideoConfig && mVideoConfig->IsValid();
 }
 
 Microseconds
 MP4Demuxer::Duration()
 {
   mMonitor->AssertCurrentThreadOwns();
-  return std::max(mVideoConfig.mDuration, mAudioConfig.mDuration);
+  int64_t videoDuration = mVideoConfig ? mVideoConfig->mDuration : 0;
+  int64_t audioDuration = mAudioConfig ? mAudioConfig->mDuration : 0;
+  return std::max(videoDuration, audioDuration);
 }
 
 bool
 MP4Demuxer::CanSeek()
 {
   mMonitor->AssertCurrentThreadOwns();
-  return mPrivate->mCanSeek;
+  return mMetadata->CanSeek();
 }
 
 void
 MP4Demuxer::SeekAudio(Microseconds aTime)
 {
   mMonitor->AssertCurrentThreadOwns();
-  if (mPrivate->mAudioIterator) {
-    mPrivate->mAudioIterator->Seek(aTime);
-  }
+  MOZ_ASSERT(mAudioIterator);
+  mAudioIterator->Seek(aTime);
 }
 
 void
 MP4Demuxer::SeekVideo(Microseconds aTime)
 {
   mMonitor->AssertCurrentThreadOwns();
-  if (mPrivate->mVideoIterator) {
-    mPrivate->mVideoIterator->Seek(aTime);
-  }
+  MOZ_ASSERT(mVideoIterator);
+  mVideoIterator->Seek(aTime);
 }
 
 already_AddRefed<mozilla::MediaRawData>
 MP4Demuxer::DemuxAudioSample()
 {
   mMonitor->AssertCurrentThreadOwns();
-  if (!mPrivate->mAudioIterator) {
-    return nullptr;
-  }
-  nsRefPtr<mozilla::MediaRawData> sample(mPrivate->mAudioIterator->GetNext());
+  MOZ_ASSERT(mAudioIterator);
+  nsRefPtr<mozilla::MediaRawData> sample(mAudioIterator->GetNext());
   if (sample) {
     if (sample->mCrypto.mValid) {
       nsAutoPtr<MediaRawDataWriter> writer(sample->CreateWriter());
-      writer->mCrypto.mMode = mAudioConfig.mCrypto.mMode;
-      writer->mCrypto.mIVSize = mAudioConfig.mCrypto.mIVSize;
-      writer->mCrypto.mKeyId.AppendElements(mAudioConfig.mCrypto.mKeyId);
+      writer->mCrypto.mMode = mAudioConfig->mCrypto.mMode;
+      writer->mCrypto.mIVSize = mAudioConfig->mCrypto.mIVSize;
+      writer->mCrypto.mKeyId.AppendElements(mAudioConfig->mCrypto.mKeyId);
     }
   }
   return sample.forget();
 }
 
 already_AddRefed<MediaRawData>
 MP4Demuxer::DemuxVideoSample()
 {
   mMonitor->AssertCurrentThreadOwns();
-  if (!mPrivate->mVideoIterator) {
-    return nullptr;
-  }
-  nsRefPtr<mozilla::MediaRawData> sample(mPrivate->mVideoIterator->GetNext());
+  MOZ_ASSERT(mVideoIterator);
+  nsRefPtr<mozilla::MediaRawData> sample(mVideoIterator->GetNext());
   if (sample) {
-    sample->mExtraData = mVideoConfig.mExtraData;
+    sample->mExtraData = mVideoConfig->GetAsVideoInfo()->mExtraData;
     if (sample->mCrypto.mValid) {
       nsAutoPtr<MediaRawDataWriter> writer(sample->CreateWriter());
-      writer->mCrypto.mMode = mVideoConfig.mCrypto.mMode;
-      writer->mCrypto.mKeyId.AppendElements(mVideoConfig.mCrypto.mKeyId);
+      writer->mCrypto.mMode = mVideoConfig->mCrypto.mMode;
+      writer->mCrypto.mKeyId.AppendElements(mVideoConfig->mCrypto.mKeyId);
     }
     if (sample->mTime >= mNextKeyframeTime) {
-      mNextKeyframeTime = mPrivate->mVideoIterator->GetNextKeyframeTime();
+      mNextKeyframeTime = mVideoIterator->GetNextKeyframeTime();
     }
   }
   return sample.forget();
 }
 
 void
 MP4Demuxer::UpdateIndex(const nsTArray<mozilla::MediaByteRange>& aByteRanges)
 {
   mMonitor->AssertCurrentThreadOwns();
-  for (int i = 0; i < mPrivate->mIndexes.Length(); i++) {
-    mPrivate->mIndexes[i]->UpdateMoofIndex(aByteRanges);
+  for (int i = 0; i < mIndexes.Length(); i++) {
+    mIndexes[i]->UpdateMoofIndex(aByteRanges);
   }
 }
 
 void
 MP4Demuxer::ConvertByteRangesToTime(
   const nsTArray<mozilla::MediaByteRange>& aByteRanges,
   nsTArray<Interval<Microseconds>>* aIntervals)
 {
   mMonitor->AssertCurrentThreadOwns();
-  if (mPrivate->mIndexes.IsEmpty()) {
+  if (mIndexes.IsEmpty()) {
     return;
   }
 
   Microseconds lastComposition = 0;
   nsTArray<Microseconds> endCompositions;
-  for (int i = 0; i < mPrivate->mIndexes.Length(); i++) {
+  for (int i = 0; i < mIndexes.Length(); i++) {
     Microseconds endComposition =
-      mPrivate->mIndexes[i]->GetEndCompositionIfBuffered(aByteRanges);
+      mIndexes[i]->GetEndCompositionIfBuffered(aByteRanges);
     endCompositions.AppendElement(endComposition);
     lastComposition = std::max(lastComposition, endComposition);
   }
 
   if (aByteRanges != mCachedByteRanges) {
     mCachedByteRanges = aByteRanges;
     mCachedTimeRanges.Clear();
-    for (int i = 0; i < mPrivate->mIndexes.Length(); i++) {
+    for (int i = 0; i < mIndexes.Length(); i++) {
       nsTArray<Interval<Microseconds>> ranges;
-      mPrivate->mIndexes[i]->ConvertByteRangesToTimeRanges(aByteRanges, &ranges);
+      mIndexes[i]->ConvertByteRangesToTimeRanges(aByteRanges, &ranges);
       if (lastComposition && endCompositions[i]) {
         Interval<Microseconds>::SemiNormalAppend(
           ranges, Interval<Microseconds>(endCompositions[i], lastComposition));
       }
 
       if (i) {
         nsTArray<Interval<Microseconds>> intersection;
         Interval<Microseconds>::Intersection(mCachedTimeRanges, ranges, &intersection);
@@ -332,30 +209,33 @@ MP4Demuxer::ConvertByteRangesToTime(
   }
   aIntervals->AppendElements(mCachedTimeRanges);
 }
 
 int64_t
 MP4Demuxer::GetEvictionOffset(Microseconds aTime)
 {
   mMonitor->AssertCurrentThreadOwns();
-  if (mPrivate->mIndexes.IsEmpty()) {
+  if (mIndexes.IsEmpty()) {
     return 0;
   }
 
   uint64_t offset = std::numeric_limits<uint64_t>::max();
-  for (int i = 0; i < mPrivate->mIndexes.Length(); i++) {
-    offset = std::min(offset, mPrivate->mIndexes[i]->GetEvictionOffset(aTime));
+  for (int i = 0; i < mIndexes.Length(); i++) {
+    offset = std::min(offset, mIndexes[i]->GetEvictionOffset(aTime));
   }
   return offset == std::numeric_limits<uint64_t>::max() ? 0 : offset;
 }
 
 Microseconds
 MP4Demuxer::GetNextKeyframeTime()
 {
   mMonitor->AssertCurrentThreadOwns();
-  if (!mPrivate->mVideoIterator) {
-    return -1;
-  }
   return mNextKeyframeTime;
 }
 
+const CryptoFile&
+MP4Demuxer::Crypto() const
+{
+  return mMetadata->Crypto();
+}
+
 } // namespace mp4_demuxer
--- a/media/libstagefright/moz.build
+++ b/media/libstagefright/moz.build
@@ -56,16 +56,17 @@ EXPORTS.mp4_demuxer += [
     'binding/include/mp4_demuxer/ByteReader.h',
     'binding/include/mp4_demuxer/ByteWriter.h',
     'binding/include/mp4_demuxer/DecoderData.h',
     'binding/include/mp4_demuxer/H264.h',
     'binding/include/mp4_demuxer/Index.h',
     'binding/include/mp4_demuxer/Interval.h',
     'binding/include/mp4_demuxer/MoofParser.h',
     'binding/include/mp4_demuxer/mp4_demuxer.h',
+    'binding/include/mp4_demuxer/MP4Metadata.h',
     'binding/include/mp4_demuxer/MP4TrackDemuxer.h',
     'binding/include/mp4_demuxer/SinfParser.h',
     'binding/include/mp4_demuxer/Stream.h',
 ]
 
 EXPORTS.demuxer += [
     'binding/include/demuxer/TrackDemuxer.h',
 ]
@@ -84,16 +85,17 @@ UNIFIED_SOURCES += [
     'binding/AnnexB.cpp',
     'binding/Box.cpp',
     'binding/BufferStream.cpp',
     'binding/DecoderData.cpp',
     'binding/H264.cpp',
     'binding/Index.cpp',
     'binding/MoofParser.cpp',
     'binding/mp4_demuxer.cpp',
+    'binding/MP4Metadata.cpp',
     'binding/MP4TrackDemuxer.cpp',
     'binding/SinfParser.cpp',
     'frameworks/av/media/libstagefright/DataSource.cpp',
     'frameworks/av/media/libstagefright/ESDS.cpp',
     'frameworks/av/media/libstagefright/foundation/AAtomizer.cpp',
     'frameworks/av/media/libstagefright/foundation/ABitReader.cpp',
     'frameworks/av/media/libstagefright/foundation/ABuffer.cpp',
     'frameworks/av/media/libstagefright/foundation/AString.cpp',