Commit 0b0baa28 by anjalibh Committed by Oliver Woodman

Expose and support colorspaces in LibVpx.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=109851975
parent e487fe6f
...@@ -22,14 +22,25 @@ import java.nio.ByteBuffer; ...@@ -22,14 +22,25 @@ import java.nio.ByteBuffer;
*/ */
public final class VpxOutputBuffer { 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 ByteBuffer data;
public long timestampUs; public long timestampUs;
public int width; public int width;
public int height; public int height;
public int flags; public int flags;
/**
* YUV planes for YUV mode.
*/
public ByteBuffer[] yuvPlanes; public ByteBuffer[] yuvPlanes;
public int[] yuvStrides; public int[] yuvStrides;
public int mode; public int mode;
public int colorspace;
/** /**
* This method is called from C++ through JNI after decoding is done. It will resize the * This method is called from C++ through JNI after decoding is done. It will resize the
...@@ -51,9 +62,10 @@ public final class VpxOutputBuffer { ...@@ -51,9 +62,10 @@ public final class VpxOutputBuffer {
* This method is called from C++ through JNI after decoding is done. It will resize the * This method is called from C++ through JNI after decoding is done. It will resize the
* buffer based on the given stride. * 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.width = width;
this.height = height; this.height = height;
this.colorspace = colorspace;
int yLength = yStride * height; int yLength = yStride * height;
int uvLength = uvStride * ((height + 1) / 2); int uvLength = uvStride * ((height + 1) / 2);
int minimumYuvSize = yLength + (uvLength * 2); int minimumYuvSize = yLength + (uvLength * 2);
......
...@@ -31,6 +31,18 @@ import javax.microedition.khronos.opengles.GL10; ...@@ -31,6 +31,18 @@ import javax.microedition.khronos.opengles.GL10;
*/ */
/* package */ class VpxRenderer implements GLSurfaceView.Renderer { /* 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 = private static final String VERTEX_SHADER =
"varying vec2 interp_tc;\n" "varying vec2 interp_tc;\n"
+ "attribute vec4 in_pos;\n" + "attribute vec4 in_pos;\n"
...@@ -46,14 +58,13 @@ import javax.microedition.khronos.opengles.GL10; ...@@ -46,14 +58,13 @@ import javax.microedition.khronos.opengles.GL10;
+ "uniform sampler2D y_tex;\n" + "uniform sampler2D y_tex;\n"
+ "uniform sampler2D u_tex;\n" + "uniform sampler2D u_tex;\n"
+ "uniform sampler2D v_tex;\n" + "uniform sampler2D v_tex;\n"
+ "uniform mat3 mColorConversion;\n"
+ "void main() {\n" + "void main() {\n"
+ " float y = 1.164 * (texture2D(y_tex, interp_tc).r - 0.0625);\n" + " vec3 yuv;"
+ " float u = texture2D(u_tex, interp_tc).r - 0.5;\n" + " yuv.x = texture2D(y_tex, interp_tc).r - 0.0625;\n"
+ " float v = texture2D(v_tex, interp_tc).r - 0.5;\n" + " yuv.y = texture2D(u_tex, interp_tc).r - 0.5;\n"
+ " gl_FragColor = vec4(y + 1.596 * v, " + " yuv.z = texture2D(v_tex, interp_tc).r - 0.5;\n"
+ " y - 0.391 * u - 0.813 * v, " + " gl_FragColor = vec4(mColorConversion * yuv, 1.0);"
+ " y + 2.018 * u, "
+ " 1.0);\n"
+ "}\n"; + "}\n";
private static final FloatBuffer TEXTURE_VERTICES = nativeFloatBuffer( private static final FloatBuffer TEXTURE_VERTICES = nativeFloatBuffer(
-1.0f, 1.0f, -1.0f, 1.0f,
...@@ -64,6 +75,7 @@ import javax.microedition.khronos.opengles.GL10; ...@@ -64,6 +75,7 @@ import javax.microedition.khronos.opengles.GL10;
private int program; private int program;
private int texLocation; private int texLocation;
private int colorMatrixLocation;
private FloatBuffer textureCoords; private FloatBuffer textureCoords;
private VpxOutputBuffer outputBuffer; private VpxOutputBuffer outputBuffer;
private int previousWidth; private int previousWidth;
...@@ -108,6 +120,9 @@ import javax.microedition.khronos.opengles.GL10; ...@@ -108,6 +120,9 @@ import javax.microedition.khronos.opengles.GL10;
posLocation, 2, GLES20.GL_FLOAT, false, 0, TEXTURE_VERTICES); posLocation, 2, GLES20.GL_FLOAT, false, 0, TEXTURE_VERTICES);
texLocation = GLES20.glGetAttribLocation(program, "in_tc"); texLocation = GLES20.glGetAttribLocation(program, "in_tc");
GLES20.glEnableVertexAttribArray(texLocation); GLES20.glEnableVertexAttribArray(texLocation);
checkNoGLES2Error();
colorMatrixLocation = GLES20.glGetUniformLocation(program, "mColorConversion");
checkNoGLES2Error();
setupTextures(); setupTextures();
checkNoGLES2Error(); checkNoGLES2Error();
} }
...@@ -125,6 +140,12 @@ import javax.microedition.khronos.opengles.GL10; ...@@ -125,6 +140,12 @@ import javax.microedition.khronos.opengles.GL10;
// Nothing to render yet. // Nothing to render yet.
return; 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++) { for (int i = 0; i < 3; i++) {
int h = (i == 0) ? outputBuffer.height : (outputBuffer.height + 1) / 2; int h = (i == 0) ? outputBuffer.height : (outputBuffer.height + 1) / 2;
GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i); GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + i);
......
...@@ -71,7 +71,7 @@ FUNC(jlong, vpxInit) { ...@@ -71,7 +71,7 @@ FUNC(jlong, vpxInit) {
const jclass outputBufferClass = env->FindClass( const jclass outputBufferClass = env->FindClass(
"com/google/android/exoplayer/ext/vp9/VpxOutputBuffer"); "com/google/android/exoplayer/ext/vp9/VpxOutputBuffer");
initForYuvFrame = env->GetMethodID(outputBufferClass, "initForYuvFrame", initForYuvFrame = env->GetMethodID(outputBufferClass, "initForYuvFrame",
"(IIII)V"); "(IIIII)V");
initForRgbFrame = env->GetMethodID(outputBufferClass, "initForRgbFrame", initForRgbFrame = env->GetMethodID(outputBufferClass, "initForRgbFrame",
"(II)V"); "(II)V");
dataField = env->GetFieldID(outputBufferClass, "data", dataField = env->GetFieldID(outputBufferClass, "data",
...@@ -128,9 +128,26 @@ FUNC(jint, vpxGetFrame, jlong jContext, jobject jOutputBuffer) { ...@@ -128,9 +128,26 @@ FUNC(jint, vpxGetFrame, jlong jContext, jobject jOutputBuffer) {
img->planes[VPX_PLANE_V], img->stride[VPX_PLANE_V], img->planes[VPX_PLANE_V], img->stride[VPX_PLANE_V],
dst, img->d_w * 2, img->d_w, img->d_h); dst, img->d_w * 2, img->d_w, img->d_h);
} else if (outputMode == kOutputModeYuv) { } 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. // resize buffer if required.
env->CallVoidMethod(jOutputBuffer, initForYuvFrame, img->d_w, img->d_h, 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. // get pointer to the data buffer.
const jobject dataObject = env->GetObjectField(jOutputBuffer, dataField); const jobject dataObject = env->GetObjectField(jOutputBuffer, dataField);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment