Update Android to use limited range YCbCr.

Limited range seems to be more used than full range and many Android
components already use limited range. This includes FileVideoCapturer,
VideoFileRenderer and HW codecs.

Bug: webrtc:9638
Change-Id: Iadd9b2f19020c6a25bde5e43a28e26a6230dde42
Reviewed-on: https://webrtc-review.googlesource.com/94543
Commit-Queue: Sami Kalliomäki <sakal@webrtc.org>
Reviewed-by: Magnus Jedvert <magjed@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24576}
This commit is contained in:
Sami Kalliomäki
2018-09-05 11:43:38 +02:00
committed by Commit Bot
parent 548dec4a81
commit 8ccddff6ac
7 changed files with 82 additions and 63 deletions

View File

@ -46,12 +46,24 @@ public class YuvConverter {
+ "}\n";
private static class ShaderCallbacks implements GlGenericDrawer.ShaderCallbacks {
// Y'UV444 to RGB888, see https://en.wikipedia.org/wiki/YUV#Y.27UV444_to_RGB888_conversion. We
// use the ITU-R coefficients for U and V.
private static final float[] yCoeffs = new float[] {0.2987856f, 0.5871095f, 0.1141049f, 0.0f};
// Y'UV444 to RGB888, see https://en.wikipedia.org/wiki/YUV#Y%E2%80%B2UV444_to_RGB888_conversion
// We use the ITU-R BT.601 coefficients for Y, U and V.
// The values in Wikipedia are inaccurate, the accurate values derived from the spec are:
// Y = 0.299 * R + 0.587 * G + 0.114 * B
// U = -0.168736 * R - 0.331264 * G + 0.5 * B + 0.5
// V = 0.5 * R - 0.418688 * G - 0.0813124 * B + 0.5
// To map the Y-values to range [16-235] and U- and V-values to range [16-240], the matrix has
// been multiplied with matrix:
// {{219 / 255, 0, 0, 16 / 255},
// {0, 224 / 255, 0, 16 / 255},
// {0, 0, 224 / 255, 16 / 255},
// {0, 0, 0, 1}}
private static final float[] yCoeffs =
new float[] {0.256788f, 0.504129f, 0.0979059f, 0.0627451f};
private static final float[] uCoeffs =
new float[] {-0.168805420f, -0.3317003f, 0.5005057f, 0.5f};
private static final float[] vCoeffs = new float[] {0.4997964f, -0.4184672f, -0.0813292f, 0.5f};
new float[] {-0.148223f, -0.290993f, 0.439216f, 0.501961f};
private static final float[] vCoeffs =
new float[] {0.439216f, -0.367788f, -0.0714274f, 0.501961f};
private int xUnitLoc;
private int coeffsLoc;

View File

@ -47,18 +47,18 @@ public class EglRendererTest {
private final static byte[][][] TEST_FRAMES_DATA = {
{
new byte[] {
11, -12, 13, -14, -15, 16, -17, 18, 19, -110, 111, -112, -113, 114, -115, 116},
new byte[] {117, 118, 119, 120}, new byte[] {121, 122, 123, 124},
-99, -93, -88, -83, -78, -73, -68, -62, -56, -52, -46, -41, -36, -31, -26, -20},
new byte[] {110, 113, 116, 118}, new byte[] {31, 45, 59, 73},
},
{
new byte[] {-11, -12, -13, -14, -15, -16, -17, -18, -19, -110, -111, -112, -113, -114,
-115, -116},
new byte[] {-121, -122, -123, -124}, new byte[] {-117, -118, -119, -120},
new byte[] {
-108, -103, -98, -93, -87, -82, -77, -72, -67, -62, -56, -50, -45, -40, -35, -30},
new byte[] {120, 123, 125, -127}, new byte[] {87, 100, 114, 127},
},
{
new byte[] {-11, -12, -13, -14, -15, -16, -17, -18, -19, -110, -111, -112, -113, -114,
-115, -116},
new byte[] {117, 118, 119, 120}, new byte[] {121, 122, 123, 124},
new byte[] {
-117, -112, -107, -102, -97, -92, -87, -81, -75, -71, -65, -60, -55, -50, -44, -39},
new byte[] {113, 116, 118, 120}, new byte[] {45, 59, 73, 87},
},
};
private final static ByteBuffer[][] TEST_FRAMES =
@ -176,7 +176,7 @@ public class EglRendererTest {
float highYValue = (plane.get(highIndexY * stride + lowIndexX) & 0xFF) * lowWeightX
+ (plane.get(highIndexY * stride + highIndexX) & 0xFF) * highWeightX;
return (lowWeightY * lowYValue + highWeightY * highYValue) / 255f;
return lowWeightY * lowYValue + highWeightY * highYValue;
}
private static byte saturatedFloatToByte(float c) {
@ -200,15 +200,16 @@ public class EglRendererTest {
for (int y = 0; y < TEST_FRAME_HEIGHT; y++) {
for (int x = 0; x < TEST_FRAME_WIDTH; x++) {
final int x2 = x / 2;
final int y2 = y / 2;
final float yC = (yuvFrame[0].get(y * yStride + x) & 0xFF) / 255f;
final float uC = linearSample(yuvFrame[1], TEST_FRAME_WIDTH / 2, TEST_FRAME_HEIGHT / 2,
(x + 0.5f) / TEST_FRAME_WIDTH, (y + 0.5f) / TEST_FRAME_HEIGHT)
final float yC = ((yuvFrame[0].get(y * yStride + x) & 0xFF) - 16f) / 219f;
final float uC = (linearSample(yuvFrame[1], TEST_FRAME_WIDTH / 2, TEST_FRAME_HEIGHT / 2,
(x + 0.5f) / TEST_FRAME_WIDTH, (y + 0.5f) / TEST_FRAME_HEIGHT)
- 16f)
/ 224f
- 0.5f;
final float vC = linearSample(yuvFrame[2], TEST_FRAME_WIDTH / 2, TEST_FRAME_HEIGHT / 2,
(x + 0.5f) / TEST_FRAME_WIDTH, (y + 0.5f) / TEST_FRAME_HEIGHT)
final float vC = (linearSample(yuvFrame[2], TEST_FRAME_WIDTH / 2, TEST_FRAME_HEIGHT / 2,
(x + 0.5f) / TEST_FRAME_WIDTH, (y + 0.5f) / TEST_FRAME_HEIGHT)
- 16f)
/ 224f
- 0.5f;
final float rC = yC + 1.403f * vC;
final float gC = yC - 0.344f * uC - 0.714f * vC;

View File

@ -181,15 +181,17 @@ public class GlRectDrawerTest {
for (int y = 0; y < HEIGHT; ++y) {
for (int x = 0; x < WIDTH; ++x) {
// YUV color space. Y in [0, 1], UV in [-0.5, 0.5]. The constants are taken from the YUV
// fragment shader code in GlRectDrawer.
// fragment shader code in GlGenericDrawer.
final float y_luma = normalizedByte(yuvPlanes[0].get());
final float u_chroma = normalizedByte(yuvPlanes[1].get()) - 0.5f;
final float v_chroma = normalizedByte(yuvPlanes[2].get()) - 0.5f;
final float u_chroma = normalizedByte(yuvPlanes[1].get());
final float v_chroma = normalizedByte(yuvPlanes[2].get());
// Expected color in unrounded RGB [0.0f, 255.0f].
final float expectedRed = saturatedConvert(y_luma + 1.403f * v_chroma);
final float expectedGreen =
saturatedConvert(y_luma - 0.344f * u_chroma - 0.714f * v_chroma);
final float expectedBlue = saturatedConvert(y_luma + 1.77f * u_chroma);
final float expectedRed =
saturatedConvert(1.16438f * y_luma + 1.59603f * v_chroma - 0.874202f);
final float expectedGreen = saturatedConvert(
1.16438f * y_luma - 0.391762f * u_chroma - 0.812968f * v_chroma + 0.531668f);
final float expectedBlue =
saturatedConvert(1.16438f * y_luma + 2.01723f * u_chroma - 1.08563f);
// Actual color in RGB8888.
final int actualRed = data.get() & 0xFF;

View File

@ -459,9 +459,9 @@ public class SurfaceTextureHelperTest {
final int green[] = new int[] {66, 210, 162};
final int blue[] = new int[] {161, 117, 158};
final int ref_y[] = new int[] {81, 180, 168};
final int ref_u[] = new int[] {173, 93, 122};
final int ref_v[] = new int[] {127, 103, 140};
final int ref_y[] = new int[] {85, 170, 161};
final int ref_u[] = new int[] {168, 97, 123};
final int ref_v[] = new int[] {127, 106, 138};
// Draw three frames.
for (int i = 0; i < 3; ++i) {

View File

@ -103,28 +103,28 @@ public class VideoFrameBufferTest {
public static VideoFrame.I420Buffer createTestI420Buffer() {
final int width = 16;
final int height = 16;
final int[] yData = new int[] {164, 170, 176, 182, 188, 194, 200, 206, 213, 218, 225, 231, 237,
243, 249, 255, 153, 159, 165, 171, 177, 183, 189, 195, 201, 207, 213, 220, 226, 232, 238,
244, 142, 148, 154, 160, 166, 172, 178, 184, 191, 196, 203, 209, 215, 221, 227, 233, 131,
137, 143, 149, 155, 161, 167, 174, 180, 186, 192, 198, 204, 210, 216, 222, 120, 126, 132,
138, 145, 151, 157, 163, 169, 175, 181, 187, 193, 199, 205, 211, 109, 115, 121, 128, 133,
140, 146, 152, 158, 164, 170, 176, 182, 188, 194, 200, 99, 104, 111, 117, 123, 129, 135,
141, 147, 153, 159, 165, 171, 177, 183, 189, 87, 94, 100, 106, 112, 118, 124, 130, 136, 142,
148, 154, 160, 166, 172, 178, 77, 83, 89, 95, 101, 107, 113, 119, 125, 131, 137, 143, 149,
155, 161, 167, 66, 72, 78, 84, 90, 96, 102, 108, 114, 120, 126, 132, 138, 144, 150, 156, 55,
61, 67, 73, 79, 85, 91, 97, 103, 109, 115, 121, 127, 133, 139, 145, 44, 50, 56, 62, 68, 74,
80, 86, 92, 98, 104, 110, 116, 122, 128, 134, 33, 39, 45, 51, 57, 63, 69, 75, 81, 87, 93,
99, 105, 111, 117, 123, 22, 28, 34, 40, 46, 52, 58, 64, 70, 76, 82, 88, 94, 100, 106, 113,
11, 17, 23, 29, 35, 41, 47, 53, 59, 65, 71, 77, 83, 89, 96, 102, 0, 6, 12, 18, 24, 30, 36,
42, 48, 54, 60, 66, 72, 79, 85, 91};
final int[] uData = new int[] {108, 111, 114, 117, 119, 122, 125, 128, 111, 114, 117, 119, 122,
125, 128, 130, 114, 117, 119, 122, 125, 128, 130, 133, 117, 119, 122, 125, 128, 130, 133,
136, 119, 122, 125, 128, 130, 133, 136, 139, 122, 125, 128, 130, 133, 136, 139, 141, 125,
128, 130, 133, 136, 139, 141, 144, 128, 130, 133, 136, 139, 141, 144, 147};
final int[] vData = new int[] {18, 34, 49, 65, 81, 96, 112, 127, 34, 49, 65, 81, 96, 112, 128,
143, 49, 65, 81, 96, 112, 127, 143, 159, 65, 81, 96, 112, 127, 143, 159, 174, 81, 96, 112,
128, 143, 159, 174, 190, 96, 112, 128, 143, 159, 174, 190, 206, 112, 127, 143, 159, 174,
190, 205, 221, 127, 143, 159, 174, 190, 205, 221, 237};
final int[] yData = new int[] {156, 162, 167, 172, 177, 182, 187, 193, 199, 203, 209, 214, 219,
224, 229, 235, 147, 152, 157, 162, 168, 173, 178, 183, 188, 193, 199, 205, 210, 215, 220,
225, 138, 143, 148, 153, 158, 163, 168, 174, 180, 184, 190, 195, 200, 205, 211, 216, 128,
133, 138, 144, 149, 154, 159, 165, 170, 175, 181, 186, 191, 196, 201, 206, 119, 124, 129,
134, 140, 145, 150, 156, 161, 166, 171, 176, 181, 187, 192, 197, 109, 114, 119, 126, 130,
136, 141, 146, 151, 156, 162, 167, 172, 177, 182, 187, 101, 105, 111, 116, 121, 126, 132,
137, 142, 147, 152, 157, 162, 168, 173, 178, 90, 96, 101, 107, 112, 117, 122, 127, 132, 138,
143, 148, 153, 158, 163, 168, 82, 87, 92, 97, 102, 107, 113, 118, 123, 128, 133, 138, 144,
149, 154, 159, 72, 77, 83, 88, 93, 98, 103, 108, 113, 119, 124, 129, 134, 139, 144, 150, 63,
68, 73, 78, 83, 89, 94, 99, 104, 109, 114, 119, 125, 130, 135, 140, 53, 58, 64, 69, 74, 79,
84, 89, 95, 100, 105, 110, 115, 120, 126, 131, 44, 49, 54, 59, 64, 70, 75, 80, 85, 90, 95,
101, 106, 111, 116, 121, 34, 40, 45, 50, 55, 60, 65, 71, 76, 81, 86, 91, 96, 101, 107, 113,
25, 30, 35, 40, 46, 51, 56, 61, 66, 71, 77, 82, 87, 92, 98, 103, 16, 21, 26, 31, 36, 41, 46,
52, 57, 62, 67, 72, 77, 83, 89, 94};
final int[] uData = new int[] {110, 113, 116, 118, 120, 123, 125, 128, 113, 116, 118, 120, 123,
125, 128, 130, 116, 118, 120, 123, 125, 128, 130, 132, 118, 120, 123, 125, 128, 130, 132,
135, 120, 123, 125, 128, 130, 132, 135, 138, 123, 125, 128, 130, 132, 135, 138, 139, 125,
128, 130, 132, 135, 138, 139, 142, 128, 130, 132, 135, 138, 139, 142, 145};
final int[] vData = new int[] {31, 45, 59, 73, 87, 100, 114, 127, 45, 59, 73, 87, 100, 114, 128,
141, 59, 73, 87, 100, 114, 127, 141, 155, 73, 87, 100, 114, 127, 141, 155, 168, 87, 100,
114, 128, 141, 155, 168, 182, 100, 114, 128, 141, 155, 168, 182, 197, 114, 127, 141, 155,
168, 182, 196, 210, 127, 141, 155, 168, 182, 196, 210, 224};
return JavaI420Buffer.wrap(width, height, toByteBuffer(yData),
/* strideY= */ width, toByteBuffer(uData), /* strideU= */ width / 2, toByteBuffer(vData),
/* strideV= */ width / 2,

View File

@ -102,12 +102,14 @@ class GlGenericDrawer implements RendererCommon.GlDrawer {
stringBuilder.append("uniform sampler2D v_tex;\n");
// Add separate function for sampling texture.
// yuv_to_rgb_mat is inverse of the matrix defined in YuvConverter.
stringBuilder.append("vec4 sample(vec2 p) {\n");
stringBuilder.append(" float y = texture2D(y_tex, p).r;\n");
stringBuilder.append(" float u = texture2D(u_tex, p).r - 0.5;\n");
stringBuilder.append(" float v = texture2D(v_tex, p).r - 0.5;\n");
stringBuilder.append(
" return vec4(y + 1.403 * v, y - 0.344 * u - 0.714 * v, y + 1.77 * u, 1);\n");
stringBuilder.append(" float y = texture2D(y_tex, p).r * 1.16438;\n");
stringBuilder.append(" float u = texture2D(u_tex, p).r;\n");
stringBuilder.append(" float v = texture2D(v_tex, p).r;\n");
stringBuilder.append(" return vec4(y + 1.59603 * v - 0.874202,\n");
stringBuilder.append(" y - 0.391762 * u - 0.812968 * v + 0.531668,\n");
stringBuilder.append(" y + 2.01723 * u - 1.08563, 1);\n");
stringBuilder.append("}\n");
stringBuilder.append(genericFragmentSource);
} else {

View File

@ -104,10 +104,12 @@ public class GlGenericDrawerTest {
+ "uniform sampler2D u_tex;\n"
+ "uniform sampler2D v_tex;\n"
+ "vec4 sample(vec2 p) {\n"
+ " float y = texture2D(y_tex, p).r;\n"
+ " float u = texture2D(u_tex, p).r - 0.5;\n"
+ " float v = texture2D(v_tex, p).r - 0.5;\n"
+ " return vec4(y + 1.403 * v, y - 0.344 * u - 0.714 * v, y + 1.77 * u, 1);\n"
+ " float y = texture2D(y_tex, p).r * 1.16438;\n"
+ " float u = texture2D(u_tex, p).r;\n"
+ " float v = texture2D(v_tex, p).r;\n"
+ " return vec4(y + 1.59603 * v - 0.874202,\n"
+ " y - 0.391762 * u - 0.812968 * v + 0.531668,\n"
+ " y + 2.01723 * u - 1.08563, 1);\n"
+ "}\n"
+ "void main() {\n"
+ " gl_FragColor = sample(tc);\n"