Android Camera2 preview data format YUV_420_888 collection of I420 turn Bitmap

I. Introduction

He said simply, is how to convert YUV I420 format RGBA8888 format.

In Camera2 API, the camera can not be used directly NV21 preview format acquired, otherwise a error “NV21 format is not supported”exception. We use YUV_420_888 official recommended format for this presentation format, you can refer to the official document or Baidu.

If you get to the camera preview data, and converted into byte YUV I420 format [], I can refer to this blog post:

Android Camera2 to get the callback data frame preview

Suppose we want to further data into YUV I420 Bitmap format to save or show how to do it?

Second, the transcoding process

Internet has been a lot of mature picture transcoding method and a library. Not described in detail herein transcoding principle, only code as a reference.

1. ColorConvertUtil

First, write a Java class that is responsible for color conversion right. And to provide a yuv420pToBitmapmethod.

import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.util.Log;

import java.nio.ByteBuffer;

public class ColorConvertUtil {

    private static final String TAG = "ColorConvertUtil";

    public static Bitmap yuv420pToBitmap(byte[] yuv420p, int width, int height) {
        if (yuv420p == null || width < 0 || height < 0) {
            Log.e(TAG, "cropNv21ToBitmap failed: illegal para !");
            return null;
        }
        byte[] rgba = new byte[width * height * 4];
        ColorConvertUtil.yuv420pToRGBA(yuv420p, width, height, rgba);
        Bitmap bitmap = byteArrayToBitmap(rgba, width, height);
        return bitmap;
    }

    public static void yuv420pToRGBA(byte[] yuv420p, int width, int height, byte[] rgba) {
        if (yuv420p == null || rgba == null) {
            Log.e(TAG, "yuv420pToRGBA failed: yuv420p or rgba is null ");
            return;
        }
        if (yuv420p.length != width * height * 3 / 2) {
            Log.e(TAG, "yuv420p length: " + yuv420p.length);
            Log.e(TAG, "yuv420pToRGBA failed: yuv420p length error!");
            return;
        }
        NativeLibrary.yuv420p2rgba(yuv420p, width, height, rgba);
    }

    /**
     * 将 rgba 的 byte[] 数据转换成 bitmap
     *
     * @param rgba   输入的 rgba 数据
     * @param width  图片宽度
     * @param height 图片高度
     * @return 得到的 bitmap
     */
    public static Bitmap byteArrayToBitmap(byte[] rgba, int width, int height) {
        ByteBuffer buffer = ByteBuffer.wrap(rgba);
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        bitmap.copyPixelsFromBuffer(buffer);
        return bitmap;
    }

2. NativeLibrary

Pictures transcoding operations such proposal is still on the bottom to do, so a new NativeLibrary class that calls the underlying code.

public class NativeLibrary {

    static {
        System.loadLibrary("native-lib");
    }

    public static native void yuv420p2rgba(byte[] yuv420p,
                                          int width,
                                          int height,
                                          byte[] rgba);
}

3. NativeLibrary.cpp

NativeLibrary cpp files corresponding to the class:

#include "com_afei_camera2getpreview_util_NativeLibrary.h"
#include "ImageUtil.h"

JNIEXPORT void JNICALL Java_com_afei_camera2getpreview_util_NativeLibrary_yuv420p2rgba
        (JNIEnv *env, jclass type, jbyteArray yuv420p_, jint width, jint height, jbyteArray rgba_) {
    jbyte *yuv420p = env->GetByteArrayElements(yuv420p_, NULL);
    jbyte *rgba = env->GetByteArrayElements(rgba_, NULL);

    i420torgba(reinterpret_cast<const unsigned char *>(yuv420p), width, height, reinterpret_cast<unsigned char *>(rgba));

    env->ReleaseByteArrayElements(yuv420p_, yuv420p, 0);
    env->ReleaseByteArrayElements(rgba_, rgba, 0);
}

4. ImageUtil.cpp

Transcoding actual implementation code, as follows:

#include "ImageUtil.h"

#define MAX(a, b) ((a > b) ? a : b)
#define MIN(a, b) ((a < b) ? a : b)
#define CLAP(a) (MAX((MIN(a, 0xff)), 0x00))

void i420torgba(const unsigned char *imgY,
                const int width,
                const int height,
                unsigned char *imgDst) {
    int w, h;
    int shift = 14, offset = 8192;
    int C0 = 22987, C1 = -11698, C2 = -5636, C3 = 29049;

    int y1, y2, u1, v1;

    const unsigned char *pY1 = imgY;
    const unsigned char *pY2 = imgY + width;
    const unsigned char *pU = imgY + width * height;
    const unsigned char *pV = imgY + (int) (width * height * 1.25);

    unsigned char *pD1 = imgDst;
    unsigned char *pD2 = imgDst + width * 4;

    for (h = 0; h < height; h += 2) {
        for (w = 0; w < width; w += 2) {
            v1 = *pV - 128;
            pV++;
            u1 = *pU - 128;
            pU++;

            y1 = *pY1;
            y2 = *pY2;

            *pD1++ = CLAP(y1 + ((v1 * C0 + offset) >> shift)); // r
            *pD1++ = CLAP(y1 + ((u1 * C2 + v1 * C1 + offset) >> shift)); // g
            *pD1++ = CLAP(y1 + ((u1 * C3 + offset) >> shift)); // b
            *pD1++ = 0xff; // a
            *pD2++ = CLAP(y2 + ((v1 * C0 + offset) >> shift)); // r
            *pD2++ = CLAP(y2 + ((u1 * C2 + v1 * C1 + offset) >> shift)); // g
            *pD2++ = CLAP(y2 + ((u1 * C3 + offset) >> shift)); // b
            *pD2++ = 0xff; // a

            pY1++;
            pY2++;
            y1 = *pY1;
            y2 = *pY2;

            *pD1++ = CLAP(y1 + ((v1 * C0 + offset) >> shift)); // r
            *pD1++ = CLAP(y1 + ((u1 * C2 + v1 * C1 + offset) >> shift)); // g
            *pD1++ = CLAP(y1 + ((u1 * C3 + offset) >> shift)); // b
            *pD1++ = 0xff; // a
            *pD2++ = CLAP(y2 + ((v1 * C0 + offset) >> shift)); // r
            *pD2++ = CLAP(y2 + ((u1 * C2 + v1 * C1 + offset) >> shift)); // g
            *pD2++ = CLAP(y2 + ((u1 * C3 + offset) >> shift)); // b
            *pD2++ = 0xff; // a
            pY1++;
            pY2++;
        }
        pY1 += width;
        pY2 += width;
        pD1 += 4 * width;
        pD2 += 4 * width;
    }
}

Third, other

Other code and project configuration, you can refer to:

https://github.com/afei-cn/Camera2GetPreview

The above project is a complete demo can be run directly, including the acquisition and preservation camera preview data.

Guess you like

Origin blog.csdn.net/afei__/article/details/94744855