820 lines
35 KiB
C++
820 lines
35 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
|
|
#include "Containers/UnrealString.h"
|
|
#include "Containers/Queue.h"
|
|
#include "Containers/SortedMap.h"
|
|
#include "Misc/Guid.h"
|
|
#include "Templates/SharedPointer.h"
|
|
#include "Templates/Greater.h"
|
|
#include "IAnalyticsProviderET.h"
|
|
|
|
#include "IElectraPlayerInterface.h"
|
|
|
|
#include "Player/AdaptiveStreamingPlayer.h"
|
|
#include "MediaStreamMetadata.h"
|
|
#include "PlayerRuntimeGlobal.h"
|
|
|
|
class FVideoDecoderOutput;
|
|
using FVideoDecoderOutputPtr = TSharedPtr<FVideoDecoderOutput, ESPMode::ThreadSafe>;
|
|
class IAudioDecoderOutput;
|
|
using IAudioDecoderOutputPtr = TSharedPtr<IAudioDecoderOutput, ESPMode::ThreadSafe>;
|
|
class IMetaDataDecoderOutput;
|
|
using IMetaDataDecoderOutputPtr = TSharedPtr<IMetaDataDecoderOutput, ESPMode::ThreadSafe>;
|
|
class ISubtitleDecoderOutput;
|
|
using ISubtitleDecoderOutputPtr = TSharedPtr<ISubtitleDecoderOutput, ESPMode::ThreadSafe>;
|
|
|
|
namespace Electra
|
|
{
|
|
class IVideoDecoderResourceDelegate;
|
|
}
|
|
|
|
class FElectraRendererVideo;
|
|
class FElectraRendererAudio;
|
|
|
|
using namespace Electra;
|
|
|
|
DECLARE_MULTICAST_DELEGATE_TwoParams(FElectraPlayerSendAnalyticMetricsDelegate, const TSharedPtr<IAnalyticsProviderET>& /*AnalyticsProvider*/, const FGuid& /*PlayerGuid*/);
|
|
DECLARE_MULTICAST_DELEGATE_OneParam(FElectraPlayerSendAnalyticMetricsPerMinuteDelegate, const TSharedPtr<IAnalyticsProviderET>& /*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 FElectraPlayer
|
|
: public IElectraPlayerInterface
|
|
, public IAdaptiveStreamingPlayerMetrics
|
|
{
|
|
public:
|
|
FElectraPlayer(const TSharedPtr<IElectraPlayerAdapterDelegate, ESPMode::ThreadSafe>& AdapterDelegate,
|
|
FElectraPlayerSendAnalyticMetricsDelegate& InSendAnalyticMetricsDelegate,
|
|
FElectraPlayerSendAnalyticMetricsPerMinuteDelegate& InSendAnalyticMetricsPerMinuteDelegate,
|
|
FElectraPlayerReportVideoStreamingErrorDelegate& InReportVideoStreamingErrorDelegate,
|
|
FElectraPlayerReportSubtitlesMetricsDelegate& InReportSubtitlesFileMetricsDelegate);
|
|
~FElectraPlayer();
|
|
|
|
void OnVideoDecoded(const FVideoDecoderOutputPtr& DecoderOutput, bool bDoNotRender);
|
|
void OnVideoFlush();
|
|
void OnAudioDecoded(const IAudioDecoderOutputPtr& DecoderOutput);
|
|
void OnAudioFlush();
|
|
void OnSubtitleDecoded(ISubtitleDecoderOutputPtr DecoderOutput);
|
|
void OnSubtitleFlush();
|
|
|
|
void SendAnalyticMetrics(const TSharedPtr<IAnalyticsProviderET>& AnalyticsProvider, const FGuid& InPlayerGuid);
|
|
void SendAnalyticMetricsPerMinute(const TSharedPtr<IAnalyticsProviderET>& AnalyticsProvider);
|
|
void SendPendingAnalyticMetrics(const TSharedPtr<IAnalyticsProviderET>& AnalyticsProvider);
|
|
void ReportVideoStreamingError(const FGuid& InPlayerGuid, const FString& LastError);
|
|
void ReportSubtitlesMetrics(const FGuid& InPlayerGuid, const FString& URL, double ResponseTime, const FString& LastError);
|
|
|
|
void DropOldFramesFromPresentationQueue();
|
|
|
|
bool CanPresentVideoFrames(uint64 NumFrames);
|
|
bool CanPresentAudioFrames(uint64 NumFrames);
|
|
|
|
FString GetUrl() const override
|
|
{
|
|
return MediaUrl;
|
|
}
|
|
|
|
void SetGuid(const FGuid& Guid) override
|
|
{
|
|
PlayerGuid = Guid;
|
|
}
|
|
|
|
void SetAsyncResourceReleaseNotification(IAsyncResourceReleaseNotifyContainer* AsyncResourceReleaseNotification) override;
|
|
|
|
// -------- PlayerAdapter (Plugin/Native) API
|
|
|
|
bool OpenInternal(const FString& Url, const FParamDict& PlayerOptions, const FPlaystartOptions& InPlaystartOptions, EOpenType InOpenType) override;
|
|
void CloseInternal(bool bKillAfterClose) override;
|
|
|
|
void Tick(FTimespan DeltaTime, FTimespan Timecode) override;
|
|
|
|
bool IsKillAfterCloseAllowed() const override { return bAllowKillAfterCloseEvent; }
|
|
|
|
EPlayerState GetState() const override;
|
|
EPlayerStatus GetStatus() const override;
|
|
|
|
bool IsLooping() const override;
|
|
bool SetLooping(bool bLooping) override;
|
|
int32 GetLoopCount() const override;
|
|
|
|
FTimespan GetTime() const override;
|
|
FTimespan GetDuration() const override;
|
|
|
|
bool IsLive() const override;
|
|
FTimespan GetSeekableDuration() const override;
|
|
|
|
void SetPlaybackRange(const FPlaybackRange& InPlaybackRange) override;
|
|
void GetPlaybackRange(FPlaybackRange& OutPlaybackRange) const override;
|
|
TRange<FTimespan> GetPlaybackRange(ETimeRangeType InRangeToGet) const override;
|
|
|
|
TRangeSet<float> GetSupportedRates(EPlayRateType InPlayRateType) const override;
|
|
float GetRate() const override;
|
|
bool SetRate(float Rate) override;
|
|
|
|
bool Seek(const FTimespan& Time, const FSeekParam& Param) override;
|
|
void SetFrameAccurateSeekMode(bool bEnableFrameAccuracy) override;
|
|
|
|
bool GetAudioTrackFormat(int32 TrackIndex, int32 FormatIndex, FAudioTrackFormat& OutFormat) const override;
|
|
bool GetVideoTrackFormat(int32 TrackIndex, int32 FormatIndex, FVideoTrackFormat& OutFormat) const override;
|
|
|
|
int32 GetNumTracks(EPlayerTrackType TrackType) const override;
|
|
int32 GetNumTrackFormats(EPlayerTrackType TrackType, int32 TrackIndex) const override;
|
|
int32 GetSelectedTrack(EPlayerTrackType TrackType) const override;
|
|
FText GetTrackDisplayName(EPlayerTrackType TrackType, int32 TrackIndex) const override;
|
|
int32 GetTrackFormat(EPlayerTrackType TrackType, int32 TrackIndex) const override;
|
|
FString GetTrackLanguage(EPlayerTrackType TrackType, int32 TrackIndex) const override;
|
|
FString GetTrackName(EPlayerTrackType TrackType, int32 TrackIndex) const override;
|
|
bool SelectTrack(EPlayerTrackType TrackType, int32 TrackIndex) override;
|
|
|
|
int32 GetNumVideoStreams(int32 TrackIndex) const override;
|
|
bool GetVideoStreamFormat(FVideoStreamFormat& OutFormat, int32 InTrackIndex, int32 InStreamIndex) const override;
|
|
bool GetActiveVideoStreamFormat(FVideoStreamFormat& OutFormat) const override;
|
|
Electra::FVariantValue GetMediaInfo(FName InInfoName) const override;
|
|
TSharedPtr<TMap<FString, TArray<TSharedPtr<Electra::IMediaStreamMetadata::IItem, ESPMode::ThreadSafe>>>, ESPMode::ThreadSafe> GetMediaMetadata() const override;
|
|
|
|
bool GetStreamBufferInformation(FStreamBufferInfo& OutBufferInformation, EPlayerTrackType InTrackType) const override;
|
|
|
|
void SuspendOrResumeDecoders(bool bSuspend, const Electra::FParamDict& InOptions) override;
|
|
|
|
private:
|
|
DECLARE_DELEGATE_TwoParams(FOnMediaPlayerEventReceivedDelegate, TSharedPtrTS<IAdaptiveStreamingPlayerAEMSEvent> /*InEvent*/, IAdaptiveStreamingPlayerAEMSReceiver::EDispatchMode /*InDispatchMode*/);
|
|
class FAEMSEventReceiver : public IAdaptiveStreamingPlayerAEMSReceiver
|
|
{
|
|
public:
|
|
virtual ~FAEMSEventReceiver() = default;
|
|
FOnMediaPlayerEventReceivedDelegate& GetEventReceivedDelegate()
|
|
{ return EventReceivedDelegate; }
|
|
private:
|
|
virtual void OnMediaPlayerEventReceived(TSharedPtrTS<IAdaptiveStreamingPlayerAEMSEvent> InEvent, IAdaptiveStreamingPlayerAEMSReceiver::EDispatchMode InDispatchMode) override
|
|
{ EventReceivedDelegate.ExecuteIfBound(InEvent, InDispatchMode); }
|
|
FOnMediaPlayerEventReceivedDelegate EventReceivedDelegate;
|
|
};
|
|
|
|
DECLARE_DELEGATE_OneParam(FOnMediaPlayerSubtitleReceivedDelegate, ISubtitleDecoderOutputPtr);
|
|
DECLARE_DELEGATE(FOnMediaPlayerSubtitleFlushDelegate);
|
|
class FSubtitleEventReceiver : public IAdaptiveStreamingPlayerSubtitleReceiver
|
|
{
|
|
public:
|
|
virtual ~FSubtitleEventReceiver() = default;
|
|
FOnMediaPlayerSubtitleReceivedDelegate& GetSubtitleReceivedDelegate()
|
|
{ return SubtitleReceivedDelegate; }
|
|
FOnMediaPlayerSubtitleFlushDelegate& GetSubtitleFlushDelegate()
|
|
{ return SubtitleFlushDelegate; }
|
|
private:
|
|
virtual void OnMediaPlayerSubtitleReceived(ISubtitleDecoderOutputPtr Subtitle) override
|
|
{ SubtitleReceivedDelegate.ExecuteIfBound(Subtitle); }
|
|
virtual void OnMediaPlayerFlushSubtitles() override
|
|
{ SubtitleFlushDelegate.ExecuteIfBound(); }
|
|
FOnMediaPlayerSubtitleReceivedDelegate SubtitleReceivedDelegate;
|
|
FOnMediaPlayerSubtitleFlushDelegate SubtitleFlushDelegate;
|
|
};
|
|
|
|
|
|
|
|
struct FPlayerMetricEventBase
|
|
{
|
|
enum class EType
|
|
{
|
|
OpenSource,
|
|
ReceivedMainPlaylist,
|
|
ReceivedPlaylists,
|
|
TracksChanged,
|
|
PlaylistDownload,
|
|
CleanStart,
|
|
BufferingStart,
|
|
BufferingEnd,
|
|
Bandwidth,
|
|
BufferUtilization,
|
|
SegmentDownload,
|
|
LicenseKey,
|
|
DataAvailabilityChange,
|
|
VideoQualityChange,
|
|
AudioQualityChange,
|
|
CodecFormatChange,
|
|
PrerollStart,
|
|
PrerollEnd,
|
|
PlaybackStart,
|
|
PlaybackPaused,
|
|
PlaybackResumed,
|
|
PlaybackEnded,
|
|
JumpInPlayPosition,
|
|
PlaybackStopped,
|
|
SeekCompleted,
|
|
MediaMetadataChanged,
|
|
Error,
|
|
LogMessage,
|
|
DroppedVideoFrame,
|
|
DroppedAudioFrame
|
|
};
|
|
FPlayerMetricEventBase(EType InType) : Type(InType) {}
|
|
virtual ~FPlayerMetricEventBase() = default;
|
|
EType Type;
|
|
};
|
|
struct FPlayerMetricEvent_OpenSource : public FPlayerMetricEventBase
|
|
{
|
|
FPlayerMetricEvent_OpenSource(const FString& InURL) : FPlayerMetricEventBase(EType::OpenSource), URL(InURL) {}
|
|
FString URL;
|
|
};
|
|
struct FPlayerMetricEvent_ReceivedMainPlaylist : public FPlayerMetricEventBase
|
|
{
|
|
FPlayerMetricEvent_ReceivedMainPlaylist(const FString& InEffectiveURL) : FPlayerMetricEventBase(EType::ReceivedMainPlaylist), EffectiveURL(InEffectiveURL) {}
|
|
FString EffectiveURL;
|
|
};
|
|
struct FPlayerMetricEvent_PlaylistDownload : public FPlayerMetricEventBase
|
|
{
|
|
FPlayerMetricEvent_PlaylistDownload(const Metrics::FPlaylistDownloadStats& InPlaylistDownloadStats) : FPlayerMetricEventBase(EType::PlaylistDownload), PlaylistDownloadStats(InPlaylistDownloadStats) {}
|
|
Metrics::FPlaylistDownloadStats PlaylistDownloadStats;
|
|
};
|
|
struct FPlayerMetricEvent_BufferingStart : public FPlayerMetricEventBase
|
|
{
|
|
FPlayerMetricEvent_BufferingStart(Metrics::EBufferingReason InBufferingReason) : FPlayerMetricEventBase(EType::BufferingStart), BufferingReason(InBufferingReason) {}
|
|
Metrics::EBufferingReason BufferingReason;
|
|
};
|
|
struct FPlayerMetricEvent_BufferingEnd : public FPlayerMetricEventBase
|
|
{
|
|
FPlayerMetricEvent_BufferingEnd(Metrics::EBufferingReason InBufferingReason) : FPlayerMetricEventBase(EType::BufferingEnd), BufferingReason(InBufferingReason) {}
|
|
Metrics::EBufferingReason BufferingReason;
|
|
};
|
|
struct FPlayerMetricEvent_Bandwidth : public FPlayerMetricEventBase
|
|
{
|
|
FPlayerMetricEvent_Bandwidth(int64 InEffectiveBps, int64 InThroughputBps, double InLatencyInSeconds) : FPlayerMetricEventBase(EType::Bandwidth), EffectiveBps(InEffectiveBps), ThroughputBps(InThroughputBps), LatencyInSeconds(InLatencyInSeconds) {}
|
|
int64 EffectiveBps;
|
|
int64 ThroughputBps;
|
|
double LatencyInSeconds;
|
|
};
|
|
struct FPlayerMetricEvent_BufferUtilization : public FPlayerMetricEventBase
|
|
{
|
|
FPlayerMetricEvent_BufferUtilization(const Metrics::FBufferStats& InBufferStats) : FPlayerMetricEventBase(EType::BufferUtilization), BufferStats(InBufferStats) {}
|
|
Metrics::FBufferStats BufferStats;
|
|
};
|
|
struct FPlayerMetricEvent_SegmentDownload : public FPlayerMetricEventBase
|
|
{
|
|
FPlayerMetricEvent_SegmentDownload(const Metrics::FSegmentDownloadStats& InSegmentDownloadStats) : FPlayerMetricEventBase(EType::SegmentDownload), SegmentDownloadStats(InSegmentDownloadStats) {}
|
|
Metrics::FSegmentDownloadStats SegmentDownloadStats;
|
|
};
|
|
struct FPlayerMetricEvent_LicenseKey : public FPlayerMetricEventBase
|
|
{
|
|
FPlayerMetricEvent_LicenseKey(const Metrics::FLicenseKeyStats& InLicenseKeyStats) : FPlayerMetricEventBase(EType::LicenseKey), LicenseKeyStats(InLicenseKeyStats) {}
|
|
Metrics::FLicenseKeyStats LicenseKeyStats;
|
|
};
|
|
struct FPlayerMetricEvent_DataAvailabilityChange : public FPlayerMetricEventBase
|
|
{
|
|
FPlayerMetricEvent_DataAvailabilityChange(const Metrics::FDataAvailabilityChange& InDataAvailability) : FPlayerMetricEventBase(EType::DataAvailabilityChange), DataAvailability(InDataAvailability) {}
|
|
Metrics::FDataAvailabilityChange DataAvailability;
|
|
};
|
|
struct FPlayerMetricEvent_VideoQualityChange : public FPlayerMetricEventBase
|
|
{
|
|
FPlayerMetricEvent_VideoQualityChange(int32 InNewBitrate, int32 InPreviousBitrate, bool bInIsDrasticDownswitch) : FPlayerMetricEventBase(EType::VideoQualityChange), NewBitrate(InNewBitrate), PreviousBitrate(InPreviousBitrate), bIsDrasticDownswitch(bInIsDrasticDownswitch) {}
|
|
int32 NewBitrate;
|
|
int32 PreviousBitrate;
|
|
bool bIsDrasticDownswitch;
|
|
};
|
|
struct FPlayerMetricEvent_AudioQualityChange : public FPlayerMetricEventBase
|
|
{
|
|
FPlayerMetricEvent_AudioQualityChange(int32 InNewBitrate, int32 InPreviousBitrate, bool bInIsDrasticDownswitch) : FPlayerMetricEventBase(EType::AudioQualityChange), NewBitrate(InNewBitrate), PreviousBitrate(InPreviousBitrate), bIsDrasticDownswitch(bInIsDrasticDownswitch) {}
|
|
int32 NewBitrate;
|
|
int32 PreviousBitrate;
|
|
bool bIsDrasticDownswitch;
|
|
};
|
|
struct FPlayerMetricEvent_CodecFormatChange : public FPlayerMetricEventBase
|
|
{
|
|
FPlayerMetricEvent_CodecFormatChange(const FStreamCodecInformation& InNewDecodingFormat) : FPlayerMetricEventBase(EType::CodecFormatChange), NewDecodingFormat(InNewDecodingFormat) {}
|
|
FStreamCodecInformation NewDecodingFormat;
|
|
};
|
|
struct FPlayerMetricEvent_JumpInPlayPosition : public FPlayerMetricEventBase
|
|
{
|
|
FPlayerMetricEvent_JumpInPlayPosition(const FTimeValue& InToNewTime, const FTimeValue& InFromTime, Metrics::ETimeJumpReason InTimejumpReason) : FPlayerMetricEventBase(EType::JumpInPlayPosition), ToNewTime(InToNewTime), FromTime(InFromTime), TimejumpReason(InTimejumpReason) {}
|
|
FTimeValue ToNewTime;
|
|
FTimeValue FromTime;
|
|
Metrics::ETimeJumpReason TimejumpReason;
|
|
};
|
|
struct FPlayerMetricEvent_MediaMetadataChange : public FPlayerMetricEventBase
|
|
{
|
|
FPlayerMetricEvent_MediaMetadataChange(const TSharedPtrTS<Electra::UtilsMP4::FMetadataParser>& InMetadata) : FPlayerMetricEventBase(EType::MediaMetadataChanged), NewMetadata(InMetadata) {}
|
|
TSharedPtrTS<Electra::UtilsMP4::FMetadataParser> NewMetadata;
|
|
};
|
|
struct FPlayerMetricEvent_Error : public FPlayerMetricEventBase
|
|
{
|
|
FPlayerMetricEvent_Error(const FString& InErrorReason) : FPlayerMetricEventBase(EType::Error), ErrorReason(InErrorReason) {}
|
|
FString ErrorReason;
|
|
};
|
|
struct FPlayerMetricEvent_LogMessage : public FPlayerMetricEventBase
|
|
{
|
|
FPlayerMetricEvent_LogMessage(IInfoLog::ELevel InLogLevel, const FString& InLogMessage, int64 InPlayerWallclockMilliseconds) : FPlayerMetricEventBase(EType::LogMessage), LogLevel(InLogLevel), LogMessage(InLogMessage), PlayerWallclockMilliseconds(InPlayerWallclockMilliseconds) {}
|
|
IInfoLog::ELevel LogLevel;
|
|
FString LogMessage;
|
|
int64 PlayerWallclockMilliseconds;
|
|
};
|
|
|
|
|
|
void CalculateTargetSeekTime(FTimespan& OutTargetTime, const FTimespan& InTime);
|
|
|
|
bool PresentVideoFrame(const FVideoDecoderOutputPtr& InVideoFrame);
|
|
bool PresentAudioFrame(const IAudioDecoderOutputPtr& DecoderOutput);
|
|
bool PresentSubtitle(const ISubtitleDecoderOutputPtr& DecoderOutput);
|
|
|
|
void PlatformSuspendOrResumeDecoders(bool bSuspend, const Electra::FParamDict& InOptions);
|
|
|
|
void OnMediaPlayerEventReceived(TSharedPtrTS<IAdaptiveStreamingPlayerAEMSEvent> InEvent, IAdaptiveStreamingPlayerAEMSReceiver::EDispatchMode InDispatchMode);
|
|
|
|
// Methods from IAdaptiveStreamingPlayerMetrics
|
|
virtual void ReportOpenSource(const FString& URL) override
|
|
{ DeferredPlayerEvents.Enqueue(MakeSharedTS<FPlayerMetricEvent_OpenSource>(URL)); }
|
|
virtual void ReportReceivedMainPlaylist(const FString& EffectiveURL) override
|
|
{ DeferredPlayerEvents.Enqueue(MakeSharedTS<FPlayerMetricEvent_ReceivedMainPlaylist>(EffectiveURL)); }
|
|
virtual void ReportReceivedPlaylists() override
|
|
{ DeferredPlayerEvents.Enqueue(MakeSharedTS<FPlayerMetricEventBase>(FPlayerMetricEventBase::EType::ReceivedPlaylists)); }
|
|
virtual void ReportTracksChanged() override
|
|
{ DeferredPlayerEvents.Enqueue(MakeSharedTS<FPlayerMetricEventBase>(FPlayerMetricEventBase::EType::TracksChanged)); }
|
|
virtual void ReportPlaylistDownload(const Metrics::FPlaylistDownloadStats& PlaylistDownloadStats) override
|
|
{ DeferredPlayerEvents.Enqueue(MakeSharedTS<FPlayerMetricEvent_PlaylistDownload>(PlaylistDownloadStats)); }
|
|
virtual void ReportCleanStart() override
|
|
{ /*DeferredPlayerEvents.Enqueue(MakeSharedTS<FPlayerMetricEventBase>(FPlayerMetricEventBase::EType::CleanStart));*/
|
|
bDiscardOutputUntilCleanStart = false;
|
|
}
|
|
virtual void ReportBufferingStart(Metrics::EBufferingReason BufferingReason) override
|
|
{ DeferredPlayerEvents.Enqueue(MakeSharedTS<FPlayerMetricEvent_BufferingStart>(BufferingReason)); }
|
|
virtual void ReportBufferingEnd(Metrics::EBufferingReason BufferingReason) override
|
|
{ DeferredPlayerEvents.Enqueue(MakeSharedTS<FPlayerMetricEvent_BufferingEnd>(BufferingReason)); }
|
|
virtual void ReportBandwidth(int64 EffectiveBps, int64 ThroughputBps, double LatencyInSeconds) override
|
|
{ DeferredPlayerEvents.Enqueue(MakeSharedTS<FPlayerMetricEvent_Bandwidth>(EffectiveBps, ThroughputBps, LatencyInSeconds)); }
|
|
virtual void ReportBufferUtilization(const Metrics::FBufferStats& BufferStats) override
|
|
{ DeferredPlayerEvents.Enqueue(MakeSharedTS<FPlayerMetricEvent_BufferUtilization>(BufferStats)); }
|
|
virtual void ReportSegmentDownload(const Metrics::FSegmentDownloadStats& SegmentDownloadStats) override
|
|
{ DeferredPlayerEvents.Enqueue(MakeSharedTS<FPlayerMetricEvent_SegmentDownload>(SegmentDownloadStats)); }
|
|
virtual void ReportLicenseKey(const Metrics::FLicenseKeyStats& LicenseKeyStats) override
|
|
{ DeferredPlayerEvents.Enqueue(MakeSharedTS<FPlayerMetricEvent_LicenseKey>(LicenseKeyStats)); }
|
|
virtual void ReportDataAvailabilityChange(const Metrics::FDataAvailabilityChange& DataAvailability) override
|
|
{ DeferredPlayerEvents.Enqueue(MakeSharedTS<FPlayerMetricEvent_DataAvailabilityChange>(DataAvailability)); }
|
|
virtual void ReportVideoQualityChange(int32 NewBitrate, int32 PreviousBitrate, bool bIsDrasticDownswitch) override
|
|
{ DeferredPlayerEvents.Enqueue(MakeSharedTS<FPlayerMetricEvent_VideoQualityChange>(NewBitrate, PreviousBitrate, bIsDrasticDownswitch)); }
|
|
virtual void ReportAudioQualityChange(int32 NewBitrate, int32 PreviousBitrate, bool bIsDrasticDownswitch) override
|
|
{ DeferredPlayerEvents.Enqueue(MakeSharedTS<FPlayerMetricEvent_AudioQualityChange>(NewBitrate, PreviousBitrate, bIsDrasticDownswitch)); }
|
|
virtual void ReportDecodingFormatChange(const FStreamCodecInformation& NewDecodingFormat) override
|
|
{ DeferredPlayerEvents.Enqueue(MakeSharedTS<FPlayerMetricEvent_CodecFormatChange>(NewDecodingFormat)); }
|
|
virtual void ReportPrerollStart() override
|
|
{ DeferredPlayerEvents.Enqueue(MakeSharedTS<FPlayerMetricEventBase>(FPlayerMetricEventBase::EType::PrerollStart)); }
|
|
virtual void ReportPrerollEnd() override
|
|
{ DeferredPlayerEvents.Enqueue(MakeSharedTS<FPlayerMetricEventBase>(FPlayerMetricEventBase::EType::PrerollEnd)); }
|
|
virtual void ReportPlaybackStart() override
|
|
{ DeferredPlayerEvents.Enqueue(MakeSharedTS<FPlayerMetricEventBase>(FPlayerMetricEventBase::EType::PlaybackStart)); }
|
|
virtual void ReportPlaybackPaused() override
|
|
{ DeferredPlayerEvents.Enqueue(MakeSharedTS<FPlayerMetricEventBase>(FPlayerMetricEventBase::EType::PlaybackPaused)); }
|
|
virtual void ReportPlaybackResumed() override
|
|
{ DeferredPlayerEvents.Enqueue(MakeSharedTS<FPlayerMetricEventBase>(FPlayerMetricEventBase::EType::PlaybackResumed)); }
|
|
virtual void ReportPlaybackEnded() override
|
|
{ DeferredPlayerEvents.Enqueue(MakeSharedTS<FPlayerMetricEventBase>(FPlayerMetricEventBase::EType::PlaybackEnded)); }
|
|
virtual void ReportJumpInPlayPosition(const FTimeValue& ToNewTime, const FTimeValue& FromTime, Metrics::ETimeJumpReason TimejumpReason) override
|
|
{ DeferredPlayerEvents.Enqueue(MakeSharedTS<FPlayerMetricEvent_JumpInPlayPosition>(ToNewTime, FromTime, TimejumpReason)); }
|
|
virtual void ReportPlaybackStopped() override
|
|
{ DeferredPlayerEvents.Enqueue(MakeSharedTS<FPlayerMetricEventBase>(FPlayerMetricEventBase::EType::PlaybackStopped)); }
|
|
virtual void ReportSeekCompleted() override
|
|
{ DeferredPlayerEvents.Enqueue(MakeSharedTS<FPlayerMetricEventBase>(FPlayerMetricEventBase::EType::SeekCompleted)); }
|
|
virtual void ReportMediaMetadataChanged(TSharedPtrTS<Electra::UtilsMP4::FMetadataParser> Metadata) override
|
|
{ DeferredPlayerEvents.Enqueue(MakeSharedTS<FPlayerMetricEvent_MediaMetadataChange>(Metadata)); }
|
|
virtual void ReportError(const FString& ErrorReason) override
|
|
{ DeferredPlayerEvents.Enqueue(MakeSharedTS<FPlayerMetricEvent_Error>(ErrorReason)); }
|
|
virtual void ReportLogMessage(IInfoLog::ELevel InLogLevel, const FString& InLogMessage, int64 InPlayerWallclockMilliseconds) override
|
|
{ DeferredPlayerEvents.Enqueue(MakeSharedTS<FPlayerMetricEvent_LogMessage>(InLogLevel, InLogMessage, InPlayerWallclockMilliseconds)); }
|
|
virtual void ReportDroppedVideoFrame() override
|
|
{ DeferredPlayerEvents.Enqueue(MakeSharedTS<FPlayerMetricEventBase>(FPlayerMetricEventBase::EType::DroppedVideoFrame)); }
|
|
virtual void ReportDroppedAudioFrame() override
|
|
{ DeferredPlayerEvents.Enqueue(MakeSharedTS<FPlayerMetricEventBase>(FPlayerMetricEventBase::EType::DroppedAudioFrame)); }
|
|
|
|
void LogPresentationFramesQueues(FTimespan DeltaTime);
|
|
|
|
void ClearToDefaultState();
|
|
|
|
void MediaStateOnPreparingFinished();
|
|
bool MediaStateOnPlay();
|
|
bool MediaStateOnPause();
|
|
void MediaStateOnEndReached();
|
|
void MediaStateOnSeekFinished();
|
|
void TriggerFirstSeekIfNecessary();
|
|
|
|
TSharedPtr<FTrackMetadata, ESPMode::ThreadSafe> GetTrackStreamMetadata(EPlayerTrackType TrackType, int32 TrackIndex) const;
|
|
|
|
// Delegate to talk back to adapter host
|
|
TWeakPtr<IElectraPlayerAdapterDelegate, ESPMode::ThreadSafe> AdapterDelegate;
|
|
|
|
// Contains number of audio tracks available to expose it later.
|
|
int32 NumTracksAudio;
|
|
int32 NumTracksVideo;
|
|
int32 NumTracksSubtitle;
|
|
int32 SelectedQuality;
|
|
mutable int32 SelectedVideoTrackIndex;
|
|
mutable int32 SelectedAudioTrackIndex;
|
|
mutable int32 SelectedSubtitleTrackIndex;
|
|
mutable bool bVideoTrackIndexDirty;
|
|
mutable bool bAudioTrackIndexDirty;
|
|
mutable bool bSubtitleTrackIndexDirty;
|
|
|
|
bool bInitialSeekPerformed;
|
|
bool bDiscardOutputUntilCleanStart;
|
|
bool bIsFirstBuffering;
|
|
|
|
FPlaybackRange CurrentPlaybackRange;
|
|
TOptional<bool> bFrameAccurateSeeking;
|
|
TOptional<bool> bEnableLooping;
|
|
|
|
TSharedPtr<TMap<FString, TArray<TSharedPtr<Electra::IMediaStreamMetadata::IItem, ESPMode::ThreadSafe>>>, ESPMode::ThreadSafe> CurrentStreamMetadata;
|
|
|
|
TOptional<FVideoStreamFormat> CurrentlyActiveVideoStreamFormat;
|
|
|
|
FIntPoint LastPresentedFrameDimension;
|
|
|
|
|
|
struct FPlayerState
|
|
{
|
|
TOptional<float> IntendedPlayRate;
|
|
float CurrentPlayRate = 0.0f;
|
|
|
|
TAtomic<EPlayerState> State;
|
|
TAtomic<EPlayerStatus> Status;
|
|
|
|
bool bUseInternal = false;
|
|
|
|
void Reset()
|
|
{
|
|
IntendedPlayRate.Reset();
|
|
CurrentPlayRate = 0.0f;
|
|
State = EPlayerState::Closed;
|
|
Status = EPlayerStatus::None;
|
|
}
|
|
|
|
float GetRate() const;
|
|
EPlayerState GetState() const;
|
|
EPlayerStatus GetStatus() const;
|
|
|
|
void SetIntendedPlayRate(float InIntendedRate);
|
|
void SetPlayRateFromPlayer(float InCurrentPlayerPlayRate);
|
|
};
|
|
|
|
|
|
/** Media player Guid */
|
|
FGuid PlayerGuid;
|
|
/** Metric delegates */
|
|
FElectraPlayerSendAnalyticMetricsDelegate& SendAnalyticMetricsDelegate;
|
|
FElectraPlayerSendAnalyticMetricsPerMinuteDelegate& SendAnalyticMetricsPerMinuteDelegate;
|
|
FElectraPlayerReportVideoStreamingErrorDelegate& ReportVideoStreamingErrorDelegate;
|
|
FElectraPlayerReportSubtitlesMetricsDelegate& ReportSubtitlesMetricsDelegate;
|
|
|
|
/** Option interface **/
|
|
FPlaystartOptions PlaystartOptions;
|
|
|
|
FPlayerState PlayerState;
|
|
|
|
TAtomic<bool> bPlayerHasClosed;
|
|
TAtomic<bool> bHasPendingError;
|
|
|
|
bool bAllowKillAfterCloseEvent;
|
|
|
|
/** Queued events */
|
|
TQueue<IElectraPlayerAdapterDelegate::EPlayerEvent> DeferredEvents;
|
|
TQueue<TSharedPtrTS<FPlayerMetricEventBase>> DeferredPlayerEvents;
|
|
TSharedPtrTS<FAEMSEventReceiver> MediaPlayerEventReceiver;
|
|
TSharedPtrTS<FSubtitleEventReceiver> MediaPlayerSubtitleReceiver;
|
|
|
|
|
|
/** The URL of the currently opened media. */
|
|
FString MediaUrl;
|
|
|
|
class FInternalPlayerImpl
|
|
{
|
|
public:
|
|
/** The media player itself **/
|
|
TSharedPtr<IAdaptiveStreamingPlayer, ESPMode::ThreadSafe> AdaptivePlayer;
|
|
|
|
/** Renderers to use **/
|
|
TSharedPtr<FElectraRendererVideo, ESPMode::ThreadSafe> RendererVideo;
|
|
TSharedPtr<FElectraRendererAudio, ESPMode::ThreadSafe> RendererAudio;
|
|
|
|
/** */
|
|
static void DoCloseAsync(TSharedPtr<FInternalPlayerImpl, ESPMode::ThreadSafe>&& Player, uint32 PlayerID, TSharedPtr<IAsyncResourceReleaseNotifyContainer, ESPMode::ThreadSafe> AsyncDestructNotification);
|
|
};
|
|
|
|
mutable FCriticalSection PlayerLock;
|
|
TSharedPtr<FInternalPlayerImpl, ESPMode::ThreadSafe> CurrentPlayer;
|
|
FEvent* WaitForPlayerDestroyedEvent;
|
|
TSharedPtr<Electra::FApplicationTerminationHandler, ESPMode::ThreadSafe> AppTerminationHandler;
|
|
|
|
TSharedPtr<IAsyncResourceReleaseNotifyContainer, ESPMode::ThreadSafe> AsyncResourceReleaseNotification;
|
|
|
|
class FAdaptiveStreamingPlayerResourceProvider : public IAdaptiveStreamingPlayerResourceProvider
|
|
{
|
|
public:
|
|
FAdaptiveStreamingPlayerResourceProvider(const TWeakPtr<IElectraPlayerAdapterDelegate, ESPMode::ThreadSafe>& AdapterDelegate);
|
|
virtual ~FAdaptiveStreamingPlayerResourceProvider();
|
|
|
|
virtual void ProvideStaticPlaybackDataForURL(TSharedPtr<IAdaptiveStreamingPlayerResourceRequest, ESPMode::ThreadSafe> InOutRequest) override;
|
|
|
|
void SetExternalDataReader(TWeakPtr<IElectraPlayerExternalDataReader, ESPMode::ThreadSafe> InExternalDataReader);
|
|
void ProcessPendingStaticResourceRequests();
|
|
void ClearPendingRequests();
|
|
|
|
private:
|
|
/** Requests for static resource fetches we want to perform on the main thread **/
|
|
TQueue<TSharedPtr<IAdaptiveStreamingPlayerResourceRequest, ESPMode::ThreadSafe>, EQueueMode::Mpsc> PendingStaticResourceRequests;
|
|
|
|
// Player adapter delegate
|
|
TWeakPtr<IElectraPlayerAdapterDelegate, ESPMode::ThreadSafe> AdapterDelegate;
|
|
// External data reader
|
|
TWeakPtr<IElectraPlayerExternalDataReader, ESPMode::ThreadSafe> ExternalDataReader;
|
|
IElectraPlayerExternalDataReader::FElectraPlayerExternalDataReaderOnRequestCompleted ExternalDataCompletedDelegate;
|
|
static void OnExternalDataReadCompleted(IElectraPlayerExternalDataReader::FResponseDataPtr InResponseData, int64 InTotalFileSize, const IElectraPlayerExternalDataReader::FReadParam& InFromRequestParams);
|
|
};
|
|
|
|
TSharedPtr<FAdaptiveStreamingPlayerResourceProvider, ESPMode::ThreadSafe> StaticResourceProvider;
|
|
TSharedPtr<IVideoDecoderResourceDelegate, ESPMode::ThreadSafe> VideoDecoderResourceDelegate;
|
|
|
|
class FBlobRequest
|
|
{
|
|
public:
|
|
FBlobRequest() : Request(MakeShared<Electra::FHTTPResourceRequest, ESPMode::ThreadSafe>())
|
|
{ }
|
|
void OnBlobRequestComplete(TSharedPtrTS<Electra::FHTTPResourceRequest> InRequest)
|
|
{
|
|
bIsComplete = true;
|
|
}
|
|
TSharedPtr<Electra::FHTTPResourceRequest, ESPMode::ThreadSafe> Request;
|
|
bool bIsComplete = false;
|
|
bool bDispatched = false;
|
|
};
|
|
TSharedPtr<FBlobRequest, ESPMode::ThreadSafe> PendingBlobRequest;
|
|
|
|
|
|
class FAverageValue
|
|
{
|
|
public:
|
|
FAverageValue()
|
|
: Samples(nullptr)
|
|
, NumSamples(0)
|
|
, MaxSamples(0)
|
|
{
|
|
}
|
|
~FAverageValue()
|
|
{
|
|
delete[] Samples;
|
|
}
|
|
void SetNumSamples(int32 InMaxSamples)
|
|
{
|
|
check(InMaxSamples > 0);
|
|
delete[] Samples;
|
|
NumSamples = 0;
|
|
MaxSamples = InMaxSamples;
|
|
Samples = new double[MaxSamples];
|
|
}
|
|
void AddValue(double Value)
|
|
{
|
|
Samples[NumSamples % MaxSamples] = Value;
|
|
++NumSamples;
|
|
}
|
|
void Reset()
|
|
{
|
|
NumSamples = 0;
|
|
}
|
|
double GetAverage() const
|
|
{
|
|
double Avg = 0.0;
|
|
if (NumSamples > 0)
|
|
{
|
|
double Sum = 0.0;
|
|
int32 Last = NumSamples <= MaxSamples ? NumSamples : MaxSamples;
|
|
for (int32 i = 0; i < Last; ++i)
|
|
{
|
|
Sum += Samples[i];
|
|
}
|
|
Avg = Sum / Last;
|
|
}
|
|
return Avg;
|
|
}
|
|
private:
|
|
double* Samples;
|
|
int32 NumSamples;
|
|
int32 MaxSamples;
|
|
};
|
|
|
|
struct FStatistics
|
|
{
|
|
struct FBandwidth
|
|
{
|
|
FBandwidth()
|
|
{
|
|
Bandwidth.SetNumSamples(3);
|
|
Latency.SetNumSamples(3);
|
|
Reset();
|
|
}
|
|
void Reset()
|
|
{
|
|
Bandwidth.Reset();
|
|
Latency.Reset();
|
|
}
|
|
void AddSample(double InBytesPerSecond, double InLatency)
|
|
{
|
|
Bandwidth.AddValue(InBytesPerSecond);
|
|
Latency.AddValue(InLatency);
|
|
}
|
|
double GetAverageBandwidth() const
|
|
{
|
|
return Bandwidth.GetAverage();
|
|
}
|
|
double GetAverageLatency() const
|
|
{
|
|
return Latency.GetAverage();
|
|
}
|
|
FAverageValue Bandwidth;
|
|
FAverageValue Latency;
|
|
};
|
|
struct FHistoryEntry
|
|
{
|
|
double TimeSinceStart = 0.0;
|
|
FString Message;
|
|
};
|
|
FStatistics()
|
|
{
|
|
Reset();
|
|
}
|
|
void Reset()
|
|
{
|
|
InitialURL.Empty();
|
|
CurrentlyActivePlaylistURL.Empty();
|
|
LastError.Empty();
|
|
LastState = "Empty";
|
|
TimeAtOpen = -1.0;
|
|
TimeToLoadMainPlaylist = -1.0;
|
|
TimeToLoadStreamPlaylists = -1.0;
|
|
InitialBufferingDuration = -1.0;
|
|
InitialVideoStreamBitrate = 0;
|
|
InitialAudioStreamBitrate = 0;
|
|
TimeAtPrerollBegin = -1.0;
|
|
TimeForInitialPreroll = -1.0;
|
|
NumTimesRebuffered = 0;
|
|
NumTimesForwarded = 0;
|
|
NumTimesRewound = 0;
|
|
NumTimesLooped = 0;
|
|
TimeAtBufferingBegin = 0.0;
|
|
TotalRebufferingDuration = 0.0;
|
|
LongestRebufferingDuration = 0.0;
|
|
PlayPosAtStart = -1.0;
|
|
PlayPosAtEnd = -1.0;
|
|
NumVideoQualityUpswitches = 0;
|
|
NumVideoQualityDownswitches = 0;
|
|
NumVideoQualityDrasticDownswitches = 0;
|
|
NumAudioQualityUpswitches = 0;
|
|
NumAudioQualityDownswitches = 0;
|
|
NumAudioQualityDrasticDownswitches = 0;
|
|
NumVideoDatabytesStreamed = 0;
|
|
NumAudioDatabytesStreamed = 0;
|
|
NumSegmentDownloadsAborted = 0;
|
|
CurrentlyActiveResolutionWidth = 0;
|
|
CurrentlyActiveResolutionHeight = 0;
|
|
VideoSegmentBitratesStreamed.Empty();
|
|
AudioSegmentBitratesStreamed.Empty();
|
|
VideoQualityPercentages.Empty();
|
|
AudioQualityPercentages.Empty();
|
|
NumVideoSegmentsStreamed = 0;
|
|
NumAudioSegmentsStreamed = 0;
|
|
InitialBufferingBandwidth.Reset();
|
|
bIsInitiallyDownloading = false;
|
|
bDidPlaybackEnd = false;
|
|
MediaTimelineAtStart.Reset();
|
|
MediaTimelineAtEnd.Reset();
|
|
MediaDuration = 0.0;
|
|
MessageHistoryBuffer.Empty();
|
|
NumErr404 = 0;
|
|
NumErr4xx = 0;
|
|
NumErr5xx = 0;
|
|
NumErrTimeouts = 0;
|
|
NumErrConnDrops = 0;
|
|
NumErrOther = 0;
|
|
}
|
|
void AddMessageToHistory(FString InMessage);
|
|
|
|
// n elements by descending bitrate holding a percentage of this bitrate being used
|
|
using FQualityPercentages = TSortedMap<int32, int32, FDefaultAllocator, TGreater<int32>>;
|
|
|
|
FString InitialURL;
|
|
FString CurrentlyActivePlaylistURL;
|
|
FString LastError;
|
|
FString LastState; // "Empty", "Opening", "Preparing", "Buffering", "Idle", "Ready", "Playing", "Paused", "Seeking", "Rebuffering", "Ended"
|
|
double TimeAtOpen;
|
|
double TimeToLoadMainPlaylist;
|
|
double TimeToLoadStreamPlaylists;
|
|
double InitialBufferingDuration;
|
|
int32 InitialVideoStreamBitrate;
|
|
int32 InitialAudioStreamBitrate;
|
|
double TimeAtPrerollBegin;
|
|
double TimeForInitialPreroll;
|
|
int32 NumTimesRebuffered;
|
|
int32 NumTimesForwarded;
|
|
int32 NumTimesRewound;
|
|
int32 NumTimesLooped;
|
|
double TimeAtBufferingBegin;
|
|
double TotalRebufferingDuration;
|
|
double LongestRebufferingDuration;
|
|
double PlayPosAtStart;
|
|
double PlayPosAtEnd;
|
|
int32 NumVideoQualityUpswitches;
|
|
int32 NumVideoQualityDownswitches;
|
|
int32 NumVideoQualityDrasticDownswitches;
|
|
int32 NumAudioQualityUpswitches;
|
|
int32 NumAudioQualityDownswitches;
|
|
int32 NumAudioQualityDrasticDownswitches;
|
|
int64 NumVideoDatabytesStreamed;
|
|
int64 NumAudioDatabytesStreamed;
|
|
int32 NumSegmentDownloadsAborted;
|
|
int32 CurrentlyActiveResolutionWidth;
|
|
int32 CurrentlyActiveResolutionHeight;
|
|
TMap<int32, uint32> VideoSegmentBitratesStreamed; // key=video stream bitrate, value=number of segments loaded at this rate
|
|
TMap<int32, uint32> AudioSegmentBitratesStreamed; // key=audio stream bitrate, value=number of segments loaded at this rate
|
|
FQualityPercentages VideoQualityPercentages;
|
|
FQualityPercentages AudioQualityPercentages;
|
|
uint32 NumVideoSegmentsStreamed;
|
|
uint32 NumAudioSegmentsStreamed;
|
|
FBandwidth InitialBufferingBandwidth;
|
|
bool bIsInitiallyDownloading;
|
|
bool bDidPlaybackEnd;
|
|
FTimeRange MediaTimelineAtStart;
|
|
FTimeRange MediaTimelineAtEnd;
|
|
double MediaDuration;
|
|
TArray<FHistoryEntry> MessageHistoryBuffer;
|
|
uint32 NumErr404;
|
|
uint32 NumErr4xx;
|
|
uint32 NumErr5xx;
|
|
uint32 NumErrTimeouts;
|
|
uint32 NumErrConnDrops;
|
|
uint32 NumErrOther;
|
|
};
|
|
|
|
struct FAnalyticsEvent
|
|
{
|
|
FString EventName;
|
|
TArray<FAnalyticsEventAttribute> ParamArray;
|
|
};
|
|
|
|
void UpdatePlayEndStatistics();
|
|
void LogStatistics();
|
|
void AddCommonAnalyticsAttributes(TArray<FAnalyticsEventAttribute>& InOutParamArray);
|
|
TSharedPtr<FAnalyticsEvent> CreateAnalyticsEvent(FString InEventName);
|
|
void EnqueueAnalyticsEvent(TSharedPtr<FAnalyticsEvent> InAnalyticEvent);
|
|
void UpdateAnalyticsCustomValues();
|
|
|
|
FCriticalSection StatisticsLock;
|
|
FStatistics Statistics;
|
|
|
|
TQueue<TSharedPtr<FAnalyticsEvent>> QueuedAnalyticEvents;
|
|
int32 NumQueuedAnalyticEvents = 0;
|
|
FString AnalyticsOSVersion;
|
|
FString AnalyticsGPUType;
|
|
|
|
/** Unique player instance GUID sent with each analytics event. This allows finding all events of a particular playback session. **/
|
|
FString AnalyticsInstanceGuid;
|
|
/** Sequential analytics event number. Helps sorting events. **/
|
|
uint32 AnalyticsInstanceEventCount;
|
|
|
|
/** Custom analytics constants. **/
|
|
FString AnalyticsCustomValues[8];
|
|
|
|
|
|
/** Unique instance ID */
|
|
uint32 InstanceID = 0;
|
|
|
|
void HandleBlobDownload();
|
|
|
|
void HandleDeferredPlayerEvents();
|
|
void HandlePlayerEventOpenSource(const FString& URL);
|
|
void HandlePlayerEventReceivedMainPlaylist(const FString& EffectiveURL);
|
|
void HandlePlayerEventReceivedPlaylists();
|
|
void HandlePlayerEventTracksChanged();
|
|
void HandlePlayerEventPlaylistDownload(const Metrics::FPlaylistDownloadStats& PlaylistDownloadStats);
|
|
void HandlePlayerEventBufferingStart(Metrics::EBufferingReason BufferingReason);
|
|
void HandlePlayerEventBufferingEnd(Metrics::EBufferingReason BufferingReason);
|
|
void HandlePlayerEventBandwidth(int64 EffectiveBps, int64 ThroughputBps, double LatencyInSeconds);
|
|
void HandlePlayerEventBufferUtilization(const Metrics::FBufferStats& BufferStats);
|
|
void HandlePlayerEventSegmentDownload(const Metrics::FSegmentDownloadStats& SegmentDownloadStats);
|
|
void HandlePlayerEventLicenseKey(const Metrics::FLicenseKeyStats& LicenseKeyStats);
|
|
void HandlePlayerEventDataAvailabilityChange(const Metrics::FDataAvailabilityChange& DataAvailability);
|
|
void HandlePlayerEventVideoQualityChange(int32 NewBitrate, int32 PreviousBitrate, bool bIsDrasticDownswitch);
|
|
void HandlePlayerEventAudioQualityChange(int32 NewBitrate, int32 PreviousBitrate, bool bIsDrasticDownswitch);
|
|
void HandlePlayerEventCodecFormatChange(const Electra::FStreamCodecInformation& NewDecodingFormat);
|
|
void HandlePlayerEventPrerollStart();
|
|
void HandlePlayerEventPrerollEnd();
|
|
void HandlePlayerEventPlaybackStart();
|
|
void HandlePlayerEventPlaybackPaused();
|
|
void HandlePlayerEventPlaybackResumed();
|
|
void HandlePlayerEventPlaybackEnded();
|
|
void HandlePlayerEventJumpInPlayPosition(const FTimeValue& ToNewTime, const FTimeValue& FromTime, Metrics::ETimeJumpReason TimejumpReason);
|
|
void HandlePlayerEventPlaybackStopped();
|
|
void HandlePlayerEventSeekCompleted();
|
|
void HandlePlayerMediaMetadataChanged(const TSharedPtrTS<Electra::UtilsMP4::FMetadataParser>& InMetadata);
|
|
void HandlePlayerEventError(const FString& ErrorReason);
|
|
void HandlePlayerEventLogMessage(IInfoLog::ELevel InLogLevel, const FString& InLogMessage, int64 InPlayerWallclockMilliseconds);
|
|
void HandlePlayerEventDroppedVideoFrame();
|
|
void HandlePlayerEventDroppedAudioFrame();
|
|
};
|
|
|
|
ENUM_CLASS_FLAGS(FElectraPlayer::EPlayerStatus);
|
|
|