Support for Android, API >= 24, WIP

This commit is contained in:
Milan Nikolic
2020-11-03 19:36:26 +01:00
parent 19ea541157
commit fc22ce5871

View File

@@ -17,8 +17,11 @@ package camera
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__) #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
AImage *image;
AImageReader *imageReader; AImageReader *imageReader;
ANativeWindow *nativeWindow;
ACameraDevice *cameraDevice; ACameraDevice *cameraDevice;
ACameraManager *cameraManager; ACameraManager *cameraManager;
ACameraOutputTarget *cameraOutputTarget; ACameraOutputTarget *cameraOutputTarget;
@@ -28,45 +31,52 @@ ACaptureRequest *captureRequest;
ACaptureSessionOutput *captureSessionOutput; ACaptureSessionOutput *captureSessionOutput;
ACaptureSessionOutputContainer *captureSessionOutputContainer; ACaptureSessionOutputContainer *captureSessionOutputContainer;
ACameraDevice_StateCallbacks deviceStateCallbacks; void device_on_disconnected(void *context, ACameraDevice *device) {
ACameraCaptureSession_stateCallbacks captureSessionStateCallbacks;
uint8_t *image_data;
int image_len = 0;
void camera_device_on_disconnected(void *context, ACameraDevice *device) {
LOGI("camera %s is diconnected.\n", ACameraDevice_getId(device)); LOGI("camera %s is diconnected.\n", ACameraDevice_getId(device));
} }
void camera_device_on_error(void *context, ACameraDevice *device, int error) { void device_on_error(void *context, ACameraDevice *device, int error) {
LOGE("error %d on camera %s.\n", error, ACameraDevice_getId(device)); LOGE("error %d on camera %s.\n", error, ACameraDevice_getId(device));
} }
void capture_session_on_ready(void *context, ACameraCaptureSession *session) { ACameraDevice_stateCallbacks deviceStateCallbacks = {
.context = NULL,
.onDisconnected = device_on_disconnected,
.onError = device_on_error,
};
void session_on_ready(void *context, ACameraCaptureSession *session) {
LOGI("session is ready. %p\n", session); LOGI("session is ready. %p\n", session);
} }
void capture_session_on_active(void *context, ACameraCaptureSession *session) { void session_on_active(void *context, ACameraCaptureSession *session) {
LOGI("session is activated. %p\n", session); LOGI("session is activated. %p\n", session);
} }
void capture_session_on_closed(void *context, ACameraCaptureSession *session) { void session_on_closed(void *context, ACameraCaptureSession *session) {
LOGI("session is closed. %p\n", session); LOGI("session is closed. %p\n", session);
} }
void imageCallback(void* context, AImageReader* reader) { ACameraCaptureSession_stateCallbacks captureSessionStateCallbacks = {
LOGD("imageCallback"); .context = NULL,
.onActive = session_on_active,
.onReady = session_on_ready,
.onClosed = session_on_closed,
};
AImage *image; void image_callback(void *context, AImageReader *reader) {
media_status_t status = AImageReader_acquireNextImage(reader, &image); LOGD("image_callback");
if(status != ACAMERA_OK) {
media_status_t status = AImageReader_acquireLatestImage(reader, &image);
if(status != AMEDIA_OK) {
LOGE("failed to acquire next image (reason: %d).\n", status); LOGE("failed to acquire next image (reason: %d).\n", status);
return; }
} }
AImage_getPlaneData(image, 0, &image_data, &image_len); AImageReader_ImageListener imageListener = {
AImage_delete(image); .context = NULL,
} .onImageAvailable = image_callback,
};
int openCamera(int index, int width, int height) { int openCamera(int index, int width, int height) {
ACameraIdList *cameraIdList; ACameraIdList *cameraIdList;
@@ -74,7 +84,7 @@ int openCamera(int index, int width, int height) {
camera_status_t status = ACAMERA_OK; camera_status_t status = ACAMERA_OK;
ACameraManager *cameraManager = ACameraManager_create(); cameraManager = ACameraManager_create();
status = ACameraManager_getCameraIdList(cameraManager, &cameraIdList); status = ACameraManager_getCameraIdList(cameraManager, &cameraIdList);
if(status != ACAMERA_OK) { if(status != ACAMERA_OK) {
@@ -93,49 +103,50 @@ int openCamera(int index, int width, int height) {
selectedCameraId = cameraIdList->cameraIds[index]; selectedCameraId = cameraIdList->cameraIds[index];
LOGI("open camera (id: %s, num of cameras: %d).\n", selectedCameraId, cameraIdList->numCameras); LOGI("open camera (id: %s, num of cameras: %d).\n", selectedCameraId, cameraIdList->numCameras);
deviceStateCallbacks.onDisconnected = camera_device_on_disconnected;
deviceStateCallbacks.onError = camera_device_on_error;
status = ACameraManager_openCamera(cameraManager, selectedCameraId, &deviceStateCallbacks, &cameraDevice); status = ACameraManager_openCamera(cameraManager, selectedCameraId, &deviceStateCallbacks, &cameraDevice);
if(status != ACAMERA_OK) { if(status != ACAMERA_OK) {
LOGE("failed to open camera device (id: %s)\n", selectedCameraId); LOGE("failed to open camera device (id: %s)\n", selectedCameraId);
return status; return status;
} }
status = ACameraDevice_createCaptureRequest(cameraDevice, TEMPLATE_VIDEO_SNAPSHOT, &captureRequest); status = ACameraDevice_createCaptureRequest(cameraDevice, TEMPLATE_STILL_CAPTURE, &captureRequest);
if(status != ACAMERA_OK) { if(status != ACAMERA_OK) {
LOGE("failed to create snapshot capture request (id: %s)\n", selectedCameraId); LOGE("failed to create snapshot capture request (id: %s)\n", selectedCameraId);
return status; return status;
} }
ACaptureSessionOutputContainer_create(&captureSessionOutputContainer); status = ACaptureSessionOutputContainer_create(&captureSessionOutputContainer);
if(status != ACAMERA_OK) {
LOGE("failed to create session output container (id: %s)\n", selectedCameraId);
return status;
}
captureSessionStateCallbacks.onReady = capture_session_on_ready; media_status_t mstatus = AImageReader_new(width, height, AIMAGE_FORMAT_YUV_420_888, 2, &imageReader);
captureSessionStateCallbacks.onActive = capture_session_on_active; if(mstatus != AMEDIA_OK) {
captureSessionStateCallbacks.onClosed = capture_session_on_closed; LOGE("failed to create image reader (reason: %d).\n", mstatus);
media_status_t mstatus = AImageReader_new(width, height, AIMAGE_FORMAT_RGBA_8888, 1, &imageReader);
if(mstatus != ACAMERA_OK) {
LOGE("failed to create image reader (reason: %d).\n", status);
return mstatus; return mstatus;
} }
AImageReader_ImageListener listener = { mstatus = AImageReader_setImageListener(imageReader, &imageListener);
.context = NULL, if(mstatus != AMEDIA_OK) {
.onImageAvailable = imageCallback, LOGE("failed to set image listener (reason: %d).\n", mstatus);
}; return mstatus;
}
AImageReader_setImageListener(imageReader, &listener);
ANativeWindow *nativeWindow;
AImageReader_getWindow(imageReader, &nativeWindow); AImageReader_getWindow(imageReader, &nativeWindow);
ANativeWindow_acquire(nativeWindow); ANativeWindow_acquire(nativeWindow);
ACameraOutputTarget_create(nativeWindow, &cameraOutputTarget); ACameraOutputTarget_create(nativeWindow, &cameraOutputTarget);
ACaptureRequest_addTarget(captureRequest, cameraOutputTarget); ACaptureRequest_addTarget(captureRequest, cameraOutputTarget);
ACaptureSessionOutput_create(nativeWindow, &captureSessionOutput);
ACameraDevice_createCaptureSession(cameraDevice, captureSessionOutputContainer, &captureSessionStateCallbacks, &cameraCaptureSession); ACaptureSessionOutput_create(nativeWindow, &captureSessionOutput);
ACaptureSessionOutputContainer_add(captureSessionOutputContainer, captureSessionOutput);
status = ACameraDevice_createCaptureSession(cameraDevice, captureSessionOutputContainer, &captureSessionStateCallbacks, &cameraCaptureSession);
if(status != ACAMERA_OK) {
LOGE("failed to create capture session (reason: %d).\n", status);
return status;
}
ACameraManager_deleteCameraIdList(cameraIdList); ACameraManager_deleteCameraIdList(cameraIdList);
ACameraManager_delete(cameraManager); ACameraManager_delete(cameraManager);
@@ -152,7 +163,7 @@ int captureCamera() {
return status; return status;
} }
void closeCamera() { int closeCamera() {
camera_status_t status = ACAMERA_OK; camera_status_t status = ACAMERA_OK;
if(captureRequest != NULL) { if(captureRequest != NULL) {
@@ -170,6 +181,7 @@ void closeCamera() {
if(status != ACAMERA_OK) { if(status != ACAMERA_OK) {
LOGE("failed to close camera device.\n"); LOGE("failed to close camera device.\n");
return status;
} }
cameraDevice = NULL; cameraDevice = NULL;
@@ -190,12 +202,18 @@ void closeCamera() {
imageReader = NULL; imageReader = NULL;
} }
if(image != NULL) {
AImage_delete(image);
image = NULL;
}
LOGI("camera closed.\n"); LOGI("camera closed.\n");
return ACAMERA_OK;
} }
int openCamera(int index, int width, int height); int openCamera(int index, int width, int height);
int captureCamera(); int captureCamera();
void closeCamera(); int closeCamera();
#cgo android CFLAGS: -D__ANDROID_API__=24 #cgo android CFLAGS: -D__ANDROID_API__=24
#cgo android LDFLAGS: -lcamera2ndk -lmediandk -llog -landroid #cgo android LDFLAGS: -lcamera2ndk -lmediandk -llog -landroid
@@ -211,7 +229,7 @@ import (
// Camera represents camera. // Camera represents camera.
type Camera struct { type Camera struct {
opts Options opts Options
img *image.RGBA img *image.YCbCr
} }
// New returns new Camera for given camera index. // New returns new Camera for given camera index.
@@ -219,7 +237,7 @@ func New(opts Options) (camera *Camera, err error) {
camera = &Camera{} camera = &Camera{}
camera.opts = opts camera.opts = opts
camera.img = image.NewRGBA(image.Rect(0, 0, int(opts.Width), int(opts.Height))) camera.img = image.NewYCbCr(image.Rect(0, 0, int(opts.Width), int(opts.Height)), image.YCbCrSubsampleRatio420)
ret := C.openCamera(C.int(opts.Index), C.int(opts.Width), C.int(opts.Height)) ret := C.openCamera(C.int(opts.Index), C.int(opts.Width), C.int(opts.Height))
if bool(int(ret) != 0) { if bool(int(ret) != 0) {
@@ -238,11 +256,29 @@ func (c *Camera) Read() (img image.Image, err error) {
return return
} }
if C.image_data != nil { if C.image == nil {
c.img.Pix = (*[1 << 24]uint8)(unsafe.Pointer(&C.image_data))[0:int(C.image_len)] err = fmt.Errorf("camera: can not retrieve frame")
img = c.img return
} }
var yStride C.int
var yLen, cbLen, crLen C.int
var yPtr, cbPtr, crPtr *C.uint8_t
C.AImage_getPlaneRowStride(C.image, 0, &yStride)
C.AImage_getPlaneData(C.image, 0, &yPtr, &yLen)
C.AImage_getPlaneData(C.image, 1, &cbPtr, &cbLen)
C.AImage_getPlaneData(C.image, 2, &crPtr, &crLen)
c.img.YStride = int(yStride)
c.img.CStride = int(yStride) / 2
c.img.Y = C.GoBytes(unsafe.Pointer(yPtr), yLen)
c.img.Cb = C.GoBytes(unsafe.Pointer(cbPtr), cbLen)
c.img.Cr = C.GoBytes(unsafe.Pointer(crPtr), crLen)
img = c.img
return return
} }
@@ -257,7 +293,11 @@ func (c *Camera) SetProperty(id int, value float64) {
// Close closes camera. // Close closes camera.
func (c *Camera) Close() (err error) { func (c *Camera) Close() (err error) {
C.closeCamera() ret := C.closeCamera()
if bool(int(ret) != 0) {
err = fmt.Errorf("camera: can not close camera %d: error %d", c.opts.Index, int(ret))
return
}
return return
} }