Thursday, November 01, 2012

Camera Preview Textures on MonoDroid and MonoGame

The saga continues with the conversion of the camera preview stream into XNA Texture2D images.

It seems that the same technique of predicated texturing is used on some Android phones as is used on XBox 360 which means that the texture buffer data for any given texture may not be available immediately after drawing because the Present method outputs the textures in sections according to how much graphics memory is available to the GPU.

The result of this is the frame buffer for a texture is not available for the SetData call and data converted over from the camera preview stream will corrupt the texture nastily if the update happens at the same time.

To overcome this I used two textures A and B and while displaying B I write into A and vice-versa. All a bit complicated but graphics is like that it seems.


I set up the textures like so:

          _cameraBGa = new Texture2D(graphics.GraphicsDevice, _pvWidth, _pvHeight, false, SurfaceFormat.Bgra5551);
            _cameraBGb = new Texture2D(graphics.GraphicsDevice, _pvWidth, _pvHeight, false, SurfaceFormat.Bgra5551);

            _frameData = new short[bs.Width * bs.Height];


Then I fill them like so:

       unsafe void _listener_PreviewFrame(object sender, PreviewFrameEventArgs e)
        {
            lock (this)
            {
                fixed (short* fd = &_frameData[0])
                {
                    fixed (byte* yuv = &e.Data[0])
                    {
                        YUV2RGB.convertYUV420_NV21toRGB5551(yuv, fd,
                                                            _pvWidth, _pvHeight);
                        if (_textureSelect)
                        {
                            _cameraBGb.SetData(_frameData);
                            _bReady = true;
                        }
                        else
                        {
                            _cameraBGa.SetData(_frameData);
                            _aReady = true;
                        }
                        _textureSelect = !_textureSelect;
                    }
                }
                _bgReady = true;
            }
        }

And finally display them like so:

        protected override void Draw(GameTime gameTime)
        {
            graphics.GraphicsDevice.Clear(Color.CornflowerBlue); //Cleared by the camera

            if (_aReady && _bReady)
            {

            spriteBatch.Begin();
           
            spriteBatch.Draw(_textureSelect ? _cameraBGa : _cameraBGb, new Rectangle(0, 0, _displayWidth, _displayHeight), Color.White);


etc, etc, etc.

Ahh I love graphics problems. Why didn't I become a priest or something? 

No comments: