using UnityEditor;
using UnityEngine;
using UnityEngine.Video;
//-----------------------------------------------------------------------------
// Copyright 2015-2024 RenderHeads Ltd. All rights reserved.
//-----------------------------------------------------------------------------
namespace RenderHeads.Media.AVProVideo
{
///
/// The different display types that are available within AVPro
///
public enum DisplayType
{
Mesh,
Material,
uGUI,
IMGUI,
CameraFarPlane,
RenderTexture,
None
}
public class VideoPlayer_AVPro : MediaPlayer
{
#region Static Properties
///
/// Maximum number of audio tracks that can be controlled. (Read Only)
///
public readonly static ushort controlledAudioTrackMaxCount = 64; // currently no implementation within MediaPlayer
#endregion Static Properties
#region UI Properties
// private properties that are utilized by the editor script to display the correct information
[SerializeField] private MediaSource Source;
[SerializeField] private MediaReference Clip;
[SerializeField] private string Url;
private MediaPath path;
[SerializeField] private bool PlayOnAwake;
[SerializeField] private bool AutoOpening = false;
[SerializeField] private bool IsLooping;
[SerializeField] private float PlaybackSpeed = 1;
public MonoBehaviour _renderModeComponent = null;
public DisplayIMGUI displayIMGUI;
public DisplayUGUI displayUGUI;
public ApplyToMesh applyToMesh;
public ApplyToMaterial applyToMaterial;
public ApplyToFarPlane applyToFarPlane;
public ResolveToRenderTexture applyToTexture;
public DisplayType currentRenderMode;
[SerializeField] private Renderer TargetMaterialRenderer;
[SerializeField] private string TargetMateralProperty;
[SerializeField] private DisplayType RenderMode;
[SerializeField] private Material TargetMaterial;
[SerializeField] private Color Colour = Color.white;
[SerializeField] private ScaleMode AspectRatio;
[SerializeField] private VideoResolveOptions.AspectRatio AspectRatioRenderTexture;
[SerializeField] private bool Fullscreen = true;
#pragma warning disable
[SerializeField] private float TargetCameraAlpha = 1.0f;
#pragma warning restore
#if UNITY_STANDALONE_WIN
[SerializeField] private Windows.AudioOutput AudioOutputMode;
#elif UNITY_WSA_10_0
[SerializeField] public WindowsUWP.AudioOutput AudioOutputMode;
#elif UNITY_ANDROID || UNITY_IOS || UNITY_STANDALONE_OSX || UNITY_TVOS || UNITY_VISIONOS || UNITY_WEBGL
[SerializeField] public PlatformOptions.AudioMode AudioOutputMode;
#endif
[SerializeField] private ushort ControlledAudioTrackCount; // currently no implementation within MediaPlayer
[SerializeField] private float Volume = 1f;
[SerializeField] private bool Muted;
[SerializeField] private AudioSource AudioSourceE;
[SerializeField] private RenderTexture TargetTexture;
[SerializeField] private Rect UVRect = new Rect(0f, 0f, 1f, 1f);
public GameObject canvasObj;
public bool _converted = false;
#endregion UI Properties
#region Accessible Properties
// accessible via script
///
/// The source that the uses for playback.
/// AVPro:
///
/// - converts from Unity's to AVPro's
/// - Stored within
///
///
public VideoSource source
{
get
{
if (sourceAVPro == MediaSource.Reference)
return VideoSource.VideoClip;
return VideoSource.Url;
}
set
{
if (value == VideoSource.VideoClip)
sourceAVPro = MediaSource.Reference;
else
sourceAVPro = MediaSource.Path;
}
}
///
/// The source that the will use for playback
///
public MediaSource sourceAVPro
{
get { return Source; }
set { Source = value; SetMediaSource(value); }
}
///
/// The clip being played by the .
///
public MediaReference clip { get { return Clip; } set { SetMediaReference(value); Clip = value; } }
///
/// The file or HTTP URL that the reads content from.
/// AVPro - utilizes to store
/// Will automatically set the path type of the
///
public MediaPath url
{
get { return path; }
set
{
if (value.PathType == MediaPathType.AbsolutePathOrURL)
{
Source = MediaSource.Path;
SetMediaSource(MediaSource.Path);
}
path = value;
Url = value.Path;
SetMediaPath(value);
}
}
///
/// Whether the content will start playing back as soon as the component awakes.
///
public bool playOnAwake { get { return PlayOnAwake; } set { PlayOnAwake = value; AutoStart = value; } }
///
/// Determines whether the restarts from the beginning when it reaches the end of the clip.
///
public bool isLooping { get { return IsLooping; } set { IsLooping = value; Loop = value; } }
///
/// Factor by which the basic playback rate will be multiplied.
///
public float playbackSpeed
{
get { return PlaybackSpeed; }
set
{
if (!canSetPlaybackSpeed)
return;
PlaybackSpeed = value; PlaybackRate = value;
}
}
///
/// which is targeted when is set to
///
public Renderer targetMaterialRenderer { get { return TargetMaterialRenderer; } set { TargetMaterialRenderer = value; } }
///
/// texture property which is targeted when is set to:
///
/// ,
///
///
///
public string targetMateralProperty { get { return TargetMateralProperty; } set { TargetMateralProperty = value; } }
///
/// that is targeted when is set to
///
public Material targetMaterial
{
get { return TargetMaterial; }
set
{
TargetMaterial = value;
if (displayUGUI)
displayUGUI.material = value;
if (applyToMaterial)
applyToMaterial.Material = value;
}
}
///
/// Where/how the video content will be drawn.
/// Recomended to convert to using with otherwise unexpected behaviour may occur
/// AVPro:
///
/// - converts from Unity's to AVPro's
/// - Stored within
///
///
public VideoRenderMode renderMode
{
get
{
LogAutomaticConversion("DisplayType", "VideoRenderMode");
switch (rendererMode)
{
case DisplayType.IMGUI:
return VideoRenderMode.CameraNearPlane;
case DisplayType.uGUI:
case DisplayType.RenderTexture:
return VideoRenderMode.RenderTexture;
case DisplayType.Material:
return VideoRenderMode.MaterialOverride;
case DisplayType.Mesh:
return VideoRenderMode.APIOnly;
case DisplayType.CameraFarPlane:
return VideoRenderMode.CameraFarPlane;
default:
return VideoRenderMode.CameraNearPlane;
}
}
set
{
LogAutomaticConversion("VideoRenderMode", "DisplayType");
switch (value)
{
case UnityEngine.Video.VideoRenderMode.CameraFarPlane:
rendererMode = DisplayType.CameraFarPlane;
break;
case UnityEngine.Video.VideoRenderMode.CameraNearPlane:
rendererMode = DisplayType.IMGUI;
break;
case UnityEngine.Video.VideoRenderMode.RenderTexture:
rendererMode = DisplayType.RenderTexture;
break;
case UnityEngine.Video.VideoRenderMode.MaterialOverride:
rendererMode = DisplayType.Material;
break;
case UnityEngine.Video.VideoRenderMode.APIOnly:
rendererMode = DisplayType.None;
break;
}
}
}
///
/// Where/how the video content will be drawn.
/// will create the desired components when renderer mode is changed
///
public DisplayType rendererMode
{
get { return RenderMode; }
set
{
RenderMode = value;
// need to check for change and then create components
if (currentRenderMode != rendererMode)
{
currentRenderMode = rendererMode;
CreateRendererComponents();
}
}
}
///
/// Defines how the video content will be stretched to fill the target area.
///
public ScaleMode aspectRatio
{
get { return AspectRatio; }
set
{
AspectRatio = value;
if (rendererMode == DisplayType.uGUI)
displayUGUI.ScaleMode = value;
if (rendererMode == DisplayType.IMGUI)
displayIMGUI.ScaleMode = value;
else
return;
}
}
///
/// used specifically for & otherwise the same as
///
public VideoResolveOptions.AspectRatio aspectRatioRenderTexture
{
get
{
return AspectRatioRenderTexture;
}
set
{
AspectRatioRenderTexture = value;
if (rendererMode == DisplayType.RenderTexture)
{
// :(
var options = applyToTexture.VideoResolveOptions;
options.aspectRatio = value;
applyToTexture.VideoResolveOptions = options;
}
if (applyToFarPlane)
applyToFarPlane.VideoAspectRatio = (VideoAspectRatio)(int)value;
}
}
///
/// Destination for the audio embedded in the video.
///
#if UNITY_STANDALONE_WIN
public VideoAudioOutputMode audioOutputMode
{
get
{
switch (audioOutputModeAVPro)
{
case Windows.AudioOutput.None:
return UnityEngine.Video.VideoAudioOutputMode.None;
case Windows.AudioOutput.Unity:
return UnityEngine.Video.VideoAudioOutputMode.AudioSource;
case Windows.AudioOutput.System:
case Windows.AudioOutput.FacebookAudio360:
return UnityEngine.Video.VideoAudioOutputMode.Direct;
}
return UnityEngine.Video.VideoAudioOutputMode.APIOnly;
}
set
{
switch (value)
{
case UnityEngine.Video.VideoAudioOutputMode.None:
audioOutputModeAVPro = Windows.AudioOutput.None;
break;
case UnityEngine.Video.VideoAudioOutputMode.AudioSource:
audioOutputModeAVPro = Windows.AudioOutput.Unity;
break;
case UnityEngine.Video.VideoAudioOutputMode.Direct:
case UnityEngine.Video.VideoAudioOutputMode.APIOnly:
audioOutputModeAVPro = Windows.AudioOutput.System;
break;
}
}
}
#elif UNITY_WSA_10_0
public VideoAudioOutputMode audioOutputMode
{
get
{
switch (audioOutputModeAVPro)
{
case WindowsUWP.AudioOutput.Unity:
return UnityEngine.Video.VideoAudioOutputMode.AudioSource;
case WindowsUWP.AudioOutput.System:
case WindowsUWP.AudioOutput.FacebookAudio360:
return UnityEngine.Video.VideoAudioOutputMode.Direct;
}
return UnityEngine.Video.VideoAudioOutputMode.Direct;
}
set
{
switch (value)
{
case UnityEngine.Video.VideoAudioOutputMode.None:
audioOutputModeAVPro = WindowsUWP.AudioOutput.None;
break;
case UnityEngine.Video.VideoAudioOutputMode.AudioSource:
audioOutputModeAVPro = WindowsUWP.AudioOutput.Unity;
break;
case UnityEngine.Video.VideoAudioOutputMode.Direct:
case UnityEngine.Video.VideoAudioOutputMode.APIOnly:
audioOutputModeAVPro = WindowsUWP.AudioOutput.System;
break;
}
}
}
#elif UNITY_ANDROID || UNITY_WEBGL || UNITY_IOS || UNITY_STANDALONE_OSX || UNITY_TVOS || UNITY_VISIONOS
public VideoAudioOutputMode audioOutputMode
{
get
{
switch (audioOutputModeAVPro)
{
case PlatformOptions.AudioMode.Unity:
return UnityEngine.Video.VideoAudioOutputMode.AudioSource;
case PlatformOptions.AudioMode.SystemDirect:
case PlatformOptions.AudioMode.FacebookAudio360:
return UnityEngine.Video.VideoAudioOutputMode.Direct;
}
return UnityEngine.Video.VideoAudioOutputMode.Direct;
}
set
{
switch (value)
{
case UnityEngine.Video.VideoAudioOutputMode.None:
audioOutputModeAVPro = PlatformOptions.AudioMode.SystemDirect;
break;
case UnityEngine.Video.VideoAudioOutputMode.AudioSource:
audioOutputModeAVPro = PlatformOptions.AudioMode.Unity;
break;
case UnityEngine.Video.VideoAudioOutputMode.Direct:
case UnityEngine.Video.VideoAudioOutputMode.APIOnly:
audioOutputModeAVPro = PlatformOptions.AudioMode.SystemDirect;
break;
}
}
}
#endif
///
/// Destination for the audio embedded in the video.
///
#if UNITY_STANDALONE_WIN
public Windows.AudioOutput audioOutputModeAVPro
{
get { return AudioOutputMode; }
set { AudioOutputMode = value; PlatformOptionsWindows._audioMode = value; CreateAudioComponents(); }
}
#elif UNITY_WSA_10_0
public WindowsUWP.AudioOutput audioOutputModeAVPro
{
get { return AudioOutputMode; }
set { AudioOutputMode = value; PlatformOptionsWindowsUWP._audioMode = value; CreateAudioComponents(); }
}
#else
public PlatformOptions.AudioMode audioOutputModeAVPro
{
get { return AudioOutputMode; }
#if UNITY_ANDROID
set { AudioOutputMode = value; PlatformOptionsAndroid.audioMode = value; CreateAudioComponents(); }
#elif UNITY_WEBGL
//set { AudioOutputMode = value; PlatformOptionsWebGL.audioMode = value; CreateAudioComponents(); }
#elif UNITY_IOS
set { AudioOutputMode = value; PlatformOptions_iOS.audioMode = value; CreateAudioComponents(); }
#elif UNITY_STANDALONE_OSX
set { AudioOutputMode = value; PlatformOptions_macOS.audioMode = value; CreateAudioComponents(); }
#elif UNITY_TVOS
set { AudioOutputMode = value; PlatformOptions_tvOS.audioMode = value; CreateAudioComponents(); }
#elif UNITY_VISIONOS
set { AudioOutputMode = value; PlatformOptions_visionOS.audioMode = value; CreateAudioComponents(); }
#endif
}
#endif
///
/// property which is targeted when is set to:
///
/// ,
/// ,
///
///
///
public Color color
{
get { return Colour; }
set
{
Colour = value;
if (displayIMGUI)
displayIMGUI.Color = value;
else if (applyToTexture)
{
var options = applyToTexture.VideoResolveOptions;
options.tint = value;
applyToTexture.VideoResolveOptions = options;
}
else if (displayUGUI)
displayUGUI.color = value;
else if (applyToFarPlane)
applyToFarPlane.MainColor = value;
}
}
///
/// used to toggle fullscreen when is set to:
///
///
public bool fullScreen
{
get { return Fullscreen; }
set
{
Fullscreen = value;
if (displayIMGUI)
displayIMGUI.IsAreaFullScreen = value;
}
}
///
/// Used to change the volume of the audio
///
public float volume
{
get
{
if (GetDirectAudioVolume(0) != Volume)
Volume = GetDirectAudioVolume(0);
return Volume;
}
set
{
Volume = value;
#if UNITY_STANDALONE_WIN
if (audioOutputModeAVPro == Windows.AudioOutput.Unity && AudioSource)
#elif UNITY_WSA_10_0
if (audioOutputModeAVPro == WindowsUWP.AudioOutput.Unity && AudioSource)
#elif UNITY_ANDROID || UNITY_IOS || UNITY_STANDALONE_OSX || UNITY_TVOS || UNITY_VISIONOS
if (audioOutputModeAVPro == PlatformOptions.AudioMode.Unity && AudioSource)
#endif
{
AudioSource.volume = value;
}
SetDirectAudioVolume(0, value);
}
}
///
/// used to toggle weather or not the audio is muted
///
public bool muted
{
get { return Muted; }
set
{
Muted = value;
AudioMuted = value;
#if UNITY_STANDALONE_WIN
if (audioOutputModeAVPro == Windows.AudioOutput.Unity && AudioSource)
AudioSource.mute = value;
#elif UNITY_WSA_10_0
if (audioOutputModeAVPro == WindowsUWP.AudioOutput.Unity && AudioSource)
AudioSource.mute = value;
#elif UNITY_ANDROID || UNITY_IOS || UNITY_STANDALONE_OSX || UNITY_TVOS || UNITY_VISIONOS
if (audioOutputModeAVPro == PlatformOptions.AudioMode.Unity && AudioSource)
AudioSource.mute = value;
#endif
}
}
///
/// The to use when is set to
///
public AudioSource audioSource { get { return AudioSourceE; } set { AudioSourceE = value; SetAudioSource(value); } }
///
/// The to use to control texture scaling/offset when is set to
///
public Rect uvRect
{
get { return UVRect; }
set
{
UVRect = value;
if (rendererMode == DisplayType.uGUI && displayUGUI)
displayUGUI.uvRect = uvRect;
}
}
// General Parameters
///
/// Number of audio tracks found in the data source currently configured. (Read Only)
///
/// 0 if not prepared; otherwise the number of audio tracks on the current media
public ushort audioTrackCount { get { if (AudioTracks != null )return (ushort)AudioTracks.GetAudioTracks().Count; return 0; } private set { } }
///
/// The clock time that the VideoPlayer follows to schedule its samples. The clock time is expressed in seconds. (Read Only)
///
/// -1 if not initilised; otherwise the current clock time
public double clockTime
{
get
{
if (UseResampler && FrameResampler != null) // may not be used as FrameResampler is optional
return (double)FrameResampler.ElapsedTimeSinceBase;
else if (Info != null)
{
// determin the total frames based on the fact that we know the missed frames, and we know our perfect percent
// so turn other into a percent, calc the difference the work backwords to calculate total frames
// from their use the framerate of the video to determine total time spent
var qualStats = Info.GetPlaybackQualityStats();
var totalOtherFrames = qualStats.DuplicateFrames + qualStats.UnityDroppedFrames + qualStats.SkippedFrames;
var totalOtherPercent = 1.0f - qualStats.PerfectFramesT;
var totalFrames = (totalOtherFrames / totalOtherPercent) + totalOtherFrames;
var time = totalFrames * (long)(Helper.SecondsToHNS / Info.GetVideoFrameRate()); // total * time per frame
return time;
}
return -1;
}
private set { }
}
///
/// Reference time of the external clock the VideoPlayer uses to correct its drift.
/// AVPro - this returns which is not the same functionality as VideoPlayer
///
public double externalReferenceTime { get { if (_baseMediaPlayer != null) return _baseMediaPlayer.GetCurrentTime(); return -1; } private set { } }
///
/// Returns the current video time in frames
///
public long frame { get { if (Control != null) return (long)Control.GetCurrentTimeFrames(); return -1; } set { if (canSetTime && Control != null) Control.SeekToFrame((int)value); } }
///
/// Number of frames in the current video content. (Read Only)
///
public ulong frameCount { get { if (Info != null) return (ulong)Info.GetMaxFrameNumber(); return 0; } private set { } }
///
/// he frame rate of the clip or URL in frames/second. (Read Only)
///
public float frameRate { get { if (Info != null) return Info.GetVideoFrameRate(); return -1; } private set { } }
///
/// The height of the images in the VideoClip, or URL, in pixels. (Read Only)
///
public uint height { get { if (Info != null) return (uint)Info.GetVideoHeight(); return 0; } private set { } }
///
/// Whether playback is paused. (Read Only)
///
public bool isPaused { get { if (Control != null) return Control.IsPaused(); return false; } private set { } }
///
/// Whether content is being played. (Read Only)
///
public bool isPlaying { get { if (Control != null) return Control.IsPlaying(); return false; } private set { } }
///
/// Whether the VideoPlayer has successfully prepared the content to be played. (Read Only)
///
public bool isPrepared { get { if (Application.isPlaying) { return Control.CanPlay(); } return false; } private set { } }
///
/// The length of the VideoClip, or the URL, in seconds. (Read Only)
///
public double length { get { if (Info != null) return Info.GetDuration(); return -1; } private set { } }
///
/// Internal texture in which video content is placed. (Read Only)
///
public Texture texture
{
get { if (TextureProducer != null) return TextureProducer.GetTexture(); return null; }
private set { }
}
///
/// The presentation time of the currently available frame in VideoPlayer.texture.
///
public double time
{
get { if (Control != null) return Control.GetCurrentTime(); return -1; }
set
{
if (canSetTime && Control != null)
Control.SeekFast(value);
}
}
///
/// The width of the images in the VideoClip, or URL, in pixels. (Read Only)
///
public uint width { get { if (Info != null) return (uint)Info.GetVideoWidth(); return 0; } private set { } }
///
/// overall alpha being applied to the color on the respective component
///
public float targetCameraAlpha
{
get
{
try
{
switch (rendererMode)
{
case DisplayType.uGUI:
return displayUGUI.color.a;
case DisplayType.IMGUI:
return displayIMGUI.Color.a;
case DisplayType.Mesh:
return applyToMesh.MeshRenderer.material.color.a;
case DisplayType.Material:
return applyToMaterial.Material.color.a;
case DisplayType.CameraFarPlane:
return applyToFarPlane.Alpha;
case DisplayType.RenderTexture:
var options = applyToTexture.VideoResolveOptions;
return options.tint.a;
}
}
catch { return 0f; } // fails due to properties in display component no being set
return 0f;
}
set
{
try
{
switch (rendererMode)
{
case DisplayType.uGUI:
displayUGUI.color = new Color(displayUGUI.color.r, displayUGUI.color.g, displayUGUI.color.b, value);
break;
case DisplayType.IMGUI:
displayIMGUI.Color = new Color(displayIMGUI.Color.r, displayIMGUI.Color.g, displayIMGUI.Color.b, value);
break;
case DisplayType.Mesh:
applyToMesh.MeshRenderer.material.color = new Color(
applyToMesh.MeshRenderer.material.color.r, applyToMesh.MeshRenderer.material.color.g, applyToMesh.MeshRenderer.material.color.b, value);
break;
case DisplayType.Material:
applyToMaterial.Material.color = new Color(
applyToMaterial.Material.color.r, applyToMaterial.Material.color.g, applyToMaterial.Material.color.b, value);
break;
case DisplayType.CameraFarPlane:
applyToFarPlane.Alpha = value;
break;
case DisplayType.RenderTexture:
var options = applyToTexture.VideoResolveOptions;
options.tint = new Color(
options.tint.r, options.tint.g, options.tint.b, value);
applyToTexture.VideoResolveOptions = options;
break;
}
}
catch { return; }
}
}
///
/// to draw to when is set to .
///
public RenderTexture targetTexture
{
get
{
if (applyToTexture)
return applyToTexture.ExternalTexture;
return null;
}
set { if (applyToTexture) applyToTexture.ExternalTexture = value; }
}
///
/// Camera component to draw to when VideoPlayer.renderMode is set to either VideoRenderMode.CameraFarPlane or VideoRenderMode.CameraNearPlane.
///
public Camera targetCamera
{
get { if (applyToFarPlane) return applyToFarPlane.Camera; return null; }
set { if (applyToFarPlane) applyToFarPlane.Camera = value; }
}
///
/// Whether direct-output volume controls are supported for the current platform and video format. (Read Only)
/// only possible when the video has been prepared
///
public bool canSetDirectAudioVolume { get { if (isPrepared) return true; return false; } private set { } }
///
/// Whether you can change the playback speed. (Read Only)
/// only possible when the video has been prepared
///
public bool canSetPlaybackSpeed { get { if (isPrepared) return true; return false; } private set { } }
///
/// Whether frame-skipping to maintain synchronization can be controlled. (Read Only)
/// only possible when the video has been prepared.
/// Warning Although This functions, has no functionality within AVPro
///
public bool canSetSkipOnDrop { get { if (isPrepared) return true; return false; } private set { } }
///
/// Whether you can change the current time using the time or frames property. (Read Only)
/// Only Possible when the video has been prepared.
///
public bool canSetTime { get { if (isPrepared) return true; return false; } private set { } }
///
/// Whether you can change the time source followed by the VideoPlayer. (Read Only)
/// Warning Although This functions, has no functionality within AVPro
///
public bool canSetTimeUpdateMode { get { if (isPrepared) return true; return false; } private set { } }
///
/// Returns true if the VideoPlayer can step forward through the video content. (Read Only)
///
public bool canStep { get { if (isPrepared) return true; return false; } private set { } }
///
/// Number of audio tracks that this VideoPlayer will take control of.
/// Warning AVPro currently only supports 1 active audio track
///
public int controlledAudioTrackCount { get { return 1; } set { /*Nothing as always 1*/ } }
// No Implementation/Functionality within AVPro
///
/// Denominator of the pixel aspect ratio (num:den) for the VideoClip or the URL. (Read Only)
/// Warning AVPro Does not currently support this
///
public uint pixelAspectRationDenominator{ get { LogNoSimWarning("pixelAspectRationDenominator"); return 1; } private set { } }
///
/// Numerator of the pixel aspect ratio (num:den) for the VideoClip or the URL. (Read Only)
/// Warning AVPro Does not currently support this
///
public uint pixelAspectRationNumerator { get { LogNoSimWarning("pixelAspectRationNumerator"); return 1; } private set { } }
///
/// Whether the VideoPlayer is allowed to skip frames to catch up with current time.
/// Warning AVPro does not currently support this
///
public bool skipOnDrop { get { LogNoSimWarning("skipOnDrop"); return false; } set { LogNoSimWarning("skipOnDrop"); } }
///
/// Type of 3D content contained in the source video media.
/// Warning AVPro does not currently support this
///
public int targetCamera3DLayout { get { LogNoSimWarning("targetCamera3DLayout"); return 0; } set { LogNoSimWarning("targetCamera3DLayout"); } }
///
/// The clock that the VideoPlayer observes to detect and correct drift.
/// Warning AVPro does not currently support this
///
public int timeReference { get { LogNoSimWarning("timeReference"); return 0; } set { LogNoSimWarning("timeReference"); } }
///
/// The clock source used by the VideoPlayer to derive its current time.
/// Warning AVPro does not currently support this
///
#if UNITY_2022_3_OR_NEWER
public UnityEngine.Video.VideoTimeUpdateMode timeUpdateMode { get { LogNoSimWarning("timeUpdateMode"); return 0; } set { LogNoSimWarning("timeUpdateMode"); } }
///
/// Determines whether the VideoPlayer will wait for the first frame to be loaded into the texture before starting playback when VideoPlayer.playOnAwake is on.
/// Warning AVPro does not currently support this
///
#endif
public bool WaitForFirstFrame { get { LogNoSimWarning("WaitForFirstFrame"); return true; } set { LogNoSimWarning("WaitForFirstFrame"); } }
///
/// Warning AVPro does not currently support this
///
public bool sendFrameReadyEvents;
#endregion Accessible Properties
#region Events & Delegates
public delegate void EventHandler(VideoPlayer_AVPro source);
public delegate void ErrorEventHandler(VideoPlayer_AVPro source, string message);
public delegate void FrameReadyEventHandler(VideoPlayer_AVPro source, long frameIdx);
public delegate void TimeEventHandler(VideoPlayer_AVPro source, double seconds);
public event EventHandler prepareCompleted; // ReadyToPlay
public event EventHandler started; // Started
public event ErrorEventHandler errorReceived; // Error
public event EventHandler seekCompleted; // FinishedSeeking
public event FrameReadyEventHandler frameReady; // Not Supported
public event EventHandler loopPointReached; // Not Supported
public event EventHandler frameDropped; // Not Supported
public event TimeEventHandler clockResyncOccurred; // Not Supported
///
/// Used to simulate and invoke the events
///
/// The this event came from
/// The type of event to invoke
/// The error code to show
public void EventCallbacks(MediaPlayer mediaPlayer, MediaPlayerEvent.EventType eventType, ErrorCode errorCode)
{
switch (eventType)
{
case MediaPlayerEvent.EventType.ReadyToPlay:
prepareCompleted?.Invoke((VideoPlayer_AVPro)mediaPlayer);
break;
case MediaPlayerEvent.EventType.Started:
started?.Invoke((VideoPlayer_AVPro)mediaPlayer);
break;
case MediaPlayerEvent.EventType.Error:
errorReceived?.Invoke((VideoPlayer_AVPro)mediaPlayer, errorCode.ToString());
break;
case MediaPlayerEvent.EventType.FinishedSeeking:
seekCompleted?.Invoke((VideoPlayer_AVPro)mediaPlayer);
break;
default:
if (loopPointReached != null)
{
if (loopPointReached.GetInvocationList().Length > 0)
LogNoSimWarning("loopPointReached Event", "AVPro does not contain a event callback for when the loop point is reached");
}
if (frameDropped != null)
{
if (frameDropped.GetInvocationList().Length > 0)
LogNoSimWarning("frameDropped Event", "AVPro does not contain a event callback for when a frame is dropped");
}
if (clockResyncOccurred != null)
{
if (clockResyncOccurred.GetInvocationList().Length > 0)
LogNoSimWarning("clockResyncOccurred Event", "AVPro does not contain a event callback for when clock resync is restored");
}
if (frameReady != null)
{
if (frameReady.GetInvocationList().Length > 0)
LogNoSimWarning("frameReady Event", "AVPro does not contain a event callback for when each frame is ready, it does have one for " +
"when the first frame is ready though");
}
break;
}
}
#endregion Events & Delegates
#region Public Methods
///
/// VideoRecord:
/// - Enable/disable audio track decoding. Only effective when the is not currently playing
/// AVPro:
/// - Changes current active audio track. Only effective when not currently playing.
/// - Will Mute the track if enabled is set to false
///
/// Index of the audio track to change to.
/// True for enabling the track. False for disabling the track.
public void EnableAudioTrack(ushort trackIndex, bool enabled)
{
// cant change if already playing
if (Control.IsPlaying())
{
Debug.LogWarning("Audio track not changed, warning you cannot change audio track whilst playing the media");
return;
}
AudioTracks audioTracks = AudioTracks.GetAudioTracks();
// no need to do anything if their are no audio tracks
if (audioTracks.Count == 0)
{
Debug.LogWarning("Warning: their are currenrly no audio tracks");
return;
}
// no need to change if already set
if (audioTracks[trackIndex] == AudioTracks.GetActiveAudioTrack())
return;
if (trackIndex >= audioTracks.Count)
{
Debug.LogError($"Error: trackIndex ({trackIndex}) is larger than total audioTrack count ({audioTracks.Count})");
return;
}
AudioTracks.SetActiveAudioTrack(audioTracks[trackIndex]);
Control.MuteAudio(enabled);
}
///
/// The number of audio channels in the specified audio track.
///
/// Index for the audio track being queried.
/// ushort Number of audio channels.
public ushort GetAudioChannelCount(ushort trackIndex)
{
AudioTracks audioTracks = AudioTracks.GetAudioTracks();
if (trackIndex >= audioTracks.Count)
{
Debug.LogError($"Error: trackIndex ({trackIndex}) is larger than total audioTrack count ({audioTracks.Count})");
return 0;
}
return (ushort)audioTracks[trackIndex].ChannelCount;
}
///
/// Returns the language code, if any, for the specified track.
///
/// index of the audio track to query
/// string> Language Code
public string GetAudioLanguageCode(ushort trackIndex)
{
AudioTracks audioTracks = AudioTracks.GetAudioTracks();
if (trackIndex >= audioTracks.Count)
{
Debug.LogError($"Error: trackIndex ({trackIndex}) is larger than total audioTrack count ({audioTracks.Count})");
return null;
}
return audioTracks[trackIndex].Language;
}
///
/// VideoPlayer:
/// - Returns the audio track sampling rate in Hertz.
/// AVPro:
/// - Returns the unity AudioSettings global sampleRate
///
/// index of the audio track to query
/// uint> The sampling rate in Hertz.
public uint GetAudioSampleRate(ushort trackIndex)
{
return (uint)((AudioSettings.GetConfiguration().sampleRate == 0) ? 0 : AudioSettings.outputSampleRate);
}
///
/// VideoRecord:
/// - Gets the direct-output audio mute status for the specified track.
/// AVPro:
/// - retruns the global mute state, as currently, tracks have no recognition
/// of volume and muted, these are handled globally.
///
/// index of the audio track to query
/// true if the selected track is muted; otherwise false
public bool GetDirectAudioMute(ushort trackIndex)
{
return AudioMuted;
}
///
/// AVPro:
/// - retruns the global volume, as currently, tracks have no recognition
/// of volume and muted, these are handled globally.
///
/// index of the audio track to query
/// float Volume, between 0 and 1.
public float GetDirectAudioVolume(ushort trackIndex)
{
return AudioVolume;
}
///
/// Gets the AudioSource that will receive audio samples for the specified track if VideoApi is set to
#if UNITY_STANDALONE_WIN || UNITY_WSA_10_0
/// Media Foundation.
#elif UNITY_ANDROID
/// ExoPlayer.
#elif UNITY_IOS || UNITY_STANDALONE_OSX || UNITY_TVOS || UNITY_VISIONOS
/// any option
#endif
/// and the Audio mode is set to output in unity
///
/// AVPro:
/// - index is not used as 1 audio source is used
///
/// Index of the audio track for which the AudioSource is wanted
/// AudioSource if correct output selected
public AudioSource GetTargetSource(ushort trackIndex)
{
#if UNITY_STANDALONE_WIN
if (PlatformOptionsWindows.videoApi == Windows.VideoApi.MediaFoundation &&
PlatformOptionsWindows._audioMode == Windows.AudioOutput.Unity)
#elif UNITY_WSA_10_0
if (PlatformOptionsWindowsUWP.videoApi == WindowsUWP.VideoApi.MediaFoundation &&
PlatformOptionsWindowsUWP._audioMode == WindowsUWP.AudioOutput.Unity)
#elif UNITY_ANDROID
if (PlatformOptionsAndroid.videoApi == Android.VideoApi.ExoPlayer &&
PlatformOptionsAndroid.audioMode == PlatformOptions.AudioMode.Unity)
#elif UNITY_IOS
if (PlatformOptions_iOS.audioMode == PlatformOptions.AudioMode.Unity)
#elif UNITY_STANDALONE_OSX
if (PlatformOptions_macOS.audioMode == PlatformOptions.AudioMode.Unity)
#elif UNITY_TVOS
if (PlatformOptions_tvOS.audioMode == PlatformOptions.AudioMode.Unity)
#elif UNITY_VISIONOS
if (PlatformOptions_visionOS.audioMode == PlatformOptions.AudioMode.Unity)
#else
return null;
#endif
{
return AudioSource;
}
return null;
}
///
/// Wherther the current track is the active audio track
///
/// Index of the audio track being queried
/// bool Returns true if the specified track is enabled
public bool IsAudioTrackEnabled(ushort trackIndex)
{
AudioTracks audioTracks = AudioTracks.GetAudioTracks();
if (trackIndex >= audioTracks.Count)
{
Debug.LogError($"Error: trackIndex ({trackIndex}) is larger than total audioTrack count ({audioTracks.Count})");
return false;
}
AudioTrack activeTrack = AudioTracks.GetActiveAudioTrack();
if (audioTracks[trackIndex] == activeTrack)
return true;
return false;
}
///
/// Pauses Playback
///
public new void Pause()
{
base.Pause();
}
///
/// Plays the media, ensuring the appropriate display components are enabled based on the current renderer mode.
///
public new void Play()
{
if (!MediaOpened)
{
base.OpenMedia();
}
// as the stop can disable the display and nothing might happen inbetween need to enable again if it is their and if it is active
switch (rendererMode)
{
case DisplayType.Mesh:
if (applyToMesh) applyToMesh.enabled = true;
break;
case DisplayType.Material:
if (applyToMaterial) applyToMaterial.enabled = true;
break;
case DisplayType.uGUI:
if (displayUGUI) displayUGUI.enabled = true;
break;
case DisplayType.IMGUI:
if (displayIMGUI) displayIMGUI.enabled = true;
break;
case DisplayType.CameraFarPlane:
if (applyToFarPlane) applyToFarPlane.enabled = true;
break;
case DisplayType.RenderTexture:
if (applyToTexture) applyToTexture.enabled = true;
break;
}
base.Play();
}
///
/// Initilises the Media Player, to start beign able to play
/// Will Create the base media player and initilize it
///
public void Prepare()
{
// Note: not 100% on this one, as the docs are a little short, they say that it preloads the video in this step as well,
// so do i put a OpenMedia() call here as well, but that can automatically start the playback which we dont want to do.
// so will have to set to false, but ehh.
Initialise();
OpenMedia(false);
}
///
/// - Sets the global direct-output audio mute status
///
/// index of the audio track to query
/// Mute on/off
public void SetDirectAudioMute(ushort trackIndex, bool mute)
{
AudioMuted = mute;
}
///
/// - Set the global direct-output volume
///
/// index of the audio track to query
/// float Volume, between 0 and 1.
public void SetDirectAudioVolume(ushort trackIndex, float volume)
{
if (canSetDirectAudioVolume)
{
AudioVolume = volume;
}
}
///
/// Sets the AudioSource that will receive audio samples for the specified track if using AudioSource
///
/// Index of the audio track to associate with the specified AudioSource.
/// AudioSource to associate with the audio track.
public void SetTargetAudioSource(ushort trackIndex, AudioSource source)
{
#if UNITY_STANDALONE_WIN
if (PlatformOptionsWindows.videoApi == Windows.VideoApi.MediaFoundation &&
PlatformOptionsWindows._audioMode == Windows.AudioOutput.Unity)
#elif UNITY_WSA_10_0
if (PlatformOptionsWindowsUWP.videoApi == WindowsUWP.VideoApi.MediaFoundation &&
PlatformOptionsWindowsUWP._audioMode == WindowsUWP.AudioOutput.Unity)
#elif UNITY_ANDROID
if (PlatformOptionsAndroid.videoApi == Android.VideoApi.ExoPlayer &&
PlatformOptionsAndroid.audioMode == PlatformOptions.AudioMode.Unity)
#elif UNITY_IOS
if (PlatformOptions_iOS.audioMode == PlatformOptions.AudioMode.Unity)
#elif UNITY_STANDALONE_OSX
if (PlatformOptions_macOS.audioMode == PlatformOptions.AudioMode.Unity)
#elif UNITY_TVOS
if (PlatformOptions_tvOS.audioMode == PlatformOptions.AudioMode.Unity)
#elif UNITY_VISIONOS
if (PlatformOptions_visionOS.audioMode == PlatformOptions.AudioMode.Unity)
#else
return;
#endif
{
SetAudioSource(source);
}
}
///
/// Advances the current time by one frame immediately
///
public void StepForward()
{
if (!canStep)
return;
int currentFrame = Control.GetCurrentTimeFrames();
Control.SeekToFrame(currentFrame + 1);
Control.SeekToFrameRelative(1);
}
///
/// Stops playback and set current playback time to 0
///
public new void Stop()
{
if (Control == null)
return;
// disable the rendering of the video (this is what VideoPlayer does)
switch (rendererMode)
{
case DisplayType.Mesh:
if (applyToMesh) applyToMesh.enabled = false;
break;
case DisplayType.Material:
if (applyToMaterial) applyToMaterial.enabled = false;
break;
case DisplayType.uGUI:
if (displayUGUI) displayUGUI.enabled = false;
break;
case DisplayType.IMGUI:
if (displayIMGUI) displayIMGUI.enabled = false;
break;
case DisplayType.CameraFarPlane:
if (applyToFarPlane) applyToFarPlane.enabled = false;
break;
case DisplayType.RenderTexture:
if (applyToTexture) applyToTexture.enabled = false;
break;
}
// set the current time to 0
Control.SeekToFrame(0);
base.Stop();
}
#endregion Public Methods
#region Conversion
// only do the context menu things when in the editor, where they will run, if not like this will crash on build as
// editor no longer exists
#if UNITY_EDITOR
///
/// Converts the attached VideoPlayer componenet on an object to a VideoPlayer_AVPro, through the context menu of the script
///
/// Allows for the getting of the object the command was sent from, to allow for the adding of the AVPro component
[MenuItem("CONTEXT/VideoPlayer/Convert To VideoPlayer_AVPro")]
public static void VideoPlayerTo_AVPro_MenuItem(MenuCommand command)
{
var obj = ((VideoPlayer)command.context).gameObject;
if (!obj.TryGetComponent(out VideoPlayer_AVPro player))
player = obj.AddComponent();
player._converted = true;
player.VideoPlayertoAVProConversion();
}
///
/// Adds a context menu option to VideoPlayer_AVPro that will copy all of the data
/// from a video player and paste it into the AVPro videoplayer.
///
[ContextMenu("Copy from VideoPlayer")]
void VideoPlayertoAVProConversion()
{
// ensure that a videoplayer is attached to this gameobject
if (!gameObject.TryGetComponent(out VideoPlayer player))
{
Debug.LogWarning("No Video Player Attached to this object, Abandoning Process");
return;
}
_converted = true;
// convert all of the imformation from the VideoPlayer into the VideoPlayer_AVPro
// MediaPath
if (player.source == VideoSource.VideoClip)
{
// clip
if (player.clip)
{
LogAutomaticConversionSolution("VideoClip", "MediaReference", "it is recommended that you create your own MediaReference and assign it");
var mediaReference = ScriptableObject.CreateInstance();
mediaReference.MediaPath = new MediaPath(Application.dataPath.TrimEnd(new char[] { 'A', 's', 's', 'e', 't', 's' }) + player.clip.originalPath, MediaPathType.AbsolutePathOrURL);
clip = mediaReference;
}
}
else
{
// url
url = new MediaPath(player.url, MediaPathType.AbsolutePathOrURL);
Url = url.Path;
}
// Source
switch (player.source)
{
// clip
case UnityEngine.Video.VideoSource.VideoClip:
sourceAVPro = MediaSource.Reference;
Source = MediaSource.Reference;
break;
// url
case UnityEngine.Video.VideoSource.Url:
sourceAVPro = MediaSource.Path;
Source = MediaSource.Path;
break;
}
// Play On Awake
playOnAwake = player.playOnAwake;
PlayOnAwake = player.playOnAwake;
// Auto Opening
AutoOpening = player.playOnAwake;
AutoOpen = player.playOnAwake;
// isLooping
isLooping = player.isLooping;
IsLooping = player.isLooping;
// playback speed
playbackSpeed = player.playbackSpeed;
PlaybackSpeed = player.playbackSpeed;
// target material renderer
targetMaterialRenderer = player.targetMaterialRenderer;
TargetMaterialRenderer = player.targetMaterialRenderer;
// target material property
targetMateralProperty = player.targetMaterialProperty;
TargetMateralProperty = player.targetMaterialProperty;
// render mode
switch (player.renderMode)
{
case UnityEngine.Video.VideoRenderMode.CameraFarPlane:
rendererMode = DisplayType.CameraFarPlane;
RenderMode = DisplayType.CameraFarPlane;
break;
case UnityEngine.Video.VideoRenderMode.CameraNearPlane:
rendererMode = DisplayType.IMGUI;
RenderMode = DisplayType.IMGUI;
break;
case UnityEngine.Video.VideoRenderMode.RenderTexture:
rendererMode = DisplayType.RenderTexture;
RenderMode = DisplayType.RenderTexture;
break;
case UnityEngine.Video.VideoRenderMode.MaterialOverride:
rendererMode = DisplayType.Material;
RenderMode = DisplayType.Material;
break;
case UnityEngine.Video.VideoRenderMode.APIOnly:
rendererMode = DisplayType.Mesh;
RenderMode = DisplayType.Mesh;
break;
}
// aspect ratio
switch (player.aspectRatio)
{
case UnityEngine.Video.VideoAspectRatio.NoScaling:
aspectRatioRenderTexture = VideoResolveOptions.AspectRatio.NoScaling;
AspectRatioRenderTexture = VideoResolveOptions.AspectRatio.NoScaling;
break;
case UnityEngine.Video.VideoAspectRatio.FitVertically:
aspectRatioRenderTexture = VideoResolveOptions.AspectRatio.FitVertically;
AspectRatioRenderTexture = VideoResolveOptions.AspectRatio.FitVertically;
break;
case UnityEngine.Video.VideoAspectRatio.FitHorizontally:
aspectRatioRenderTexture = VideoResolveOptions.AspectRatio.FitHorizontally;
AspectRatioRenderTexture = VideoResolveOptions.AspectRatio.FitHorizontally;
break;
case UnityEngine.Video.VideoAspectRatio.FitInside:
aspectRatio = ScaleMode.ScaleToFit;
AspectRatio = ScaleMode.ScaleToFit;
aspectRatioRenderTexture = VideoResolveOptions.AspectRatio.FitInside;
AspectRatioRenderTexture = VideoResolveOptions.AspectRatio.FitInside;
break;
case UnityEngine.Video.VideoAspectRatio.FitOutside:
aspectRatio = ScaleMode.ScaleAndCrop;
AspectRatio = ScaleMode.ScaleAndCrop;
aspectRatioRenderTexture = VideoResolveOptions.AspectRatio.FitOutside;
AspectRatioRenderTexture = VideoResolveOptions.AspectRatio.FitOutside;
break;
case UnityEngine.Video.VideoAspectRatio.Stretch:
aspectRatio = ScaleMode.StretchToFill;
AspectRatio = ScaleMode.StretchToFill;
aspectRatioRenderTexture = VideoResolveOptions.AspectRatio.Stretch;
AspectRatioRenderTexture = VideoResolveOptions.AspectRatio.Stretch;
break;
}
// audio output mode
#if UNITY_STANDALONE_WIN
switch (player.audioOutputMode)
{
case UnityEngine.Video.VideoAudioOutputMode.None:
audioOutputModeAVPro = Windows.AudioOutput.None;
AudioOutputMode = Windows.AudioOutput.None;
break;
case UnityEngine.Video.VideoAudioOutputMode.AudioSource:
audioOutputModeAVPro = Windows.AudioOutput.Unity;
AudioOutputMode = Windows.AudioOutput.Unity;
CreateAudioComponents();
break;
case UnityEngine.Video.VideoAudioOutputMode.Direct:
case UnityEngine.Video.VideoAudioOutputMode.APIOnly:
audioOutputModeAVPro = Windows.AudioOutput.System;
AudioOutputMode = Windows.AudioOutput.System;
break;
}
#elif UNITY_WSA_10_0
switch (player.audioOutputMode)
{
case UnityEngine.Video.VideoAudioOutputMode.None:
audioOutputModeAVPro = WindowsUWP.AudioOutput.None;
AudioOutputMode = WindowsUWP.AudioOutput.None;
break;
case UnityEngine.Video.VideoAudioOutputMode.AudioSource:
audioOutputModeAVPro = WindowsUWP.AudioOutput.Unity;
AudioOutputMode = WindowsUWP.AudioOutput.Unity;
CreateAudioComponents();
break;
case UnityEngine.Video.VideoAudioOutputMode.Direct:
case UnityEngine.Video.VideoAudioOutputMode.APIOnly:
audioOutputModeAVPro = WindowsUWP.AudioOutput.System;
AudioOutputMode = WindowsUWP.AudioOutput.System;
break;
}
#elif UNITY_ANDROID || UNITY_IOS || UNITY_STANDALONE_OSX || UNITY_TVOS || UNITY_VISIONOS
switch (player.audioOutputMode)
{
case UnityEngine.Video.VideoAudioOutputMode.None:
audioOutputModeAVPro = PlatformOptions.AudioMode.SystemDirect;
AudioOutputMode = PlatformOptions.AudioMode.SystemDirect;
break;
case UnityEngine.Video.VideoAudioOutputMode.AudioSource:
audioOutputModeAVPro = PlatformOptions.AudioMode.Unity;
AudioOutputMode = PlatformOptions.AudioMode.Unity;
CreateAudioComponents();
break;
case UnityEngine.Video.VideoAudioOutputMode.Direct:
case UnityEngine.Video.VideoAudioOutputMode.APIOnly:
audioOutputModeAVPro = PlatformOptions.AudioMode.SystemDirect;
AudioOutputMode = PlatformOptions.AudioMode.SystemDirect;
break;
}
#endif
// disable the VideoPlayer
player.enabled = false;
CreateRendererComponents();
// apply properties that require components to be created
if (rendererMode == DisplayType.Material)
{
#if UNITY_EDITOR
targetMaterial = player.targetMaterialRenderer.sharedMaterial;
#else
targetMaterial = player.targetMaterialRenderer.material;
#endif
}
else if (rendererMode == DisplayType.RenderTexture)
{
targetTexture = player.targetTexture;
TargetTexture = player.targetTexture;
}
else if (rendererMode == DisplayType.CameraFarPlane)
{
applyToFarPlane.VideoAspectRatio = (VideoAspectRatio)(int)aspectRatioRenderTexture;
applyToFarPlane.MainColor = color;
}
}
///
/// This method will convert, VideoPlayer_AVPro to a MediaPlayer, this is alot simpler than
/// converting from VideoPlayer to VideoPlayer_AVPro, as all the data matches so can just set it
/// all
///
[ContextMenu("Convert to MediaPlayer")]
public void ConvertToMediaPlayer()
{
MediaPlayer player = gameObject.AddComponent();
//if (!gameObject.TryGetComponent(out player))
// Source
player.SetMediaSource(sourceAVPro);
// Set media based on source
if (sourceAVPro == MediaSource.Reference)
player.SetMediaReference(clip); // clip
else
player.SetMediaPath(new MediaPath(Url, MediaPathType.AbsolutePathOrURL)); // url
// Play On Awake
player.AutoStart = playOnAwake;
// Auto Opening
player.AutoOpen = true;
// isLooping
player.Loop = isLooping;
// playback speed
player.PlaybackRate = playbackSpeed;
// audio source
if (TryGetComponent(out AudioOutput audioOut))
{
if (TryGetComponent(out AudioSource audioSource))
audioOut.SetAudioSource(audioSource);
}
// audio output mode
#if UNITY_STANDALONE_WIN
player.PlatformOptionsWindows._audioMode = audioOutputModeAVPro;
if (audioOutputModeAVPro == Windows.AudioOutput.Unity)
GetComponent().Player = player;
#elif UNITY_WSA_10_0
player.PlatformOptionsWindowsUWP._audioMode = audioOutputModeAVPro;
if (audioOutputModeAVPro == WindowsUWP.AudioOutput.Unity)
GetComponent().Player = player;
#elif UNITY_ANDROID
player.PlatformOptionsAndroid.audioMode = audioOutputModeAVPro;
#elif UNITY_IOS
player.PlatformOptions_iOS.audioMode = audioOutputModeAVPro;
#elif UNITY_STANDALONE_OSX
player.PlatformOptions_macOS.audioMode = audioOutputModeAVPro;
#elif UNITY_TVOS
player.PlatformOptions_tvOS.audioMode = audioOutputModeAVPro;
#elif UNITY_VISIONOS
player.PlatformOptions_visionOS.audioMode = audioOutputModeAVPro;
#endif
#if UNITY_ANDROID || UNITY_IOS || UNITY_STANDALONE_OSX || UNITY_TVOS || UNITY_VISIONOS
if (audioOutputModeAVPro == PlatformOptions.AudioMode.Unity)
GetComponent().Player = player;
#endif
if (_renderModeComponent != null)
{
switch(rendererMode)
{
case DisplayType.Mesh:
((ApplyToMesh)_renderModeComponent).Player = player;
break;
case DisplayType.Material:
((ApplyToMaterial)_renderModeComponent).Player = player;
break;
case DisplayType.uGUI:
((DisplayUGUI)_renderModeComponent).Player = player;
break;
case DisplayType.IMGUI:
((DisplayIMGUI)_renderModeComponent).Player = player;
break;
case DisplayType.CameraFarPlane:
((ApplyToFarPlane)_renderModeComponent).Player = player;
break;
case DisplayType.RenderTexture:
((ResolveToRenderTexture)_renderModeComponent).MediaPlayer = player;
break;
case DisplayType.None:
default:
break;
}
}
// disable this as media player now active
this.enabled = false;
}
#endif
#endregion Conversion
#region Helper Methods
///
/// Creates a compoenent that will be used to play audio when selecting the Unity option from
///
public void CreateAudioComponents()
{
DestroyAudioOutputBehaviour();
#if UNITY_STANDALONE_WIN
if (audioOutputModeAVPro == Windows.AudioOutput.Unity)
#elif UNITY_WSA_10_0
if (audioOutputModeAVPro == WindowsUWP.AudioOutput.Unity)
#elif UNITY_ANDROID || UNITY_IOS || UNITY_STANDALONE_OSX || UNITY_TVOS || UNITY_VISIONOS
if (audioOutputModeAVPro == PlatformOptions.AudioMode.Unity)
#endif
{
var output = gameObject.AddComponent();
if (!gameObject.TryGetComponent(out AudioSource source))
{
source = gameObject.AddComponent();
}
else
{
audioSource = source;
}
output.SetAudioSource(source);
output.Player = this;
}
}
///
/// Creates the components for the differernt rendering modes, this method
/// also handles the destruction of the previous rendering mode components.
///
public void CreateRendererComponents()
{
// destroy the previous component
DestroyRendererBehaviours();
// Add current output type
switch (rendererMode)
{
case DisplayType.Mesh:
if (!gameObject.GetComponent())
applyToMesh = gameObject.AddComponent();
else
applyToMesh = gameObject.GetComponent();
applyToMesh.Player = this;
_renderModeComponent = applyToMesh;
break;
case DisplayType.Material:
if (!gameObject.GetComponent())
applyToMaterial = gameObject.AddComponent();
else
applyToMaterial = gameObject.GetComponent();
applyToMaterial.Player = this;
_renderModeComponent = applyToMaterial;
// VideoPlayer's material override is for the material attached to the current object, so just get the renderer attached to this object and set the material to be the one to be overridden
if (gameObject.TryGetComponent(out Renderer rendererMat))
{
targetMaterial = rendererMat.material;
applyToMaterial.Material = rendererMat.material;
}
break;
case DisplayType.uGUI:
if (!canvasObj)
{
Debug.LogWarning("[AVProVideo] Warning, No Canvas Object Set For uGUI, Overriding DisplayType");
break;
}
if (!canvasObj.GetComponent())
displayUGUI = canvasObj.AddComponent();
else
displayUGUI = canvasObj.GetComponent();
displayUGUI.Player = this;
_renderModeComponent = displayUGUI;
break;
case DisplayType.IMGUI:
if (!gameObject.GetComponent())
displayIMGUI = gameObject.AddComponent();
else
displayIMGUI = gameObject.GetComponent();
displayIMGUI.Player = this;
_renderModeComponent = displayIMGUI;
displayIMGUI.Color = Color.white;
break;
case DisplayType.CameraFarPlane:
if (!gameObject.GetComponent())
applyToFarPlane = gameObject.AddComponent();
else
applyToFarPlane = gameObject.GetComponent();
applyToFarPlane.Player = this;
_renderModeComponent = applyToFarPlane;
applyToFarPlane.VideoAspectRatio = (VideoAspectRatio)(int)aspectRatioRenderTexture;
applyToFarPlane.MainColor = color;
break;
case DisplayType.RenderTexture:
if (!gameObject.GetComponent())
applyToTexture = gameObject.AddComponent();
else
applyToTexture = gameObject.GetComponent();
applyToTexture.MediaPlayer = this;
_renderModeComponent = applyToTexture;
applyToTexture.ExternalTexture = TargetTexture;
break;
case DisplayType.None:
_renderModeComponent = null;
break;
default:
Debug.LogError("Error: Invalid Render Mode selected");
break;
}
}
///
/// Destroys the compoenent attached to this object
/// This componenet is used to take the audio from the video codec and play it through a unity AudioSource compoenent
///
public void DestroyAudioOutputBehaviour()
{
if (gameObject.TryGetComponent(out AudioOutput audio))
DestroyImmediate(audio);
//if (gameObject.TryGetComponent(out AudioSource source))
// DestroyImmediate(source);
}
///
/// Destroys the rendering mode compoennts attatched to the current object,
/// can handle more than 1 type but not multiple of the same type
///
public void DestroyRendererBehaviours()
{
if (gameObject.TryGetComponent(out ApplyToMesh mesh))
DestroyImmediate(mesh);
if (gameObject.TryGetComponent(out ApplyToMaterial material))
DestroyImmediate(material);
if (canvasObj && canvasObj.TryGetComponent(out DisplayUGUI uGUI))
DestroyImmediate(uGUI);
if (gameObject.TryGetComponent(out DisplayIMGUI IMGUI))
DestroyImmediate(IMGUI);
if (gameObject.TryGetComponent(out ApplyToFarPlane farPlane))
DestroyImmediate(farPlane);
if (gameObject.TryGetComponent(out ResolveToRenderTexture texture))
DestroyImmediate(texture);
}
///
/// This will set the output mode based on the context.
///
/// - Material - Object containing a component with material attached
/// - UGUI - Object containing both a and
/// - IMGUI - Default Option
///
///
public void SetOutputModeContextual()
{
// Material
// UGUI
// None
// remove any previous renderers
DestroyRendererBehaviours();
if (gameObject.TryGetComponent(out CanvasRenderer canvas) && gameObject.TryGetComponent(out RectTransform transform))
{
var added = gameObject.AddComponent();
if (!added)
{
_renderModeComponent = null;
displayUGUI = null;
rendererMode = DisplayType.None;
return;
}
_renderModeComponent = added;
displayUGUI = added;
rendererMode = DisplayType.uGUI;
added.Player = this;
return;
}
else if (gameObject.TryGetComponent(out Renderer renderer))
{
if (renderer.sharedMaterial)
{
var added = gameObject.AddComponent();
_renderModeComponent = added;
applyToMaterial = added;
rendererMode = DisplayType.Material;
added.Player = this;
return;
}
}
_renderModeComponent = null;
rendererMode = DisplayType.None;
}
///
/// Used to check if any of the output modes have been set
///
/// true if any output mode is set; otherwise false
public bool OutputModeSet()
{
return applyToFarPlane || applyToMaterial || applyToMesh || applyToTexture || displayIMGUI || displayUGUI;
}
#endregion Helper Methods
#region General Methods
///
/// this will handle setting up the rendering component, based on the object that it is placed on
/// (if it was not generated by a conversion (i which case it will use the same output mode as
/// the one used on the orignal video player))
///
public void Start()
{
if (!_converted && _renderModeComponent == null && !OutputModeSet())
{
// add the appropriate output mode
SetOutputModeContextual();
}
}
///
/// this will ensure that the media player is properly initilized when turning on
///
public void Awake()
{
// this is just a copy of the one from Media Player so surly thats gotta work
if (Control == null)
{
if (Application.isPlaying)
{
Initialise();
if (Control != null)
{
//dont want to auto open with VideoPlayer
if (AutoOpening)
{
OpenMedia(playOnAwake);
}
StartRenderCoroutine();
}
}
}
}
public void OnEnable()
{
// add lister to callback propagator
Events.AddListener(EventCallbacks);
}
public void OnDisable()
{
// clear all of the Event/Delegate data
prepareCompleted = null;
started = null;
errorReceived = null;
seekCompleted = null;
loopPointReached = null;
frameDropped = null;
clockResyncOccurred = null;
Events.RemoveListener(EventCallbacks);
}
// logs when their is no similar behaviour/Functionality to a VideoRecord function within AVPro
private void LogAutomaticConversionSolution(string value1, string value2, string solution)
{
Debug.LogWarning($"[VideoPlayer_AVPro] Warning: Automatic Conversion Occuring from {value1} to {value2}. {solution}");
}
private void LogAutomaticConversion(string value1, string value2)
{
Debug.LogWarning($"[VideoPlayer_AVPro] Warning: Automatic conversion occuring from {value1} to {value2}, unexpected behaviour may occur");
}
private void LogNoSimWarning(string behaviourName, string reason = "")
{
Debug.LogWarning($"[VideoPlayer_AVPro] Warning: AVPro contains no similar Behaviour to \"{behaviourName}\". {reason}");
}
private void LogNoFunctionality(string behaviourName, string reason = "")
{
Debug.LogWarning($"[VideoPlayer_AVPro] Warning: AVPro method/Parameter: \"{behaviourName}\" does not contain any functionality. {reason}");
}
#endregion General Methods
}
}