1/* 2 * Copyright 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package androidx.media.filterfw.samples.simplecamera; 18 19import android.content.Context; 20import android.graphics.Bitmap; 21import android.graphics.ImageFormat; 22import android.hardware.camera2.CameraAccessException; 23import android.hardware.camera2.CameraCharacteristics; 24import android.hardware.camera2.CameraDevice; 25import android.hardware.camera2.CameraCaptureSession; 26import android.hardware.camera2.CameraManager; 27import android.hardware.camera2.CaptureFailure; 28import android.hardware.camera2.CaptureRequest; 29import android.hardware.camera2.CaptureResult; 30import android.hardware.camera2.TotalCaptureResult; 31import android.os.Handler; 32import android.renderscript.Allocation; 33import android.renderscript.Element; 34import android.renderscript.RenderScript; 35import android.renderscript.ScriptIntrinsicYuvToRGB; 36import android.renderscript.Type; 37import android.util.Log; 38import android.view.Surface; 39import com.android.ex.camera2.blocking.BlockingCameraManager; 40import com.android.ex.camera2.blocking.BlockingCameraManager.BlockingOpenException; 41import com.android.ex.camera2.blocking.BlockingSessionCallback; 42import androidx.media.filterfw.Filter; 43import androidx.media.filterfw.Frame; 44import androidx.media.filterfw.FrameImage2D; 45import androidx.media.filterfw.FrameType; 46import androidx.media.filterfw.FrameValue; 47import androidx.media.filterfw.MffContext; 48import androidx.media.filterfw.OutputPort; 49import androidx.media.filterfw.Signature; 50 51import java.util.ArrayList; 52import java.util.List; 53 54public class Camera2Source extends Filter implements Allocation.OnBufferAvailableListener { 55 56 private boolean mNewFrameAvailable = false; 57 private FrameType mOutputType; 58 private static final String TAG = "Camera2Source"; 59 private CameraManager mCameraManager; 60 private CameraDevice mCamera; 61 private CameraCaptureSession mCameraSession; 62 private RenderScript mRS; 63 private Surface mSurface; 64 private CameraCharacteristics mProperties; 65 private CameraTestThread mLooperThread; 66 private int mHeight = 480; 67 private int mWidth = 640; 68 private Allocation mAllocationIn; 69 private ScriptIntrinsicYuvToRGB rgbConverter; 70 private Allocation mAllocationOut; 71 private Bitmap mBitmap; 72 73 private static final long SESSION_TIMEOUT_MS = 2000; 74 75 class MyCameraListener extends CameraManager.AvailabilityCallback { 76 77 @Override 78 public void onCameraAvailable(String cameraId) { 79 // TODO Auto-generated method stub 80 Log.v(TAG, "camera available to open"); 81 } 82 83 @Override 84 public void onCameraUnavailable(String cameraId) { 85 // TODO Auto-generated method stub 86 Log.v(TAG, "camera unavailable to open"); 87 } 88 89 } 90 91 class MyCaptureCallback extends CameraCaptureSession.CaptureCallback { 92 93 @Override 94 public void onCaptureCompleted(CameraCaptureSession camera, CaptureRequest request, 95 TotalCaptureResult result) { 96 // TODO Auto-generated method stub 97 Log.v(TAG, "in onCaptureComplete"); 98 99 } 100 101 @Override 102 public void onCaptureFailed(CameraCaptureSession camera, CaptureRequest request, 103 CaptureFailure failure) { 104 // TODO Auto-generated method stub 105 Log.v(TAG, "onCaptureFailed is being called"); 106 } 107 108 } 109 110 public Camera2Source(MffContext context, String name) { 111 super(context, name); 112 mOutputType = FrameType.image2D(FrameType.ELEMENT_RGBA8888, FrameType.WRITE_GPU); 113 114 Context ctx = context.getApplicationContext(); 115 mCameraManager = (CameraManager) ctx.getSystemService(Context.CAMERA_SERVICE); 116 117 mRS = RenderScript.create(context.getApplicationContext()); 118 } 119 120 @Override 121 public Signature getSignature() { 122 return new Signature() 123 .addOutputPort("timestamp", Signature.PORT_OPTIONAL, FrameType.single(long.class)) 124 .addOutputPort("video", Signature.PORT_REQUIRED, mOutputType) 125 .addOutputPort("orientation", Signature.PORT_REQUIRED, 126 FrameType.single(float.class)) 127 .disallowOtherPorts(); 128 } 129 130 @Override 131 protected void onClose() { 132 Log.v(TAG, "onClose being called"); 133 try { 134 mCamera.close(); 135 mSurface.release(); 136 mLooperThread.close(); 137 } catch (Exception e) { 138 // TODO Auto-generated catch block 139 e.printStackTrace(); 140 } 141 } 142 143 @Override 144 protected void onOpen() { 145 mLooperThread = new CameraTestThread(); 146 Handler mHandler; 147 try { 148 mHandler = mLooperThread.start(); 149 } catch (Exception e) { 150 // TODO Auto-generated catch block 151 e.printStackTrace(); 152 throw new RuntimeException(e); 153 } 154 155 try { 156 String backCameraId = "0"; 157 BlockingCameraManager blkManager = new BlockingCameraManager(mCameraManager); 158 mCamera = blkManager.openCamera(backCameraId, /*listener*/null, mHandler); 159 } catch (CameraAccessException e) { 160 e.printStackTrace(); 161 throw new RuntimeException(e); 162 } catch (BlockingOpenException e) { 163 e.printStackTrace(); 164 throw new RuntimeException(e); 165 } 166 167 Element ele = Element.createPixel(mRS, Element.DataType.UNSIGNED_8, 168 Element.DataKind.PIXEL_YUV); 169 170 rgbConverter = ScriptIntrinsicYuvToRGB.create(mRS,ele); 171 Type.Builder yuvBuilder = new Type.Builder(mRS,ele); 172 173 yuvBuilder.setYuvFormat(ImageFormat.YUV_420_888); 174 yuvBuilder.setX(mWidth); 175 yuvBuilder.setY(mHeight); 176 mAllocationIn = Allocation.createTyped(mRS, yuvBuilder.create(), 177 Allocation.USAGE_SCRIPT | Allocation.USAGE_IO_INPUT); 178 mSurface = mAllocationIn.getSurface(); 179 mAllocationIn.setOnBufferAvailableListener(this); 180 rgbConverter.setInput(mAllocationIn); 181 182 mBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888); 183 mAllocationOut = Allocation.createFromBitmap(mRS, mBitmap); 184 185 186 Log.v(TAG, "mcamera: " + mCamera); 187 188 List<Surface> surfaces = new ArrayList<Surface>(); 189 surfaces.add(mSurface); 190 CaptureRequest.Builder mCaptureRequest = null; 191 try { 192 BlockingSessionCallback blkSession = new BlockingSessionCallback(); 193 194 mCamera.createCaptureSession(surfaces, blkSession, mHandler); 195 mCaptureRequest = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 196 mCaptureRequest.addTarget(mSurface); 197 198 mCameraSession = blkSession.waitAndGetSession(SESSION_TIMEOUT_MS); 199 200 } catch (CameraAccessException e) { 201 e.printStackTrace(); 202 throw new RuntimeException(e); 203 } 204 205 try { 206 mCameraSession.setRepeatingRequest(mCaptureRequest.build(), new MyCaptureCallback(), 207 mHandler); 208 } catch (CameraAccessException e) { 209 e.printStackTrace(); 210 throw new RuntimeException(e); 211 } 212 mProperties = null; 213 try { 214 mProperties = mCameraManager.getCameraCharacteristics(mCamera.getId()); 215 } catch (CameraAccessException e) { 216 e.printStackTrace(); 217 throw new RuntimeException(e); 218 } 219 220 } 221 222 @Override 223 protected void onProcess() { 224 Log.v(TAG, "on Process"); 225 if (nextFrame()) { 226 OutputPort outPort = getConnectedOutputPort("video"); 227 228 // Create a 2D frame that will hold the output 229 int[] dims = new int[] { 230 mWidth, mHeight 231 }; 232 FrameImage2D outputFrame = Frame.create(mOutputType, dims).asFrameImage2D(); 233 rgbConverter.forEach(mAllocationOut); 234 mAllocationOut.copyTo(mBitmap); 235 outputFrame.setBitmap(mBitmap); 236 outPort.pushFrame(outputFrame); 237 outputFrame.release(); 238 239 OutputPort orientationPort = getConnectedOutputPort("orientation"); 240 FrameValue orientationFrame = orientationPort.fetchAvailableFrame(null).asFrameValue(); 241 242 // FIXME: Hardcoded value because ORIENTATION returns null, Qualcomm 243 // bug 244 Integer orientation = mProperties.get(CameraCharacteristics.SENSOR_ORIENTATION); 245 float temp; 246 if (orientation != null) { 247 temp = orientation.floatValue(); 248 } else { 249 temp = 90.0f; 250 } 251 orientationFrame.setValue(temp); 252 orientationPort.pushFrame(orientationFrame); 253 } 254 } 255 256 private synchronized boolean nextFrame() { 257 boolean frameAvailable = mNewFrameAvailable; 258 if (frameAvailable) { 259 mNewFrameAvailable = false; 260 } else { 261 enterSleepState(); 262 } 263 return frameAvailable; 264 } 265 266 public void onBufferAvailable(Allocation a) { 267 Log.v(TAG, "on Buffer Available"); 268 a.ioReceive(); 269 synchronized (this) { 270 mNewFrameAvailable = true; 271 } 272 wakeUp(); 273 } 274 275 276} 277