Skip to content

Commit 3a16edc

Browse files
committed
Support take still picture while preview is on-going
1 parent 01812b9 commit 3a16edc

File tree

3 files changed

+64
-28
lines changed

3 files changed

+64
-28
lines changed

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# CameraDemoForAndroidThings
22

3-
Camera demo for android things, current support capture still picture as well as camera preview.
3+
Camera demo for android things, current support capture still picture, camera preview as well as capture still picture while preview is on-going.
44

55
## Schematics
66

@@ -12,6 +12,8 @@ Key process of setup camera preview extract from example [Android Camera2 Exampl
1212

1313
In order to support camera preview, you should enable hardware acceleration for your `Activity` or `Application`. More information about hardware acceleration, please refer to [Android Things Realse Notes][AndroidThingsRleaseNotes] and [Android Hardware Acceleration][HardwareAcceleration].
1414

15+
Take still picture while preview is on-going will close the preview capture session first and renew a preview capture session after picture is taken. This is because `V4L2 only supports 1 stream configuration at a time`, so we can not pass more than one `Surface` like `ImageReader.getSurface()` when we call `CameraDevice.createCaptureSession(...)`.
16+
1517
## Capture still picutre support
1618

1719
Key process of capture still picture extract from example [Doorbell][Doorbell].
@@ -32,7 +34,7 @@ In `TakePictureActivity`:
3234

3335
In `CameraPreviewActivity`:
3436

35-
- Button A: current not defined (*maybe trigger take still picture while preview is going on.*)
37+
- Button A: trigger take still picture while preview is on-going
3638
- Button B: return to `MainActivity`
3739

3840

app/src/main/java/com/example/chenwei/androidthingscamerademo/CameraPreviewActivity.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,8 @@ class CameraPreviewActivity : Activity() {
9494

9595
override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean {
9696
if (keyCode == KeyEvent.KEYCODE_A) {
97-
// TODO: start camera preview
97+
Log.d(TAG, "Take picture while preview")
98+
mCamera.tackPicture()
9899
return true
99100
}
100101
if (keyCode == KeyEvent.KEYCODE_B) {
@@ -148,5 +149,14 @@ class CameraPreviewActivity : Activity() {
148149

149150
private val mOnImageAvailableListener = ImageReader.OnImageAvailableListener { reader ->
150151
Log.d(TAG, "Image available now")
152+
// Do whatever you want here with the new still picture.
153+
/*
154+
val image = reader.acquireLatestImage()
155+
val imageBuf = image.planes[0].buffer
156+
val imageBytes = ByteArray(imageBuf.remaining())
157+
imageBuf.get(imageBytes)
158+
image.close()
159+
Log.d(TAG, "Still image size: ${imageBytes.size}")
160+
*/
151161
}
152162
}

app/src/main/java/com/example/chenwei/androidthingscamerademo/DemoCamera.kt

Lines changed: 49 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class DemoCamera(private val mImageAvailableListener: ImageReader.OnImageAvailab
2525
private var mImageReader: ImageReader? = null
2626
private var mCameraDevice: CameraDevice? = null
2727
private var mCaptureSession: CameraCaptureSession? = null
28+
private var mCaptureSessionForImage: CameraCaptureSession? = null
2829
private var mPreviewSize: Size? = null
2930
private var mFlashSupported = false
3031
private var mSupportedAFModes: IntArray = kotlin.IntArray(0)
@@ -53,11 +54,19 @@ class DemoCamera(private val mImageAvailableListener: ImageReader.OnImageAvailab
5354
// Nothing to do
5455
}
5556
STATE.STATE_PICTURE_TAKEN -> {
56-
session.close()
57+
// session may not equal to mCaptureSessionForImage when take picture while
58+
// preview. In this case, leave session as it is, it will close automatically
59+
// because next call of createCaptureSession(...) will cause the previous
60+
// session to close according to the API of CameraDevice:
61+
// https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#createCaptureSession(java.util.List<android.view.Surface>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler)
62+
if (mCaptureSessionForImage == session) {
63+
Log.d(TAG, "Close take picture session: $session")
64+
session.close()
65+
}
5766
mCaptureSession = null
58-
Log.d(TAG, "CaptureSession closed")
5967
// Reset to preview state
6068
mState = STATE.STATE_PREVIEW
69+
createPreviewSession()
6170
}
6271
}
6372
}
@@ -259,19 +268,27 @@ class DemoCamera(private val mImageAvailableListener: ImageReader.OnImageAvailab
259268
Log.d(TAG, "Cannot capture image. Camera not initialized")
260269
return
261270
}
271+
mCaptureSession?.stopRepeating()
272+
mCaptureSession?.abortCaptures()
262273
try {
263274
mCameraDevice!!.createCaptureSession(Collections.singletonList(mImageReader!!.surface),
264275
object : CameraCaptureSession.StateCallback() {
276+
override fun onClosed(session: CameraCaptureSession?) {
277+
Log.d(TAG, "Take picture session closed, session: $session")
278+
mCaptureSessionForImage = null
279+
}
280+
265281
override fun onConfigureFailed(session: CameraCaptureSession?) {
266-
Log.d(TAG, "Failed to configure camera")
282+
Log.d(TAG, "Failed to configure take picture session: $session")
267283
}
268284

269285
override fun onConfigured(session: CameraCaptureSession?) {
270286
if (mCameraDevice == null) {
271287
return
272288
}
273289
mCaptureSession = session
274-
Log.d(TAG, "Session initialized")
290+
mCaptureSessionForImage = session
291+
Log.d(TAG, "Take picture session initialized, session: $session")
275292
triggerImageCapture()
276293
}
277294
}, null)
@@ -289,6 +306,7 @@ class DemoCamera(private val mImageAvailableListener: ImageReader.OnImageAvailab
289306
captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON)
290307
}
291308
mState = STATE.STATE_PICTURE_TAKEN
309+
Log.d(TAG, "Use session to capture picture, session: $mCaptureSession")
292310
mCaptureSession!!.capture(captureBuilder.build(), mCaptureCallback, null)
293311
} catch (ex: CameraAccessException) {
294312
Log.d(TAG, "Camera capture exception", ex)
@@ -303,28 +321,34 @@ class DemoCamera(private val mImageAvailableListener: ImageReader.OnImageAvailab
303321
texture.setDefaultBufferSize(mPreviewSize!!.width, mPreviewSize!!.height)
304322
val surface = Surface(texture)
305323

306-
mCameraDevice!!.createCaptureSession(Collections.singletonList(surface), object : CameraCaptureSession.StateCallback() {
307-
override fun onConfigureFailed(session: CameraCaptureSession) {
308-
Log.d(TAG, "Create preview capture session failed")
309-
}
324+
// V4L2CameraHAL: setupStreams:384: V4L2 only supports 1 stream configuration at a time
325+
mCameraDevice!!.createCaptureSession(Collections.singletonList(surface),
326+
object : CameraCaptureSession.StateCallback() {
327+
override fun onClosed(session: CameraCaptureSession?) {
328+
Log.d(TAG, "Camera preview session closed, session: $session")
329+
}
310330

311-
override fun onConfigured(session: CameraCaptureSession?) {
312-
if (mCameraDevice == null) {
313-
return
314-
}
315-
mCaptureSession = session
316-
Log.d(TAG, "Camera preview session initialized")
317-
318-
mPreviewRequestBuilder = mCameraDevice!!.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
319-
mPreviewRequestBuilder!!.addTarget(surface)
320-
setAutoFlash(mPreviewRequestBuilder!!)
321-
if (CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE in mSupportedAFModes) {
322-
mPreviewRequestBuilder!!.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)
323-
}
324-
mPreviewRequest = mPreviewRequestBuilder!!.build()
325-
mCaptureSession!!.setRepeatingRequest(mPreviewRequest, mCaptureCallback, mBackgroundHandler)
326-
}
327-
}, null)
331+
override fun onConfigureFailed(session: CameraCaptureSession) {
332+
Log.d(TAG, "Create preview capture session failed, session: $session")
333+
}
334+
335+
override fun onConfigured(session: CameraCaptureSession?) {
336+
if (mCameraDevice == null) {
337+
return
338+
}
339+
mCaptureSession = session
340+
Log.d(TAG, "Camera preview session initialized, session: $session")
341+
342+
mPreviewRequestBuilder = mCameraDevice!!.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
343+
mPreviewRequestBuilder!!.addTarget(surface)
344+
setAutoFlash(mPreviewRequestBuilder!!)
345+
if (CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE in mSupportedAFModes) {
346+
mPreviewRequestBuilder!!.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE)
347+
}
348+
mPreviewRequest = mPreviewRequestBuilder!!.build()
349+
mCaptureSession!!.setRepeatingRequest(mPreviewRequest, mCaptureCallback, mBackgroundHandler)
350+
}
351+
}, null)
328352
}
329353

330354
private fun setAutoFlash(requestBuilder: CaptureRequest.Builder) {

0 commit comments

Comments
 (0)