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 int read_packet(void *opaque, uint8_t *buf, int buf_size)
#define i(width, name, range_min, range_max)
#define atomic_store(object, desired)
#define atomic_load(object)
#define atomic_init(obj, value)
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
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)
static AVFormatContext * ctx
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.