| 
						
						
							
								
							
						
						
					 | 
					 | 
					@ -3,7 +3,9 @@ package com.otaliastudios.cameraview; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					import android.content.Context; | 
					 | 
					 | 
					 | 
					import android.content.Context; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					import android.graphics.SurfaceTexture; | 
					 | 
					 | 
					 | 
					import android.graphics.SurfaceTexture; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					import android.opengl.GLSurfaceView; | 
					 | 
					 | 
					 | 
					import android.opengl.GLSurfaceView; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					import android.opengl.Matrix; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					import android.support.annotation.NonNull; | 
					 | 
					 | 
					 | 
					import android.support.annotation.NonNull; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					import android.util.Log; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					import android.view.LayoutInflater; | 
					 | 
					 | 
					 | 
					import android.view.LayoutInflater; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					import android.view.SurfaceHolder; | 
					 | 
					 | 
					 | 
					import android.view.SurfaceHolder; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					import android.view.View; | 
					 | 
					 | 
					 | 
					import android.view.View; | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -12,13 +14,47 @@ import android.view.ViewGroup; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					import javax.microedition.khronos.egl.EGLConfig; | 
					 | 
					 | 
					 | 
					import javax.microedition.khronos.egl.EGLConfig; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					import javax.microedition.khronos.opengles.GL10; | 
					 | 
					 | 
					 | 
					import javax.microedition.khronos.opengles.GL10; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					/** | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 * - The android camera will stream image to the given {@link SurfaceTexture}. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 * | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 * - in the SurfaceTexture constructor we pass the GL texture handle that we have created. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 * | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 * - The SurfaceTexture is linked to the Camera1 object. It will pass down buffers of data with | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 *   a specified size (that is, the Camera1 preview size). | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 * | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 * - When SurfaceTexture.updateTexImage() is called, it will take the latest image from the camera stream | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 *   and update it into the GL texture that was passed. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 * | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 * - Now we have a GL texture referencing data. It must be drawn. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 *  [Note: it must be drawn using a transformation matrix taken from SurfaceTexture] | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 * | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 * - The easy way to render an OpenGL texture is using the {@link GLSurfaceView} class. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 *   It manages the gl context, hosts a surface and runs a separated rendering thread that will perform | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 *   the rendering. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 * | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 * - As per docs, we ask the GLSurfaceView to delegate rendering to us, using | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 *   {@link GLSurfaceView#setRenderer(GLSurfaceView.Renderer)}. We request a render on the SurfaceView | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 *   anytime the SurfaceTexture notifies that it has new data available (see OnFrameAvailableListener below). | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 * | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 * - Everything is linked: | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 *   - The SurfaceTexture has buffers of data of mInputStreamSize | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 *   - The SurfaceView hosts a view (and surface) of size mOutputSurfaceSize | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 *   - We have a GL rich texture to be drawn (in the given method & thread). | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 * | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 * TODO | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 * CROPPING: Managed to do this using Matrix transformation. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 * UPDATING: Still bugged: if you change the surface size on the go, the stream is not updated. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 *           I guess we should create a new texture... | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 * TAKING PICTURES: Sometime the snapshot takes ages... | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 * TAKING VIDEOS: Still have not tried... | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 */ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					class GLCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture> implements GLSurfaceView.Renderer { | 
					 | 
					 | 
					 | 
					class GLCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture> implements GLSurfaceView.Renderer { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    private boolean mDispatched; | 
					 | 
					 | 
					 | 
					    private boolean mDispatched; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    private final float[] mTransformMatrix = new float[16]; | 
					 | 
					 | 
					 | 
					    private final float[] mTransformMatrix = new float[16]; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    private int mTextureId = -1; | 
					 | 
					 | 
					 | 
					    private int mOutputTextureId = -1; | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    private SurfaceTexture mSurfaceTexture; | 
					 | 
					 | 
					 | 
					    private SurfaceTexture mInputSurfaceTexture; | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    private GLViewport mViewport; | 
					 | 
					 | 
					 | 
					    private GLViewport mOutputViewport; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    GLCameraPreview(Context context, ViewGroup parent, SurfaceCallback callback) { | 
					 | 
					 | 
					 | 
					    GLCameraPreview(Context context, ViewGroup parent, SurfaceCallback callback) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        super(context, parent, callback); | 
					 | 
					 | 
					 | 
					        super(context, parent, callback); | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -33,9 +69,12 @@ class GLCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture> imple | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        glView.setEGLContextClientVersion(2); | 
					 | 
					 | 
					 | 
					        glView.setEGLContextClientVersion(2); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        glView.setRenderer(this); | 
					 | 
					 | 
					 | 
					        glView.setRenderer(this); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        glView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); | 
					 | 
					 | 
					 | 
					        glView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        // glView.getHolder().setFixedSize(600, 300);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        glView.getHolder().addCallback(new SurfaceHolder.Callback() { | 
					 | 
					 | 
					 | 
					        glView.getHolder().addCallback(new SurfaceHolder.Callback() { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            public void surfaceCreated(SurfaceHolder holder) {} | 
					 | 
					 | 
					 | 
					            public void surfaceCreated(SurfaceHolder holder) {} | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {} | 
					 | 
					 | 
					 | 
					            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                Log.e("GlCameraPreview", "width: " + width + ", height: " + height); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            @Override | 
					 | 
					 | 
					 | 
					            @Override | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            public void surfaceDestroyed(SurfaceHolder holder) { | 
					 | 
					 | 
					 | 
					            public void surfaceDestroyed(SurfaceHolder holder) { | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -60,22 +99,26 @@ class GLCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture> imple | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    @Override | 
					 | 
					 | 
					 | 
					    @Override | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    void onDestroy() { | 
					 | 
					 | 
					 | 
					    void onDestroy() { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        super.onDestroy(); | 
					 | 
					 | 
					 | 
					        super.onDestroy(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        if (mSurfaceTexture != null) { | 
					 | 
					 | 
					 | 
					        if (mInputSurfaceTexture != null) { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            mSurfaceTexture.release(); | 
					 | 
					 | 
					 | 
					            mInputSurfaceTexture.release(); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            mSurfaceTexture = null; | 
					 | 
					 | 
					 | 
					            mInputSurfaceTexture = null; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        } | 
					 | 
					 | 
					 | 
					        } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        if (mViewport != null) { | 
					 | 
					 | 
					 | 
					        if (mOutputViewport != null) { | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            mViewport.release(); | 
					 | 
					 | 
					 | 
					            mOutputViewport.release(); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            mViewport = null; | 
					 | 
					 | 
					 | 
					            mOutputViewport = null; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        } | 
					 | 
					 | 
					 | 
					        } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    } | 
					 | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    // Renderer thread
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    @Override | 
					 | 
					 | 
					 | 
					    @Override | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    public void onSurfaceCreated(GL10 gl, EGLConfig config) { | 
					 | 
					 | 
					 | 
					    public void onSurfaceCreated(GL10 gl, EGLConfig config) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        mViewport = new GLViewport(); | 
					 | 
					 | 
					 | 
					        mOutputViewport = new GLViewport(); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        mTextureId = mViewport.createTexture(); | 
					 | 
					 | 
					 | 
					        mOutputTextureId = mOutputViewport.createTexture(); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        mSurfaceTexture = new SurfaceTexture(mTextureId); | 
					 | 
					 | 
					 | 
					        mInputSurfaceTexture = new SurfaceTexture(mOutputTextureId); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        mSurfaceTexture.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() { | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        // Since we are using GLSurfaceView.RENDERMODE_WHEN_DIRTY, we must notify the SurfaceView
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        // of dirtyness, so that it draws again. This is how it's done.
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        mInputSurfaceTexture.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            @Override | 
					 | 
					 | 
					 | 
					            @Override | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            public void onFrameAvailable(SurfaceTexture surfaceTexture) { | 
					 | 
					 | 
					 | 
					            public void onFrameAvailable(SurfaceTexture surfaceTexture) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					                // requestRender is thread-safe.
 | 
					 | 
					 | 
					 | 
					                // requestRender is thread-safe.
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -84,6 +127,7 @@ class GLCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture> imple | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        }); | 
					 | 
					 | 
					 | 
					        }); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    } | 
					 | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    // Renderer thread
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    @Override | 
					 | 
					 | 
					 | 
					    @Override | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    public void onSurfaceChanged(GL10 gl, int width, int height) { | 
					 | 
					 | 
					 | 
					    public void onSurfaceChanged(GL10 gl, int width, int height) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        if (!mDispatched) { | 
					 | 
					 | 
					 | 
					        if (!mDispatched) { | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -99,15 +143,16 @@ class GLCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture> imple | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    public void onDrawFrame(GL10 gl) { | 
					 | 
					 | 
					 | 
					    public void onDrawFrame(GL10 gl) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        // Latch the latest frame.  If there isn't anything new,
 | 
					 | 
					 | 
					 | 
					        // Latch the latest frame.  If there isn't anything new,
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        // we'll just re-use whatever was there before.
 | 
					 | 
					 | 
					 | 
					        // we'll just re-use whatever was there before.
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        mSurfaceTexture.updateTexImage(); | 
					 | 
					 | 
					 | 
					        mInputSurfaceTexture.updateTexImage(); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        if (mDesiredWidth <= 0 || mDesiredHeight <= 0) { | 
					 | 
					 | 
					 | 
					        if (mInputStreamWidth <= 0 || mInputStreamHeight <= 0) { | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            // Skip drawing. Camera was not opened.
 | 
					 | 
					 | 
					 | 
					            // Skip drawing. Camera was not opened.
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					            return; | 
					 | 
					 | 
					 | 
					            return; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        } | 
					 | 
					 | 
					 | 
					        } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        // Draw the video frame.
 | 
					 | 
					 | 
					 | 
					        // Draw the video frame.
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        mSurfaceTexture.getTransformMatrix(mTransformMatrix); | 
					 | 
					 | 
					 | 
					        mInputSurfaceTexture.getTransformMatrix(mTransformMatrix); | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        mViewport.drawFrame(mTextureId, mTransformMatrix); | 
					 | 
					 | 
					 | 
					        Matrix.scaleM(mTransformMatrix, 0, mScaleX, mScaleY, 1); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        mOutputViewport.drawFrame(mOutputTextureId, mTransformMatrix); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    } | 
					 | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    @Override | 
					 | 
					 | 
					 | 
					    @Override | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -117,7 +162,7 @@ class GLCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture> imple | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    @Override | 
					 | 
					 | 
					 | 
					    @Override | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    SurfaceTexture getOutput() { | 
					 | 
					 | 
					 | 
					    SurfaceTexture getOutput() { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        return mSurfaceTexture; | 
					 | 
					 | 
					 | 
					        return mInputSurfaceTexture; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    } | 
					 | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -126,9 +171,39 @@ class GLCameraPreview extends CameraPreview<GLSurfaceView, SurfaceTexture> imple | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        return true; | 
					 | 
					 | 
					 | 
					        return true; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    } | 
					 | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    private float mScaleX = 1F; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    private float mScaleY = 1F; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					    /** | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					     * To crop in GL, we could actually use view.setScaleX and setScaleY, but only from Android N onward. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					     * See documentation: https://developer.android.com/reference/android/view/SurfaceView
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					     * | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					     *   Note: Starting in platform version Build.VERSION_CODES.N, SurfaceView's window position is updated | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					     *   synchronously with other View rendering. This means that translating and scaling a SurfaceView on | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					     *   screen will not cause rendering artifacts. Such artifacts may occur on previous versions of the | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					     *   platform when its window is positioned asynchronously. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					     * | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					     * But to support older platforms, this seem to work - computing scale values and requesting a new frame, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					     * then drawing it with a scaled transformation matrix. See {@link #onDrawFrame(GL10)}. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					     */ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    @Override | 
					 | 
					 | 
					 | 
					    @Override | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    protected void crop() { | 
					 | 
					 | 
					 | 
					    protected void crop() { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        mCropTask.start(); | 
					 | 
					 | 
					 | 
					        mCropTask.start(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        if (mInputStreamWidth > 0 && mInputStreamHeight > 0 && mOutputSurfaceWidth > 0 && mOutputSurfaceHeight > 0) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            float scaleX = 1f, scaleY = 1f; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            AspectRatio current = AspectRatio.of(mOutputSurfaceWidth, mOutputSurfaceHeight); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            AspectRatio target = AspectRatio.of(mInputStreamWidth, mInputStreamHeight); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            if (current.toFloat() >= target.toFloat()) { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                // We are too short. Must increase height.
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                scaleY = current.toFloat() / target.toFloat(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            } else { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                // We must increase width.
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					                scaleX = target.toFloat() / current.toFloat(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            mScaleX = 1F / scaleX; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            mScaleY = 1F / scaleY; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					            getView().requestRender(); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					        } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					        mCropTask.end(null); | 
					 | 
					 | 
					 | 
					        mCropTask.end(null); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    } | 
					 | 
					 | 
					 | 
					    } | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					} | 
					 | 
					 | 
					 | 
					} | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
					 | 
					 | 
					
  |