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
Родитель 067b45951a
Коммит 1a98b5d4e0
5 изменённых файлов: 53 добавлений и 25 удалений

Просмотреть файл

@ -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);

Просмотреть файл

@ -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

Просмотреть файл

@ -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>

Просмотреть файл

@ -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;

Просмотреть файл

@ -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;