зеркало из https://github.com/mozilla/gecko-dev.git
Bug 657791 - Update seekable range handling for cueless WebMs. r=kinetik
MediaDecoder previously had 3 states within GetSeekable(), media is either seekable, seekable but not supported by transport, or not seekable. Due to changes to make cueless webms playable, a 4th option is needed: a file that is not fully seekable, but may support seeking from the transport, such as these webms, should only be seekable in the buffered range. MozReview-Commit-ID: ISeFkngtrGU
This commit is contained in:
Родитель
25356d3a7c
Коммит
939ab2b661
|
@ -2803,6 +2803,8 @@ nsresult HTMLMediaElement::InitializeDecoderAsClone(MediaDecoder* aOriginal)
|
|||
LOG(LogLevel::Debug, ("%p Cloned decoder %p from %p", this, decoder.get(), aOriginal));
|
||||
|
||||
decoder->SetMediaSeekable(aOriginal->IsMediaSeekable());
|
||||
decoder->SetMediaSeekableOnlyInBufferedRanges(
|
||||
aOriginal->IsMediaSeekableOnlyInBufferedRanges());
|
||||
|
||||
RefPtr<MediaResource> resource =
|
||||
originalResource->CloneData(decoder->GetResourceCallback());
|
||||
|
|
|
@ -70,6 +70,10 @@ public:
|
|||
// Returns true if the underlying resource allows seeking.
|
||||
virtual bool IsSeekable() const = 0;
|
||||
|
||||
// Returns true if the underlying resource can only seek within buffered
|
||||
// ranges.
|
||||
virtual bool IsSeekableOnlyInBufferedRanges() const { return false; }
|
||||
|
||||
// Returns the media's crypto information, or nullptr if media isn't
|
||||
// encrypted.
|
||||
virtual UniquePtr<EncryptionInfo> GetCrypto()
|
||||
|
|
|
@ -564,6 +564,8 @@ MediaDecoder::MediaDecoder(MediaDecoderOwner* aOwner)
|
|||
"MediaDecoder::mDecoderPosition (Canonical)")
|
||||
, mMediaSeekable(AbstractThread::MainThread(), true,
|
||||
"MediaDecoder::mMediaSeekable (Canonical)")
|
||||
, mMediaSeekableOnlyInBufferedRanges(AbstractThread::MainThread(), false,
|
||||
"MediaDecoder::mMediaSeekableOnlyInBufferedRanges (Canonical)")
|
||||
, mTelemetryReported(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(MediaDecoder);
|
||||
|
@ -875,6 +877,7 @@ MediaDecoder::MetadataLoaded(nsAutoPtr<MediaInfo> aInfo,
|
|||
aInfo->HasAudio(), aInfo->HasVideo());
|
||||
|
||||
SetMediaSeekable(aInfo->mMediaSeekable);
|
||||
SetMediaSeekableOnlyInBufferedRanges(aInfo->mMediaSeekableOnlyInBufferedRanges);
|
||||
mInfo = aInfo.forget();
|
||||
ConstructMediaTracks();
|
||||
|
||||
|
@ -1377,6 +1380,12 @@ MediaDecoder::SetMediaSeekable(bool aMediaSeekable) {
|
|||
mMediaSeekable = aMediaSeekable;
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoder::SetMediaSeekableOnlyInBufferedRanges(bool aMediaSeekableOnlyInBufferedRanges){
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mMediaSeekableOnlyInBufferedRanges = aMediaSeekableOnlyInBufferedRanges;
|
||||
}
|
||||
|
||||
bool
|
||||
MediaDecoder::IsTransportSeekable()
|
||||
{
|
||||
|
@ -1392,14 +1401,23 @@ MediaDecoder::IsMediaSeekable()
|
|||
return mMediaSeekable;
|
||||
}
|
||||
|
||||
bool
|
||||
MediaDecoder::IsMediaSeekableOnlyInBufferedRanges()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return mMediaSeekableOnlyInBufferedRanges;
|
||||
}
|
||||
|
||||
media::TimeIntervals
|
||||
MediaDecoder::GetSeekable()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
// We can seek in buffered range if the media is seekable. Also, we can seek
|
||||
// in unbuffered ranges if the transport level is seekable (local file or the
|
||||
// server supports range requests, etc.)
|
||||
if (!IsMediaSeekable()) {
|
||||
// server supports range requests, etc.) or in cue-less WebMs
|
||||
if (IsMediaSeekableOnlyInBufferedRanges()) {
|
||||
return GetBuffered();
|
||||
} else if (!IsMediaSeekable()) {
|
||||
return media::TimeIntervals();
|
||||
} else if (!IsTransportSeekable()) {
|
||||
return GetBuffered();
|
||||
|
|
|
@ -253,12 +253,17 @@ public:
|
|||
// Called from HTMLMediaElement when owner document activity changes
|
||||
virtual void SetElementVisibility(bool aIsVisible) {}
|
||||
|
||||
// Set a flag indicating whether seeking is supported
|
||||
// Set a flag indicating whether random seeking is supported
|
||||
void SetMediaSeekable(bool aMediaSeekable);
|
||||
// Set a flag indicating whether seeking is supported only in buffered ranges
|
||||
void SetMediaSeekableOnlyInBufferedRanges(bool aMediaSeekableOnlyInBufferedRanges);
|
||||
|
||||
// Returns true if this media supports seeking. False for example for WebM
|
||||
// files without an index and chained ogg files.
|
||||
// Returns true if this media supports random seeking. False for example with
|
||||
// chained ogg files.
|
||||
bool IsMediaSeekable();
|
||||
// Returns true if this media supports seeking only in buffered ranges. True
|
||||
// for example in WebMs with no cues
|
||||
bool IsMediaSeekableOnlyInBufferedRanges();
|
||||
// Returns true if seeking is supported on a transport level (e.g. the server
|
||||
// supports range requests, we are playing a file, etc.).
|
||||
bool IsTransportSeekable();
|
||||
|
@ -792,6 +797,9 @@ protected:
|
|||
// True if the media is seekable (i.e. supports random access).
|
||||
Canonical<bool> mMediaSeekable;
|
||||
|
||||
// True if the media is only seekable within its buffered ranges.
|
||||
Canonical<bool> mMediaSeekableOnlyInBufferedRanges;
|
||||
|
||||
public:
|
||||
AbstractCanonical<media::NullableTimeUnit>* CanonicalDurationOrNull() override;
|
||||
AbstractCanonical<double>* CanonicalVolume() {
|
||||
|
@ -833,6 +841,9 @@ public:
|
|||
AbstractCanonical<bool>* CanonicalMediaSeekable() {
|
||||
return &mMediaSeekable;
|
||||
}
|
||||
AbstractCanonical<bool>* CanonicalMediaSeekableOnlyInBufferedRanges() {
|
||||
return &mMediaSeekableOnlyInBufferedRanges;
|
||||
}
|
||||
|
||||
private:
|
||||
// Notify owner when the audible state changed
|
||||
|
|
|
@ -268,6 +268,8 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
|
|||
"MediaDecoderStateMachine::mDecoderPosition (Mirror)"),
|
||||
mMediaSeekable(mTaskQueue, true,
|
||||
"MediaDecoderStateMachine::mMediaSeekable (Mirror)"),
|
||||
mMediaSeekableOnlyInBufferedRanges(mTaskQueue, false,
|
||||
"MediaDecoderStateMachine::mMediaSeekableOnlyInBufferedRanges (Mirror)"),
|
||||
mDuration(mTaskQueue, NullableTimeUnit(),
|
||||
"MediaDecoderStateMachine::mDuration (Canonical"),
|
||||
mIsShutdown(mTaskQueue, false,
|
||||
|
@ -350,6 +352,7 @@ MediaDecoderStateMachine::InitializationTask(MediaDecoder* aDecoder)
|
|||
mPlaybackRateReliable.Connect(aDecoder->CanonicalPlaybackRateReliable());
|
||||
mDecoderPosition.Connect(aDecoder->CanonicalDecoderPosition());
|
||||
mMediaSeekable.Connect(aDecoder->CanonicalMediaSeekable());
|
||||
mMediaSeekableOnlyInBufferedRanges.Connect(aDecoder->CanonicalMediaSeekableOnlyInBufferedRanges());
|
||||
|
||||
// Initialize watchers.
|
||||
mWatchManager.Watch(mBuffered, &MediaDecoderStateMachine::BufferedRangeUpdated);
|
||||
|
@ -1474,9 +1477,8 @@ MediaDecoderStateMachine::Seek(SeekTarget aTarget)
|
|||
return MediaDecoder::SeekPromise::CreateAndReject(/* aIgnored = */ true, __func__);
|
||||
}
|
||||
|
||||
// We need to be able to seek both at a transport level and at a media level
|
||||
// to seek.
|
||||
if (!mMediaSeekable) {
|
||||
// We need to be able to seek in some way
|
||||
if (!mMediaSeekable && !mMediaSeekableOnlyInBufferedRanges) {
|
||||
DECODER_WARN("Seek() function should not be called on a non-seekable state machine");
|
||||
return MediaDecoder::SeekPromise::CreateAndReject(/* aIgnored = */ true, __func__);
|
||||
}
|
||||
|
@ -2192,6 +2194,7 @@ MediaDecoderStateMachine::FinishShutdown()
|
|||
mPlaybackRateReliable.DisconnectIfConnected();
|
||||
mDecoderPosition.DisconnectIfConnected();
|
||||
mMediaSeekable.DisconnectIfConnected();
|
||||
mMediaSeekableOnlyInBufferedRanges.DisconnectIfConnected();
|
||||
|
||||
mDuration.DisconnectAll();
|
||||
mIsShutdown.DisconnectAll();
|
||||
|
|
|
@ -1239,6 +1239,9 @@ private:
|
|||
// True if the media is seekable (i.e. supports random access).
|
||||
Mirror<bool> mMediaSeekable;
|
||||
|
||||
// True if the media is seekable only in buffered ranges.
|
||||
Mirror<bool> mMediaSeekableOnlyInBufferedRanges;
|
||||
|
||||
// Duration of the media. This is guaranteed to be non-null after we finish
|
||||
// decoding the first frame.
|
||||
Canonical<media::NullableTimeUnit> mDuration;
|
||||
|
|
|
@ -337,6 +337,8 @@ MediaFormatReader::OnDemuxerInitDone(nsresult)
|
|||
}
|
||||
|
||||
mInfo.mMediaSeekable = mDemuxer->IsSeekable();
|
||||
mInfo.mMediaSeekableOnlyInBufferedRanges =
|
||||
mDemuxer->IsSeekableOnlyInBufferedRanges();
|
||||
|
||||
if (!videoActive && !audioActive) {
|
||||
mMetadataPromise.Reject(ReadMetadataFailureReason::METADATA_ERROR, __func__);
|
||||
|
@ -1428,7 +1430,7 @@ MediaFormatReader::Seek(SeekTarget aTarget, int64_t aUnused)
|
|||
MOZ_DIAGNOSTIC_ASSERT(mVideo.mTimeThreshold.isNothing());
|
||||
MOZ_DIAGNOSTIC_ASSERT(mAudio.mTimeThreshold.isNothing());
|
||||
|
||||
if (!mInfo.mMediaSeekable) {
|
||||
if (!mInfo.mMediaSeekable && !mInfo.mMediaSeekableOnlyInBufferedRanges) {
|
||||
LOG("Seek() END (Unseekable)");
|
||||
return SeekPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
|
||||
}
|
||||
|
|
|
@ -417,6 +417,9 @@ public:
|
|||
// True if the media is seekable (i.e. supports random access).
|
||||
bool mMediaSeekable = true;
|
||||
|
||||
// True if the media is only seekable within its buffered ranges.
|
||||
bool mMediaSeekableOnlyInBufferedRanges = false;
|
||||
|
||||
EncryptionInfo mCrypto;
|
||||
};
|
||||
|
||||
|
|
|
@ -431,7 +431,13 @@ WebMDemuxer::ReadMetadata()
|
|||
bool
|
||||
WebMDemuxer::IsSeekable() const
|
||||
{
|
||||
return mContext;
|
||||
return mContext && nestegg_has_cues(mContext);
|
||||
}
|
||||
|
||||
bool
|
||||
WebMDemuxer::IsSeekableOnlyInBufferedRanges() const
|
||||
{
|
||||
return mContext && !nestegg_has_cues(mContext);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -98,6 +98,8 @@ public:
|
|||
|
||||
bool IsSeekable() const override;
|
||||
|
||||
bool IsSeekableOnlyInBufferedRanges() const override;
|
||||
|
||||
UniquePtr<EncryptionInfo> GetCrypto() override;
|
||||
|
||||
bool GetOffsetForTime(uint64_t aTime, int64_t* aOffset);
|
||||
|
|
Загрузка…
Ссылка в новой задаче