25 #include <stdatomic.h>
30 #include <camera/NdkCameraDevice.h>
31 #include <camera/NdkCameraManager.h>
32 #include <media/NdkImage.h>
33 #include <media/NdkImageReader.h>
49 #define IMAGE_FORMAT_ANDROID AIMAGE_FORMAT_YUV_420_888
51 #define MAX_BUF_COUNT 2
52 #define VIDEO_STREAM_INDEX 0
53 #define VIDEO_TIMEBASE_ANDROID 1000000000
55 #define RETURN_CASE(x) case x: return AV_STRINGIFY(x);
56 #define RETURN_DEFAULT(x) default: return AV_STRINGIFY(x);
153 return "ERROR_CAMERA_UNKNOWN";
163 ACameraDevice_getId(device));
179 ACameraIdList *camera_ids;
181 ret = ACameraManager_getCameraIdList(
ctx->camera_mgr, &camera_ids);
182 if (
ret != ACAMERA_OK) {
188 if (
ctx->camera_index < camera_ids->numCameras) {
190 if (!
ctx->camera_id) {
200 ACameraManager_deleteCameraIdList(camera_ids);
202 ret = ACameraManager_getCameraCharacteristics(
ctx->camera_mgr,
203 ctx->camera_id, &
ctx->camera_metadata);
204 if (
ret != ACAMERA_OK) {
205 av_log(avctx,
AV_LOG_ERROR,
"Failed to get metadata for camera with id %s, error: %s.\n",
210 ctx->camera_state_callbacks.context = avctx;
214 ret = ACameraManager_openCamera(
ctx->camera_mgr,
ctx->camera_id,
215 &
ctx->camera_state_callbacks, &
ctx->camera_dev);
216 if (
ret != ACAMERA_OK) {
228 ACameraMetadata_const_entry lens_facing;
229 ACameraMetadata_const_entry sensor_orientation;
231 ACameraMetadata_getConstEntry(
ctx->camera_metadata,
232 ACAMERA_LENS_FACING, &lens_facing);
233 ACameraMetadata_getConstEntry(
ctx->camera_metadata,
234 ACAMERA_SENSOR_ORIENTATION, &sensor_orientation);
236 ctx->lens_facing = lens_facing.data.u8[0];
237 ctx->sensor_orientation = sensor_orientation.data.i32[0];
243 ACameraMetadata_const_entry available_configs;
246 ACameraMetadata_getConstEntry(
ctx->camera_metadata,
247 ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
250 for (
int i = 0;
i < available_configs.count;
i++) {
273 if (!found ||
ctx->width == 0 ||
ctx->height == 0) {
274 ctx->width = available_configs.data.i32[1];
275 ctx->height = available_configs.data.i32[2];
278 "Requested video_size %dx%d not available, falling back to %dx%d\n",
279 ctx->requested_width,
ctx->requested_height,
ctx->width,
ctx->height);
288 ACameraMetadata_const_entry available_framerates;
290 int current_best_match = -1;
291 int requested_framerate =
av_q2d(
ctx->framerate);
293 ACameraMetadata_getConstEntry(
ctx->camera_metadata,
294 ACAMERA_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
295 &available_framerates);
297 for (
int i = 0;
i < available_framerates.count;
i++) {
298 int32_t min = available_framerates.data.i32[
i * 2 + 0];
299 int32_t max = available_framerates.data.i32[
i * 2 + 1];
301 if (requested_framerate ==
max) {
303 ctx->framerate_range[0] =
min;
304 ctx->framerate_range[1] =
max;
307 }
else if (current_best_match >= 0) {
308 int32_t current_best_match_min = available_framerates.data.i32[current_best_match * 2 + 0];
309 if (
min > current_best_match_min) {
310 current_best_match =
i;
313 current_best_match =
i;
319 if (current_best_match >= 0) {
320 ctx->framerate_range[0] = available_framerates.data.i32[current_best_match * 2 + 0];
321 ctx->framerate_range[1] = available_framerates.data.i32[current_best_match * 2 + 1];
324 ctx->framerate_range[0] = available_framerates.data.i32[0];
325 ctx->framerate_range[1] = available_framerates.data.i32[1];
329 "Requested framerate %d not available, falling back to min: %d and max: %d fps\n",
330 requested_framerate,
ctx->framerate_range[0],
ctx->framerate_range[1]);
340 uint8_t *image_plane_data[2];
341 int plane_data_length[2];
343 for (
int i = 0;
i < 2;
i++) {
344 AImage_getPlanePixelStride(image,
i + 1, &image_pixelstrides[
i]);
345 AImage_getPlaneData(image,
i + 1, &image_plane_data[
i], &plane_data_length[
i]);
348 if (image_pixelstrides[0] != image_pixelstrides[1]) {
350 "Pixel strides of U and V plane should have been the same.\n");
354 switch (image_pixelstrides[0]) {
359 if (image_plane_data[0] < image_plane_data[1]) {
367 "Unknown pixel stride %d of U and V plane, cannot determine camera image format.\n",
368 image_pixelstrides[0]);
379 media_status_t media_status;
383 int64_t image_timestamp;
385 uint8_t *image_plane_data[4];
386 int plane_data_length[4];
389 int pkt_buffer_size = 0;
391 media_status = AImageReader_acquireLatestImage(reader, &image);
392 if (media_status != AMEDIA_OK) {
393 if (media_status == AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE) {
395 "An image reader frame was discarded");
398 "Failed to acquire latest image from image reader, error: %s.\n",
415 "Could not get image format of camera.\n");
423 AImage_getTimestamp(image, &image_timestamp);
425 AImage_getPlaneRowStride(image, 0, &image_linestrides[0]);
426 AImage_getPlaneData(image, 0, &image_plane_data[0], &plane_data_length[0]);
428 switch (
ctx->image_format) {
430 AImage_getPlaneRowStride(image, 1, &image_linestrides[1]);
431 AImage_getPlaneData(image, 1, &image_plane_data[1], &plane_data_length[1]);
432 AImage_getPlaneRowStride(image, 2, &image_linestrides[2]);
433 AImage_getPlaneData(image, 2, &image_plane_data[2], &plane_data_length[2]);
436 AImage_getPlaneRowStride(image, 1, &image_linestrides[1]);
437 AImage_getPlaneData(image, 1, &image_plane_data[1], &plane_data_length[1]);
440 AImage_getPlaneRowStride(image, 2, &image_linestrides[1]);
441 AImage_getPlaneData(image, 2, &image_plane_data[1], &plane_data_length[1]);
452 "Failed to create new av packet, error: %s.\n",
av_err2str(
ret));
457 pkt.
pts = image_timestamp;
459 (
const uint8_t *
const *) image_plane_data,
460 image_linestrides,
ctx->image_format,
461 ctx->width,
ctx->height, 32);
469 "Error while processing new image, error: %s.\n",
av_err2str(
ret));
474 "Input queue was full, dropping frame, consider raising the input_queue_size option (current value: %d)\n",
475 ctx->input_queue_size);
477 if (pkt_buffer_size) {
482 AImage_delete(image);
494 if (
ret != AMEDIA_OK) {
500 ctx->image_listener.context = avctx;
503 ret = AImageReader_setImageListener(
ctx->image_reader, &
ctx->image_listener);
504 if (
ret != AMEDIA_OK) {
506 "Failed to set image listener on image reader, error: %s.\n",
511 ret = AImageReader_getWindow(
ctx->image_reader, &
ctx->image_reader_window);
512 if (
ret != AMEDIA_OK) {
514 "Could not get image reader window, error: %s.\n",
542 ret = ACaptureSessionOutputContainer_create(&
ctx->capture_session_output_container);
543 if (
ret != ACAMERA_OK) {
545 "Failed to create capture session output container, error: %s.\n",
550 ANativeWindow_acquire(
ctx->image_reader_window);
552 ret = ACaptureSessionOutput_create(
ctx->image_reader_window, &
ctx->capture_session_output);
553 if (
ret != ACAMERA_OK) {
555 "Failed to create capture session container, error: %s.\n",
560 ret = ACaptureSessionOutputContainer_add(
ctx->capture_session_output_container,
561 ctx->capture_session_output);
562 if (
ret != ACAMERA_OK) {
564 "Failed to add output to output container, error: %s.\n",
569 ret = ACameraOutputTarget_create(
ctx->image_reader_window, &
ctx->camera_output_target);
570 if (
ret != ACAMERA_OK) {
572 "Failed to create camera output target, error: %s.\n",
577 ret = ACameraDevice_createCaptureRequest(
ctx->camera_dev, TEMPLATE_RECORD, &
ctx->capture_request);
578 if (
ret != ACAMERA_OK) {
580 "Failed to create capture request, error: %s.\n",
585 ret = ACaptureRequest_setEntry_i32(
ctx->capture_request, ACAMERA_CONTROL_AE_TARGET_FPS_RANGE,
586 2,
ctx->framerate_range);
587 if (
ret != ACAMERA_OK) {
589 "Failed to set target fps range in capture request, error: %s.\n",
594 ret = ACaptureRequest_addTarget(
ctx->capture_request,
ctx->camera_output_target);
595 if (
ret != ACAMERA_OK) {
597 "Failed to add capture request capture request, error: %s.\n",
602 ctx->capture_session_state_callbacks.context = avctx;
607 ret = ACameraDevice_createCaptureSession(
ctx->camera_dev,
ctx->capture_session_output_container,
608 &
ctx->capture_session_state_callbacks, &
ctx->capture_session);
609 if (
ret != ACAMERA_OK) {
611 "Failed to create capture session, error: %s.\n",
616 ret = ACameraCaptureSession_setRepeatingRequest(
ctx->capture_session,
NULL, 1, &
ctx->capture_request,
NULL);
617 if (
ret != ACAMERA_OK) {
619 "Failed to set repeating request on capture session, error: %s.\n",
647 if (
ctx->lens_facing == ACAMERA_LENS_FACING_FRONT) {
654 sizeof(display_matrix), 0);
660 memcpy(side_data->
data, display_matrix,
sizeof(display_matrix));
702 if (
ctx->capture_session) {
703 ACameraCaptureSession_stopRepeating(
ctx->capture_session);
707 ACameraCaptureSession_close(
ctx->capture_session);
711 if (
ctx->capture_request) {
712 ACaptureRequest_removeTarget(
ctx->capture_request,
ctx->camera_output_target);
713 ACaptureRequest_free(
ctx->capture_request);
717 if (
ctx->camera_output_target) {
718 ACameraOutputTarget_free(
ctx->camera_output_target);
719 ctx->camera_output_target =
NULL;
722 if (
ctx->capture_session_output) {
723 ACaptureSessionOutputContainer_remove(
ctx->capture_session_output_container,
724 ctx->capture_session_output);
725 ACaptureSessionOutput_free(
ctx->capture_session_output);
726 ctx->capture_session_output =
NULL;
729 if (
ctx->image_reader_window) {
730 ANativeWindow_release(
ctx->image_reader_window);
731 ctx->image_reader_window =
NULL;
734 if (
ctx->capture_session_output_container) {
735 ACaptureSessionOutputContainer_free(
ctx->capture_session_output_container);
736 ctx->capture_session_output_container =
NULL;
739 if (
ctx->camera_dev) {
740 ACameraDevice_close(
ctx->camera_dev);
744 if (
ctx->image_reader) {
745 AImageReader_delete(
ctx->image_reader);
749 if (
ctx->camera_metadata) {
750 ACameraMetadata_free(
ctx->camera_metadata);
756 if (
ctx->camera_mgr) {
757 ACameraManager_delete(
ctx->camera_mgr);
761 if (
ctx->input_queue) {
784 "Failed to allocate input queue, error: %s.\n",
av_err2str(
ret));
788 ctx->camera_mgr = ACameraManager_create();
789 if (!
ctx->camera_mgr) {
845 #define OFFSET(x) offsetof(AndroidCameraCtx, x)
846 #define DEC AV_OPT_FLAG_DECODING_PARAM
850 {
"camera_index",
"set index of camera to use",
OFFSET(camera_index),
AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX,
DEC },
851 {
"input_queue_size",
"set maximum number of frames to buffer",
OFFSET(input_queue_size),
AV_OPT_TYPE_INT, {.i64 = 5}, 0, INT_MAX,
DEC },
864 .
name =
"android_camera",