3package org.qtproject.qt.android.multimedia;
7import android.annotation.SuppressLint;
8import android.annotation.TargetApi;
9import android.content.Context;
10import android.graphics.Rect;
11import android.hardware.camera2.CameraAccessException;
12import android.hardware.camera2.CameraCaptureSession;
13import android.hardware.camera2.CameraDevice;
14import android.hardware.camera2.CameraMetadata;
15import android.hardware.camera2.CameraManager;
16import android.hardware.camera2.CaptureFailure;
17import android.hardware.camera2.CaptureResult;
18import android.hardware.camera2.CaptureRequest;
19import android.hardware.camera2.TotalCaptureResult;
20import android.media.Image;
21import android.media.ImageReader;
22import android.graphics.ImageFormat;
23import android.os.Handler;
24import android.os.HandlerThread;
25import android.util.Log;
26import android.view.Surface;
27import android.media.MediaCodec;
28import android.media.MediaCodecInfo;
29import android.media.MediaFormat;
30import java.util.ArrayList;
36 CameraDevice mCameraDevice =
null;
38 HandlerThread mBackgroundThread;
39 Handler mBackgroundHandler;
40 ImageReader mImageReader =
null;
41 ImageReader mCapturedPhotoReader =
null;
42 CameraManager mCameraManager;
43 CameraCaptureSession mCaptureSession;
44 CaptureRequest.Builder mPreviewRequestBuilder;
45 CaptureRequest mPreviewRequest;
47 List<Surface> mTargetSurfaces =
new ArrayList<>();
49 private static final int STATE_PREVIEW = 0;
50 private static final int STATE_WAITING_LOCK = 1;
51 private static final int STATE_WAITING_PRECAPTURE = 2;
52 private static final int STATE_WAITING_NON_PRECAPTURE = 3;
53 private static final int STATE_PICTURE_TAKEN = 4;
55 private int mState = STATE_PREVIEW;
57 private boolean mIsStarted =
false;
58 private static int MaxNumberFrames = 10;
59 private int mFlashMode = CaptureRequest.CONTROL_AE_MODE_ON;
60 private int mTorchMode = CameraMetadata.FLASH_MODE_OFF;
65 CameraDevice.StateCallback mStateCallback =
new CameraDevice.StateCallback() {
67 public void onOpened(CameraDevice cameraDevice) {
68 if (mCameraDevice !=
null)
69 mCameraDevice.close();
70 mCameraDevice = cameraDevice;
74 public void onDisconnected(CameraDevice cameraDevice) {
76 if (mCameraDevice == cameraDevice)
81 public void onError(CameraDevice cameraDevice,
int error) {
83 if (mCameraDevice == cameraDevice)
91 CameraCaptureSession.StateCallback mCaptureStateCallback =
new CameraCaptureSession.StateCallback() {
93 public void onConfigured(CameraCaptureSession cameraCaptureSession) {
94 mCaptureSession = cameraCaptureSession;
99 public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
104 public void onActive(CameraCaptureSession cameraCaptureSession) {
105 super.onActive(cameraCaptureSession);
110 public void onClosed(CameraCaptureSession cameraCaptureSession) {
111 super.onClosed(cameraCaptureSession);
119 CameraCaptureSession.CaptureCallback mCaptureCallback =
new CameraCaptureSession.CaptureCallback() {
120 public void onCaptureFailed(CameraCaptureSession session, CaptureRequest
request, CaptureFailure failure) {
121 super.onCaptureFailed(session,
request, failure);
125 private void process(CaptureResult
result) {
127 case STATE_WAITING_LOCK: {
128 Integer afState =
result.get(CaptureResult.CONTROL_AF_STATE);
129 if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
130 CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {
131 Integer aeState =
result.get(CaptureResult.CONTROL_AE_STATE);
132 if (aeState ==
null ||
133 aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
134 mState = STATE_PICTURE_TAKEN;
138 mPreviewRequestBuilder.set(
139 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
140 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
141 mState = STATE_WAITING_PRECAPTURE;
142 mCaptureSession.capture(mPreviewRequestBuilder.build(),
145 }
catch (CameraAccessException
e) {
146 Log.w(
"QtCamera2",
"Cannot get access to the camera: " +
e);
152 case STATE_WAITING_PRECAPTURE: {
153 Integer aeState =
result.get(CaptureResult.CONTROL_AE_STATE);
154 if (aeState ==
null || aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
155 mState = STATE_WAITING_NON_PRECAPTURE;
159 case STATE_WAITING_NON_PRECAPTURE: {
160 Integer aeState =
result.get(CaptureResult.CONTROL_AE_STATE);
161 if (aeState ==
null || aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
162 mState = STATE_PICTURE_TAKEN;
173 public void onCaptureProgressed(CameraCaptureSession
s, CaptureRequest
r, CaptureResult partialResult) {
174 process(partialResult);
178 public void onCaptureCompleted(CameraCaptureSession
s, CaptureRequest
r, TotalCaptureResult
result) {
184 mCameraManager = (CameraManager)
context.getSystemService(Context.CAMERA_SERVICE);
186 startBackgroundThread();
189 void startBackgroundThread() {
190 mBackgroundThread =
new HandlerThread(
"CameraBackground");
191 mBackgroundThread.start();
192 mBackgroundHandler =
new Handler(mBackgroundThread.getLooper());
195 void stopBackgroundThread() {
196 mBackgroundThread.quitSafely();
198 mBackgroundThread.join();
199 mBackgroundThread =
null;
200 mBackgroundHandler =
null;
201 }
catch (Exception
e) {
206 @SuppressLint(
"MissingPermission")
207 public
boolean open(String cameraId) {
209 mCameraId = cameraId;
210 mCameraManager.openCamera(cameraId,mStateCallback,mBackgroundHandler);
212 }
catch (Exception
e){
213 Log.w(
"QtCamera2",
"Failed to open camera:" +
e);
221 ImageReader.OnImageAvailableListener mOnPhotoAvailableListener =
new ImageReader.OnImageAvailableListener() {
223 public void onImageAvailable(ImageReader reader) {
224 QtCamera2.this.onPhotoAvailable(mCameraId, reader.acquireLatestImage());
230 ImageReader.OnImageAvailableListener mOnImageAvailableListener =
new ImageReader.OnImageAvailableListener() {
232 public void onImageAvailable(ImageReader reader) {
233 QtCamera2.this.onFrameAvailable(mCameraId, reader.acquireLatestImage());
239 if (mImageReader !=
null)
240 removeSurface(mImageReader.getSurface());
243 mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler);
244 addSurface(mImageReader.getSurface());
246 mCapturedPhotoReader = ImageReader.newInstance(
width,
height,
format, MaxNumberFrames);
247 mCapturedPhotoReader.setOnImageAvailableListener(mOnPhotoAvailableListener, mBackgroundHandler);
248 addSurface(mCapturedPhotoReader.getSurface());
254 if (mTargetSurfaces.contains(surface))
257 return mTargetSurfaces.add(surface);
261 return mTargetSurfaces.remove(surface);
265 mTargetSurfaces.clear();
269 if (mCameraDevice ==
null)
273 mCameraDevice.createCaptureSession(mTargetSurfaces, mCaptureStateCallback, mBackgroundHandler);
275 }
catch (Exception exception) {
276 Log.w(
"QtCamera2",
"Failed to create a capture session:" + exception);
281 public boolean start(
int template) {
283 if (mCameraDevice ==
null)
286 if (mCaptureSession ==
null)
289 synchronized (mStartMutex) {
291 mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(template);
292 mPreviewRequestBuilder.addTarget(mImageReader.getSurface());
294 mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, mFlashMode);
295 mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE, mTorchMode);
296 mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_IDLE);
297 mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
298 mPreviewRequestBuilder.set(CaptureRequest.CONTROL_CAPTURE_INTENT, CameraMetadata.CONTROL_CAPTURE_INTENT_VIDEO_RECORD);
300 mPreviewRequest = mPreviewRequestBuilder.build();
301 mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback, mBackgroundHandler);
305 }
catch (Exception exception) {
306 Log.w(
"QtCamera2",
"Failed to start preview:" + exception);
313 synchronized (mStartMutex) {
315 if (
null != mCaptureSession) {
316 mCaptureSession.close();
317 mCaptureSession =
null;
319 if (
null != mCameraDevice) {
320 mCameraDevice.close();
321 mCameraDevice =
null;
324 mTargetSurfaces.clear();
325 }
catch (Exception exception) {
326 Log.w(
"QtCamera2",
"Failed to stop and close:" + exception);
332 private void capturePhoto() {
334 final CaptureRequest.Builder captureBuilder =
335 mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
336 captureBuilder.addTarget(mCapturedPhotoReader.getSurface());
337 captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, mFlashMode);
339 CameraCaptureSession.CaptureCallback captureCallback
340 =
new CameraCaptureSession.CaptureCallback() {
342 public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest
request,
343 TotalCaptureResult
result) {
346 mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
347 CameraMetadata.CONTROL_AF_TRIGGER_IDLE);
348 mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
349 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE);
350 mPreviewRequest = mPreviewRequestBuilder.build();
351 mState = STATE_PREVIEW;
352 mCaptureSession.setRepeatingRequest(mPreviewRequest,
355 }
catch (CameraAccessException
e) {
361 mCaptureSession.capture(captureBuilder.build(), captureCallback, mBackgroundHandler);
362 }
catch (CameraAccessException
e) {
369 mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
370 mState = STATE_WAITING_LOCK;
371 mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
372 }
catch (CameraAccessException
e) {
373 Log.w(
"QtCamera2",
"Cannot get access to the camera: " +
e);
379 synchronized (mStartMutex) {
381 Log.w(
"QtCamera2",
"Cannot set zoom on invalid camera");
386 float zoomRatio = 1/factor;
387 int croppedWidth = activePixels.width() - (int)(activePixels.width() * zoomRatio);
388 int croppedHeight = activePixels.height() - (int)(activePixels.height() * zoomRatio);
389 Rect zoom =
new Rect(croppedWidth/2, croppedHeight/2, activePixels.width() - croppedWidth/2,
390 activePixels.height() - croppedHeight/2);
391 mPreviewRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, zoom);
392 mPreviewRequest = mPreviewRequestBuilder.build();
395 mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback, mBackgroundHandler);
396 }
catch (Exception exception) {
397 Log.w(
"QtCamera2",
"Failed to set zoom:" + exception);
403 synchronized (mStartMutex) {
406 if (flashModeValue < 0) {
407 Log.w(
"QtCamera2",
"Unknown flash mode");
410 mFlashMode = flashModeValue;
415 mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, mFlashMode);
416 mPreviewRequest = mPreviewRequestBuilder.build();
419 mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback, mBackgroundHandler);
420 }
catch (Exception exception) {
421 Log.w(
"QtCamera2",
"Failed to set flash mode:" + exception);
426 private int getTorchModeValue(
boolean mode)
428 return mode ? CameraMetadata.FLASH_MODE_TORCH : CameraMetadata.FLASH_MODE_OFF;
433 synchronized (mStartMutex) {
434 mTorchMode = getTorchModeValue(torchMode);
437 mPreviewRequestBuilder.set(CaptureRequest.FLASH_MODE, mTorchMode);
438 mPreviewRequest = mPreviewRequestBuilder.build();
441 mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback, mBackgroundHandler);
442 }
catch (Exception exception) {
443 Log.w(
"QtCamera2",
"Failed to set flash mode:" + exception);
static void onFrameAvailable(JNIEnv *env, jobject obj, jstring cameraId, QtJniTypes::AndroidImage image)
static void onCaptureSessionFailed(JNIEnv *env, jobject obj, jstring cameraId, jint reason, jlong framenumber)
static void onSessionClosed(JNIEnv *env, jobject obj, jstring cameraId)
static void onPhotoAvailable(JNIEnv *env, jobject obj, jstring cameraId, QtJniTypes::AndroidImage image)
static void onCameraError(JNIEnv *env, jobject obj, jstring cameraId, jint error)
static void onCaptureSessionConfigureFailed(JNIEnv *env, jobject obj, jstring cameraId)
static void onCameraOpened(JNIEnv *env, jobject obj, jstring cameraId)
static void onSessionActive(JNIEnv *env, jobject obj, jstring cameraId)
static void onCameraDisconnect(JNIEnv *env, jobject obj, jstring cameraId)
static void onCaptureSessionConfigured(JNIEnv *env, jobject obj, jstring cameraId)
DBusConnection const char DBusError * error
GLint GLsizei GLsizei height
GLint GLsizei GLsizei GLenum format
file open(QIODevice::ReadOnly)
QNetworkRequest request(url)