From ddfed3bab27943147d8595796e7a70c99ec8d413 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Thu, 20 Aug 2015 16:50:08 +1000 Subject: [PATCH] Bug 1196398: [mp4] Do not allocate memory spanning across ftyp and moov atom. r=kentuckyfriedtakahe A typical non-fragmented mp4 would have the ftyp atom located at the beginning of the mp4 and the moov at the end. We would to calculate the location of the metadata by spanning the byte range of the two atoms. As such, we would typically allocate an amount of memory equivalent to the size of the mp4. Instead we now reconstruct the metadata to only have the ftyp and moov atoms contiguously. --- dom/media/fmp4/MP4Demuxer.cpp | 12 ++--- media/libstagefright/binding/MP4Metadata.cpp | 9 ++-- media/libstagefright/binding/MoofParser.cpp | 52 +++++++++++++++---- .../binding/include/mp4_demuxer/MP4Metadata.h | 2 +- .../binding/include/mp4_demuxer/MoofParser.h | 3 ++ 5 files changed, 53 insertions(+), 25 deletions(-) diff --git a/dom/media/fmp4/MP4Demuxer.cpp b/dom/media/fmp4/MP4Demuxer.cpp index a21ff213941..0a95ac56c86 100644 --- a/dom/media/fmp4/MP4Demuxer.cpp +++ b/dom/media/fmp4/MP4Demuxer.cpp @@ -79,22 +79,16 @@ MP4Demuxer::Init() AutoPinned stream(mStream); // Check that we have enough data to read the metadata. - MediaByteRange br = mp4_demuxer::MP4Metadata::MetadataRange(stream); - if (br.IsNull()) { + if (!mp4_demuxer::MP4Metadata::HasCompleteMetadata(stream)) { return InitPromise::CreateAndReject(DemuxerFailureReason::WAITING_FOR_DATA, __func__); } - if (!mInitData->SetLength(br.Length(), fallible)) { + mInitData = mp4_demuxer::MP4Metadata::Metadata(stream); + if (!mInitData) { // OOM return InitPromise::CreateAndReject(DemuxerFailureReason::DEMUXER_ERROR, __func__); } - size_t size; - mStream->ReadAt(br.mStart, mInitData->Elements(), br.Length(), &size); - if (size != size_t(br.Length())) { - return InitPromise::CreateAndReject(DemuxerFailureReason::DEMUXER_ERROR, __func__); - } - nsRefPtr bufferstream = new mp4_demuxer::BufferStream(mInitData); diff --git a/media/libstagefright/binding/MP4Metadata.cpp b/media/libstagefright/binding/MP4Metadata.cpp index 5effe9f4499..6782b34e942 100644 --- a/media/libstagefright/binding/MP4Metadata.cpp +++ b/media/libstagefright/binding/MP4Metadata.cpp @@ -287,17 +287,14 @@ MP4Metadata::HasCompleteMetadata(Stream* aSource) return parser->HasMetadata(); } -/*static*/ mozilla::MediaByteRange -MP4Metadata::MetadataRange(Stream* aSource) +/*static*/ already_AddRefed +MP4Metadata::Metadata(Stream* aSource) { // The MoofParser requires a monitor, but we don't need one here. mozilla::Monitor monitor("MP4Metadata::HasCompleteMetadata"); mozilla::MonitorAutoLock mon(monitor); auto parser = mozilla::MakeUnique(aSource, 0, false, &monitor); - if (parser->HasMetadata()) { - return parser->mInitRange; - } - return mozilla::MediaByteRange(); + return parser->Metadata(); } } // namespace mp4_demuxer diff --git a/media/libstagefright/binding/MoofParser.cpp b/media/libstagefright/binding/MoofParser.cpp index 7bb7d090de0..79fa3ff7741 100644 --- a/media/libstagefright/binding/MoofParser.cpp +++ b/media/libstagefright/binding/MoofParser.cpp @@ -148,8 +148,9 @@ MoofParser::BlockingReadNextMoof() return false; } -bool -MoofParser::HasMetadata() +void +MoofParser::ScanForMetadata(mozilla::MediaByteRange& aFtyp, + mozilla::MediaByteRange& aMoov) { int64_t length = std::numeric_limits::max(); mSource->Length(&length); @@ -157,24 +158,57 @@ MoofParser::HasMetadata() byteRanges.AppendElement(MediaByteRange(0, length)); nsRefPtr stream = new BlockingStream(mSource); - MediaByteRange ftyp; - MediaByteRange moov; BoxContext context(stream, byteRanges); for (Box box(&context, mOffset); box.IsAvailable(); box = box.Next()) { if (box.IsType("ftyp")) { - ftyp = box.Range(); + aFtyp = box.Range(); continue; } if (box.IsType("moov")) { - moov = box.Range(); + aMoov = box.Range(); break; } } + mInitRange = aFtyp.Extents(aMoov); +} + +bool +MoofParser::HasMetadata() +{ + MediaByteRange ftyp; + MediaByteRange moov; + ScanForMetadata(ftyp, moov); + return !!ftyp.Length() && !!moov.Length(); +} + +already_AddRefed +MoofParser::Metadata() +{ + MediaByteRange ftyp; + MediaByteRange moov; + ScanForMetadata(ftyp, moov); if (!ftyp.Length() || !moov.Length()) { - return false; + return nullptr; } - mInitRange = ftyp.Extents(moov); - return true; + nsRefPtr metadata = new MediaByteBuffer(); + if (!metadata->SetLength(ftyp.Length() + moov.Length(), fallible)) { + // OOM + return nullptr; + } + + nsRefPtr stream = new BlockingStream(mSource); + size_t read; + bool rv = + stream->ReadAt(ftyp.mStart, metadata->Elements(), ftyp.Length(), &read); + if (!rv || read != ftyp.Length()) { + return nullptr; + } + rv = + stream->ReadAt(moov.mStart, metadata->Elements() + ftyp.Length(), moov.Length(), &read); + if (!rv || read != moov.Length()) { + return nullptr; + } + return metadata.forget(); } Interval diff --git a/media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h b/media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h index de9273c2725..45def45af7a 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h +++ b/media/libstagefright/binding/include/mp4_demuxer/MP4Metadata.h @@ -30,7 +30,7 @@ public: ~MP4Metadata(); static bool HasCompleteMetadata(Stream* aSource); - static mozilla::MediaByteRange MetadataRange(Stream* aSource); + static already_AddRefed Metadata(Stream* aSource); uint32_t GetNumberTracks(mozilla::TrackInfo::TrackType aType) const; mozilla::UniquePtr GetTrackInfo(mozilla::TrackInfo::TrackType aType, size_t aTrackNumber) const; diff --git a/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h b/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h index 86daead28cd..4b1740b1e23 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h +++ b/media/libstagefright/binding/include/mp4_demuxer/MoofParser.h @@ -228,6 +228,7 @@ public: bool BlockingReadNextMoof(); bool HasMetadata(); + already_AddRefed Metadata(); MediaByteRange FirstCompleteMediaSegment(); MediaByteRange FirstCompleteMediaHeader(); @@ -244,6 +245,8 @@ public: Monitor* mMonitor; nsTArray& Moofs() { mMonitor->AssertCurrentThreadOwns(); return mMoofs; } private: + void ScanForMetadata(mozilla::MediaByteRange& aFtyp, + mozilla::MediaByteRange& aMoov); nsTArray mMoofs; nsTArray mMediaRanges; bool mIsAudio;