mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-21 07:47:32 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
361
dom/media/mediasource/MediaSourceDecoder.cpp
Normal file
361
dom/media/mediasource/MediaSourceDecoder.cpp
Normal file
|
|
@ -0,0 +1,361 @@
|
|||
/* -*- mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "MediaSourceDecoder.h"
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/dom/HTMLMediaElement.h"
|
||||
#include "MediaDecoderStateMachine.h"
|
||||
#include "MediaShutdownManager.h"
|
||||
#include "MediaSource.h"
|
||||
#include "MediaSourceResource.h"
|
||||
#include "MediaSourceUtils.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "MediaSourceDemuxer.h"
|
||||
#include "SourceBufferList.h"
|
||||
#include <algorithm>
|
||||
|
||||
extern mozilla::LogModule* GetMediaSourceLog();
|
||||
|
||||
#define MSE_DEBUG(arg, ...) MOZ_LOG(GetMediaSourceLog(), mozilla::LogLevel::Debug, ("MediaSourceDecoder(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
|
||||
#define MSE_DEBUGV(arg, ...) MOZ_LOG(GetMediaSourceLog(), mozilla::LogLevel::Verbose, ("MediaSourceDecoder(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
|
||||
|
||||
using namespace mozilla::media;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
MediaSourceDecoder::MediaSourceDecoder(dom::HTMLMediaElement* aElement)
|
||||
: MediaDecoder(aElement)
|
||||
, mMediaSource(nullptr)
|
||||
, mEnded(false)
|
||||
{
|
||||
mExplicitDuration.Set(Some(UnspecifiedNaN<double>()));
|
||||
}
|
||||
|
||||
MediaDecoder*
|
||||
MediaSourceDecoder::Clone(MediaDecoderOwner* aOwner)
|
||||
{
|
||||
// TODO: Sort out cloning.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MediaDecoderStateMachine*
|
||||
MediaSourceDecoder::CreateStateMachine()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mDemuxer = new MediaSourceDemuxer();
|
||||
mReader = new MediaFormatReader(this, mDemuxer, GetVideoFrameContainer());
|
||||
return new MediaDecoderStateMachine(this, mReader);
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaSourceDecoder::Load(nsIStreamListener**)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!GetStateMachine());
|
||||
|
||||
nsresult rv = MediaShutdownManager::Instance().Register(this);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
SetStateMachine(CreateStateMachine());
|
||||
if (!GetStateMachine()) {
|
||||
NS_WARNING("Failed to create state machine!");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
rv = GetStateMachine()->Init(this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
SetStateMachineParameters();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
media::TimeIntervals
|
||||
MediaSourceDecoder::GetSeekable()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (!mMediaSource) {
|
||||
NS_WARNING("MediaSource element isn't attached");
|
||||
return media::TimeIntervals::Invalid();
|
||||
}
|
||||
|
||||
media::TimeIntervals seekable;
|
||||
double duration = mMediaSource->Duration();
|
||||
if (IsNaN(duration)) {
|
||||
// Return empty range.
|
||||
} else if (duration > 0 && mozilla::IsInfinite(duration)) {
|
||||
media::TimeIntervals buffered = GetBuffered();
|
||||
|
||||
// 1. If live seekable range is not empty:
|
||||
if (mMediaSource->HasLiveSeekableRange()) {
|
||||
// 1. Let union ranges be the union of live seekable range and the
|
||||
// HTMLMediaElement.buffered attribute.
|
||||
media::TimeIntervals unionRanges =
|
||||
buffered + mMediaSource->LiveSeekableRange();
|
||||
// 2. Return a single range with a start time equal to the earliest start
|
||||
// time in union ranges and an end time equal to the highest end time in
|
||||
// union ranges and abort these steps.
|
||||
seekable +=
|
||||
media::TimeInterval(unionRanges.GetStart(), unionRanges.GetEnd());
|
||||
return seekable;
|
||||
}
|
||||
|
||||
if (buffered.Length()) {
|
||||
seekable +=
|
||||
media::TimeInterval(media::TimeUnit::FromSeconds(0), buffered.GetEnd());
|
||||
}
|
||||
} else {
|
||||
seekable += media::TimeInterval(media::TimeUnit::FromSeconds(0),
|
||||
media::TimeUnit::FromSeconds(duration));
|
||||
}
|
||||
MSE_DEBUG("ranges=%s", DumpTimeRanges(seekable).get());
|
||||
return seekable;
|
||||
}
|
||||
|
||||
media::TimeIntervals
|
||||
MediaSourceDecoder::GetBuffered()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!mMediaSource) {
|
||||
NS_WARNING("MediaSource element isn't attached");
|
||||
return media::TimeIntervals::Invalid();
|
||||
}
|
||||
dom::SourceBufferList* sourceBuffers = mMediaSource->ActiveSourceBuffers();
|
||||
if (!sourceBuffers) {
|
||||
// Media source object is shutting down.
|
||||
return TimeIntervals();
|
||||
}
|
||||
media::TimeUnit highestEndTime;
|
||||
nsTArray<media::TimeIntervals> activeRanges;
|
||||
media::TimeIntervals buffered;
|
||||
|
||||
for (uint32_t i = 0; i < sourceBuffers->Length(); i++) {
|
||||
bool found;
|
||||
dom::SourceBuffer* sb = sourceBuffers->IndexedGetter(i, found);
|
||||
MOZ_ASSERT(found);
|
||||
|
||||
activeRanges.AppendElement(sb->GetTimeIntervals());
|
||||
highestEndTime =
|
||||
std::max(highestEndTime, activeRanges.LastElement().GetEnd());
|
||||
}
|
||||
|
||||
buffered +=
|
||||
media::TimeInterval(media::TimeUnit::FromMicroseconds(0), highestEndTime);
|
||||
|
||||
for (auto& range : activeRanges) {
|
||||
if (mEnded && range.Length()) {
|
||||
// Set the end time on the last range to highestEndTime by adding a
|
||||
// new range spanning the current end time to highestEndTime, which
|
||||
// Normalize() will then merge with the old last range.
|
||||
range +=
|
||||
media::TimeInterval(range.GetEnd(), highestEndTime);
|
||||
}
|
||||
buffered.Intersection(range);
|
||||
}
|
||||
|
||||
MSE_DEBUG("ranges=%s", DumpTimeRanges(buffered).get());
|
||||
return buffered;
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceDecoder::Shutdown()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MSE_DEBUG("Shutdown");
|
||||
// Detach first so that TrackBuffers are unused on the main thread when
|
||||
// shut down on the decode task queue.
|
||||
if (mMediaSource) {
|
||||
mMediaSource->Detach();
|
||||
}
|
||||
mDemuxer = nullptr;
|
||||
|
||||
MediaDecoder::Shutdown();
|
||||
}
|
||||
|
||||
/*static*/
|
||||
already_AddRefed<MediaResource>
|
||||
MediaSourceDecoder::CreateResource(nsIPrincipal* aPrincipal)
|
||||
{
|
||||
return RefPtr<MediaResource>(new MediaSourceResource(aPrincipal)).forget();
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceDecoder::AttachMediaSource(dom::MediaSource* aMediaSource)
|
||||
{
|
||||
MOZ_ASSERT(!mMediaSource && !GetStateMachine() && NS_IsMainThread());
|
||||
mMediaSource = aMediaSource;
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceDecoder::DetachMediaSource()
|
||||
{
|
||||
MOZ_ASSERT(mMediaSource && NS_IsMainThread());
|
||||
mMediaSource = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceDecoder::Ended(bool aEnded)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
static_cast<MediaSourceResource*>(GetResource())->SetEnded(aEnded);
|
||||
if (aEnded) {
|
||||
// We want the MediaSourceReader to refresh its buffered range as it may
|
||||
// have been modified (end lined up).
|
||||
NotifyDataArrived();
|
||||
}
|
||||
mEnded = aEnded;
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceDecoder::AddSizeOfResources(ResourceSizes* aSizes)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (GetDemuxer()) {
|
||||
GetDemuxer()->AddSizeOfResources(aSizes);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceDecoder::SetInitialDuration(int64_t aDuration)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
// Only use the decoded duration if one wasn't already
|
||||
// set.
|
||||
if (!mMediaSource || !IsNaN(ExplicitDuration())) {
|
||||
return;
|
||||
}
|
||||
double duration = aDuration;
|
||||
// A duration of -1 is +Infinity.
|
||||
if (aDuration >= 0) {
|
||||
duration /= USECS_PER_S;
|
||||
}
|
||||
SetMediaSourceDuration(duration);
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceDecoder::SetMediaSourceDuration(double aDuration)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!IsShutdown());
|
||||
if (aDuration >= 0) {
|
||||
int64_t checkedDuration;
|
||||
if (NS_FAILED(SecondsToUsecs(aDuration, checkedDuration))) {
|
||||
// INT64_MAX is used as infinity by the state machine.
|
||||
// We want a very bigger number, but not infinity.
|
||||
checkedDuration = INT64_MAX - 1;
|
||||
}
|
||||
SetExplicitDuration(aDuration);
|
||||
} else {
|
||||
SetExplicitDuration(PositiveInfinity<double>());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceDecoder::GetMozDebugReaderData(nsAString& aString)
|
||||
{
|
||||
if (mReader && mDemuxer) {
|
||||
mReader->GetMozDebugReaderData(aString);
|
||||
mDemuxer->GetMozDebugReaderData(aString);
|
||||
}
|
||||
}
|
||||
|
||||
double
|
||||
MediaSourceDecoder::GetDuration()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return ExplicitDuration();
|
||||
}
|
||||
|
||||
MediaDecoderOwner::NextFrameStatus
|
||||
MediaSourceDecoder::NextFrameBufferedStatus()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!mMediaSource ||
|
||||
mMediaSource->ReadyState() == dom::MediaSourceReadyState::Closed) {
|
||||
return MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE;
|
||||
}
|
||||
|
||||
// Next frame hasn't been decoded yet.
|
||||
// Use the buffered range to consider if we have the next frame available.
|
||||
TimeUnit currentPosition = TimeUnit::FromMicroseconds(CurrentPosition());
|
||||
TimeIntervals buffered = GetBuffered();
|
||||
buffered.SetFuzz(MediaSourceDemuxer::EOS_FUZZ / 2);
|
||||
TimeInterval interval(
|
||||
currentPosition,
|
||||
currentPosition
|
||||
+ media::TimeUnit::FromMicroseconds(DEFAULT_NEXT_FRAME_AVAILABLE_BUFFERED));
|
||||
return buffered.ContainsStrict(ClampIntervalToEnd(interval))
|
||||
? MediaDecoderOwner::NEXT_FRAME_AVAILABLE
|
||||
: MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE;
|
||||
}
|
||||
|
||||
bool
|
||||
MediaSourceDecoder::CanPlayThrough()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (NextFrameBufferedStatus() == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsNaN(mMediaSource->Duration())) {
|
||||
// Don't have any data yet.
|
||||
return false;
|
||||
}
|
||||
TimeUnit duration = TimeUnit::FromSeconds(mMediaSource->Duration());
|
||||
TimeUnit currentPosition = TimeUnit::FromMicroseconds(CurrentPosition());
|
||||
if (duration.IsInfinite()) {
|
||||
// We can't make an informed decision and just assume that it's a live stream
|
||||
return true;
|
||||
} else if (duration <= currentPosition) {
|
||||
return true;
|
||||
}
|
||||
// If we have data up to the mediasource's duration or 30s ahead, we can
|
||||
// assume that we can play without interruption.
|
||||
TimeIntervals buffered = GetBuffered();
|
||||
buffered.SetFuzz(MediaSourceDemuxer::EOS_FUZZ / 2);
|
||||
TimeUnit timeAhead =
|
||||
std::min(duration, currentPosition + TimeUnit::FromSeconds(30));
|
||||
TimeInterval interval(currentPosition, timeAhead);
|
||||
return buffered.ContainsStrict(ClampIntervalToEnd(interval));
|
||||
}
|
||||
|
||||
void
|
||||
MediaSourceDecoder::NotifyWaitingForKey()
|
||||
{
|
||||
mWaitingForKeyEvent.Notify();
|
||||
}
|
||||
|
||||
MediaEventSource<void>*
|
||||
MediaSourceDecoder::WaitingForKeyEvent()
|
||||
{
|
||||
return &mWaitingForKeyEvent;
|
||||
}
|
||||
|
||||
TimeInterval
|
||||
MediaSourceDecoder::ClampIntervalToEnd(const TimeInterval& aInterval)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!mEnded) {
|
||||
return aInterval;
|
||||
}
|
||||
TimeUnit duration = TimeUnit::FromSeconds(GetDuration());
|
||||
if (duration < aInterval.mStart) {
|
||||
return aInterval;
|
||||
}
|
||||
return TimeInterval(aInterval.mStart,
|
||||
std::min(aInterval.mEnd, duration),
|
||||
aInterval.mFuzz);
|
||||
}
|
||||
|
||||
#undef MSE_DEBUG
|
||||
#undef MSE_DEBUGV
|
||||
|
||||
} // namespace mozilla
|
||||
Loading…
Add table
Add a link
Reference in a new issue