LCOV - code coverage report
Current view: top level - media/libstagefright/binding - MP4Metadata.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 469 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 57 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* This Source Code Form is subject to the terms of the Mozilla Public
       2             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       3             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       4             : 
       5             : #include "include/MPEG4Extractor.h"
       6             : #include "media/stagefright/DataSource.h"
       7             : #include "media/stagefright/MediaDefs.h"
       8             : #include "media/stagefright/MediaSource.h"
       9             : #include "media/stagefright/MetaData.h"
      10             : #include "mozilla/Assertions.h"
      11             : #include "mozilla/CheckedInt.h"
      12             : #include "mozilla/EndianUtils.h"
      13             : #include "mozilla/Logging.h"
      14             : #include "mozilla/RefPtr.h"
      15             : #include "mozilla/SizePrintfMacros.h"
      16             : #include "mozilla/Telemetry.h"
      17             : #include "mozilla/UniquePtr.h"
      18             : #include "VideoUtils.h"
      19             : #include "mp4_demuxer/MoofParser.h"
      20             : #include "mp4_demuxer/MP4Metadata.h"
      21             : #include "mp4_demuxer/Stream.h"
      22             : #include "MediaPrefs.h"
      23             : #include "mp4parse.h"
      24             : 
      25             : #include <limits>
      26             : #include <stdint.h>
      27             : #include <vector>
      28             : 
      29             : 
      30           0 : struct FreeMP4Parser { void operator()(mp4parse_parser* aPtr) { mp4parse_free(aPtr); } };
      31             : 
      32             : using namespace stagefright;
      33             : using mozilla::media::TimeUnit;
      34             : 
      35             : namespace mp4_demuxer
      36             : {
      37             : 
      38             : static LazyLogModule sLog("MP4Metadata");
      39             : 
      40             : class DataSourceAdapter : public DataSource
      41             : {
      42             : public:
      43           0 :   explicit DataSourceAdapter(Stream* aSource) : mSource(aSource) {}
      44             : 
      45           0 :   ~DataSourceAdapter() {}
      46             : 
      47           0 :   virtual status_t initCheck() const { return NO_ERROR; }
      48             : 
      49           0 :   virtual ssize_t readAt(off64_t offset, void* data, size_t size)
      50             :   {
      51           0 :     MOZ_ASSERT(((ssize_t)size) >= 0);
      52             :     size_t bytesRead;
      53           0 :     if (!mSource->ReadAt(offset, data, size, &bytesRead))
      54           0 :       return ERROR_IO;
      55             : 
      56           0 :     if (bytesRead == 0)
      57           0 :       return ERROR_END_OF_STREAM;
      58             : 
      59           0 :     MOZ_ASSERT(((ssize_t)bytesRead) > 0);
      60           0 :     return bytesRead;
      61             :   }
      62             : 
      63           0 :   virtual status_t getSize(off64_t* size)
      64             :   {
      65           0 :     if (!mSource->Length(size))
      66           0 :       return ERROR_UNSUPPORTED;
      67           0 :     return NO_ERROR;
      68             :   }
      69             : 
      70           0 :   virtual uint32_t flags() { return kWantsPrefetching | kIsHTTPBasedSource; }
      71             : 
      72           0 :   virtual status_t reconnectAtOffset(off64_t offset) { return NO_ERROR; }
      73             : 
      74             : private:
      75             :   RefPtr<Stream> mSource;
      76             : };
      77             : 
      78             : class MP4MetadataStagefright
      79             : {
      80             : public:
      81             :   explicit MP4MetadataStagefright(Stream* aSource);
      82             :   ~MP4MetadataStagefright();
      83             : 
      84             :   static MP4Metadata::ResultAndByteBuffer Metadata(Stream* aSource);
      85             : 
      86             :   MP4Metadata::ResultAndTrackCount
      87             :   GetNumberTracks(mozilla::TrackInfo::TrackType aType) const;
      88             :   MP4Metadata::ResultAndTrackInfo GetTrackInfo(
      89             :     mozilla::TrackInfo::TrackType aType, size_t aTrackNumber) const;
      90             :   bool CanSeek() const;
      91             : 
      92             :   MP4Metadata::ResultAndCryptoFile Crypto() const;
      93             : 
      94             :   MediaResult ReadTrackIndex(FallibleTArray<Index::Indice>& aDest, mozilla::TrackID aTrackID);
      95             : 
      96             : private:
      97             :   int32_t GetTrackNumber(mozilla::TrackID aTrackID);
      98             :   void UpdateCrypto(const stagefright::MetaData* aMetaData);
      99             :   mozilla::UniquePtr<mozilla::TrackInfo> CheckTrack(const char* aMimeType,
     100             :                                                     stagefright::MetaData* aMetaData,
     101             :                                                     int32_t aIndex) const;
     102             :   CryptoFile mCrypto;
     103             :   RefPtr<Stream> mSource;
     104             :   sp<MediaExtractor> mMetadataExtractor;
     105             :   bool mCanSeek;
     106             : };
     107             : 
     108             : // Wrap an mp4_demuxer::Stream to remember the read offset.
     109             : 
     110             : class RustStreamAdaptor {
     111             : public:
     112           0 :   explicit RustStreamAdaptor(Stream* aSource)
     113           0 :     : mSource(aSource)
     114           0 :     , mOffset(0)
     115             :   {
     116           0 :   }
     117             : 
     118           0 :   ~RustStreamAdaptor() {}
     119             : 
     120             :   bool Read(uint8_t* buffer, uintptr_t size, size_t* bytes_read);
     121             : 
     122             : private:
     123             :   Stream* mSource;
     124             :   CheckedInt<size_t> mOffset;
     125             : };
     126             : 
     127             : class MP4MetadataRust
     128             : {
     129             : public:
     130             :   explicit MP4MetadataRust(Stream* aSource);
     131             :   ~MP4MetadataRust();
     132             : 
     133             :   static MP4Metadata::ResultAndByteBuffer Metadata(Stream* aSource);
     134             : 
     135             :   MP4Metadata::ResultAndTrackCount
     136             :   GetNumberTracks(mozilla::TrackInfo::TrackType aType) const;
     137             :   MP4Metadata::ResultAndTrackInfo GetTrackInfo(
     138             :     mozilla::TrackInfo::TrackType aType, size_t aTrackNumber) const;
     139             :   bool CanSeek() const;
     140             : 
     141             :   MP4Metadata::ResultAndCryptoFile Crypto() const;
     142             : 
     143             :   MediaResult ReadTrackIndice(mp4parse_byte_data* aIndices, mozilla::TrackID aTrackID);
     144             : 
     145             :   bool Init();
     146             : 
     147             : private:
     148             :   void UpdateCrypto();
     149             :   Maybe<uint32_t> TrackTypeToGlobalTrackIndex(mozilla::TrackInfo::TrackType aType, size_t aTrackNumber) const;
     150             : 
     151             :   CryptoFile mCrypto;
     152             :   RefPtr<Stream> mSource;
     153             :   RustStreamAdaptor mRustSource;
     154             :   mozilla::UniquePtr<mp4parse_parser, FreeMP4Parser> mRustParser;
     155             : };
     156             : 
     157           0 : class IndiceWrapperStagefright : public IndiceWrapper {
     158             : public:
     159             :   size_t Length() const override;
     160             : 
     161             :   bool GetIndice(size_t aIndex, Index::Indice& aIndice) const override;
     162             : 
     163             :   explicit IndiceWrapperStagefright(FallibleTArray<Index::Indice>& aIndice);
     164             : 
     165             : protected:
     166             :   FallibleTArray<Index::Indice> mIndice;
     167             : };
     168             : 
     169           0 : IndiceWrapperStagefright::IndiceWrapperStagefright(FallibleTArray<Index::Indice>& aIndice)
     170             : {
     171           0 :   mIndice.SwapElements(aIndice);
     172           0 : }
     173             : 
     174             : size_t
     175           0 : IndiceWrapperStagefright::Length() const
     176             : {
     177           0 :   return mIndice.Length();
     178             : }
     179             : 
     180             : bool
     181           0 : IndiceWrapperStagefright::GetIndice(size_t aIndex, Index::Indice& aIndice) const
     182             : {
     183           0 :   if (aIndex >= mIndice.Length()) {
     184           0 :     MOZ_LOG(sLog, LogLevel::Error, ("Index overflow in indice"));
     185           0 :     return false;
     186             :   }
     187             : 
     188           0 :   aIndice = mIndice[aIndex];
     189           0 :   return true;
     190             : }
     191             : 
     192             : // the owner of mIndice is rust mp4 paser, so lifetime of this class
     193             : // SHOULD NOT longer than rust parser.
     194           0 : class IndiceWrapperRust : public IndiceWrapper
     195             : {
     196             : public:
     197             :   size_t Length() const override;
     198             : 
     199             :   bool GetIndice(size_t aIndex, Index::Indice& aIndice) const override;
     200             : 
     201             :   explicit IndiceWrapperRust(mp4parse_byte_data& aRustIndice);
     202             : 
     203             : protected:
     204             :   UniquePtr<mp4parse_byte_data> mIndice;
     205             : };
     206             : 
     207           0 : IndiceWrapperRust::IndiceWrapperRust(mp4parse_byte_data& aRustIndice)
     208           0 :   : mIndice(mozilla::MakeUnique<mp4parse_byte_data>())
     209             : {
     210           0 :   mIndice->length = aRustIndice.length;
     211           0 :   mIndice->indices = aRustIndice.indices;
     212           0 : }
     213             : 
     214             : size_t
     215           0 : IndiceWrapperRust::Length() const
     216             : {
     217           0 :   return mIndice->length;
     218             : }
     219             : 
     220             : bool
     221           0 : IndiceWrapperRust::GetIndice(size_t aIndex, Index::Indice& aIndice) const
     222             : {
     223           0 :   if (aIndex >= mIndice->length) {
     224           0 :     MOZ_LOG(sLog, LogLevel::Error, ("Index overflow in indice"));
     225           0 :    return false;
     226             :   }
     227             : 
     228           0 :   const mp4parse_indice* indice = &mIndice->indices[aIndex];
     229           0 :   aIndice.start_offset = indice->start_offset;
     230           0 :   aIndice.end_offset = indice->end_offset;
     231           0 :   aIndice.start_composition = indice->start_composition;
     232           0 :   aIndice.end_composition = indice->end_composition;
     233           0 :   aIndice.start_decode = indice->start_decode;
     234           0 :   aIndice.sync = indice->sync;
     235           0 :   return true;
     236             : }
     237             : 
     238           0 : MP4Metadata::MP4Metadata(Stream* aSource)
     239             :  : mStagefright(MakeUnique<MP4MetadataStagefright>(aSource))
     240             :  , mRust(MakeUnique<MP4MetadataRust>(aSource))
     241             :  , mReportedAudioTrackTelemetry(false)
     242           0 :  , mReportedVideoTrackTelemetry(false)
     243             : {
     244           0 :   mDisableRust = !MediaPrefs::EnableRustMP4Parser() && !MediaPrefs::RustTestMode();
     245           0 :   if (mDisableRust) {
     246           0 :     return;
     247             :   }
     248             :   // Fallback to stagefright if it fails.
     249           0 :   mDisableRust = !mRust->Init();
     250             : }
     251             : 
     252           0 : MP4Metadata::~MP4Metadata()
     253             : {
     254           0 : }
     255             : 
     256             : /*static*/ MP4Metadata::ResultAndByteBuffer
     257           0 : MP4Metadata::Metadata(Stream* aSource)
     258             : {
     259           0 :   return MP4MetadataStagefright::Metadata(aSource);
     260             : }
     261             : 
     262             : static const char *
     263           0 : TrackTypeToString(mozilla::TrackInfo::TrackType aType)
     264             : {
     265           0 :   switch (aType) {
     266             :   case mozilla::TrackInfo::kAudioTrack:
     267           0 :     return "audio";
     268             :   case mozilla::TrackInfo::kVideoTrack:
     269           0 :     return "video";
     270             :   default:
     271           0 :     return "unknown";
     272             :   }
     273             : }
     274             : 
     275             : MP4Metadata::ResultAndTrackCount
     276           0 : MP4Metadata::GetNumberTracks(mozilla::TrackInfo::TrackType aType) const
     277             : {
     278             :   MP4Metadata::ResultAndTrackCount numTracks =
     279           0 :     mStagefright->GetNumberTracks(aType);
     280             : 
     281             :   MP4Metadata::ResultAndTrackCount numTracksRust =
     282           0 :     mRust->GetNumberTracks(aType);
     283           0 :   MOZ_LOG(sLog, LogLevel::Info, ("%s tracks found: stagefright=(%s)%u rust=(%s)%u",
     284             :                                  TrackTypeToString(aType),
     285             :                                  numTracks.Result().Description().get(),
     286             :                                  numTracks.Ref(),
     287             :                                  numTracksRust.Result().Description().get(),
     288             :                                  numTracksRust.Ref()));
     289             : 
     290             : 
     291             :   // Consider '0' and 'error' the same for comparison purposes.
     292             :   // (Mostly because Stagefright never returns errors, but Rust may.)
     293             :   bool numTracksMatch =
     294           0 :     (numTracks.Ref() != NumberTracksError() ? numTracks.Ref() : 0) ==
     295           0 :     (numTracksRust.Ref() != NumberTracksError() ? numTracksRust.Ref() : 0);
     296             : 
     297           0 :   if (aType == mozilla::TrackInfo::kAudioTrack && !mReportedAudioTrackTelemetry) {
     298           0 :     Telemetry::Accumulate(Telemetry::MEDIA_RUST_MP4PARSE_TRACK_MATCH_AUDIO,
     299           0 :                           numTracksMatch);
     300           0 :     mReportedAudioTrackTelemetry = true;
     301           0 :   } else if (aType == mozilla::TrackInfo::kVideoTrack && !mReportedVideoTrackTelemetry) {
     302           0 :     Telemetry::Accumulate(Telemetry::MEDIA_RUST_MP4PARSE_TRACK_MATCH_VIDEO,
     303           0 :                             numTracksMatch);
     304           0 :     mReportedVideoTrackTelemetry = true;
     305             :   }
     306             : 
     307           0 :   if (!numTracksMatch && MediaPrefs::MediaWarningsAsErrorsStageFrightVsRust()) {
     308           0 :     return {MediaResult(NS_ERROR_DOM_MEDIA_METADATA_ERR,
     309           0 :                         RESULT_DETAIL("Different numbers of tracks: "
     310             :                                       "Stagefright=%u (%s) Rust=%u (%s)",
     311             :                                       numTracks.Ref(),
     312             :                                       numTracks.Result().Description().get(),
     313             :                                       numTracksRust.Ref(),
     314             :                                       numTracksRust.Result().Description().get())),
     315           0 :             NumberTracksError()};
     316             :   }
     317             : 
     318           0 :   return mDisableRust ? numTracks : numTracksRust;
     319             : }
     320             : 
     321             : static const char*
     322           0 : GetDifferentField(const mozilla::TrackInfo& info,
     323             :                   const mozilla::TrackInfo& infoRust)
     324             : {
     325           0 :   if (infoRust.mId != info.mId) { return "Id"; }
     326           0 :   if (infoRust.mKind != info.mKind) { return "Kind"; }
     327           0 :   if (infoRust.mLabel != info.mLabel) { return "Label"; }
     328           0 :   if (infoRust.mLanguage != info.mLanguage) { return "Language"; }
     329           0 :   if (infoRust.mEnabled != info.mEnabled) { return "Enabled"; }
     330           0 :   if (infoRust.mTrackId != info.mTrackId) { return "TrackId"; }
     331           0 :   if (infoRust.mMimeType != info.mMimeType) { return "MimeType"; }
     332           0 :   if (infoRust.mDuration != info.mDuration) { return "Duration"; }
     333           0 :   if (infoRust.mMediaTime != info.mMediaTime) { return "MediaTime"; }
     334           0 :   if (infoRust.mCrypto.mValid != info.mCrypto.mValid) { return "Crypto-Valid"; }
     335           0 :   if (infoRust.mCrypto.mMode != info.mCrypto.mMode) { return "Crypto-Mode"; }
     336           0 :   if (infoRust.mCrypto.mIVSize != info.mCrypto.mIVSize) { return "Crypto-IVSize"; }
     337           0 :   if (infoRust.mCrypto.mKeyId != info.mCrypto.mKeyId) { return "Crypto-KeyId"; }
     338           0 :   switch (info.GetType()) {
     339             :   case mozilla::TrackInfo::kAudioTrack: {
     340           0 :     const AudioInfo *audioRust = infoRust.GetAsAudioInfo();
     341           0 :     const AudioInfo *audio = info.GetAsAudioInfo();
     342           0 :     if (audioRust->mRate != audio->mRate) { return "Rate"; }
     343           0 :     if (audioRust->mChannels != audio->mChannels) { return "Channels"; }
     344           0 :     if (audioRust->mBitDepth != audio->mBitDepth) { return "BitDepth"; }
     345           0 :     if (audioRust->mProfile != audio->mProfile) { return "Profile"; }
     346           0 :     if (audioRust->mExtendedProfile != audio->mExtendedProfile) { return "ExtendedProfile"; }
     347           0 :     break;
     348             :   }
     349             :   case mozilla::TrackInfo::kVideoTrack: {
     350           0 :     const VideoInfo *videoRust = infoRust.GetAsVideoInfo();
     351           0 :     const VideoInfo *video = info.GetAsVideoInfo();
     352           0 :     if (videoRust->mDisplay != video->mDisplay) { return "Display"; }
     353           0 :     if (videoRust->mImage != video->mImage) { return "Image"; }
     354           0 :     if (*videoRust->mExtraData != *video->mExtraData) { return "ExtraData"; }
     355             :     // mCodecSpecificConfig is for video/mp4-es, not video/avc. Since video/mp4-es
     356             :     // is supported on b2g only, it could be removed from TrackInfo.
     357           0 :     if (*videoRust->mCodecSpecificConfig != *video->mCodecSpecificConfig) { return "CodecSpecificConfig"; }
     358           0 :     break;
     359             :   }
     360             :   default:
     361           0 :     break;
     362             :   }
     363             : 
     364           0 :   return nullptr;
     365             : }
     366             : 
     367             : MP4Metadata::ResultAndTrackInfo
     368           0 : MP4Metadata::GetTrackInfo(mozilla::TrackInfo::TrackType aType,
     369             :                           size_t aTrackNumber) const
     370             : {
     371             :   MP4Metadata::ResultAndTrackInfo info =
     372           0 :     mStagefright->GetTrackInfo(aType, aTrackNumber);
     373             : 
     374             :   MP4Metadata::ResultAndTrackInfo infoRust =
     375           0 :     mRust->GetTrackInfo(aType, aTrackNumber);
     376             : 
     377           0 :   if (info.Ref() && infoRust.Ref() && MediaPrefs::MediaWarningsAsErrorsStageFrightVsRust()) {
     378           0 :     const char* diff = GetDifferentField(*info.Ref(), *infoRust.Ref());
     379           0 :     if (diff) {
     380           0 :       return {MediaResult(NS_ERROR_DOM_MEDIA_METADATA_ERR,
     381           0 :                           RESULT_DETAIL("Different field '%s' between "
     382             :                                         "Stagefright (%s) and Rust (%s)",
     383             :                                         diff,
     384             :                                         info.Result().Description().get(),
     385             :                                         infoRust.Result().Description().get())),
     386           0 :               MediaPrefs::MediaWarningsAsErrorsStageFrightVsRust()
     387           0 :                 ? mozilla::UniquePtr<mozilla::TrackInfo>(nullptr)
     388           0 :                 : mDisableRust ? Move(info.Ref()) : Move(infoRust.Ref())};
     389             :     }
     390             :   }
     391             : 
     392           0 :   return mDisableRust ? Move(info) : Move(infoRust);
     393             : }
     394             : 
     395             : bool
     396           0 : MP4Metadata::CanSeek() const
     397             : {
     398           0 :   return mStagefright->CanSeek();
     399             : }
     400             : 
     401             : MP4Metadata::ResultAndCryptoFile
     402           0 : MP4Metadata::Crypto() const
     403             : {
     404           0 :   MP4Metadata::ResultAndCryptoFile crypto = mStagefright->Crypto();
     405           0 :   MP4Metadata::ResultAndCryptoFile rustCrypto = mRust->Crypto();
     406             : 
     407           0 :   if (MediaPrefs::MediaWarningsAsErrorsStageFrightVsRust()) {
     408           0 :     if (rustCrypto.Ref()->pssh != crypto.Ref()->pssh) {
     409           0 :       return {MediaResult(
     410             :                NS_ERROR_DOM_MEDIA_METADATA_ERR,
     411           0 :                RESULT_DETAIL("Mismatch between Stagefright (%s) and Rust (%s) crypto file",
     412             :                              crypto.Result().Description().get(),
     413             :                              rustCrypto.Result().Description().get())),
     414           0 :               mDisableRust ? crypto.Ref() : rustCrypto.Ref()};
     415             :     }
     416             :   }
     417             : 
     418           0 :   return mDisableRust ? crypto : rustCrypto;
     419             : }
     420             : 
     421             : MP4Metadata::ResultAndIndice
     422           0 : MP4Metadata::GetTrackIndice(mozilla::TrackID aTrackID)
     423             : {
     424           0 :   FallibleTArray<Index::Indice> indiceSF;
     425           0 :   if (mDisableRust || MediaPrefs::MediaWarningsAsErrorsStageFrightVsRust()) {
     426           0 :     MediaResult rv = mStagefright->ReadTrackIndex(indiceSF, aTrackID);
     427           0 :     if (NS_FAILED(rv)) {
     428           0 :       return {Move(rv), nullptr};
     429             :     }
     430             :   }
     431             : 
     432           0 :   mp4parse_byte_data indiceRust = {};
     433           0 :   if (!mDisableRust || MediaPrefs::MediaWarningsAsErrorsStageFrightVsRust()) {
     434           0 :     MediaResult rvRust = mRust->ReadTrackIndice(&indiceRust, aTrackID);
     435           0 :     if (NS_FAILED(rvRust)) {
     436           0 :       return {Move(rvRust), nullptr};
     437             :     }
     438             :   }
     439             : 
     440           0 :   if (MediaPrefs::MediaWarningsAsErrorsStageFrightVsRust()) {
     441           0 :     MOZ_DIAGNOSTIC_ASSERT(indiceRust.length == indiceSF.Length());
     442           0 :     for (uint32_t i = 0; i < indiceRust.length; i++) {
     443           0 :       MOZ_DIAGNOSTIC_ASSERT(indiceRust.indices[i].start_offset == indiceSF[i].start_offset);
     444           0 :       MOZ_DIAGNOSTIC_ASSERT(indiceRust.indices[i].end_offset == indiceSF[i].end_offset);
     445           0 :       MOZ_DIAGNOSTIC_ASSERT(llabs(indiceRust.indices[i].start_composition - int64_t(indiceSF[i].start_composition)) <= 1);
     446           0 :       MOZ_DIAGNOSTIC_ASSERT(llabs(indiceRust.indices[i].end_composition - int64_t(indiceSF[i].end_composition)) <= 1);
     447           0 :       MOZ_DIAGNOSTIC_ASSERT(llabs(indiceRust.indices[i].start_decode - int64_t(indiceSF[i].start_decode)) <= 1);
     448           0 :       MOZ_DIAGNOSTIC_ASSERT(indiceRust.indices[i].sync == indiceSF[i].sync);
     449             :     }
     450             :   }
     451             : 
     452           0 :   UniquePtr<IndiceWrapper> indice;
     453           0 :   if (mDisableRust) {
     454           0 :     indice = mozilla::MakeUnique<IndiceWrapperStagefright>(indiceSF);
     455             :   } else {
     456           0 :     indice = mozilla::MakeUnique<IndiceWrapperRust>(indiceRust);
     457             :   }
     458             : 
     459           0 :   return {NS_OK, Move(indice)};
     460             : }
     461             : 
     462             : static inline MediaResult
     463           0 : ConvertIndex(FallibleTArray<Index::Indice>& aDest,
     464             :              const nsTArray<stagefright::MediaSource::Indice>& aIndex,
     465             :              int64_t aMediaTime)
     466             : {
     467           0 :   if (!aDest.SetCapacity(aIndex.Length(), mozilla::fallible)) {
     468             :     return MediaResult{NS_ERROR_OUT_OF_MEMORY,
     469           0 :                        RESULT_DETAIL("Could not resize to %" PRIuSIZE " indices",
     470           0 :                                      aIndex.Length())};
     471             :   }
     472           0 :   for (size_t i = 0; i < aIndex.Length(); i++) {
     473             :     Index::Indice indice;
     474           0 :     const stagefright::MediaSource::Indice& s_indice = aIndex[i];
     475           0 :     indice.start_offset = s_indice.start_offset;
     476           0 :     indice.end_offset = s_indice.end_offset;
     477           0 :     indice.start_composition = s_indice.start_composition - aMediaTime;
     478           0 :     indice.end_composition = s_indice.end_composition - aMediaTime;
     479           0 :     indice.start_decode = s_indice.start_decode;
     480           0 :     indice.sync = s_indice.sync;
     481             :     // FIXME: Make this infallible after bug 968520 is done.
     482           0 :     MOZ_ALWAYS_TRUE(aDest.AppendElement(indice, mozilla::fallible));
     483           0 :     MOZ_LOG(sLog, LogLevel::Debug, ("s_o: %" PRIu64 ", e_o: %" PRIu64 ", s_c: %" PRIu64 ", e_c: %" PRIu64 ", s_d: %" PRIu64 ", sync: %d\n",
     484             :                                     indice.start_offset, indice.end_offset, indice.start_composition, indice.end_composition,
     485             :                                     indice.start_decode, indice.sync));
     486             :   }
     487           0 :   return NS_OK;
     488             : }
     489             : 
     490           0 : MP4MetadataStagefright::MP4MetadataStagefright(Stream* aSource)
     491             :   : mSource(aSource)
     492           0 :   , mMetadataExtractor(new MPEG4Extractor(new DataSourceAdapter(mSource)))
     493           0 :   , mCanSeek(mMetadataExtractor->flags() & MediaExtractor::CAN_SEEK)
     494             : {
     495           0 :   sp<MetaData> metaData = mMetadataExtractor->getMetaData();
     496             : 
     497           0 :   if (metaData.get()) {
     498           0 :     UpdateCrypto(metaData.get());
     499             :   }
     500           0 : }
     501             : 
     502           0 : MP4MetadataStagefright::~MP4MetadataStagefright()
     503             : {
     504           0 : }
     505             : 
     506             : MP4Metadata::ResultAndTrackCount
     507           0 : MP4MetadataStagefright::GetNumberTracks(mozilla::TrackInfo::TrackType aType) const
     508             : {
     509           0 :   size_t tracks = mMetadataExtractor->countTracks();
     510           0 :   uint32_t total = 0;
     511           0 :   for (size_t i = 0; i < tracks; i++) {
     512           0 :     sp<MetaData> metaData = mMetadataExtractor->getTrackMetaData(i);
     513             : 
     514             :     const char* mimeType;
     515           0 :     if (metaData == nullptr || !metaData->findCString(kKeyMIMEType, &mimeType)) {
     516           0 :       continue;
     517             :     }
     518           0 :     switch (aType) {
     519             :       case mozilla::TrackInfo::kAudioTrack:
     520           0 :         if (!strncmp(mimeType, "audio/", 6) &&
     521           0 :             CheckTrack(mimeType, metaData.get(), i)) {
     522           0 :           total++;
     523             :         }
     524           0 :         break;
     525             :       case mozilla::TrackInfo::kVideoTrack:
     526           0 :         if (!strncmp(mimeType, "video/", 6) &&
     527           0 :             CheckTrack(mimeType, metaData.get(), i)) {
     528           0 :           total++;
     529             :         }
     530           0 :         break;
     531             :       default:
     532           0 :         break;
     533             :     }
     534             :   }
     535           0 :   return {NS_OK, total};
     536             : }
     537             : 
     538             : MP4Metadata::ResultAndTrackInfo
     539           0 : MP4MetadataStagefright::GetTrackInfo(mozilla::TrackInfo::TrackType aType,
     540             :                                      size_t aTrackNumber) const
     541             : {
     542           0 :   size_t tracks = mMetadataExtractor->countTracks();
     543           0 :   if (!tracks) {
     544           0 :     return {MediaResult(NS_ERROR_DOM_MEDIA_METADATA_ERR,
     545           0 :                         RESULT_DETAIL("No %s tracks",
     546             :                                       TrackTypeToStr(aType))),
     547           0 :             nullptr};
     548             :   }
     549           0 :   int32_t index = -1;
     550             :   const char* mimeType;
     551           0 :   sp<MetaData> metaData;
     552             : 
     553           0 :   size_t i = 0;
     554           0 :   while (i < tracks) {
     555           0 :     metaData = mMetadataExtractor->getTrackMetaData(i);
     556             : 
     557           0 :     if (metaData == nullptr || !metaData->findCString(kKeyMIMEType, &mimeType)) {
     558           0 :       continue;
     559             :     }
     560           0 :     switch (aType) {
     561             :       case mozilla::TrackInfo::kAudioTrack:
     562           0 :         if (!strncmp(mimeType, "audio/", 6) &&
     563           0 :             CheckTrack(mimeType, metaData.get(), i)) {
     564           0 :           index++;
     565             :         }
     566           0 :         break;
     567             :       case mozilla::TrackInfo::kVideoTrack:
     568           0 :         if (!strncmp(mimeType, "video/", 6) &&
     569           0 :             CheckTrack(mimeType, metaData.get(), i)) {
     570           0 :           index++;
     571             :         }
     572           0 :         break;
     573             :       default:
     574           0 :         break;
     575             :     }
     576           0 :     if (index == aTrackNumber) {
     577           0 :       break;
     578             :     }
     579           0 :     i++;
     580             :   }
     581           0 :   if (index < 0) {
     582           0 :     return {MediaResult(NS_ERROR_DOM_MEDIA_METADATA_ERR,
     583           0 :                         RESULT_DETAIL("Cannot access %s track #%zu",
     584             :                                       TrackTypeToStr(aType),
     585             :                                       aTrackNumber)),
     586           0 :             nullptr};
     587             :   }
     588             : 
     589           0 :   UniquePtr<mozilla::TrackInfo> e = CheckTrack(mimeType, metaData.get(), index);
     590             : 
     591           0 :   if (e) {
     592           0 :     metaData = mMetadataExtractor->getMetaData();
     593             :     int64_t movieDuration;
     594           0 :     if (!e->mDuration.IsPositive() &&
     595           0 :         metaData->findInt64(kKeyMovieDuration, &movieDuration)) {
     596             :       // No duration in track, use movie extend header box one.
     597           0 :       e->mDuration = TimeUnit::FromMicroseconds(movieDuration);
     598             :     }
     599             :   }
     600             : 
     601           0 :   return {NS_OK, Move(e)};
     602             : }
     603             : 
     604             : mozilla::UniquePtr<mozilla::TrackInfo>
     605           0 : MP4MetadataStagefright::CheckTrack(const char* aMimeType,
     606             :                                    stagefright::MetaData* aMetaData,
     607             :                                    int32_t aIndex) const
     608             : {
     609           0 :   sp<MediaSource> track = mMetadataExtractor->getTrack(aIndex);
     610           0 :   if (!track.get()) {
     611           0 :     return nullptr;
     612             :   }
     613             : 
     614           0 :   UniquePtr<mozilla::TrackInfo> e;
     615             : 
     616           0 :   if (!strncmp(aMimeType, "audio/", 6)) {
     617           0 :     auto info = mozilla::MakeUnique<MP4AudioInfo>();
     618           0 :     info->Update(aMetaData, aMimeType);
     619           0 :     e = Move(info);
     620           0 :   } else if (!strncmp(aMimeType, "video/", 6)) {
     621           0 :     auto info = mozilla::MakeUnique<MP4VideoInfo>();
     622           0 :     info->Update(aMetaData, aMimeType);
     623           0 :     e = Move(info);
     624             :   }
     625             : 
     626           0 :   if (e && e->IsValid()) {
     627           0 :     return e;
     628             :   }
     629             : 
     630           0 :   return nullptr;
     631             : }
     632             : 
     633             : bool
     634           0 : MP4MetadataStagefright::CanSeek() const
     635             : {
     636           0 :   return mCanSeek;
     637             : }
     638             : 
     639             : MP4Metadata::ResultAndCryptoFile
     640           0 : MP4MetadataStagefright::Crypto() const
     641             : {
     642           0 :   return {NS_OK, &mCrypto};
     643             : }
     644             : 
     645             : void
     646           0 : MP4MetadataStagefright::UpdateCrypto(const MetaData* aMetaData)
     647             : {
     648             :   const void* data;
     649             :   size_t size;
     650             :   uint32_t type;
     651             : 
     652             :   // There's no point in checking that the type matches anything because it
     653             :   // isn't set consistently in the MPEG4Extractor.
     654           0 :   if (!aMetaData->findData(kKeyPssh, &type, &data, &size)) {
     655           0 :     return;
     656             :   }
     657           0 :   mCrypto.Update(reinterpret_cast<const uint8_t*>(data), size);
     658             : }
     659             : 
     660             : MediaResult
     661           0 : MP4MetadataStagefright::ReadTrackIndex(FallibleTArray<Index::Indice>& aDest, mozilla::TrackID aTrackID)
     662             : {
     663           0 :   size_t numTracks = mMetadataExtractor->countTracks();
     664           0 :   int32_t trackNumber = GetTrackNumber(aTrackID);
     665           0 :   if (trackNumber < 0) {
     666             :     return MediaResult(NS_ERROR_DOM_MEDIA_METADATA_ERR,
     667           0 :                        RESULT_DETAIL("Cannot find track id %d",
     668           0 :                                      int(aTrackID)));
     669             :   }
     670           0 :   sp<MediaSource> track = mMetadataExtractor->getTrack(trackNumber);
     671           0 :   if (!track.get()) {
     672             :     return MediaResult(NS_ERROR_DOM_MEDIA_METADATA_ERR,
     673           0 :                        RESULT_DETAIL("Cannot access track id %d",
     674           0 :                                      int(aTrackID)));
     675             :   }
     676           0 :   sp<MetaData> metadata = mMetadataExtractor->getTrackMetaData(trackNumber);
     677             :   int64_t mediaTime;
     678           0 :   if (!metadata->findInt64(kKeyMediaTime, &mediaTime)) {
     679           0 :     mediaTime = 0;
     680             :   }
     681             : 
     682           0 :   return ConvertIndex(aDest, track->exportIndex(), mediaTime);
     683             : }
     684             : 
     685             : int32_t
     686           0 : MP4MetadataStagefright::GetTrackNumber(mozilla::TrackID aTrackID)
     687             : {
     688           0 :   size_t numTracks = mMetadataExtractor->countTracks();
     689           0 :   for (size_t i = 0; i < numTracks; i++) {
     690           0 :     sp<MetaData> metaData = mMetadataExtractor->getTrackMetaData(i);
     691           0 :     if (!metaData.get()) {
     692           0 :       continue;
     693             :     }
     694             :     int32_t value;
     695           0 :     if (metaData->findInt32(kKeyTrackID, &value) && value == aTrackID) {
     696           0 :       return i;
     697             :     }
     698             :   }
     699           0 :   return -1;
     700             : }
     701             : 
     702             : /*static*/ MP4Metadata::ResultAndByteBuffer
     703           0 : MP4MetadataStagefright::Metadata(Stream* aSource)
     704             : {
     705           0 :   auto parser = mozilla::MakeUnique<MoofParser>(aSource, 0, false);
     706           0 :   RefPtr<mozilla::MediaByteBuffer> buffer = parser->Metadata();
     707           0 :   if (!buffer) {
     708           0 :     return {MediaResult(NS_ERROR_DOM_MEDIA_METADATA_ERR,
     709           0 :                         RESULT_DETAIL("Cannot parse metadata")),
     710           0 :             nullptr};
     711             :   }
     712           0 :   return {NS_OK, Move(buffer)};
     713             : }
     714             : 
     715             : bool
     716           0 : RustStreamAdaptor::Read(uint8_t* buffer, uintptr_t size, size_t* bytes_read)
     717             : {
     718           0 :   if (!mOffset.isValid()) {
     719           0 :     MOZ_LOG(sLog, LogLevel::Error, ("Overflow in source stream offset"));
     720           0 :     return false;
     721             :   }
     722           0 :   bool rv = mSource->ReadAt(mOffset.value(), buffer, size, bytes_read);
     723           0 :   if (rv) {
     724           0 :     mOffset += *bytes_read;
     725             :   }
     726           0 :   return rv;
     727             : }
     728             : 
     729             : // Wrapper to allow rust to call our read adaptor.
     730             : static intptr_t
     731           0 : read_source(uint8_t* buffer, uintptr_t size, void* userdata)
     732             : {
     733           0 :   MOZ_ASSERT(buffer);
     734           0 :   MOZ_ASSERT(userdata);
     735             : 
     736           0 :   auto source = reinterpret_cast<RustStreamAdaptor*>(userdata);
     737           0 :   size_t bytes_read = 0;
     738           0 :   bool rv = source->Read(buffer, size, &bytes_read);
     739           0 :   if (!rv) {
     740           0 :     MOZ_LOG(sLog, LogLevel::Warning, ("Error reading source data"));
     741           0 :     return -1;
     742             :   }
     743           0 :   return bytes_read;
     744             : }
     745             : 
     746           0 : MP4MetadataRust::MP4MetadataRust(Stream* aSource)
     747             :   : mSource(aSource)
     748           0 :   , mRustSource(aSource)
     749             : {
     750           0 : }
     751             : 
     752           0 : MP4MetadataRust::~MP4MetadataRust()
     753             : {
     754           0 : }
     755             : 
     756             : bool
     757           0 : MP4MetadataRust::Init()
     758             : {
     759           0 :   mp4parse_io io = { read_source, &mRustSource };
     760           0 :   mRustParser.reset(mp4parse_new(&io));
     761           0 :   MOZ_ASSERT(mRustParser);
     762             : 
     763           0 :   if (MOZ_LOG_TEST(sLog, LogLevel::Debug)) {
     764           0 :     mp4parse_log(true);
     765             :   }
     766             : 
     767           0 :   mp4parse_status rv = mp4parse_read(mRustParser.get());
     768           0 :   MOZ_LOG(sLog, LogLevel::Debug, ("rust parser returned %d\n", rv));
     769           0 :   Telemetry::Accumulate(Telemetry::MEDIA_RUST_MP4PARSE_SUCCESS,
     770           0 :                         rv == mp4parse_status_OK);
     771           0 :   if (rv != mp4parse_status_OK) {
     772           0 :     MOZ_LOG(sLog, LogLevel::Info, ("Rust mp4 parser fails to parse this stream."));
     773           0 :     MOZ_ASSERT(rv > 0);
     774           0 :     Telemetry::Accumulate(Telemetry::MEDIA_RUST_MP4PARSE_ERROR_CODE, rv);
     775           0 :     return false;
     776             :   }
     777             : 
     778           0 :   UpdateCrypto();
     779             : 
     780           0 :   return true;
     781             : }
     782             : 
     783             : void
     784           0 : MP4MetadataRust::UpdateCrypto()
     785             : {
     786           0 :   mp4parse_pssh_info info = {};
     787           0 :   if (mp4parse_get_pssh_info(mRustParser.get(), &info) != mp4parse_status_OK) {
     788           0 :     return;
     789             :   }
     790             : 
     791           0 :   if (info.data.length == 0) {
     792           0 :     return;
     793             :   }
     794             : 
     795           0 :   mCrypto.Update(info.data.data, info.data.length);
     796             : }
     797             : 
     798             : bool
     799           0 : TrackTypeEqual(TrackInfo::TrackType aLHS, mp4parse_track_type aRHS)
     800             : {
     801           0 :   switch (aLHS) {
     802             :   case TrackInfo::kAudioTrack:
     803           0 :     return aRHS == mp4parse_track_type_AUDIO;
     804             :   case TrackInfo::kVideoTrack:
     805           0 :     return aRHS == mp4parse_track_type_VIDEO;
     806             :   default:
     807           0 :     return false;
     808             :   }
     809             : }
     810             : 
     811             : MP4Metadata::ResultAndTrackCount
     812           0 : MP4MetadataRust::GetNumberTracks(mozilla::TrackInfo::TrackType aType) const
     813             : {
     814             :   uint32_t tracks;
     815           0 :   auto rv = mp4parse_get_track_count(mRustParser.get(), &tracks);
     816           0 :   if (rv != mp4parse_status_OK) {
     817           0 :     MOZ_LOG(sLog, LogLevel::Warning,
     818             :         ("rust parser error %d counting tracks", rv));
     819           0 :     return {MediaResult(NS_ERROR_DOM_MEDIA_METADATA_ERR,
     820           0 :                         RESULT_DETAIL("Rust parser error %d", rv)),
     821           0 :             MP4Metadata::NumberTracksError()};
     822             :   }
     823           0 :   MOZ_LOG(sLog, LogLevel::Info, ("rust parser found %u tracks", tracks));
     824             : 
     825           0 :   uint32_t total = 0;
     826           0 :   for (uint32_t i = 0; i < tracks; ++i) {
     827             :     mp4parse_track_info track_info;
     828           0 :     rv = mp4parse_get_track_info(mRustParser.get(), i, &track_info);
     829           0 :     if (rv != mp4parse_status_OK) {
     830           0 :       continue;
     831             :     }
     832             :     // JPEG 'video' decoder is not supported in media stack yet.
     833           0 :     if (track_info.codec == mp4parse_codec::mp4parse_codec_JPEG ||
     834           0 :         track_info.codec == mp4parse_codec::mp4parse_codec_UNKNOWN) {
     835           0 :       continue;
     836             :     }
     837           0 :     if (TrackTypeEqual(aType, track_info.track_type)) {
     838           0 :         total += 1;
     839             :     }
     840             :   }
     841             : 
     842           0 :   return {NS_OK, total};
     843             : }
     844             : 
     845             : Maybe<uint32_t>
     846           0 : MP4MetadataRust::TrackTypeToGlobalTrackIndex(mozilla::TrackInfo::TrackType aType, size_t aTrackNumber) const
     847             : {
     848             :   uint32_t tracks;
     849           0 :   auto rv = mp4parse_get_track_count(mRustParser.get(), &tracks);
     850           0 :   if (rv != mp4parse_status_OK) {
     851           0 :     return Nothing();
     852             :   }
     853             : 
     854             :   /* The MP4Metadata API uses a per-TrackType index of tracks, but mp4parse
     855             :      (and libstagefright) use a global track index.  Convert the index by
     856             :      counting the tracks of the requested type and returning the global
     857             :      track index when a match is found. */
     858           0 :   uint32_t perType = 0;
     859           0 :   for (uint32_t i = 0; i < tracks; ++i) {
     860             :     mp4parse_track_info track_info;
     861           0 :     rv = mp4parse_get_track_info(mRustParser.get(), i, &track_info);
     862           0 :     if (rv != mp4parse_status_OK) {
     863           0 :       continue;
     864             :     }
     865           0 :     if (TrackTypeEqual(aType, track_info.track_type)) {
     866           0 :       if (perType == aTrackNumber) {
     867           0 :         return Some(i);
     868             :       }
     869           0 :       perType += 1;
     870             :     }
     871             :   }
     872             : 
     873           0 :   return Nothing();
     874             : }
     875             : 
     876             : MP4Metadata::ResultAndTrackInfo
     877           0 : MP4MetadataRust::GetTrackInfo(mozilla::TrackInfo::TrackType aType,
     878             :                               size_t aTrackNumber) const
     879             : {
     880           0 :   Maybe<uint32_t> trackIndex = TrackTypeToGlobalTrackIndex(aType, aTrackNumber);
     881           0 :   if (trackIndex.isNothing()) {
     882           0 :     return {MediaResult(NS_ERROR_DOM_MEDIA_METADATA_ERR,
     883           0 :                         RESULT_DETAIL("No %s tracks",
     884             :                                       TrackTypeToStr(aType))),
     885           0 :             nullptr};
     886             :   }
     887             : 
     888             :   mp4parse_track_info info;
     889           0 :   auto rv = mp4parse_get_track_info(mRustParser.get(), trackIndex.value(), &info);
     890           0 :   if (rv != mp4parse_status_OK) {
     891           0 :     MOZ_LOG(sLog, LogLevel::Warning, ("mp4parse_get_track_info returned %d", rv));
     892           0 :     return {MediaResult(NS_ERROR_DOM_MEDIA_METADATA_ERR,
     893           0 :                         RESULT_DETAIL("Cannot find %s track #%zu",
     894             :                                       TrackTypeToStr(aType),
     895             :                                       aTrackNumber)),
     896           0 :             nullptr};
     897             :   }
     898             : #ifdef DEBUG
     899           0 :   const char* codec_string = "unrecognized";
     900           0 :   switch (info.codec) {
     901           0 :     case mp4parse_codec_UNKNOWN: codec_string = "unknown"; break;
     902           0 :     case mp4parse_codec_AAC: codec_string = "aac"; break;
     903           0 :     case mp4parse_codec_OPUS: codec_string = "opus"; break;
     904           0 :     case mp4parse_codec_FLAC: codec_string = "flac"; break;
     905           0 :     case mp4parse_codec_AVC: codec_string = "h.264"; break;
     906           0 :     case mp4parse_codec_VP9: codec_string = "vp9"; break;
     907           0 :     case mp4parse_codec_MP3: codec_string = "mp3"; break;
     908           0 :     case mp4parse_codec_MP4V: codec_string = "mp4v"; break;
     909           0 :     case mp4parse_codec_JPEG: codec_string = "jpeg"; break;
     910           0 :     case mp4parse_codec_AC3: codec_string = "ac-3"; break;
     911           0 :     case mp4parse_codec_EC3: codec_string = "ec-3"; break;
     912             :   }
     913           0 :   MOZ_LOG(sLog, LogLevel::Debug, ("track codec %s (%u)\n",
     914             :         codec_string, info.codec));
     915             : #endif
     916             : 
     917             :   // This specialization interface is crazy.
     918           0 :   UniquePtr<mozilla::TrackInfo> e;
     919           0 :   switch (aType) {
     920             :     case TrackInfo::TrackType::kAudioTrack: {
     921             :       mp4parse_track_audio_info audio;
     922           0 :       auto rv = mp4parse_get_track_audio_info(mRustParser.get(), trackIndex.value(), &audio);
     923           0 :       if (rv != mp4parse_status_OK) {
     924           0 :         MOZ_LOG(sLog, LogLevel::Warning, ("mp4parse_get_track_audio_info returned error %d", rv));
     925           0 :         return {MediaResult(NS_ERROR_DOM_MEDIA_METADATA_ERR,
     926           0 :                             RESULT_DETAIL("Cannot parse %s track #%zu",
     927             :                                           TrackTypeToStr(aType),
     928             :                                           aTrackNumber)),
     929           0 :                 nullptr};
     930             :       }
     931           0 :       auto track = mozilla::MakeUnique<MP4AudioInfo>();
     932           0 :       track->Update(&info, &audio);
     933           0 :       e = Move(track);
     934             :     }
     935           0 :     break;
     936             :     case TrackInfo::TrackType::kVideoTrack: {
     937             :       mp4parse_track_video_info video;
     938           0 :       auto rv = mp4parse_get_track_video_info(mRustParser.get(), trackIndex.value(), &video);
     939           0 :       if (rv != mp4parse_status_OK) {
     940           0 :         MOZ_LOG(sLog, LogLevel::Warning, ("mp4parse_get_track_video_info returned error %d", rv));
     941           0 :         return {MediaResult(NS_ERROR_DOM_MEDIA_METADATA_ERR,
     942           0 :                             RESULT_DETAIL("Cannot parse %s track #%zu",
     943             :                                           TrackTypeToStr(aType),
     944             :                                           aTrackNumber)),
     945           0 :                 nullptr};
     946             :       }
     947           0 :       auto track = mozilla::MakeUnique<MP4VideoInfo>();
     948           0 :       track->Update(&info, &video);
     949           0 :       e = Move(track);
     950             :     }
     951           0 :     break;
     952             :     default:
     953           0 :       MOZ_LOG(sLog, LogLevel::Warning, ("unhandled track type %d", aType));
     954           0 :       return {MediaResult(NS_ERROR_DOM_MEDIA_METADATA_ERR,
     955           0 :                           RESULT_DETAIL("Cannot handle %s track #%zu",
     956             :                                         TrackTypeToStr(aType),
     957             :                                         aTrackNumber)),
     958           0 :               nullptr};
     959             :   }
     960             : 
     961             :   // No duration in track, use fragment_duration.
     962           0 :   if (e && !e->mDuration.IsPositive()) {
     963             :     mp4parse_fragment_info info;
     964           0 :     auto rv = mp4parse_get_fragment_info(mRustParser.get(), &info);
     965           0 :     if (rv == mp4parse_status_OK) {
     966           0 :       e->mDuration = TimeUnit::FromMicroseconds(info.fragment_duration);
     967             :     }
     968             :   }
     969             : 
     970           0 :   if (e && e->IsValid()) {
     971           0 :     return {NS_OK, Move(e)};
     972             :   }
     973           0 :   MOZ_LOG(sLog, LogLevel::Debug, ("TrackInfo didn't validate"));
     974             : 
     975           0 :   return {MediaResult(NS_ERROR_DOM_MEDIA_METADATA_ERR,
     976           0 :                       RESULT_DETAIL("Invalid %s track #%zu",
     977             :                                     TrackTypeToStr(aType),
     978             :                                     aTrackNumber)),
     979           0 :           nullptr};
     980             : }
     981             : 
     982             : bool
     983           0 : MP4MetadataRust::CanSeek() const
     984             : {
     985           0 :   MOZ_ASSERT(false, "Not yet implemented");
     986             :   return false;
     987             : }
     988             : 
     989             : MP4Metadata::ResultAndCryptoFile
     990           0 : MP4MetadataRust::Crypto() const
     991             : {
     992           0 :   return {NS_OK, &mCrypto};
     993             : }
     994             : 
     995             : MediaResult
     996           0 : MP4MetadataRust::ReadTrackIndice(mp4parse_byte_data* aIndices, mozilla::TrackID aTrackID)
     997             : {
     998           0 :   uint8_t fragmented = false;
     999           0 :   auto rv = mp4parse_is_fragmented(mRustParser.get(), aTrackID, &fragmented);
    1000           0 :   if (rv != mp4parse_status_OK) {
    1001             :     return MediaResult(NS_ERROR_DOM_MEDIA_METADATA_ERR,
    1002           0 :                        RESULT_DETAIL("Cannot parse whether track id %d is "
    1003             :                                      "fragmented, mp4parse_error=%d",
    1004           0 :                                      int(aTrackID), int(rv)));
    1005             :   }
    1006             : 
    1007           0 :   if (fragmented) {
    1008           0 :     return NS_OK;
    1009             :   }
    1010             : 
    1011           0 :   rv = mp4parse_get_indice_table(mRustParser.get(), aTrackID, aIndices);
    1012           0 :   if (rv != mp4parse_status_OK) {
    1013             :     return MediaResult(NS_ERROR_DOM_MEDIA_METADATA_ERR,
    1014           0 :                        RESULT_DETAIL("Cannot parse index table in track id %d, "
    1015             :                                      "mp4parse_error=%d",
    1016           0 :                                      int(aTrackID), int(rv)));
    1017             :   }
    1018             : 
    1019           0 :   return NS_OK;
    1020             : }
    1021             : 
    1022             : /*static*/ MP4Metadata::ResultAndByteBuffer
    1023           0 : MP4MetadataRust::Metadata(Stream* aSource)
    1024             : {
    1025           0 :   MOZ_ASSERT(false, "Not yet implemented");
    1026             :   return {NS_ERROR_NOT_IMPLEMENTED, nullptr};
    1027             : }
    1028             : 
    1029             : } // namespace mp4_demuxer

Generated by: LCOV version 1.13