Bug 1123498 - Make MP4Reader skip-to-next-keyframe less aggressively. r=mattwoodrow

This commit is contained in:
Chris Pearce 2015-01-20 15:20:43 +13:00
Родитель b52e9b0fd5
Коммит 8a239a32e3
6 изменённых файлов: 75 добавлений и 3 удалений

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

@ -107,7 +107,6 @@ InvokeAndRetry(ThisType* aThisVal, ReturnType(ThisType::*aMethod)(), MP4Stream*
}
}
MP4Reader::MP4Reader(AbstractMediaDecoder* aDecoder)
: MediaDecoderReader(aDecoder)
, mAudio(MediaData::AUDIO_DATA, Preferences::GetUint("media.mp4-audio-decode-ahead", 2))
@ -196,6 +195,7 @@ MP4Reader::InitLayersBackendType()
}
static bool sIsEMEEnabled = false;
static bool sDemuxSkipToNextKeyframe = true;
nsresult
MP4Reader::Init(MediaDecoderReader* aCloneDonor)
@ -217,6 +217,7 @@ MP4Reader::Init(MediaDecoderReader* aCloneDonor)
if (!sSetupPrefCache) {
sSetupPrefCache = true;
Preferences::AddBoolVarCache(&sIsEMEEnabled, "media.eme.enabled", false);
Preferences::AddBoolVarCache(&sDemuxSkipToNextKeyframe, "media.fmp4.demux-skip", true);
}
return NS_OK;
@ -519,6 +520,29 @@ MP4Reader::GetDecoderData(TrackType aTrack)
return mVideo;
}
Microseconds
MP4Reader::GetNextKeyframeTime()
{
MonitorAutoLock mon(mDemuxerMonitor);
return mDemuxer->GetNextKeyframeTime();
}
bool
MP4Reader::ShouldSkip(bool aSkipToNextKeyframe, int64_t aTimeThreshold)
{
// The MP4Reader doesn't do normal skip-to-next-keyframe if the demuxer
// has exposes where the next keyframe is. We can then instead skip only
// if the time threshold (the current playback position) is after the next
// keyframe in the stream. This means we'll only skip frames that we have
// no hope of ever playing.
Microseconds nextKeyframe = -1;
if (!sDemuxSkipToNextKeyframe ||
(nextKeyframe = GetNextKeyframeTime()) == -1) {
return aSkipToNextKeyframe;
}
return nextKeyframe < aTimeThreshold;
}
nsRefPtr<MediaDecoderReader::VideoDataPromise>
MP4Reader::RequestVideoData(bool aSkipToNextKeyframe,
int64_t aTimeThreshold)
@ -537,7 +561,7 @@ MP4Reader::RequestVideoData(bool aSkipToNextKeyframe,
MOZ_ASSERT(HasVideo() && mPlatform && mVideo.mDecoder);
bool eos = false;
if (aSkipToNextKeyframe) {
if (ShouldSkip(aSkipToNextKeyframe, aTimeThreshold)) {
uint32_t parsed = 0;
eos = !SkipVideoDemuxToNextKeyFrame(aTimeThreshold, parsed);
if (!eos && NS_FAILED(mVideo.mDecoder->Flush())) {

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

@ -121,6 +121,9 @@ private:
bool IsWaitingOnCodecResource();
virtual bool IsWaitingOnCDMResource() MOZ_OVERRIDE;
Microseconds GetNextKeyframeTime();
bool ShouldSkip(bool aSkipToNextKeyframe, int64_t aTimeThreshold);
size_t SizeOfQueue(TrackType aTrack);
nsRefPtr<MP4Stream> mStream;

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

@ -186,6 +186,31 @@ void SampleIterator::Seek(Microseconds aTime)
mCurrentSample = syncSample;
}
Microseconds
SampleIterator::GetNextKeyframeTime()
{
nsTArray<Moof>& moofs = mIndex->mMoofParser->Moofs();
size_t sample = mCurrentSample + 1;
size_t moof = mCurrentMoof;
while (true) {
while (true) {
if (moof == moofs.Length()) {
return -1;
}
if (sample < moofs[moof].mIndex.Length()) {
break;
}
sample = 0;
++moof;
}
if (moofs[moof].mIndex[sample].mSync) {
return moofs[moof].mIndex[sample].mDecodeTime;
}
++sample;
}
MOZ_ASSERT(false); // should not be reached.
}
Index::Index(const stagefright::Vector<MediaSource::Indice>& aIndex,
Stream* aSource, uint32_t aTrackId, Microseconds aTimestampOffset,
Monitor* aMonitor)

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

@ -22,6 +22,7 @@ public:
explicit SampleIterator(Index* aIndex);
MP4Sample* GetNext();
void Seek(Microseconds aTime);
Microseconds GetNextKeyframeTime();
private:
Sample* Get();

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

@ -73,6 +73,10 @@ public:
int64_t GetEvictionOffset(Microseconds aTime);
// Returns timestamp of next keyframe, or -1 if demuxer can't
// report this.
Microseconds GetNextKeyframeTime();
private:
AudioDecoderConfig mAudioConfig;
VideoDecoderConfig mVideoConfig;
@ -84,6 +88,7 @@ private:
nsTArray<Interval<Microseconds>> mCachedTimeRanges;
Microseconds mTimestampOffset;
Monitor* mMonitor;
Microseconds mNextKeyframeTime;
};
} // namespace mozilla

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

@ -75,7 +75,8 @@ private:
MP4Demuxer::MP4Demuxer(Stream* source, Microseconds aTimestampOffset, Monitor* aMonitor)
: mPrivate(new StageFrightPrivate()), mSource(source),
mTimestampOffset(aTimestampOffset), mMonitor(aMonitor)
mTimestampOffset(aTimestampOffset), mMonitor(aMonitor),
mNextKeyframeTime(-1)
{
mPrivate->mExtractor = new MPEG4Extractor(new DataSourceAdapter(source));
}
@ -248,6 +249,9 @@ MP4Demuxer::DemuxVideoSample()
sample->crypto.mode = mVideoConfig.crypto.mode;
sample->crypto.key.AppendElements(mVideoConfig.crypto.key);
}
if (sample->composition_timestamp >= mNextKeyframeTime) {
mNextKeyframeTime = mPrivate->mVideoIterator->GetNextKeyframeTime();
}
}
return sample.forget();
}
@ -333,4 +337,14 @@ MP4Demuxer::GetEvictionOffset(Microseconds aTime)
return offset == std::numeric_limits<uint64_t>::max() ? -1 : offset;
}
Microseconds
MP4Demuxer::GetNextKeyframeTime()
{
mMonitor->AssertCurrentThreadOwns();
if (!mPrivate->mVideoIterator) {
return -1;
}
return mNextKeyframeTime;
}
} // namespace mp4_demuxer