blob: c625457afc1663adfc4621d26c261bbd295c54cc [file] [log] [blame]
/*
* Copyright (C) 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "config.h"
#import "MediaSourcePrivateAVFObjC.h"
#if ENABLE(MEDIA_SOURCE) && USE(AVFOUNDATION)
#import "CDMInstance.h"
#import "CDMSessionMediaSourceAVFObjC.h"
#import "ContentType.h"
#import "Logging.h"
#import "MediaPlayerPrivateMediaSourceAVFObjC.h"
#import "MediaSourcePrivateClient.h"
#import "SourceBufferParserAVFObjC.h"
#import "SourceBufferPrivateAVFObjC.h"
#import <objc/runtime.h>
#import <wtf/Algorithms.h>
#import <wtf/SoftLinking.h>
#import <wtf/text/AtomString.h>
namespace WebCore {
#pragma mark -
#pragma mark MediaSourcePrivateAVFObjC
Ref<MediaSourcePrivateAVFObjC> MediaSourcePrivateAVFObjC::create(MediaPlayerPrivateMediaSourceAVFObjC& parent, MediaSourcePrivateClient& client)
{
auto mediaSourcePrivate = adoptRef(*new MediaSourcePrivateAVFObjC(parent, client));
client.setPrivateAndOpen(mediaSourcePrivate.copyRef());
return mediaSourcePrivate;
}
MediaSourcePrivateAVFObjC::MediaSourcePrivateAVFObjC(MediaPlayerPrivateMediaSourceAVFObjC& parent, MediaSourcePrivateClient& client)
: m_player(parent)
, m_client(client)
, m_isEnded(false)
#if !RELEASE_LOG_DISABLED
, m_logger(m_player->mediaPlayerLogger())
, m_logIdentifier(m_player->mediaPlayerLogIdentifier())
#endif
{
ALWAYS_LOG(LOGIDENTIFIER);
#if !RELEASE_LOG_DISABLED
client.setLogIdentifier(m_logIdentifier);
#endif
}
MediaSourcePrivateAVFObjC::~MediaSourcePrivateAVFObjC()
{
ALWAYS_LOG(LOGIDENTIFIER);
for (auto it = m_sourceBuffers.begin(), end = m_sourceBuffers.end(); it != end; ++it)
(*it)->clearMediaSource();
}
MediaSourcePrivate::AddStatus MediaSourcePrivateAVFObjC::addSourceBuffer(const ContentType& contentType, bool webMParserEnabled, RefPtr<SourceBufferPrivate>& outPrivate)
{
DEBUG_LOG(LOGIDENTIFIER, contentType);
MediaEngineSupportParameters parameters;
parameters.isMediaSource = true;
parameters.type = contentType;
if (MediaPlayerPrivateMediaSourceAVFObjC::supportsTypeAndCodecs(parameters) == MediaPlayer::SupportsType::IsNotSupported)
return AddStatus::NotSupported;
auto parser = SourceBufferParser::create(contentType, webMParserEnabled);
if (!parser)
return AddStatus::NotSupported;
auto newSourceBuffer = SourceBufferPrivateAVFObjC::create(this, parser.releaseNonNull());
#if ENABLE(ENCRYPTED_MEDIA)
newSourceBuffer->setCDMInstance(m_cdmInstance.get());
#endif
outPrivate = newSourceBuffer.copyRef();
m_sourceBuffers.append(WTFMove(newSourceBuffer));
return AddStatus::Ok;
}
void MediaSourcePrivateAVFObjC::removeSourceBuffer(SourceBufferPrivate* buffer)
{
ASSERT(m_sourceBuffers.contains(buffer));
if (buffer == m_sourceBufferWithSelectedVideo)
m_sourceBufferWithSelectedVideo = nullptr;
size_t pos = m_activeSourceBuffers.find(buffer);
if (pos != notFound) {
m_activeSourceBuffers.remove(pos);
if (m_player)
m_player->notifyActiveSourceBuffersChanged();
}
pos = m_sourceBuffers.find(buffer);
m_sourceBuffers[pos]->clearMediaSource();
m_sourceBuffers.remove(pos);
}
MediaTime MediaSourcePrivateAVFObjC::duration() const
{
if (m_client)
return m_client->duration();
return MediaTime::invalidTime();
}
std::unique_ptr<PlatformTimeRanges> MediaSourcePrivateAVFObjC::buffered()
{
if (m_client)
return m_client->buffered();
return nullptr;
}
void MediaSourcePrivateAVFObjC::durationChanged(const MediaTime&)
{
if (m_player)
m_player->durationChanged();
}
void MediaSourcePrivateAVFObjC::markEndOfStream(EndOfStreamStatus status)
{
if (status == EosNoError && m_player)
m_player->setNetworkState(MediaPlayer::NetworkState::Loaded);
m_isEnded = true;
}
void MediaSourcePrivateAVFObjC::unmarkEndOfStream()
{
// FIXME(125159): implement unmarkEndOfStream()
m_isEnded = false;
}
MediaPlayer::ReadyState MediaSourcePrivateAVFObjC::readyState() const
{
return m_player ? m_player->readyState() : MediaPlayer::ReadyState::HaveNothing;
}
void MediaSourcePrivateAVFObjC::setReadyState(MediaPlayer::ReadyState readyState)
{
if (m_player)
m_player->setReadyState(readyState);
}
void MediaSourcePrivateAVFObjC::waitForSeekCompleted()
{
if (m_player)
m_player->waitForSeekCompleted();
}
void MediaSourcePrivateAVFObjC::seekCompleted()
{
if (m_player)
m_player->seekCompleted();
}
MediaTime MediaSourcePrivateAVFObjC::currentMediaTime() const
{
return m_player ? m_player->currentMediaTime() : MediaTime::invalidTime();
}
void MediaSourcePrivateAVFObjC::sourceBufferPrivateDidChangeActiveState(SourceBufferPrivateAVFObjC* buffer, bool active)
{
if (active && !m_activeSourceBuffers.contains(buffer)) {
m_activeSourceBuffers.append(buffer);
if (m_player)
m_player->notifyActiveSourceBuffersChanged();
}
if (!active) {
size_t position = m_activeSourceBuffers.find(buffer);
if (position != notFound) {
m_activeSourceBuffers.remove(position);
if (m_player)
m_player->notifyActiveSourceBuffersChanged();
}
}
}
#if ENABLE(LEGACY_ENCRYPTED_MEDIA)
void MediaSourcePrivateAVFObjC::sourceBufferKeyNeeded(SourceBufferPrivateAVFObjC* buffer, const SharedBuffer& initData)
{
m_sourceBuffersNeedingSessions.append(buffer);
if (m_player)
m_player->keyNeeded(initData);
}
#endif
static bool MediaSourcePrivateAVFObjCHasAudio(SourceBufferPrivateAVFObjC* sourceBuffer)
{
return sourceBuffer->hasAudio();
}
bool MediaSourcePrivateAVFObjC::hasAudio() const
{
return std::any_of(m_activeSourceBuffers.begin(), m_activeSourceBuffers.end(), MediaSourcePrivateAVFObjCHasAudio);
}
bool MediaSourcePrivateAVFObjC::hasVideo() const
{
return std::any_of(m_activeSourceBuffers.begin(), m_activeSourceBuffers.end(), [] (SourceBufferPrivateAVFObjC* sourceBuffer) {
return sourceBuffer->hasVideo();
});
}
bool MediaSourcePrivateAVFObjC::hasSelectedVideo() const
{
return std::any_of(m_activeSourceBuffers.begin(), m_activeSourceBuffers.end(), [] (SourceBufferPrivateAVFObjC* sourceBuffer) {
return sourceBuffer->hasSelectedVideo();
});
}
void MediaSourcePrivateAVFObjC::willSeek()
{
for (auto* sourceBuffer : m_activeSourceBuffers)
sourceBuffer->willSeek();
}
void MediaSourcePrivateAVFObjC::seekToTime(const MediaTime& time)
{
if (m_client)
m_client->seekToTime(time);
}
MediaTime MediaSourcePrivateAVFObjC::fastSeekTimeForMediaTime(const MediaTime& targetTime, const MediaTime& negativeThreshold, const MediaTime& positiveThreshold)
{
MediaTime seekTime = targetTime;
for (auto it = m_activeSourceBuffers.begin(), end = m_activeSourceBuffers.end(); it != end; ++it) {
MediaTime sourceSeekTime = (*it)->fastSeekTimeForMediaTime(targetTime, negativeThreshold, positiveThreshold);
if (abs(targetTime - sourceSeekTime) > abs(targetTime - seekTime))
seekTime = sourceSeekTime;
}
return seekTime;
}
FloatSize MediaSourcePrivateAVFObjC::naturalSize() const
{
FloatSize result;
for (auto* sourceBuffer : m_activeSourceBuffers)
result = result.expandedTo(sourceBuffer->naturalSize());
return result;
}
void MediaSourcePrivateAVFObjC::hasSelectedVideoChanged(SourceBufferPrivateAVFObjC& sourceBuffer)
{
bool hasSelectedVideo = sourceBuffer.hasSelectedVideo();
if (m_sourceBufferWithSelectedVideo == &sourceBuffer && !hasSelectedVideo)
setSourceBufferWithSelectedVideo(nullptr);
else if (m_sourceBufferWithSelectedVideo != &sourceBuffer && hasSelectedVideo)
setSourceBufferWithSelectedVideo(&sourceBuffer);
}
void MediaSourcePrivateAVFObjC::setVideoLayer(AVSampleBufferDisplayLayer* layer)
{
if (m_sourceBufferWithSelectedVideo)
m_sourceBufferWithSelectedVideo->setVideoLayer(layer);
}
void MediaSourcePrivateAVFObjC::setDecompressionSession(WebCoreDecompressionSession* decompressionSession)
{
if (m_sourceBufferWithSelectedVideo)
m_sourceBufferWithSelectedVideo->setDecompressionSession(decompressionSession);
}
#if PLATFORM(IOS_FAMILY)
void MediaSourcePrivateAVFObjC::flushActiveSourceBuffersIfNeeded()
{
for (auto* sourceBuffer : m_activeSourceBuffers)
sourceBuffer->flushIfNeeded();
}
#endif
#if ENABLE(ENCRYPTED_MEDIA)
void MediaSourcePrivateAVFObjC::cdmInstanceAttached(CDMInstance& instance)
{
if (m_cdmInstance.get() == &instance)
return;
ASSERT(!m_cdmInstance);
m_cdmInstance = &instance;
for (auto& sourceBuffer : m_sourceBuffers)
sourceBuffer->setCDMInstance(&instance);
}
void MediaSourcePrivateAVFObjC::cdmInstanceDetached(CDMInstance& instance)
{
ASSERT_UNUSED(instance, m_cdmInstance && m_cdmInstance == &instance);
for (auto& sourceBuffer : m_sourceBuffers)
sourceBuffer->setCDMInstance(nullptr);
m_cdmInstance = nullptr;
}
void MediaSourcePrivateAVFObjC::attemptToDecryptWithInstance(CDMInstance& instance)
{
ASSERT_UNUSED(instance, m_cdmInstance && m_cdmInstance == &instance);
for (auto& sourceBuffer : m_sourceBuffers)
sourceBuffer->attemptToDecrypt();
}
bool MediaSourcePrivateAVFObjC::waitingForKey() const
{
return anyOf(m_sourceBuffers, [] (auto& sourceBuffer) {
return sourceBuffer->waitingForKey();
});
}
void MediaSourcePrivateAVFObjC::outputObscuredDueToInsufficientExternalProtectionChanged(bool obscured)
{
if (m_cdmInstance)
m_cdmInstance->setHDCPStatus(obscured ? CDMInstance::HDCPStatus::OutputRestricted : CDMInstance::HDCPStatus::Valid);
}
#endif
void MediaSourcePrivateAVFObjC::setSourceBufferWithSelectedVideo(SourceBufferPrivateAVFObjC* sourceBuffer)
{
if (m_sourceBufferWithSelectedVideo) {
m_sourceBufferWithSelectedVideo->setVideoLayer(nullptr);
m_sourceBufferWithSelectedVideo->setDecompressionSession(nullptr);
}
m_sourceBufferWithSelectedVideo = sourceBuffer;
if (m_sourceBufferWithSelectedVideo && m_player) {
m_sourceBufferWithSelectedVideo->setVideoLayer(m_player->sampleBufferDisplayLayer());
m_sourceBufferWithSelectedVideo->setDecompressionSession(m_player->decompressionSession());
}
}
#if !RELEASE_LOG_DISABLED
WTFLogChannel& MediaSourcePrivateAVFObjC::logChannel() const
{
return LogMediaSource;
}
#endif
void MediaSourcePrivateAVFObjC::failedToCreateRenderer(RendererType type)
{
if (m_client)
m_client->failedToCreateRenderer(type);
}
}
#endif // ENABLE(MEDIA_SOURCE) && USE(AVFOUNDATION)