• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.tensorflow.demo;
2 
3 /*
4  * Copyright 2017 The TensorFlow Authors. All Rights Reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *       http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 import android.app.Fragment;
20 import android.graphics.SurfaceTexture;
21 import android.hardware.Camera;
22 import android.hardware.Camera.CameraInfo;
23 import android.os.Bundle;
24 import android.os.Handler;
25 import android.os.HandlerThread;
26 import android.util.Size;
27 import android.util.SparseIntArray;
28 import android.view.LayoutInflater;
29 import android.view.Surface;
30 import android.view.TextureView;
31 import android.view.View;
32 import android.view.ViewGroup;
33 import java.io.IOException;
34 import java.util.List;
35 import org.tensorflow.demo.env.ImageUtils;
36 import org.tensorflow.demo.env.Logger;
37 import org.tensorflow.demo.R; // Explicit import needed for internal Google builds.
38 
39 public class LegacyCameraConnectionFragment extends Fragment {
40   private Camera camera;
41   private static final Logger LOGGER = new Logger();
42   private Camera.PreviewCallback imageListener;
43   private Size desiredSize;
44 
45   /**
46    * The layout identifier to inflate for this Fragment.
47    */
48   private int layout;
49 
LegacyCameraConnectionFragment( final Camera.PreviewCallback imageListener, final int layout, final Size desiredSize)50   public LegacyCameraConnectionFragment(
51       final Camera.PreviewCallback imageListener, final int layout, final Size desiredSize) {
52     this.imageListener = imageListener;
53     this.layout = layout;
54     this.desiredSize = desiredSize;
55   }
56 
57   /**
58    * Conversion from screen rotation to JPEG orientation.
59    */
60   private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
61 
62   static {
ORIENTATIONS.append(Surface.ROTATION_0, 90)63     ORIENTATIONS.append(Surface.ROTATION_0, 90);
ORIENTATIONS.append(Surface.ROTATION_90, 0)64     ORIENTATIONS.append(Surface.ROTATION_90, 0);
ORIENTATIONS.append(Surface.ROTATION_180, 270)65     ORIENTATIONS.append(Surface.ROTATION_180, 270);
ORIENTATIONS.append(Surface.ROTATION_270, 180)66     ORIENTATIONS.append(Surface.ROTATION_270, 180);
67   }
68 
69   /**
70    * {@link android.view.TextureView.SurfaceTextureListener} handles several lifecycle events on a
71    * {@link TextureView}.
72    */
73   private final TextureView.SurfaceTextureListener surfaceTextureListener =
74       new TextureView.SurfaceTextureListener() {
75         @Override
76         public void onSurfaceTextureAvailable(
77             final SurfaceTexture texture, final int width, final int height) {
78 
79           int index = getCameraId();
80           camera = Camera.open(index);
81 
82           try {
83             Camera.Parameters parameters = camera.getParameters();
84             List<String> focusModes = parameters.getSupportedFocusModes();
85             if (focusModes != null
86                 && focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
87               parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
88             }
89             List<Camera.Size> cameraSizes = parameters.getSupportedPreviewSizes();
90             Size[] sizes = new Size[cameraSizes.size()];
91             int i = 0;
92             for (Camera.Size size : cameraSizes) {
93               sizes[i++] = new Size(size.width, size.height);
94             }
95             Size previewSize =
96                 CameraConnectionFragment.chooseOptimalSize(
97                     sizes, desiredSize.getWidth(), desiredSize.getHeight());
98             parameters.setPreviewSize(previewSize.getWidth(), previewSize.getHeight());
99             camera.setDisplayOrientation(90);
100             camera.setParameters(parameters);
101             camera.setPreviewTexture(texture);
102           } catch (IOException exception) {
103             camera.release();
104           }
105 
106           camera.setPreviewCallbackWithBuffer(imageListener);
107           Camera.Size s = camera.getParameters().getPreviewSize();
108           camera.addCallbackBuffer(new byte[ImageUtils.getYUVByteSize(s.height, s.width)]);
109 
110           textureView.setAspectRatio(s.height, s.width);
111 
112           camera.startPreview();
113         }
114 
115         @Override
116         public void onSurfaceTextureSizeChanged(
117             final SurfaceTexture texture, final int width, final int height) {}
118 
119         @Override
120         public boolean onSurfaceTextureDestroyed(final SurfaceTexture texture) {
121           return true;
122         }
123 
124         @Override
125         public void onSurfaceTextureUpdated(final SurfaceTexture texture) {}
126       };
127 
128   /**
129    * An {@link AutoFitTextureView} for camera preview.
130    */
131   private AutoFitTextureView textureView;
132 
133   /**
134    * An additional thread for running tasks that shouldn't block the UI.
135    */
136   private HandlerThread backgroundThread;
137 
138   @Override
onCreateView( final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState)139   public View onCreateView(
140       final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
141     return inflater.inflate(layout, container, false);
142   }
143 
144   @Override
onViewCreated(final View view, final Bundle savedInstanceState)145   public void onViewCreated(final View view, final Bundle savedInstanceState) {
146     textureView = (AutoFitTextureView) view.findViewById(R.id.texture);
147   }
148 
149   @Override
onActivityCreated(final Bundle savedInstanceState)150   public void onActivityCreated(final Bundle savedInstanceState) {
151     super.onActivityCreated(savedInstanceState);
152   }
153 
154   @Override
onResume()155   public void onResume() {
156     super.onResume();
157     startBackgroundThread();
158     // When the screen is turned off and turned back on, the SurfaceTexture is already
159     // available, and "onSurfaceTextureAvailable" will not be called. In that case, we can open
160     // a camera and start preview from here (otherwise, we wait until the surface is ready in
161     // the SurfaceTextureListener).
162 
163     if (textureView.isAvailable()) {
164       camera.startPreview();
165     } else {
166       textureView.setSurfaceTextureListener(surfaceTextureListener);
167     }
168   }
169 
170   @Override
onPause()171   public void onPause() {
172     stopCamera();
173     stopBackgroundThread();
174     super.onPause();
175   }
176 
177   /**
178    * Starts a background thread and its {@link Handler}.
179    */
startBackgroundThread()180   private void startBackgroundThread() {
181     backgroundThread = new HandlerThread("CameraBackground");
182     backgroundThread.start();
183   }
184 
185   /**
186    * Stops the background thread and its {@link Handler}.
187    */
stopBackgroundThread()188   private void stopBackgroundThread() {
189     backgroundThread.quitSafely();
190     try {
191       backgroundThread.join();
192       backgroundThread = null;
193     } catch (final InterruptedException e) {
194       LOGGER.e(e, "Exception!");
195     }
196   }
197 
stopCamera()198   protected void stopCamera() {
199     if (camera != null) {
200       camera.stopPreview();
201       camera.setPreviewCallback(null);
202       camera.release();
203       camera = null;
204     }
205   }
206 
getCameraId()207   private int getCameraId() {
208     CameraInfo ci = new CameraInfo();
209     for (int i = 0; i < Camera.getNumberOfCameras(); i++) {
210       Camera.getCameraInfo(i, ci);
211       if (ci.facing == CameraInfo.CAMERA_FACING_BACK)
212         return i;
213     }
214     return -1; // No camera found
215   }
216 }
217