Esempio n. 1
0
        public virtual CVOpenGLESTexture LumaTextureForPixelBuffer(CVPixelBuffer pixelBuffer)
        {
            CVOpenGLESTexture lumaTexture = null;

            if (_videoTextureCache == null)
            {
                Console.Error.WriteLine("No video texture cache");
                goto bail;
            }

            // Periodic texture cache flush every frame
            _videoTextureCache.Flush(0);

            // CVOpenGLTextureCacheCreateTextureFromImage will create GL texture optimally from CVPixelBufferRef.
            // Y
            lumaTexture = _videoTextureCache.TextureFromImage(pixelBuffer,
                                                              true,
                                                              All.RedExt,
                                                              (int)pixelBuffer.Width,
                                                              (int)pixelBuffer.Height,
                                                              All.RedExt,
                                                              DataType.UnsignedByte,
                                                              0,
                                                              out CVReturn error);

            if (lumaTexture == null || error != CVReturn.Success)
            {
                Console.Error.WriteLine($"Error at creating luma texture using CVOpenGLESTextureCacheCreateTextureFromImage: {error}");
            }

bail:
            return(lumaTexture);
        }
Esempio n. 2
0
        public virtual CVOpenGLESTexture ChromaTextureForPixelBuffer(CVPixelBuffer pixelBuffer)
        {
            CVOpenGLESTexture chromaTexture = null;
            CVReturn          err;

            if (VideoTextureCache == null)
            {
                Console.Error.WriteLine("No video texture cache");
                return(chromaTexture);
            }
            // Periodic texture cache flush every frame
            VideoTextureCache.Flush(0);

            // CVOpenGLTextureCacheCreateTextureFromImage will create GL texture optimally from CVPixelBufferRef.
            // UV
            var height = pixelBuffer.GetHeightOfPlane(1);
            var width  = pixelBuffer.GetWidthOfPlane(1);

            chromaTexture = VideoTextureCache.TextureFromImage(pixelBuffer, true, All.RgExt, width, height, All.RgExt, DataType.UnsignedByte, 1, out err);

            if (chromaTexture == null || err != CVReturn.Success)
            {
                Console.Error.WriteLine("Error at creating chroma texture using CVOpenGLESTextureCacheCreateTextureFromImage: " + err.ToString());
            }

            return(chromaTexture);
        }
Esempio n. 3
0
 virtual void Dispose(bool disposing)
 {
     if (handle != IntPtr.Zero)
     {
         CVOpenGLESTexture.CFRelease(handle);
         handle = IntPtr.Zero;
     }
 }
        public override void DidOutputSampleBuffer(AVCaptureOutput captureOutput, CMSampleBuffer sampleBuffer, AVCaptureConnection connection)
        {
            try
            {
                using (var pixelBuffer = sampleBuffer.GetImageBuffer() as CVPixelBuffer)
                {
                    int width  = (int)pixelBuffer.Width;
                    int height = (int)pixelBuffer.Height;

                    if (this.viewControllerReference.TryGetTarget(out var container))
                    {
                        if (container.Ripple == null || width != this.textureWidth || height != this.textureHeight)
                        {
                            this.textureWidth  = width;
                            this.textureHeight = height;
                            container.SetupRipple(this.textureWidth, this.textureHeight);
                        }

                        this.CleanupTextures();

                        // Y-plane
                        GL.ActiveTexture(TextureUnit.Texture0);
                        All re = (All)0x1903; // GL_RED_EXT, RED component from ARB OpenGL extension

                        this.lumaTexture = container.VideoTextureCache.TextureFromImage(pixelBuffer, true, re, this.textureWidth, this.textureHeight, re, DataType.UnsignedByte, 0, out CVReturn status);
                        if (this.lumaTexture == null)
                        {
                            Console.WriteLine("Error creating luma texture: {0}", status);
                            return;
                        }

                        GL.BindTexture(this.lumaTexture.Target, this.lumaTexture.Name);
                        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge);
                        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge);

                        // UV Plane
                        GL.ActiveTexture(TextureUnit.Texture1);
                        re = (All)0x8227; // GL_RG_EXT, RED GREEN component from ARB OpenGL extension
                        this.chromaTexture = container.VideoTextureCache.TextureFromImage(pixelBuffer, true, re, this.textureWidth / 2, this.textureHeight / 2, re, DataType.UnsignedByte, 1, out status);
                        if (this.chromaTexture == null)
                        {
                            Console.WriteLine("Error creating chroma texture: {0}", status);
                            return;
                        }

                        GL.BindTexture(this.chromaTexture.Target, this.chromaTexture.Name);
                        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge);
                        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge);
                    }
                }
            }
            finally
            {
                sampleBuffer.Dispose();
            }
        }
Esempio n. 5
0
        void CleanUpTextures()
        {
            if (lumaTexture != null)
            {
                lumaTexture.Dispose();
                lumaTexture = null;
            }

            if (chromaTexture != null)
            {
                chromaTexture.Dispose();
                chromaTexture = null;
            }
        }
            public override void DidOutputSampleBuffer(AVCaptureOutput captureOutput, MonoTouch.CoreMedia.CMSampleBuffer sampleBuffer, AVCaptureConnection connection)
            {
                try {
                    using (var pixelBuffer = sampleBuffer.GetImageBuffer() as CVPixelBuffer){
                        int width  = pixelBuffer.Width;
                        int height = pixelBuffer.Height;

                        if (container.ripple == null || width != textureWidth || height != textureHeight)
                        {
                            textureWidth  = width;
                            textureHeight = height;
                            container.SetupRipple(textureWidth, textureHeight);
                        }
                        CleanupTextures();

                        // Y-plane
                        GL.ActiveTexture(All.Texture0);
                        All      re = (All)0x1903;                     // GL_RED_EXT, RED component from ARB OpenGL extension
                        CVReturn status;
                        lumaTexture = container.videoTextureCache.TextureFromImage(pixelBuffer, true, re, textureWidth, textureHeight, re, DataType.UnsignedByte, 0, out status);

                        if (lumaTexture == null)
                        {
                            Console.WriteLine("Error creating luma texture: {0}", status);
                            return;
                        }
                        GL.BindTexture((All)lumaTexture.Target, lumaTexture.Name);
                        GL.TexParameter(All.Texture2D, All.TextureWrapS, (int)All.ClampToEdge);
                        GL.TexParameter(All.Texture2D, All.TextureWrapT, (int)All.ClampToEdge);

                        // UV Plane
                        GL.ActiveTexture(All.Texture1);
                        re            = (All)0x8227;               // GL_RG_EXT, RED GREEN component from ARB OpenGL extension
                        chromaTexture = container.videoTextureCache.TextureFromImage(pixelBuffer, true, re, textureWidth / 2, textureHeight / 2, re, DataType.UnsignedByte, 1, out status);

                        if (chromaTexture == null)
                        {
                            Console.WriteLine("Error creating chroma texture: {0}", status);
                            return;
                        }
                        GL.BindTexture((All)chromaTexture.Target, chromaTexture.Name);
                        GL.TexParameter(All.Texture2D, All.TextureWrapS, (int)All.ClampToEdge);
                        GL.TexParameter(All.Texture2D, All.TextureWrapT, (int)All.ClampToEdge);
                    }
                } finally {
                    sampleBuffer.Dispose();
                }
            }
        private void CleanupTextures()
        {
            if (this.lumaTexture != null)
            {
                this.lumaTexture.Dispose();
                this.lumaTexture = null;
            }

            if (this.chromaTexture != null)
            {
                this.chromaTexture.Dispose();
                this.chromaTexture = null;
            }

            if (this.viewControllerReference.TryGetTarget(out var container))
            {
                container.VideoTextureCache.Flush(CVOptionFlags.None);
            }
        }
Esempio n. 8
0
		void CleanUpTextures ()
		{
			if (lumaTexture != null) {
				lumaTexture.Dispose ();
				lumaTexture = null;
			}

			if (chromaTexture != null) {
				chromaTexture.Dispose ();
				chromaTexture = null;
			}
		}
Esempio n. 9
0
		public void DisplayPixelBuffer (CVPixelBuffer pixelBuffer)
		{
			DrawTextInCorner (pixelBuffer);
			CVReturn error;

			if (pixelBuffer != null) {
				int frameWidth = (int)pixelBuffer.Width;
				int frameHeight = (int)pixelBuffer.Height;

				if (videoTextureCache == null) {
					Console.WriteLine ("No video texture cache");
					return;
				}

				CleanUpTextures ();
				CVAttachmentMode attachmentMode;
				var colorAttachments = pixelBuffer.GetAttachment <NSString> (CVImageBuffer.YCbCrMatrixKey, out attachmentMode);

				if (colorAttachments == CVImageBuffer.YCbCrMatrix_ITU_R_601_4)
					preferredConversion = colorConversion601;
				else
					preferredConversion = colorConversion709;

				GL.ActiveTexture (TextureUnit.Texture0);
				lumaTexture = videoTextureCache.TextureFromImage (pixelBuffer, true, All.RedExt, frameWidth, frameHeight,
					All.RedExt, DataType.UnsignedByte, 0, out error);

				if (lumaTexture == null)
					Console.WriteLine ("Error at CVOpenGLESTextureCach.TextureFromImage");

				GL.BindTexture (lumaTexture.Target, lumaTexture.Name);
				GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
				GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
				GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge);
				GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge);

				GL.ActiveTexture (TextureUnit.Texture1);
				chromaTexture = videoTextureCache.TextureFromImage (pixelBuffer, true, All.RgExt, frameWidth / 2, frameHeight / 2,
					All.RgExt, DataType.UnsignedByte, 1, out error);

				if (chromaTexture == null)
					Console.WriteLine ("Error at CVOpenGLESTextureCach.TextureFromImage");

				GL.BindTexture (chromaTexture.Target, chromaTexture.Name);
				GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
				GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
				GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge);
				GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge);

				GL.BindFramebuffer (FramebufferTarget.Framebuffer, frameBufferHandle);
				GL.Viewport (0, 0, backingWidth, backingHeight);
			}

			GL.ClearColor (0f, 0f, 0f, 1f);
			GL.Clear (ClearBufferMask.ColorBufferBit);

			GL.UseProgram (Program);
			GL.Uniform1 (uniforms [(int)UniformIndex.RotationAngle], 0f);
			GL.UniformMatrix3 (uniforms [(int)UniformIndex.ColorConversionMatrix], 1, false, preferredConversion);

			CGRect vertexSamplingRect = AVUtilities.WithAspectRatio (Bounds, PresentationRect);

			var normalizedSamplingSize = new CGSize (0f, 0f);
			var cropScaleAmount = new CGSize (vertexSamplingRect.Width / Bounds.Width, vertexSamplingRect.Height / Bounds.Height);

			if (cropScaleAmount.Width > cropScaleAmount.Height) {
				normalizedSamplingSize.Width = 1f;
				normalizedSamplingSize.Height = cropScaleAmount.Height / cropScaleAmount.Width;
			} else {
				normalizedSamplingSize.Width = 1f;
				normalizedSamplingSize.Height = cropScaleAmount.Width / cropScaleAmount.Height;
			}

			float[] quadVertexData = {
				-1f * (float)normalizedSamplingSize.Width, -1f * (float)normalizedSamplingSize.Height,
				(float)normalizedSamplingSize.Width, -1f * (float)normalizedSamplingSize.Height,
				-1f * (float)normalizedSamplingSize.Width, (float)normalizedSamplingSize.Height,
				(float)normalizedSamplingSize.Width, (float)normalizedSamplingSize.Height,
			};

			GL.VertexAttribPointer ((int)AttributeIndex.Vertex, 2, VertexAttribPointerType.Float, false, 0, quadVertexData);
			GL.EnableVertexAttribArray ((int)AttributeIndex.Vertex);

			var textureSamplingRect = new CGRect (0, 0, 1, 1);
			float[] quadTextureData = {
				(float)textureSamplingRect.GetMinX (), (float)textureSamplingRect.GetMaxY (),
				(float)textureSamplingRect.GetMaxX (), (float)textureSamplingRect.GetMaxY (),
				(float)textureSamplingRect.GetMinX (), (float)textureSamplingRect.GetMinY (),
				(float)textureSamplingRect.GetMaxX (), (float)textureSamplingRect.GetMinY ()
			};

			GL.VertexAttribPointer ((int)AttributeIndex.TextureCoordinates, 2, VertexAttribPointerType.Float, false, 0, quadTextureData);
			GL.EnableVertexAttribArray ((int)AttributeIndex.TextureCoordinates);

			GL.DrawArrays (BeginMode.TriangleStrip, 0, 4);
			GL.BindRenderbuffer (RenderbufferTarget.Renderbuffer, colorBufferHandle);
			context.PresentRenderBuffer ((int)RenderbufferTarget.Renderbuffer);
		}
Esempio n. 10
0
        public void DisplayPixelBuffer(CVPixelBuffer pixelBuffer)
        {
            DrawTextInCorner(pixelBuffer);
            CVReturn error;

            if (pixelBuffer != null)
            {
                int frameWidth  = (int)pixelBuffer.Width;
                int frameHeight = (int)pixelBuffer.Height;

                if (videoTextureCache == null)
                {
                    Console.WriteLine("No video texture cache");
                    return;
                }

                CleanUpTextures();
                CVAttachmentMode attachmentMode;
                var colorAttachments = pixelBuffer.GetAttachment <NSString> (CVImageBuffer.YCbCrMatrixKey, out attachmentMode);

                if (colorAttachments == CVImageBuffer.YCbCrMatrix_ITU_R_601_4)
                {
                    preferredConversion = colorConversion601;
                }
                else
                {
                    preferredConversion = colorConversion709;
                }

                GL.ActiveTexture(TextureUnit.Texture0);
                lumaTexture = videoTextureCache.TextureFromImage(pixelBuffer, true, All.RedExt, frameWidth, frameHeight,
                                                                 All.RedExt, DataType.UnsignedByte, 0, out error);

                if (lumaTexture == null)
                {
                    Console.WriteLine("Error at CVOpenGLESTextureCach.TextureFromImage");
                }

                GL.BindTexture(lumaTexture.Target, lumaTexture.Name);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge);

                GL.ActiveTexture(TextureUnit.Texture1);
                chromaTexture = videoTextureCache.TextureFromImage(pixelBuffer, true, All.RgExt, frameWidth / 2, frameHeight / 2,
                                                                   All.RgExt, DataType.UnsignedByte, 1, out error);

                if (chromaTexture == null)
                {
                    Console.WriteLine("Error at CVOpenGLESTextureCach.TextureFromImage");
                }

                GL.BindTexture(chromaTexture.Target, chromaTexture.Name);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge);

                GL.BindFramebuffer(FramebufferTarget.Framebuffer, frameBufferHandle);
                GL.Viewport(0, 0, backingWidth, backingHeight);
            }

            GL.ClearColor(0f, 0f, 0f, 1f);
            GL.Clear(ClearBufferMask.ColorBufferBit);

            GL.UseProgram(Program);
            GL.Uniform1(uniforms [(int)UniformIndex.RotationAngle], 0f);
            GL.UniformMatrix3(uniforms [(int)UniformIndex.ColorConversionMatrix], 1, false, preferredConversion);

            CGRect vertexSamplingRect = AVUtilities.WithAspectRatio(Bounds, PresentationRect);

            var normalizedSamplingSize = new CGSize(0f, 0f);
            var cropScaleAmount        = new CGSize(vertexSamplingRect.Width / Bounds.Width, vertexSamplingRect.Height / Bounds.Height);

            if (cropScaleAmount.Width > cropScaleAmount.Height)
            {
                normalizedSamplingSize.Width  = 1f;
                normalizedSamplingSize.Height = cropScaleAmount.Height / cropScaleAmount.Width;
            }
            else
            {
                normalizedSamplingSize.Width  = 1f;
                normalizedSamplingSize.Height = cropScaleAmount.Width / cropScaleAmount.Height;
            }

            float[] quadVertexData =
            {
                -1f * (float)normalizedSamplingSize.Width, -1f * (float)normalizedSamplingSize.Height,
                (float)normalizedSamplingSize.Width,       -1f * (float)normalizedSamplingSize.Height,
                -1f * (float)normalizedSamplingSize.Width, (float)normalizedSamplingSize.Height,
                (float)normalizedSamplingSize.Width,       (float)normalizedSamplingSize.Height,
            };

            GL.VertexAttribPointer((int)AttributeIndex.Vertex, 2, VertexAttribPointerType.Float, false, 0, quadVertexData);
            GL.EnableVertexAttribArray((int)AttributeIndex.Vertex);

            var textureSamplingRect = new CGRect(0, 0, 1, 1);

            float[] quadTextureData =
            {
                (float)textureSamplingRect.GetMinX(), (float)textureSamplingRect.GetMaxY(),
                (float)textureSamplingRect.GetMaxX(), (float)textureSamplingRect.GetMaxY(),
                (float)textureSamplingRect.GetMinX(), (float)textureSamplingRect.GetMinY(),
                (float)textureSamplingRect.GetMaxX(), (float)textureSamplingRect.GetMinY()
            };

            GL.VertexAttribPointer((int)AttributeIndex.TextureCoordinates, 2, VertexAttribPointerType.Float, false, 0, quadTextureData);
            GL.EnableVertexAttribArray((int)AttributeIndex.TextureCoordinates);

            GL.DrawArrays(BeginMode.TriangleStrip, 0, 4);
            GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, colorBufferHandle);
            context.PresentRenderBuffer((int)RenderbufferTarget.Renderbuffer);
        }
        public override void RenderPixelBuffer(MonoTouch.CoreVideo.CVPixelBuffer destinationPixelBuffer, MonoTouch.CoreVideo.CVPixelBuffer foregroundPixelBuffer, MonoTouch.CoreVideo.CVPixelBuffer backgroundPixelBuffer, float tween)
        {
            EAGLContext.SetCurrentContext(CurrentContext);
            if (foregroundPixelBuffer != null || backgroundPixelBuffer != null)
            {
                CVOpenGLESTexture foregroundLumaTexture   = LumaTextureForPixelBuffer(foregroundPixelBuffer);
                CVOpenGLESTexture foregroundChromaTexture = ChromaTextureForPixelBuffer(foregroundPixelBuffer);

                CVOpenGLESTexture backgroundLumaTexture   = LumaTextureForPixelBuffer(backgroundPixelBuffer);
                CVOpenGLESTexture backgroundChromaTexture = ChromaTextureForPixelBuffer(backgroundPixelBuffer);

                CVOpenGLESTexture destLumaTexture   = LumaTextureForPixelBuffer(destinationPixelBuffer);
                CVOpenGLESTexture destChromaTexture = ChromaTextureForPixelBuffer(destinationPixelBuffer);

                GL.UseProgram(ProgramY);

                // Set the render transform
                float[] preferredRenderTransform =
                {
                    RenderTransform.xx, RenderTransform.xy, RenderTransform.x0, 0.0f,
                    RenderTransform.yx, RenderTransform.yy, RenderTransform.y0, 0.0f,
                    0.0f,                             0.0f,               1.0f, 0.0f,
                    0.0f,                             0.0f,               0.0f, 1.0f,
                };


                GL.UniformMatrix4(Uniforms [(int)Uniform.Render_Transform_Y], 1, false, preferredRenderTransform);

                GL.BindFramebuffer(FramebufferTarget.Framebuffer, OffscreenBufferHandle);
                GL.Viewport(0, 0, destinationPixelBuffer.Width, destinationPixelBuffer.Height);

                GL.ActiveTexture(TextureUnit.Texture0);
                GL.BindTexture(foregroundLumaTexture.Target, foregroundLumaTexture.Name);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge);

                GL.ActiveTexture(TextureUnit.Texture1);
                GL.BindTexture(backgroundLumaTexture.Target, backgroundLumaTexture.Name);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge);

                // Attach the destination texture as a color attachment to the off screen frame buffer
                GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferSlot.ColorAttachment0, destLumaTexture.Target, destLumaTexture.Name, 0);

                if (GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer) != FramebufferErrorCode.FramebufferComplete)
                {
                    Console.Error.WriteLine("Failed to make complete framebuffer object " + GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer));
                    foregroundLumaTexture.Dispose();
                    foregroundChromaTexture.Dispose();
                    backgroundLumaTexture.Dispose();
                    backgroundChromaTexture.Dispose();
                    destLumaTexture.Dispose();
                    destChromaTexture.Dispose();
                    VideoTextureCache.Flush(0);
                    EAGLContext.SetCurrentContext(null);
                    return;
                }

                GL.ClearColor(0.0f, 0.0f, 0.0f, 1.0f);
                GL.Clear(ClearBufferMask.ColorBufferBit);

                float[] quadVertexData1 =
                {
                    -1.0f,  1.0f,
                    1.0f,   1.0f,
                    -1.0f, -1.0f,
                    1.0f,  -1.0f,
                };
                // texture data varies from 0 -> 1, whereas vertex data varies from -1 -> 1
                float[] quadTextureData1 =
                {
                    0.5f + quadVertexData1 [0] / 2, 0.5f + quadVertexData1 [1] / 2,
                    0.5f + quadVertexData1 [2] / 2, 0.5f + quadVertexData1 [3] / 2,
                    0.5f + quadVertexData1 [4] / 2, 0.5f + quadVertexData1 [5] / 2,
                    0.5f + quadVertexData1 [6] / 2, 0.5f + quadVertexData1 [7] / 2,
                };

                GL.Uniform1(Uniforms [(int)Uniform.Y], 0);

                GL.VertexAttribPointer((int)Attrib.Vertex_Y, 2, VertexAttribPointerType.Float, false, 0, quadVertexData1);
                GL.EnableVertexAttribArray((int)Attrib.Vertex_Y);

                GL.VertexAttribPointer((int)Attrib.TexCoord_Y, 2, VertexAttribPointerType.Float, false, 0, quadTextureData1);
                GL.EnableVertexAttribArray((int)Attrib.TexCoord_Y);

                // Blend function to draw the foreground frame
                GL.Enable(EnableCap.Blend);
                GL.BlendFunc(BlendingFactorSrc.One, BlendingFactorDest.Zero);

                // Draw the foreground frame
                GL.DrawArrays(BeginMode.TriangleStrip, 0, 4);

                GL.Uniform1(Uniforms [(int)Uniform.Y], 1);

                GL.VertexAttribPointer((int)Attrib.Vertex_Y, 2, VertexAttribPointerType.Float, false, 0, quadVertexData1);
                GL.EnableVertexAttribArray((int)Attrib.Vertex_Y);

                GL.VertexAttribPointer((int)Attrib.TexCoord_Y, 2, VertexAttribPointerType.Float, false, 0, quadTextureData1);
                GL.EnableVertexAttribArray((int)Attrib.TexCoord_Y);

                // Blend function to draw the background frame
                GL.BlendColor(0, 0, 0, tween);
                GL.BlendFunc(BlendingFactorSrc.ConstantAlpha, BlendingFactorDest.OneMinusConstantAlpha);

                // Draw the background frame
                GL.DrawArrays(BeginMode.TriangleStrip, 0, 4);

                // Perform similar operations as above for the UV plane
                GL.UseProgram(ProgramUV);

                GL.UniformMatrix4(Uniforms [(int)Uniform.Render_Transform_UV], 1, false, preferredRenderTransform);

                GL.ActiveTexture(TextureUnit.Texture2);
                GL.BindTexture(foregroundChromaTexture.Target, foregroundChromaTexture.Name);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge);

                GL.ActiveTexture(TextureUnit.Texture3);
                GL.BindTexture(backgroundChromaTexture.Target, backgroundChromaTexture.Name);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)All.Linear);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)All.ClampToEdge);
                GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)All.ClampToEdge);

                GL.Viewport(0, 0, destinationPixelBuffer.Width, destinationPixelBuffer.Height);

                // Attach the destination texture as a color attachment to the off screen frame buffer
                GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferSlot.ColorAttachment0, destChromaTexture.Target, destChromaTexture.Name, 0);

                if (GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer) != FramebufferErrorCode.FramebufferComplete)
                {
                    Console.Error.WriteLine("Failed to make complete framebuffer object " + GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer));
                    foregroundLumaTexture.Dispose();
                    foregroundChromaTexture.Dispose();
                    backgroundLumaTexture.Dispose();
                    backgroundChromaTexture.Dispose();
                    destLumaTexture.Dispose();
                    destChromaTexture.Dispose();
                    this.VideoTextureCache.Flush(0);
                    EAGLContext.SetCurrentContext(null);
                    return;
                }

                GL.ClearColor(0.0f, 0.0f, 0.0f, 1.0f);
                GL.Clear(ClearBufferMask.ColorBufferBit);

                GL.Uniform1(Uniforms [(int)Uniform.UV], 2);

                GL.VertexAttribPointer((int)Attrib.Vertex_UV, 2, VertexAttribPointerType.Float, false, 0, quadVertexData1);
                GL.EnableVertexAttribArray((int)Attrib.Vertex_UV);

                GL.VertexAttribPointer((int)Attrib.TexCoord_UV, 2, VertexAttribPointerType.Float, false, 0, quadTextureData1);
                GL.EnableVertexAttribArray((int)Attrib.TexCoord_UV);

                // Blend function to draw the foreground frame
                GL.BlendFunc(BlendingFactorSrc.One, BlendingFactorDest.Zero);

                // Draw the foreground frame
                GL.DrawArrays(BeginMode.TriangleStrip, 0, 4);

                GL.Uniform1(Uniforms [(int)Uniform.UV], 3);

                GL.VertexAttribPointer((int)Attrib.Vertex_UV, 2, VertexAttribPointerType.Float, false, 0, quadVertexData1);
                GL.EnableVertexAttribArray((int)Attrib.Vertex_UV);

                GL.VertexAttribPointer((int)Attrib.TexCoord_UV, 2, VertexAttribPointerType.Float, false, 0, quadTextureData1);
                GL.EnableVertexAttribArray((int)Attrib.TexCoord_UV);

                // Blend function to draw the background frame
                GL.BlendColor(0, 0, 0, tween);
                GL.BlendFunc(BlendingFactorSrc.ConstantAlpha, BlendingFactorDest.OneMinusConstantAlpha);

                // Draw the background frame
                GL.DrawArrays(BeginMode.TriangleStrip, 0, 4);

                GL.Flush();

                foregroundLumaTexture.Dispose();
                foregroundChromaTexture.Dispose();
                backgroundLumaTexture.Dispose();
                backgroundChromaTexture.Dispose();
                destLumaTexture.Dispose();
                destChromaTexture.Dispose();
                this.VideoTextureCache.Flush(0);
                EAGLContext.SetCurrentContext(null);
            }
        }
			public override void DidOutputSampleBuffer (AVCaptureOutput captureOutput, CMSampleBuffer sampleBuffer, AVCaptureConnection connection)
			{
				try {
					using (var pixelBuffer = sampleBuffer.GetImageBuffer () as CVPixelBuffer){
						int width = (int) pixelBuffer.Width;
						int height = (int) pixelBuffer.Height;

						if (container.ripple == null || width != textureWidth || height != textureHeight){
							textureWidth = width;
							textureHeight = height;
							container.SetupRipple (textureWidth, textureHeight);
						}
						CleanupTextures ();

						// Y-plane
						GL.ActiveTexture(TextureUnit.Texture0);
						All re = (All) 0x1903; // GL_RED_EXT, RED component from ARB OpenGL extension
						CVReturn status;
						lumaTexture = container.videoTextureCache.TextureFromImage (pixelBuffer, true, re, textureWidth, textureHeight, re, DataType.UnsignedByte, 0, out status);

						if (lumaTexture == null){
							Console.WriteLine ("Error creating luma texture: {0}", status);
							return;
						}
						GL.BindTexture (lumaTexture.Target, lumaTexture.Name);
						GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int) All.ClampToEdge);
						GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int) All.ClampToEdge);

						// UV Plane
						GL.ActiveTexture (TextureUnit.Texture1);
						re = (All) 0x8227; // GL_RG_EXT, RED GREEN component from ARB OpenGL extension
						chromaTexture = container.videoTextureCache.TextureFromImage (pixelBuffer, true, re, textureWidth/2, textureHeight/2, re, DataType.UnsignedByte, 1, out status);

						if (chromaTexture == null){
							Console.WriteLine ("Error creating chroma texture: {0}", status);
							return;
						}
						GL.BindTexture (chromaTexture.Target, chromaTexture.Name);
						GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int) All.ClampToEdge);
						GL.TexParameter (TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int) All.ClampToEdge);
					}
				} finally {
					sampleBuffer.Dispose ();
				}
			}