Files
UnrealEngineUWP/Engine/Source/Runtime/MediaAssets/Private/Assets/MediaPlayer.cpp
Max Preussner f92bf91c5f MediaAssets: Fixed crash in TickVideo after media player is GC'ed
Copied from CL# 3299912 & 3300133

#jira FORT-37386
#lockdown cristina.riveron
#rb bob.tellez

[CL 3302418 by Max Preussner in Main branch]
2017-02-14 15:47:58 -05:00

704 lines
12 KiB
C++

// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
#include "MediaPlayer.h"
#include "IMediaControls.h"
#include "IMediaModule.h"
#include "IMediaOutput.h"
#include "IMediaPlayer.h"
#include "IMediaPlayerFactory.h"
#include "IMediaTracks.h"
#include "MediaOverlays.h"
#include "Misc/Paths.h"
#include "MediaAssetsPrivate.h"
#include "MediaPlaylist.h"
#include "MediaSource.h"
#include "MediaSoundWave.h"
#include "MediaTexture.h"
#include "Modules/ModuleManager.h"
/* UMediaPlayer structors
*****************************************************************************/
UMediaPlayer::UMediaPlayer(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
, PlayOnOpen(true)
, Shuffle(false)
, Loop(false)
, PlaylistIndex(INDEX_NONE)
, Player(MakeShareable(new FMediaPlayerBase))
#if WITH_EDITOR
, WasPlayingInPIE(false)
#endif
{
Player->OnMediaEvent().AddUObject(this, &UMediaPlayer::HandlePlayerMediaEvent);
}
/* UMediaPlayer interface
*****************************************************************************/
bool UMediaPlayer::CanPause() const
{
return Player->CanPause();
}
bool UMediaPlayer::CanPlaySource(UMediaSource* MediaSource)
{
if ((MediaSource == nullptr) || !MediaSource->Validate())
{
return false;
}
return Player->CanPlayUrl(MediaSource->GetUrl(), *MediaSource);
}
bool UMediaPlayer::CanPlayUrl(const FString& Url)
{
if (Url.IsEmpty())
{
return false;
}
return Player->CanPlayUrl(Url, *GetDefault<UMediaSource>());
}
void UMediaPlayer::Close()
{
Player->Close();
LastUrl.Empty();
Playlist = nullptr;
PlaylistIndex = INDEX_NONE;
}
FMediaPlayerBase& UMediaPlayer::GetBasePlayer()
{
return *Player;
}
FName UMediaPlayer::GetDesiredPlayerName() const
{
return Player->DesiredPlayerName;
}
FTimespan UMediaPlayer::GetDuration() const
{
return Player->GetDuration();
}
FFloatRange UMediaPlayer::GetForwardRates(bool Unthinned)
{
return Player->GetForwardRates(Unthinned);
}
int32 UMediaPlayer::GetNumTracks(EMediaPlayerTrack TrackType) const
{
return Player->GetNumTracks((EMediaTrackType)TrackType);
}
FName UMediaPlayer::GetPlayerName() const
{
return Player->GetPlayerName();
}
float UMediaPlayer::GetRate() const
{
return Player->GetRate();
}
FFloatRange UMediaPlayer::GetReverseRates(bool Unthinned)
{
return Player->GetReverseRates(Unthinned);
}
int32 UMediaPlayer::GetSelectedTrack(EMediaPlayerTrack TrackType) const
{
return Player->GetSelectedTrack((EMediaTrackType)TrackType);
}
FTimespan UMediaPlayer::GetTime() const
{
return Player->GetTime();
}
FText UMediaPlayer::GetTrackDisplayName(EMediaPlayerTrack TrackType, int32 TrackIndex) const
{
return Player->GetTrackDisplayName((EMediaTrackType)TrackType, TrackIndex);
}
FString UMediaPlayer::GetTrackLanguage(EMediaPlayerTrack TrackType, int32 TrackIndex) const
{
return Player->GetTrackLanguage((EMediaTrackType)TrackType, TrackIndex);
}
const FString& UMediaPlayer::GetUrl() const
{
return Player->GetUrl();
}
bool UMediaPlayer::IsLooping() const
{
return Player->IsLooping();
}
bool UMediaPlayer::IsPaused() const
{
return Player->IsPaused();
}
bool UMediaPlayer::IsPlaying() const
{
return Player->IsPlaying();
}
bool UMediaPlayer::IsPreparing() const
{
return Player->IsPreparing();
}
bool UMediaPlayer::IsReady() const
{
return Player->IsReady();
}
bool UMediaPlayer::Next()
{
if (Playlist == nullptr)
{
return false;
}
int32 RemainingAttempts = Playlist->Num();
while (RemainingAttempts-- > 0)
{
UMediaSource* NextSource = Shuffle
? Playlist->GetRandom(PlaylistIndex)
: Playlist->GetNext(PlaylistIndex);
if ((NextSource != nullptr) && NextSource->Validate() && Player->Open(NextSource->GetUrl(), *NextSource))
{
return true;
}
}
return false;
}
bool UMediaPlayer::OpenFile(const FString& FilePath)
{
FString FullPath;
if (FPaths::IsRelative(FilePath))
{
FullPath = FPaths::ConvertRelativePathToFull(FilePath);
}
else
{
FullPath = FilePath;
FPaths::NormalizeFilename(FullPath);
}
return OpenUrl(FString(TEXT("file://")) + FullPath);
}
bool UMediaPlayer::OpenPlaylistIndex(UMediaPlaylist* InPlaylist, int32 Index)
{
Close();
if (InPlaylist == nullptr)
{
UE_LOG(LogMediaAssets, Warning, TEXT("UMediaPlayer::OpenPlaylistIndex called with null MediaPlaylist"));
return false;
}
Playlist = InPlaylist;
if (Index == INDEX_NONE)
{
return true;
}
UMediaSource* MediaSource = Playlist->Get(Index);
if (MediaSource == nullptr)
{
UE_LOG(LogMediaAssets, Warning, TEXT("UMediaPlayer::OpenPlaylistIndex called with invalid PlaylistIndex %i"), Index);
return false;
}
LastUrl = MediaSource->GetUrl();
PlaylistIndex = Index;
if (!MediaSource->Validate())
{
UE_LOG(LogMediaAssets, Error, TEXT("Failed to validate media source %s (%s)"), *MediaSource->GetName(), *MediaSource->GetUrl());
return false;
}
return Player->Open(LastUrl, *MediaSource);
}
bool UMediaPlayer::OpenSource(UMediaSource* MediaSource)
{
Close();
if (MediaSource == nullptr)
{
UE_LOG(LogMediaAssets, Warning, TEXT("UMediaPlayer::OpenSource called with null MediaSource"));
return false;
}
LastUrl = MediaSource->GetUrl();
if (!MediaSource->Validate())
{
UE_LOG(LogMediaAssets, Error, TEXT("Failed to validate media source %s (%s)"), *MediaSource->GetName(), *MediaSource->GetUrl());
return false;
}
return Player->Open(LastUrl, *MediaSource);
}
bool UMediaPlayer::OpenUrl(const FString& Url)
{
Close();
if (Url.IsEmpty())
{
return false;
}
LastUrl = Url;
return Player->Open(LastUrl, *GetDefault<UMediaSource>());
}
bool UMediaPlayer::Pause()
{
return Player->SetRate(0.0f);
}
bool UMediaPlayer::Play()
{
return Player->SetRate(1.0f);
}
bool UMediaPlayer::Previous()
{
if (Playlist == nullptr)
{
return false;
}
int32 RemainingAttempts = Playlist->Num();
while (--RemainingAttempts >= 0)
{
UMediaSource* PrevSource = Shuffle
? Playlist->GetRandom(PlaylistIndex)
: Playlist->GetNext(PlaylistIndex);
if ((PrevSource != nullptr) && PrevSource->Validate() && Player->Open(PrevSource->GetUrl(), *PrevSource))
{
return true;
}
}
return false;
}
bool UMediaPlayer::Reopen()
{
if (Playlist != nullptr)
{
return OpenPlaylistIndex(Playlist, PlaylistIndex);
}
return Player->Open(LastUrl, *GetDefault<UMediaSource>());
}
bool UMediaPlayer::Rewind()
{
return Seek(FTimespan::Zero());
}
bool UMediaPlayer::Seek(const FTimespan& Time)
{
return Player->Seek(Time);
}
bool UMediaPlayer::SelectTrack(EMediaPlayerTrack TrackType, int32 TrackIndex)
{
return Player->SelectTrack((EMediaTrackType)TrackType, TrackIndex);
}
void UMediaPlayer::SetDesiredPlayerName(FName PlayerName)
{
Player->DesiredPlayerName = PlayerName;
}
bool UMediaPlayer::SetLooping(bool Looping)
{
Loop = Looping;
return Player->SetLooping(Looping);
}
void UMediaPlayer::SetOverlays(UMediaOverlays* NewOverlays)
{
if (Overlays != nullptr)
{
Overlays->OnBeginDestroy().RemoveAll(this);
}
if (NewOverlays != nullptr)
{
NewOverlays->OnBeginDestroy().AddUObject(this, &UMediaPlayer::HandleMediaOverlaysBeginDestroy);
}
Player->SetOverlaySink(NewOverlays);
Overlays = NewOverlays;
}
bool UMediaPlayer::SetRate(float Rate)
{
return Player->SetRate(Rate);
}
void UMediaPlayer::SetSoundWave(UMediaSoundWave* NewSoundWave)
{
if (SoundWave != nullptr)
{
SoundWave->OnBeginDestroy().RemoveAll(this);
}
if (NewSoundWave != nullptr)
{
NewSoundWave->OnBeginDestroy().AddUObject(this, &UMediaPlayer::HandleMediaSoundWaveBeginDestroy);
}
Player->SetAudioSink(NewSoundWave);
SoundWave = NewSoundWave;
}
void UMediaPlayer::SetVideoTexture(UMediaTexture* NewTexture)
{
if (VideoTexture != nullptr)
{
VideoTexture->OnBeginDestroy().RemoveAll(this);
}
if (NewTexture != nullptr)
{
NewTexture->OnBeginDestroy().AddUObject(this, &UMediaPlayer::HandleMediaTextureBeginDestroy);
}
Player->SetVideoSink(NewTexture);
VideoTexture = NewTexture;
}
bool UMediaPlayer::SupportsRate(float Rate, bool Unthinned) const
{
return Player->SupportsRate(Rate, Unthinned);
}
bool UMediaPlayer::SupportsScrubbing() const
{
return Player->SupportsScrubbing();
}
bool UMediaPlayer::SupportsSeeking() const
{
return Player->SupportsSeeking();
}
#if WITH_EDITOR
void UMediaPlayer::PausePIE()
{
WasPlayingInPIE = IsPlaying();
if (WasPlayingInPIE)
{
Pause();
}
}
void UMediaPlayer::ResumePIE()
{
if (WasPlayingInPIE)
{
Play();
}
}
#endif
/* UObject overrides
*****************************************************************************/
void UMediaPlayer::BeginDestroy()
{
Super::BeginDestroy();
FlushRenderingCommands();
Close();
SetOverlays(nullptr);
SetSoundWave(nullptr);
SetVideoTexture(nullptr);
}
FString UMediaPlayer::GetDesc()
{
return TEXT("UMediaPlayer");
}
void UMediaPlayer::PostLoad()
{
Super::PostLoad();
if (Overlays != nullptr)
{
Overlays->OnBeginDestroy().AddUObject(this, &UMediaPlayer::HandleMediaOverlaysBeginDestroy);
}
if (SoundWave != nullptr)
{
SoundWave->OnBeginDestroy().AddUObject(this, &UMediaPlayer::HandleMediaSoundWaveBeginDestroy);
}
if (VideoTexture != nullptr)
{
VideoTexture->OnBeginDestroy().AddUObject(this, &UMediaPlayer::HandleMediaTextureBeginDestroy);
}
}
#if WITH_EDITOR
void UMediaPlayer::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
const FName PropertyName = (PropertyChangedEvent.Property != nullptr)
? PropertyChangedEvent.Property->GetFName()
: NAME_None;
if (PropertyName == GET_MEMBER_NAME_CHECKED(UMediaPlayer, Overlays))
{
SetOverlays(Overlays);
}
else if (PropertyName == GET_MEMBER_NAME_CHECKED(UMediaPlayer, SoundWave))
{
SetSoundWave(SoundWave);
}
else if (PropertyName == GET_MEMBER_NAME_CHECKED(UMediaPlayer, VideoTexture))
{
SetVideoTexture(VideoTexture);
}
else if (PropertyName == GET_MEMBER_NAME_CHECKED(UMediaPlayer, Loop))
{
SetLooping(Loop);
}
Super::PostEditChangeProperty(PropertyChangedEvent);
}
void UMediaPlayer::PreEditChange(UProperty* PropertyAboutToChange)
{
const FName PropertyName = (PropertyAboutToChange != nullptr)
? PropertyAboutToChange->GetFName()
: NAME_None;
if (PropertyName == GET_MEMBER_NAME_CHECKED(UMediaPlayer, Overlays))
{
SetOverlays(nullptr);
}
else if (PropertyName == GET_MEMBER_NAME_CHECKED(UMediaPlayer, SoundWave))
{
SetSoundWave(nullptr);
}
else if (PropertyName == GET_MEMBER_NAME_CHECKED(UMediaPlayer, VideoTexture))
{
SetVideoTexture(nullptr);
}
Super::PreEditChange(PropertyAboutToChange);
}
#endif
/* FTickerObjectBase interface
*****************************************************************************/
bool UMediaPlayer::Tick(float DeltaTime)
{
Player->TickPlayer(DeltaTime);
typedef TWeakPtr<FMediaPlayerBase, ESPMode::ThreadSafe> FMediaPlayerBasePtr;
ENQUEUE_UNIQUE_RENDER_COMMAND_TWOPARAMETER(MediaPlayerTickRender,
FMediaPlayerBasePtr, PlayerPtr, Player,
float, DeltaTime, DeltaTime,
{
auto PinnedPlayer = PlayerPtr.Pin();
if (PinnedPlayer.IsValid())
{
PinnedPlayer->TickVideo(DeltaTime);
}
});
return true;
}
/* UMediaPlayer callbacks
*****************************************************************************/
void UMediaPlayer::HandleMediaOverlaysBeginDestroy(UMediaOverlays& DestroyedOverlays)
{
if (&DestroyedOverlays == Overlays)
{
Player->SetOverlaySink(nullptr);
}
}
void UMediaPlayer::HandleMediaSoundWaveBeginDestroy(UMediaSoundWave& DestroyedSoundWave)
{
if (&DestroyedSoundWave == SoundWave)
{
Player->SetAudioSink(nullptr);
}
}
void UMediaPlayer::HandleMediaTextureBeginDestroy(UMediaTexture& DestroyedMediaTexture)
{
if (&DestroyedMediaTexture == VideoTexture)
{
Player->SetVideoSink(nullptr);
}
}
void UMediaPlayer::HandlePlayerMediaEvent(EMediaEvent Event)
{
MediaEvent.Broadcast(Event);
switch(Event)
{
case EMediaEvent::MediaClosed:
OnMediaClosed.Broadcast();
break;
case EMediaEvent::MediaOpened:
Player->SetLooping(Loop);
if (Overlays != nullptr)
{
Player->SetOverlaySink(Overlays);
}
if (SoundWave != nullptr)
{
Player->SetAudioSink(SoundWave);
}
if (VideoTexture != nullptr)
{
Player->SetVideoSink(VideoTexture);
}
OnMediaOpened.Broadcast(Player->GetUrl());
if (PlayOnOpen)
{
Play();
}
break;
case EMediaEvent::MediaOpenFailed:
OnMediaOpenFailed.Broadcast(Player->GetUrl());
if (!Loop && (Playlist != nullptr))
{
Next();
}
break;
case EMediaEvent::PlaybackEndReached:
OnEndReached.Broadcast();
if (!Loop && (Playlist != nullptr))
{
Next();
}
break;
case EMediaEvent::PlaybackResumed:
OnPlaybackResumed.Broadcast();
break;
case EMediaEvent::PlaybackSuspended:
OnPlaybackSuspended.Broadcast();
break;
}
}