--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -498,17 +498,17 @@ MediaFormatReader::ShouldSkip(bool aSkip
MOZ_ASSERT(HasVideo());
media::TimeUnit nextKeyframe;
nsresult rv = mVideo.mTrackDemuxer->GetNextRandomAccessPoint(&nextKeyframe);
if (NS_FAILED(rv)) {
return aSkipToNextKeyframe;
}
return (nextKeyframe < aTimeThreshold ||
(mVideo.mTimeThreshold &&
- mVideo.mTimeThreshold.ref().mTime < aTimeThreshold)) &&
+ mVideo.mTimeThreshold.ref().EndTime() < aTimeThreshold)) &&
nextKeyframe.ToMicroseconds() >= 0 && !nextKeyframe.IsInfinite();
}
RefPtr<MediaDecoderReader::MediaDataPromise>
MediaFormatReader::RequestVideoData(bool aSkipToNextKeyframe,
int64_t aTimeThreshold)
{
MOZ_ASSERT(OnTaskQueue());
@@ -966,20 +966,23 @@ MediaFormatReader::HandleDemuxedSamples(
// Reset will clear our array of queued samples. So make a copy now.
nsTArray<RefPtr<MediaRawData>> samples{decoder.mQueuedSamples};
Reset(aTrack);
decoder.ShutdownDecoder();
if (sample->mKeyframe) {
decoder.mQueuedSamples.AppendElements(Move(samples));
NotifyDecodingRequested(aTrack);
} else {
+ TimeInterval time =
+ TimeInterval(TimeUnit::FromMicroseconds(sample->mTime),
+ TimeUnit::FromMicroseconds(sample->GetEndTime()));
InternalSeekTarget seekTarget =
- decoder.mTimeThreshold.refOr(InternalSeekTarget(TimeUnit::FromMicroseconds(sample->mTime), false));
+ decoder.mTimeThreshold.refOr(InternalSeekTarget(time, false));
LOG("Stream change occurred on a non-keyframe. Seeking to:%lld",
- seekTarget.mTime.ToMicroseconds());
+ sample->mTime);
InternalSeek(aTrack, seekTarget);
}
return;
}
LOGV("Input:%lld (dts:%lld kf:%d)",
sample->mTime, sample->mTimecode, sample->mKeyframe);
decoder.mOutputRequested = true;
@@ -1009,24 +1012,24 @@ MediaFormatReader::HandleDemuxedSamples(
decoder.mInputExhausted = false;
}
void
MediaFormatReader::InternalSeek(TrackType aTrack, const InternalSeekTarget& aTarget)
{
MOZ_ASSERT(OnTaskQueue());
LOG("%s internal seek to %f",
- TrackTypeToStr(aTrack), aTarget.mTime.ToSeconds());
+ TrackTypeToStr(aTrack), aTarget.Time().ToSeconds());
auto& decoder = GetDecoderData(aTrack);
decoder.Flush();
decoder.ResetDemuxer();
decoder.mTimeThreshold = Some(aTarget);
RefPtr<MediaFormatReader> self = this;
- decoder.mSeekRequest.Begin(decoder.mTrackDemuxer->Seek(decoder.mTimeThreshold.ref().mTime)
+ decoder.mSeekRequest.Begin(decoder.mTrackDemuxer->Seek(decoder.mTimeThreshold.ref().Time())
->Then(OwnerThread(), __func__,
[self, aTrack] (media::TimeUnit aTime) {
auto& decoder = self->GetDecoderData(aTrack);
decoder.mSeekRequest.Complete();
MOZ_ASSERT(decoder.mTimeThreshold,
"Seek promise must be disconnected when timethreshold is reset");
decoder.mTimeThreshold.ref().mHasSeeked = true;
self->NotifyDecodingRequested(aTrack);
@@ -1116,25 +1119,25 @@ MediaFormatReader::Update(TrackType aTra
// stats counters using the AutoNotifyDecoded stack-based class.
AbstractMediaDecoder::AutoNotifyDecoded a(mDecoder);
// Drop any frames found prior our internal seek target.
while (decoder.mTimeThreshold && decoder.mOutput.Length()) {
RefPtr<MediaData>& output = decoder.mOutput[0];
InternalSeekTarget target = decoder.mTimeThreshold.ref();
media::TimeUnit time = media::TimeUnit::FromMicroseconds(output->mTime);
- if (time >= target.mTime) {
+ if (time >= target.Time()) {
// We have reached our internal seek target.
decoder.mTimeThreshold.reset();
}
- if (time < target.mTime || (target.mDropTarget && time == target.mTime)) {
+ if (time < target.Time() || (target.mDropTarget && target.Contains(time))) {
LOGV("Internal Seeking: Dropping %s frame time:%f wanted:%f (kf:%d)",
TrackTypeToStr(aTrack),
media::TimeUnit::FromMicroseconds(output->mTime).ToSeconds(),
- target.mTime.ToSeconds(),
+ target.Time().ToSeconds(),
output->mKeyframe);
decoder.mOutput.RemoveElementAt(0);
}
}
if (decoder.HasPromise()) {
needOutput = true;
if (decoder.mOutput.Length()) {
@@ -1147,17 +1150,18 @@ MediaFormatReader::Update(TrackType aTra
nsCString error;
mVideo.mIsHardwareAccelerated =
mVideo.mDecoder && mVideo.mDecoder->IsHardwareAccelerated(error);
}
RefPtr<MediaData> output = decoder.mOutput[0];
decoder.mOutput.RemoveElementAt(0);
decoder.mSizeOfQueue -= 1;
decoder.mLastSampleTime =
- Some(media::TimeUnit::FromMicroseconds(output->mTime));
+ Some(TimeInterval(TimeUnit::FromMicroseconds(output->mTime),
+ TimeUnit::FromMicroseconds(output->GetEndTime())));
ReturnOutput(output, aTrack);
} else if (decoder.mError) {
LOG("Rejecting %s promise: DECODE_ERROR", TrackTypeToStr(aTrack));
decoder.RejectPromise(DECODE_ERROR, __func__);
return;
} else if (decoder.mDrainComplete) {
bool wasDraining = decoder.mDraining;
decoder.mDrainComplete = false;
@@ -1167,17 +1171,17 @@ MediaFormatReader::Update(TrackType aTra
decoder.RejectPromise(END_OF_STREAM, __func__);
} else if (decoder.mWaitingForData) {
if (wasDraining && decoder.mLastSampleTime &&
!decoder.mNextStreamSourceID) {
// We have completed draining the decoder following WaitingForData.
// Set up the internal seek machinery to be able to resume from the
// last sample decoded.
LOG("Seeking to last sample time: %lld",
- decoder.mLastSampleTime.ref().ToMicroseconds());
+ decoder.mLastSampleTime.ref().mStart.ToMicroseconds());
InternalSeek(aTrack, InternalSeekTarget(decoder.mLastSampleTime.ref(), true));
}
if (!decoder.mReceivedNewData) {
LOG("Rejecting %s promise: WAITING_FOR_DATA", TrackTypeToStr(aTrack));
decoder.RejectPromise(WAITING_FOR_DATA, __func__);
}
}
// Now that draining has completed, we check if we have received
@@ -1814,17 +1818,17 @@ MediaFormatReader::GetMozDebugReaderData
if (HasAudio()) {
result += nsPrintfCString("audio state: ni=%d no=%d ie=%d demuxr:%d demuxq:%d decoder:%d tt:%f tths:%d in:%llu out:%llu qs=%u pending:%u waiting:%d sid:%u\n",
NeedInput(mAudio), mAudio.HasPromise(),
mAudio.mInputExhausted,
mAudio.mDemuxRequest.Exists(),
int(mAudio.mQueuedSamples.Length()),
mAudio.mDecodingRequested,
mAudio.mTimeThreshold
- ? mAudio.mTimeThreshold.ref().mTime.ToSeconds()
+ ? mAudio.mTimeThreshold.ref().Time().ToSeconds()
: -1.0,
mAudio.mTimeThreshold
? mAudio.mTimeThreshold.ref().mHasSeeked
: -1,
mAudio.mNumSamplesInput, mAudio.mNumSamplesOutput,
unsigned(size_t(mAudio.mSizeOfQueue)),
unsigned(mAudio.mOutput.Length()),
mAudio.mWaitingForData, mAudio.mLastStreamSourceID);
@@ -1838,17 +1842,17 @@ MediaFormatReader::GetMozDebugReaderData
if (HasVideo()) {
result += nsPrintfCString("video state: ni=%d no=%d ie=%d demuxr:%d demuxq:%d decoder:%d tt:%f tths:%d in:%llu out:%llu qs=%u pending:%u waiting:%d sid:%u\n",
NeedInput(mVideo), mVideo.HasPromise(),
mVideo.mInputExhausted,
mVideo.mDemuxRequest.Exists(),
int(mVideo.mQueuedSamples.Length()),
mVideo.mDecodingRequested,
mVideo.mTimeThreshold
- ? mVideo.mTimeThreshold.ref().mTime.ToSeconds()
+ ? mVideo.mTimeThreshold.ref().Time().ToSeconds()
: -1.0,
mVideo.mTimeThreshold
? mVideo.mTimeThreshold.ref().mHasSeeked
: -1,
mVideo.mNumSamplesInput, mVideo.mNumSamplesOutput,
unsigned(size_t(mVideo.mSizeOfQueue)),
unsigned(mVideo.mOutput.Length()),
mVideo.mWaitingForData, mVideo.mLastStreamSourceID);
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -128,24 +128,31 @@ private:
// Handle demuxed samples by the input behavior.
void HandleDemuxedSamples(TrackType aTrack,
AbstractMediaDecoder::AutoNotifyDecoded& aA);
// Decode any pending already demuxed samples.
bool DecodeDemuxedSamples(TrackType aTrack,
MediaRawData* aSample);
struct InternalSeekTarget {
- InternalSeekTarget(const media::TimeUnit& aTime, bool aDropTarget)
+ InternalSeekTarget(const media::TimeInterval& aTime, bool aDropTarget)
: mTime(aTime)
, mDropTarget(aDropTarget)
, mWaiting(false)
, mHasSeeked(false)
{}
- media::TimeUnit mTime;
+ media::TimeUnit Time() const { return mTime.mStart; }
+ media::TimeUnit EndTime() const { return mTime.mEnd; }
+ bool Contains(const media::TimeUnit& aTime) const
+ {
+ return mTime.Contains(aTime);
+ }
+
+ media::TimeInterval mTime;
bool mDropTarget;
bool mWaiting;
bool mHasSeeked;
};
// Perform an internal seek to aTime. If aDropTarget is true then
// the first sample past the target will be dropped.
void InternalSeek(TrackType aTrack, const InternalSeekTarget& aTarget);
@@ -303,17 +310,17 @@ private:
bool mNeedDraining;
bool mDraining;
bool mDrainComplete;
// If set, all decoded samples prior mTimeThreshold will be dropped.
// Used for internal seeking when a change of stream is detected or when
// encountering data discontinuity.
Maybe<InternalSeekTarget> mTimeThreshold;
// Time of last sample returned.
- Maybe<media::TimeUnit> mLastSampleTime;
+ Maybe<media::TimeInterval> mLastSampleTime;
// Decoded samples returned my mDecoder awaiting being returned to
// state machine upon request.
nsTArray<RefPtr<MediaData>> mOutput;
uint64_t mNumSamplesInput;
uint64_t mNumSamplesOutput;
uint64_t mNumSamplesOutputTotal;
uint64_t mNumSamplesSkippedTotal;