private void InitConversionResources(DeckLinkPlugin.PixelFormat format, int width, int height)
        {
            if (_conversionMaterial != null || _format != format)
            {
                Material.Destroy(_conversionMaterial);
                _conversionMaterial = null;
                _format             = format;
            }

            int texWidth = -1;

            // If we are doing keying and a non-RGBA mode is used for output, then use an RGBA texture,
            // as this conversion will be handled by the DeckLink hardware.
            if (_keyerMode != KeyerMode.None && !HasAlphaChannel(format))
            {
                _conversionMaterial = new Material(_rgbaToArgbShader);
                texWidth            = width;
            }
            else
            {
                // Otherwise convert to the output format
                switch (format)
                {
                case DeckLinkPlugin.PixelFormat.YCbCr_8bpp_422:
                    _conversionMaterial = new Material(_rgbaToYuv422Shader);
                    texWidth            = width / 2;
                    break;

                case DeckLinkPlugin.PixelFormat.YCbCr_10bpp_422:
                    _conversionMaterial = new Material(_rgbaToYuv422Shader2);
                    texWidth            = (width / 6) * 4;
                    _conversionMaterial.SetFloat("_TextureWidth", texWidth);
                    break;

                case DeckLinkPlugin.PixelFormat.BGRA_8bpp_444:
                    _conversionMaterial = new Material(_rgbaToBgraShader);
                    texWidth            = width;
                    break;

                case DeckLinkPlugin.PixelFormat.ARGB_8bpp_444:
                    _conversionMaterial = new Material(_rgbaToArgbShader);
                    texWidth            = width;
                    break;

                default:
                    break;
                }
            }

            if (_parameters != null)
            {
                _parameters.Release();
                _parameters = null;
            }

            DeckLinkPlugin.SetOutputBufferPointer(_deviceIndex, null);
            DeckLinkPlugin.SetOutputTexturePointer(_deviceIndex, IntPtr.Zero);
            DeckLinkPlugin.SetRightOutputBufferPointer(_deviceIndex, null);
            DeckLinkPlugin.SetRightOutputTexturePointer(_deviceIndex, IntPtr.Zero);

            if (_convertedTexture != null)
            {
                RenderTexture.ReleaseTemporary(_convertedTexture);
                _convertedTexture = null;
                _convertedPointer = IntPtr.Zero;
            }

            if (_rightConvertedTexture != null)
            {
                RenderTexture.ReleaseTemporary(_rightConvertedTexture);
                _rightConvertedTexture = null;
                _rightConvertedPointer = IntPtr.Zero;
            }

            if (_outputBuffer != null)
            {
                _outputBuffer = null;
            }

            if (_rightOutputBuffer != null)
            {
                _rightOutputBuffer = null;
            }

            if (_convertedCompBuffer != null)
            {
                _convertedCompBuffer.Release();
                _convertedCompBuffer = null;
            }

            if (texWidth < 0)
            {
                //sets up compute buffers
                if (_format == DeckLinkPlugin.PixelFormat.RGBX_10bpp_444 ||
                    _format == DeckLinkPlugin.PixelFormat.RGBX_10bpp_444_LE ||
                    _format == DeckLinkPlugin.PixelFormat.RGB_10bpp_444)
                {
                    _parameters = new ComputeBuffer(1, ComputeBufferParams.Size());

                    ComputeBufferParams[] parms = new ComputeBufferParams[1];
                    parms[0].height      = (uint)height;
                    parms[0].width       = (uint)width;
                    parms[0].bufferWidth = (uint)(width + 63) / 64 * 64;
                    parms[0].leading     = _format == DeckLinkPlugin.PixelFormat.RGB_10bpp_444 ? 1U : 0U;
                    bool formatBigEndian = _format != DeckLinkPlugin.PixelFormat.RGBX_10bpp_444_LE ? true : false;
                    if (BitConverter.IsLittleEndian)
                    {
                        formatBigEndian = !formatBigEndian;
                    }
                    parms[0].bigEndian = formatBigEndian ? 1U : 0U;
                    parms[0].isLinear  = QualitySettings.activeColorSpace == ColorSpace.Linear ? 1U : 0U;

                    _outputBuffer = new byte[parms[0].bufferWidth * parms[0].height * 4];
                    if (_current3DEnabled)
                    {
                        _rightOutputBuffer = new byte[parms[0].bufferWidth * parms[0].height * 4];
                    }

                    _convertedCompBuffer = new ComputeBuffer((int)(parms[0].bufferWidth * parms[0].height), 4, ComputeBufferType.Raw);

                    _parameters.SetData(parms);

                    DeckLinkPlugin.SetOutputBufferPointer(_deviceIndex, _outputBuffer);
                    DeckLinkPlugin.SetRightOutputBufferPointer(_deviceIndex, _rightOutputBuffer);
                }
                else
                {
                    RenderTextureReadWrite readWriteMode = (QualitySettings.activeColorSpace == ColorSpace.Linear ? RenderTextureReadWrite.Linear : RenderTextureReadWrite.Default);

                    _convertedTexture = RenderTexture.GetTemporary(width, height, 0, RenderTextureFormat.ARGB32, readWriteMode, 1);
                    _convertedPointer = _convertedTexture.GetNativeTexturePtr();
                    DeckLinkPlugin.SetOutputTexturePointer(_deviceIndex, _convertedPointer);

                    if (_current3DEnabled)
                    {
                        _rightConvertedTexture = RenderTexture.GetTemporary(width, height, 0, RenderTextureFormat.ARGB32, readWriteMode, 1);
                        _rightConvertedPointer = _rightConvertedTexture.GetNativeTexturePtr();
                        DeckLinkPlugin.SetRightOutputTexturePointer(_deviceIndex, _rightConvertedPointer);
                    }
                }
            }
            else
            {
                RenderTextureReadWrite readWriteMode = (QualitySettings.activeColorSpace == ColorSpace.Linear ? RenderTextureReadWrite.Linear : RenderTextureReadWrite.Default);

                RenderTextureFormat textureFormat = RenderTextureFormat.ARGB32;
                if (format == DeckLinkPlugin.PixelFormat.YCbCr_10bpp_422)
                {
                    textureFormat = RenderTextureFormat.ARGB2101010;
                }

                _convertedTexture = RenderTexture.GetTemporary(texWidth, height, 0, textureFormat, readWriteMode, 1);
                _convertedPointer = _convertedTexture.GetNativeTexturePtr();
                DeckLinkPlugin.SetOutputTexturePointer(_deviceIndex, _convertedPointer);

                if (_current3DEnabled)
                {
                    _rightConvertedTexture = RenderTexture.GetTemporary(texWidth, height, 0, textureFormat, readWriteMode, 1);
                    _rightConvertedPointer = _rightConvertedTexture.GetNativeTexturePtr();
                    DeckLinkPlugin.SetRightOutputTexturePointer(_deviceIndex, _rightConvertedPointer);
                }
            }
        }
        protected override void Cleanup()
        {
#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
            StopOutput();

            if (_inputTexture != null)
            {
                RenderTexture.ReleaseTemporary(_inputTexture);
                _inputTexture = null;
            }

            if (_rightInputTexture != null)
            {
                RenderTexture.ReleaseTemporary(_rightInputTexture);
                _rightInputTexture = null;
            }

            if (_capturedFrames != null)
            {
                foreach (var frame in _capturedFrames)
                {
                    RenderTexture.ReleaseTemporary(frame);
                }
                _capturedFrames = null;
            }

            if (_rightCapturedFrames != null)
            {
                foreach (var frame in _rightCapturedFrames)
                {
                    RenderTexture.ReleaseTemporary(frame);
                }
                _rightCapturedFrames = null;
            }

            if (_blended != null)
            {
                RenderTexture.ReleaseTemporary(_blended);
                _blended = null;
            }

            if (_rightBlended != null)
            {
                RenderTexture.ReleaseTemporary(_rightBlended);
                _rightBlended = null;
            }

            if (_interlacedTexture != null)
            {
                RenderTexture.ReleaseTemporary(_interlacedTexture);
                _blended = null;
            }

            DeckLinkPlugin.SetOutputBufferPointer(_deviceIndex, null);
            DeckLinkPlugin.SetOutputTexturePointer(_deviceIndex, IntPtr.Zero);
            DeckLinkPlugin.SetRightOutputBufferPointer(_deviceIndex, null);
            DeckLinkPlugin.SetRightOutputTexturePointer(_deviceIndex, IntPtr.Zero);

            if (_convertedTexture != null)
            {
                RenderTexture.ReleaseTemporary(_convertedTexture);
                _convertedTexture = null;
                _convertedPointer = IntPtr.Zero;
            }

            if (_rightConvertedTexture)
            {
                RenderTexture.ReleaseTemporary(_rightConvertedTexture);
                _rightConvertedTexture = null;
                _rightConvertedPointer = IntPtr.Zero;
            }

            if (_outputBuffer != null)
            {
                _outputBuffer = null;
            }

            if (_rightOutputBuffer != null)
            {
                _rightOutputBuffer = null;
            }

            if (_parameters != null)
            {
                _parameters.Release();
                _parameters = null;
            }

            if (_convertedCompBuffer != null)
            {
                _convertedCompBuffer.Release();
                _convertedCompBuffer = null;
            }

            if (_interlaceMaterial != null)
            {
                Destroy(_interlaceMaterial);
                _interlaceMaterial = null;
            }

            if (_conversionMaterial != null)
            {
                Destroy(_conversionMaterial);
                _conversionMaterial = null;
            }

            if (_blendMat != null)
            {
                Destroy(_blendMat);
                _blendMat = null;
            }
#endif
        }
        protected override void Process()
        {
#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
            if (_device == null)
            {
                return;
            }

            bool restartDevice = false;

            if (_current3DEnabled != _enable3D)
            {
                _current3DEnabled = _enable3D;
                restartDevice     = true;
            }

            _device.LowLatencyMode = _lowLatencyMode;

            // If we're syncing to an input, then make sure we output using the same frame rate
            if (_syncedToInput != null && _syncedToInput.Device != null && _syncedToInput.Device.IsStreamingInput && _syncedToInput.ModeIndex >= 0)
            {
                // If we're using auto detect mode then we need to wait for frames to start coming in, otherwise
                // it may be still on the default mode awaiting auto detection
                if (!_syncedToInput._autoDetectMode || _syncedToInput.Device.FramesTotal > 1)
                {
                    var inputMode  = _syncedToInput.Device.CurrentMode;
                    var outputMode = (Device == null) ? null : Device.CurrentOutputMode;

                    // TODO: add better support for interlaced modes
                    float inputFrameRate = inputMode.FrameRate;                    // * (inputMode.InterlacedFieldMode ? 2 : 1);

                    if (outputMode == null || outputMode.FrameRate != inputFrameRate)
                    {
                        _filterModeByFPS         = true;
                        _filterModeByInterlacing = true;

                        _modeFPS         = inputFrameRate;
                        _modeInterlacing = false;

                        restartDevice = true;
                    }
                }
                else
                {
                    return;
                }
            }

            if (restartDevice)
            {
                StopOutput();
                Begin(true);

                if (_device == null)
                {
                    return;
                }
            }

            _enable3D = _current3DEnabled;

            if (_conversionMaterial != null)
            {
                //in this case, since we are dealing with non-srgb texture, need to do conversion from gamma to linear
                if (QualitySettings.activeColorSpace == ColorSpace.Linear && !_bypassGamma)
                {
                    _conversionMaterial.EnableKeyword("APPLY_GAMMA");
                }
                else
                {
                    _conversionMaterial.DisableKeyword("APPLY_GAMMA");
                }
                if (_ignoreAlphaChannel)
                {
                    _conversionMaterial.EnableKeyword(ShaderKeyIgnoreAlpha);
                }
                else
                {
                    _conversionMaterial.DisableKeyword(ShaderKeyIgnoreAlpha);
                }

                switch (_colorspaceMode)
                {
                case DeckLink.ColorspaceMode.Rec709:
                    _conversionMaterial.DisableKeyword(ShaderKeyRec2020);
                    _conversionMaterial.DisableKeyword(ShaderKeyRec2100);
                    _conversionMaterial.EnableKeyword(ShaderKeyRec709);
                    break;

                case DeckLink.ColorspaceMode.Rec2020:
                    _conversionMaterial.DisableKeyword(ShaderKeyRec709);
                    _conversionMaterial.DisableKeyword(ShaderKeyRec2100);
                    _conversionMaterial.EnableKeyword(ShaderKeyRec2020);
                    break;

                case DeckLink.ColorspaceMode.Rec2100:
                    _conversionMaterial.DisableKeyword(ShaderKeyRec709);
                    _conversionMaterial.DisableKeyword(ShaderKeyRec2020);
                    _conversionMaterial.EnableKeyword(ShaderKeyRec2100);
                    break;
                }
            }

            if (_convertedTexture != null && _convertedPointer == IntPtr.Zero)
            {
                _convertedPointer = _convertedTexture.GetNativeTexturePtr();
                DeckLinkPlugin.SetOutputTexturePointer(_deviceIndex, _convertedPointer);
            }

            if (_rightConvertedTexture != null && _rightConvertedPointer == IntPtr.Zero)
            {
                _rightConvertedPointer = _rightConvertedTexture.GetNativeTexturePtr();
                DeckLinkPlugin.SetRightOutputTexturePointer(_deviceIndex, _rightConvertedPointer);
            }

            if (_device.IsStreamingOutput)
            {
                CaptureFrame();

                if (CanOutputFrame())
                {
                    if (_syncedToInput)
                    {
                        _syncedToInput.UnsetInputReceivedFlag = true;
                    }

                    if (DeckLinkSettings.Instance._multiOutput)
                    {
                        BlendCapturedFrames();
                    }

                    RenderTexture input = _blended;

                    input = Interlace(input, !_current3DEnabled);
                    Convert(input, _convertedTexture, _outputBuffer);

                    if (_current3DEnabled)
                    {
                        input = _rightBlended;
                        input = Interlace(input, true);
                        Convert(input, _rightConvertedTexture, _rightOutputBuffer);
                    }

                    if (_syncedToInput == null)
                    {
                        AdjustPlaybackFramerate();
                    }

                    DeckLinkPlugin.SetDeviceOutputReady(_deviceIndex);
                }
            }
            ProcessAudio();
#endif
        }