Android裁剪YUV同时支持Camera1 Camera2

在Android中使用Camera避免不了操作YUV,但是我们经常会遇到在不同手机上Camera出来的尺寸不是我们想要的,这个时候就需要裁剪了,最优办法当然是从源头YUV进行处理,一是YUV相对来说数据量较小,二是在源头上处理了,可以为后续流程节省CPU算力开销。如果你们在整个工程中用的是Texture,我也有解决方案,稍后放出来。

源码地址与Demo:https://github.com/bookzhan/bzyuvlib

首先我们要知道Android 中常见的YUV数据结构:

YV12:YYYYYYYY VVUU

NV21:YYYYYYYY UVUV

YUV420:YYYYYYYY UUVV

我们裁剪的原理就是通过一个矩形区域startX,startY,disWidth,disHeight来操作指针,copy出这个矩形区域的数据,话不多说直接上代码:

extern "C"
JNIEXPORT jint JNICALL
Java_com_luoye_bzyuvlib_BZYUVUtil_cropNV21(JNIEnv *env, jclass type, jbyteArray src_,
                                           jbyteArray dis_, jint srcWidth, jint srcHeight,
                                           jint startX, jint startY, jint disWidth,
                                           jint disHeight) {
    if (NULL == src_ || NULL == dis_ || startX < 0 || startY < 0 ||
        startX + disWidth > srcWidth || startY + disHeight > srcHeight) {
        BZLogUtil::logE(
                "cropNV21 param is error NULL == src_ || NULL == dis_ || startX < 0 || startY < 0 ||startX + disWidth > srcWidth || startY + disHeight > srcHeight");
        return -1;
    }
    jsize srcLength = env->GetArrayLength(src_);
    if (srcLength < srcWidth * srcHeight * 3 / 2) {
        BZLogUtil::logE("srcLength < srcWidth * srcHeight * 3 / 2");
        return -1;
    }
    jsize disLength = env->GetArrayLength(dis_);
    if (disLength < disWidth * disHeight * 3 / 2) {
        BZLogUtil::logE("disLength < disWidth * disHeight * 3 / 2");
        return -1;
    }

    jbyte *src = env->GetByteArrayElements(src_, NULL);
    jbyte *dis = env->GetByteArrayElements(dis_, NULL);

    if (nullptr == src || nullptr == dis) {
        BZLogUtil::logE("nullptr == src || nullptr == dis");
        return -1;
    }

    //Align
    startY = startY / 2 * 2;
    startX = startX / 2 * 2;
    disWidth = disWidth / 2 * 2;
    disHeight = disHeight / 2 * 2;

    //The x and y values are reversed
//    startY = srcHeight - disHeight - startY;
//    startX = srcWidth - disWidth - startX;

    signed char *srcStartP = src + srcWidth * startY;
    signed char *disStartP = dis;

    //copyY
    for (int i = 0; i < disHeight; ++i) {
        memcpy(disStartP, srcStartP + startX, (size_t) disWidth);
        disStartP += disWidth;
        srcStartP += srcWidth;
    }
    //This is where the UV starts
    srcStartP = src + srcWidth * srcHeight + srcWidth * startY / 2;
    //copyUV
    for (int i = 0; i < disHeight / 2; ++i) {
        memcpy(disStartP, srcStartP + startX, (size_t) disWidth);
        disStartP += disWidth;
        srcStartP += srcWidth;
    }

    env->ReleaseByteArrayElements(src_, src, 0);
    env->ReleaseByteArrayElements(dis_, dis, 0);
    return 0;
}

YU12与YUV420(I420)只是UV顺序不同这里不影响我们裁剪,可以合并成一个函数

extern "C"
JNIEXPORT jint JNICALL
Java_com_luoye_bzyuvlib_BZYUVUtil_cropYUV420(JNIEnv *env, jclass type, jbyteArray src_,
                                             jbyteArray dis_, jint srcWidth, jint srcHeight,
                                             jint startX, jint startY, jint disWidth,
                                             jint disHeight) {
    if (NULL == src_ || NULL == dis_ || startX < 0 || startY < 0 ||
        startX + disWidth > srcWidth || startY + disHeight > srcHeight) {
        BZLogUtil::logE(
                "cropYV12 param is error NULL == src_ || NULL == dis_ || startX < 0 || startY < 0 ||startX + disWidth > srcWidth || startY + disHeight > srcHeight");
        return -1;
    }
    jsize srcLength = env->GetArrayLength(src_);
    if (srcLength < srcWidth * srcHeight * 3 / 2) {
        BZLogUtil::logE("srcLength < srcWidth * srcHeight * 3 / 2");
        return -1;
    }
    jsize disLength = env->GetArrayLength(dis_);
    if (disLength < disWidth * disHeight * 3 / 2) {
        BZLogUtil::logE("disLength < disWidth * disHeight * 3 / 2");
        return -1;
    }

    jbyte *src = env->GetByteArrayElements(src_, NULL);
    jbyte *dis = env->GetByteArrayElements(dis_, NULL);

    if (nullptr == src || nullptr == dis) {
        BZLogUtil::logE("nullptr == src || nullptr == dis");
        return -1;
    }

    //Align
    startY = startY / 2 * 2;
    startX = startX / 2 * 2;
    disWidth = disWidth / 2 * 2;
    disHeight = disHeight / 2 * 2;

    //The x and y values are reversed
//    startY = srcHeight - disHeight - startY;
//    startX = srcWidth - disWidth - startX;

    signed char *srcStartP = src + srcWidth * startY;
    signed char *disStartP = dis;

    //copyY
    for (int i = 0; i < disHeight; ++i) {
        memcpy(disStartP, srcStartP + startX, (size_t) disWidth);
        disStartP += disWidth;
        srcStartP += srcWidth;
    }
    //copy Y or V
    srcStartP = src + srcWidth * srcHeight + srcWidth * startY / 4;
    for (int i = 0; i < disHeight / 2; ++i) {
        memcpy(disStartP, srcStartP + startX / 2, (size_t) disWidth);
        disStartP += disWidth / 2;
        srcStartP += srcWidth / 2;
    }
    //copy Y or V
    srcStartP = src + srcWidth * srcHeight * 5 / 4 + srcWidth * startY / 4;
    for (int i = 0; i < disHeight / 2; ++i) {
        memcpy(disStartP, srcStartP + startX / 2, (size_t) disWidth);
        disStartP += disWidth / 2;
        srcStartP += srcWidth / 2;
    }

    env->ReleaseByteArrayElements(src_, src, 0);
    env->ReleaseByteArrayElements(dis_, dis, 0);
    return 0;
}

YUV转RGB

YUV转RGB RenderScript版

此条目发表在Android分类目录。将固定链接加入收藏夹。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注