// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "MediaDecoderOutput.h" #include "IAnalyticsProviderET.h" #include "ParameterDictionary.h" #include "Math/RangeSet.h" #include "ElectraPlayerMisc.h" #include "ElectraPlayerResourceDelegate.h" #include "IElectraPlayerDataCache.h" #include "MediaStreamMetadata.h" #define UE_API ELECTRAPLAYERRUNTIME_API class FVideoDecoderOutput; using FVideoDecoderOutputPtr = TSharedPtr; class IAudioDecoderOutput; using IAudioDecoderOutputPtr = TSharedPtr; class IMetaDataDecoderOutput; using IMetaDataDecoderOutputPtr = TSharedPtr; class ISubtitleDecoderOutput; using ISubtitleDecoderOutputPtr = TSharedPtr; // --------------------------------------------------------------------------------------------- DECLARE_MULTICAST_DELEGATE_TwoParams(FElectraPlayerSendAnalyticMetricsDelegate, const TSharedPtr& /*AnalyticsProvider*/, const FGuid& /*PlayerGuid*/); DECLARE_MULTICAST_DELEGATE_OneParam(FElectraPlayerSendAnalyticMetricsPerMinuteDelegate, const TSharedPtr& /*AnalyticsProvider*/); DECLARE_MULTICAST_DELEGATE_TwoParams(FElectraPlayerReportVideoStreamingErrorDelegate, const FGuid& /*PlayerGuid*/, const FString& /*LastError*/); DECLARE_MULTICAST_DELEGATE_FourParams(FElectraPlayerReportSubtitlesMetricsDelegate, const FGuid& /*PlayerGuid*/, const FString& /*URL*/, double /*ResponseTime*/, const FString& /*LastError*/); // --------------------------------------------------------------------------------------------- class IElectraPlayerAdapterDelegate { public: virtual ~IElectraPlayerAdapterDelegate() {} enum class EOptionType { MaxVerticalStreamResolution = 0, MaxBandwidthForStreaming, PlayListData, LicenseKeyData, PlaystartPosFromSeekPositions, CustomAnalyticsMetric }; virtual Electra::FVariantValue QueryOptions(EOptionType Type, const Electra::FVariantValue& Param = Electra::FVariantValue()) = 0; enum class EBlobResultType { Success, TimedOut, HttpFailure }; virtual void BlobReceived(const TSharedPtr, ESPMode::ThreadSafe>& InBlobData, EBlobResultType InResultType, int32 InResultCode, const Electra::FParamDict* InExtraInfo) = 0; enum class EPlayerEvent { MediaBuffering = 0, MediaBufferingComplete, MediaClosed, MediaConnecting, MediaOpened, MediaOpenFailed, PlaybackEndReached, PlaybackResumed, PlaybackSuspended, SeekCompleted, TracksChanged, MetadataChanged, Internal_Start, Internal_PurgeVideoSamplesHint = Internal_Start, Internal_VideoSamplesAvailable, Internal_VideoSamplesUnavailable, Internal_AudioSamplesAvailable, Internal_AudioSamplesUnavailable }; virtual void SendMediaEvent(EPlayerEvent Event) = 0; virtual void OnVideoFlush() = 0; virtual void OnAudioFlush() = 0; virtual void OnSubtitleFlush() = 0; virtual void PresentVideoFrame(const FVideoDecoderOutputPtr& InVideoFrame) = 0; virtual void PresentAudioFrame(const IAudioDecoderOutputPtr& InAudioFrame) = 0; virtual void PresentSubtitleSample(const ISubtitleDecoderOutputPtr& InSubtitleSample) = 0; virtual void PresentMetadataSample(const IMetaDataDecoderOutputPtr& InMetadataSample) = 0; virtual bool CanReceiveVideoSamples(int32 NumFrames) = 0; virtual bool CanReceiveAudioSamples(int32 NumFrames) = 0; virtual FString GetVideoAdapterName() const = 0; virtual TSharedPtr GetResourceDelegate() const = 0; }; class IElectraPlayerExternalDataReader : public TSharedFromThis { public: virtual ~IElectraPlayerExternalDataReader() = default; struct FReadParam { FString URL; int64 AbsoluteFileOffset = 0; int64 NumBytesToRead = 0; void* Custom = nullptr; }; using FResponseDataPtr = TSharedPtr, ESPMode::ThreadSafe>; DECLARE_DELEGATE_ThreeParams(FElectraPlayerExternalDataReaderOnRequestCompleted, FResponseDataPtr /*ResponseData*/, int64 /*TotalFileSize*/, const FReadParam& FromRequestParams); /** * Called to read data by some external means. * When done the provided completion delegate must be called. * Passing a nullptr for the response data will trigger a read error and a subsequent playback error. * Returning fewer bytes than requested implicitly means the end of the file was reached while reading. * If a read request for 0 bytes at offset 0 is made you are to return the total size of the file. For this * request it is permitted to return a nullptr for response data without resulting in an error. * Read requests may set the number of bytes to read to MAX_INT64 to indicate reading until the end of the file. * The player has no upfront knowledge about the size of the file so it cannot always adjust the number of * bytes to be read. Even when returning the size of the file in an earlier read there is no guarantee * that the number of bytes to be read will be adjusted accordingly. * Returning a negative value for the total size of the file is treated as an error and will be handled * like a file-not-found error, even though that should not be possible. * You are providing this reader class to the player knowing that the URL to play exists and is valid. * If the offset to read from is given as a negative value this is an indication that you may close the * file, but such a call is optional. You may close the file after having closed the player. * You may however open and close the file with every read request if that is more convenient for you. * The player will wait indefinitely for the response data to be provided. There are no timeouts. * You *must* call the provided delegate even for failures. */ virtual void ReadDataFromFile(const FReadParam& InReadParam, FElectraPlayerExternalDataReaderOnRequestCompleted OutCompletionDelegate) = 0; }; // Container class to be passed through options as shared pointer to allow passing any non-standard ref-counted entities to the player class IOptionPointerValueContainer { public: virtual ~IOptionPointerValueContainer() {} virtual void* GetPointer() const = 0; }; class IElectraPlayerInterface : public TSharedFromThis { public: virtual ~IElectraPlayerInterface() {} virtual FString GetUrl() const = 0; virtual void SetGuid(const FGuid& Guid) = 0; // -------- PlayerAdapter (Plugin/Native) API struct FStreamSelectionAttributes { TOptional Kind; TOptional Language_RFC4647; TOptional Codec; TOptional TrackIndexOverride; void Reset() { Kind.Reset(); Language_RFC4647.Reset(); Codec.Reset(); TrackIndexOverride.Reset(); } }; struct FPlaystartOptions { TOptional TimeOffset; FStreamSelectionAttributes InitialVideoTrackAttributes; FStreamSelectionAttributes InitialAudioTrackAttributes; FStreamSelectionAttributes InitialSubtitleTrackAttributes; TOptional MaxVerticalStreamResolution; TOptional MaxBandwidthForStreaming; bool bDoNotPreload = false; TSharedPtr ExternalDataReader; TSharedPtr ExternalDataCache; }; enum class EOpenType { Media, Blob }; virtual bool OpenInternal(const FString& Url, const Electra::FParamDict& PlayerOptions, const FPlaystartOptions& InPlaystartOptions, EOpenType InOpenType) = 0; virtual void CloseInternal(bool bKillAfterClose) = 0; virtual void Tick(FTimespan DeltaTime, FTimespan Timecode) = 0; virtual bool IsKillAfterCloseAllowed() const = 0; enum class EPlayerState { Closed = 0, Error, Paused, Playing, Preparing, Stopped }; enum class EPlayerStatus { None = 0x0, Buffering = 0x1, Connecting = 0x2 }; virtual EPlayerState GetState() const = 0; virtual EPlayerStatus GetStatus() const = 0; virtual bool IsLooping() const = 0; virtual bool SetLooping(bool bLooping) = 0; virtual int32 GetLoopCount() const = 0; virtual FTimespan GetTime() const = 0; virtual FTimespan GetDuration() const = 0; virtual bool IsLive() const = 0; virtual FTimespan GetSeekableDuration() const = 0; struct FPlaybackRange { TOptional Start; TOptional End; }; virtual void SetPlaybackRange(const FPlaybackRange& InPlaybackRange) = 0; virtual void GetPlaybackRange(FPlaybackRange& OutPlaybackRange) const = 0; enum class ETimeRangeType { /** Total absolute time range as defined by the media. */ Absolute, /** Current time range of the media, set by media internal means or through API calls. */ Current }; virtual TRange GetPlaybackRange(ETimeRangeType InRangeToGet) const = 0; enum class EPlayRateType { // Playback rate with frames being dropped. Thinned, // Playback rate without dropping frames. Unthinned }; virtual TRangeSet GetSupportedRates(EPlayRateType InPlayRateType) const = 0; virtual float GetRate() const = 0; virtual bool SetRate(float Rate) = 0; struct FSeekParam { TOptional SequenceIndex; TOptional StartingBitrate; }; virtual bool Seek(const FTimespan& Time, const FSeekParam& Param) = 0; virtual void SetFrameAccurateSeekMode(bool bEnableFrameAccuracy) = 0; struct FAudioTrackFormat { uint32 BitsPerSample; uint32 NumChannels; uint32 SampleRate; FString TypeName; }; struct FVideoTrackFormat { FIntPoint Dim; float FrameRate; TRange FrameRates; FString TypeName; }; virtual bool GetAudioTrackFormat(int32 TrackIndex, int32 FormatIndex, FAudioTrackFormat& OutFormat) const = 0; virtual bool GetVideoTrackFormat(int32 TrackIndex, int32 FormatIndex, FVideoTrackFormat& OutFormat) const = 0; enum class EPlayerTrackType { Audio = 0, Caption, Metadata, Script, Subtitle, Text, Video }; virtual int32 GetNumTracks(EPlayerTrackType TrackType) const = 0; virtual int32 GetNumTrackFormats(EPlayerTrackType TrackType, int32 TrackIndex) const = 0; virtual int32 GetSelectedTrack(EPlayerTrackType TrackType) const = 0; virtual FText GetTrackDisplayName(EPlayerTrackType TrackType, int32 TrackIndex) const = 0; virtual int32 GetTrackFormat(EPlayerTrackType TrackType, int32 TrackIndex) const = 0; virtual FString GetTrackLanguage(EPlayerTrackType TrackType, int32 TrackIndex) const = 0; virtual FString GetTrackName(EPlayerTrackType TrackType, int32 TrackIndex) const = 0; virtual bool SelectTrack(EPlayerTrackType TrackType, int32 TrackIndex) = 0; struct FVideoStreamFormat { FIntPoint Resolution; double FrameRate; int32 Bitrate; }; virtual int32 GetNumVideoStreams(int32 TrackIndex) const = 0; virtual bool GetVideoStreamFormat(FVideoStreamFormat& OutFormat, int32 InTrackIndex, int32 InStreamIndex) const = 0; virtual bool GetActiveVideoStreamFormat(FVideoStreamFormat& OutFormat) const = 0; virtual Electra::FVariantValue GetMediaInfo(FName InInfoName) const = 0; virtual TSharedPtr>>, ESPMode::ThreadSafe> GetMediaMetadata() const = 0; struct FStreamBufferInfo { struct FTimeValue { FTimespan Time; int64 SequenceIndex = -1; }; struct FTimeRange { FTimeValue Start; FTimeValue End; }; TArray TimeEnqueued; TArray TimeAvailable; TArray TimeRequested; }; virtual bool GetStreamBufferInformation(FStreamBufferInfo& OutBufferInformation, EPlayerTrackType InTrackType) const = 0; // Suspends or resumes decoder instances. Not supported on all platforms. virtual void SuspendOrResumeDecoders(bool bSuspend, const Electra::FParamDict& InOptions) = 0; enum { ResourceFlags_Decoder = 1 << 0, ResourceFlags_OutputBuffers = 1 << 1, ResourceFlags_All = (1 << 2) - 1, ResourceFlags_Any = ResourceFlags_All, }; class IAsyncResourceReleaseNotifyContainer { public: virtual ~IAsyncResourceReleaseNotifyContainer() {} virtual void Signal(uint32 ResourceFlags) = 0; }; virtual void SetAsyncResourceReleaseNotification(IAsyncResourceReleaseNotifyContainer* AsyncResourceReleaseNotification) = 0; }; class FElectraPlayerRuntimeFactory { public: static UE_API IElectraPlayerInterface* CreatePlayer(const TSharedPtr& AdapterDelegate, FElectraPlayerSendAnalyticMetricsDelegate& InSendAnalyticMetricsDelegate, FElectraPlayerSendAnalyticMetricsPerMinuteDelegate& InSendAnalyticMetricsPerMinuteDelegate, FElectraPlayerReportVideoStreamingErrorDelegate& InReportVideoStreamingErrorDelegate, FElectraPlayerReportSubtitlesMetricsDelegate& InReportSubtitlesFileMetricsDelegate); }; class FElectraPlayerPlatform { public: static UE_API bool StartupPlatformResources(const Electra::FParamDict & Params = Electra::FParamDict()); }; #undef UE_API