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