blob: 71c350bd4adeb8263d462dbe07b61382a942652f [file] [log] [blame]
/*
* Copyright (C) 2011-2022 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.
*/
#pragma once
#if ENABLE(VIDEO) && USE(AVFOUNDATION)
#include "FloatSize.h"
#include "InbandTextTrackPrivateAVF.h"
#include "MediaPlayerPrivate.h"
#include "Timer.h"
#include <wtf/Deque.h>
#include <wtf/Function.h>
#include <wtf/Lock.h>
#include <wtf/LoggerHelper.h>
#include <wtf/WeakPtr.h>
namespace WebCore {
class InbandMetadataTextTrackPrivateAVF;
class InbandTextTrackPrivateAVF;
// Use eager initialization for the WeakPtrFactory since we construct WeakPtrs on another thread.
class MediaPlayerPrivateAVFoundation : public CanMakeWeakPtr<MediaPlayerPrivateAVFoundation, WeakPtrFactoryInitialization::Eager>, public MediaPlayerPrivateInterface, public AVFInbandTrackParent
#if !RELEASE_LOG_DISABLED
, private LoggerHelper
#endif
{
public:
virtual void metadataLoaded();
virtual void playabilityKnown();
virtual void rateChanged();
virtual void loadedTimeRangesChanged();
virtual void seekableTimeRangesChanged();
virtual void timeChanged(const MediaTime&);
virtual void seekCompleted(bool);
virtual void didEnd();
virtual void contentsNeedsDisplay() { }
virtual void configureInbandTracks();
virtual void setCurrentTextTrack(InbandTextTrackPrivateAVF*) { }
virtual InbandTextTrackPrivateAVF* currentTextTrack() const = 0;
#if ENABLE(WIRELESS_PLAYBACK_TARGET)
void playbackTargetIsWirelessChanged();
#endif
void queueTaskOnEventLoop(Function<void()>&&);
class Notification {
public:
#define FOR_EACH_MEDIAPLAYERPRIVATEAVFOUNDATION_NOTIFICATION_TYPE(macro) \
macro(None) \
macro(ItemDidPlayToEndTime) \
macro(ItemTracksChanged) \
macro(ItemStatusChanged) \
macro(ItemSeekableTimeRangesChanged) \
macro(ItemLoadedTimeRangesChanged) \
macro(ItemPresentationSizeChanged) \
macro(ItemIsPlaybackLikelyToKeepUpChanged) \
macro(ItemIsPlaybackBufferEmptyChanged) \
macro(ItemIsPlaybackBufferFullChanged) \
macro(AssetMetadataLoaded) \
macro(AssetPlayabilityKnown) \
macro(PlayerRateChanged) \
macro(PlayerTimeChanged) \
macro(SeekCompleted) \
macro(DurationChanged) \
macro(ContentsNeedsDisplay) \
macro(InbandTracksNeedConfiguration) \
macro(TargetIsWirelessChanged) \
enum Type {
#define DEFINE_TYPE_ENUM(type) type,
FOR_EACH_MEDIAPLAYERPRIVATEAVFOUNDATION_NOTIFICATION_TYPE(DEFINE_TYPE_ENUM)
#undef DEFINE_TYPE_ENUM
FunctionType,
};
Notification()
: m_type(None)
, m_finished(false)
{
}
Notification(Type type, const MediaTime& time)
: m_type(type)
, m_time(time)
, m_finished(false)
{
}
Notification(Type type, bool finished)
: m_type(type)
, m_finished(finished)
{
}
Notification(Function<void()>&& function)
: m_type(FunctionType)
, m_finished(false)
, m_function(WTFMove(function))
{
}
Type type() { return m_type; }
bool isValid() { return m_type != None; }
MediaTime time() { return m_time; }
bool finished() { return m_finished; }
Function<void ()>& function() { return m_function; }
private:
Type m_type;
MediaTime m_time;
bool m_finished;
Function<void()> m_function;
};
void scheduleMainThreadNotification(Notification&&);
void scheduleMainThreadNotification(Notification::Type, const MediaTime& = MediaTime::zeroTime());
void scheduleMainThreadNotification(Notification::Type, bool completed);
void dispatchNotification();
void clearMainThreadPendingFlag();
#if ENABLE(LEGACY_ENCRYPTED_MEDIA)
static bool extractKeyURIKeyIDAndCertificateFromInitData(Uint8Array* initData, String& keyURI, String& keyID, RefPtr<Uint8Array>& certificate);
#endif
#if !RELEASE_LOG_DISABLED
const Logger& logger() const final { return m_logger.get(); }
const char* logClassName() const override { return "MediaPlayerPrivateAVFoundation"; }
const void* logIdentifier() const final { return reinterpret_cast<const void*>(m_logIdentifier); }
WTFLogChannel& logChannel() const final;
#endif
enum class MediaRenderingMode : uint8_t {
MediaRenderingNone,
MediaRenderingToContext,
MediaRenderingToLayer
};
protected:
explicit MediaPlayerPrivateAVFoundation(MediaPlayer*);
virtual ~MediaPlayerPrivateAVFoundation();
// MediaPlayerPrivatePrivateInterface overrides.
void load(const String& url) override;
#if ENABLE(MEDIA_SOURCE)
void load(const URL&, const ContentType&, MediaSourcePrivateClient&) override;
#endif
#if ENABLE(MEDIA_STREAM)
void load(MediaStreamPrivate&) override { setNetworkState(MediaPlayer::NetworkState::FormatError); }
#endif
void cancelLoad() override = 0;
void prepareToPlay() override;
void play() override;
void pause() override;
FloatSize naturalSize() const override;
bool hasVideo() const override { return m_cachedHasVideo; }
bool hasAudio() const override { return m_cachedHasAudio; }
void setPageIsVisible(bool) final;
MediaTime durationMediaTime() const override;
MediaTime currentMediaTime() const override = 0;
void seek(const MediaTime&) override;
void seekWithTolerance(const MediaTime&, const MediaTime&, const MediaTime&) override;
bool seeking() const override;
bool paused() const override;
void setVolume(float) override = 0;
bool hasClosedCaptions() const override { return m_cachedHasCaptions; }
MediaPlayer::NetworkState networkState() const override { return m_networkState; }
MediaPlayer::ReadyState readyState() const override { return m_readyState; }
MediaTime maxMediaTimeSeekable() const override;
MediaTime minMediaTimeSeekable() const override;
std::unique_ptr<PlatformTimeRanges> buffered() const override;
bool didLoadingProgress() const override;
void paint(GraphicsContext&, const FloatRect&) override = 0;
DestinationColorSpace colorSpace() override = 0;
void paintCurrentFrameInContext(GraphicsContext&, const FloatRect&) override = 0;
void setPreload(MediaPlayer::Preload) override;
PlatformLayer* platformLayer() const override { return 0; }
bool supportsAcceleratedRendering() const override = 0;
void acceleratedRenderingStateChanged() override;
bool shouldMaintainAspectRatio() const { return m_shouldMaintainAspectRatio; }
void setShouldMaintainAspectRatio(bool) override;
bool canSaveMediaData() const override;
MediaPlayer::MovieLoadType movieLoadType() const override;
void prepareForRendering() override;
bool supportsPictureInPicture() const override { return true; }
bool supportsFullscreen() const override;
bool supportsScanning() const override { return true; }
unsigned long long fileSize() const override { return totalBytes(); }
bool hasSingleSecurityOrigin() const override;
// Required interfaces for concrete derived classes.
virtual void createAVAssetForURL(const URL&) = 0;
virtual void createAVPlayer() = 0;
virtual void createAVPlayerItem() = 0;
enum ItemStatus {
MediaPlayerAVPlayerItemStatusDoesNotExist,
MediaPlayerAVPlayerItemStatusUnknown,
MediaPlayerAVPlayerItemStatusFailed,
MediaPlayerAVPlayerItemStatusReadyToPlay,
MediaPlayerAVPlayerItemStatusPlaybackBufferEmpty,
MediaPlayerAVPlayerItemStatusPlaybackBufferFull,
MediaPlayerAVPlayerItemStatusPlaybackLikelyToKeepUp,
};
virtual ItemStatus playerItemStatus() const = 0;
enum AssetStatus {
MediaPlayerAVAssetStatusDoesNotExist,
MediaPlayerAVAssetStatusUnknown,
MediaPlayerAVAssetStatusLoading,
MediaPlayerAVAssetStatusFailed,
MediaPlayerAVAssetStatusCancelled,
MediaPlayerAVAssetStatusLoaded,
MediaPlayerAVAssetStatusPlayable,
};
virtual AssetStatus assetStatus() const = 0;
virtual long assetErrorCode() const = 0;
virtual void platformSetVisible(bool) = 0;
virtual void platformPlay() = 0;
virtual void platformPause() = 0;
virtual bool platformPaused() const { return !rate(); }
virtual void seekToTime(const MediaTime&, const MediaTime& negativeTolerance, const MediaTime& positiveTolerance) = 0;
unsigned long long totalBytes() const override = 0;
virtual std::unique_ptr<PlatformTimeRanges> platformBufferedTimeRanges() const = 0;
virtual MediaTime platformMaxTimeSeekable() const = 0;
virtual MediaTime platformMinTimeSeekable() const = 0;
virtual MediaTime platformMaxTimeLoaded() const = 0;
virtual MediaTime platformDuration() const = 0;
virtual void beginLoadingMetadata() = 0;
virtual void sizeChanged() = 0;
virtual void createContextVideoRenderer() = 0;
virtual void destroyContextVideoRenderer() = 0;
virtual void createVideoLayer() = 0;
virtual void destroyVideoLayer() = 0;
bool hasAvailableVideoFrame() const override = 0;
virtual bool hasContextRenderer() const = 0;
virtual bool hasLayerRenderer() const = 0;
virtual void updateVideoLayerGravity() = 0;
virtual void resolvedURLChanged() = 0;
static bool isUnsupportedMIMEType(const String&);
static const HashSet<String, ASCIICaseInsensitiveHash>& staticMIMETypeList();
void updateStates();
void setHasVideo(bool);
void setHasAudio(bool);
void setHasClosedCaptions(bool);
void characteristicsChanged();
void setDelayCharacteristicsChangedNotification(bool);
void setDelayCallbacks(bool) const;
void setIgnoreLoadStateChanges(bool delay) { m_ignoreLoadStateChanges = delay; }
void setNaturalSize(FloatSize);
bool isLiveStream() const { return std::isinf(duration()); }
void setNetworkState(MediaPlayer::NetworkState);
void setReadyState(MediaPlayer::ReadyState);
MediaRenderingMode currentRenderingMode() const;
MediaRenderingMode preferredRenderingMode() const;
bool metaDataAvailable() const { return m_readyState >= MediaPlayer::ReadyState::HaveMetadata; }
MediaTime maxTimeLoaded() const;
bool isReadyForVideoSetup() const;
virtual void setUpVideoRendering();
virtual void tearDownVideoRendering();
virtual bool haveBeenAskedToPaint() const { return false; }
bool hasSetUpVideoRendering() const;
void mainThreadCallback();
void invalidateCachedDuration();
const String& assetURL() const { return m_assetURL.string(); }
MediaPlayer* player() { return m_player; }
const MediaPlayer* player() const { return m_player; }
String engineDescription() const override { return "AVFoundation"_s; }
long platformErrorCode() const override { return assetErrorCode(); }
void trackModeChanged() override;
#if ENABLE(AVF_CAPTIONS)
void notifyTrackModeChanged() override { }
virtual void synchronizeTextTrackState() { }
#endif
void processNewAndRemovedTextTracks(const Vector<RefPtr<InbandTextTrackPrivateAVF>>&);
void clearTextTracks();
Vector<RefPtr<InbandTextTrackPrivateAVF>> m_textTracks;
void setResolvedURL(URL&&);
const URL& resolvedURL() const { return m_resolvedURL; }
void setNeedsRenderingModeChanged();
void renderingModeChanged();
bool loadingMetadata() const { return m_loadingMetadata; }
bool shouldEnableInheritURIQueryComponent() const;
private:
MediaPlayer* m_player;
Function<void()> m_pendingSeek;
mutable Lock m_queuedNotificationsLock;
Deque<Notification> m_queuedNotifications WTF_GUARDED_BY_LOCK(m_queuedNotificationsLock);
mutable std::unique_ptr<PlatformTimeRanges> m_cachedLoadedTimeRanges;
MediaPlayer::NetworkState m_networkState;
MediaPlayer::ReadyState m_readyState;
URL m_assetURL;
URL m_resolvedURL;
RefPtr<SecurityOrigin> m_requestedOrigin;
RefPtr<SecurityOrigin> m_resolvedOrigin;
MediaPlayer::Preload m_preload;
#if !RELEASE_LOG_DISABLED
Ref<const Logger> m_logger;
const void* m_logIdentifier;
#endif
FloatSize m_cachedNaturalSize;
mutable MediaTime m_cachedMaxTimeLoaded;
mutable MediaTime m_cachedMaxTimeSeekable;
mutable MediaTime m_cachedMinTimeSeekable;
mutable MediaTime m_cachedDuration;
MediaTime m_reportedDuration;
mutable MediaTime m_maxTimeLoadedAtLastDidLoadingProgress;
mutable int m_delayCallbacks;
int m_delayCharacteristicsChangedNotification;
bool m_mainThreadCallPending;
bool m_assetIsPlayable;
bool m_visible;
bool m_loadingMetadata;
bool m_isAllowedToRender;
bool m_cachedHasAudio;
bool m_cachedHasVideo;
bool m_cachedHasCaptions;
bool m_ignoreLoadStateChanges;
bool m_haveReportedFirstVideoFrame;
bool m_inbandTrackConfigurationPending;
bool m_characteristicsChanged;
bool m_shouldMaintainAspectRatio;
bool m_seeking;
bool m_needsRenderingModeChanged { false };
};
String convertEnumerationToString(MediaPlayerPrivateAVFoundation::MediaRenderingMode);
} // namespace WebCore
namespace WTF {
template<typename Type>
struct LogArgument;
template<> struct EnumTraits<WebCore::MediaPlayerPrivateAVFoundation::MediaRenderingMode> {
using values = EnumValues<
WebCore::MediaPlayerPrivateAVFoundation::MediaRenderingMode,
WebCore::MediaPlayerPrivateAVFoundation::MediaRenderingMode::MediaRenderingNone,
WebCore::MediaPlayerPrivateAVFoundation::MediaRenderingMode::MediaRenderingToContext,
WebCore::MediaPlayerPrivateAVFoundation::MediaRenderingMode::MediaRenderingToLayer
>;
};
}; // namespace WTF
#endif // ENABLE(VIDEO) && USE(AVFOUNDATION)