--- a/dom/media/mediasource/ContainerParser.cpp
+++ b/dom/media/mediasource/ContainerParser.cpp
@@ -436,48 +436,58 @@ public:
{
ContainerParser::IsInitSegmentPresent(aData);
// Each MP4 atom has a chunk size and chunk type. The root chunk in an MP4
// file is the 'ftyp' atom followed by a file type. We just check for a
// vaguely valid 'ftyp' atom.
if (aData->Length() < 8) {
return NS_ERROR_NOT_AVAILABLE;
}
- AtomParser parser(mType, aData);
+ AtomParser parser(mType, aData, AtomParser::StopAt::eInitSegment);
if (!parser.IsValid()) {
return MediaResult(
NS_ERROR_FAILURE,
RESULT_DETAIL("Invalid Top-Level Box:%s", parser.LastInvalidBox()));
}
return parser.StartWithInitSegment() ? NS_OK : NS_ERROR_NOT_AVAILABLE;
}
MediaResult IsMediaSegmentPresent(MediaByteBuffer* aData) override
{
if (aData->Length() < 8) {
return NS_ERROR_NOT_AVAILABLE;
}
- AtomParser parser(mType, aData);
+ AtomParser parser(mType, aData, AtomParser::StopAt::eMediaSegment);
if (!parser.IsValid()) {
return MediaResult(
NS_ERROR_FAILURE,
RESULT_DETAIL("Invalid Box:%s", parser.LastInvalidBox()));
}
return parser.StartWithMediaSegment() ? NS_OK : NS_ERROR_NOT_AVAILABLE;
}
private:
- class AtomParser {
+ class AtomParser
+ {
public:
- AtomParser(const MediaContainerType& aType, const MediaByteBuffer* aData)
+ enum class StopAt
+ {
+ eInitSegment,
+ eMediaSegment,
+ eEnd
+ };
+
+ AtomParser(const MediaContainerType& aType, const MediaByteBuffer* aData,
+ StopAt aStop = StopAt::eEnd)
{
const MediaContainerType mType(aType); // for logging macro.
mp4_demuxer::ByteReader reader(aData);
mp4_demuxer::AtomType initAtom("moov");
mp4_demuxer::AtomType mediaAtom("moof");
+ mp4_demuxer::AtomType dataAtom("mdat");
// Valid top-level boxes defined in ISO/IEC 14496-12 (Table 1)
static const mp4_demuxer::AtomType validBoxes[] = {
"ftyp", "moov", // init segment
"pdin", "free", "sidx", // optional prior moov box
"styp", "moof", "mdat", // media segment
"mfra", "skip", "meta", "meco", "ssix", "prft", // others.
"pssh", // optional with encrypted EME, though ignored.
@@ -506,19 +516,19 @@ private:
if (mInitOffset.isNothing() &&
mp4_demuxer::AtomType(type) == initAtom) {
mInitOffset = Some(reader.Offset());
}
if (mMediaOffset.isNothing() &&
mp4_demuxer::AtomType(type) == mediaAtom) {
mMediaOffset = Some(reader.Offset());
}
- if (mInitOffset.isSome() && mMediaOffset.isSome()) {
- // We have everything we need.
- break;
+ if (mDataOffset.isNothing() &&
+ mp4_demuxer::AtomType(type) == dataAtom) {
+ mDataOffset = Some(reader.Offset());
}
if (size == 1) {
// 64 bits size.
if (!reader.CanReadType<uint64_t>()) {
break;
}
size = reader.ReadU64();
} else if (size == 0) {
@@ -526,16 +536,30 @@ private:
// looking for.
break;
}
if (reader.Remaining() < size - 8) {
// Incomplete atom.
break;
}
reader.Read(size - 8);
+
+ if (aStop == StopAt::eInitSegment && (mInitOffset || mMediaOffset)) {
+ // When we're looking for an init segment, if we encountered a media
+ // segment, it we will need to be processed first. So we can stop
+ // right away if we have found a media segment.
+ break;
+ }
+ if (aStop == StopAt::eMediaSegment &&
+ (mInitOffset || (mMediaOffset && mDataOffset))) {
+ // When we're looking for a media segment, if we encountered an init
+ // segment, it we will need to be processed first. So we can stop
+ // right away if we have found an init segment.
+ break;
+ }
}
}
bool StartWithInitSegment() const
{
return mInitOffset.isSome() &&
(mMediaOffset.isNothing() || mInitOffset.ref() < mMediaOffset.ref());
}
@@ -544,16 +568,17 @@ private:
return mMediaOffset.isSome() &&
(mInitOffset.isNothing() || mMediaOffset.ref() < mInitOffset.ref());
}
bool IsValid() const { return mValid; }
const char* LastInvalidBox() const { return mLastInvalidBox; }
private:
Maybe<size_t> mInitOffset;
Maybe<size_t> mMediaOffset;
+ Maybe<size_t> mDataOffset;
bool mValid = true;
char mLastInvalidBox[5];
};
public:
MediaResult ParseStartAndEndTimestamps(MediaByteBuffer* aData,
int64_t& aStart,
int64_t& aEnd) override