18

When trying to convert the byte[] of Camera.onPreviewFrame to Bitamp using BitmapFactory.decodeByteArray gives me an error SkImageDecoder::Factory returned null

Following is my code:

public void onPreviewFrame(byte[] data, Camera camera) {
    Bitmap bmp=BitmapFactory.decodeByteArray(data, 0, data.length);
}
Vinod Maurya
  • 4,167
  • 11
  • 50
  • 81
  • Meybe it will be useful to someone. Look at my solution here: http://stackoverflow.com/questions/20298699/onpreviewframe-data-image-to-imageview/34438806#34438806 – DeniSHow Dec 23 '15 at 15:28

4 Answers4

34

This has been hard to find! But since API 8, there is a YuvImage class in android.graphics. It's not an Image descendent, so all you can do with it is save it to Jpeg, but you could save it to memory stream and then load into Bitmap Image if that's what you need.

import android.graphics.YuvImage;

@Override
public void onPreviewFrame(byte[] data, Camera camera) {
    try {
        Camera.Parameters parameters = camera.getParameters();
        Size size = parameters.getPreviewSize();
        YuvImage image = new YuvImage(data, parameters.getPreviewFormat(),
                size.width, size.height, null);
        File file = new File(Environment.getExternalStorageDirectory()
                .getPath() + "/out.jpg");
        FileOutputStream filecon = new FileOutputStream(file);
        image.compressToJpeg(
                new Rect(0, 0, image.getWidth(), image.getHeight()), 90,
                filecon);
    } catch (FileNotFoundException e) {
        Toast toast = Toast
                .makeText(getBaseContext(), e.getMessage(), 1000);
        toast.show();
    }
}
weston
  • 54,145
  • 21
  • 145
  • 203
  • 2
    This is a very hacky solution. Saving to a jpeg and then immediately decoding it? I think I'd rather use a custom YUV function. – Timmmm Sep 11 '12 at 11:56
  • 1
    @Timmmm I agree that a custom YUV function, which are not hard to come across, would be better than saving and loading via jpeg. But this is sill best if saving to jpeg is all you want to do. I think it's a shame `YuvImage` is not an `Image` descendant, then it wouldn't need any hacking or self YUV coding. – weston Sep 11 '12 at 12:18
7

Since Android 3.0 you can use a TextureView and TextureSurface to display the camera, and then use mTextureView.getBitmap() to retrieve a friendly RGB preview frame.

A very skeletal example of how to do this is given in the TextureView docs. Note that you'll have to set your application or activity to be hardware accelerated by putting android:hardwareAccelerated="true" in the manifest.

Timmmm
  • 88,195
  • 71
  • 364
  • 509
4

I found the answer after a long time. Here it is...

Instead of using BitmapFactory, I used my custom method to decode this byte[] data to a valid image format. To decode the image to a valid image format, one need to know what picture format is being used by the camera by calling camera.getParameters().getPictureFormat(). This returns a constant defined by ImageFormat. After knowing the format, use the appropriate encoder to encode the image.

In my case, the byte[] data was in the YUV format, so I looked for YUV to BMP conversion and that solved my problem.

Andrew Wyld
  • 7,133
  • 7
  • 54
  • 96
Vinod Maurya
  • 4,167
  • 11
  • 50
  • 81
  • Can you please tell me how do you query the **camera.getParametrs()** , how i can check my image format? – Numair Jul 17 '12 at 17:23
  • @Numair http://developer.android.com/reference/android/hardware/Camera.Parameters.html#getPictureFormat() – Andrew Wyld May 15 '13 at 10:44
  • It's also possible to call http://developer.android.com/reference/android/hardware/Camera.Parameters.html#setPreviewFormat(int) but not all cameras support all formats. `NV21` or `YV12` are apparently universally supported and the default is `NV21`. – Andrew Wyld May 15 '13 at 10:49
  • @ArslanAhmad not sure where the code is now. Consider looking at http://developer.android.com/reference/android/graphics/YuvImage.html (may be helpful) – Vinod Maurya Jun 02 '14 at 08:31
2

you can try this: This example send camera frames to server

 @Override
        public void onPreviewFrame(byte[] data, Camera camera) {
        try {
            byte[] baos = convertYuvToJpeg(data, camera);
            StringBuilder dataBuilder = new StringBuilder();
            dataBuilder.append("data:image/jpeg;base64,").append(Base64.encodeToString(baos, Base64.DEFAULT));
            mSocket.emit("newFrame", dataBuilder.toString());
        } catch (Exception e) {
           Log.d("########", "ERROR");
        }
    }

};


public byte[] convertYuvToJpeg(byte[] data, Camera camera) {

    YuvImage image = new YuvImage(data, ImageFormat.NV21,
            camera.getParameters().getPreviewSize().width, camera.getParameters().getPreviewSize().height, null);

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    int quality = 20; //set quality
    image.compressToJpeg(new Rect(0, 0, camera.getParameters().getPreviewSize().width, camera.getParameters().getPreviewSize().height), quality, baos);//this line decreases the image quality


    return baos.toByteArray();
}
vrbsm
  • 1,188
  • 15
  • 22