зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
067b45951a
Коммит
1a98b5d4e0
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче