//
// Created by 阳坤 on 2021/4/8.
//
#include <libyuv/rotate.h>
#include <cstdio>
#include "yuv_convert.h"
void ScaleI420AndRotate(jbyte_ *src_i420_data, jint_ width, jint_ height,
                        jbyte_ *dst_i420_data, int scale_width, int scale_height, int rotate) {

    if (rotate == 0) {
        scaleI420(reinterpret_cast<jbyte_ *>(src_i420_data), width,height , dst_i420_data, scale_width,
                  scale_height, 0);

    } else {
        jbyte_ *src_i420 = (jbyte_ *) malloc(sizeof(jbyte_) * width * height * 3 / 2);
        rotateI420(src_i420_data, width, height, reinterpret_cast<jbyte_ *>(src_i420), rotate);
        scaleI420(reinterpret_cast<jbyte_ *>(src_i420), height, width, dst_i420_data, scale_width,
                  scale_height, 0);
        free(src_i420);
    }
}

void
scaleI420(jbyte_ *src_i420_data, jint_ width, jint_ height, jbyte_ *dst_i420_data, jint_ dst_width,
          jint_ dst_height, jint_ mode) {

    jint_ src_i420_y_size = width * height;
    jint_ src_i420_u_size = (width >> 1) * (height >> 1);
    jbyte_ *src_i420_y_data = src_i420_data;
    jbyte_ *src_i420_u_data = src_i420_data + src_i420_y_size;
    jbyte_ *src_i420_v_data = src_i420_data + src_i420_y_size + src_i420_u_size;

    jint_ dst_i420_y_size = dst_width * dst_height;
    jint_ dst_i420_u_size = (dst_width >> 1) * (dst_height >> 1);
    jbyte_ *dst_i420_y_data = dst_i420_data;
    jbyte_ *dst_i420_u_data = dst_i420_data + dst_i420_y_size;
    jbyte_ *dst_i420_v_data = dst_i420_data + dst_i420_y_size + dst_i420_u_size;

    libyuv::I420Scale((const uint8_t *) src_i420_y_data, width,
                      (const uint8_t *) src_i420_u_data, width >> 1,
                      (const uint8_t *) src_i420_v_data, width >> 1,
                      width, height,
                      (uint8_t *) dst_i420_y_data, dst_width,
                      (uint8_t *) dst_i420_u_data, dst_width >> 1,
                      (uint8_t *) dst_i420_v_data, dst_width >> 1,
                      dst_width, dst_height,
                      (libyuv::FilterMode) mode);
}

void
rotateI420(jbyte_ *src_i420_data, jint_ width, jint_ height, jbyte_ *dst_i420_data, jint_ degree) {
    jint_ src_i420_y_size = width * height;
    jint_ src_i420_u_size = (width >> 1) * (height >> 1);

    jbyte_ *src_i420_y_data = src_i420_data;
    jbyte_ *src_i420_u_data = src_i420_data + src_i420_y_size;
    jbyte_ *src_i420_v_data = src_i420_data + src_i420_y_size + src_i420_u_size;

    jbyte_ *dst_i420_y_data = dst_i420_data;
    jbyte_ *dst_i420_u_data = dst_i420_data + src_i420_y_size;
    jbyte_ *dst_i420_v_data = dst_i420_data + src_i420_y_size + src_i420_u_size;

    //要注意这里的width和height在旋转之后是相反的
    if (degree == libyuv::kRotate90 || degree == libyuv::kRotate270) {
        libyuv::I420Rotate((const uint8_t *) src_i420_y_data, width,
                           (const uint8_t *) src_i420_u_data, width >> 1,
                           (const uint8_t *) src_i420_v_data, width >> 1,
                           (uint8_t *) dst_i420_y_data, height,
                           (uint8_t *) dst_i420_u_data, height >> 1,
                           (uint8_t *) dst_i420_v_data, height >> 1,
                           width, height,
                           (libyuv::RotationMode) degree);
    } else {
        libyuv::I420Rotate((const uint8_t *) src_i420_y_data, width,
                           (const uint8_t *) src_i420_u_data, width >> 1,
                           (const uint8_t *) src_i420_v_data, width >> 1,
                           (uint8_t *) dst_i420_y_data, width,
                           (uint8_t *) dst_i420_u_data, width >> 1,
                           (uint8_t *) dst_i420_v_data, width >> 1,
                           width, height,
                           (libyuv::RotationMode) degree);
    }
}

void RotateI420fff(jbyte_ *src_i420_data, jint_ width, jint_ height,
                   jbyte_ *dst_i420_data, jint_ degree) {
    jint_ I420_Y_Size = width * height;
    jint_ I420_U_Size = (width >> 1) * (height >> 1);
    jint_ I420_V_Size = I420_U_Size;

    // src: buffer address of  Y channel、U channel and V channel
    jbyte_ *Y_data_Src = src_i420_data;
    jbyte_ *U_data_Src = src_i420_data + I420_Y_Size;
    jbyte_ *V_data_Src = src_i420_data + I420_Y_Size + I420_U_Size;
    jint_ src_stride_y = width;
    jint_ src_stride_u = width >> 1;
    jint_ src_stride_v = src_stride_u;

    //dst: buffer address of Y channel、U channel and V channel
    jbyte_ *Y_data_Dst = dst_i420_data;
    jbyte_ *U_data_Dst = dst_i420_data + I420_Y_Size;
    jbyte_ *V_data_Dst = dst_i420_data + I420_Y_Size + I420_U_Size;
    jint_ Dst_Stride_Y;
    jint_ Dst_Stride_U;
    jint_ Dst_Stride_V;
    if (degree == libyuv::kRotate90 || degree == libyuv::kRotate270) {
        Dst_Stride_Y = height;
        Dst_Stride_U = height >> 1;
        Dst_Stride_V = Dst_Stride_U;
    } else {
        Dst_Stride_Y = width;
        Dst_Stride_U = width >> 1;
        Dst_Stride_V = Dst_Stride_U;
    }

    libyuv::I420Rotate((const uint8_t *) Y_data_Src, src_stride_y,
                       (const uint8_t *) U_data_Src, src_stride_u,
                       (const uint8_t *) V_data_Src, src_stride_v,
                       (uint8_t *) Y_data_Dst, Dst_Stride_Y,
                       (uint8_t *) U_data_Dst, Dst_Stride_U,
                       (uint8_t *) V_data_Dst, Dst_Stride_V,
                       width, height,
                       (libyuv::RotationMode) degree);
}

void MirrorI420(jbyte_ *src_i420_data, jint_ width, jint_ height, jbyte_ *dst_i420_data) {
    jint_ src_i420_y_size = width * height;
    // jint_ src_i420_u_size = (width >> 1) * (height >> 1);
    jint_ src_i420_u_size = src_i420_y_size >> 2;

    jbyte_ *src_i420_y_data = src_i420_data;
    jbyte_ *src_i420_u_data = src_i420_data + src_i420_y_size;
    jbyte_ *src_i420_v_data = src_i420_data + src_i420_y_size + src_i420_u_size;

    jbyte_ *dst_i420_y_data = dst_i420_data;
    jbyte_ *dst_i420_u_data = dst_i420_data + src_i420_y_size;
    jbyte_ *dst_i420_v_data = dst_i420_data + src_i420_y_size + src_i420_u_size;

    libyuv::I420Mirror((const uint8_t *) src_i420_y_data, width,
                       (const uint8_t *) src_i420_u_data, width >> 1,
                       (const uint8_t *) src_i420_v_data, width >> 1,
                       (uint8_t *) dst_i420_y_data, width,
                       (uint8_t *) dst_i420_u_data, width >> 1,
                       (uint8_t *) dst_i420_v_data, width >> 1,
                       width, height);
}

void CropI420(jbyte_ *src_i420_data, jint_ src_length, jint_ width, jint_ height,
              jbyte_ *dst_i420_data, jint_ dst_width, jint_ dst_height, jint_ left, jint_ top) {
    jint_ dst_i420_y_size = dst_width * dst_height;
    jint_ dst_i420_u_size = (dst_width >> 1) * (dst_height >> 1);

    jbyte_ *dst_i420_y_data = dst_i420_data;
    jbyte_ *dst_i420_u_data = dst_i420_data + dst_i420_y_size;
    jbyte_ *dst_i420_v_data = dst_i420_data + dst_i420_y_size + dst_i420_u_size;

    libyuv::ConvertToI420((const uint8_t *) src_i420_data, src_length,
                          (uint8_t *) dst_i420_y_data, dst_width,
                          (uint8_t *) dst_i420_u_data, dst_width >> 1,
                          (uint8_t *) dst_i420_v_data, dst_width >> 1,
                          left, top,
                          width, height,
                          dst_width, dst_height,
                          libyuv::kRotate0, libyuv::FOURCC_I420);
}

//void NV21ToI420(jbyte_ *src_nv21_data, jint_ width, jint_ height, jbyte_ *src_i420_data) {
//    jint_ src_y_size = width * height;
//    jint_ src_u_size = (width >> 1) * (height >> 1);
//
//    jbyte_ *src_nv21_y_data = src_nv21_data;
//    jbyte_ *src_nv21_vu_data = src_nv21_data + src_y_size;
//
//    jbyte_ *src_i420_y_data = src_i420_data;
//    jbyte_ *src_i420_u_data = src_i420_data + src_y_size;
//    jbyte_ *src_i420_v_data = src_i420_data + src_y_size + src_u_size;
//
//
//    libyuv::NV21ToI420((const uint8_t *) src_nv21_y_data, width,
//                       (const uint8_t *) src_nv21_vu_data, width,
//                       (uint8_t *) src_i420_y_data, width,
//                       (uint8_t *) src_i420_u_data, width >> 1,
//                       (uint8_t *) src_i420_v_data, width >> 1,
//                       width, height);
//}

//void NV12ToI420(jbyte_ *Src_data, jint_ src_width, jint_ src_height, jbyte_ *Dst_data) {
//    // NV12 video size
//    jint_ NV12_Size = src_width * src_height * 3 / 2;
//    jint_ NV12_Y_Size = src_width * src_height;
//
//    // YUV420 video size
//    jint_ I420_Size = src_width * src_height * 3 / 2;
//    jint_ I420_Y_Size = src_width * src_height;
//    jint_ I420_U_Size = (src_width >> 1) * (src_height >> 1);
//    jint_ I420_V_Size = I420_U_Size;
//
//    // src: buffer address of Y channel and UV channel
//    jbyte_ *Y_data_Src = Src_data;
//    jbyte_ *UV_data_Src = Src_data + NV12_Y_Size;
//    jint_ src_stride_y = src_width;
//    jint_ src_stride_uv = src_width;
//
//    //dst: buffer address of Y channel、U channel and V channel
//    jbyte_ *Y_data_Dst = Dst_data;
//    jbyte_ *U_data_Dst = Dst_data + I420_Y_Size;
//    jbyte_ *V_data_Dst = Dst_data + I420_Y_Size + I420_U_Size;
//    jint_ Dst_Stride_Y = src_width;
//    jint_ Dst_Stride_U = src_width >> 1;
//    jint_ Dst_Stride_V = Dst_Stride_U;
//
//    libyuv::NV12ToI420((const uint8_t *) Y_data_Src, src_stride_y,
//                       (const uint8_t *) UV_data_Src, src_stride_uv,
//                       (uint8_t *) Y_data_Dst, Dst_Stride_Y,
//                       (uint8_t *) U_data_Dst, Dst_Stride_U,
//                       (uint8_t *) V_data_Dst, Dst_Stride_V,
//                       src_width, src_height);
//}

void I420ToNv12(jbyte_ *src_i420_data, jint_ width, jint_ height, jbyte_ *src_nv12_data) {
    jint_ src_y_size = width * height;
    jint_ src_u_size = (width >> 1) * (height >> 1);

    jbyte_ *src_nv12_y_data = src_nv12_data;
    jbyte_ *src_nv12_uv_data = src_nv12_data + src_y_size;

    jbyte_ *src_i420_y_data = src_i420_data;
    jbyte_ *src_i420_u_data = src_i420_data + src_y_size;
    jbyte_ *src_i420_v_data = src_i420_data + src_y_size + src_u_size;


    libyuv::I420ToNV12(
            (const uint8_t *) src_i420_y_data, width,
            (const uint8_t *) src_i420_u_data, width >> 1,
            (const uint8_t *) src_i420_v_data, width >> 1,
            (uint8_t *) src_nv12_y_data, width,
            (uint8_t *) src_nv12_uv_data, width,
            width, height);
}

void I420ToRGB24(jbyte_ *src_i420_data, jint_ width, jint_ height, jbyte_ *dst_rgb24_data) {

    jbyte_ *yplane = src_i420_data;
    jbyte_ *uplane = src_i420_data + width * height;
    jbyte_ *vplane = uplane + (width * height / 4);

    libyuv::I420ToRGB24(
            (const uint8_t *) yplane, width,
            (const uint8_t *) uplane, width / 2,
            (const uint8_t *) vplane, width / 2,
            (uint8_t *) dst_rgb24_data, width * 3,
            width, height);
}

void I420ToARGB(jbyte_ *src_i420_data, jint_ width, jint_ height,
                jint_ dst_stride, jbyte_ *dst_argb_data) {

    if (dst_stride == 0 || dst_stride == width)
        dst_stride = width * 4;
    jbyte_ *yplane = src_i420_data;
    jbyte_ *uplane = src_i420_data + width * height;
    jbyte_ *vplane = uplane + (width * height / 4);

    libyuv::I420ToARGB(
            (const uint8_t *) yplane, width,
            (const uint8_t *) uplane, width / 2,
            (const uint8_t *) vplane, width / 2,
            (uint8_t *) dst_argb_data, dst_stride,
            width, height);
}

void I420ToRGBAMac(jbyte_ *src_i420_data, jint_ width, jint_ height, jint_ dst_stride,
                   jbyte_ *dst_rgba_mac_data) {
    // Equivalent to Convert YV12ToBGRA.
    // YV12 same as I420 with U and V swapped.
    if (dst_stride == 0 || dst_stride == width) dst_stride = 4 * width;
    jbyte_ *yplane = src_i420_data;
    jbyte_ *uplane = src_i420_data + width * height;
    jbyte_ *vplane = uplane + (width * height / 4);
    libyuv::I420ToBGRA(
            (const uint8_t *) yplane, width,
            (const uint8_t *) vplane, width / 2,
            (const uint8_t *) uplane, width / 2,
            (uint8_t *) dst_rgba_mac_data, dst_stride,
            width, height);
}

void I420ToARGB4444(jbyte_ *src_i420_data, jint_ width, jint_ height, jint_ dst_stride,
                    jbyte_ *dst_argb4444_data) {
    if (dst_stride == 0 || dst_stride == width)
        dst_stride = 2 * width;
    jbyte_ *yplane = src_i420_data;
    jbyte_ *uplane = src_i420_data + width * height;
    jbyte_ *vplane = uplane + (width * height / 4);
    libyuv::I420ToARGB4444(
            (const uint8_t *) yplane, width,
            (const uint8_t *) uplane, width / 2,
            (const uint8_t *) vplane, width / 2,
            (uint8_t *) dst_argb4444_data, dst_stride,
            width, height);
}

void I420ToRGB565(jbyte_ *src_i420_data, jint_ width, jint_ height, jbyte_ *dst_rgb565_data) {
    jbyte_ *yplane = src_i420_data;
    jbyte_ *uplane = src_i420_data + width * height;
    jbyte_ *vplane = uplane + (width * height / 4);
    libyuv::I420ToRGB565(
            (const uint8_t *) yplane, width,
            (const uint8_t *) uplane, width / 2,
            (const uint8_t *) vplane, width / 2,
            (uint8_t *) dst_rgb565_data, width,
            width, height);
}

void
I420ToRGB565Android(jbyte_ *src_i420_data, jint_ width, jint_ height, jbyte_ *dst_rgb565_data) {
    jbyte_ *yplane = src_i420_data;
    jbyte_ *uplane = src_i420_data + width * height;
    jbyte_ *vplane = uplane + (width * height / 4);
    // Same as RGB565 + inversion - set negative height.
    height = -height;
    libyuv::I420ToRGB565(
            (const uint8_t *) yplane, width,
            (const uint8_t *) uplane, width / 2,
            (const uint8_t *) vplane, width / 2,
            (uint8_t *) dst_rgb565_data, width,
            width, height);
}

void I420ToARGB1555(jbyte_ *src_i420_data, jint_ width, jint_ height, jint_ dst_stride,
                    jbyte_ *dst_argb1555_data) {
    if (dst_stride == 0 || dst_stride == width)
        dst_stride = 2 * width;
    else if (dst_stride < 2 * width)
        return;
    jbyte_ *yplane = src_i420_data;
    jbyte_ *uplane = src_i420_data + width * height;
    jbyte_ *vplane = uplane + (width * height / 4);
    libyuv::I420ToARGB1555(
            (const uint8_t *) yplane, width,
            (const uint8_t *) uplane, width / 2,
            (const uint8_t *) vplane, width / 2,
            (uint8_t *) dst_argb1555_data, dst_stride,
            width, height);
}

void I420ToYUY2(jbyte_ *src_i420_data, jint_ width, jint_ height,
                jint_ dst_stride, jbyte_ *dst_yuy2_data) {
    jbyte_ *yplane = src_i420_data;
    jbyte_ *uplane = src_i420_data + width * height;
    jbyte_ *vplane = uplane + (width * height / 4);
    if (dst_stride == 0 || dst_stride == width)
        dst_stride = 2 * width;
    libyuv::I420ToYUY2(
            (const uint8_t *) yplane, width,
            (const uint8_t *) uplane, width / 2,
            (const uint8_t *) vplane, width / 2,
            (uint8_t *) dst_yuy2_data, dst_stride,
            width, height);
}

void I420ToUYVY(jbyte_ *src_i420_data, jint_ width, jint_ height,
                jint_ dst_stride, jbyte_ *dst_uyvy_data) {
    if (dst_stride == 0 || dst_stride == width)
        dst_stride = 2 * width;
    else if (dst_stride < width)
        return;
    jbyte_ *yplane = src_i420_data;
    jbyte_ *uplane = src_i420_data + width * height;
    jbyte_ *vplane = uplane + (width * height / 4);
    libyuv::I420ToUYVY(
            (const uint8_t *) yplane, width,
            (const uint8_t *) uplane, width / 2,
            (const uint8_t *) vplane, width / 2,
            (uint8_t *) dst_uyvy_data, dst_stride,
            width, height);
}

void I420ToYV12(jbyte_ *src_i420_data, jint_ width, jint_ height,
                jint_ dst_stride, jbyte_ *dst_yv12_data) {
    if (dst_stride == 0 || dst_stride == width)
        dst_stride = width;
    else if (dst_stride < width)
        return;
    jbyte_ *src_yplane = src_i420_data;
    jbyte_ *src_uplane = src_i420_data + width * height;
    jbyte_ *src_vplane = src_uplane + (width * height / 4);
    jbyte_ *dst_yplane = dst_yv12_data;
    jbyte_ *dst_uplane = dst_yv12_data + width * height;

    jbyte_ *dst_vplane = dst_uplane + (width * height / 4);
    // YV12 is YVU => Use I420(YUV) copy and flip U and V.
    libyuv::I420Copy((const uint8_t *) src_yplane, width,
                     (const uint8_t *) src_vplane, width / 2,
                     (const uint8_t *) src_uplane, width / 2,
                     (uint8_t *) dst_yplane, dst_stride,
                     (uint8_t *) dst_uplane, dst_stride / 2,
                     (uint8_t *) dst_vplane, dst_stride / 2,
                     width, height);
}

void YV12ToI420(jbyte_ *src_yv12_data, jint_ width, jint_ height, jbyte_ *dst_i420_data) {
    jbyte_ *src_yplane = src_yv12_data;
    jbyte_ *src_uplane = src_yv12_data + width * height;
    jbyte_ *src_vplane = src_uplane + (width * height / 4);
    jbyte_ *dst_yplane = dst_i420_data;
    jbyte_ *dst_uplane = dst_i420_data + width * height;
    jbyte_ *dst_vplane = dst_uplane + (width * height / 4);
    // YV12 is YVU => Use I420(YUV) copy and flip U and V.
    libyuv::I420Copy(
            (const uint8_t *) src_yplane, width,
            (const uint8_t *) src_vplane, width / 2,
            (const uint8_t *) src_uplane, width / 2,
            (uint8_t *) dst_yplane, width,
            (uint8_t *) dst_uplane, width / 2,
            (uint8_t *) dst_vplane, width / 2,
            width, height);
}

void NV12ToI420(jbyte_ *src_nv21_data, jint_ width, jint_ height, jbyte_ *dst_i420_data) {
    jbyte_ *src_yplane = src_nv21_data;
    jbyte_ *src_uvplane = src_nv21_data + width * height;
    jbyte_ *dst_yplane = dst_i420_data;
    jbyte_ *dst_uplane = dst_i420_data + width * height;
    jbyte_ *dst_vplane = dst_uplane + (width * height / 4);
    libyuv::NV12ToI420(
            (const uint8_t *) src_yplane, width,
            (const uint8_t *) src_uvplane, width,
            (uint8_t *) dst_yplane, width,
            (uint8_t *) dst_uplane, width / 2,
            (uint8_t *) dst_vplane, width / 2,
            width, height);
}

void I420ToNv21(jbyte_ *src_i420_data, jint_ width, jint_ height, jbyte_ *src_nv21_data) {
    jint_ src_y_size = width * height;
    jint_ src_u_size = (width >> 1) * (height >> 1);

    jbyte_ *src_nv21_y_data = src_nv21_data;
    jbyte_ *src_nv21_uv_data = src_nv21_data + src_y_size;

    jbyte_ *src_i420_y_data = src_i420_data;
    jbyte_ *src_i420_u_data = src_i420_data + src_y_size;
    jbyte_ *src_i420_v_data = src_i420_data + src_y_size + src_u_size;


    libyuv::I420ToNV21(
            (const uint8_t *) src_i420_y_data, width,
            (const uint8_t *) src_i420_u_data, width >> 1,
            (const uint8_t *) src_i420_v_data, width >> 1,
            (uint8_t *) src_nv21_y_data, width,
            (uint8_t *) src_nv21_uv_data, width,
            width, height);
}

void
NV12ToI420AndRotate180(jbyte_ *src_nv12_data, jint_ width, jint_ height, jbyte_ *dst_i420_data) {
    jbyte_ *src_yplane = src_nv12_data;
    jbyte_ *src_uvplane = src_nv12_data + width * height;
    jbyte_ *dst_yplane = dst_i420_data;
    jbyte_ *dst_uplane = dst_i420_data + width * height;
    jbyte_ *dst_vplane = dst_uplane + (width * height / 4);
    libyuv::NV12ToI420Rotate(
            (const uint8_t *) src_yplane, width,
            (const uint8_t *) src_uvplane, width,
            (uint8_t *) dst_yplane, width,
            (uint8_t *) dst_uplane, width / 2,
            (uint8_t *) dst_vplane, width / 2,
            width, height,
            libyuv::kRotate180);

}


void NV12ToScaleI420AndRotate(jbyte_ *src_nv12_data, jint_ width, jint_ height,
                              jbyte_ *dst_i420_data, int scale_width, int scale_height, int degree) {


    jbyte_ *src_i420 = (jbyte_ *) malloc(sizeof(jbyte_) * width * height * 3 / 2);
    jbyte_ *src_yplane = src_nv12_data;
    jbyte_ *src_uvplane = src_nv12_data + width * height;

    jbyte_ *dst_yplane = src_i420;
    jbyte_ *dst_uplane = src_i420 + width * height;
    jbyte_ *dst_vplane = dst_uplane + (width * height / 4);

    //这里的width和height在旋转之后是相反的
    if (degree == libyuv::kRotate90 || degree == libyuv::kRotate270) {
        int opt = 1;
        if (opt) {
            libyuv::NV12ToI420Rotate(
                    (const uint8_t *) src_yplane, width,
                    (const uint8_t *) src_uvplane, width,
                    (uint8_t *) dst_yplane, height,
                    (uint8_t *) dst_uplane, height >> 1,
                    (uint8_t *) dst_vplane, height >> 1,
                    width, height,
                    (libyuv::RotationMode) degree);
            scaleI420(src_i420, height, width, dst_i420_data, scale_width, scale_height, 0);
        } else {
            libyuv::NV12ToI420Rotate(
                    (const uint8_t *) src_yplane, width,
                    (const uint8_t *) src_uvplane, width,
                    (uint8_t *) dst_yplane, width,
                    (uint8_t *) dst_uplane, width >> 1,
                    (uint8_t *) dst_vplane, width >> 1,
                    width, height,
                    (libyuv::RotationMode) 0);
            uint8_t *tempRd = static_cast<uint8_t *>(malloc(sizeof(uint8_t) * width * height * 3 >> 1));
            rotateI420(src_i420, width, height, tempRd, degree);
            scaleI420(tempRd, height, width, dst_i420_data, scale_width, scale_height, 0);
            free(tempRd);
        }
    } else {
        libyuv::NV12ToI420Rotate(//传 0 的话内部不会旋转
                (const uint8_t *) src_yplane, width,
                (const uint8_t *) src_uvplane, width,
                (uint8_t *) dst_yplane, width,
                (uint8_t *) dst_uplane, width >> 1,
                (uint8_t *) dst_vplane, width >> 1,
                width, height,
                (libyuv::RotationMode) degree);
        scaleI420(src_i420, width, height, dst_i420_data, scale_width, scale_height, 0);
    }
    free((void *) src_i420);
}

void NV12ToI420AndRotateClockwise(jbyte_ *src_nv12_data, jint_
width,
                                  jint_ height,
                                  jbyte_
                                  *dst_i420_data) {
    jbyte_ *src_yplane = src_nv12_data;
    jbyte_ *src_uvplane = src_nv12_data + width * height;
    jbyte_ *dst_yplane = dst_i420_data;
    jbyte_ *dst_uplane = dst_i420_data + width * height;
    jbyte_ *dst_vplane = dst_uplane + (width * height / 4);
    libyuv::NV12ToI420Rotate(
            (const uint8_t *) src_yplane, width,
            (const uint8_t *) src_uvplane, width,
            (uint8_t *) dst_yplane, width,
            (uint8_t *) dst_uplane, width / 2,
            (uint8_t *) dst_vplane, width / 2,
            width, height,
            libyuv::kRotate90);
}

void NV12ToI420AndRotateAntiClockwise(jbyte_ *src_nv12_data, jint_
width,
                                      jint_ height,
                                      jbyte_
                                      *dst_i420_data) {
    jbyte_ *src_yplane = src_nv12_data;
    jbyte_ *src_uvplane = src_nv12_data + width * height;
    jbyte_ *dst_yplane = dst_i420_data;
    jbyte_ *dst_uplane = dst_i420_data + width * height;
    jbyte_ *dst_vplane = dst_uplane + (width * height / 4);
    libyuv::NV12ToI420Rotate(
            (const uint8_t *) src_yplane, width,
            (const uint8_t *) src_uvplane, width,
            (uint8_t *) dst_yplane, width,
            (uint8_t *) dst_uplane, width / 2,
            (uint8_t *) dst_vplane, width / 2,
            width, height,
            libyuv::kRotate270);
}

void NV12ToRGB565(jbyte_ *src_nv12_data, jint_
width,
                  jint_ height, jbyte_
                  *dst_rgb565_data) {
    jbyte_ *yplane = src_nv12_data;
    jbyte_ *uvInterlaced = src_nv12_data + (width * height);
    libyuv::NV12ToRGB565(
            (const uint8_t *) yplane, width,
            (const uint8_t *) uvInterlaced, width / 2,
            (uint8_t *) dst_rgb565_data, width,
            width, height);
}

void NV21ToI420(jbyte_ *src_nv21_data, jint_
width,
                jint_ height, jbyte_
                *dst_i420_data) {
// NV21 = y plane followed by an interleaved V/U plane, i.e. same as NV12
// but the U and the V are switched. Use the NV12 function and switch the U
// and V planes.
    jbyte_ *src_yplane = src_nv21_data;
    jbyte_ *src_uvplane = src_nv21_data + width * height;
    jbyte_ *dst_yplane = dst_i420_data;
    jbyte_ *dst_uplane = dst_i420_data + width * height;
    jbyte_ *dst_vplane = dst_uplane + (width * height / 4);
    libyuv::NV12ToI420(
            (const uint8_t *) src_yplane, width,
            (const uint8_t *) src_uvplane, width,
            (uint8_t *) dst_yplane, width,
            (uint8_t *) dst_vplane, width / 2,
            (uint8_t *) dst_uplane, width / 2,
            width, height);
}

void
NV21ToI420AndRotate180(jbyte_ *src_nv21_data, jint_
width,
                       jint_ height, jbyte_
                       *dst_i420_data) {
    jbyte_ *src_yplane = src_nv21_data;
    jbyte_ *src_uvplane = src_nv21_data + width * height;
    jbyte_ *dst_yplane = dst_i420_data;
    jbyte_ *dst_uplane = dst_i420_data + width * height;
    jbyte_ *dst_vplane = dst_uplane + (width * height / 4);
    libyuv::NV12ToI420Rotate(
            (const uint8_t *) src_yplane, width,
            (const uint8_t *) src_uvplane, width,
            (uint8_t *) dst_yplane, width,
            (uint8_t *) dst_vplane, width / 2,
            (uint8_t *) dst_uplane, width / 2,
            width, height,
            libyuv::kRotate180);
}

void NV21ToI420AndRotateClockwise(jbyte_ *src_nv21_data, jint_
width,
                                  jint_ height, jbyte_
                                  *dst_i420_data) {
    jbyte_ *src_yplane = src_nv21_data;
    jbyte_ *src_uvplane = src_nv21_data + width * height;
    jbyte_ *dst_yplane = dst_i420_data;
    jbyte_ *dst_uplane = dst_i420_data + width * height;
    jbyte_ *dst_vplane = dst_uplane + (width * height / 4);
    libyuv::NV12ToI420Rotate(
            (const uint8_t *) src_yplane, width,
            (const uint8_t *) src_uvplane, width,
            (uint8_t *) dst_yplane, width,
            (uint8_t *) dst_vplane, width / 2,
            (uint8_t *) dst_uplane, width / 2,
            width, height,
            libyuv::kRotate90);
}

void NV21ToI420AndRotateAntiClockwise(jbyte_ *src_nv21_data, jint_
width,
                                      jint_ height, jbyte_
                                      *dst_i420_data) {
    jbyte_ *src_yplane = src_nv21_data;
    jbyte_ *src_uvplane = src_nv21_data + width * height;
    jbyte_ *dst_yplane = dst_i420_data;
    jbyte_ *dst_uplane = dst_i420_data + width * height;
    jbyte_ *dst_vplane = dst_uplane + (width * height / 4);
    libyuv::NV12ToI420Rotate(
            (const uint8_t *) src_yplane, width,
            (const uint8_t *) src_uvplane, width,
            (uint8_t *) dst_yplane, width,
            (uint8_t *) dst_vplane, width / 2,
            (uint8_t *) dst_uplane, width / 2,
            width, height,
            libyuv::kRotate270);
}

void I420ToRGBAIPhone(jbyte_ *src_i420_data, jint_
width,
                      jint_ height,
                      jint_
                      dst_stride,
                      jbyte_ *dst_rgba_data
) {
    if (dst_stride == 0 || dst_stride == width)
        dst_stride = 4 * width;
    else if (dst_stride < 4 * width)
        return;
    jbyte_ *yplane = src_i420_data;
    jbyte_ *uplane = src_i420_data + width * height;
    jbyte_ *vplane = uplane + (width * height / 4);
// RGBAIPhone = ABGR
    libyuv::I420ToABGR(
            (const uint8_t *) yplane, width,
            (const uint8_t *) uplane, width / 2,
            (const uint8_t *) vplane, width / 2,
            (uint8_t *) dst_rgba_data, dst_stride,
            width, height);
}

void I420Copy(jbyte_ *src_i420_data, jint_
width,
              jint_ height,
              jint_
              dst_stride,
              jbyte_ *dst_i420_data
) {

    if (dst_stride == 0)
        dst_stride = width;
    jbyte_ *src_yplane = src_i420_data;
    jbyte_ *src_uplane = src_i420_data + width * height;
    jbyte_ *src_vplane = src_uplane + (width * height / 4);
    jbyte_ *dst_yplane = dst_i420_data;
    jbyte_ *dst_uplane = dst_i420_data + width * height;
    jbyte_ *dst_vplane = dst_uplane + (width * height / 4);
    libyuv::I420Copy(
            (const uint8_t *) src_yplane, width,
            (const uint8_t *) src_uplane, width / 2,
            (const uint8_t *) src_vplane, width / 2,
            (uint8_t *) dst_yplane, dst_stride,
            (uint8_t *) dst_uplane, dst_stride / 2,
            (uint8_t *) dst_vplane, dst_stride / 2,
            width, height);
}

void UYVYToI420(jbyte_ *src_uyvy_data, jint_
width,
                jint_ height, jbyte_
                *dst_i420_data) {
    jbyte_ *dst_yplane = dst_i420_data;
    jbyte_ *dst_uplane = dst_i420_data + width * height;
    jbyte_ *dst_vplane = dst_uplane + (width * height / 4);
    libyuv::UYVYToI420(
            (const uint8_t *) src_uyvy_data, 2 * width,
            (uint8_t *) dst_yplane, width,
            (uint8_t *) dst_uplane, width / 2,
            (uint8_t *) dst_vplane, width / 2,
            width, height);
}

void YUY2ToI420(jbyte_ *src_yuy2_data, jint_
width,
                jint_ height, jbyte_
                *dst_i420_data) {
    jbyte_ *dst_yplane = dst_i420_data;
    jbyte_ *dst_uplane = dst_i420_data + width * height;
    jbyte_ *dst_vplane = dst_uplane + (width * height / 4);
    libyuv::YUY2ToI420(
            (const uint8_t *) src_yuy2_data, 2 * width,
            (uint8_t *) dst_yplane, width,
            (uint8_t *) dst_uplane, width / 2,
            (uint8_t *) dst_vplane, width / 2,
            width, height);
}

void RGB24ToARGB(jbyte_ *src_rbg24_data, jint_
width,
                 jint_ height,
                 jint_
                 dst_stride,
                 jbyte_ *dst_argb_data
) {
    if (dst_stride == 0 || dst_stride == width)
        dst_stride = width;
// Stride - currently webrtc style
    libyuv::RGB24ToARGB(
            (const uint8_t *) src_rbg24_data, width,
            (uint8_t *) dst_argb_data, dst_stride,
            width, height);
}

void RGBAToI420(jbyte_ *src_rbga_data, jint_
width,
                jint_ height, jbyte_
                *dst_i420_data) {
    jbyte_ *yplane = dst_i420_data;
    jbyte_ *uplane = yplane + width * height;
    jbyte_ *vplane = uplane + (width * height / 4);
// WebRtc expects a vertical flipped image.
    libyuv::RGBAToI420(
            (const uint8_t *) src_rbga_data, width * 3,
            (uint8_t *) yplane, width,
            (uint8_t *) uplane, width / 2,
            (uint8_t *) vplane, width / 2,
            width, -height);
}

void RGB24ToI420(jbyte_ *src_rbg24_data, jint_
width,
                 jint_ height, jbyte_
                 *dst_i420_data) {
    jbyte_ *yplane = dst_i420_data;
    jbyte_ *uplane = yplane + width * height;
    jbyte_ *vplane = uplane + (width * height / 4);
// WebRtc expects a vertical flipped image.
    libyuv::RGB24ToI420(
            (const uint8_t *) src_rbg24_data, width * 3,
            (uint8_t *) yplane, width,
            (uint8_t *) uplane, width / 2,
            (uint8_t *) vplane, width / 2,
            width, -height);
}

void I420ToARGBMac(jbyte_ *src_i420_data, jint_
width,
                   jint_ height,
                   jint_
                   dst_stride,
                   jbyte_ *dst_argb_mac_data
) {
// Equivalent to YV12ToARGB.
// YV12 = YVU => use I420 and interchange U and V.
    jbyte_ *yplane = src_i420_data;
    jbyte_ *uplane = yplane + width * height;
    jbyte_ *vplane = uplane + (width * height / 4);
    if (dst_stride == 0 || dst_stride == width)
        dst_stride = 4 * width;
    else if (dst_stride < 4 * width)
        return;
    libyuv::I420ToARGB(
            (const uint8_t *) yplane, width,
            (const uint8_t *) vplane, width / 2,
            (const uint8_t *) uplane, width / 2,
            (uint8_t *) dst_argb_mac_data, dst_stride,
            width, height);
}

void ARGBMacToI420(jbyte_ *src_argb_mac_data, jint_
width,
                   jint_ height, jbyte_
                   *dst_i420_data) {
// Equivalent to BGRAToI420
    jbyte_ *yplane = dst_i420_data;
    jbyte_ *uplane = yplane + width * height;
    jbyte_ *vplane = uplane + (width * height / 4);
    libyuv::BGRAToI420(
            (const uint8_t *) src_argb_mac_data, width * 4,
            (uint8_t *) yplane, width,
            (uint8_t *) uplane, width / 2,
            (uint8_t *) vplane, width / 2,
            width, height);
}

void BGRAToI420(jbyte_ *src_argb_mac_data, jint_
width,
                jint_ height, jbyte_
                *dst_i420_data) {
// Equivalent to BGRAToI420
    jbyte_ *yplane = dst_i420_data;
    jbyte_ *uplane = yplane + width * height;
    jbyte_ *vplane = uplane + (width * height / 4);
    libyuv::BGRAToI420(
            (const uint8_t *) src_argb_mac_data, width * 4,
            (uint8_t *) yplane, width,
            (uint8_t *) uplane, width / 2,
            (uint8_t *) vplane, width / 2,
            width, height);
}

void MirrorI420LeftRight(jbyte_ *src_i420_data, jint_
width,
                         jint_ height, jbyte_
                         *dst_i420_data) {
    jbyte_ *src_yplane = src_i420_data;
    jbyte_ *src_uplane = src_yplane + width * height;
    jbyte_ *src_vplane = src_uplane + (width * height / 4);
    jbyte_ *dst_yplane = dst_i420_data;
    jbyte_ *dst_uplane = dst_yplane + width * height;
    jbyte_ *dst_vplane = dst_uplane + (width * height / 4);
    libyuv::I420Mirror(
            (const uint8_t *) src_yplane, width,
            (const uint8_t *) src_uplane, width / 2,
            (const uint8_t *) src_vplane, width / 2,
            (uint8_t *) dst_yplane, width,
            (uint8_t *) dst_uplane, width / 2,
            (uint8_t *) dst_vplane, width / 2,
            width, height);
}

void MirrorI420UpDown(jbyte_ *src_i420_data, jint_
width,
                      jint_ height, jbyte_
                      *dst_i420_data) {
    jbyte_ *src_yplane = src_i420_data;
    jbyte_ *src_uplane = src_i420_data + width * height;
    jbyte_ *src_vplane = src_uplane + (width * height / 4);
    jbyte_ *dst_yplane = dst_i420_data;
    jbyte_ *dst_uplane = dst_i420_data + width * height;
    jbyte_ *dst_vplane = dst_uplane + (width * height / 4);

// Inserting negative height flips the frame.
    libyuv::I420Copy(
            (const uint8_t *) src_yplane, width,
            (const uint8_t *) src_uplane, width / 2,
            (const uint8_t *) src_vplane, width / 2,
            (uint8_t *) dst_yplane, width,
            (uint8_t *) dst_uplane, width / 2,
            (uint8_t *) dst_vplane, width / 2,
            width, -height);
}

void NV12ToNV21(jbyte_ *input, jint_
width,
                jint_ height, jbyte_
                *output) {
    int frameSize = width * height;
    int qFrameSize = frameSize / 2;

    memmove(output, input, frameSize
    ); // Y
    int i = 0;
    for (
            i = 0;
            i + 1 <
            qFrameSize;
            i += 2) {
        output[frameSize + i] = input[frameSize + i + 1]; // U
        output[frameSize + i + 1] = input[frameSize + i]; // V
    }
}


