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}
diff --git a/sdk/android/api/org/webrtc/YuvConverter.java b/sdk/android/api/org/webrtc/YuvConverter.java
index de02c11..7d55f07 100644
--- a/sdk/android/api/org/webrtc/YuvConverter.java
+++ b/sdk/android/api/org/webrtc/YuvConverter.java
@@ -46,12 +46,24 @@
       + "}\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;
diff --git a/sdk/android/instrumentationtests/src/org/webrtc/EglRendererTest.java b/sdk/android/instrumentationtests/src/org/webrtc/EglRendererTest.java
index 29d822f..fe2a863 100644
--- a/sdk/android/instrumentationtests/src/org/webrtc/EglRendererTest.java
+++ b/sdk/android/instrumentationtests/src/org/webrtc/EglRendererTest.java
@@ -47,18 +47,18 @@
   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 @@
     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 @@
 
     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;
diff --git a/sdk/android/instrumentationtests/src/org/webrtc/GlRectDrawerTest.java b/sdk/android/instrumentationtests/src/org/webrtc/GlRectDrawerTest.java
index fecddb3..7d5196e 100644
--- a/sdk/android/instrumentationtests/src/org/webrtc/GlRectDrawerTest.java
+++ b/sdk/android/instrumentationtests/src/org/webrtc/GlRectDrawerTest.java
@@ -181,15 +181,17 @@
     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;
diff --git a/sdk/android/instrumentationtests/src/org/webrtc/SurfaceTextureHelperTest.java b/sdk/android/instrumentationtests/src/org/webrtc/SurfaceTextureHelperTest.java
index 3cd08cc..837bd6e 100644
--- a/sdk/android/instrumentationtests/src/org/webrtc/SurfaceTextureHelperTest.java
+++ b/sdk/android/instrumentationtests/src/org/webrtc/SurfaceTextureHelperTest.java
@@ -459,9 +459,9 @@
     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) {
diff --git a/sdk/android/instrumentationtests/src/org/webrtc/VideoFrameBufferTest.java b/sdk/android/instrumentationtests/src/org/webrtc/VideoFrameBufferTest.java
index 539ba3d..afbb0fd 100644
--- a/sdk/android/instrumentationtests/src/org/webrtc/VideoFrameBufferTest.java
+++ b/sdk/android/instrumentationtests/src/org/webrtc/VideoFrameBufferTest.java
@@ -103,28 +103,28 @@
   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,
diff --git a/sdk/android/src/java/org/webrtc/GlGenericDrawer.java b/sdk/android/src/java/org/webrtc/GlGenericDrawer.java
index cd7b1e8..20d71c0 100644
--- a/sdk/android/src/java/org/webrtc/GlGenericDrawer.java
+++ b/sdk/android/src/java/org/webrtc/GlGenericDrawer.java
@@ -102,12 +102,14 @@
       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 {
diff --git a/sdk/android/tests/src/org/webrtc/GlGenericDrawerTest.java b/sdk/android/tests/src/org/webrtc/GlGenericDrawerTest.java
index 06b5367..1f92b9c 100644
--- a/sdk/android/tests/src/org/webrtc/GlGenericDrawerTest.java
+++ b/sdk/android/tests/src/org/webrtc/GlGenericDrawerTest.java
@@ -104,10 +104,12 @@
         + "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"