Bug 1525507 - P1. Don't trust mp4 container to determine if a VP9 frame is a keyframe. r=bryce

Similar to what we do for H264 and for vp9 in webm, we parse the VP9 bytestream and check if a frame is a keyframe there instead.

Differential Revision: https://phabricator.services.mozilla.com/D18790

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Jean-Yves Avenard 2019-02-06 20:34:39 +00:00
Родитель 8e0e225e22
Коммит 8be6b34abb
1 изменённых файлов: 29 добавлений и 6 удалений

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

@ -14,9 +14,12 @@
#include "BufferStream.h"
#include "H264.h"
#include "Index.h"
#include "MP4Decoder.h"
#include "MP4Metadata.h"
#include "MoofParser.h"
#include "ResourceStream.h"
#include "VPXDecoder.h"
#include "mozilla/Span.h"
#include "mozilla/StaticPrefs.h"
#include "mozilla/Telemetry.h"
#include "nsAutoPtr.h"
@ -71,7 +74,11 @@ class MP4TrackDemuxer : public MediaTrackDemuxer,
RefPtr<MediaRawData> mQueuedSample;
bool mNeedReIndex;
bool mNeedSPSForTelemetry;
bool mIsH264 = false;
enum CodecType {
kH264,
kVP9,
kOther
} mType = kOther;
};
// Returns true if no SPS was found and search for it should continue.
@ -350,9 +357,8 @@ MP4TrackDemuxer::MP4TrackDemuxer(MediaResource* aResource,
VideoInfo* videoInfo = mInfo->GetAsVideoInfo();
// Collect telemetry from h264 AVCC SPS.
if (videoInfo && (mInfo->mMimeType.EqualsLiteral("video/mp4") ||
mInfo->mMimeType.EqualsLiteral("video/avc"))) {
mIsH264 = true;
if (videoInfo && MP4Decoder::IsH264(mInfo->mMimeType)) {
mType = kH264;
RefPtr<MediaByteBuffer> extraData = videoInfo->mExtraData;
mNeedSPSForTelemetry = AccumulateSPSTelemetry(extraData);
SPSData spsdata;
@ -365,6 +371,9 @@ MP4TrackDemuxer::MP4TrackDemuxer(MediaResource* aResource,
videoInfo->mDisplay.height = spsdata.display_height;
}
} else {
if (videoInfo && VPXDecoder::IsVP9(mInfo->mMimeType)) {
mType = kVP9;
}
// No SPS to be found.
mNeedSPSForTelemetry = false;
}
@ -422,7 +431,7 @@ already_AddRefed<MediaRawData> MP4TrackDemuxer::GetNextSample() {
}
if (mInfo->GetAsVideoInfo()) {
sample->mExtraData = mInfo->GetAsVideoInfo()->mExtraData;
if (mIsH264 && !sample->mCrypto.IsEncrypted()) {
if (mType == kH264 && !sample->mCrypto.IsEncrypted()) {
H264::FrameType type = H264::GetFrameType(sample);
switch (type) {
case H264::FrameType::I_FRAME:
@ -455,6 +464,20 @@ already_AddRefed<MediaRawData> MP4TrackDemuxer::GetNextSample() {
// TODO: make demuxer errors non-fatal.
break;
}
} else if (mType == kVP9 && !sample->mCrypto.IsEncrypted()) {
bool keyframe = VPXDecoder::IsKeyframe(
MakeSpan<const uint8_t>(sample->Data(), sample->Size()),
VPXDecoder::Codec::VP9);
if (sample->mKeyframe != keyframe) {
NS_WARNING(nsPrintfCString(
"Frame incorrectly marked as %skeyframe "
"@ pts:%" PRId64 " dur:%" PRId64 " dts:%" PRId64,
keyframe ? "" : "non-", sample->mTime.ToMicroseconds(),
sample->mDuration.ToMicroseconds(),
sample->mTimecode.ToMicroseconds())
.get());
sample->mKeyframe = keyframe;
}
}
}
@ -491,7 +514,7 @@ RefPtr<MP4TrackDemuxer::SamplesPromise> MP4TrackDemuxer::GetSamples(
}
for (const auto& sample : samples->mSamples) {
// Collect telemetry from h264 Annex B SPS.
if (mNeedSPSForTelemetry && mIsH264 && AnnexB::IsAVCC(sample)) {
if (mNeedSPSForTelemetry && mType == kH264 && AnnexB::IsAVCC(sample)) {
RefPtr<MediaByteBuffer> extradata = H264::ExtractExtraData(sample);
if (H264::HasSPS(extradata)) {
RefPtr<MediaByteBuffer> extradata = H264::ExtractExtraData(sample);