In the code, I fixed the resolution of camera preview to the device resolution, and tested on the NEXUS 9.
// AndroidManifest.xml ... < uses-feature android:glEsVersion="0x00020000" android:required="true"/> < uses-feature android:name="android.hardware.camera2"/> < uses-permission android:name="android.permission.CAMERA"/> ... < activity android:name=".MainActivity" android:screenOrientation="landscape"> ... // MainActivity.java package ... import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.Window; import android.view.WindowManager; public class MainActivity extends Activity { private MainView mView; @Override public void onCreate ( Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); int ui = getWindow().getDecorView().getSystemUiVisibility(); ui = ui | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; getWindow().getDecorView().setSystemUiVisibility(ui); getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); mView = new MainView(this); setContentView ( mView ); } @Override protected void onResume() { super.onResume(); mView.onResume(); } @Override protected void onPause() { mView.onPause(); super.onPause(); } } // MainView.java package ... import android.content.Context; import android.opengl.GLSurfaceView; import android.view.SurfaceHolder; public class MainView extends GLSurfaceView { MainRenderer mRenderer; MainView ( Context context ) { super ( context ); mRenderer = new MainRenderer(this); setEGLContextClientVersion ( 2 ); setRenderer ( mRenderer ); setRenderMode ( GLSurfaceView.RENDERMODE_WHEN_DIRTY ); } public void surfaceCreated ( SurfaceHolder holder ) { super.surfaceCreated ( holder ); } public void surfaceDestroyed ( SurfaceHolder holder ) { super.surfaceDestroyed ( holder ); } public void surfaceChanged ( SurfaceHolder holder, int format, int w, int h ) { super.surfaceChanged ( holder, format, w, h ); } @Override public void onResume() { super.onResume(); mRenderer.onResume(); } @Override public void onPause() { mRenderer.onPause(); super.onPause(); } } // MainRenderer.java package ... import android.content.Context; import android.graphics.Point; import android.graphics.SurfaceTexture; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CameraManager; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.params.StreamConfigurationMap; import android.opengl.GLES11Ext; import android.opengl.GLES20; import android.opengl.GLSurfaceView; import android.os.Handler; import android.os.HandlerThread; import android.util.Log; import android.util.Size; import android.view.Surface; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import java.util.Arrays; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; public class MainRenderer implements GLSurfaceView.Renderer, SurfaceTexture.OnFrameAvailableListener { private final String vss_default = "" + "attribute vec2 vPosition;\n" + "attribute vec2 vTexCoord;\n" + "varying vec2 texCoord;\n" + "void main() {\n" + " texCoord = vTexCoord;\n" + " gl_Position = vec4 ( vPosition.x, vPosition.y, 0.0, 1.0 );\n" + "}"; private final String fss_default = "" + "#extension GL_OES_EGL_image_external : require\n" + "precision mediump float;\n" + "uniform samplerExternalOES sTexture;\n" + "varying vec2 texCoord;\n" + "void main() {\n" + " gl_FragColor = texture2D(sTexture,texCoord);\n" + "}"; private int[] hTex; private FloatBuffer pVertex; private FloatBuffer pTexCoord; private int hProgram; private SurfaceTexture mSTexture; private boolean mGLInit = false; private boolean mUpdateST = false; private MainView mView; private CameraDevice mCameraDevice; private CameraCaptureSession mCaptureSession; private CaptureRequest.Builder mPreviewRequestBuilder; private String mCameraID; private Size mPreviewSize = new Size ( 1920, 1080 ); private HandlerThread mBackgroundThread; private Handler mBackgroundHandler; private Semaphore mCameraOpenCloseLock = new Semaphore(1); MainRenderer ( MainView view ) { mView = view; float[] vtmp = { 1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f }; float[] ttmp = { 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f }; pVertex = ByteBuffer.allocateDirect(8 * 4).order(ByteOrder.nativeOrder()).asFloatBuffer(); pVertex.put ( vtmp ); pVertex.position(0); pTexCoord = ByteBuffer.allocateDirect(8*4).order(ByteOrder.nativeOrder()).asFloatBuffer(); pTexCoord.put ( ttmp ); pTexCoord.position(0); } public void onResume() { startBackgroundThread(); } public void onPause() { mGLInit = false; mUpdateST = false; closeCamera(); stopBackgroundThread(); } public void onSurfaceCreated ( GL10 unused, EGLConfig config ) { initTex(); mSTexture = new SurfaceTexture ( hTex[0] ); mSTexture.setOnFrameAvailableListener(this); GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); hProgram = loadShader ( vss_default, fss_default ); Point ss = new Point(); mView.getDisplay().getRealSize(ss); cacPreviewSize(ss.x, ss.y); openCamera(); mGLInit = true; } public void onDrawFrame ( GL10 unused ) { if ( !mGLInit ) return; GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); synchronized(this) { if ( mUpdateST ) { mSTexture.updateTexImage(); mUpdateST = false; } } GLES20.glUseProgram(hProgram); int ph = GLES20.glGetAttribLocation(hProgram, "vPosition"); int tch = GLES20.glGetAttribLocation ( hProgram, "vTexCoord" ); GLES20.glVertexAttribPointer(ph, 2, GLES20.GL_FLOAT, false, 4*2, pVertex); GLES20.glVertexAttribPointer(tch, 2, GLES20.GL_FLOAT, false, 4*2, pTexCoord ); GLES20.glEnableVertexAttribArray(ph); GLES20.glEnableVertexAttribArray(tch); GLES20.glActiveTexture(GLES20.GL_TEXTURE0); GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, hTex[0]); GLES20.glUniform1i(GLES20.glGetUniformLocation ( hProgram, "sTexture" ), 0); GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); GLES20.glFlush(); } public void onSurfaceChanged ( GL10 unused, int width, int height ) { GLES20.glViewport(0, 0, width, height); } private void initTex() { hTex = new int[1]; GLES20.glGenTextures ( 1, hTex, 0 ); GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, hTex[0]); GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST); } public synchronized void onFrameAvailable ( SurfaceTexture st ) { mUpdateST = true; mView.requestRender(); } private static int loadShader ( String vss, String fss ) { int vshader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER); GLES20.glShaderSource(vshader, vss); GLES20.glCompileShader(vshader); int[] compiled = new int[1]; GLES20.glGetShaderiv(vshader, GLES20.GL_COMPILE_STATUS, compiled, 0); if (compiled[0] == 0) { Log.e("Shader", "Could not compile vshader"); Log.v("Shader", "Could not compile vshader:"+GLES20.glGetShaderInfoLog(vshader)); GLES20.glDeleteShader(vshader); vshader = 0; } int fshader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER); GLES20.glShaderSource(fshader, fss); GLES20.glCompileShader(fshader); GLES20.glGetShaderiv(fshader, GLES20.GL_COMPILE_STATUS, compiled, 0); if (compiled[0] == 0) { Log.e("Shader", "Could not compile fshader"); Log.v("Shader", "Could not compile fshader:"+GLES20.glGetShaderInfoLog(fshader)); GLES20.glDeleteShader(fshader); fshader = 0; } int program = GLES20.glCreateProgram(); GLES20.glAttachShader(program, vshader); GLES20.glAttachShader(program, fshader); GLES20.glLinkProgram(program); return program; } void cacPreviewSize( final int width, final int height ) { CameraManager manager = (CameraManager)mView.getContext().getSystemService(Context.CAMERA_SERVICE); try { for (String cameraID : manager.getCameraIdList()) { CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraID); if (characteristics.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_FRONT) continue; mCameraID = cameraID; StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); for ( Size psize : map.getOutputSizes(SurfaceTexture.class)) { if ( width == psize.getWidth() && height == psize.getHeight() ) { mPreviewSize = psize; break; } } break; } } catch ( CameraAccessException e ) { Log.e("mr", "cacPreviewSize - Camera Access Exception"); } catch ( IllegalArgumentException e ) { Log.e("mr", "cacPreviewSize - Illegal Argument Exception"); } catch ( SecurityException e ) { Log.e("mr", "cacPreviewSize - Security Exception"); } } void openCamera() { CameraManager manager = (CameraManager)mView.getContext().getSystemService(Context.CAMERA_SERVICE); try { CameraCharacteristics characteristics = manager.getCameraCharacteristics(mCameraID); if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) { throw new RuntimeException("Time out waiting to lock camera opening."); } manager.openCamera(mCameraID,mStateCallback,mBackgroundHandler); } catch ( CameraAccessException e ) { Log.e("mr", "OpenCamera - Camera Access Exception"); } catch ( IllegalArgumentException e ) { Log.e("mr", "OpenCamera - Illegal Argument Exception"); } catch ( SecurityException e ) { Log.e("mr", "OpenCamera - Security Exception"); } catch ( InterruptedException e ) { Log.e("mr", "OpenCamera - Interrupted Exception"); } } private void closeCamera() { try { mCameraOpenCloseLock.acquire(); if (null != mCaptureSession) { mCaptureSession.close(); mCaptureSession = null; } if (null != mCameraDevice) { mCameraDevice.close(); mCameraDevice = null; } } catch (InterruptedException e) { throw new RuntimeException("Interrupted while trying to lock camera closing.", e); } finally { mCameraOpenCloseLock.release(); } } private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() { @Override public void onOpened(CameraDevice cameraDevice) { mCameraOpenCloseLock.release(); mCameraDevice = cameraDevice; createCameraPreviewSession(); } @Override public void onDisconnected(CameraDevice cameraDevice) { mCameraOpenCloseLock.release(); cameraDevice.close(); mCameraDevice = null; } @Override public void onError(CameraDevice cameraDevice, int error) { mCameraOpenCloseLock.release(); cameraDevice.close(); mCameraDevice = null; } }; private void createCameraPreviewSession() { try { mSTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight()); Surface surface = new Surface(mSTexture); mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); mPreviewRequestBuilder.addTarget(surface); mCameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() { @Override public void onConfigured(CameraCaptureSession cameraCaptureSession) { if (null == mCameraDevice) return; mCaptureSession = cameraCaptureSession; try { mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), null, mBackgroundHandler); } catch (CameraAccessException e) { Log.e("mr", "createCaptureSession"); } } @Override public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) { } }, null ); } catch (CameraAccessException e) { Log.e("mr", "createCameraPreviewSession"); } } private void startBackgroundThread() { mBackgroundThread = new HandlerThread("CameraBackground"); mBackgroundThread.start(); mBackgroundHandler = new Handler(mBackgroundThread.getLooper()); } private void stopBackgroundThread() { mBackgroundThread.quitSafely(); try { mBackgroundThread.join(); mBackgroundThread = null; mBackgroundHandler = null; } catch (InterruptedException e) { Log.e("mr", "stopBackgroundThread"); } } }