1227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks/* 2227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Copyright (C) 2012 The Android Open Source Project 3227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 4227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Licensed under the Apache License, Version 2.0 (the "License"); 5227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * you may not use this file except in compliance with the License. 6227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * You may obtain a copy of the License at 7227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 8227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * http://www.apache.org/licenses/LICENSE-2.0 9227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 10227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Unless required by applicable law or agreed to in writing, software 11227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * distributed under the License is distributed on an "AS IS" BASIS, 12227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * See the License for the specific language governing permissions and 14227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * limitations under the License. 15227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 16227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 17227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickspackage androidx.media.filterfw; 18227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 19227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.annotation.TargetApi; 20227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.graphics.SurfaceTexture; 21227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.hardware.Camera; 22227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.hardware.Camera.CameraInfo; 23227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.hardware.Camera.PreviewCallback; 24227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.media.CamcorderProfile; 25227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.media.MediaRecorder; 26227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.opengl.GLES20; 27227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.os.Build.VERSION; 28227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.util.Log; 29227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.view.Display; 30227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.view.Surface; 31227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport android.view.SurfaceView; 32227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 33227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.io.IOException; 34227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.nio.ByteBuffer; 35227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.util.HashMap; 36227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.util.HashSet; 37227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.util.List; 38227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.util.Set; 39227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.util.Vector; 40227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.util.concurrent.LinkedBlockingQueue; 41227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.util.concurrent.TimeUnit; 42227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.util.concurrent.atomic.AtomicInteger; 43227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.util.concurrent.locks.Condition; 44227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport java.util.concurrent.locks.ReentrantLock; 45227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 46227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksimport javax.microedition.khronos.egl.EGLContext; 47227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 48227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks/** 49227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * The CameraStreamer streams Frames from a camera to connected clients. 50227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 51227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * There is one centralized CameraStreamer object per MffContext, and only one stream can be 52227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * active at any time. The CameraStreamer acts as a Camera "server" that streams frames to any 53227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * number of connected clients. Typically, these are CameraSource filters that are part of a 54227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * graph, but other clients can be written as well. 55227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 56227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendrickspublic class CameraStreamer { 57227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 58227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** Camera Facing: Don't Care: Picks any available camera. */ 59227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public static final int FACING_DONTCARE = 0; 60227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** Camera Facing: Front: Use the front facing camera. */ 61227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public static final int FACING_FRONT = 1; 62227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** Camera Facing: Back: Use the rear facing camera. */ 63227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public static final int FACING_BACK = 2; 64227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 65227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** How long the streamer should wait to acquire the camera before giving up. */ 66227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public static long MAX_CAMERA_WAIT_TIME = 5; 67227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 68227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 69227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * The global camera lock, that is closed when the camera is acquired by any CameraStreamer, 70227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * and opened when a streamer is done using the camera. 71227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 72227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks static ReentrantLock mCameraLock = new ReentrantLock(); 73227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 74227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** The Camera thread that grabs frames from the camera */ 75227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private CameraRunnable mCameraRunner = null; 76227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 77227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private abstract class CamFrameHandler { 78227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected int mCameraWidth; 79227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected int mCameraHeight; 80227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected int mOutWidth; 81227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected int mOutHeight; 82227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected CameraRunnable mRunner; 83227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 84227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** Map of GLSL shaders (one for each target context) */ 85227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected HashMap<EGLContext, ImageShader> mTargetShaders 86227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks = new HashMap<EGLContext, ImageShader>(); 87227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 88227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** Map of target textures (one for each target context) */ 89227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected HashMap<EGLContext, TextureSource> mTargetTextures 90227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks = new HashMap<EGLContext, TextureSource>(); 91227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 92227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** Map of set of clients (one for each target context) */ 93227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected HashMap<EGLContext, Set<FrameClient>> mContextClients 94227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks = new HashMap<EGLContext, Set<FrameClient>>(); 95227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 96227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** List of clients that are consuming camera frames. */ 97227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected Vector<FrameClient> mClients = new Vector<FrameClient>(); 98227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 99227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void initWithRunner(CameraRunnable camRunner) { 100227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRunner = camRunner; 101227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 102227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 103227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void setCameraSize(int width, int height) { 104227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraWidth = width; 105227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraHeight = height; 106227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 107227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 108227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void registerClient(FrameClient client) { 109227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks EGLContext context = RenderTarget.currentContext(); 110227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Set<FrameClient> clientTargets = clientsForContext(context); 111227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks clientTargets.add(client); 112227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mClients.add(client); 113227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks onRegisterClient(client, context); 114227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 115227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 116227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void unregisterClient(FrameClient client) { 117227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks EGLContext context = RenderTarget.currentContext(); 118227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Set<FrameClient> clientTargets = clientsForContext(context); 119227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks clientTargets.remove(client); 120227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (clientTargets.isEmpty()) { 121227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks onCleanupContext(context); 122227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 123227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mClients.remove(client); 124227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 125227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 126227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public abstract void setupServerFrame(); 127227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public abstract void updateServerFrame(); 128227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public abstract void grabFrame(FrameImage2D targetFrame); 129227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public abstract void release(); 130227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 131227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void onUpdateCameraOrientation(int orientation) { 132227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (orientation % 180 != 0) { 133227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mOutWidth = mCameraHeight; 134227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mOutHeight = mCameraWidth; 135227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } else { 136227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mOutWidth = mCameraWidth; 137227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mOutHeight = mCameraHeight; 138227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 139227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 140227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 141227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected Set<FrameClient> clientsForContext(EGLContext context) { 142227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Set<FrameClient> clients = mContextClients.get(context); 143227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (clients == null) { 144227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks clients = new HashSet<FrameClient>(); 145227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mContextClients.put(context, clients); 146227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 147227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return clients; 148227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 149227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 150227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected void onRegisterClient(FrameClient client, EGLContext context) { 151227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 152227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 153227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected void onCleanupContext(EGLContext context) { 154227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks TextureSource texture = mTargetTextures.get(context); 155227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks ImageShader shader = mTargetShaders.get(context); 156227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (texture != null) { 157227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks texture.release(); 158227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mTargetTextures.remove(context); 159227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 160227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (shader != null) { 161227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mTargetShaders.remove(context); 162227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 163227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 164227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 165227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected TextureSource textureForContext(EGLContext context) { 166227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks TextureSource texture = mTargetTextures.get(context); 167227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (texture == null) { 168227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks texture = createClientTexture(); 169227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mTargetTextures.put(context, texture); 170227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 171227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return texture; 172227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 173227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 174227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected ImageShader shaderForContext(EGLContext context) { 175227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks ImageShader shader = mTargetShaders.get(context); 176227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (shader == null) { 177227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks shader = createClientShader(); 178227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mTargetShaders.put(context, shader); 179227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 180227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return shader; 181227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 182227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 183227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected ImageShader createClientShader() { 184227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return null; 185227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 186227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 187227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected TextureSource createClientTexture() { 188227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return null; 189227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 190227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 191227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public boolean isFrontMirrored() { 192227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return true; 193227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 194227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 195227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 196227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Jellybean (and later) back-end 197227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @TargetApi(16) 198227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private class CamFrameHandlerJB extends CamFrameHandlerICS { 199227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 200227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 201227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void setupServerFrame() { 202227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks setupPreviewTexture(mRunner.mCamera); 203227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 204227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 205227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 206227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public synchronized void updateServerFrame() { 207227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks updateSurfaceTexture(); 208227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks informClients(); 209227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 210227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 211227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 212227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public synchronized void grabFrame(FrameImage2D targetFrame) { 213227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks TextureSource targetTex = TextureSource.newExternalTexture(); 214227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks ImageShader copyShader = shaderForContext(RenderTarget.currentContext()); 215227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (targetTex == null || copyShader == null) { 216227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new RuntimeException("Attempting to grab camera frame from unknown " 217227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks + "thread: " + Thread.currentThread() + "!"); 218227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 219227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mPreviewSurfaceTexture.attachToGLContext(targetTex.getTextureId()); 220227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks updateTransform(copyShader); 221227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks updateShaderTargetRect(copyShader); 222227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks targetFrame.resize(new int[] { mOutWidth, mOutHeight }); 223227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks copyShader.process(targetTex, 224227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks targetFrame.lockRenderTarget(), 225227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mOutWidth, 226227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mOutHeight); 227227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks targetFrame.setTimestamp(mPreviewSurfaceTexture.getTimestamp()); 228227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks targetFrame.unlock(); 229227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mPreviewSurfaceTexture.detachFromGLContext(); 230227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks targetTex.release(); 231227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 232227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 233227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 234227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected void updateShaderTargetRect(ImageShader shader) { 235227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if ((mRunner.mActualFacing == FACING_FRONT) && mRunner.mFlipFront) { 236227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks shader.setTargetRect(1f, 1f, -1f, -1f); 237227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } else { 238227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks shader.setTargetRect(0f, 1f, 1f, -1f); 239227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 240227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 241227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 242227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 243227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected void setupPreviewTexture(Camera camera) { 244227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks super.setupPreviewTexture(camera); 245227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mPreviewSurfaceTexture.detachFromGLContext(); 246227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 247227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 248227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected void updateSurfaceTexture() { 249227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mPreviewSurfaceTexture.attachToGLContext(mPreviewTexture.getTextureId()); 250227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mPreviewSurfaceTexture.updateTexImage(); 251227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mPreviewSurfaceTexture.detachFromGLContext(); 252227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 253227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 254227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected void informClients() { 255227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks synchronized (mClients) { 256227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks for (FrameClient client : mClients) { 257227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks client.onCameraFrameAvailable(); 258227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 259227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 260227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 261227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 262227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 263227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // ICS (and later) back-end 264227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @TargetApi(15) 265227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private class CamFrameHandlerICS extends CamFrameHandler { 266227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 267227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected static final String mCopyShaderSource = 268227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "#extension GL_OES_EGL_image_external : require\n" + 269227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "precision mediump float;\n" + 270227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "uniform samplerExternalOES tex_sampler_0;\n" + 271227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "varying vec2 v_texcoord;\n" + 272227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "void main() {\n" + 273227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks " gl_FragColor = texture2D(tex_sampler_0, v_texcoord);\n" + 274227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "}\n"; 275227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 276227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** The camera transform matrix */ 277227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private float[] mCameraTransform = new float[16]; 278227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 279227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** The texture the camera streams to */ 280227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected TextureSource mPreviewTexture = null; 281227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected SurfaceTexture mPreviewSurfaceTexture = null; 282227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 283227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** Map of target surface textures (one for each target context) */ 284227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected HashMap<EGLContext, SurfaceTexture> mTargetSurfaceTextures 285227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks = new HashMap<EGLContext, SurfaceTexture>(); 286227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 287227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** Map of RenderTargets for client SurfaceTextures */ 288227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected HashMap<SurfaceTexture, RenderTarget> mClientRenderTargets 289227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks = new HashMap<SurfaceTexture, RenderTarget>(); 290227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 291227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** Server side copy shader */ 292227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected ImageShader mCopyShader = null; 293227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 294227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 295227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public synchronized void setupServerFrame() { 296227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks setupPreviewTexture(mRunner.mCamera); 297227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 298227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 299227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 300227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public synchronized void updateServerFrame() { 301227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mPreviewSurfaceTexture.updateTexImage(); 302227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks distributeFrames(); 303227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 304227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 305227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 306227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void onUpdateCameraOrientation(int orientation) { 307227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks super.onUpdateCameraOrientation(orientation); 308227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRunner.mCamera.setDisplayOrientation(orientation); 309227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks updateSurfaceTextureSizes(); 310227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 311227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 312227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 313227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public synchronized void onRegisterClient(FrameClient client, EGLContext context) { 314227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks final Set<FrameClient> clientTargets = clientsForContext(context); 315227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 316227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Make sure we have texture, shader, and surfacetexture setup for this context. 317227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks TextureSource clientTex = textureForContext(context); 318227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks ImageShader copyShader = shaderForContext(context); 319227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks SurfaceTexture surfTex = surfaceTextureForContext(context); 320227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 321227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Listen to client-side surface texture updates 322227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks surfTex.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() { 323227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 324227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void onFrameAvailable(SurfaceTexture surfaceTexture) { 325227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks for (FrameClient clientTarget : clientTargets) { 326227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks clientTarget.onCameraFrameAvailable(); 327227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 328227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 329227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks }); 330227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 331227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 332227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 333227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public synchronized void grabFrame(FrameImage2D targetFrame) { 334227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Get the GL objects for the receiver's context 335227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks EGLContext clientContext = RenderTarget.currentContext(); 336227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks TextureSource clientTex = textureForContext(clientContext); 337227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks ImageShader copyShader = shaderForContext(clientContext); 338227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks SurfaceTexture surfTex = surfaceTextureForContext(clientContext); 339227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (clientTex == null || copyShader == null || surfTex == null) { 340227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new RuntimeException("Attempting to grab camera frame from unknown " 341227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks + "thread: " + Thread.currentThread() + "!"); 342227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 343227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 344227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Copy from client ST to client tex 345227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks surfTex.updateTexImage(); 346227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks targetFrame.resize(new int[] { mOutWidth, mOutHeight }); 347227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks copyShader.process(clientTex, 348227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks targetFrame.lockRenderTarget(), 349227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mOutWidth, 350227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mOutHeight); 351227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 352227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks targetFrame.setTimestamp(mPreviewSurfaceTexture.getTimestamp()); 353227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks targetFrame.unlock(); 354227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 355227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 356227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 357227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public synchronized void release() { 358227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mPreviewTexture != null) { 359227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mPreviewTexture.release(); 360227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mPreviewTexture = null; 361227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 362227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mPreviewSurfaceTexture != null) { 363227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mPreviewSurfaceTexture.release(); 364227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mPreviewSurfaceTexture = null; 365227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 366227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 367227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 368227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 369227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected ImageShader createClientShader() { 370227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return new ImageShader(mCopyShaderSource); 371227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 372227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 373227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 374227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected TextureSource createClientTexture() { 375227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return TextureSource.newExternalTexture(); 376227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 377227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 378227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected void distributeFrames() { 379227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks updateTransform(getCopyShader()); 380227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks updateShaderTargetRect(getCopyShader()); 381227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 382227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks for (SurfaceTexture clientTexture : mTargetSurfaceTextures.values()) { 383227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks RenderTarget clientTarget = renderTargetFor(clientTexture); 384227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks clientTarget.focus(); 385227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks getCopyShader().process(mPreviewTexture, 386227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks clientTarget, 387227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mOutWidth, 388227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mOutHeight); 389227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks GLToolbox.checkGlError("distribute frames"); 390227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks clientTarget.swapBuffers(); 391227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 392227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 393227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 394227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected RenderTarget renderTargetFor(SurfaceTexture surfaceTex) { 395227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks RenderTarget target = mClientRenderTargets.get(surfaceTex); 396227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (target == null) { 397227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks target = RenderTarget.currentTarget().forSurfaceTexture(surfaceTex); 398227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mClientRenderTargets.put(surfaceTex, target); 399227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 400227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return target; 401227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 402227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 403227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected void setupPreviewTexture(Camera camera) { 404227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mPreviewTexture == null) { 405227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mPreviewTexture = TextureSource.newExternalTexture(); 406227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 407227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mPreviewSurfaceTexture == null) { 408227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mPreviewSurfaceTexture = new SurfaceTexture(mPreviewTexture.getTextureId()); 409227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks try { 410227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks camera.setPreviewTexture(mPreviewSurfaceTexture); 411227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } catch (IOException e) { 412227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new RuntimeException("Could not bind camera surface texture: " + 413227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks e.getMessage() + "!"); 414227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 415227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mPreviewSurfaceTexture.setOnFrameAvailableListener(mOnCameraFrameListener); 416227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 417227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 418227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 419227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected ImageShader getCopyShader() { 420227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mCopyShader == null) { 421227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCopyShader = new ImageShader(mCopyShaderSource); 422227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 423227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mCopyShader; 424227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 425227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 426227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected SurfaceTexture surfaceTextureForContext(EGLContext context) { 427227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks SurfaceTexture surfTex = mTargetSurfaceTextures.get(context); 428227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (surfTex == null) { 429227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks TextureSource texture = textureForContext(context); 430227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (texture != null) { 431227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks surfTex = new SurfaceTexture(texture.getTextureId()); 432227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks surfTex.setDefaultBufferSize(mOutWidth, mOutHeight); 433227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mTargetSurfaceTextures.put(context, surfTex); 434227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 435227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 436227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return surfTex; 437227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 438227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 439227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected void updateShaderTargetRect(ImageShader shader) { 440227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if ((mRunner.mActualFacing == FACING_FRONT) && mRunner.mFlipFront) { 441227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks shader.setTargetRect(1f, 0f, -1f, 1f); 442227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } else { 443227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks shader.setTargetRect(0f, 0f, 1f, 1f); 444227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 445227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 446227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 447227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected synchronized void updateSurfaceTextureSizes() { 448227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks for (SurfaceTexture clientTexture : mTargetSurfaceTextures.values()) { 449227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks clientTexture.setDefaultBufferSize(mOutWidth, mOutHeight); 450227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 451227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 452227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 453227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected void updateTransform(ImageShader shader) { 454227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mPreviewSurfaceTexture.getTransformMatrix(mCameraTransform); 455227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks shader.setSourceTransform(mCameraTransform); 456227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 457227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 458227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 459227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected void onCleanupContext(EGLContext context) { 460227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks super.onCleanupContext(context); 461227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks SurfaceTexture surfaceTex = mTargetSurfaceTextures.get(context); 462227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (surfaceTex != null) { 463227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks surfaceTex.release(); 464227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mTargetSurfaceTextures.remove(context); 465227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 466227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 467227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 468227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected SurfaceTexture.OnFrameAvailableListener mOnCameraFrameListener = 469227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks new SurfaceTexture.OnFrameAvailableListener() { 470227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 471227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void onFrameAvailable(SurfaceTexture surfaceTexture) { 472227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRunner.signalNewFrame(); 473227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 474227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks }; 475227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 476227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 477227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Gingerbread (and later) back-end 478227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @TargetApi(9) 479227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private final class CamFrameHandlerGB extends CamFrameHandler { 480227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 481227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private SurfaceView mSurfaceView; 482227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private byte[] mFrameBufferFront; 483227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private byte[] mFrameBufferBack; 484227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private boolean mWriteToBack = true; 485227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private float[] mTargetCoords = new float[] { 0f, 0f, 1f, 0f, 0f, 1f, 1f, 1f }; 486227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks final Object mBufferLock = new Object(); 487227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 488227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private String mNV21ToRGBAFragment = 489227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "precision mediump float;\n" + 490227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "\n" + 491227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "uniform sampler2D tex_sampler_0;\n" + 492227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "varying vec2 v_y_texcoord;\n" + 493227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "varying vec2 v_vu_texcoord;\n" + 494227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "varying vec2 v_pixcoord;\n" + 495227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "\n" + 496227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "vec3 select(vec4 yyyy, vec4 vuvu, int s) {\n" + 497227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks " if (s == 0) {\n" + 498227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks " return vec3(yyyy.r, vuvu.g, vuvu.r);\n" + 499227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks " } else if (s == 1) {\n" + 500227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks " return vec3(yyyy.g, vuvu.g, vuvu.r);\n" + 501227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks " } else if (s == 2) {\n" + 502227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks " return vec3(yyyy.b, vuvu.a, vuvu.b);\n" + 503227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks " } else {\n" + 504227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks " return vec3(yyyy.a, vuvu.a, vuvu.b);\n" + 505227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks " }\n" + 506227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "}\n" + 507227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "\n" + 508227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "vec3 yuv2rgb(vec3 yuv) {\n" + 509227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks " mat4 conversion = mat4(1.0, 0.0, 1.402, -0.701,\n" + 510227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks " 1.0, -0.344, -0.714, 0.529,\n" + 511227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks " 1.0, 1.772, 0.0, -0.886,\n" + 512227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks " 0, 0, 0, 0);" + 513227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks " return (vec4(yuv, 1.0) * conversion).rgb;\n" + 514227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "}\n" + 515227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "\n" + 516227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "void main() {\n" + 517227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks " vec4 yyyy = texture2D(tex_sampler_0, v_y_texcoord);\n" + 518227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks " vec4 vuvu = texture2D(tex_sampler_0, v_vu_texcoord);\n" + 519227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks " int s = int(mod(floor(v_pixcoord.x), 4.0));\n" + 520227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks " vec3 yuv = select(yyyy, vuvu, s);\n" + 521227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks " vec3 rgb = yuv2rgb(yuv);\n" + 522227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks " gl_FragColor = vec4(rgb, 1.0);\n" + 523227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "}"; 524227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 525227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private String mNV21ToRGBAVertex = 526227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "attribute vec4 a_position;\n" + 527227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "attribute vec2 a_y_texcoord;\n" + 528227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "attribute vec2 a_vu_texcoord;\n" + 529227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "attribute vec2 a_pixcoord;\n" + 530227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "varying vec2 v_y_texcoord;\n" + 531227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "varying vec2 v_vu_texcoord;\n" + 532227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "varying vec2 v_pixcoord;\n" + 533227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "void main() {\n" + 534227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks " gl_Position = a_position;\n" + 535227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks " v_y_texcoord = a_y_texcoord;\n" + 536227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks " v_vu_texcoord = a_vu_texcoord;\n" + 537227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks " v_pixcoord = a_pixcoord;\n" + 538227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "}\n"; 539227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 540227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private byte[] readBuffer() { 541227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks synchronized (mBufferLock) { 542227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mWriteToBack ? mFrameBufferFront : mFrameBufferBack; 543227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 544227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 545227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 546227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private byte[] writeBuffer() { 547227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks synchronized (mBufferLock) { 548227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mWriteToBack ? mFrameBufferBack : mFrameBufferFront; 549227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 550227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 551227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 552227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private synchronized void swapBuffers() { 553227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks synchronized (mBufferLock) { 554227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mWriteToBack = !mWriteToBack; 555227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 556227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 557227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 558227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private PreviewCallback mPreviewCallback = new PreviewCallback() { 559227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 560227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 561227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void onPreviewFrame(byte[] data, Camera camera) { 562227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks swapBuffers(); 563227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks camera.addCallbackBuffer(writeBuffer()); 564227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRunner.signalNewFrame(); 565227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 566227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 567227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks }; 568227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 569227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 570227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void setupServerFrame() { 571227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks checkCameraDimensions(); 572227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Camera camera = mRunner.mCamera; 573227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int bufferSize = mCameraWidth * (mCameraHeight + mCameraHeight/2); 574227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mFrameBufferFront = new byte[bufferSize]; 575227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mFrameBufferBack = new byte[bufferSize]; 576227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks camera.addCallbackBuffer(writeBuffer()); 577227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks camera.setPreviewCallbackWithBuffer(mPreviewCallback); 578227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks SurfaceView previewDisplay = getPreviewDisplay(); 579227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (previewDisplay != null) { 580227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks try { 581227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks camera.setPreviewDisplay(previewDisplay.getHolder()); 582227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } catch (IOException e) { 583227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new RuntimeException("Could not start camera with given preview " + 584227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks "display!"); 585227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 586227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 587227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 588227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 589227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private void checkCameraDimensions() { 590227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mCameraWidth % 4 != 0) { 591227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new RuntimeException("Camera width must be a multiple of 4!"); 592227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } else if (mCameraHeight % 2 != 0) { 593227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new RuntimeException("Camera height must be a multiple of 2!"); 594227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 595227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 596227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 597227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 598227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void updateServerFrame() { 599227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Server frame has been updated already, simply inform clients here. 600227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks informClients(); 601227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 602227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 603227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 604227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void grabFrame(FrameImage2D targetFrame) { 605227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks EGLContext clientContext = RenderTarget.currentContext(); 606227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 607227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Copy camera data to the client YUV texture 608227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks TextureSource clientTex = textureForContext(clientContext); 609227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int texWidth = mCameraWidth / 4; 610227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int texHeight = mCameraHeight + mCameraHeight / 2; 611227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks synchronized(mBufferLock) { // Don't swap buffers while we are reading 612227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks ByteBuffer pixels = ByteBuffer.wrap(readBuffer()); 613227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks clientTex.allocateWithPixels(pixels, texWidth, texHeight); 614227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 615227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks clientTex.setParameter(GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST); 616227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks clientTex.setParameter(GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); 617227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 618227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Setup the YUV-2-RGBA shader 619227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks ImageShader transferShader = shaderForContext(clientContext); 620227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks transferShader.setTargetCoords(mTargetCoords); 621227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks updateShaderPixelSize(transferShader); 622227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 623227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Convert pixels into target frame 624227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks targetFrame.resize(new int[] { mOutWidth, mOutHeight }); 625227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks transferShader.process(clientTex, 626227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks targetFrame.lockRenderTarget(), 627227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mOutWidth, 628227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mOutHeight); 629227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks targetFrame.unlock(); 630227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 631227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 632227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 633227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void onUpdateCameraOrientation(int orientation) { 634227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks super.onUpdateCameraOrientation(orientation); 635227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if ((mRunner.mActualFacing == FACING_FRONT) && mRunner.mFlipFront) { 636227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks switch (orientation) { 637227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks case 0: 638227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mTargetCoords = new float[] { 1f, 0f, 0f, 0f, 1f, 1f, 0f, 1f }; 639227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks break; 640227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks case 90: 641227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mTargetCoords = new float[] { 0f, 0f, 0f, 1f, 1f, 0f, 1f, 1f }; 642227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks break; 643227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks case 180: 644227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mTargetCoords = new float[] { 0f, 1f, 1f, 1f, 0f, 0f, 1f, 0f }; 645227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks break; 646227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks case 270: 647227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mTargetCoords = new float[] { 1f, 1f, 1f, 0f, 0f, 1f, 0f, 0f }; 648227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks break; 649227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 650227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } else { 651227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks switch (orientation) { 652227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks case 0: 653227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mTargetCoords = new float[] { 0f, 0f, 1f, 0f, 0f, 1f, 1f, 1f }; 654227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks break; 655227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks case 90: 656227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mTargetCoords = new float[] { 1f, 0f, 1f, 1f, 0f, 0f, 0f, 1f }; 657227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks break; 658227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks case 180: 659227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mTargetCoords = new float[] { 1f, 1f, 0f, 1f, 1f, 0f, 0f, 0f }; 660227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks break; 661227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks case 270: 662227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mTargetCoords = new float[] { 0f, 1f, 0f, 0f, 1f, 1f, 1f, 0f }; 663227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks break; 664227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 665227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 666227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 667227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 668227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 669227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void release() { 670227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mFrameBufferBack = null; 671227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mFrameBufferFront = null; 672227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 673227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 674227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 675227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public boolean isFrontMirrored() { 676227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return false; 677227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 678227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 679227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 680227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected ImageShader createClientShader() { 681227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks ImageShader shader = new ImageShader(mNV21ToRGBAVertex, mNV21ToRGBAFragment); 682227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // TODO: Make this a VBO 683227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks float[] yCoords = new float[] { 684227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 0f, 0f, 685227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1f, 0f, 686227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 0f, 2f / 3f, 687227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1f, 2f / 3f }; 688227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks float[] uvCoords = new float[] { 689227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 0f, 2f / 3f, 690227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1f, 2f / 3f, 691227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 0f, 1f, 692227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1f, 1f }; 693227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks shader.setAttributeValues("a_y_texcoord", yCoords, 2); 694227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks shader.setAttributeValues("a_vu_texcoord", uvCoords, 2); 695227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return shader; 696227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 697227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 698227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 699227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks protected TextureSource createClientTexture() { 700227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks TextureSource texture = TextureSource.newTexture(); 701227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks texture.setParameter(GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST); 702227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks texture.setParameter(GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); 703227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return texture; 704227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 705227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 706227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private void updateShaderPixelSize(ImageShader shader) { 707227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks float[] pixCoords = new float[] { 708227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 0f, 0f, 709227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraWidth, 0f, 710227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 0f, mCameraHeight, 711227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraWidth, mCameraHeight }; 712227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks shader.setAttributeValues("a_pixcoord", pixCoords, 2); 713227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 714227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 715227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private SurfaceView getPreviewDisplay() { 716227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mSurfaceView == null) { 717227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mSurfaceView = mRunner.getContext().getDummySurfaceView(); 718227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 719227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mSurfaceView; 720227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 721227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 722227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private void informClients() { 723227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks synchronized (mClients) { 724227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks for (FrameClient client : mClients) { 725227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks client.onCameraFrameAvailable(); 726227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 727227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 728227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 729227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 730227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 731227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private static class State { 732227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public static final int STATE_RUNNING = 1; 733227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public static final int STATE_STOPPED = 2; 734227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public static final int STATE_HALTED = 3; 735227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 736227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private AtomicInteger mCurrent = new AtomicInteger(STATE_STOPPED); 737227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 738227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public int current() { 739227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mCurrent.get(); 740227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 741227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 742227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void set(int newState) { 743227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCurrent.set(newState); 744227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 745227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 746227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 747227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private static class Event { 748227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public static final int START = 1; 749227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public static final int FRAME = 2; 750227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public static final int STOP = 3; 751227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public static final int HALT = 4; 752227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public static final int RESTART = 5; 753227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public static final int UPDATE = 6; 754227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public static final int TEARDOWN = 7; 755227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 756227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public int code; 757227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 758227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public Event(int code) { 759227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks this.code = code; 760227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 761227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 762227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 763227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private final class CameraRunnable implements Runnable { 764227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 765227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** On slower devices the event queue can easily fill up. We bound the queue to this. */ 766227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private final static int MAX_EVENTS = 32; 767227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 768227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** The runner's state */ 769227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private State mState = new State(); 770227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 771227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** The CameraRunner's event queue */ 772227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private LinkedBlockingQueue<Event> mEventQueue = new LinkedBlockingQueue<Event>(MAX_EVENTS); 773227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 774227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** The requested FPS */ 775227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private int mRequestedFramesPerSec = 30; 776227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 777227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** The actual FPS */ 778227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private int mActualFramesPerSec = 0; 779227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 780227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** The requested preview width and height */ 781227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private int mRequestedPreviewWidth = 640; 782227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private int mRequestedPreviewHeight = 480; 783227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 784227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** The requested picture width and height */ 785227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private int mRequestedPictureWidth = 640; 786227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private int mRequestedPictureHeight = 480; 787227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 788227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** The actual camera width and height */ 789227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private int[] mActualDims = null; 790227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 791227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** The requested facing */ 792227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private int mRequestedFacing = FACING_DONTCARE; 793227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 794227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** The actual facing */ 795227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private int mActualFacing = FACING_DONTCARE; 796227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 797227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** Whether to horizontally flip the front facing camera */ 798227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private boolean mFlipFront = true; 799227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 800227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** The display the camera streamer is bound to. */ 801227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private Display mDisplay = null; 802227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 803227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** The camera and screen orientation. */ 804227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private int mCamOrientation = 0; 805227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private int mOrientation = -1; 806227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 807227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** The camera rotation (used for capture). */ 808227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private int mCamRotation = 0; 809227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 810227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** The camera flash mode */ 811227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private String mFlashMode = Camera.Parameters.FLASH_MODE_OFF; 812227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 813227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** The camera object */ 814227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private Camera mCamera = null; 815227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 816227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private MediaRecorder mRecorder = null; 817227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 818227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** The ID of the currently used camera */ 819227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int mCamId = 0; 820227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 821227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** The platform-dependent camera frame handler. */ 822227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private CamFrameHandler mCamFrameHandler = null; 823227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 824227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** The set of camera listeners. */ 825227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private Set<CameraListener> mCamListeners = new HashSet<CameraListener>(); 826227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 827227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private ReentrantLock mCameraReadyLock = new ReentrantLock(true); 828227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // mCameraReady condition is used when waiting for the camera getting ready. 829227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private Condition mCameraReady = mCameraReadyLock.newCondition(); 830227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // external camera lock used to provide the capability of external camera access. 831227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private ExternalCameraLock mExternalCameraLock = new ExternalCameraLock(); 832227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 833227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private RenderTarget mRenderTarget; 834227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private MffContext mContext; 835227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 836227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 837227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * This provides the capability of locking and unlocking from different threads. 838227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * The thread will wait until the lock state is idle. Any thread can wake up 839227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * a waiting thread by calling unlock (i.e. signal), provided that unlock 840227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * are called using the same context when lock was called. Using context prevents 841227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * from rogue usage of unlock. 842227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 843227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private class ExternalCameraLock { 844227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public static final int IDLE = 0; 845227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public static final int IN_USE = 1; 846227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private int mLockState = IDLE; 847227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private Object mLockContext; 848227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private final ReentrantLock mLock = new ReentrantLock(true); 849227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private final Condition mInUseLockCondition= mLock.newCondition(); 850227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 851227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public boolean lock(Object context) { 852227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (context == null) { 853227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new RuntimeException("Null context when locking"); 854227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 855227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mLock.lock(); 856227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mLockState == IN_USE) { 857227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks try { 858227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mInUseLockCondition.await(); 859227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } catch (InterruptedException e) { 860227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return false; 861227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 862227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 863227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mLockState = IN_USE; 864227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mLockContext = context; 865227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mLock.unlock(); 866227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return true; 867227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 868227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 869227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void unlock(Object context) { 870227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mLock.lock(); 871227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mLockState != IN_USE) { 872227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new RuntimeException("Not in IN_USE state"); 873227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 874227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (context != mLockContext) { 875227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new RuntimeException("Lock is not owned by this context"); 876227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 877227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mLockState = IDLE; 878227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mLockContext = null; 879227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mInUseLockCondition.signal(); 880227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mLock.unlock(); 881227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 882227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 883227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 884227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public CameraRunnable(MffContext context) { 885227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mContext = context; 886227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks createCamFrameHandler(); 887227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCamFrameHandler.initWithRunner(this); 888227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks launchThread(); 889227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 890227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 891227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public MffContext getContext() { 892227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mContext; 893227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 894227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 895227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void loop() { 896227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks while (true) { 897227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks try { 898227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Event event = nextEvent(); 899227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (event == null) continue; 900227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks switch (event.code) { 901227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks case Event.START: 902227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks onStart(); 903227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks break; 904227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks case Event.STOP: 905227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks onStop(); 906227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks break; 907227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks case Event.FRAME: 908227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks onFrame(); 909227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks break; 910227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks case Event.HALT: 911227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks onHalt(); 912227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks break; 913227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks case Event.RESTART: 914227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks onRestart(); 915227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks break; 916227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks case Event.UPDATE: 917227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks onUpdate(); 918227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks break; 919227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks case Event.TEARDOWN: 920227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks onTearDown(); 921227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks break; 922227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 923227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } catch (Exception e) { 924227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks e.printStackTrace(); 925227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 926227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 927227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 928227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 929227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Override 930227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void run() { 931227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks loop(); 932227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 933227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 934227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void signalNewFrame() { 935227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks pushEvent(Event.FRAME, false); 936227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 937227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 938227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void pushEvent(int eventId, boolean required) { 939227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks try { 940227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (required) { 941227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mEventQueue.put(new Event(eventId)); 942227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } else { 943227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mEventQueue.offer(new Event(eventId)); 944227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 945227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } catch (InterruptedException e) { 946227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // We should never get here (as we do not limit capacity in the queue), but if 947227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // we do, we log an error. 948227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Log.e("CameraStreamer", "Dropping event " + eventId + "!"); 949227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 950227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 951227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 952227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void launchThread() { 953227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Thread cameraThread = new Thread(this); 954227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks cameraThread.start(); 955227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 956227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 957227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Deprecated 958227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public Camera getCamera() { 959227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks synchronized (mState) { 960227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mCamera; 961227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 962227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 963227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 964227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public Camera lockCamera(Object context) { 965227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mExternalCameraLock.lock(context); 966227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 967227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * since lockCamera can happen right after closeCamera, 968227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * the camera handle can be null, wait until valid handle 969227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * is acquired. 970227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 971227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks while (mCamera == null) { 972227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mExternalCameraLock.unlock(context); 973227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraReadyLock.lock(); 974227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks try { 975227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraReady.await(); 976227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } catch (InterruptedException e) { 977227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new RuntimeException("Condition interrupted", e); 978227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 979227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraReadyLock.unlock(); 980227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mExternalCameraLock.lock(context); 981227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 982227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mCamera; 983227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 984227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 985227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void unlockCamera(Object context) { 986227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mExternalCameraLock.unlock(context); 987227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 988227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 989227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public int getCurrentCameraId() { 990227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks synchronized (mState) { 991227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mCamId; 992227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 993227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 994227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 995227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public boolean isRunning() { 996227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mState.current() != State.STATE_STOPPED; 997227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 998227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 999227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void addListener(CameraListener listener) { 1000227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks synchronized (mCamListeners) { 1001227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCamListeners.add(listener); 1002227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1003227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1004227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1005227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void removeListener(CameraListener listener) { 1006227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks synchronized (mCamListeners) { 1007227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCamListeners.remove(listener); 1008227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1009227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1010227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1011227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public synchronized void bindToDisplay(Display display) { 1012227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mDisplay = display; 1013227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1014227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1015227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public synchronized void setDesiredPreviewSize(int width, int height) { 1016227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (width != mRequestedPreviewWidth || height != mRequestedPreviewHeight) { 1017227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRequestedPreviewWidth = width; 1018227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRequestedPreviewHeight = height; 1019227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks onParamsUpdated(); 1020227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1021227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1022227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1023227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public synchronized void setDesiredPictureSize(int width, int height) { 1024227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (width != mRequestedPictureWidth || height != mRequestedPictureHeight) { 1025227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRequestedPictureWidth = width; 1026227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRequestedPictureHeight = height; 1027227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks onParamsUpdated(); 1028227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1029227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1030227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1031227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public synchronized void setDesiredFrameRate(int fps) { 1032227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (fps != mRequestedFramesPerSec) { 1033227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRequestedFramesPerSec = fps; 1034227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks onParamsUpdated(); 1035227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1036227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1037227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1038227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public synchronized void setFacing(int facing) { 1039227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (facing != mRequestedFacing) { 1040227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks switch (facing) { 1041227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks case FACING_DONTCARE: 1042227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks case FACING_FRONT: 1043227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks case FACING_BACK: 1044227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRequestedFacing = facing; 1045227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks break; 1046227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks default: 1047227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new IllegalArgumentException("Unknown facing value '" + facing 1048227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks + "' passed to setFacing!"); 1049227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1050227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks onParamsUpdated(); 1051227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1052227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1053227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1054227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public synchronized void setFlipFrontCamera(boolean flipFront) { 1055227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mFlipFront != flipFront) { 1056227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mFlipFront = flipFront; 1057227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1058227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1059227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1060227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public synchronized void setFlashMode(String flashMode) { 1061227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (!flashMode.equals(mFlashMode)) { 1062227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mFlashMode = flashMode; 1063227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks onParamsUpdated(); 1064227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1065227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1066227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1067227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public synchronized int getCameraFacing() { 1068227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mActualFacing; 1069227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1070227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1071227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public synchronized int getCameraRotation() { 1072227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mCamRotation; 1073227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1074227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1075227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public synchronized boolean supportsHardwareFaceDetection() { 1076227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks //return mCamFrameHandler.supportsHardwareFaceDetection(); 1077227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // TODO 1078227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return true; 1079227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1080227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1081227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public synchronized int getCameraWidth() { 1082227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return (mActualDims != null) ? mActualDims[0] : 0; 1083227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1084227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1085227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public synchronized int getCameraHeight() { 1086227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return (mActualDims != null) ? mActualDims[1] : 0; 1087227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1088227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1089227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public synchronized int getCameraFrameRate() { 1090227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mActualFramesPerSec; 1091227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1092227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1093227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public synchronized String getFlashMode() { 1094227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mCamera.getParameters().getFlashMode(); 1095227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1096227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1097227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public synchronized boolean canStart() { 1098227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // If we can get a camera id without error we should be able to start. 1099227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks try { 1100227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks getCameraId(); 1101227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } catch (RuntimeException e) { 1102227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return false; 1103227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1104227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return true; 1105227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1106227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1107227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public boolean grabFrame(FrameImage2D targetFrame) { 1108227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Make sure we stay in state running while we are grabbing the frame. 1109227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks synchronized (mState) { 1110227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mState.current() != State.STATE_RUNNING) { 1111227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return false; 1112227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1113227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // we may not have the camera ready, this might happen when in the middle 1114227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // of switching camera. 1115227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mCamera == null) { 1116227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return false; 1117227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1118227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCamFrameHandler.grabFrame(targetFrame); 1119227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return true; 1120227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1121227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1122227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1123227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public CamFrameHandler getCamFrameHandler() { 1124227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mCamFrameHandler; 1125227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1126227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1127227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private void onParamsUpdated() { 1128227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks pushEvent(Event.UPDATE, true); 1129227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1130227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1131227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private Event nextEvent() { 1132227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks try { 1133227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mEventQueue.take(); 1134227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } catch (InterruptedException e) { 1135227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Ignore and keep going. 1136227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Log.w("GraphRunner", "Event queue processing was interrupted."); 1137227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return null; 1138227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1139227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1140227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1141227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private void onStart() { 1142227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mState.current() == State.STATE_STOPPED) { 1143227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mState.set(State.STATE_RUNNING); 1144227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks getRenderTarget().focus(); 1145227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks openCamera(); 1146227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1147227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1148227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1149227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private void onStop() { 1150227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mState.current() == State.STATE_RUNNING) { 1151227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks closeCamera(); 1152227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks RenderTarget.focusNone(); 1153227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1154227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Set state to stop (halted becomes stopped). 1155227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mState.set(State.STATE_STOPPED); 1156227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1157227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1158227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private void onHalt() { 1159227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Only halt if running. Stopped overrides halt. 1160227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mState.current() == State.STATE_RUNNING) { 1161227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks closeCamera(); 1162227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks RenderTarget.focusNone(); 1163227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mState.set(State.STATE_HALTED); 1164227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1165227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1166227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1167227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private void onRestart() { 1168227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Only restart if halted 1169227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mState.current() == State.STATE_HALTED) { 1170227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mState.set(State.STATE_RUNNING); 1171227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks getRenderTarget().focus(); 1172227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks openCamera(); 1173227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1174227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1175227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1176227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private void onUpdate() { 1177227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mState.current() == State.STATE_RUNNING) { 1178227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks pushEvent(Event.STOP, true); 1179227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks pushEvent(Event.START, true); 1180227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1181227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1182227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private void onFrame() { 1183227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mState.current() == State.STATE_RUNNING) { 1184227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks updateRotation(); 1185227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCamFrameHandler.updateServerFrame(); 1186227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1187227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1188227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1189227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private void onTearDown() { 1190227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mState.current() == State.STATE_STOPPED) { 1191227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Remove all listeners. This will release their resources 1192227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks for (CameraListener listener : mCamListeners) { 1193227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks removeListener(listener); 1194227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1195227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCamListeners.clear(); 1196227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } else { 1197227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Log.e("CameraStreamer", "Could not tear-down CameraStreamer as camera still " 1198227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks + "seems to be running!"); 1199227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1200227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1201227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1202227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private void createCamFrameHandler() { 1203227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // TODO: For now we simply assert that OpenGL is supported. Later on, we should add 1204227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // a CamFrameHandler that does not depend on OpenGL. 1205227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks getContext().assertOpenGLSupported(); 1206227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (VERSION.SDK_INT >= 16) { 1207227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCamFrameHandler = new CamFrameHandlerJB(); 1208227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } else if (VERSION.SDK_INT >= 15) { 1209227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCamFrameHandler = new CamFrameHandlerICS(); 1210227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } else { 1211227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCamFrameHandler = new CamFrameHandlerGB(); 1212227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1213227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1214227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1215227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private void updateRotation() { 1216227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mDisplay != null) { 1217227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks updateDisplayRotation(mDisplay.getRotation()); 1218227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1219227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1220227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1221227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private synchronized void updateDisplayRotation(int rotation) { 1222227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks switch (rotation) { 1223227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks case Surface.ROTATION_0: 1224227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks onUpdateOrientation(0); 1225227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks break; 1226227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks case Surface.ROTATION_90: 1227227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks onUpdateOrientation(90); 1228227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks break; 1229227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks case Surface.ROTATION_180: 1230227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks onUpdateOrientation(180); 1231227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks break; 1232227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks case Surface.ROTATION_270: 1233227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks onUpdateOrientation(270); 1234227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks break; 1235227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks default: 1236227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new IllegalArgumentException("Unsupported display rotation constant! Use " 1237227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks + "one of the Surface.ROTATION_ constants!"); 1238227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1239227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1240227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1241227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private RenderTarget getRenderTarget() { 1242227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mRenderTarget == null) { 1243227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRenderTarget = RenderTarget.newTarget(1, 1); 1244227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1245227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mRenderTarget; 1246227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1247227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1248227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private void updateCamera() { 1249227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks synchronized (mState) { 1250227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCamId = getCameraId(); 1251227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks updateCameraOrientation(mCamId); 1252227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCamera = Camera.open(mCamId); 1253227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks initCameraParameters(); 1254227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1255227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1256227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1257227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private void updateCameraOrientation(int camId) { 1258227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks CameraInfo cameraInfo = new CameraInfo(); 1259227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Camera.getCameraInfo(camId, cameraInfo); 1260227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCamOrientation = cameraInfo.orientation; 1261227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mOrientation = -1; // Forces recalculation to match display 1262227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mActualFacing = (cameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT) 1263227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks ? FACING_FRONT 1264227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks : FACING_BACK; 1265227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1266227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1267227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private int getCameraId() { 1268227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int camCount = Camera.getNumberOfCameras(); 1269227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (camCount == 0) { 1270227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new RuntimeException("Device does not have any cameras!"); 1271227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } else if (mRequestedFacing == FACING_DONTCARE) { 1272227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Simply return first camera if mRequestedFacing is don't care 1273227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return 0; 1274227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1275227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1276227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Attempt to find requested camera 1277227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks boolean useFrontCam = (mRequestedFacing == FACING_FRONT); 1278227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks CameraInfo cameraInfo = new CameraInfo(); 1279227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks for (int i = 0; i < camCount; ++i) { 1280227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Camera.getCameraInfo(i, cameraInfo); 1281227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if ((cameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT) == useFrontCam) { 1282227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return i; 1283227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1284227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1285227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new RuntimeException("Could not find a camera facing (" + mRequestedFacing 1286227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks + ")!"); 1287227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1288227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1289227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private void initCameraParameters() { 1290227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Camera.Parameters params = mCamera.getParameters(); 1291227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1292227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Find closest preview size 1293227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mActualDims = 1294227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks findClosestPreviewSize(mRequestedPreviewWidth, mRequestedPreviewHeight, params); 1295227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCamFrameHandler.setCameraSize(mActualDims[0], mActualDims[1]); 1296227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks params.setPreviewSize(mActualDims[0], mActualDims[1]); 1297227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Find closest picture size 1298227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int[] dims = 1299227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks findClosestPictureSize(mRequestedPictureWidth, mRequestedPictureHeight, params); 1300227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks params.setPictureSize(dims[0], dims[1]); 1301227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1302227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Find closest FPS 1303227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int closestRange[] = findClosestFpsRange(mRequestedFramesPerSec, params); 1304227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks params.setPreviewFpsRange(closestRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX], 1305227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks closestRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]); 1306227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1307227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Set flash mode (if supported) 1308227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (params.getFlashMode() != null) { 1309227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks params.setFlashMode(mFlashMode); 1310227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1311227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1312227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCamera.setParameters(params); 1313227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1314227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1315227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private int[] findClosestPreviewSize(int width, int height, Camera.Parameters parameters) { 1316227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes(); 1317227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return findClosestSizeFromList(width, height, previewSizes); 1318227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1319227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1320227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private int[] findClosestPictureSize(int width, int height, Camera.Parameters parameters) { 1321227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks List<Camera.Size> pictureSizes = parameters.getSupportedPictureSizes(); 1322227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return findClosestSizeFromList(width, height, pictureSizes); 1323227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1324227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1325227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private int[] findClosestSizeFromList(int width, int height, List<Camera.Size> sizes) { 1326227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int closestWidth = -1; 1327227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int closestHeight = -1; 1328227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int smallestWidth = sizes.get(0).width; 1329227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int smallestHeight = sizes.get(0).height; 1330227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks for (Camera.Size size : sizes) { 1331227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Best match defined as not being larger in either dimension than 1332227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // the requested size, but as close as possible. The below isn't a 1333227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // stable selection (reording the size list can give different 1334227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // results), but since this is a fallback nicety, that's acceptable. 1335227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if ( size.width <= width && 1336227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks size.height <= height && 1337227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks size.width >= closestWidth && 1338227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks size.height >= closestHeight) { 1339227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks closestWidth = size.width; 1340227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks closestHeight = size.height; 1341227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1342227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if ( size.width < smallestWidth && 1343227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks size.height < smallestHeight) { 1344227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks smallestWidth = size.width; 1345227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks smallestHeight = size.height; 1346227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1347227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1348227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (closestWidth == -1) { 1349227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Requested size is smaller than any listed size; match with smallest possible 1350227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks closestWidth = smallestWidth; 1351227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks closestHeight = smallestHeight; 1352227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1353227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int[] closestSize = {closestWidth, closestHeight}; 1354227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return closestSize; 1355227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1356227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1357227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private int[] findClosestFpsRange(int fps, Camera.Parameters params) { 1358227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks List<int[]> supportedFpsRanges = params.getSupportedPreviewFpsRange(); 1359227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int[] closestRange = supportedFpsRanges.get(0); 1360227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int fpsk = fps * 1000; 1361227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int minDiff = 1000000; 1362227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks for (int[] range : supportedFpsRanges) { 1363227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int low = range[Camera.Parameters.PREVIEW_FPS_MIN_INDEX]; 1364227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int high = range[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]; 1365227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (low <= fpsk && high >= fpsk) { 1366227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int diff = (fpsk - low) + (high - fpsk); 1367227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (diff < minDiff) { 1368227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks closestRange = range; 1369227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks minDiff = diff; 1370227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1371227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1372227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1373227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mActualFramesPerSec = closestRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX] / 1000; 1374227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return closestRange; 1375227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1376227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1377227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private void onUpdateOrientation(int orientation) { 1378227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // First we calculate the camera rotation. 1379227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int rotation = (mActualFacing == FACING_FRONT) 1380227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks ? (mCamOrientation + orientation) % 360 1381227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks : (mCamOrientation - orientation + 360) % 360; 1382227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (rotation != mCamRotation) { 1383227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks synchronized (this) { 1384227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCamRotation = rotation; 1385227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1386227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1387227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1388227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // We compensate for mirroring in the orientation. This differs from the rotation, 1389227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // where we are invariant to mirroring. 1390227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int fixedOrientation = rotation; 1391227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mActualFacing == FACING_FRONT && mCamFrameHandler.isFrontMirrored()) { 1392227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks fixedOrientation = (360 - rotation) % 360; // compensate the mirror 1393227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1394227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mOrientation != fixedOrientation) { 1395227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mOrientation = fixedOrientation; 1396227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCamFrameHandler.onUpdateCameraOrientation(mOrientation); 1397227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1398227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1399227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1400227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private void openCamera() { 1401227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Acquire lock for camera 1402227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks try { 1403227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (!mCameraLock.tryLock(MAX_CAMERA_WAIT_TIME, TimeUnit.SECONDS)) { 1404227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new RuntimeException("Timed out while waiting to acquire camera!"); 1405227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1406227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } catch (InterruptedException e) { 1407227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new RuntimeException("Interrupted while waiting to acquire camera!"); 1408227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1409227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1410227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Make sure external entities are not holding camera. We need to hold the lock until 1411227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // the preview is started again. 1412227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Object lockContext = new Object(); 1413227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mExternalCameraLock.lock(lockContext); 1414227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1415227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Need to synchronize this as many of the member values are modified during setup. 1416227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks synchronized (this) { 1417227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks updateCamera(); 1418227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks updateRotation(); 1419227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCamFrameHandler.setupServerFrame(); 1420227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1421227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1422227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCamera.startPreview(); 1423227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1424227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Inform listeners 1425227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks synchronized (mCamListeners) { 1426227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks for (CameraListener listener : mCamListeners) { 1427227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks listener.onCameraOpened(CameraStreamer.this); 1428227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1429227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1430227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mExternalCameraLock.unlock(lockContext); 1431227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // New camera started 1432227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraReadyLock.lock(); 1433227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraReady.signal(); 1434227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraReadyLock.unlock(); 1435227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1436227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1437227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1438227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Creates an instance of MediaRecorder to be used for the streamer. 1439227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * User should call the functions in the following sequence:<p> 1440227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * {@link #createRecorder}<p> 1441227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * {@link #startRecording}<p> 1442227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * {@link #stopRecording}<p> 1443227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * {@link #releaseRecorder}<p> 1444227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * @param outputPath the output video path for the recorder 1445227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * @param profile the recording {@link CamcorderProfile} which has parameters indicating 1446227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * the resolution, quality etc. 1447227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1448227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void createRecorder(String outputPath, CamcorderProfile profile) { 1449227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks lockCamera(this); 1450227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCamera.unlock(); 1451227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mRecorder != null) { 1452227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRecorder.release(); 1453227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1454227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRecorder = new MediaRecorder(); 1455227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRecorder.setCamera(mCamera); 1456227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); 1457227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); 1458227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRecorder.setProfile(profile); 1459227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRecorder.setOutputFile(outputPath); 1460227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks try { 1461227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRecorder.prepare(); 1462227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } catch (Exception e) { 1463227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new RuntimeException(e); 1464227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1465227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1466227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1467227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1468227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Starts recording video using the created MediaRecorder object 1469227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1470227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void startRecording() { 1471227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mRecorder == null) { 1472227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new RuntimeException("No recorder created"); 1473227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1474227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRecorder.start(); 1475227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1476227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1477227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1478227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Stops recording video 1479227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1480227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void stopRecording() { 1481227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mRecorder == null) { 1482227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new RuntimeException("No recorder created"); 1483227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1484227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRecorder.stop(); 1485227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1486227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1487227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1488227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Release the resources held by the MediaRecorder, call this after done recording. 1489227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1490227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void releaseRecorder() { 1491227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mRecorder == null) { 1492227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks throw new RuntimeException("No recorder created"); 1493227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1494227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRecorder.release(); 1495227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mRecorder = null; 1496227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCamera.lock(); 1497227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks unlockCamera(this); 1498227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1499227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1500227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks private void closeCamera() { 1501227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Object lockContext = new Object(); 1502227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mExternalCameraLock.lock(lockContext); 1503227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (mCamera != null) { 1504227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCamera.stopPreview(); 1505227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCamera.release(); 1506227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCamera = null; 1507227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1508227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraLock.unlock(); 1509227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCamFrameHandler.release(); 1510227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mExternalCameraLock.unlock(lockContext); 1511227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Inform listeners 1512227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks synchronized (mCamListeners) { 1513227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks for (CameraListener listener : mCamListeners) { 1514227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks listener.onCameraClosed(CameraStreamer.this); 1515227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1516227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1517227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1518227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1519227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1520227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1521227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1522227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * The frame-client callback interface. 1523227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * FrameClients, that wish to receive Frames from the camera must implement this callback 1524227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * method. 1525227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Note, that this method is called on the Camera server thread. However, the 1526227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * {@code getLatestFrame()} method must be called from the client thread. 1527227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1528227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public static interface FrameClient { 1529227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void onCameraFrameAvailable(); 1530227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1531227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1532227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1533227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * The CameraListener callback interface. 1534227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * This interface allows observers to monitor the CameraStreamer and respond to stream open 1535227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * and close events. 1536227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1537227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public static interface CameraListener { 1538227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1539227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Called when the camera is opened and begins producing frames. 1540227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * This is also called when settings have changed that caused the camera to be reopened. 1541227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1542227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void onCameraOpened(CameraStreamer camera); 1543227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1544227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1545227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Called when the camera is closed and stops producing frames. 1546227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1547227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void onCameraClosed(CameraStreamer camera); 1548227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1549227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1550227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1551227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Manually update the display rotation. 1552227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * You do not need to call this, if the camera is bound to a display, or your app does not 1553227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * support multiple orientations. 1554227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1555227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void updateDisplayRotation(int rotation) { 1556227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraRunner.updateDisplayRotation(rotation); 1557227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1558227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1559227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1560227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Bind the camera to your Activity's display. 1561227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Use this, if your Activity supports multiple display orientation, and you would like the 1562227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * camera to update accordingly when the orientation is changed. 1563227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1564227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void bindToDisplay(Display display) { 1565227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraRunner.bindToDisplay(display); 1566227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1567227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1568227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1569227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Sets the desired preview size. 1570227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Note that the actual width and height may vary. 1571227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 1572227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * @param width The desired width of the preview camera stream. 1573227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * @param height The desired height of the preview camera stream. 1574227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1575227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void setDesiredPreviewSize(int width, int height) { 1576227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraRunner.setDesiredPreviewSize(width, height); 1577227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1578227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1579227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1580227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Sets the desired picture size. 1581227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Note that the actual width and height may vary. 1582227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 1583227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * @param width The desired picture width. 1584227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * @param height The desired picture height. 1585227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1586227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void setDesiredPictureSize(int width, int height) { 1587227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraRunner.setDesiredPictureSize(width, height); 1588227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1589227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1590227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1591227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Sets the desired camera frame-rate. 1592227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Note, that the actual frame-rate may vary. 1593227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 1594227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * @param fps The desired FPS. 1595227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1596227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void setDesiredFrameRate(int fps) { 1597227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraRunner.setDesiredFrameRate(fps); 1598227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1599227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1600227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1601227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Sets the camera facing direction. 1602227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 1603227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Specify {@code FACING_DONTCARE} (default) if you would like the CameraStreamer to choose 1604227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * the direction. When specifying any other direction be sure to first check whether the 1605227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * device supports the desired facing. 1606227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 1607227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * @param facing The desired camera facing direction. 1608227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1609227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void setFacing(int facing) { 1610227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraRunner.setFacing(facing); 1611227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1612227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1613227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1614227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Set whether to flip the camera image horizontally when using the front facing camera. 1615227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1616227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void setFlipFrontCamera(boolean flipFront) { 1617227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraRunner.setFlipFrontCamera(flipFront); 1618227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1619227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1620227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1621227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Sets the camera flash mode. 1622227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 1623227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * This must be one of the String constants defined in the Camera.Parameters class. 1624227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 1625227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * @param flashMode A String constant specifying the flash mode. 1626227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1627227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void setFlashMode(String flashMode) { 1628227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraRunner.setFlashMode(flashMode); 1629227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1630227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1631227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1632227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Returns the current flash mode. 1633227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 1634227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * This returns the currently running camera's flash-mode, or NULL if flash modes are not 1635227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * supported on that camera. 1636227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 1637227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * @return The flash mode String, or NULL if flash modes are not supported. 1638227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1639227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public String getFlashMode() { 1640227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mCameraRunner.getFlashMode(); 1641227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1642227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1643227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1644227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Get the actual camera facing. 1645227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Returns 0 if actual facing is not yet known. 1646227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1647227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public int getCameraFacing() { 1648227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mCameraRunner.getCameraFacing(); 1649227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1650227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1651227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1652227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Get the current camera rotation. 1653227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 1654227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Use this rotation if you want to snap pictures from the camera and need to rotate the 1655227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * picture to be up-right. 1656227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 1657227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * @return the current camera rotation. 1658227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1659227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public int getCameraRotation() { 1660227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mCameraRunner.getCameraRotation(); 1661227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1662227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1663227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1664227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Specifies whether or not the camera supports hardware face detection. 1665227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * @return true, if the camera supports hardware face detection. 1666227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1667227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public boolean supportsHardwareFaceDetection() { 1668227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mCameraRunner.supportsHardwareFaceDetection(); 1669227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1670227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1671227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1672227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Returns the camera facing that is chosen when DONT_CARE is specified. 1673227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Returns 0 if neither a front nor back camera could be found. 1674227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1675227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public static int getDefaultFacing() { 1676227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int camCount = Camera.getNumberOfCameras(); 1677227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (camCount == 0) { 1678227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return 0; 1679227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } else { 1680227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks CameraInfo cameraInfo = new CameraInfo(); 1681227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Camera.getCameraInfo(0, cameraInfo); 1682227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return (cameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT) 1683227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks ? FACING_FRONT 1684227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks : FACING_BACK; 1685227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1686227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1687227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1688227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1689227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Get the actual camera width. 1690227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Returns 0 if actual width is not yet known. 1691227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1692227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public int getCameraWidth() { 1693227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mCameraRunner.getCameraWidth(); 1694227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1695227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1696227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1697227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Get the actual camera height. 1698227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Returns 0 if actual height is not yet known. 1699227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1700227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public int getCameraHeight() { 1701227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mCameraRunner.getCameraHeight(); 1702227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1703227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1704227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1705227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Get the actual camera frame-rate. 1706227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Returns 0 if actual frame-rate is not yet known. 1707227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1708227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public int getCameraFrameRate() { 1709227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mCameraRunner.getCameraFrameRate(); 1710227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1711227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1712227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1713227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Returns true if the camera can be started at this point. 1714227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1715227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public boolean canStart() { 1716227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mCameraRunner.canStart(); 1717227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1718227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1719227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1720227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Returns true if the camera is currently running. 1721227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1722227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public boolean isRunning() { 1723227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mCameraRunner.isRunning(); 1724227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1725227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1726227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1727227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Starts the camera. 1728227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1729227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void start() { 1730227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraRunner.pushEvent(Event.START, true); 1731227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1732227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1733227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1734227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Stops the camera. 1735227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1736227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void stop() { 1737227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraRunner.pushEvent(Event.STOP, true); 1738227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1739227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1740227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1741227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Stops the camera and waits until it is completely closed. Generally, this should not be 1742227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * called in the UI thread, but may be necessary if you need the camera to be closed before 1743227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * performing subsequent steps. 1744227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1745227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void stopAndWait() { 1746227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraRunner.pushEvent(Event.STOP, true); 1747227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks try { 1748227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (!mCameraLock.tryLock(MAX_CAMERA_WAIT_TIME, TimeUnit.SECONDS)) { 1749227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Log.w("CameraStreamer", "Time-out waiting for camera to close!"); 1750227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1751227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } catch (InterruptedException e) { 1752227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks Log.w("CameraStreamer", "Interrupted while waiting for camera to close!"); 1753227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1754227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraLock.unlock(); 1755227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1756227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1757227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1758227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Registers a listener to handle camera state changes. 1759227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1760227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void addListener(CameraListener listener) { 1761227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraRunner.addListener(listener); 1762227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1763227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1764227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1765227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Unregisters a listener to handle camera state changes. 1766227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1767227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void removeListener(CameraListener listener) { 1768227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraRunner.removeListener(listener); 1769227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1770227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1771227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1772227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Registers the frame-client with the camera. 1773227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * This MUST be called from the client thread! 1774227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1775227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void registerClient(FrameClient client) { 1776227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraRunner.getCamFrameHandler().registerClient(client); 1777227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1778227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1779227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1780227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Unregisters the frame-client with the camera. 1781227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * This MUST be called from the client thread! 1782227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1783227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void unregisterClient(FrameClient client) { 1784227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraRunner.getCamFrameHandler().unregisterClient(client); 1785227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1786227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1787227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1788227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Gets the latest camera frame for the client. 1789227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 1790227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * This must be called from the same thread as the {@link #registerClient(FrameClient)} call! 1791227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * The frame passed in will be resized by the camera streamer to fit the camera frame. 1792227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Returns false if the frame could not be grabbed. This may happen if the camera has been 1793227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * closed in the meantime, and its resources let go. 1794227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 1795227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * @return true, if the frame was grabbed successfully. 1796227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1797227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public boolean getLatestFrame(FrameImage2D targetFrame) { 1798227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mCameraRunner.grabFrame(targetFrame); 1799227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1800227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1801227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1802227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Expose the underlying android.hardware.Camera object. 1803227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Use the returned object with care: some camera functions may break the functionality 1804227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * of CameraStreamer. 1805227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * @return the Camera object. 1806227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1807227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks @Deprecated 1808227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public Camera getCamera() { 1809227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mCameraRunner.getCamera(); 1810227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1811227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1812227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1813227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Obtain access to the underlying android.hardware.Camera object. 1814227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * This grants temporary access to the internal Camera handle. Once you are done using the 1815227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * handle you must call {@link #unlockCamera(Object)}. While you are holding the Camera, 1816227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * it will not be modified or released by the CameraStreamer. The Camera object return is 1817227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * guaranteed to have the preview running. 1818227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 1819227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * The CameraStreamer does not account for changes you make to the Camera. That is, if you 1820227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * change the Camera unexpectedly this may cause unintended behavior by the streamer. 1821227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * 1822227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Note that the returned object may be null. This can happen when the CameraStreamer is not 1823227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * running, or is just transitioning to another Camera, such as during a switch from front to 1824227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * back Camera. 1825227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * @param context an object used as a context for locking and unlocking. lockCamera and 1826227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * unlockCamera should use the same context object. 1827227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * @return The Camera object. 1828227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1829227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public Camera lockCamera(Object context) { 1830227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mCameraRunner.lockCamera(context); 1831227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1832227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1833227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1834227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Release the acquire Camera object. 1835227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * @param context the context object that used when lockCamera is called. 1836227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1837227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void unlockCamera(Object context) { 1838227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraRunner.unlockCamera(context); 1839227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1840227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1841227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1842227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Creates an instance of MediaRecorder to be used for the streamer. 1843227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * User should call the functions in the following sequence:<p> 1844227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * {@link #createRecorder}<p> 1845227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * {@link #startRecording}<p> 1846227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * {@link #stopRecording}<p> 1847227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * {@link #releaseRecorder}<p> 1848227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * @param path the output video path for the recorder 1849227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * @param profile the recording {@link CamcorderProfile} which has parameters indicating 1850227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * the resolution, quality etc. 1851227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1852227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void createRecorder(String path, CamcorderProfile profile) { 1853227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraRunner.createRecorder(path, profile); 1854227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1855227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1856227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void releaseRecorder() { 1857227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraRunner.releaseRecorder(); 1858227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1859227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1860227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void startRecording() { 1861227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraRunner.startRecording(); 1862227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1863227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1864227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public void stopRecording() { 1865227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraRunner.stopRecording(); 1866227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1867227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1868227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1869227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Retrieve the ID of the currently used camera. 1870227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * @return the ID of the currently used camera. 1871227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1872227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public int getCameraId() { 1873227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return mCameraRunner.getCurrentCameraId(); 1874227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1875227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1876227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** 1877227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * @return The number of cameras available for streaming on this device. 1878227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */ 1879227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks public static int getNumberOfCameras() { 1880227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Currently, this is just the number of cameras that are available on the device. 1881227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return Camera.getNumberOfCameras(); 1882227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1883227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1884227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks CameraStreamer(MffContext context) { 1885227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraRunner = new CameraRunnable(context); 1886227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1887227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1888227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** Halt is like stop, but may be resumed using restart(). */ 1889227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks void halt() { 1890227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraRunner.pushEvent(Event.HALT, true); 1891227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1892227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1893227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks /** Restart starts the camera only if previously halted. */ 1894227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks void restart() { 1895227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraRunner.pushEvent(Event.RESTART, true); 1896227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1897227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1898227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks static boolean requireDummySurfaceView() { 1899227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks return VERSION.SDK_INT < 15; 1900227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1901227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1902227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks void tearDown() { 1903227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks mCameraRunner.pushEvent(Event.TEARDOWN, true); 1904227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 1905227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks} 1906227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 1907