public void OnImageAvailable(ImageReader reader)
            {
                Image image = reader.AcquireLatestImage();

                if (image == null)
                {
                    return;
                }

                Image.Plane[] planes      = image.GetPlanes();
                int           totalLength = 0;

                for (int i = 0; i < planes.Length; i++)
                {
                    Java.Nio.ByteBuffer buffer = planes[i].Buffer;
                    totalLength += buffer.Remaining();
                }

                if (_data == null || _data.Length != totalLength)
                {
                    _data = new byte[totalLength];
                }
                int offset = 0;

                for (int i = 0; i < planes.Length; i++)
                {
                    Java.Nio.ByteBuffer buffer = planes[i].Buffer;
                    int length = buffer.Remaining();

                    buffer.Get(_data, offset, length);
                    offset += length;
                }

                if (_yuv420Converter == null)
                {
                    _yuv420Converter = new YUV420Converter(_activity);
                }

                if (_bitmapSrcBuffer[_bitmapBufferIdx] == null || image.Width != (_bitmapSrcBuffer[_bitmapBufferIdx].Width) || (image.Height != _bitmapSrcBuffer[_bitmapBufferIdx].Height))
                {
                    _bitmapSrcBuffer[_bitmapBufferIdx] = Bitmap.CreateBitmap(image.Width, image.Height, Bitmap.Config.Argb8888);
                }
                Bitmap bmpSrc = _bitmapSrcBuffer[_bitmapBufferIdx];

                _yuv420Converter.YUV_420_888_toRGBIntrinsics(image.Width, image.Height, _data, bmpSrc);


                using (Mat m = new Mat(bmpSrc.Height, bmpSrc.Width, DepthType.Cv8U, 4, bmpSrc.LockPixels(),
                                       bmpSrc.Width * 4))
                {
                    bmpSrc.UnlockPixels();
                    CvInvoke.CvtColor(m, _bgrMat, ColorConversion.Bgra2Bgr);

                    //Rotate 90 degree by transpose and flip
                    CvInvoke.Transpose(_bgrMat, _rotatedMat);
                    CvInvoke.Flip(_rotatedMat, _rotatedMat, FlipType.Horizontal);

                    //apply a simple invert filter
                    CvInvoke.BitwiseNot(_rotatedMat, _rotatedMat);
                }

                _activity.SetImage(_rotatedMat);
                _bitmapBufferIdx = (_bitmapBufferIdx + 1) % _bitmapSrcBuffer.Length;



                /*
                 * GCHandle dataHandle = GCHandle.Alloc(_data, GCHandleType.Pinned);
                 * using (Mat m = new Mat((image.Height << 1) + (image.Height >> 1), image.Width, DepthType.Cv8U, 1,
                 *  dataHandle.AddrOfPinnedObject(), image.Width))
                 * {
                 *  CvInvoke.CvtColor(m, _bgrMat, ColorConversion.Yuv420Sp2Bgr);
                 *
                 *  if (_activity != null)
                 *      _activity.SetImage(_bgrMat);
                 * }
                 * dataHandle.Free();
                 */
                //int bytesPerPixel = ImageFormat.GetBitsPerPixel(Android.Graphics.ImageFormatType.Yuv420888) / 8;
                //int dataSize = width * height * bytesPerPixel;

                /*
                 * byte[] rowData = new byte[planes[0].RowStride];
                 *
                 * for (int i = 0; i < planes.Length; i++)
                 * {
                 *  buffer = planes[i].Buffer;
                 *  rowStride = planes[i].RowStride;
                 *  pixelStride = planes[i].PixelStride;
                 *  int w = (i == 0) ? width : width / 2;
                 *  int h = (i == 0) ? height : height / 2;
                 *  for (int row = 0; row < h; row++)
                 *  {
                 *      if (pixelStride == bytesPerPixel)
                 *      {
                 *          int length = w * bytesPerPixel;
                 *          buffer.Get(_data, offset, length);
                 *
                 *          // Advance buffer the remainder of the row stride, unless on the last row.
                 *          // Otherwise, this will throw an IllegalArgumentException because the buffer
                 *          // doesn't include the last padding.
                 *          if (h - row != 1)
                 *          {
                 *              buffer.Position(buffer.Position() + rowStride - length);
                 *          }
                 *          offset += length;
                 *      }
                 *      else
                 *      {
                 *
                 *          // On the last row only read the width of the image minus the pixel stride
                 *          // plus one. Otherwise, this will throw a BufferUnderflowException because the
                 *          // buffer doesn't include the last padding.
                 *          if (h - row == 1)
                 *          {
                 *              buffer.Get(rowData, 0, width - pixelStride + 1);
                 *          }
                 *          else
                 *          {
                 *              buffer.Get(rowData, 0, rowStride);
                 *          }
                 *
                 *          for (int col = 0; col < w; col++)
                 *          {
                 *              _data[offset++] = rowData[col * pixelStride];
                 *          }
                 *      }
                 *  }
                 * }*/

                image.Close();
                //image.Dispose();
            }
        public void OnImageAvailable(ImageReader reader)
        {
            Image image = reader.AcquireLatestImage();

            if (image == null)
            {
                return;
            }

            Image.Plane[] planes      = image.GetPlanes();
            int           totalLength = 0;

            for (int i = 0; i < planes.Length; i++)
            {
                Java.Nio.ByteBuffer buffer = planes[i].Buffer;
                totalLength += buffer.Remaining();
            }

            if (_data == null || _data.Length != totalLength)
            {
                _data = new byte[totalLength];
            }
            int offset = 0;

            for (int i = 0; i < planes.Length; i++)
            {
                Java.Nio.ByteBuffer buffer = planes[i].Buffer;
                int length = buffer.Remaining();

                buffer.Get(_data, offset, length);
                offset += length;
            }

            if (_yuv420Converter == null)
            {
                _yuv420Converter = new YUV420Converter(Android.App.Application.Context);
            }

            if (_bitmapSrcBuffer[_bitmapBufferIdx] == null || image.Width != (_bitmapSrcBuffer[_bitmapBufferIdx].Width) || (image.Height != _bitmapSrcBuffer[_bitmapBufferIdx].Height))
            {
                _bitmapSrcBuffer[_bitmapBufferIdx] = Bitmap.CreateBitmap(image.Width, image.Height, Bitmap.Config.Argb8888);
            }
            Bitmap bmpSrc = _bitmapSrcBuffer[_bitmapBufferIdx];

            _yuv420Converter.YUV_420_888_toRGBIntrinsics(image.Width, image.Height, _data, bmpSrc);


            using (Mat m = new Mat(bmpSrc.Height, bmpSrc.Width, DepthType.Cv8U, 4, bmpSrc.LockPixels(),
                                   bmpSrc.Width * 4))
            {
                bmpSrc.UnlockPixels();
                CvInvoke.CvtColor(m, _bgrMat, ColorConversion.Bgra2Bgr);

                //Rotate 90 degree by transpose and flip
                CvInvoke.Transpose(_bgrMat, _rotatedMat);
                CvInvoke.Flip(_rotatedMat, _rotatedMat, FlipType.Horizontal);

                //apply a simple invert filter
                CvInvoke.BitwiseNot(_rotatedMat, _rotatedMat);
            }

            if (OnImageProcessed != null)
            {
                OnImageProcessed(reader, _rotatedMat);
            }

            _bitmapBufferIdx = (_bitmapBufferIdx + 1) % _bitmapSrcBuffer.Length;


            image.Close();
            //image.Dispose();
        }