2024-09-05 16:43:17 +02:00
using UnityEngine ;
//-----------------------------------------------------------------------------
// Copyright 2019-2023 RenderHeads Ltd. All rights reserved.
//-----------------------------------------------------------------------------
namespace RenderHeads.Media.AVProVideo
{
/// Renders the video texture to a RenderTexture - either one provided by the user (external) or to an internal one.
/// The video frames can optionally be "resolved" to unpack packed alpha, display a single stereo eye, generate mip maps, and apply colorspace conversions
[AddComponentMenu("AVPro Video/Resolve To RenderTexture", 330)]
[HelpURL("https://www.renderheads.com/products/avpro-video/")]
public class ResolveToRenderTexture : MonoBehaviour
{
[SerializeField] MediaPlayer _mediaPlayer = null ;
[SerializeField] VideoResolveOptions _options = VideoResolveOptions . Create ( ) ;
[SerializeField] VideoRender . ResolveFlags _resolveFlags = ( VideoRender . ResolveFlags . ColorspaceSRGB | VideoRender . ResolveFlags . Mipmaps | VideoRender . ResolveFlags . PackedAlpha | VideoRender . ResolveFlags . StereoLeft ) ;
[SerializeField] RenderTexture _externalTexture = null ;
private Material _materialResolve ;
private bool _isMaterialSetup ;
private bool _isMaterialDirty ;
private bool _isMaterialOES ;
private RenderTexture _internalTexture ;
private int _textureFrameCount = - 1 ;
// Material used for blitting the texture as we need a shader to provide clamp to border colour style texture sampling
private Material _materialBlit ;
private int _srcTexId ;
public MediaPlayer MediaPlayer
{
get
{
return _mediaPlayer ;
}
set
{
ChangeMediaPlayer ( value ) ;
}
}
public VideoResolveOptions VideoResolveOptions
{
get
{
return _options ;
}
set
{
_options = value ;
_isMaterialDirty = true ;
}
}
public RenderTexture ExternalTexture
{
get
{
return _externalTexture ;
}
set
{
_externalTexture = value ;
}
}
public RenderTexture TargetTexture
{
get
{
if ( _externalTexture = = null )
return _internalTexture ;
return _externalTexture ;
}
}
public void SetMaterialDirty ( )
{
_isMaterialDirty = true ;
}
private void ChangeMediaPlayer ( MediaPlayer mediaPlayer )
{
if ( _mediaPlayer ! = mediaPlayer )
{
_mediaPlayer = mediaPlayer ;
_textureFrameCount = - 1 ;
_isMaterialSetup = false ;
_isMaterialDirty = true ;
Resolve ( ) ;
}
}
void Start ( )
{
_isMaterialOES = _mediaPlayer ! = null ? _mediaPlayer . IsUsingAndroidOESPath ( ) : false ;
_materialResolve = VideoRender . CreateResolveMaterial ( _isMaterialOES ) ;
VideoRender . SetupMaterialForMedia ( _materialResolve , _mediaPlayer , - 1 ) ;
_materialBlit = new Material ( Shader . Find ( "AVProVideo/Internal/Blit" ) ) ;
_srcTexId = Shader . PropertyToID ( "_SrcTex" ) ;
}
void LateUpdate ( )
{
Debug . Assert ( _mediaPlayer ! = null ) ;
Resolve ( ) ;
}
public void Resolve ( )
{
ITextureProducer textureProducer = _mediaPlayer ! = null ? _mediaPlayer . TextureProducer : null ;
if ( textureProducer = = null )
return ;
if ( textureProducer . GetTexture ( ) )
{
// Check for a swap between OES and none-OES
bool playerIsOES = _mediaPlayer . IsUsingAndroidOESPath ( ) ;
if ( _isMaterialOES ! = playerIsOES )
{
_isMaterialOES = playerIsOES ;
_materialResolve = VideoRender . CreateResolveMaterial ( playerIsOES ) ;
}
if ( ! _isMaterialSetup )
{
VideoRender . SetupMaterialForMedia ( _materialResolve , _mediaPlayer , - 1 ) ;
_isMaterialSetup = true ;
_isMaterialDirty = true ;
}
if ( _isMaterialDirty )
{
VideoRender . SetupResolveMaterial ( _materialResolve , _options ) ;
_isMaterialDirty = false ;
}
int textureFrameCount = textureProducer . GetTextureFrameCount ( ) ;
if ( textureFrameCount ! = _textureFrameCount )
{
_internalTexture = VideoRender . ResolveVideoToRenderTexture ( _materialResolve , _internalTexture , textureProducer , _resolveFlags ) ;
_textureFrameCount = textureFrameCount ;
if ( _internalTexture & & _externalTexture )
{
float srcAspectRatio = ( float ) _internalTexture . width / ( float ) _internalTexture . height ;
float dstAspectRatio = ( float ) _externalTexture . width / ( float ) _externalTexture . height ;
Vector2 offset = Vector2 . zero ;
Vector2 scale = new Vector2 ( 1.0f , 1.0f ) ;
// No point in handling the aspect ratio if the textures dimension's are the same
if ( srcAspectRatio ! = dstAspectRatio )
{
switch ( _options . aspectRatio )
{
case VideoResolveOptions . AspectRatio . NoScaling :
scale . x = ( float ) _externalTexture . width / ( float ) _internalTexture . width ;
scale . y = ( float ) _externalTexture . height / ( float ) _internalTexture . height ;
offset . x = ( 1.0f - scale . x ) * 0.5f ;
offset . y = ( 1.0f - scale . y ) * 0.5f ;
break ;
case VideoResolveOptions . AspectRatio . FitVertically :
scale . x = ( float ) _internalTexture . height / ( float ) _internalTexture . width * dstAspectRatio ;
offset . x = ( 1.0f - scale . x ) * 0.5f ;
break ;
case VideoResolveOptions . AspectRatio . FitHorizontally :
scale . y = ( float ) _externalTexture . height / ( float ) _externalTexture . width * srcAspectRatio ;
offset . y = ( 1.0f - scale . y ) * 0.5f ;
break ;
case VideoResolveOptions . AspectRatio . FitInside :
{
if ( srcAspectRatio > dstAspectRatio )
goto case VideoResolveOptions . AspectRatio . FitHorizontally ;
else if ( srcAspectRatio < dstAspectRatio )
goto case VideoResolveOptions . AspectRatio . FitVertically ;
} break ;
case VideoResolveOptions . AspectRatio . FitOutside :
{
if ( srcAspectRatio > dstAspectRatio )
goto case VideoResolveOptions . AspectRatio . FitVertically ;
else if ( srcAspectRatio < dstAspectRatio )
goto case VideoResolveOptions . AspectRatio . FitHorizontally ;
} break ;
case VideoResolveOptions . AspectRatio . Stretch :
break ;
}
}
// NOTE: This blit can be removed once we can ResolveVideoToRenderTexture is made not to recreate textures
// NOTE: This blit probably doesn't do correct linear/srgb conversion if the colorspace settings differ, may have to use GL.sRGBWrite
// NOTE: Cannot use _MainTex as Graphics.Blit replaces the texture offset and scale when using a material
_materialBlit . SetTexture ( _srcTexId , _internalTexture ) ;
_materialBlit . SetTextureOffset ( _srcTexId , offset ) ;
_materialBlit . SetTextureScale ( _srcTexId , scale ) ;
Graphics . Blit ( null , _externalTexture , _materialBlit , 0 ) ;
}
}
}
}
void OnDisable ( )
{
if ( _internalTexture )
{
2025-02-21 10:21:19 +01:00
RenderTexture . ReleaseTemporary ( _internalTexture ) ;
_internalTexture = null ;
2024-09-05 16:43:17 +02:00
}
}
void OnDestroy ( )
{
if ( _materialResolve )
{
2025-02-21 10:21:19 +01:00
Destroy ( _materialResolve ) ;
_materialResolve = null ;
2024-09-05 16:43:17 +02:00
}
}
#if false
void OnGUI ( )
{
if ( TargetTexture )
{
GUI . DrawTexture ( new Rect ( 0f , 0f , Screen . width * 0.8f , Screen . height * 0.8f ) , TargetTexture , ScaleMode . ScaleToFit , true ) ;
}
}
#endif
}
}