From 0b0baa28be92ddc96128ba793d2f96f2c9e12cfc Mon Sep 17 00:00:00 2001 From: anjalibh Date: Wed, 9 Dec 2015 17:46:07 -0800 Subject: [PATCH] Expose and support colorspaces in LibVpx. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=109851975 --- .../exoplayer/ext/vp9/VpxOutputBuffer.java | 14 +++++++- .../exoplayer/ext/vp9/VpxRenderer.java | 35 +++++++++++++++---- extensions/vp9/src/main/jni/vpx_jni.cc | 21 +++++++++-- 3 files changed, 60 insertions(+), 10 deletions(-) diff --git a/extensions/vp9/src/main/java/com/google/android/exoplayer/ext/vp9/VpxOutputBuffer.java b/extensions/vp9/src/main/java/com/google/android/exoplayer/ext/vp9/VpxOutputBuffer.java index 193de149b7..a509e7bcb2 100644 --- a/extensions/vp9/src/main/java/com/google/android/exoplayer/ext/vp9/VpxOutputBuffer.java +++ b/extensions/vp9/src/main/java/com/google/android/exoplayer/ext/vp9/VpxOutputBuffer.java @@ -22,14 +22,25 @@ import java.nio.ByteBuffer; */ public final class VpxOutputBuffer { + public static final int COLORSPACE_UNKNOWN = 0; + public static final int COLORSPACE_BT601 = 1; + public static final int COLORSPACE_BT709 = 2; + + /** + * RGB buffer for RGB mode. + */ public ByteBuffer data; public long timestampUs; public int width; public int height; public int flags; + /** + * YUV planes for YUV mode. + */ public ByteBuffer[] yuvPlanes; public int[] yuvStrides; public int mode; + public int colorspace; /** * This method is called from C++ through JNI after decoding is done. It will resize the @@ -51,9 +62,10 @@ public final class VpxOutputBuffer { * This method is called from C++ through JNI after decoding is done. It will resize the * buffer based on the given stride. */ - public void initForYuvFrame(int width, int height, int yStride, int uvStride) { + public void initForYuvFrame(int width, int height, int yStride, int uvStride, int colorspace) { this.width = width; this.height = height; + this.colorspace = colorspace; int yLength = yStride * height; int uvLength = uvStride * ((height + 1) / 2); int minimumYuvSize = yLength + (uvLength * 2); diff --git a/extensions/vp9/src/main/java/com/google/android/exoplayer/ext/vp9/VpxRenderer.java b/extensions/vp9/src/main/java/com/google/android/exoplayer/ext/vp9/VpxRenderer.java index 68765968a1..6deeab5c3d 100644 --- a/extensions/vp9/src/main/java/com/google/android/exoplayer/ext/vp9/VpxRenderer.java +++ b/extensions/vp9/src/main/java/com/google/android/exoplayer/ext/vp9/VpxRenderer.java @@ -31,6 +31,18 @@ import javax.microedition.khronos.opengles.GL10; */ /* package */ class VpxRenderer implements GLSurfaceView.Renderer { + private static final float[] kColorConversion601 = { + 1.164f, 1.164f, 1.164f, + 0.0f, -0.392f, 2.017f, + 1.596f, -0.813f, 0.0f, + }; + + private static final float[] kColorConversion709 = { + 1.164f, 1.164f, 1.164f, + 0.0f, -0.213f, 2.112f, + 1.793f, -0.533f, 0.0f, + }; + private static final String VERTEX_SHADER = "varying vec2 interp_tc;\n" + "attribute vec4 in_pos;\n" @@ -46,14 +58,13 @@ import javax.microedition.khronos.opengles.GL10; + "uniform sampler2D y_tex;\n" + "uniform sampler2D u_tex;\n" + "uniform sampler2D v_tex;\n" + + "uniform mat3 mColorConversion;\n" + "void main() {\n" - + " float y = 1.164 * (texture2D(y_tex, interp_tc).r - 0.0625);\n" - + " float u = texture2D(u_tex, interp_tc).r - 0.5;\n" - + " float v = texture2D(v_tex, interp_tc).r - 0.5;\n" - + " gl_FragColor = vec4(y + 1.596 * v, " - + " y - 0.391 * u - 0.813 * v, " - + " y + 2.018 * u, " - + " 1.0);\n" + + " vec3 yuv;" + + " yuv.x = texture2D(y_tex, interp_tc).r - 0.0625;\n" + + " yuv.y = texture2D(u_tex, interp_tc).r - 0.5;\n" + + " yuv.z = texture2D(v_tex, interp_tc).r - 0.5;\n" + + " gl_FragColor = vec4(mColorConversion * yuv, 1.0);" + "}\n"; private static final FloatBuffer TEXTURE_VERTICES = nativeFloatBuffer( -1.0f, 1.0f, @@ -64,6 +75,7 @@ import javax.microedition.khronos.opengles.GL10; private int program; private int texLocation; + private int colorMatrixLocation; private FloatBuffer textureCoords; private VpxOutputBuffer outputBuffer; private int previousWidth; @@ -108,6 +120,9 @@ import javax.microedition.khronos.opengles.GL10; posLocation, 2, GLES20.GL_FLOAT, false, 0, TEXTURE_VERTICES); texLocation = GLES20.glGetAttribLocation(program, "in_tc"); GLES20.glEnableVertexAttribArray(texLocation); + checkNoGLES2Error(); + colorMatrixLocation = GLES20.glGetUniformLocation(program, "mColorConversion"); + checkNoGLES2Error(); setupTextures(); checkNoGLES2Error(); } @@ -125,6 +140,12 @@ import javax.microedition.khronos.opengles.GL10; // Nothing to render yet. return; } + + // Set color matrix. Assume BT709 if the color space is unknown. + float[] colorConversion = outputBuffer.colorspace == VpxOutputBuffer.COLORSPACE_BT601 + ? kColorConversion601 : kColorConversion709; + GLES20.glUniformMatrix3fv(colorMatrixLocation, 1, false, colorConversion, 0); + for (int i = 0; i < 3; i++) { int h = (i == 0) ? outputBuffer.height : (outputBuffer.height + 1) / 2; GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i); diff --git a/extensions/vp9/src/main/jni/vpx_jni.cc b/extensions/vp9/src/main/jni/vpx_jni.cc index ba19f299cb..a3abe24399 100644 --- a/extensions/vp9/src/main/jni/vpx_jni.cc +++ b/extensions/vp9/src/main/jni/vpx_jni.cc @@ -71,7 +71,7 @@ FUNC(jlong, vpxInit) { const jclass outputBufferClass = env->FindClass( "com/google/android/exoplayer/ext/vp9/VpxOutputBuffer"); initForYuvFrame = env->GetMethodID(outputBufferClass, "initForYuvFrame", - "(IIII)V"); + "(IIIII)V"); initForRgbFrame = env->GetMethodID(outputBufferClass, "initForRgbFrame", "(II)V"); dataField = env->GetFieldID(outputBufferClass, "data", @@ -128,9 +128,26 @@ FUNC(jint, vpxGetFrame, jlong jContext, jobject jOutputBuffer) { img->planes[VPX_PLANE_V], img->stride[VPX_PLANE_V], dst, img->d_w * 2, img->d_w, img->d_h); } else if (outputMode == kOutputModeYuv) { + const int kColorspaceUnknown = 0; + const int kColorspaceBT601 = 1; + const int kColorspaceBT709 = 2; + + int colorspace = kColorspaceUnknown; + switch (img->cs) { + case VPX_CS_BT_601: + colorspace = kColorspaceBT601; + break; + case VPX_CS_BT_709: + colorspace = kColorspaceBT709; + break; + default: + break; + } + // resize buffer if required. env->CallVoidMethod(jOutputBuffer, initForYuvFrame, img->d_w, img->d_h, - img->stride[VPX_PLANE_Y], img->stride[VPX_PLANE_U]); + img->stride[VPX_PLANE_Y], img->stride[VPX_PLANE_U], + colorspace); // get pointer to the data buffer. const jobject dataObject = env->GetObjectField(jOutputBuffer, dataField);