30#include <camera/NdkCameraDevice.h>
31#include <camera/NdkCameraManager.h>
32#include <media/NdkImage.h>
33#include <media/NdkImageReader.h>
51#define IMAGE_FORMAT_ANDROID AIMAGE_FORMAT_YUV_420_888
53#define MAX_BUF_COUNT 2
54#define VIDEO_STREAM_INDEX 0
55#define VIDEO_TIMEBASE_ANDROID 1000000000
57#define RETURN_CASE(x) case x: return AV_STRINGIFY(x);
58#define RETURN_DEFAULT(x) default: return AV_STRINGIFY(x);
155 return "ERROR_CAMERA_UNKNOWN";
165 ACameraDevice_getId(device));
181 ACameraIdList *camera_ids;
183 ret = ACameraManager_getCameraIdList(
ctx->camera_mgr, &camera_ids);
184 if (ret != ACAMERA_OK) {
190 if (
ctx->camera_index < camera_ids->numCameras) {
192 if (!
ctx->camera_id) {
202 ACameraManager_deleteCameraIdList(camera_ids);
204 ret = ACameraManager_getCameraCharacteristics(
ctx->camera_mgr,
205 ctx->camera_id, &
ctx->camera_metadata);
206 if (ret != ACAMERA_OK) {
207 av_log(avctx,
AV_LOG_ERROR,
"Failed to get metadata for camera with id %s, error: %s.\n",
212 ctx->camera_state_callbacks.context = avctx;
216 ret = ACameraManager_openCamera(
ctx->camera_mgr,
ctx->camera_id,
217 &
ctx->camera_state_callbacks, &
ctx->camera_dev);
218 if (ret != ACAMERA_OK) {
230 ACameraMetadata_const_entry lens_facing;
231 ACameraMetadata_const_entry sensor_orientation;
233 ACameraMetadata_getConstEntry(
ctx->camera_metadata,
234 ACAMERA_LENS_FACING, &lens_facing);
235 ACameraMetadata_getConstEntry(
ctx->camera_metadata,
236 ACAMERA_SENSOR_ORIENTATION, &sensor_orientation);
238 ctx->lens_facing = lens_facing.data.u8[0];
239 ctx->sensor_orientation = sensor_orientation.data.i32[0];
245 ACameraMetadata_const_entry available_configs;
248 ACameraMetadata_getConstEntry(
ctx->camera_metadata,
249 ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
252 for (
int i = 0;
i < available_configs.count / 4;
i++) {
253 int32_t input = available_configs.data.i32[
i * 4 + 3];
275 if (!found ||
ctx->width == 0 ||
ctx->height == 0) {
276 ctx->width = available_configs.data.i32[1];
277 ctx->height = available_configs.data.i32[2];
280 "Requested video_size %dx%d not available, falling back to %dx%d\n",
281 ctx->requested_width,
ctx->requested_height,
ctx->width,
ctx->height);
290 ACameraMetadata_const_entry available_framerates;
292 int current_best_match = -1;
293 int requested_framerate =
av_q2d(
ctx->framerate);
295 ACameraMetadata_getConstEntry(
ctx->camera_metadata,
296 ACAMERA_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
297 &available_framerates);
299 for (
int i = 0;
i < available_framerates.count / 2;
i++) {
300 int32_t min = available_framerates.data.i32[
i * 2 + 0];
301 int32_t max = available_framerates.data.i32[
i * 2 + 1];
303 if (requested_framerate ==
max) {
305 ctx->framerate_range[0] =
min;
306 ctx->framerate_range[1] =
max;
309 }
else if (current_best_match >= 0) {
310 int32_t current_best_match_min = available_framerates.data.i32[current_best_match * 2 + 0];
311 if (
min > current_best_match_min) {
312 current_best_match =
i;
315 current_best_match =
i;
321 if (current_best_match >= 0) {
322 ctx->framerate_range[0] = available_framerates.data.i32[current_best_match * 2 + 0];
323 ctx->framerate_range[1] = available_framerates.data.i32[current_best_match * 2 + 1];
326 ctx->framerate_range[0] = available_framerates.data.i32[0];
327 ctx->framerate_range[1] = available_framerates.data.i32[1];
331 "Requested framerate %d not available, falling back to min: %d and max: %d fps\n",
332 requested_framerate,
ctx->framerate_range[0],
ctx->framerate_range[1]);
342 uint8_t *image_plane_data[2];
343 int plane_data_length[2];
345 for (
int i = 0;
i < 2;
i++) {
346 AImage_getPlanePixelStride(image,
i + 1, &image_pixelstrides[
i]);
347 AImage_getPlaneData(image,
i + 1, &image_plane_data[
i], &plane_data_length[
i]);
350 if (image_pixelstrides[0] != image_pixelstrides[1]) {
352 "Pixel strides of U and V plane should have been the same.\n");
356 switch (image_pixelstrides[0]) {
361 if (image_plane_data[0] < image_plane_data[1]) {
369 "Unknown pixel stride %d of U and V plane, cannot determine camera image format.\n",
370 image_pixelstrides[0]);
381 media_status_t media_status;
387 uint8_t *image_plane_data[4];
388 int plane_data_length[4];
391 int pkt_buffer_size = 0;
393 media_status = AImageReader_acquireLatestImage(reader, &image);
394 if (media_status != AMEDIA_OK) {
395 if (media_status == AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE) {
397 "An image reader frame was discarded");
400 "Failed to acquire latest image from image reader, error: %s.\n",
417 "Could not get image format of camera.\n");
425 AImage_getTimestamp(image, &image_timestamp);
427 AImage_getPlaneRowStride(image, 0, &image_linestrides[0]);
428 AImage_getPlaneData(image, 0, &image_plane_data[0], &plane_data_length[0]);
430 switch (
ctx->image_format) {
432 AImage_getPlaneRowStride(image, 1, &image_linestrides[1]);
433 AImage_getPlaneData(image, 1, &image_plane_data[1], &plane_data_length[1]);
434 AImage_getPlaneRowStride(image, 2, &image_linestrides[2]);
435 AImage_getPlaneData(image, 2, &image_plane_data[2], &plane_data_length[2]);
438 AImage_getPlaneRowStride(image, 1, &image_linestrides[1]);
439 AImage_getPlaneData(image, 1, &image_plane_data[1], &plane_data_length[1]);
442 AImage_getPlaneRowStride(image, 2, &image_linestrides[1]);
443 AImage_getPlaneData(image, 2, &image_plane_data[1], &plane_data_length[1]);
454 "Failed to create new av packet, error: %s.\n",
av_err2str(ret));
459 pkt.pts = image_timestamp;
461 (
const uint8_t *
const *) image_plane_data,
462 image_linestrides,
ctx->image_format,
463 ctx->width,
ctx->height, 1);
471 "Error while processing new image, error: %s.\n",
av_err2str(ret));
476 "Input queue was full, dropping frame, consider raising the input_queue_size option (current value: %d)\n",
477 ctx->input_queue_size);
479 if (pkt_buffer_size) {
484 AImage_delete(image);
496 if (ret != AMEDIA_OK) {
502 ctx->image_listener.context = avctx;
505 ret = AImageReader_setImageListener(
ctx->image_reader, &
ctx->image_listener);
506 if (ret != AMEDIA_OK) {
508 "Failed to set image listener on image reader, error: %s.\n",
513 ret = AImageReader_getWindow(
ctx->image_reader, &
ctx->image_reader_window);
514 if (ret != AMEDIA_OK) {
516 "Could not get image reader window, error: %s.\n",
544 ret = ACaptureSessionOutputContainer_create(&
ctx->capture_session_output_container);
545 if (ret != ACAMERA_OK) {
547 "Failed to create capture session output container, error: %s.\n",
552 ANativeWindow_acquire(
ctx->image_reader_window);
554 ret = ACaptureSessionOutput_create(
ctx->image_reader_window, &
ctx->capture_session_output);
555 if (ret != ACAMERA_OK) {
557 "Failed to create capture session container, error: %s.\n",
562 ret = ACaptureSessionOutputContainer_add(
ctx->capture_session_output_container,
563 ctx->capture_session_output);
564 if (ret != ACAMERA_OK) {
566 "Failed to add output to output container, error: %s.\n",
571 ret = ACameraOutputTarget_create(
ctx->image_reader_window, &
ctx->camera_output_target);
572 if (ret != ACAMERA_OK) {
574 "Failed to create camera output target, error: %s.\n",
579 ret = ACameraDevice_createCaptureRequest(
ctx->camera_dev, TEMPLATE_RECORD, &
ctx->capture_request);
580 if (ret != ACAMERA_OK) {
582 "Failed to create capture request, error: %s.\n",
587 ret = ACaptureRequest_setEntry_i32(
ctx->capture_request, ACAMERA_CONTROL_AE_TARGET_FPS_RANGE,
588 2,
ctx->framerate_range);
589 if (ret != ACAMERA_OK) {
591 "Failed to set target fps range in capture request, error: %s.\n",
596 ret = ACaptureRequest_addTarget(
ctx->capture_request,
ctx->camera_output_target);
597 if (ret != ACAMERA_OK) {
599 "Failed to add capture request capture request, error: %s.\n",
604 ctx->capture_session_state_callbacks.context = avctx;
609 ret = ACameraDevice_createCaptureSession(
ctx->camera_dev,
ctx->capture_session_output_container,
610 &
ctx->capture_session_state_callbacks, &
ctx->capture_session);
611 if (ret != ACAMERA_OK) {
613 "Failed to create capture session, error: %s.\n",
618 ret = ACameraCaptureSession_setRepeatingRequest(
ctx->capture_session,
NULL, 1, &
ctx->capture_request,
NULL);
619 if (ret != ACAMERA_OK) {
621 "Failed to set repeating request on capture session, error: %s.\n",
649 if (
ctx->lens_facing == ACAMERA_LENS_FACING_FRONT) {
656 sizeof(display_matrix), 0);
662 memcpy(side_data->
data, display_matrix,
sizeof(display_matrix));
704 if (
ctx->capture_session) {
705 ACameraCaptureSession_stopRepeating(
ctx->capture_session);
709 ACameraCaptureSession_close(
ctx->capture_session);
713 if (
ctx->capture_request) {
714 ACaptureRequest_removeTarget(
ctx->capture_request,
ctx->camera_output_target);
715 ACaptureRequest_free(
ctx->capture_request);
719 if (
ctx->camera_output_target) {
720 ACameraOutputTarget_free(
ctx->camera_output_target);
721 ctx->camera_output_target =
NULL;
724 if (
ctx->capture_session_output) {
725 ACaptureSessionOutputContainer_remove(
ctx->capture_session_output_container,
726 ctx->capture_session_output);
727 ACaptureSessionOutput_free(
ctx->capture_session_output);
728 ctx->capture_session_output =
NULL;
731 if (
ctx->image_reader_window) {
732 ANativeWindow_release(
ctx->image_reader_window);
733 ctx->image_reader_window =
NULL;
736 if (
ctx->capture_session_output_container) {
737 ACaptureSessionOutputContainer_free(
ctx->capture_session_output_container);
738 ctx->capture_session_output_container =
NULL;
741 if (
ctx->camera_dev) {
742 ACameraDevice_close(
ctx->camera_dev);
746 if (
ctx->image_reader) {
747 AImageReader_delete(
ctx->image_reader);
751 if (
ctx->camera_metadata) {
752 ACameraMetadata_free(
ctx->camera_metadata);
758 if (
ctx->camera_mgr) {
759 ACameraManager_delete(
ctx->camera_mgr);
763 if (
ctx->input_queue) {
786 "Failed to allocate input queue, error: %s.\n",
av_err2str(ret));
790 ctx->camera_mgr = ACameraManager_create();
791 if (!
ctx->camera_mgr) {
847#define OFFSET(x) offsetof(AndroidCameraCtx, x)
848#define DEC AV_OPT_FLAG_DECODING_PARAM
852 {
"camera_index",
"set index of camera to use",
OFFSET(camera_index),
AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX,
DEC },
853 {
"input_queue_size",
"set maximum number of frames to buffer",
OFFSET(input_queue_size),
AV_OPT_TYPE_INT, {.i64 = 5}, 0, INT_MAX,
DEC },
858 .class_name =
"android_camera indev",
866 .p.name =
"android_camera",
static double val(void *priv, double ch)
static const char *const format[]
const FFInputFormat ff_android_camera_demuxer
static void image_available(void *context, AImageReader *reader)
static int android_camera_read_header(AVFormatContext *avctx)
static void capture_session_active(void *context, ACameraCaptureSession *session)
#define RETURN_DEFAULT(x)
static const char * media_status_string(media_status_t val)
static int add_video_stream(AVFormatContext *avctx)
static int get_image_format(AVFormatContext *avctx, AImage *image)
static void camera_dev_error(void *context, ACameraDevice *device, int error)
#define IMAGE_FORMAT_ANDROID
#define VIDEO_STREAM_INDEX
static void camera_dev_disconnected(void *context, ACameraDevice *device)
#define VIDEO_TIMEBASE_ANDROID
static int android_camera_read_packet(AVFormatContext *avctx, AVPacket *pkt)
static int create_image_reader(AVFormatContext *avctx)
static void get_sensor_orientation(AVFormatContext *avctx)
static int open_camera(AVFormatContext *avctx)
static void capture_session_ready(void *context, ACameraCaptureSession *session)
static int wait_for_image_format(AVFormatContext *avctx)
static void capture_session_closed(void *context, ACameraCaptureSession *session)
static const char * error_state_callback_string(int val)
static int android_camera_read_close(AVFormatContext *avctx)
static int create_capture_session(AVFormatContext *avctx)
static const AVClass android_camera_class
static void match_framerate(AVFormatContext *avctx)
static void match_video_size(AVFormatContext *avctx)
static int add_display_matrix(AVFormatContext *avctx, AVStream *st)
static const char * camera_status_string(camera_status_t val)
static AVFormatContext * ctx
static int read_packet(void *opaque, uint8_t *buf, int buf_size)
#define i(width, name, range_min, range_max)
static int read_header(FFV1Context *f, RangeCoder *c)
@ AV_OPT_TYPE_IMAGE_SIZE
Underlying C type is two consecutive integers.
@ AV_OPT_TYPE_VIDEO_RATE
Underlying C type is AVRational.
@ AV_OPT_TYPE_INT
Underlying C type is int.
AVPacketSideData * av_packet_side_data_new(AVPacketSideData **psd, int *pnb_sd, enum AVPacketSideDataType type, size_t size, int flags)
Allocate a new packet side data.
@ AV_PKT_DATA_DISPLAYMATRIX
This side data contains a 3x3 transformation matrix describing an affine transformation that needs to...
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
int av_new_packet(AVPacket *pkt, int size)
Allocate the payload of a packet and initialize its fields with default values.
AVStream * avformat_new_stream(AVFormatContext *s, const struct AVCodec *c)
Add a new stream to a media file.
#define AVERROR_EXTERNAL
Generic error in an external library.
#define AVERROR_EOF
End of file.
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
#define AV_LOG_WARNING
Something somehow does not look correct.
#define AV_LOG_INFO
Standard information.
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
const char * av_default_item_name(void *ptr)
Return the context name.
static double av_q2d(AVRational a)
Convert an AVRational to a double.
int av_image_get_buffer_size(enum AVPixelFormat pix_fmt, int width, int height, int align)
Return the size in bytes of the amount of data required to store an image with the given parameters.
int av_image_copy_to_buffer(uint8_t *dst, int dst_size, const uint8_t *const src_data[4], const int src_linesize[4], enum AVPixelFormat pix_fmt, int width, int height, int align)
Copy image data from an image into a buffer.
#define LIBAVUTIL_VERSION_INT
void av_display_rotation_set(int32_t matrix[9], double angle)
Initialize a transformation matrix describing a pure clockwise rotation by the specified angle (in de...
void av_display_matrix_flip(int32_t matrix[9], int hflip, int vflip)
Flip the input matrix horizontally and/or vertically.
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
static av_cold int read_close(AVFormatContext *ctx)
@ AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT
Memory handling functions.
@ AV_PIX_FMT_NV12
planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (firs...
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
@ AV_PIX_FMT_NV21
as above, but U and V bytes are swapped
#define atomic_store(object, desired)
#define atomic_load(object)
#define atomic_init(obj, value)
Describe the class of an AVClass context structure.
This struct describes the properties of an encoded stream.
int height
The height of the video frame in pixels.
int nb_coded_side_data
Amount of entries in coded_side_data.
int width
The width of the video frame in pixels.
enum AVMediaType codec_type
General type of the encoded data.
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
AVPacketSideData * coded_side_data
Additional data associated with the entire stream.
int flags
Flags modifying the (de)muxer behaviour.
void * priv_data
Format private data.
This structure stores auxiliary information for decoding, presenting, or otherwise processing the cod...
This structure stores compressed data.
Rational number (pair of numerator and denominator).
AVCodecParameters * codecpar
Codec parameters associated with this stream.
int id
Format-specific stream ID.
AVRational avg_frame_rate
Average framerate.
AVRational r_frame_rate
Real base framerate of the stream.
ACameraDevice_StateCallbacks camera_state_callbacks
atomic_int got_image_format
ANativeWindow * image_reader_window
ACameraCaptureSession_stateCallbacks capture_session_state_callbacks
ACameraCaptureSession * capture_session
AImageReader_ImageListener image_listener
ACameraManager * camera_mgr
int32_t framerate_range[2]
ACameraDevice * camera_dev
ACameraOutputTarget * camera_output_target
AImageReader * image_reader
ACameraMetadata * camera_metadata
AVThreadMessageQueue * input_queue
int32_t sensor_orientation
ACaptureRequest * capture_request
ACaptureSessionOutputContainer * capture_session_output_container
ACaptureSessionOutput * capture_session_output
static void error(const char *err)
void av_thread_message_queue_set_err_send(AVThreadMessageQueue *mq, int err)
Set the sending error code.
int av_thread_message_queue_recv(AVThreadMessageQueue *mq, void *msg, unsigned flags)
Receive a message from the queue.
int av_thread_message_queue_alloc(AVThreadMessageQueue **mq, unsigned nelem, unsigned elsize)
Allocate a new message queue.
void av_thread_message_queue_set_err_recv(AVThreadMessageQueue *mq, int err)
Set the receiving error code.
int av_thread_message_queue_send(AVThreadMessageQueue *mq, void *msg, unsigned flags)
Send a message on the queue.
void av_thread_message_queue_free(AVThreadMessageQueue **mq)
Free a message queue.
@ AV_THREAD_MESSAGE_NONBLOCK
Perform non-blocking operation.