diff --git a/Live/src/main/java/com/frank/live/util/YUVUtil.java b/Live/src/main/java/com/frank/live/util/YUVUtil.java index ff109ac..4d94d1b 100644 --- a/Live/src/main/java/com/frank/live/util/YUVUtil.java +++ b/Live/src/main/java/com/frank/live/util/YUVUtil.java @@ -1,7 +1,5 @@ package com.frank.live.util; -import android.util.Log; - /** * Tool of transforming YUV format * Created by frank on 2018/7/1. @@ -9,40 +7,72 @@ import android.util.Log; public class YUVUtil { - public static byte[] ARGBtoYUV420SemiPlanar(int[] input, int width, int height) { - + public static void rgbaToYUV420p(int[] argb, byte[] yuv, int width, int height) { final int frameSize = width * height; - byte[] yuv420sp = new byte[width * height * 3 / 2]; + int index = 0; int yIndex = 0; - int uvIndex = frameSize; + int uIndex = frameSize; + int vIndex = frameSize * 5 / 4; + int R, G, B, Y, U, V; - int a, R, G, B, Y, U, V; - int index = 0; for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) { - - a = (input[index] & 0xff000000) >> 24; - R = (input[index] & 0xff0000) >> 16; - G = (input[index] & 0xff00) >> 8; - B = (input[index] & 0xff); + R = (argb[index] & 0xff0000) >> 16; + G = (argb[index] & 0xff00) >> 8; + B = (argb[index] & 0xff); // RGB to YUV algorithm Y = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16; - U = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128; - V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128; - - // NV21 has a plane of Y and interleaved planes of VU each sampled by a factor of 2 - // meaning for every 4 Y pixels there are 1 V and 1 U. - yuv420sp[yIndex++] = (byte) ((Y < 0) ? 0 : (Math.min(Y, 255))); - if (j % 2 == 0 && index % 2 == 0) { - yuv420sp[uvIndex++] = (byte) ((V < 0) ? 0 : (Math.min(V, 255))); - yuv420sp[uvIndex++] = (byte) ((U < 0) ? 0 : (Math.min(U, 255))); - } + // I420(YUV420p) -> YYYYYYYY UU VV + yuv[yIndex++] = (byte) Y; + if (j % 2 == 0 && i % 2 == 0) { + U = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128; + V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128; + yuv[uIndex++] = (byte) U; + yuv[vIndex++] = (byte) V; + } index++; } } - return yuv420sp; + } + + private static int yuv2argb(int y, int u, int v) { + int r, g, b; + + r = y + (int) (1.402f * u); + g = y - (int) (0.344f * v + 0.714f * u); + b = y + (int) (1.772f * v); + r = r > 255 ? 255 : Math.max(r, 0); + g = g > 255 ? 255 : Math.max(g, 0); + b = b > 255 ? 255 : Math.max(b, 0); + return 0xff000000 | (r << 16) | (g << 8) | b; + } + + private static void yuv420pToARGB(byte[] yuv, int[] argb, int width, int height) { + int size = width * height; + int offset = size; + int u, v, y1, y2, y3, y4; + + for (int i = 0, k = 0; i < size; i += 2, k += 2) { + y1 = yuv[i] & 0xff; + y2 = yuv[i + 1] & 0xff; + y3 = yuv[width + i] & 0xff; + y4 = yuv[width + i + 1] & 0xff; + + u = yuv[offset + k] & 0xff; + v = yuv[offset + k + 1] & 0xff; + u = u - 128; + v = v - 128; + + argb[i] = yuv2argb(y1, u, v); + argb[i + 1] = yuv2argb(y2, u, v); + argb[width + i] = yuv2argb(y3, u, v); + argb[width + i + 1] = yuv2argb(y4, u, v); + + if (i != 0 && (i + 2) % width == 0) + i += width; + } } public static void YUV420pRotate90(byte[] dst, byte[] src, int width, int height) { diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index c03c780..9e879c1 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -42,7 +42,7 @@ add_library( # Sets the name of the library. src/main/cpp/metadata/media_retriever_jni.cpp src/main/cpp/metadata/metadata_util.c src/main/cpp/metadata/ffmpeg_media_retriever.c - src/main/cpp/yuv2rgb/yuv_2_rgb.cpp + src/main/cpp/yuv/yuv_converter.cpp ) add_library( ffmpeg diff --git a/app/src/main/cpp/yuv/yuv_converter.cpp b/app/src/main/cpp/yuv/yuv_converter.cpp new file mode 100644 index 0000000..a10ae51 --- /dev/null +++ b/app/src/main/cpp/yuv/yuv_converter.cpp @@ -0,0 +1,115 @@ +// +// Created by xu fulong on 2022/7/9. +// + +#include "yuv_converter.h" +#include + +// https://chromium.googlesource.com/libyuv/libyuv +// https://mymusing.co/bt601-yuv-to-rgb-conversion-color/ +// https://www.color.org/chardata/rgb/rgb_registry.xalter + +// BT.601 YUV to RGB +// R = 1.164 * (Y - 16) + 1.596 * (V - 128) +// G = 1.164 * (Y - 16) - 0.392 * (U - 128) - 0.812 * (V - 128) +// B = 1.164 * (Y - 16) + 2.016 * (U - 128) + +// Y = 0.257 * R + 0.504 * G + 0.098 * B + 16 +// U = -0.148 * R - 0.291 * G + 0.439 * B + 128 +// V = 0.439 * R - 0.368 * G - 0.072 * B + 128 + +// BT.709 YUV to RGB +// R = 1.1644 * (Y - 16) + 1.7928 * (V - 128) +// G = 1.1644 * (Y - 16) - 0.2133 * (U - 128) - 0.533 * (V - 128) +// B = 1.1644 * (Y - 16) + 2.1124 * (U - 128) + +// Y = 0.1826 * R + 0.6142 * G + 0.0620 * B + 16 +// U = -0.1006 * R - 0.3386 * G + 0.4392 * B + 128 +// V = 0.4392 * B - 0.3989 * G - 0.0403 * B + 128 + +// BT.2020 YUV to RGB +// R = Y - 16 + 1.4746 * (V - 128) +// G = Y - 16 - 0.1645 * (U - 128) - 0.5713 * (V - 128) +// B = Y - 16 + 1.881 * (U - 128) + +// Y = 0.2627 * R + 0.6780 * G + 0.0593 * B + 16 +// U = -0.1396 * R - 0.3604 * G + 0.5 * B + 128 +// V = 0.5 * R - 0.4598 * G - 0.0402 * B + 128 + +static void rgba_to_yuv420p(int *argb, int8_t *yuv, int width, int height) { + int frameSize = width * height; + int index = 0; + int yIndex = 0; + int uIndex = frameSize; + int vIndex = frameSize * 5 / 4; + int R, G, B, Y, U, V; + + for (int j = 0; j < height; j++) { + for (int i = 0; i < width; i++) { + R = (argb[index] & 0xff0000) >> 16; + G = (argb[index] & 0xff00) >> 8; + B = (argb[index] & 0xff); + + // RGB to YUV algorithm + Y = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16; + + // I420(YUV420p) -> YYYYYYYY UU VV + yuv[yIndex++] = (int8_t) Y; + if (j % 2 == 0 && i % 2 == 0) { + U = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128; + V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128; + yuv[uIndex++] = (int8_t) U; + yuv[vIndex++] = (int8_t) V; + } + index++; + } + } +} + +static int yuv2argb(int y, int u, int v) { +#define max(a, b) ((a) > (b) ? (a) : (b)) + + int r, g, b; + + r = y + (int) (1.402f * u); + g = y - (int) (0.344f * v + 0.714f * u); + b = y + (int) (1.772f * v); + r = r > 255 ? 255 : max(r, 0); + g = g > 255 ? 255 : max(g, 0); + b = b > 255 ? 255 : max(b, 0); + return 0xff000000 | (r << 16) | (g << 8) | b; +} + +static void yuv420p_to_argb(int8_t *yuv, int *argb, int width, int height) { + int size = width * height; + int offset = size; + int u, v, y1, y2, y3, y4; + + for (int i = 0, k = 0; i < size; i += 2, k += 2) { + y1 = yuv[i] & 0xff; + y2 = yuv[i + 1] & 0xff; + y3 = yuv[width + i] & 0xff; + y4 = yuv[width + i + 1] & 0xff; + + u = yuv[offset + k] & 0xff; + v = yuv[offset + k + 1] & 0xff; + u = u - 128; + v = v - 128; + + argb[i] = yuv2argb(y1, u, v); + argb[i + 1] = yuv2argb(y2, u, v); + argb[width + i] = yuv2argb(y3, u, v); + argb[width + i + 1] = yuv2argb(y4, u, v); + + if (i != 0 && (i + 2) % width == 0) + i += width; + } +} + +static void nv21_to_yuv420p(int8_t *dst, int8_t *src, int len) { + memcpy(dst, src, len); // y + for (int i = 0; i < len/4; ++i) { + *(dst + len + i) = *(src + len + i * 2 + 1); // u + *(dst + len * 5 / 4 + i) = *(src + len + i * 2); // v + } +} \ No newline at end of file diff --git a/app/src/main/cpp/yuv/yuv_converter.h b/app/src/main/cpp/yuv/yuv_converter.h new file mode 100644 index 0000000..878c7e5 --- /dev/null +++ b/app/src/main/cpp/yuv/yuv_converter.h @@ -0,0 +1,22 @@ +// +// Created by xu fulong on 2022/7/9. +// + +#ifndef FFMPEGANDROID_YUV_CONVERTER_H +#define FFMPEGANDROID_YUV_CONVERTER_H + +#include + +static void rgba_to_yuv420p(int *argb, int8_t *yuv, int width, int height); + +static void yuv420p_to_argb(int8_t *yuv, int *argb, int width, int height); + +/** + * convert NV21 to YUV420P + * @param dst data of yuv420p + * @param src data of nv21 + * @param len width*height + */ +static void nv21_to_yuv420p(int8_t *dst, int8_t *src, int len); + +#endif //FFMPEGANDROID_YUV_CONVERTER_H diff --git a/app/src/main/cpp/yuv2rgb/yuv_2_rgb.cpp b/app/src/main/cpp/yuv2rgb/yuv_2_rgb.cpp deleted file mode 100644 index 044fcbc..0000000 --- a/app/src/main/cpp/yuv2rgb/yuv_2_rgb.cpp +++ /dev/null @@ -1,91 +0,0 @@ -// -// Created by xu fulong on 2022/7/8. -// - -#include "yuv_to_rgb.h" - -// https://chromium.googlesource.com/libyuv/libyuv -// https://mymusing.co/bt601-yuv-to-rgb-conversion-color/ -// https://www.color.org/chardata/rgb/rgb_registry.xalter - -// BT.601 YUV to RGB -// R = 1.164 * (Y - 16) + 1.596 * (V - 128) -// G = 1.164 * (Y - 16) - 0.392 * (U - 128) - 0.812 * (V - 128) -// B = 1.164 * (Y - 16) + 2.016 * (U - 128) - -// Y = 0.257 * R + 0.504 * G + 0.098 * B + 16 -// U = -0.148 * R - 0.291 * G + 0.439 * B + 128 -// V = 0.439 * R - 0.368 * G - 0.072 * B + 128 - -// BT.709 YUV to RGB -// R = 1.1644 * (Y - 16) + 1.7928 * (V - 128) -// G = 1.1644 * (Y - 16) - 0.2133 * (U - 128) - 0.533 * (V - 128) -// B = 1.1644 * (Y - 16) + 2.1124 * (U - 128) - -// Y = 0.1826 * R + 0.6142 * G + 0.0620 * B + 16 -// U = -0.1006 * R - 0.3386 * G + 0.4392 * B + 128 -// V = 0.4392 * B - 0.3989 * G - 0.0403 * B + 128 - -// BT.2020 YUV to RGB -// R = Y - 16 + 1.4746 * (V - 128) -// G = Y - 16 - 0.1645 * (U - 128) - 0.5713 * (V - 128) -// B = Y - 16 + 1.881 * (U - 128) - -// Y = 0.2627 * R + 0.6780 * G + 0.0593 * B + 16 -// U = -0.1396 * R - 0.3604 * G + 0.5 * B + 128 -// V = 0.5 * R - 0.4598 * G - 0.0402 * B + 128 - -static int range(int val) { - if (val < 0) { - return 0; - } else if (val > 255) { - return 255; - } else { - return val; - } -} - -static void YCbCr_to_RGB(uint8_t *dst, const uint8_t *src, int length) { - if (length < 1) return; - int R, G, B; - int Y, Cb, Cr; - int i, offset; - for (i = 0; i < length; i++) { - offset = (i << 1) + i; - Y = src[offset]; - Cb = src[offset + 1] - 128; - Cr = src[offset + 2] - 128; - R = Y + ((RGBRCrI * Cr + half_shift) >> shift); - G = Y + ((RGBGCbI * Cb + RGBGCrI * Cr + half_shift) >> shift); - B = Y + ((RGBBCbI * Cb + half_shift) >> shift); - R = range(R); - G = range(G); - B = range(B); - offset = i << 2; - dst[offset] = (uint8_t) B; - dst[offset + 1] = (uint8_t) G; - dst[offset + 2] = (uint8_t) R; - dst[offset + 3] = 0xff; - } -} - -static void RGB_to_YCbCr(uint8_t *dst, const uint8_t *src, int length) { - if (length < 1) return; - int R, G, B; - int i, offset; - for (i = 0; i < length; i++) { - offset = i << 2; - B = src[offset]; - G = src[offset + 1]; - R = src[offset + 2]; - offset = (i << 1) + i; - dst[offset] = (uint8_t) ((YCbCrYRI * R + YCbCrYGI * G + YCbCrYBI * B + half_shift) - >> shift); - dst[offset + 1] = (uint8_t) (128 + - ((YCbCrCbRI * R + YCbCrCbGI * G + YCbCrCbBI * B + half_shift) - >> shift)); - dst[offset + 2] = (uint8_t) (128 + - ((YCbCrCrRI * R + YCbCrCrGI * G + YCbCrCrBI * B + half_shift) - >> shift)); - } -} \ No newline at end of file diff --git a/app/src/main/cpp/yuv2rgb/yuv_to_rgb.h b/app/src/main/cpp/yuv2rgb/yuv_to_rgb.h deleted file mode 100644 index 6d367eb..0000000 --- a/app/src/main/cpp/yuv2rgb/yuv_to_rgb.h +++ /dev/null @@ -1,47 +0,0 @@ -// -// Created by xu fulong on 2022/7/8. -// - -#ifndef FFMPEGANDROID_YUV_TO_RGB_H -#define FFMPEGANDROID_YUV_TO_RGB_H - -#include - -const float YCbCrYRF = 0.299F; -const float YCbCrYGF = 0.587F; -const float YCbCrYBF = 0.114F; -const float YCbCrCbRF = -0.168736F; -const float YCbCrCbGF = -0.331264F; -const float YCbCrCbBF = 0.500000F; -const float YCbCrCrRF = 0.500000F; -const float YCbCrCrGF = -0.418688F; -const float YCbCrCrBF = -0.081312F; - -const float RGBRCrF = 1.40200F; -const float RGBGCbF = -0.34414F; -const float RGBGCrF = -0.71414F; -const float RGBBCbF = 1.77200F; - -const int shift = 20; -const int half_shift = 1 << (shift - 1); - -const int YCbCrYRI = (int)(YCbCrYRF * (1 << shift) + 0.5); -const int YCbCrYGI = (int)(YCbCrYGF * (1 << shift) + 0.5); -const int YCbCrYBI = (int)(YCbCrYBF * (1 << shift) + 0.5); -const int YCbCrCbRI = (int)(YCbCrCbRF * (1 << shift) + 0.5); -const int YCbCrCbGI = (int)(YCbCrCbGF * (1 << shift) + 0.5); -const int YCbCrCbBI = (int)(YCbCrCbBF * (1 << shift) + 0.5); -const int YCbCrCrRI = (int)(YCbCrCrRF * (1 << shift) + 0.5); -const int YCbCrCrGI = (int)(YCbCrCrGF * (1 << shift) + 0.5); -const int YCbCrCrBI = (int)(YCbCrCrBF * (1 << shift) + 0.5); - -const int RGBRCrI = (int)(RGBRCrF * (1 << shift) + 0.5); -const int RGBGCbI = (int)(RGBGCbF * (1 << shift) + 0.5); -const int RGBGCrI = (int)(RGBGCrF * (1 << shift) + 0.5); -const int RGBBCbI = (int)(RGBBCbF * (1 << shift) + 0.5); - -static void YCbCr_to_RGB(uint8_t* dst, const uint8_t* src, int length); - -static void RGB_to_YCbCr(uint8_t* dst, const uint8_t* src, int length); - -#endif //FFMPEGANDROID_YUV_TO_RGB_H