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