diff --git a/Runtime/Scripts/TextureVideoSource.cs b/Runtime/Scripts/TextureVideoSource.cs index 5b140c86..38fc33fc 100644 --- a/Runtime/Scripts/TextureVideoSource.cs +++ b/Runtime/Scripts/TextureVideoSource.cs @@ -10,6 +10,7 @@ namespace LiveKit public class TextureVideoSource : RtcVideoSource { TextureFormat _textureFormat; + private RenderTexture _flippedRT; public Texture Texture { get; } @@ -39,6 +40,17 @@ public TextureVideoSource(Texture texture, VideoBufferType bufferType = VideoBuf Dispose(false); } + protected override void Dispose(bool disposing) + { + if (disposing && _flippedRT != null) + { + _flippedRT.Release(); + UnityEngine.Object.Destroy(_flippedRT); + _flippedRT = null; + } + base.Dispose(disposing); + } + // Read the texture data into a native array asynchronously protected override bool ReadBuffer() { @@ -53,10 +65,20 @@ protected override bool ReadBuffer() _bufferType = GetVideoBufferType(_textureFormat); _captureBuffer = new NativeArray(GetWidth() * GetHeight() * GetStrideForBuffer(_bufferType), Allocator.Persistent); _previewTexture = new Texture2D(GetWidth(), GetHeight(), _textureFormat, false); + if (_flippedRT != null) + { + _flippedRT.Release(); + UnityEngine.Object.Destroy(_flippedRT); + } + _flippedRT = new RenderTexture(GetWidth(), GetHeight(), 0, compatibleFormat); textureChanged = true; } - Graphics.CopyTexture(Texture, _previewTexture); - AsyncGPUReadback.RequestIntoNativeArray(ref _captureBuffer, _previewTexture, 0, _textureFormat, OnReadback); + // Vertically flip into an intermediate RT so the bytes AsyncGPUReadback produces are + // top-down (WebRTC expects top-down; Unity render textures are bottom-up on macOS/Metal + // and other GL-origin platforms). + Graphics.Blit(Texture, _flippedRT, new Vector2(1f, -1f), new Vector2(0f, 1f)); + Graphics.CopyTexture(_flippedRT, _previewTexture); + AsyncGPUReadback.RequestIntoNativeArray(ref _captureBuffer, _flippedRT, 0, _textureFormat, OnReadback); return textureChanged; } }