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:
Bryce Van Dyk 2016-02-04 17:31:21 +13:00
Родитель 25356d3a7c
Коммит 939ab2b661
10 изменённых файлов: 64 добавлений и 10 удалений

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

@ -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);