Bug 1370175 - enable rust mp4 parser on other platforms and fallback to stagefright if rust parser fails. r?kinetik draft
authorAlfredo Yang <ayang@mozilla.com>
Wed, 14 Jun 2017 11:29:10 +0800
changeset 593818 e1f61fe0e950e23f8a33c41015aa7b447859f173
parent 593717 b266a8d8fd595b84a7d6218d7b8c6b7af0b5027c
child 633222 21515a7fc40b74b173b763b37f8c471912fccd2c
push id63820
push userayang@mozilla.com
push dateWed, 14 Jun 2017 06:15:39 +0000
reviewerskinetik
bugs1370175
milestone56.0a1
Bug 1370175 - enable rust mp4 parser on other platforms and fallback to stagefright if rust parser fails. r?kinetik MozReview-Commit-ID: 37cJxlPF8E2
dom/media/MediaPrefs.h
media/libstagefright/binding/MP4Metadata.cpp
media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h
--- a/dom/media/MediaPrefs.h
+++ b/dom/media/MediaPrefs.h
@@ -181,25 +181,18 @@ private:
   DECL_MEDIA_PREF("media.ogg.enabled",                        OggEnabled, bool, true);
   // Flac
   DECL_MEDIA_PREF("media.ogg.flac.enabled",                   FlacInOgg, bool, false);
   DECL_MEDIA_PREF("media.flac.enabled",                       FlacEnabled, bool, true);
 
   // Hls
   DECL_MEDIA_PREF("media.hls.enabled",                        HLSEnabled, bool, false);
 
-#if !defined(RELEASE_OR_BETA)
   DECL_MEDIA_PREF("media.rust.test_mode",                     RustTestMode, bool, false);
-#endif
-
-#if defined(MOZ_WIDGET_GTK)
   DECL_MEDIA_PREF("media.rust.mp4parser",                     EnableRustMP4Parser, bool, true);
-#else
-  DECL_MEDIA_PREF("media.rust.mp4parser",                     EnableRustMP4Parser, bool, false);
-#endif
 
   DECL_MEDIA_PREF("media.mp4.enabled",                        MP4Enabled, bool, false);
 
   // Error/warning handling, Decoder Doctor
   DECL_MEDIA_PREF("media.playback.warnings-as-errors",        MediaWarningsAsErrors, bool, false);
   DECL_MEDIA_PREF("media.playback.warnings-as-errors.stagefright-vs-rust",
                                                               MediaWarningsAsErrorsStageFrightVsRust, bool, false);
 
--- a/media/libstagefright/binding/MP4Metadata.cpp
+++ b/media/libstagefright/binding/MP4Metadata.cpp
@@ -122,31 +122,33 @@ public:
 private:
   Stream* mSource;
   CheckedInt<size_t> mOffset;
 };
 
 class MP4MetadataRust
 {
 public:
-  explicit MP4MetadataRust(Stream* aSource);
+  explicit MP4MetadataRust(Stream* aSource, bool& aParseFailure);
   ~MP4MetadataRust();
 
   static MP4Metadata::ResultAndByteBuffer Metadata(Stream* aSource);
 
   MP4Metadata::ResultAndTrackCount
   GetNumberTracks(mozilla::TrackInfo::TrackType aType) const;
   MP4Metadata::ResultAndTrackInfo GetTrackInfo(
     mozilla::TrackInfo::TrackType aType, size_t aTrackNumber) const;
   bool CanSeek() const;
 
   MP4Metadata::ResultAndCryptoFile Crypto() const;
 
   MediaResult ReadTrackIndice(mp4parse_byte_data* aIndices, mozilla::TrackID aTrackID);
 
+  bool ParseSuccess();
+
 private:
   void UpdateCrypto();
   Maybe<uint32_t> TrackTypeToGlobalTrackIndex(mozilla::TrackInfo::TrackType aType, size_t aTrackNumber) const;
 
   CryptoFile mCrypto;
   RefPtr<Stream> mSource;
   RustStreamAdaptor mRustSource;
   mozilla::UniquePtr<mp4parse_parser, FreeMP4Parser> mRustParser;
@@ -230,23 +232,20 @@ IndiceWrapperRust::GetIndice(size_t aInd
   aIndice.end_composition = indice->end_composition;
   aIndice.start_decode = indice->start_decode;
   aIndice.sync = indice->sync;
   return true;
 }
 
 MP4Metadata::MP4Metadata(Stream* aSource)
  : mStagefright(MakeUnique<MP4MetadataStagefright>(aSource))
- , mRust(MakeUnique<MP4MetadataRust>(aSource))
- , mPreferRust(MediaPrefs::EnableRustMP4Parser())
+ , mRust(MakeUnique<MP4MetadataRust>(aSource, mDisableRust))
  , mReportedAudioTrackTelemetry(false)
  , mReportedVideoTrackTelemetry(false)
-#ifndef RELEASE_OR_BETA
  , mRustTestMode(MediaPrefs::RustTestMode())
-#endif
 {
 }
 
 MP4Metadata::~MP4Metadata()
 {
 }
 
 /*static*/ MP4Metadata::ResultAndByteBuffer
@@ -269,130 +268,82 @@ TrackTypeToString(mozilla::TrackInfo::Tr
 }
 
 MP4Metadata::ResultAndTrackCount
 MP4Metadata::GetNumberTracks(mozilla::TrackInfo::TrackType aType) const
 {
   MP4Metadata::ResultAndTrackCount numTracks =
     mStagefright->GetNumberTracks(aType);
 
-  if (!mRust) {
-    return numTracks;
-  }
-
   MP4Metadata::ResultAndTrackCount numTracksRust =
     mRust->GetNumberTracks(aType);
   MOZ_LOG(sLog, LogLevel::Info, ("%s tracks found: stagefright=(%s)%u rust=(%s)%u",
                                  TrackTypeToString(aType),
                                  numTracks.Result().Description().get(),
                                  numTracks.Ref(),
                                  numTracksRust.Result().Description().get(),
                                  numTracksRust.Ref()));
 
-  // Consider '0' and 'error' the same for comparison purposes.
-  // (Mostly because Stagefright never returns errors, but Rust may.)
-  bool numTracksMatch =
-    (numTracks.Ref() != NumberTracksError() ? numTracks.Ref() : 0) ==
-    (numTracksRust.Ref() != NumberTracksError() ? numTracksRust.Ref() : 0);
 
-  if (aType == mozilla::TrackInfo::kAudioTrack && !mReportedAudioTrackTelemetry) {
-    Telemetry::Accumulate(Telemetry::MEDIA_RUST_MP4PARSE_TRACK_MATCH_AUDIO,
-                          numTracksMatch);
-    mReportedAudioTrackTelemetry = true;
-  } else if (aType == mozilla::TrackInfo::kVideoTrack && !mReportedVideoTrackTelemetry) {
-    Telemetry::Accumulate(Telemetry::MEDIA_RUST_MP4PARSE_TRACK_MATCH_VIDEO,
-                            numTracksMatch);
-    mReportedVideoTrackTelemetry = true;
-  }
+  if (mRustTestMode) {
+    // Consider '0' and 'error' the same for comparison purposes.
+    // (Mostly because Stagefright never returns errors, but Rust may.)
+    bool numTracksMatch =
+      (numTracks.Ref() != NumberTracksError() ? numTracks.Ref() : 0) ==
+      (numTracksRust.Ref() != NumberTracksError() ? numTracksRust.Ref() : 0);
 
-  if (!numTracksMatch &&
-      MediaPrefs::MediaWarningsAsErrorsStageFrightVsRust()) {
-    return {MediaResult(NS_ERROR_DOM_MEDIA_METADATA_ERR,
-                        RESULT_DETAIL("Different numbers of tracks: "
-                                      "Stagefright=%u (%s) Rust=%u (%s)",
-                                      numTracks.Ref(),
-                                      numTracks.Result().Description().get(),
-                                      numTracksRust.Ref(),
-                                      numTracksRust.Result().Description().get())),
-            NumberTracksError()};
-  }
-
-  // If we prefer Rust, just return it.
-  if (mPreferRust || ShouldPreferRust()) {
-    MOZ_LOG(sLog, LogLevel::Info, ("Preferring rust demuxer"));
-    mPreferRust = true;
-    return numTracksRust;
-  }
+    if (aType == mozilla::TrackInfo::kAudioTrack && !mReportedAudioTrackTelemetry) {
+      Telemetry::Accumulate(Telemetry::MEDIA_RUST_MP4PARSE_TRACK_MATCH_AUDIO,
+                            numTracksMatch);
+      mReportedAudioTrackTelemetry = true;
+    } else if (aType == mozilla::TrackInfo::kVideoTrack && !mReportedVideoTrackTelemetry) {
+      Telemetry::Accumulate(Telemetry::MEDIA_RUST_MP4PARSE_TRACK_MATCH_VIDEO,
+                              numTracksMatch);
+      mReportedVideoTrackTelemetry = true;
+    }
 
-  // If numbers are different, return the stagefright number with a warning.
-  if (!numTracksMatch) {
-    return {MediaResult(NS_ERROR_DOM_MEDIA_METADATA_ERR,
-                        RESULT_DETAIL("Different numbers of tracks: "
-                                      "Stagefright=%u (%s) Rust=%u (%s)",
-                                      numTracks.Ref(),
-                                      numTracks.Result().Description().get(),
-                                      numTracksRust.Ref(),
-                                      numTracksRust.Result().Description().get())),
-            numTracks.Ref()};
-  }
-
-  // Numbers are effectively the same.
+    if (!numTracksMatch &&
+        MediaPrefs::MediaWarningsAsErrorsStageFrightVsRust()) {
+      return {MediaResult(NS_ERROR_DOM_MEDIA_METADATA_ERR,
+                          RESULT_DETAIL("Different numbers of tracks: "
+                                        "Stagefright=%u (%s) Rust=%u (%s)",
+                                        numTracks.Ref(),
+                                        numTracks.Result().Description().get(),
+                                        numTracksRust.Ref(),
+                                        numTracksRust.Result().Description().get())),
+              NumberTracksError()};
+    }
 
-  // Error(s) -> Combine both messages to get more details out.
-  if (numTracks.Ref() == NumberTracksError() ||
-      numTracksRust.Ref() == NumberTracksError()) {
-    return {MediaResult(NS_ERROR_DOM_MEDIA_METADATA_ERR,
-                        RESULT_DETAIL("Errors: "
-                                      "Stagefright=(%s) Rust=(%s)",
-                                      numTracks.Result().Description().get(),
-                                      numTracksRust.Result().Description().get())),
-            numTracks.Ref()};
-  }
-
-  // Same non-error numbers, just return any.
-  // (Choosing Rust here, in case it carries a warning, we'd want to know that.)
-  return numTracksRust;
-}
+    // If numbers are different, return the stagefright number with a warning.
+    if (!numTracksMatch) {
+      return {MediaResult(NS_ERROR_DOM_MEDIA_METADATA_ERR,
+                          RESULT_DETAIL("Different numbers of tracks: "
+                                        "Stagefright=%u (%s) Rust=%u (%s)",
+                                        numTracks.Ref(),
+                                        numTracks.Result().Description().get(),
+                                        numTracksRust.Ref(),
+                                        numTracksRust.Result().Description().get())),
+              numTracks.Ref()};
+    }
 
-bool MP4Metadata::ShouldPreferRust() const {
-  if (!mRust) {
-    return false;
-  }
-  // See if there's an Opus track.
-  MP4Metadata::ResultAndTrackCount numTracks =
-    mRust->GetNumberTracks(TrackInfo::kAudioTrack);
-  if (numTracks.Ref() != NumberTracksError()) {
-    for (auto i = 0; i < numTracks.Ref(); i++) {
-      MP4Metadata::ResultAndTrackInfo info =
-        mRust->GetTrackInfo(TrackInfo::kAudioTrack, i);
-      if (!info.Ref()) {
-        return false;
-      }
-      if (info.Ref()->mMimeType.EqualsASCII("audio/opus") ||
-          info.Ref()->mMimeType.EqualsASCII("audio/flac")) {
-        return true;
-      }
+    // Numbers are effectively the same.
+
+    // Error(s) -> Combine both messages to get more details out.
+    if (numTracks.Ref() == NumberTracksError() ||
+        numTracksRust.Ref() == NumberTracksError()) {
+      return {MediaResult(NS_ERROR_DOM_MEDIA_METADATA_ERR,
+                          RESULT_DETAIL("Errors: "
+                                        "Stagefright=(%s) Rust=(%s)",
+                                        numTracks.Result().Description().get(),
+                                        numTracksRust.Result().Description().get())),
+              numTracks.Ref()};
     }
   }
 
-  numTracks = mRust->GetNumberTracks(TrackInfo::kVideoTrack);
-  if (numTracks.Ref() != NumberTracksError()) {
-    for (auto i = 0; i < numTracks.Ref(); i++) {
-      MP4Metadata::ResultAndTrackInfo info =
-        mRust->GetTrackInfo(TrackInfo::kVideoTrack, i);
-      if (!info.Ref()) {
-        return false;
-      }
-      if (info.Ref()->mMimeType.EqualsASCII("video/vp9")) {
-        return true;
-      }
-    }
-  }
-  // Otherwise, fall back.
-  return false;
+  return mDisableRust ? numTracks : numTracksRust;
 }
 
 static const char*
 GetDifferentField(const mozilla::TrackInfo& info,
                   const mozilla::TrackInfo& infoRust)
 {
   if (infoRust.mId != info.mId) { return "Id"; }
   if (infoRust.mKind != info.mKind) { return "Kind"; }
@@ -438,24 +389,19 @@ GetDifferentField(const mozilla::TrackIn
 
 MP4Metadata::ResultAndTrackInfo
 MP4Metadata::GetTrackInfo(mozilla::TrackInfo::TrackType aType,
                           size_t aTrackNumber) const
 {
   MP4Metadata::ResultAndTrackInfo info =
     mStagefright->GetTrackInfo(aType, aTrackNumber);
 
-  if (!mRust) {
-    return info;
-  }
-
   MP4Metadata::ResultAndTrackInfo infoRust =
     mRust->GetTrackInfo(aType, aTrackNumber);
 
-#ifndef RELEASE_OR_BETA
   if (mRustTestMode && info.Ref() && infoRust.Ref()) {
     MOZ_DIAGNOSTIC_ASSERT(infoRust.Ref()->mId == info.Ref()->mId);
     MOZ_DIAGNOSTIC_ASSERT(infoRust.Ref()->mKind == info.Ref()->mKind);
     MOZ_DIAGNOSTIC_ASSERT(infoRust.Ref()->mLabel == info.Ref()->mLabel);
     MOZ_DIAGNOSTIC_ASSERT(infoRust.Ref()->mLanguage == info.Ref()->mLanguage);
     MOZ_DIAGNOSTIC_ASSERT(infoRust.Ref()->mEnabled == info.Ref()->mEnabled);
     MOZ_DIAGNOSTIC_ASSERT(infoRust.Ref()->mTrackId == info.Ref()->mTrackId);
     MOZ_DIAGNOSTIC_ASSERT(infoRust.Ref()->mMimeType == info.Ref()->mMimeType);
@@ -488,121 +434,98 @@ MP4Metadata::GetTrackInfo(mozilla::Track
       // mCodecSpecificConfig is for video/mp4-es, not video/avc. Since video/mp4-es
       // is supported on b2g only, it could be removed from TrackInfo.
       MOZ_DIAGNOSTIC_ASSERT(*videoRust->mCodecSpecificConfig == *video->mCodecSpecificConfig);
       break;
     }
     default:
       break;
     }
-  }
-#endif
 
-  if (info.Ref() && infoRust.Ref()) {
     const char* diff = GetDifferentField(*info.Ref(), *infoRust.Ref());
     if (diff) {
       return {MediaResult(NS_ERROR_DOM_MEDIA_METADATA_ERR,
                           RESULT_DETAIL("Different field '%s' between "
                                         "Stagefright (%s) and Rust (%s)",
                                         diff,
                                         info.Result().Description().get(),
                                         infoRust.Result().Description().get())),
               MediaPrefs::MediaWarningsAsErrorsStageFrightVsRust()
               ? mozilla::UniquePtr<mozilla::TrackInfo>(nullptr)
-              : mPreferRust ? Move(infoRust.Ref()) : Move(info.Ref())};
+              : mDisableRust ? Move(info.Ref()) : Move(infoRust.Ref())};
     }
   }
 
-  if (mPreferRust) {
-    return infoRust;
-  }
-
-  return info;
+  return mDisableRust ? Move(info) : Move(infoRust);
 }
 
 bool
 MP4Metadata::CanSeek() const
 {
   return mStagefright->CanSeek();
 }
 
 MP4Metadata::ResultAndCryptoFile
 MP4Metadata::Crypto() const
 {
   MP4Metadata::ResultAndCryptoFile crypto = mStagefright->Crypto();
   MP4Metadata::ResultAndCryptoFile rustCrypto = mRust->Crypto();
 
-#ifndef RELEASE_OR_BETA
   if (mRustTestMode) {
     MOZ_DIAGNOSTIC_ASSERT(rustCrypto.Ref()->pssh == crypto.Ref()->pssh);
-  }
-#endif
 
-  if (rustCrypto.Ref()->pssh != crypto.Ref()->pssh) {
-    return {MediaResult(
-             NS_ERROR_DOM_MEDIA_METADATA_ERR,
-             RESULT_DETAIL("Mismatch between Stagefright (%s) and Rust (%s) crypto file",
-                           crypto.Result().Description().get(),
-                           rustCrypto.Result().Description().get())),
-            mPreferRust ? rustCrypto.Ref() : crypto.Ref()};
+    if (rustCrypto.Ref()->pssh != crypto.Ref()->pssh) {
+      return {MediaResult(
+               NS_ERROR_DOM_MEDIA_METADATA_ERR,
+               RESULT_DETAIL("Mismatch between Stagefright (%s) and Rust (%s) crypto file",
+                             crypto.Result().Description().get(),
+                             rustCrypto.Result().Description().get())),
+              mDisableRust ? crypto.Ref() : rustCrypto.Ref()};
+    }
   }
 
-  if (mPreferRust) {
-    return rustCrypto;
-  }
-
-  return crypto;
+  return mDisableRust ? crypto : rustCrypto;
 }
 
 MP4Metadata::ResultAndIndice
 MP4Metadata::GetTrackIndice(mozilla::TrackID aTrackID)
 {
   FallibleTArray<Index::Indice> indiceSF;
-  if (!mPreferRust
-#ifndef RELEASE_OR_BETA
-      || mRustTestMode
-#endif
-     ) {
+  if (mDisableRust || mRustTestMode) {
     MediaResult rv = mStagefright->ReadTrackIndex(indiceSF, aTrackID);
     if (NS_FAILED(rv)) {
       return {Move(rv), nullptr};
     }
   }
 
   mp4parse_byte_data indiceRust = {};
-  if (mPreferRust
-#ifndef RELEASE_OR_BETA
-      || mRustTestMode
-#endif
-     ) {
+  if (!mDisableRust || mRustTestMode) {
     MediaResult rvRust = mRust->ReadTrackIndice(&indiceRust, aTrackID);
     if (NS_FAILED(rvRust)) {
       return {Move(rvRust), nullptr};
     }
   }
 
-#ifndef RELEASE_OR_BETA
   if (mRustTestMode) {
     MOZ_DIAGNOSTIC_ASSERT(indiceRust.length == indiceSF.Length());
     for (uint32_t i = 0; i < indiceRust.length; i++) {
       MOZ_DIAGNOSTIC_ASSERT(indiceRust.indices[i].start_offset == indiceSF[i].start_offset);
       MOZ_DIAGNOSTIC_ASSERT(indiceRust.indices[i].end_offset == indiceSF[i].end_offset);
       MOZ_DIAGNOSTIC_ASSERT(llabs(indiceRust.indices[i].start_composition - int64_t(indiceSF[i].start_composition)) <= 1);
       MOZ_DIAGNOSTIC_ASSERT(llabs(indiceRust.indices[i].end_composition - int64_t(indiceSF[i].end_composition)) <= 1);
       MOZ_DIAGNOSTIC_ASSERT(llabs(indiceRust.indices[i].start_decode - int64_t(indiceSF[i].start_decode)) <= 1);
       MOZ_DIAGNOSTIC_ASSERT(indiceRust.indices[i].sync == indiceSF[i].sync);
     }
   }
-#endif
 
   UniquePtr<IndiceWrapper> indice;
-  if (mPreferRust) {
+  if (mDisableRust) {
+    indice = mozilla::MakeUnique<IndiceWrapperStagefright>(indiceSF);
+  } else {
     indice = mozilla::MakeUnique<IndiceWrapperRust>(indiceRust);
-  } else {
-    indice = mozilla::MakeUnique<IndiceWrapperStagefright>(indiceSF);
   }
 
   return {NS_OK, Move(indice)};
 }
 
 static inline MediaResult
 ConvertIndex(FallibleTArray<Index::Indice>& aDest,
              const nsTArray<stagefright::MediaSource::Indice>& aIndex,
@@ -882,33 +805,41 @@ read_source(uint8_t* buffer, uintptr_t s
   bool rv = source->Read(buffer, size, &bytes_read);
   if (!rv) {
     MOZ_LOG(sLog, LogLevel::Warning, ("Error reading source data"));
     return -1;
   }
   return bytes_read;
 }
 
-MP4MetadataRust::MP4MetadataRust(Stream* aSource)
+MP4MetadataRust::MP4MetadataRust(Stream* aSource, bool& aParseFailure)
   : mSource(aSource)
   , mRustSource(aSource)
 {
+  if (!MediaPrefs::EnableRustMP4Parser()) {
+    aParseFailure = true;
+    return;
+  }
+  aParseFailure = false;
+
   mp4parse_io io = { read_source, &mRustSource };
   mRustParser.reset(mp4parse_new(&io));
   MOZ_ASSERT(mRustParser);
 
   if (MOZ_LOG_TEST(sLog, LogLevel::Debug)) {
     mp4parse_log(true);
   }
 
   mp4parse_status rv = mp4parse_read(mRustParser.get());
   MOZ_LOG(sLog, LogLevel::Debug, ("rust parser returned %d\n", rv));
   Telemetry::Accumulate(Telemetry::MEDIA_RUST_MP4PARSE_SUCCESS,
                         rv == mp4parse_status_OK);
   if (rv != mp4parse_status_OK) {
+    MOZ_LOG(sLog, LogLevel::Info, ("Rust mp4 parser fails to parse this stream."));
+    aParseFailure = true;
     MOZ_ASSERT(rv > 0);
     Telemetry::Accumulate(Telemetry::MEDIA_RUST_MP4PARSE_ERROR_CODE, rv);
   }
 
   UpdateCrypto();
 }
 
 MP4MetadataRust::~MP4MetadataRust()
--- a/media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h
+++ b/media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h
@@ -78,17 +78,17 @@ public:
   ResultAndCryptoFile Crypto() const;
 
   using ResultAndIndice = ResultAndType<mozilla::UniquePtr<IndiceWrapper>>;
   ResultAndIndice GetTrackIndice(mozilla::TrackID aTrackID);
 
 private:
   UniquePtr<MP4MetadataStagefright> mStagefright;
   UniquePtr<MP4MetadataRust> mRust;
-  mutable bool mPreferRust;
+  mutable bool mDisableRust;
   mutable bool mReportedAudioTrackTelemetry;
   mutable bool mReportedVideoTrackTelemetry;
 #ifndef RELEASE_OR_BETA
   mutable bool mRustTestMode;
 #endif
   bool ShouldPreferRust() const;
 };