1

I'm developing a kind of research application for Android. The subtask I'm working on is getting a frame from live video stream from Camera. I tried to get it from SurfaceView source (and decoding YUV -> RGB -> HSV), but the FPS is too low (ca 5-7 FPS).

So, please advise me, how to get video frames directly from camera video stream (some low-level stuff like onFrameChanged())

How I did it:

 @Override
    public void onPreviewFrame(byte[] data, Camera camera) {
        yuvs.add(data);
        rgbText.setText("FRAMES: " + count);
        count++;
    }

where yuvs is

 private ArrayList<byte[]> yuvs;

Thanks for any andvice or code snippet

Rachnog
  • 353
  • 1
  • 7
  • 18

3 Answers3

2

Actually FPS is very sensitive to a light conditions and it can variate in wide range (8-30 in my tests). I don't know any reliable way to increase FPS of preview, but only recomendations like decrease resolution, use native API and so on. I can suggest to use this lib https://github.com/natario1/CameraView - it provide the same FPS as native API, but significantly reduces volume of code.

Here is an example(Kotlin) to get RGB bitmap:

cameraView.addFrameProcessor { frame ->
        if(frame!=null) {
            val data = frame.data
            val size = frame.size
            // Process...
            // cameraView.previewSize

            val yuvImage = YuvImage(data, ImageFormat.NV21, size.width, size.height, null)
            val os = ByteArrayOutputStream()
            yuvImage.compressToJpeg(Rect(0, 0, size.width, size.height), 100, os)
            val jpegByteArray = os.toByteArray()
            var bitmap = BitmapFactory.decodeByteArray(jpegByteArray, 0, jpegByteArray.size)
        }
}

And with openCV you can convert it to HSV very fast:

val bmp = convert(bitmap, Bitmap.Config.ARGB_8888)
var mat = Mat(bmp.width, bmp.height, CvType.CV_8UC4)
Utils.bitmapToMat(bmp, mat)
Imgproc.cvtColor(mat, mat, Imgproc.COLOR_RGB2HSV)

fun convert(bitmap: Bitmap, config: Bitmap.Config): Bitmap {
        val convertedBitmap = Bitmap.createBitmap(bitmap.width, bitmap.height, config)
        val canvas = Canvas(convertedBitmap)
        val paint = Paint()
        paint.color = Color.BLACK
        canvas.drawBitmap(bitmap, 0F, 0F, paint)
        return convertedBitmap
    }
Raskilas
  • 691
  • 6
  • 17
0

set that on your Camera object

setPreviewCallback(Camera.PreviewCallback cb)

and on

Camera.PreviewCallback

override

onPreviewFrame(byte[] data, Camera camera)
bummi
  • 27,123
  • 14
  • 62
  • 101
Xenione
  • 2,174
  • 1
  • 23
  • 30
  • Thank you. I've already done it. But it takes frames much slower than 30fps, ca. 5-7 fps, that's the problem, 'cause I need more accuracy to solve my problem. – Rachnog Apr 18 '14 at 10:30
  • use this getSupportedPreviewFpsRange() in Camera.Parameters just to get to know the range of fps that your camera support becouse is a little bit weird becouse should be around 100 fps – Xenione Apr 18 '14 at 10:37
  • is onPreviewFrame called 5 times per second? – Xenione Apr 18 '14 at 10:47
  • hhhhm, I'm just adding byte[] to ArrayList, I didn't changed anything else in onPreviewFrame – Rachnog Apr 18 '14 at 10:52
  • please retrive fps range as I said before – Xenione Apr 18 '14 at 10:58
0

ArrayList is the worst class to use in games, frame rendering, etc. Try this instead
public void onPreviewFrame(byte[] data, Camera camera) { yuvs[count] = data; rgbText.setText("FRAMES: " + count); count++; }
and replace ArrayList<byte[]> with byte[][].

Mk Km
  • 94
  • 6