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