ishan jain
ishan jain

Reputation: 681

PreviewCallback for Camera video

Can someone provide me the sample code or example for reading each frame of Camera video using PreviewCallback interface?

I want to get the frame without using surface as I want frame of the camera video first without displaying on the screen and then I can pass that frame to the CCLayer of cocos2dx.

Upvotes: 0

Views: 612

Answers (1)

David Manpearl
David Manpearl

Reputation: 12656

This is a slow process and cannot process every frame of data delivered to the preview callback. It should only be used if your requirements for a live preview application make it impossible to display video from the camera or video from the camera with a stencil type overlay, and your display can tolerate only a few frames per second with some latency.

Some important steps:

  1. Your Activity must extend Surface Holder, and you shouldn't start the camera until the surface is created.
  2. Preview only supports a specific size on each device (480 x 320 on the last device I checked - some time ago), but your request will not cause any problems, it will just get ignored. When you finally do receive the preview callback, check the actual frame size in onPreviewFrame().
  3. The byte[] array data sent to onPreviewFrame() is in YCbCr_422_SP format. No other formats are available, even if you attempt to set them. The data is described here: http://groups.google.com/group/android-developers/msg/d3b29d3ddc8abf9b
  4. Don't try to decode the data in onPreviewFrame(). There isn't enough time - you will hose the camera if you try to hold up the system in that function for so long. Copy the data to your own buffer and decode in a separate Thread.
  5. You will have to skip processing of new frames received while your Thread is processing any particular frame. Wait until the Thread is finished before using the data from the next available frame.

Decode the YUV Preview Data:

// decode Y, U, and V values on the YUV 420 buffer 
// described as YCbCr_422_SP by Android - David Manpearl
public static void decodeYUV(int[] out, byte[] fg, int width, int 
height) throws NullPointerException, IllegalArgumentException { 
        final int sz = width * height; 
        if(out == null) throw new NullPointerException("buffer 'out' is null"); 
        if(out.length < sz) throw new IllegalArgumentException("buffer 'out' size " + out.length + " < minimum " + sz); 
        if(fg == null) throw new NullPointerException("buffer 'fg' is null"); 
        if(fg.length < sz) throw new IllegalArgumentException("buffer 'fg' size " + fg.length + " < minimum " + sz * 3/ 2); 
        int i, j; 
        int Y, Cr = 0, Cb = 0; 
        for(j = 0; j < height; j++) { 
                int pixPtr = j * width; 
                final int jDiv2 = j >> 1; 
                for(i = 0; i < width; i++) { 
                        Y = fg[pixPtr]; if(Y < 0) Y += 255; 
                        if((i & 0x1) != 1) { 
                                final int cOff = sz + jDiv2 * width + (i >> 1) * 2; 
                                Cb = fg[cOff]; 
                                if(Cb < 0) Cb += 127; else Cb -= 128; 
                                Cr = fg[cOff + 1]; 
                                if(Cr < 0) Cr += 127; else Cr -= 128; 
                        } 
                        int R = Y + Cr + (Cr >> 2) + (Cr >> 3) + (Cr >> 5); 
                        if(R < 0) R = 0; else if(R > 255) R = 255; 
                        int G = Y - (Cb >> 2) + (Cb >> 4) + (Cb >> 5) - (Cr >> 1) + (Cr >> 3) + (Cr >> 4) + (Cr >> 5); 
                        if(G < 0) G = 0; else if(G > 255) G = 255; 
                        int B = Y + Cb + (Cb >> 1) + (Cb >> 2) + (Cb >> 6); 
                        if(B < 0) B = 0; else if(B > 255) B = 255; 
                        out[pixPtr++] = 0xff000000 + (B << 16) + (G << 8) + R; 
                } 
        } 
} 

Convert byte[] Array to Bitmap:

Bitmap bitmap = BitmapFactory.decodeByteArray(out , 0, out.length);

Upvotes: 1

Related Questions