Home | History | Annotate | Download | only in camera
      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