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.
This commit is contained in:
Jean-Yves Avenard 2015-08-20 16:50:08 +10:00
parent 22a71eae08
commit ddfed3bab2
5 changed files with 53 additions and 25 deletions

View File

@ -79,22 +79,16 @@ MP4Demuxer::Init()
AutoPinned<mp4_demuxer::ResourceStream> 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<mp4_demuxer::BufferStream> bufferstream =
new mp4_demuxer::BufferStream(mInitData);

View File

@ -287,17 +287,14 @@ MP4Metadata::HasCompleteMetadata(Stream* aSource)
return parser->HasMetadata();
}
/*static*/ mozilla::MediaByteRange
MP4Metadata::MetadataRange(Stream* aSource)
/*static*/ already_AddRefed<mozilla::MediaByteBuffer>
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<MoofParser>(aSource, 0, false, &monitor);
if (parser->HasMetadata()) {
return parser->mInitRange;
}
return mozilla::MediaByteRange();
return parser->Metadata();
}
} // namespace mp4_demuxer

View File

@ -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<int64_t>::max();
mSource->Length(&length);
@ -157,24 +158,57 @@ MoofParser::HasMetadata()
byteRanges.AppendElement(MediaByteRange(0, length));
nsRefPtr<mp4_demuxer::BlockingStream> 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<mozilla::MediaByteBuffer>
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<MediaByteBuffer> metadata = new MediaByteBuffer();
if (!metadata->SetLength(ftyp.Length() + moov.Length(), fallible)) {
// OOM
return nullptr;
}
nsRefPtr<mp4_demuxer::BlockingStream> 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<Microseconds>

View File

@ -30,7 +30,7 @@ public:
~MP4Metadata();
static bool HasCompleteMetadata(Stream* aSource);
static mozilla::MediaByteRange MetadataRange(Stream* aSource);
static already_AddRefed<mozilla::MediaByteBuffer> Metadata(Stream* aSource);
uint32_t GetNumberTracks(mozilla::TrackInfo::TrackType aType) const;
mozilla::UniquePtr<mozilla::TrackInfo> GetTrackInfo(mozilla::TrackInfo::TrackType aType,
size_t aTrackNumber) const;

View File

@ -228,6 +228,7 @@ public:
bool BlockingReadNextMoof();
bool HasMetadata();
already_AddRefed<mozilla::MediaByteBuffer> Metadata();
MediaByteRange FirstCompleteMediaSegment();
MediaByteRange FirstCompleteMediaHeader();
@ -244,6 +245,8 @@ public:
Monitor* mMonitor;
nsTArray<Moof>& Moofs() { mMonitor->AssertCurrentThreadOwns(); return mMoofs; }
private:
void ScanForMetadata(mozilla::MediaByteRange& aFtyp,
mozilla::MediaByteRange& aMoov);
nsTArray<Moof> mMoofs;
nsTArray<MediaByteRange> mMediaRanges;
bool mIsAudio;