Feature: yuv convert to argb

pull/221/head
xufuji456 2 years ago
parent 77c8ece3b4
commit c987c5cebc
  1. 74
      Live/src/main/java/com/frank/live/util/YUVUtil.java
  2. 2
      app/CMakeLists.txt
  3. 115
      app/src/main/cpp/yuv/yuv_converter.cpp
  4. 22
      app/src/main/cpp/yuv/yuv_converter.h
  5. 91
      app/src/main/cpp/yuv2rgb/yuv_2_rgb.cpp
  6. 47
      app/src/main/cpp/yuv2rgb/yuv_to_rgb.h

@ -1,7 +1,5 @@
package com.frank.live.util; package com.frank.live.util;
import android.util.Log;
/** /**
* Tool of transforming YUV format * Tool of transforming YUV format
* Created by frank on 2018/7/1. * Created by frank on 2018/7/1.
@ -9,40 +7,72 @@ import android.util.Log;
public class YUVUtil { 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; final int frameSize = width * height;
byte[] yuv420sp = new byte[width * height * 3 / 2]; int index = 0;
int yIndex = 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 j = 0; j < height; j++) {
for (int i = 0; i < width; i++) { for (int i = 0; i < width; i++) {
R = (argb[index] & 0xff0000) >> 16;
a = (input[index] & 0xff000000) >> 24; G = (argb[index] & 0xff00) >> 8;
R = (input[index] & 0xff0000) >> 16; B = (argb[index] & 0xff);
G = (input[index] & 0xff00) >> 8;
B = (input[index] & 0xff);
// RGB to YUV algorithm // RGB to YUV algorithm
Y = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16; Y = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16;
// 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; U = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128;
V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128; V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128;
yuv[uIndex++] = (byte) U;
// NV21 has a plane of Y and interleaved planes of VU each sampled by a factor of 2 yuv[vIndex++] = (byte) V;
// 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)));
} }
index++; 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) { public static void YUV420pRotate90(byte[] dst, byte[] src, int width, int height) {

@ -42,7 +42,7 @@ add_library( # Sets the name of the library.
src/main/cpp/metadata/media_retriever_jni.cpp src/main/cpp/metadata/media_retriever_jni.cpp
src/main/cpp/metadata/metadata_util.c src/main/cpp/metadata/metadata_util.c
src/main/cpp/metadata/ffmpeg_media_retriever.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 add_library( ffmpeg

@ -0,0 +1,115 @@
//
// Created by xu fulong on 2022/7/9.
//
#include "yuv_converter.h"
#include <cstring>
// 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
}
}

@ -0,0 +1,22 @@
//
// Created by xu fulong on 2022/7/9.
//
#ifndef FFMPEGANDROID_YUV_CONVERTER_H
#define FFMPEGANDROID_YUV_CONVERTER_H
#include <cstdint>
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

@ -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));
}
}

@ -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 <cstdint>
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
Loading…
Cancel
Save