672 lines
22 KiB
C#
672 lines
22 KiB
C#
|
#if UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX || UNITY_IOS || UNITY_TVOS || UNITY_VISIONOS
|
|||
|
#define UNITY_PLATFORM_SUPPORTS_YPCBCR
|
|||
|
#endif
|
|||
|
|
|||
|
#if UNITY_EDITOR || UNITY_STANDALONE_OSX || UNITY_STANDALONE_WIN || UNITY_WSA_10_0 || UNITY_IOS || UNITY_TVOS || UNITY_VISIONOS || UNITY_ANDROID || (UNITY_WEBGL && UNITY_2017_2_OR_NEWER)
|
|||
|
#define UNITY_PLATFORM_SUPPORTS_LINEAR
|
|||
|
#endif
|
|||
|
|
|||
|
using System.Collections;
|
|||
|
using System.Collections.Generic;
|
|||
|
using UnityEngine;
|
|||
|
using UnityEngine.Rendering;
|
|||
|
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
// Copyright 2015-2024 RenderHeads Ltd. All rights reserved.
|
|||
|
//-----------------------------------------------------------------------------
|
|||
|
|
|||
|
namespace RenderHeads.Media.AVProVideo
|
|||
|
{
|
|||
|
#if AVPRO_FEATURE_VIDEORESOLVE
|
|||
|
[System.Serializable]
|
|||
|
public class VideoResolve : ITextureProducer
|
|||
|
{
|
|||
|
[SerializeField] VideoResolveOptions _options = VideoResolveOptions.Create();
|
|||
|
[SerializeField] RenderTexture _targetRenderTexture = null;
|
|||
|
[SerializeField] ScaleMode _targetRenderTextureScale = ScaleMode.ScaleToFit;
|
|||
|
|
|||
|
void SetSource(ITextureProducer textureSource)
|
|||
|
{
|
|||
|
//_commandBuffer.IssuePluginEvent(blahCallback, 0);
|
|||
|
//Graphics.ExecuteCommandBuffer(_commandBuffer);
|
|||
|
}
|
|||
|
|
|||
|
// ITextureProducer implementation
|
|||
|
|
|||
|
/// <inheritdoc/>
|
|||
|
public int GetTextureCount() { return 1; }
|
|||
|
|
|||
|
/// <inheritdoc/>
|
|||
|
public Texture GetTexture(int index = 0) { return _texture; }
|
|||
|
|
|||
|
/// <inheritdoc/>
|
|||
|
public int GetTextureFrameCount() { return _textureSource.GetTextureFrameCount(); }
|
|||
|
|
|||
|
/// <inheritdoc/>
|
|||
|
public bool SupportsTextureFrameCount() { return _textureSource.SupportsTextureFrameCount(); }
|
|||
|
|
|||
|
/// <inheritdoc/>
|
|||
|
public long GetTextureTimeStamp() { return _textureSource.GetTextureTimeStamp(); }
|
|||
|
|
|||
|
/// <inheritdoc/>
|
|||
|
public bool RequiresVerticalFlip() { return false; }
|
|||
|
|
|||
|
/// <inheritdoc/>
|
|||
|
public StereoPacking GetTextureStereoPacking() { return StereoPacking.None; }
|
|||
|
|
|||
|
/// <inheritdoc/>
|
|||
|
public TransparencyMode GetTextureTransparency() { return TransparencyMode.Transparent; }
|
|||
|
|
|||
|
/// <inheritdoc/>
|
|||
|
public AlphaPacking GetTextureAlphaPacking() { return AlphaPacking.None; }
|
|||
|
|
|||
|
/// <inheritdoc/>
|
|||
|
public Matrix4x4 GetYpCbCrTransform() { return Matrix4x4.identity; }
|
|||
|
|
|||
|
private ITextureProducer _textureSource;
|
|||
|
private Texture _texture;
|
|||
|
private CommandBuffer _commandBuffer;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
public struct LazyShaderProperty
|
|||
|
{
|
|||
|
public LazyShaderProperty(string name)
|
|||
|
{
|
|||
|
_name = name;
|
|||
|
_id = 0;
|
|||
|
}
|
|||
|
|
|||
|
public string Name { get { return _name;} }
|
|||
|
public int Id { get { if (_id == 0) { _id = Shader.PropertyToID(_name); } return _id; } }
|
|||
|
|
|||
|
private string _name;
|
|||
|
private int _id;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>Helper class for everything related to setting up materials for rendering/resolving videos</summary>
|
|||
|
public class VideoRender
|
|||
|
{
|
|||
|
public const string Shader_IMGUI = "AVProVideo/Internal/IMGUI/Texture Transparent";
|
|||
|
public const string Shader_Resolve = "AVProVideo/Internal/Resolve";
|
|||
|
public const string Shader_ResolveOES = "AVProVideo/Internal/ResolveOES";
|
|||
|
public const string Shader_Preview = "AVProVideo/Internal/Preview";
|
|||
|
|
|||
|
#if UNITY_PLATFORM_SUPPORTS_YPCBCR
|
|||
|
public const string Keyword_UseYpCbCr = "USE_YPCBCR";
|
|||
|
#endif
|
|||
|
public const string Keyword_AlphaPackTopBottom = "ALPHAPACK_TOP_BOTTOM";
|
|||
|
public const string Keyword_AlphaPackLeftRight = "ALPHAPACK_LEFT_RIGHT";
|
|||
|
public const string Keyword_AlphaPackNone = "ALPHAPACK_NONE";
|
|||
|
public const string Keyword_StereoTopBottom = "STEREO_TOP_BOTTOM";
|
|||
|
public const string Keyword_StereoLeftRight = "STEREO_LEFT_RIGHT";
|
|||
|
public const string Keyword_StereoCustomUV = "STEREO_CUSTOM_UV";
|
|||
|
public const string Keyword_StereoTwoTextures = "STEREO_TWOTEXTURES";
|
|||
|
public const string Keyword_StereoNone = "MONOSCOPIC";
|
|||
|
public const string Keyword_StereoDebug = "STEREO_DEBUG";
|
|||
|
public const string Keyword_LayoutEquirect180 = "LAYOUT_EQUIRECT180";
|
|||
|
public const string Keyword_LayoutNone = "LAYOUT_NONE";
|
|||
|
public const string Keyword_ForceEyeNone = "FORCEEYE_NONE";
|
|||
|
public const string Keyword_ForceEyeLeft = "FORCEEYE_LEFT";
|
|||
|
public const string Keyword_ForceEyeRight = "FORCEEYE_RIGHT";
|
|||
|
public const string Keyword_ApplyGamma = "APPLY_GAMMA";
|
|||
|
|
|||
|
public static readonly LazyShaderProperty PropChromaTex = new LazyShaderProperty("_ChromaTex");
|
|||
|
|
|||
|
#if UNITY_PLATFORM_SUPPORTS_YPCBCR
|
|||
|
public static readonly LazyShaderProperty PropYpCbCrTransform = new LazyShaderProperty("_YpCbCrTransform");
|
|||
|
public static readonly LazyShaderProperty PropUseYpCbCr = new LazyShaderProperty("_UseYpCbCr");
|
|||
|
#endif
|
|||
|
|
|||
|
public static readonly LazyShaderProperty PropVertScale = new LazyShaderProperty("_VertScale");
|
|||
|
public static readonly LazyShaderProperty PropApplyGamma = new LazyShaderProperty("_ApplyGamma");
|
|||
|
public static readonly LazyShaderProperty PropStereo = new LazyShaderProperty("Stereo");
|
|||
|
public static readonly LazyShaderProperty PropAlphaPack = new LazyShaderProperty("AlphaPack");
|
|||
|
public static readonly LazyShaderProperty PropLayout = new LazyShaderProperty("Layout");
|
|||
|
public static readonly LazyShaderProperty PropViewMatrix = new LazyShaderProperty("_ViewMatrix");
|
|||
|
public static readonly LazyShaderProperty PropTextureMatrix = new LazyShaderProperty("_MainTex_Xfrm");
|
|||
|
|
|||
|
public static string Keyword_UseHSBC = "USE_HSBC";
|
|||
|
public static readonly LazyShaderProperty PropHue = new LazyShaderProperty("_Hue");
|
|||
|
public static readonly LazyShaderProperty PropSaturation = new LazyShaderProperty("_Saturation");
|
|||
|
public static readonly LazyShaderProperty PropContrast = new LazyShaderProperty("_Contrast");
|
|||
|
public static readonly LazyShaderProperty PropBrightness = new LazyShaderProperty("_Brightness");
|
|||
|
public static readonly LazyShaderProperty PropInvGamma = new LazyShaderProperty("_InvGamma");
|
|||
|
|
|||
|
public static Material CreateResolveMaterial(bool usingAndroidOES)
|
|||
|
{
|
|||
|
return new Material(Shader.Find( usingAndroidOES ? VideoRender.Shader_ResolveOES : VideoRender.Shader_Resolve ));
|
|||
|
}
|
|||
|
|
|||
|
public static Material CreateIMGUIMaterial()
|
|||
|
{
|
|||
|
return new Material(Shader.Find(VideoRender.Shader_Preview));
|
|||
|
}
|
|||
|
|
|||
|
public static void SetupLayoutMaterial(Material material, VideoMapping mapping)
|
|||
|
{
|
|||
|
switch (mapping)
|
|||
|
{
|
|||
|
default:
|
|||
|
material.DisableKeyword(Keyword_LayoutEquirect180);
|
|||
|
material.EnableKeyword(Keyword_LayoutNone);
|
|||
|
break;
|
|||
|
// Only EquiRectangular180 currently does anything in the shader
|
|||
|
case VideoMapping.EquiRectangular180:
|
|||
|
material.DisableKeyword(Keyword_LayoutNone);
|
|||
|
material.EnableKeyword(Keyword_LayoutEquirect180);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public static void SetupStereoEyeModeMaterial(Material material, StereoEye mode)
|
|||
|
{
|
|||
|
switch (mode)
|
|||
|
{
|
|||
|
case StereoEye.Both:
|
|||
|
material.DisableKeyword(Keyword_ForceEyeLeft);
|
|||
|
material.DisableKeyword(Keyword_ForceEyeRight);
|
|||
|
material.EnableKeyword(Keyword_ForceEyeNone);
|
|||
|
break;
|
|||
|
case StereoEye.Left:
|
|||
|
material.DisableKeyword(Keyword_ForceEyeNone);
|
|||
|
material.DisableKeyword(Keyword_ForceEyeRight);
|
|||
|
material.EnableKeyword(Keyword_ForceEyeLeft);
|
|||
|
break;
|
|||
|
case StereoEye.Right:
|
|||
|
material.DisableKeyword(Keyword_ForceEyeNone);
|
|||
|
material.DisableKeyword(Keyword_ForceEyeLeft);
|
|||
|
material.EnableKeyword(Keyword_ForceEyeRight);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public static void SetupStereoMaterial(Material material, StereoPacking packing)
|
|||
|
{
|
|||
|
switch (packing)
|
|||
|
{
|
|||
|
case StereoPacking.None:
|
|||
|
material.DisableKeyword(Keyword_StereoTopBottom);
|
|||
|
material.DisableKeyword(Keyword_StereoLeftRight);
|
|||
|
material.DisableKeyword(Keyword_StereoCustomUV);
|
|||
|
material.DisableKeyword(Keyword_StereoTwoTextures);
|
|||
|
material.EnableKeyword(Keyword_StereoNone);
|
|||
|
break;
|
|||
|
case StereoPacking.TopBottom:
|
|||
|
material.DisableKeyword(Keyword_StereoNone);
|
|||
|
material.DisableKeyword(Keyword_StereoLeftRight);
|
|||
|
material.DisableKeyword(Keyword_StereoCustomUV);
|
|||
|
material.DisableKeyword(Keyword_StereoTwoTextures);
|
|||
|
material.EnableKeyword(Keyword_StereoTopBottom);
|
|||
|
break;
|
|||
|
case StereoPacking.LeftRight:
|
|||
|
material.DisableKeyword(Keyword_StereoNone);
|
|||
|
material.DisableKeyword(Keyword_StereoTopBottom);
|
|||
|
material.DisableKeyword(Keyword_StereoTwoTextures);
|
|||
|
material.DisableKeyword(Keyword_StereoCustomUV);
|
|||
|
material.EnableKeyword(Keyword_StereoLeftRight);
|
|||
|
break;
|
|||
|
case StereoPacking.CustomUV:
|
|||
|
material.DisableKeyword(Keyword_StereoNone);
|
|||
|
material.DisableKeyword(Keyword_StereoTopBottom);
|
|||
|
material.DisableKeyword(Keyword_StereoLeftRight);
|
|||
|
material.DisableKeyword(Keyword_StereoTwoTextures);
|
|||
|
material.EnableKeyword(Keyword_StereoCustomUV);
|
|||
|
break;
|
|||
|
case StereoPacking.TwoTextures:
|
|||
|
material.DisableKeyword(Keyword_StereoNone);
|
|||
|
material.DisableKeyword(Keyword_StereoTopBottom);
|
|||
|
material.DisableKeyword(Keyword_StereoLeftRight);
|
|||
|
material.DisableKeyword(Keyword_StereoCustomUV);
|
|||
|
material.EnableKeyword(Keyword_StereoTwoTextures);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public static void SetupGlobalDebugStereoTinting(bool enabled)
|
|||
|
{
|
|||
|
if (enabled)
|
|||
|
{
|
|||
|
Shader.EnableKeyword(Keyword_StereoDebug);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Shader.DisableKeyword(Keyword_StereoDebug);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public static void SetupAlphaPackedMaterial(Material material, AlphaPacking packing)
|
|||
|
{
|
|||
|
switch (packing)
|
|||
|
{
|
|||
|
case AlphaPacking.None:
|
|||
|
material.DisableKeyword(Keyword_AlphaPackTopBottom);
|
|||
|
material.DisableKeyword(Keyword_AlphaPackLeftRight);
|
|||
|
material.EnableKeyword(Keyword_AlphaPackNone);
|
|||
|
break;
|
|||
|
case AlphaPacking.TopBottom:
|
|||
|
material.DisableKeyword(Keyword_AlphaPackNone);
|
|||
|
material.DisableKeyword(Keyword_AlphaPackLeftRight);
|
|||
|
material.EnableKeyword(Keyword_AlphaPackTopBottom);
|
|||
|
break;
|
|||
|
case AlphaPacking.LeftRight:
|
|||
|
material.DisableKeyword(Keyword_AlphaPackNone);
|
|||
|
material.DisableKeyword(Keyword_AlphaPackTopBottom);
|
|||
|
material.EnableKeyword(Keyword_AlphaPackLeftRight);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public static void SetupGammaMaterial(Material material, bool playerSupportsLinear)
|
|||
|
{
|
|||
|
#if UNITY_PLATFORM_SUPPORTS_LINEAR
|
|||
|
if (QualitySettings.activeColorSpace == ColorSpace.Linear && !playerSupportsLinear)
|
|||
|
{
|
|||
|
material.EnableKeyword(Keyword_ApplyGamma);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
material.DisableKeyword(Keyword_ApplyGamma);
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
public static void SetupTextureMatrix(Material material, float[] transform)
|
|||
|
{
|
|||
|
if (material == null)
|
|||
|
return;
|
|||
|
|
|||
|
if (transform == null || transform.Length != 6)
|
|||
|
transform = new float[6] { 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f };
|
|||
|
|
|||
|
Vector4 v0 = new Vector4(transform[0], transform[1], 0, 0);
|
|||
|
Vector4 v1 = new Vector4(transform[2], transform[3], 0, 0);
|
|||
|
Vector4 v2 = new Vector4(0, 0, 1, 0);
|
|||
|
Vector4 v3 = new Vector4(transform[4], transform[5], 0, 1);
|
|||
|
|
|||
|
material.SetMatrix(PropTextureMatrix.Id, new Matrix4x4(v0, v1, v2, v3));
|
|||
|
}
|
|||
|
|
|||
|
public static void SetupTextureMatrix(Material material, Matrix4x4 transform)
|
|||
|
{
|
|||
|
if (material == null)
|
|||
|
return;
|
|||
|
material.SetMatrix(PropTextureMatrix.Id, transform);
|
|||
|
}
|
|||
|
|
|||
|
#if UNITY_PLATFORM_SUPPORTS_YPCBCR
|
|||
|
public static void SetupYpCbCrMaterial(Material material, bool enable, Matrix4x4 transform, Texture texture)
|
|||
|
{
|
|||
|
if (material.HasProperty(VideoRender.PropUseYpCbCr.Id))
|
|||
|
{
|
|||
|
if (enable)
|
|||
|
{
|
|||
|
material.EnableKeyword(VideoRender.Keyword_UseYpCbCr);
|
|||
|
material.SetMatrix(VideoRender.PropYpCbCrTransform.Id, transform);
|
|||
|
material.SetTexture(VideoRender.PropChromaTex.Id, texture);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
material.DisableKeyword(VideoRender.Keyword_UseYpCbCr);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
public static void SetupVerticalFlipMaterial(Material material, bool flip)
|
|||
|
{
|
|||
|
material.SetFloat(VideoRender.PropVertScale.Id, flip?-1f:1f);
|
|||
|
}
|
|||
|
|
|||
|
public static Texture GetTexture(MediaPlayer mediaPlayer, int textureIndex)
|
|||
|
{
|
|||
|
Texture result = null;
|
|||
|
if (mediaPlayer != null)
|
|||
|
{
|
|||
|
if (mediaPlayer.UseResampler && mediaPlayer.FrameResampler != null && mediaPlayer.FrameResampler.OutputTexture != null)
|
|||
|
{
|
|||
|
if ( mediaPlayer.FrameResampler.OutputTexture.Length > textureIndex)
|
|||
|
{
|
|||
|
result = mediaPlayer.FrameResampler.OutputTexture[textureIndex];
|
|||
|
}
|
|||
|
}
|
|||
|
else if (mediaPlayer.TextureProducer != null)
|
|||
|
{
|
|||
|
if (mediaPlayer.TextureProducer.GetTextureCount() > textureIndex)
|
|||
|
{
|
|||
|
result = mediaPlayer.TextureProducer.GetTexture(textureIndex);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
public static void SetupMaterialForMedia(Material material, MediaPlayer mediaPlayer, int texturePropId = -1, Texture fallbackTexture = null, bool forceFallbackTexture = false)
|
|||
|
{
|
|||
|
Debug.Assert(material != null);
|
|||
|
if (mediaPlayer != null)
|
|||
|
{
|
|||
|
Texture mainTexture = GetTexture(mediaPlayer, 0);
|
|||
|
Matrix4x4 textureTransform = Matrix4x4.identity;
|
|||
|
Texture yCbCrTexture = GetTexture(mediaPlayer, 1);
|
|||
|
Matrix4x4 yCbCrTransform = Matrix4x4.identity;
|
|||
|
StereoPacking stereoPacking = StereoPacking.None;
|
|||
|
AlphaPacking alphaPacking = AlphaPacking.None;
|
|||
|
bool flipY = false;
|
|||
|
bool isLinear = false;
|
|||
|
|
|||
|
if (texturePropId != -1)
|
|||
|
{
|
|||
|
if (mainTexture == null || forceFallbackTexture)
|
|||
|
{
|
|||
|
mainTexture = fallbackTexture;
|
|||
|
}
|
|||
|
material.SetTexture(texturePropId, mainTexture);
|
|||
|
}
|
|||
|
|
|||
|
ITextureProducer textureProducer = mediaPlayer.TextureProducer;
|
|||
|
if (textureProducer != null)
|
|||
|
{
|
|||
|
flipY = textureProducer.RequiresVerticalFlip();
|
|||
|
yCbCrTransform = textureProducer.GetYpCbCrTransform();
|
|||
|
stereoPacking = textureProducer.GetTextureStereoPacking();
|
|||
|
alphaPacking = textureProducer.GetTextureAlphaPacking();
|
|||
|
textureTransform = textureProducer.GetTextureMatrix();
|
|||
|
}
|
|||
|
|
|||
|
if (mediaPlayer.Info != null)
|
|||
|
{
|
|||
|
isLinear = mediaPlayer.Info.PlayerSupportsLinearColorSpace();
|
|||
|
}
|
|||
|
|
|||
|
SetupMaterial(material, flipY, isLinear, yCbCrTransform, yCbCrTexture, textureTransform, mediaPlayer.VideoLayoutMapping, stereoPacking, alphaPacking);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (texturePropId != -1)
|
|||
|
{
|
|||
|
material.SetTexture(texturePropId, fallbackTexture);
|
|||
|
}
|
|||
|
SetupMaterial(material, false, true, Matrix4x4.identity, null, Matrix4x4.identity);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
internal static void SetupMaterial(
|
|||
|
Material material,
|
|||
|
bool flipVertically,
|
|||
|
bool playerSupportsLinear,
|
|||
|
Matrix4x4 ycbcrTransform,
|
|||
|
Texture ycbcrTexture,
|
|||
|
Matrix4x4 textureTransform,
|
|||
|
VideoMapping mapping = VideoMapping.Normal,
|
|||
|
StereoPacking stereoPacking = StereoPacking.None,
|
|||
|
AlphaPacking alphaPacking = AlphaPacking.None)
|
|||
|
{
|
|||
|
SetupVerticalFlipMaterial(material, flipVertically);
|
|||
|
|
|||
|
// Apply changes for layout
|
|||
|
if (material.HasProperty(VideoRender.PropLayout.Id))
|
|||
|
{
|
|||
|
VideoRender.SetupLayoutMaterial(material, mapping);
|
|||
|
}
|
|||
|
|
|||
|
// Apply changes for stereo videos
|
|||
|
if (material.HasProperty(VideoRender.PropStereo.Id))
|
|||
|
{
|
|||
|
VideoRender.SetupStereoMaterial(material, stereoPacking);
|
|||
|
}
|
|||
|
|
|||
|
// Apply changes for alpha videos
|
|||
|
if (material.HasProperty(VideoRender.PropAlphaPack.Id))
|
|||
|
{
|
|||
|
VideoRender.SetupAlphaPackedMaterial(material, alphaPacking);
|
|||
|
}
|
|||
|
|
|||
|
// Apply gamma correction
|
|||
|
#if UNITY_PLATFORM_SUPPORTS_LINEAR
|
|||
|
if (material.HasProperty(VideoRender.PropApplyGamma.Id))
|
|||
|
{
|
|||
|
VideoRender.SetupGammaMaterial(material, playerSupportsLinear);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
// Adjust for cropping/orientation (when the decoder decodes in blocks that overrun the video frame size, it pads), OES only as we apply this lower down for none-OES
|
|||
|
VideoRender.SetupTextureMatrix(material, textureTransform);
|
|||
|
|
|||
|
#if UNITY_PLATFORM_SUPPORTS_YPCBCR
|
|||
|
VideoRender.SetupYpCbCrMaterial(material, ycbcrTexture != null, ycbcrTransform, ycbcrTexture);
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
[System.Flags]
|
|||
|
public enum ResolveFlags : int
|
|||
|
{
|
|||
|
Mipmaps = 1 << 0,
|
|||
|
PackedAlpha = 1 << 1,
|
|||
|
StereoLeft = 1 << 2,
|
|||
|
StereoRight = 1 << 3,
|
|||
|
ColorspaceSRGB = 1 << 4,
|
|||
|
}
|
|||
|
|
|||
|
public static void SetupResolveMaterial(Material material, VideoResolveOptions options)
|
|||
|
{
|
|||
|
if (options.IsColourAdjust())
|
|||
|
{
|
|||
|
material.EnableKeyword(VideoRender.Keyword_UseHSBC);
|
|||
|
material.SetFloat(VideoRender.PropHue.Id, options.hue);
|
|||
|
material.SetFloat(VideoRender.PropSaturation.Id, options.saturation);
|
|||
|
material.SetFloat(VideoRender.PropBrightness.Id, options.brightness);
|
|||
|
material.SetFloat(VideoRender.PropContrast.Id, options.contrast);
|
|||
|
material.SetFloat(VideoRender.PropInvGamma.Id, 1f / options.gamma);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
material.DisableKeyword(VideoRender.Keyword_UseHSBC);
|
|||
|
}
|
|||
|
|
|||
|
material.color = options.tint;
|
|||
|
}
|
|||
|
|
|||
|
public static RenderTexture ResolveVideoToRenderTexture(Material resolveMaterial, RenderTexture targetTexture, ITextureProducer texture, ResolveFlags flags, ScaleMode scaleMode = ScaleMode.StretchToFill)
|
|||
|
{
|
|||
|
int targetWidth = texture.GetTexture(0).width;
|
|||
|
int targetHeight = texture.GetTexture(0).height;
|
|||
|
|
|||
|
StereoEye eyeMode = StereoEye.Both;
|
|||
|
if (((flags & ResolveFlags.StereoLeft) == ResolveFlags.StereoLeft) &&
|
|||
|
((flags & ResolveFlags.StereoRight) != ResolveFlags.StereoRight))
|
|||
|
{
|
|||
|
eyeMode = StereoEye.Left;
|
|||
|
}
|
|||
|
else if (((flags & ResolveFlags.StereoLeft) != ResolveFlags.StereoLeft) &&
|
|||
|
((flags & ResolveFlags.StereoRight) == ResolveFlags.StereoRight))
|
|||
|
{
|
|||
|
eyeMode = StereoEye.Right;
|
|||
|
}
|
|||
|
|
|||
|
// RJT NOTE: No longer passing in PAR as combined with larger videos (e.g. 8K+) it can lead to textures >16K which most platforms don't support
|
|||
|
// - Instead, the PAR is accounted for during drawing (which is more efficient too)
|
|||
|
// - https://github.com/RenderHeads/UnityPlugin-AVProVideo/issues/1297
|
|||
|
float pixelAspectRatio = 1.0f; // texture.GetTexturePixelAspectRatio();
|
|||
|
GetResolveTextureSize(
|
|||
|
texture.GetTextureAlphaPacking(),
|
|||
|
texture.GetTextureStereoPacking(),
|
|||
|
eyeMode,
|
|||
|
pixelAspectRatio,
|
|||
|
texture.GetTextureMatrix(),
|
|||
|
ref targetWidth,
|
|||
|
ref targetHeight);
|
|||
|
|
|||
|
if (targetTexture)
|
|||
|
{
|
|||
|
bool sizeChanged = (targetTexture.width != targetWidth) || (targetTexture.height != targetHeight);
|
|||
|
if (sizeChanged)
|
|||
|
{
|
|||
|
RenderTexture.ReleaseTemporary(targetTexture);
|
|||
|
targetTexture = null;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!targetTexture)
|
|||
|
{
|
|||
|
RenderTextureReadWrite readWrite = ((flags & ResolveFlags.ColorspaceSRGB) == ResolveFlags.ColorspaceSRGB) ? RenderTextureReadWrite.sRGB : RenderTextureReadWrite.Linear;
|
|||
|
targetTexture = RenderTexture.GetTemporary(targetWidth, targetHeight, 0, RenderTextureFormat.ARGB32, readWrite);
|
|||
|
}
|
|||
|
|
|||
|
// Set target mipmap generation support
|
|||
|
{
|
|||
|
bool requiresMipmap = (flags & ResolveFlags.Mipmaps) == ResolveFlags.Mipmaps;
|
|||
|
bool requiresRecreate = (targetTexture.IsCreated() && targetTexture.useMipMap != requiresMipmap);
|
|||
|
if (requiresRecreate)
|
|||
|
{
|
|||
|
targetTexture.Release();
|
|||
|
}
|
|||
|
if (!targetTexture.IsCreated())
|
|||
|
{
|
|||
|
targetTexture.useMipMap = targetTexture.autoGenerateMips = requiresMipmap;
|
|||
|
targetTexture.Create();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Render resolve blit
|
|||
|
// TODO: combine these two paths into a single material blit
|
|||
|
{
|
|||
|
bool prevSRGB = GL.sRGBWrite;
|
|||
|
GL.sRGBWrite = targetTexture.sRGB;
|
|||
|
RenderTexture prev = RenderTexture.active;
|
|||
|
if (scaleMode == ScaleMode.StretchToFill)
|
|||
|
{
|
|||
|
Graphics.Blit(texture.GetTexture(0), targetTexture, resolveMaterial);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
RenderTexture.active = targetTexture;
|
|||
|
bool partialAreaRender = (scaleMode == ScaleMode.ScaleToFit);
|
|||
|
if (partialAreaRender)
|
|||
|
{
|
|||
|
GL.Clear(false, true, Color.black);
|
|||
|
}
|
|||
|
VideoRender.DrawTexture(new Rect(0f, 0f, targetTexture.width, targetTexture.height), texture.GetTexture(0), scaleMode, texture.GetTextureAlphaPacking(), texture.GetTexturePixelAspectRatio(), resolveMaterial);
|
|||
|
}
|
|||
|
RenderTexture.active = prev;
|
|||
|
GL.sRGBWrite = prevSRGB;
|
|||
|
}
|
|||
|
|
|||
|
return targetTexture;
|
|||
|
}
|
|||
|
|
|||
|
public static void GetResolveTextureSize(AlphaPacking alphaPacking, StereoPacking stereoPacking, StereoEye eyeMode, float pixelAspectRatio, Matrix4x4 textureXfrm, ref int width, ref int height)
|
|||
|
{
|
|||
|
Vector4 size = new Vector4(width, height, 0, 0);
|
|||
|
size = textureXfrm * size;
|
|||
|
width = (int)Mathf.Abs(size.x);
|
|||
|
height = (int)Mathf.Abs(size.y);
|
|||
|
|
|||
|
switch (alphaPacking)
|
|||
|
{
|
|||
|
case AlphaPacking.LeftRight:
|
|||
|
width /= 2;
|
|||
|
break;
|
|||
|
case AlphaPacking.TopBottom:
|
|||
|
height /= 2;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (eyeMode != StereoEye.Both)
|
|||
|
{
|
|||
|
switch (stereoPacking)
|
|||
|
{
|
|||
|
case StereoPacking.LeftRight:
|
|||
|
width /= 2;
|
|||
|
break;
|
|||
|
case StereoPacking.TopBottom:
|
|||
|
height /= 2;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (pixelAspectRatio > 0f)
|
|||
|
{
|
|||
|
if (pixelAspectRatio > 1f)
|
|||
|
{
|
|||
|
width = Mathf.RoundToInt(width * pixelAspectRatio);
|
|||
|
}
|
|||
|
else if (pixelAspectRatio < 1f)
|
|||
|
{
|
|||
|
height = Mathf.RoundToInt(height / pixelAspectRatio);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public static bool RequiresResolve(ITextureProducer texture)
|
|||
|
{
|
|||
|
return (texture.GetTextureAlphaPacking() != AlphaPacking.None ||
|
|||
|
texture.RequiresVerticalFlip() ||
|
|||
|
texture.GetTextureStereoPacking() != StereoPacking.None ||
|
|||
|
texture.GetTextureCount() > 1
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
public static void DrawTexture(Rect destRect, Texture texture, ScaleMode scaleMode, AlphaPacking alphaPacking, float pixelAspectRatio, Material material)
|
|||
|
{
|
|||
|
if (Event.current == null || Event.current.type == EventType.Repaint)
|
|||
|
{
|
|||
|
int sourceWidth = texture.width;
|
|||
|
int sourceHeight = texture.height;
|
|||
|
Matrix4x4 textureXfrm = Matrix4x4.identity;
|
|||
|
GetResolveTextureSize(alphaPacking, StereoPacking.Unknown, StereoEye.Both, pixelAspectRatio, textureXfrm, ref sourceWidth, ref sourceHeight);
|
|||
|
|
|||
|
float sourceRatio = (float)sourceWidth / (float)sourceHeight;
|
|||
|
Rect sourceRect = new Rect(0f, 0f, 1f, 1f);
|
|||
|
switch (scaleMode)
|
|||
|
{
|
|||
|
case ScaleMode.ScaleAndCrop:
|
|||
|
{
|
|||
|
float destRatio = destRect.width / destRect.height;
|
|||
|
if (destRatio > sourceRatio)
|
|||
|
{
|
|||
|
float adjust = sourceRatio / destRatio;
|
|||
|
sourceRect = new Rect(0f, (1f - adjust) * 0.5f, 1f, adjust);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
float adjust = destRatio / sourceRatio;
|
|||
|
sourceRect = new Rect(0.5f - adjust * 0.5f, 0f, adjust, 1f);
|
|||
|
}
|
|||
|
}
|
|||
|
break;
|
|||
|
case ScaleMode.ScaleToFit:
|
|||
|
{
|
|||
|
float destRatio = destRect.width / destRect.height;
|
|||
|
if (destRatio > sourceRatio)
|
|||
|
{
|
|||
|
float adjust = sourceRatio / destRatio;
|
|||
|
destRect = new Rect(destRect.xMin + destRect.width * (1f - adjust) * 0.5f, destRect.yMin, adjust * destRect.width, destRect.height);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
float adjust = destRatio / sourceRatio;
|
|||
|
destRect = new Rect(destRect.xMin, destRect.yMin + destRect.height * (1f - adjust) * 0.5f, destRect.width, adjust * destRect.height);
|
|||
|
}
|
|||
|
}
|
|||
|
break;
|
|||
|
case ScaleMode.StretchToFill:
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
GL.PushMatrix();
|
|||
|
if (RenderTexture.active == null)
|
|||
|
{
|
|||
|
//GL.LoadPixelMatrix();
|
|||
|
GL.LoadPixelMatrix(0f, Screen.width, Screen.height, 0f);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
GL.LoadPixelMatrix(0f, RenderTexture.active.width, RenderTexture.active.height, 0f);
|
|||
|
}
|
|||
|
Graphics.DrawTexture(destRect, texture, sourceRect, 0, 0, 0, 0, GUI.color, material);
|
|||
|
GL.PopMatrix();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|