1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.camera; 18 19 import android.graphics.SurfaceTexture; 20 import android.os.ConditionVariable; 21 import android.os.Handler; 22 import android.os.HandlerThread; 23 import android.os.Looper; 24 import android.os.Message; 25 26 import javax.microedition.khronos.opengles.GL10; 27 28 public class MosaicPreviewRenderer { 29 30 @SuppressWarnings("unused") 31 private static final String TAG = "CAM_MosaicPreviewRenderer"; 32 33 private int mWidth; // width of the view in UI 34 private int mHeight; // height of the view in UI 35 36 private boolean mIsLandscape = true; 37 private final float[] mTransformMatrix = new float[16]; 38 39 private ConditionVariable mEglThreadBlockVar = new ConditionVariable(); 40 private HandlerThread mEglThread; 41 private MyHandler mHandler; 42 private SurfaceTextureRenderer mSTRenderer; 43 44 private SurfaceTexture mInputSurfaceTexture; 45 46 private class MyHandler extends Handler { 47 public static final int MSG_INIT_SYNC = 0; 48 public static final int MSG_SHOW_PREVIEW_FRAME_SYNC = 1; 49 public static final int MSG_SHOW_PREVIEW_FRAME = 2; 50 public static final int MSG_ALIGN_FRAME_SYNC = 3; 51 public static final int MSG_RELEASE = 4; 52 53 public MyHandler(Looper looper) { 54 super(looper); 55 } 56 57 @Override 58 public void handleMessage(Message msg) { 59 switch (msg.what) { 60 case MSG_INIT_SYNC: 61 doInit(); 62 mEglThreadBlockVar.open(); 63 break; 64 case MSG_SHOW_PREVIEW_FRAME_SYNC: 65 doShowPreviewFrame(); 66 mEglThreadBlockVar.open(); 67 break; 68 case MSG_SHOW_PREVIEW_FRAME: 69 doShowPreviewFrame(); 70 break; 71 case MSG_ALIGN_FRAME_SYNC: 72 doAlignFrame(); 73 mEglThreadBlockVar.open(); 74 break; 75 case MSG_RELEASE: 76 doRelease(); 77 mEglThreadBlockVar.open(); 78 break; 79 } 80 } 81 82 private void doAlignFrame() { 83 mInputSurfaceTexture.updateTexImage(); 84 mInputSurfaceTexture.getTransformMatrix(mTransformMatrix); 85 86 MosaicRenderer.setWarping(true); 87 // Call preprocess to render it to low-res and high-res RGB textures. 88 MosaicRenderer.preprocess(mTransformMatrix); 89 // Now, transfer the textures from GPU to CPU memory for processing 90 MosaicRenderer.transferGPUtoCPU(); 91 MosaicRenderer.updateMatrix(); 92 MosaicRenderer.step(); 93 } 94 95 private void doShowPreviewFrame() { 96 mInputSurfaceTexture.updateTexImage(); 97 mInputSurfaceTexture.getTransformMatrix(mTransformMatrix); 98 99 MosaicRenderer.setWarping(false); 100 // Call preprocess to render it to low-res and high-res RGB textures. 101 MosaicRenderer.preprocess(mTransformMatrix); 102 MosaicRenderer.updateMatrix(); 103 MosaicRenderer.step(); 104 } 105 106 private void doInit() { 107 mInputSurfaceTexture = new SurfaceTexture(MosaicRenderer.init()); 108 MosaicRenderer.reset(mWidth, mHeight, mIsLandscape); 109 } 110 111 private void doRelease() { 112 releaseSurfaceTexture(mInputSurfaceTexture); 113 mEglThread.quit(); 114 } 115 116 private void releaseSurfaceTexture(SurfaceTexture st) { 117 st.release(); 118 } 119 120 // Should be called from other thread. 121 public void sendMessageSync(int msg) { 122 mEglThreadBlockVar.close(); 123 sendEmptyMessage(msg); 124 mEglThreadBlockVar.block(); 125 } 126 } 127 128 /** 129 * Constructor. 130 * 131 * @param tex The {@link SurfaceTexture} for the final UI output. 132 * @param w The width of the UI view. 133 * @param h The height of the UI view. 134 * @param isLandscape The UI orientation. {@code true} if in landscape, 135 * false if in portrait. 136 */ 137 public MosaicPreviewRenderer(SurfaceTexture tex, int w, int h, boolean isLandscape) { 138 mIsLandscape = isLandscape; 139 140 mEglThread = new HandlerThread("PanoramaRealtimeRenderer"); 141 mEglThread.start(); 142 mHandler = new MyHandler(mEglThread.getLooper()); 143 mWidth = w; 144 mHeight = h; 145 146 SurfaceTextureRenderer.FrameDrawer dummy = new SurfaceTextureRenderer.FrameDrawer() { 147 @Override 148 public void onDrawFrame(GL10 gl) { 149 // nothing, we have our draw functions. 150 } 151 }; 152 mSTRenderer = new SurfaceTextureRenderer(tex, mHandler, dummy); 153 154 // We need to sync this because the generation of surface texture for input is 155 // done here and the client will continue with the assumption that the 156 // generation is completed. 157 mHandler.sendMessageSync(MyHandler.MSG_INIT_SYNC); 158 } 159 160 public void release() { 161 mSTRenderer.release(); 162 mHandler.sendMessageSync(MyHandler.MSG_RELEASE); 163 } 164 165 public void showPreviewFrameSync() { 166 mHandler.sendMessageSync(MyHandler.MSG_SHOW_PREVIEW_FRAME_SYNC); 167 mSTRenderer.draw(true); 168 } 169 170 public void showPreviewFrame() { 171 mHandler.sendEmptyMessage(MyHandler.MSG_SHOW_PREVIEW_FRAME); 172 mSTRenderer.draw(false); 173 } 174 175 public void alignFrameSync() { 176 mHandler.sendMessageSync(MyHandler.MSG_ALIGN_FRAME_SYNC); 177 mSTRenderer.draw(true); 178 } 179 180 public SurfaceTexture getInputSurfaceTexture() { 181 return mInputSurfaceTexture; 182 } 183 } 184