blob: ebbfd30bf8f59fbb1d8730921151fde6adbae85e [file] [log] [blame]
/*
* Copyright 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.hardware.cts;
import static android.opengl.GLES20.glDeleteTextures;
import static android.opengl.GLES20.glGenTextures;
import static org.junit.Assert.assertEquals;
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.DataSpace;
import android.media.Image;
import android.media.ImageReader;
import android.media.ImageWriter;
import android.opengl.EGL14;
import android.opengl.EGLConfig;
import android.opengl.EGLContext;
import android.opengl.EGLDisplay;
import android.opengl.EGLSurface;
import android.view.Surface;
import androidx.test.annotation.UiThreadTest;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class DataSpaceTest {
private SurfaceTexture mSurfaceTexture;
private Surface mSurface;
private int[] mTex;
private ImageWriter mWriter;
private ImageReader mReader;
private EGLDisplay mEglDisplay = EGL14.EGL_NO_DISPLAY;
private EGLConfig mEglConfig = null;
private EGLSurface mEglSurface = EGL14.EGL_NO_SURFACE;
private EGLContext mEglContext = EGL14.EGL_NO_CONTEXT;
@UiThreadTest
@Before
public void setUp() throws Throwable {
mEglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
if (mEglDisplay == EGL14.EGL_NO_DISPLAY) {
throw new RuntimeException("no EGL display");
}
int[] major = new int[1];
int[] minor = new int[1];
if (!EGL14.eglInitialize(mEglDisplay, major, 0, minor, 0)) {
throw new RuntimeException("error in eglInitialize");
}
// If we could rely on having EGL_KHR_surfaceless_context and EGL_KHR_context_no_config, we
// wouldn't have to create a config or pbuffer at all.
int[] numConfigs = new int[1];
EGLConfig[] configs = new EGLConfig[1];
if (!EGL14.eglChooseConfig(mEglDisplay, new int[] {
EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
EGL14.EGL_SURFACE_TYPE, EGL14.EGL_PBUFFER_BIT,
EGL14.EGL_NONE}, 0, configs, 0, 1, numConfigs, 0)) {
throw new RuntimeException("eglChooseConfig failed");
}
mEglConfig = configs[0];
mEglSurface = EGL14.eglCreatePbufferSurface(mEglDisplay, mEglConfig,
new int[] {EGL14.EGL_WIDTH, 1, EGL14.EGL_HEIGHT, 1, EGL14.EGL_NONE}, 0);
if (mEglSurface == EGL14.EGL_NO_SURFACE) {
throw new RuntimeException("eglCreatePbufferSurface failed");
}
mEglContext = EGL14.eglCreateContext(mEglDisplay, mEglConfig, EGL14.EGL_NO_CONTEXT,
new int[] {EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL14.EGL_NONE}, 0);
if (mEglContext == EGL14.EGL_NO_CONTEXT) {
throw new RuntimeException("eglCreateContext failed");
}
if (!EGL14.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
throw new RuntimeException("eglMakeCurrent failed");
}
}
@After
public void tearDown() throws Throwable {
if (mReader != null) {
mReader.close();
mReader = null;
}
if (mWriter != null) {
mWriter.close();
mWriter = null;
}
if (mSurface != null) {
mSurface.release();
mSurface = null;
}
if (mSurfaceTexture != null) {
mSurfaceTexture.release();
mSurfaceTexture = null;
glDeleteTextures(1, mTex, 0);
}
if (mEglDisplay != EGL14.EGL_NO_DISPLAY) {
EGL14.eglDestroyContext(mEglDisplay, mEglContext);
EGL14.eglDestroySurface(mEglDisplay, mEglSurface);
EGL14.eglTerminate(mEglDisplay);
}
mEglDisplay = EGL14.EGL_NO_DISPLAY;
mEglContext = EGL14.EGL_NO_CONTEXT;
mEglSurface = EGL14.EGL_NO_SURFACE;
}
@UiThreadTest
@Test
public void getDataSpace() {
mTex = new int[1];
glGenTextures(1, mTex, 0);
// create a surfaceTexture attached to mTex[0]
mSurfaceTexture = new SurfaceTexture(mTex[0]);
mSurfaceTexture.setDefaultBufferSize(16, 16);
mSurface = new Surface(mSurfaceTexture);
mWriter = new ImageWriter.Builder(mSurface).build();
int dataSpace = DataSpace.pack(DataSpace.STANDARD_BT709,
DataSpace.TRANSFER_SMPTE_170M,
DataSpace.RANGE_LIMITED);
Image inputImage = null;
try {
inputImage = mWriter.dequeueInputImage();
inputImage.setDataSpace(dataSpace);
assertEquals(dataSpace, inputImage.getDataSpace());
mWriter.queueInputImage(inputImage);
mSurfaceTexture.updateTexImage();
int outDataSpace = mSurfaceTexture.getDataSpace();
assertEquals(dataSpace, outDataSpace);
assertEquals(DataSpace.STANDARD_BT709, DataSpace.getStandard(outDataSpace));
assertEquals(DataSpace.TRANSFER_SMPTE_170M, DataSpace.getTransfer(outDataSpace));
assertEquals(DataSpace.RANGE_LIMITED, DataSpace.getRange(outDataSpace));
} finally {
if (inputImage != null) {
inputImage.close();
inputImage = null;
}
}
}
@UiThreadTest
@Test
public void getDataSpaceWithoutSetDataSpace() {
mTex = new int[1];
glGenTextures(1, mTex, 0);
// create a surfaceTexture attached to mTex[0]
mSurfaceTexture = new SurfaceTexture(mTex[0]);
mSurfaceTexture.setDefaultBufferSize(16, 16);
mSurface = new Surface(mSurfaceTexture);
mWriter = ImageWriter.newInstance(mSurface, 1);
Image inputImage = null;
try {
inputImage = mWriter.dequeueInputImage();
mWriter.queueInputImage(inputImage);
mSurfaceTexture.updateTexImage();
assertEquals(DataSpace.DATASPACE_UNKNOWN, mSurfaceTexture.getDataSpace());
} finally {
if (inputImage != null) {
inputImage.close();
inputImage = null;
}
}
}
@UiThreadTest
@Test
public void getDataSpaceWithFormatYUV420_888() {
mTex = new int[1];
glGenTextures(1, mTex, 0);
// create a surfaceTexture attached to mTex[0]
mSurfaceTexture = new SurfaceTexture(mTex[0]);
mSurfaceTexture.setDefaultBufferSize(16, 16);
mSurface = new Surface(mSurfaceTexture);
mWriter = new ImageWriter.Builder(mSurface)
.setImageFormat(ImageFormat.YUV_420_888)
.build();
Image inputImage = null;
try {
inputImage = mWriter.dequeueInputImage();
mWriter.queueInputImage(inputImage);
mSurfaceTexture.updateTexImage();
// test default dataspace value of ImageFormat.YUV_420_888 format.
assertEquals(DataSpace.DATASPACE_JFIF, mSurfaceTexture.getDataSpace());
} finally {
if (inputImage != null) {
inputImage.close();
inputImage = null;
}
}
}
@UiThreadTest
@Test
public void getDataSpaceFromImageReaderNextImage() {
mReader = ImageReader.newInstance(100, 100, ImageFormat.YUV_420_888, 1);
mWriter = ImageWriter.newInstance(mReader.getSurface(), 1);
int dataSpace = DataSpace.pack(DataSpace.STANDARD_BT601_625,
DataSpace.TRANSFER_SMPTE_170M,
DataSpace.RANGE_FULL);
Image outputImage = null;
Image nextImage = null;
try {
outputImage = mWriter.dequeueInputImage();
outputImage.setDataSpace(dataSpace);
assertEquals(dataSpace, outputImage.getDataSpace());
mWriter.queueInputImage(outputImage);
nextImage = mReader.acquireLatestImage();
assertEquals(dataSpace, nextImage.getDataSpace());
} finally {
if (outputImage != null) {
outputImage.close();
outputImage = null;
}
if (nextImage != null) {
nextImage.close();
nextImage = null;
}
}
}
}