美文网首页
关于libyuv格式转换、图像裁剪说明

关于libyuv格式转换、图像裁剪说明

作者: 璃云曦 | 来源:发表于2020-03-23 14:47 被阅读0次

    项目源代码https://github.com/liluojun/PlayVideo

             Android相机输出的是yuv数据、yuv数据格式太多了如420p、420sp等,我们经常会需要对yuv数据做处理,最原始的使用java for循环的方式耗时太多不合算,libyuv是由google开源的一个针对yuv数据处理的库,其效率比使用java处理的方式快太多了,故比较推荐使用。

    public class NativeMethod {

    public native void nv21ToI420(byte[] src, byte[] dst, int w, int h, byte[] y, byte[] u, byte[] v);

    public native void nv21ToNv12(byte[] src, byte[] dst, int w, int h, byte[] y, byte[] u, byte[] v);

    public native void nv21CutterToI420(byte[] src, byte[] dst, int cutter_w, int cutter_h, int w, int h, byte[] y, byte[] u, byte[] v);

    public native void nv21CutterToNv12(byte[] src, byte[] dst, int cutter_w, int cutter_h, int w, int h, byte[] y, byte[] u, byte[] v);

    }

    我在项目中提供了4个方法示例前两个是nv21转420p和420sp,后两个是转的过程中做出裁剪。

    参数说明:byte[] src 源数据

                      byte[] dst转换后的输出数据

                      int cutter_w裁剪的宽度

                      int cutter_h裁剪的高度

                      int w原宽度

                      int h原高度

                     byte[] y, byte[] u, byte[] v裁剪后yuv三个分量的数据,由于我用的是yuv渲染故需要这些值,没需求的可以不用理会。

    jni层代码

    #define  LOGE(...) __android_log_print(ANDROID_LOG_ERROR,"ffmpeg",__VA_ARGS__)

    #ifndef _Included_media_jni_NativeMethod

    #define _Included_media_jni_NativeMethod

    #ifdef __cplusplus

    extern "C" {

    #include "libyuv.h"

    #include

    #include "media_jni_NativeMethod.h"

    #endif

    void releaseByteArray(JNIEnv *env, jbyteArray array, uint8_t *elems, jint mode) {

    env->ReleaseByteArrayElements(array, (jbyte *) elems, mode);

    env->DeleteLocalRef(array);

    }

    /*

    * Class:    media_jni_NativeMethod

    * Method:    nv21ToI420

    * Signature: ([B[BII)V

    */

    JNIEXPORT void JNICALL Java_media_jni_NativeMethod_nv21ToI420

    (JNIEnv *env, jobject job, jbyteArray src, jbyteArray dst, jint w, jint h, jbyteArray y,

    jbyteArray u, jbyteArray v) {

    uint8_t *srcArray = (uint8_t *) env->GetByteArrayElements(src, NULL);

    uint8_t *dstArray = (uint8_t *) env->GetByteArrayElements(dst, NULL);

    uint8_t *yArray = (uint8_t *) env->GetByteArrayElements(y, NULL);

    uint8_t *uArray = (uint8_t *) env->GetByteArrayElements(u, NULL);

    uint8_t *vArray = (uint8_t *) env->GetByteArrayElements(v, NULL);

    jint uvW = w >> 1;

    jint ySize = w * h;

    jint uSize = (uvW) * (h >> 1);

    uint8_t *y_src = srcArray;

    uint8_t *uv_src = srcArray + ySize;

    uint8_t *y_dst = dstArray;

    uint8_t *u_dst = dstArray + ySize;

    uint8_t *v_dst = dstArray + ySize + uSize;

    libyuv::NV21ToI420(y_src, w, uv_src, w, y_dst, w, u_dst, uvW, v_dst, uvW, w, h);

    memcpy(yArray, y_dst, ySize);

    memcpy(uArray, u_dst, (w * h) >> 2);

    memcpy(vArray, v_dst, (w * h) >> 2);

    //I420旋转方法注释但不能删除

    //    yuv.libyuv::I420Rotate(y_tran, w, u_tran, w >> 1, v_tran, w >> 1, y_dst, h, u_dst, h >> 1, v_dst,

    //                      h >> 1, h, w, yuv.libyuv::kRotate270);

    releaseByteArray(env, src, srcArray, 0);

    releaseByteArray(env, dst, dstArray, 0);

    releaseByteArray(env, y, yArray, 0);

    releaseByteArray(env, v, vArray, 0);

    releaseByteArray(env, u, uArray, 0);

    } ;

    /*

    * Class:    media_jni_NativeMethod

    * Method:    nv21ToNv12

    * Signature: ([B[BII)V

    */

    JNIEXPORT void JNICALL Java_media_jni_NativeMethod_nv21ToNv12

    (JNIEnv *env, jobject job, jbyteArray src, jbyteArray dst, jint w, jint h, jbyteArray y,

    jbyteArray u, jbyteArray v) {

    LOGE("111");

    uint8_t *srcArray = (uint8_t *) env->GetByteArrayElements(src, 0);

    uint8_t *dstArray = (uint8_t *) env->GetByteArrayElements(dst, 0);

    LOGE("222");

    uint8_t *yArray = (uint8_t *) env->GetByteArrayElements(y, NULL);

    uint8_t *uArray = (uint8_t *) env->GetByteArrayElements(u, NULL);

    uint8_t *vArray = (uint8_t *) env->GetByteArrayElements(v, NULL);

    jint ySize = w * h;

    jint uvSize = (w >> 1) * (h >> 1);

    uint8_t *y_src = srcArray;

    uint8_t *uv_src = srcArray + ySize;

    uint8_t *u_src = srcArray + ySize;

    uint8_t *v_src = srcArray + ySize + uvSize;

    uint8_t *y_dst = dstArray;

    uint8_t *uv_dst = dstArray + ySize;

    libyuv::NV21ToI420(y_src, w, uv_src, w, yArray, w, uArray, w >> 1, vArray, w >> 1, w,

    h);

    libyuv::I420ToNV12(yArray, w, uArray, w >> 1, vArray, w >> 1, y_dst, w, uv_dst, w, w, h);

    releaseByteArray(env, src, srcArray, 0);

    releaseByteArray(env, dst, dstArray, 0);

    releaseByteArray(env, y, yArray, 0);

    releaseByteArray(env, v, vArray, 0);

    releaseByteArray(env, u, uArray, 0);

    } ;

    /*

    * Class:    media_jni_NativeMethod

    * Method:    nv21CutterToI420

    * Signature: ([B[BIIII)V

    */

    JNIEXPORT void JNICALL Java_media_jni_NativeMethod_nv21CutterToI420

    (JNIEnv *env, jobject job, jbyteArray src, jbyteArray dst, jint cw, jint ch, jint w,

    jint h, jbyteArray y,

    jbyteArray u, jbyteArray v) {

    uint8_t *srcArray = (uint8_t *) env->GetByteArrayElements(src, 0);

    uint8_t *dstArray = (uint8_t *) env->GetByteArrayElements(dst, 0);

    jbyteArray transitJbyteArray = env->NewByteArray(w * h * 3 / 2);

    uint8_t *transitArray = (uint8_t *) env->GetByteArrayElements(transitJbyteArray, 0);

    uint8_t *yArray = (uint8_t *) env->GetByteArrayElements(y, NULL);

    uint8_t *uArray = (uint8_t *) env->GetByteArrayElements(u, NULL);

    uint8_t *vArray = (uint8_t *) env->GetByteArrayElements(v, NULL);

    jint ySize = w * h;

    jint startx = (w - cw) / 2;

    jint starty = (h - ch) / 2;

    jint uvSize = (w >> 1) * (h >> 1);

    uint8_t *y_src = srcArray;

    uint8_t *uv_src = srcArray + ySize;

    uint8_t *y_transit = transitArray;

    uint8_t *u_transit = transitArray + ySize;

    uint8_t *v_transit = transitArray + ySize + uvSize;

    uint8_t *y_dst = dstArray;

    uint8_t *u_dst = dstArray + (cw * ch);

    uint8_t *v_dst = dstArray + (cw * ch) + ((cw * ch) >> 2);

    libyuv::NV21ToI420(y_src, w, uv_src, w, y_transit, w, u_transit, w >> 1, v_transit, w >> 1, w,

    h);

    libyuv::ConvertToI420(transitArray, ySize + uvSize, y_dst, cw, u_dst, cw >> 1,

    v_dst, cw >> 1,

    startx, starty, w, h, cw, ch, libyuv::kRotate0, libyuv::FOURCC_I420);

    memcpy(yArray, y_dst, cw * ch);

    memcpy(uArray, u_dst, (cw * ch) >> 2);

    memcpy(vArray, v_dst, (cw * ch) >> 2);

    releaseByteArray(env, transitJbyteArray, transitArray, 0);

    releaseByteArray(env, src, srcArray, 0);

    releaseByteArray(env, dst, dstArray, 0);

    releaseByteArray(env, y, yArray, 0);

    releaseByteArray(env, v, vArray, 0);

    releaseByteArray(env, u, uArray, 0);

    } ;

    /*

    * Class:    media_jni_NativeMethod

    * Method:    nv21CutterToNv12

    * Signature: ([B[BIIII)V

    */

    JNIEXPORT void JNICALL Java_media_jni_NativeMethod_nv21CutterToNv12

    (JNIEnv *env, jobject job, jbyteArray src, jbyteArray dst, jint cw, jint ch, jint w,

    jint h, jbyteArray y,

    jbyteArray u, jbyteArray v) {

    uint8_t *srcArray = (uint8_t *) env->GetByteArrayElements(src, 0);

    uint8_t *dstArray = (uint8_t *) env->GetByteArrayElements(dst, 0);

    uint8_t *yArray = (uint8_t *) env->GetByteArrayElements(y, NULL);

    uint8_t *uArray = (uint8_t *) env->GetByteArrayElements(u, NULL);

    uint8_t *vArray = (uint8_t *) env->GetByteArrayElements(v, NULL);

    jbyteArray transitJbyteArray = env->NewByteArray(w * h * 3 / 2);

    uint8_t *transitArray = (uint8_t *) env->GetByteArrayElements(transitJbyteArray, 0);

    jint ySize = w * h;

    jint startx = (w - cw) / 2;

    jint starty = (h - ch) / 2;

    jint uvSize = (w >> 1) * (h >> 1);

    uint8_t *y_src = srcArray;

    uint8_t *uv_src = srcArray + ySize;

    uint8_t *y_transit = transitArray;

    uint8_t *u_transit = transitArray + ySize;

    uint8_t *v_transit = transitArray + ySize + uvSize;

    uint8_t *y_dst = dstArray;

    uint8_t *uv_dst = dstArray + (cw * ch);

    libyuv::NV21ToI420(y_src, w, uv_src, w, y_transit, w, u_transit, w >> 1, v_transit, w >> 1, w,

    h);

    libyuv::ConvertToI420(transitArray, ySize + uvSize, yArray, cw, uArray, cw >> 1,

    vArray, cw >> 1,

    startx, starty, w, h, cw, ch, libyuv::kRotate0, libyuv::FOURCC_I420);

    libyuv::I420ToNV12(yArray, cw, uArray, cw >> 1, vArray, cw >> 1, y_dst, cw,

    uv_dst, cw, cw, ch);

    releaseByteArray(env, transitJbyteArray, transitArray, 0);

    releaseByteArray(env, src, srcArray, 0);

    releaseByteArray(env, dst, dstArray, 0);

    releaseByteArray(env, y, yArray, 0);

    releaseByteArray(env, v, vArray, 0);

    releaseByteArray(env, u, uArray, 0);

    } ;

    #ifdef __cplusplus

    }

    #endif

    #endif

    以上就是jni层全部的代码基本上只涉及到数据转换和libyuv库的调用没啥太不好理解的地方。里面有注释旋转的代码有兴趣或者需求的童鞋可以恢复过来玩一玩。

    这是yuv jni的目录。

    相关文章

      网友评论

          本文标题:关于libyuv格式转换、图像裁剪说明

          本文链接:https://www.haomeiwen.com/subject/cvjwyhtx.html