1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Android camera input device
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * Copyright (C) 2017 Felix Matouschek
5cabdff1aSopenharmony_ci *
6cabdff1aSopenharmony_ci * This file is part of FFmpeg.
7cabdff1aSopenharmony_ci *
8cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
9cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
10cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
11cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
12cabdff1aSopenharmony_ci *
13cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
14cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
15cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16cabdff1aSopenharmony_ci * Lesser General Public License for more details.
17cabdff1aSopenharmony_ci *
18cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
19cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
20cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21cabdff1aSopenharmony_ci */
22cabdff1aSopenharmony_ci
23cabdff1aSopenharmony_ci#include <errno.h>
24cabdff1aSopenharmony_ci#include <pthread.h>
25cabdff1aSopenharmony_ci#include <stdatomic.h>
26cabdff1aSopenharmony_ci#include <stdbool.h>
27cabdff1aSopenharmony_ci#include <stdint.h>
28cabdff1aSopenharmony_ci
29cabdff1aSopenharmony_ci#include <camera/NdkCameraDevice.h>
30cabdff1aSopenharmony_ci#include <camera/NdkCameraManager.h>
31cabdff1aSopenharmony_ci#include <media/NdkImage.h>
32cabdff1aSopenharmony_ci#include <media/NdkImageReader.h>
33cabdff1aSopenharmony_ci
34cabdff1aSopenharmony_ci#include "libavformat/avformat.h"
35cabdff1aSopenharmony_ci#include "libavformat/internal.h"
36cabdff1aSopenharmony_ci#include "libavutil/avstring.h"
37cabdff1aSopenharmony_ci#include "libavutil/display.h"
38cabdff1aSopenharmony_ci#include "libavutil/imgutils.h"
39cabdff1aSopenharmony_ci#include "libavutil/log.h"
40cabdff1aSopenharmony_ci#include "libavutil/opt.h"
41cabdff1aSopenharmony_ci#include "libavutil/parseutils.h"
42cabdff1aSopenharmony_ci#include "libavutil/pixfmt.h"
43cabdff1aSopenharmony_ci#include "libavutil/threadmessage.h"
44cabdff1aSopenharmony_ci#include "libavutil/time.h"
45cabdff1aSopenharmony_ci
46cabdff1aSopenharmony_ci/* This image format is available on all Android devices
47cabdff1aSopenharmony_ci * supporting the Camera2 API */
48cabdff1aSopenharmony_ci#define IMAGE_FORMAT_ANDROID AIMAGE_FORMAT_YUV_420_888
49cabdff1aSopenharmony_ci
50cabdff1aSopenharmony_ci#define MAX_BUF_COUNT 2
51cabdff1aSopenharmony_ci#define VIDEO_STREAM_INDEX 0
52cabdff1aSopenharmony_ci#define VIDEO_TIMEBASE_ANDROID 1000000000
53cabdff1aSopenharmony_ci
54cabdff1aSopenharmony_ci#define RETURN_CASE(x) case x: return AV_STRINGIFY(x);
55cabdff1aSopenharmony_ci#define RETURN_DEFAULT(x) default: return AV_STRINGIFY(x);
56cabdff1aSopenharmony_ci
57cabdff1aSopenharmony_citypedef struct AndroidCameraCtx {
58cabdff1aSopenharmony_ci    const AVClass *class;
59cabdff1aSopenharmony_ci
60cabdff1aSopenharmony_ci    int requested_width;
61cabdff1aSopenharmony_ci    int requested_height;
62cabdff1aSopenharmony_ci    AVRational framerate;
63cabdff1aSopenharmony_ci    int camera_index;
64cabdff1aSopenharmony_ci    int input_queue_size;
65cabdff1aSopenharmony_ci
66cabdff1aSopenharmony_ci    uint8_t lens_facing;
67cabdff1aSopenharmony_ci    int32_t sensor_orientation;
68cabdff1aSopenharmony_ci    int width;
69cabdff1aSopenharmony_ci    int height;
70cabdff1aSopenharmony_ci    int32_t framerate_range[2];
71cabdff1aSopenharmony_ci    int image_format;
72cabdff1aSopenharmony_ci
73cabdff1aSopenharmony_ci    ACameraManager *camera_mgr;
74cabdff1aSopenharmony_ci    char *camera_id;
75cabdff1aSopenharmony_ci    ACameraMetadata *camera_metadata;
76cabdff1aSopenharmony_ci    ACameraDevice *camera_dev;
77cabdff1aSopenharmony_ci    ACameraDevice_StateCallbacks camera_state_callbacks;
78cabdff1aSopenharmony_ci    AImageReader *image_reader;
79cabdff1aSopenharmony_ci    AImageReader_ImageListener image_listener;
80cabdff1aSopenharmony_ci    ANativeWindow *image_reader_window;
81cabdff1aSopenharmony_ci    ACaptureSessionOutputContainer *capture_session_output_container;
82cabdff1aSopenharmony_ci    ACaptureSessionOutput *capture_session_output;
83cabdff1aSopenharmony_ci    ACameraOutputTarget *camera_output_target;
84cabdff1aSopenharmony_ci    ACaptureRequest *capture_request;
85cabdff1aSopenharmony_ci    ACameraCaptureSession_stateCallbacks capture_session_state_callbacks;
86cabdff1aSopenharmony_ci    ACameraCaptureSession *capture_session;
87cabdff1aSopenharmony_ci
88cabdff1aSopenharmony_ci    AVThreadMessageQueue *input_queue;
89cabdff1aSopenharmony_ci    atomic_int exit;
90cabdff1aSopenharmony_ci    atomic_int got_image_format;
91cabdff1aSopenharmony_ci} AndroidCameraCtx;
92cabdff1aSopenharmony_ci
93cabdff1aSopenharmony_cistatic const char *camera_status_string(camera_status_t val)
94cabdff1aSopenharmony_ci{
95cabdff1aSopenharmony_ci    switch(val) {
96cabdff1aSopenharmony_ci        RETURN_CASE(ACAMERA_OK)
97cabdff1aSopenharmony_ci        RETURN_CASE(ACAMERA_ERROR_UNKNOWN)
98cabdff1aSopenharmony_ci        RETURN_CASE(ACAMERA_ERROR_INVALID_PARAMETER)
99cabdff1aSopenharmony_ci        RETURN_CASE(ACAMERA_ERROR_CAMERA_DISCONNECTED)
100cabdff1aSopenharmony_ci        RETURN_CASE(ACAMERA_ERROR_NOT_ENOUGH_MEMORY)
101cabdff1aSopenharmony_ci        RETURN_CASE(ACAMERA_ERROR_METADATA_NOT_FOUND)
102cabdff1aSopenharmony_ci        RETURN_CASE(ACAMERA_ERROR_CAMERA_DEVICE)
103cabdff1aSopenharmony_ci        RETURN_CASE(ACAMERA_ERROR_CAMERA_SERVICE)
104cabdff1aSopenharmony_ci        RETURN_CASE(ACAMERA_ERROR_SESSION_CLOSED)
105cabdff1aSopenharmony_ci        RETURN_CASE(ACAMERA_ERROR_INVALID_OPERATION)
106cabdff1aSopenharmony_ci        RETURN_CASE(ACAMERA_ERROR_STREAM_CONFIGURE_FAIL)
107cabdff1aSopenharmony_ci        RETURN_CASE(ACAMERA_ERROR_CAMERA_IN_USE)
108cabdff1aSopenharmony_ci        RETURN_CASE(ACAMERA_ERROR_MAX_CAMERA_IN_USE)
109cabdff1aSopenharmony_ci        RETURN_CASE(ACAMERA_ERROR_CAMERA_DISABLED)
110cabdff1aSopenharmony_ci        RETURN_CASE(ACAMERA_ERROR_PERMISSION_DENIED)
111cabdff1aSopenharmony_ci        RETURN_DEFAULT(ACAMERA_ERROR_UNKNOWN)
112cabdff1aSopenharmony_ci    }
113cabdff1aSopenharmony_ci}
114cabdff1aSopenharmony_ci
115cabdff1aSopenharmony_cistatic const char *media_status_string(media_status_t val)
116cabdff1aSopenharmony_ci{
117cabdff1aSopenharmony_ci    switch(val) {
118cabdff1aSopenharmony_ci        RETURN_CASE(AMEDIA_OK)
119cabdff1aSopenharmony_ci        RETURN_CASE(AMEDIA_ERROR_UNKNOWN)
120cabdff1aSopenharmony_ci        RETURN_CASE(AMEDIA_ERROR_MALFORMED)
121cabdff1aSopenharmony_ci        RETURN_CASE(AMEDIA_ERROR_UNSUPPORTED)
122cabdff1aSopenharmony_ci        RETURN_CASE(AMEDIA_ERROR_INVALID_OBJECT)
123cabdff1aSopenharmony_ci        RETURN_CASE(AMEDIA_ERROR_INVALID_PARAMETER)
124cabdff1aSopenharmony_ci        RETURN_CASE(AMEDIA_ERROR_INVALID_OPERATION)
125cabdff1aSopenharmony_ci        RETURN_CASE(AMEDIA_DRM_NOT_PROVISIONED)
126cabdff1aSopenharmony_ci        RETURN_CASE(AMEDIA_DRM_RESOURCE_BUSY)
127cabdff1aSopenharmony_ci        RETURN_CASE(AMEDIA_DRM_DEVICE_REVOKED)
128cabdff1aSopenharmony_ci        RETURN_CASE(AMEDIA_DRM_SHORT_BUFFER)
129cabdff1aSopenharmony_ci        RETURN_CASE(AMEDIA_DRM_SESSION_NOT_OPENED)
130cabdff1aSopenharmony_ci        RETURN_CASE(AMEDIA_DRM_TAMPER_DETECTED)
131cabdff1aSopenharmony_ci        RETURN_CASE(AMEDIA_DRM_VERIFY_FAILED)
132cabdff1aSopenharmony_ci        RETURN_CASE(AMEDIA_DRM_NEED_KEY)
133cabdff1aSopenharmony_ci        RETURN_CASE(AMEDIA_DRM_LICENSE_EXPIRED)
134cabdff1aSopenharmony_ci        RETURN_CASE(AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE)
135cabdff1aSopenharmony_ci        RETURN_CASE(AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED)
136cabdff1aSopenharmony_ci        RETURN_CASE(AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE)
137cabdff1aSopenharmony_ci        RETURN_CASE(AMEDIA_IMGREADER_CANNOT_UNLOCK_IMAGE)
138cabdff1aSopenharmony_ci        RETURN_CASE(AMEDIA_IMGREADER_IMAGE_NOT_LOCKED)
139cabdff1aSopenharmony_ci        RETURN_DEFAULT(AMEDIA_ERROR_UNKNOWN)
140cabdff1aSopenharmony_ci    }
141cabdff1aSopenharmony_ci}
142cabdff1aSopenharmony_ci
143cabdff1aSopenharmony_cistatic const char *error_state_callback_string(int val)
144cabdff1aSopenharmony_ci{
145cabdff1aSopenharmony_ci    switch(val) {
146cabdff1aSopenharmony_ci        RETURN_CASE(ERROR_CAMERA_IN_USE)
147cabdff1aSopenharmony_ci        RETURN_CASE(ERROR_MAX_CAMERAS_IN_USE)
148cabdff1aSopenharmony_ci        RETURN_CASE(ERROR_CAMERA_DISABLED)
149cabdff1aSopenharmony_ci        RETURN_CASE(ERROR_CAMERA_DEVICE)
150cabdff1aSopenharmony_ci        RETURN_CASE(ERROR_CAMERA_SERVICE)
151cabdff1aSopenharmony_ci        default:
152cabdff1aSopenharmony_ci            return "ERROR_CAMERA_UNKNOWN";
153cabdff1aSopenharmony_ci    }
154cabdff1aSopenharmony_ci}
155cabdff1aSopenharmony_ci
156cabdff1aSopenharmony_cistatic void camera_dev_disconnected(void *context, ACameraDevice *device)
157cabdff1aSopenharmony_ci{
158cabdff1aSopenharmony_ci    AVFormatContext *avctx = context;
159cabdff1aSopenharmony_ci    AndroidCameraCtx *ctx = avctx->priv_data;
160cabdff1aSopenharmony_ci    atomic_store(&ctx->exit, 1);
161cabdff1aSopenharmony_ci    av_log(avctx, AV_LOG_ERROR, "Camera with id %s disconnected.\n",
162cabdff1aSopenharmony_ci           ACameraDevice_getId(device));
163cabdff1aSopenharmony_ci}
164cabdff1aSopenharmony_ci
165cabdff1aSopenharmony_cistatic void camera_dev_error(void *context, ACameraDevice *device, int error)
166cabdff1aSopenharmony_ci{
167cabdff1aSopenharmony_ci    AVFormatContext *avctx = context;
168cabdff1aSopenharmony_ci    AndroidCameraCtx *ctx = avctx->priv_data;
169cabdff1aSopenharmony_ci    atomic_store(&ctx->exit, 1);
170cabdff1aSopenharmony_ci    av_log(avctx, AV_LOG_ERROR, "Error %s on camera with id %s.\n",
171cabdff1aSopenharmony_ci           error_state_callback_string(error), ACameraDevice_getId(device));
172cabdff1aSopenharmony_ci}
173cabdff1aSopenharmony_ci
174cabdff1aSopenharmony_cistatic int open_camera(AVFormatContext *avctx)
175cabdff1aSopenharmony_ci{
176cabdff1aSopenharmony_ci    AndroidCameraCtx *ctx = avctx->priv_data;
177cabdff1aSopenharmony_ci    camera_status_t ret;
178cabdff1aSopenharmony_ci    ACameraIdList *camera_ids;
179cabdff1aSopenharmony_ci
180cabdff1aSopenharmony_ci    ret = ACameraManager_getCameraIdList(ctx->camera_mgr, &camera_ids);
181cabdff1aSopenharmony_ci    if (ret != ACAMERA_OK) {
182cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Failed to get camera id list, error: %s.\n",
183cabdff1aSopenharmony_ci               camera_status_string(ret));
184cabdff1aSopenharmony_ci        return AVERROR_EXTERNAL;
185cabdff1aSopenharmony_ci    }
186cabdff1aSopenharmony_ci
187cabdff1aSopenharmony_ci    if (ctx->camera_index < camera_ids->numCameras) {
188cabdff1aSopenharmony_ci        ctx->camera_id = av_strdup(camera_ids->cameraIds[ctx->camera_index]);
189cabdff1aSopenharmony_ci        if (!ctx->camera_id) {
190cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Failed to allocate memory for camera_id.\n");
191cabdff1aSopenharmony_ci            return AVERROR(ENOMEM);
192cabdff1aSopenharmony_ci        }
193cabdff1aSopenharmony_ci    } else {
194cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "No camera with index %d available.\n",
195cabdff1aSopenharmony_ci               ctx->camera_index);
196cabdff1aSopenharmony_ci        return AVERROR(ENXIO);
197cabdff1aSopenharmony_ci    }
198cabdff1aSopenharmony_ci
199cabdff1aSopenharmony_ci    ACameraManager_deleteCameraIdList(camera_ids);
200cabdff1aSopenharmony_ci
201cabdff1aSopenharmony_ci    ret = ACameraManager_getCameraCharacteristics(ctx->camera_mgr,
202cabdff1aSopenharmony_ci            ctx->camera_id, &ctx->camera_metadata);
203cabdff1aSopenharmony_ci    if (ret != ACAMERA_OK) {
204cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Failed to get metadata for camera with id %s, error: %s.\n",
205cabdff1aSopenharmony_ci               ctx->camera_id, camera_status_string(ret));
206cabdff1aSopenharmony_ci        return AVERROR_EXTERNAL;
207cabdff1aSopenharmony_ci    }
208cabdff1aSopenharmony_ci
209cabdff1aSopenharmony_ci    ctx->camera_state_callbacks.context = avctx;
210cabdff1aSopenharmony_ci    ctx->camera_state_callbacks.onDisconnected = camera_dev_disconnected;
211cabdff1aSopenharmony_ci    ctx->camera_state_callbacks.onError = camera_dev_error;
212cabdff1aSopenharmony_ci
213cabdff1aSopenharmony_ci    ret = ACameraManager_openCamera(ctx->camera_mgr, ctx->camera_id,
214cabdff1aSopenharmony_ci                                    &ctx->camera_state_callbacks, &ctx->camera_dev);
215cabdff1aSopenharmony_ci    if (ret != ACAMERA_OK) {
216cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Failed to open camera with id %s, error: %s.\n",
217cabdff1aSopenharmony_ci               ctx->camera_id, camera_status_string(ret));
218cabdff1aSopenharmony_ci        return AVERROR_EXTERNAL;
219cabdff1aSopenharmony_ci    }
220cabdff1aSopenharmony_ci
221cabdff1aSopenharmony_ci    return 0;
222cabdff1aSopenharmony_ci}
223cabdff1aSopenharmony_ci
224cabdff1aSopenharmony_cistatic void get_sensor_orientation(AVFormatContext *avctx)
225cabdff1aSopenharmony_ci{
226cabdff1aSopenharmony_ci    AndroidCameraCtx *ctx = avctx->priv_data;
227cabdff1aSopenharmony_ci    ACameraMetadata_const_entry lens_facing;
228cabdff1aSopenharmony_ci    ACameraMetadata_const_entry sensor_orientation;
229cabdff1aSopenharmony_ci
230cabdff1aSopenharmony_ci    ACameraMetadata_getConstEntry(ctx->camera_metadata,
231cabdff1aSopenharmony_ci                                  ACAMERA_LENS_FACING, &lens_facing);
232cabdff1aSopenharmony_ci    ACameraMetadata_getConstEntry(ctx->camera_metadata,
233cabdff1aSopenharmony_ci                                  ACAMERA_SENSOR_ORIENTATION, &sensor_orientation);
234cabdff1aSopenharmony_ci
235cabdff1aSopenharmony_ci    ctx->lens_facing = lens_facing.data.u8[0];
236cabdff1aSopenharmony_ci    ctx->sensor_orientation = sensor_orientation.data.i32[0];
237cabdff1aSopenharmony_ci}
238cabdff1aSopenharmony_ci
239cabdff1aSopenharmony_cistatic void match_video_size(AVFormatContext *avctx)
240cabdff1aSopenharmony_ci{
241cabdff1aSopenharmony_ci    AndroidCameraCtx *ctx = avctx->priv_data;
242cabdff1aSopenharmony_ci    ACameraMetadata_const_entry available_configs;
243cabdff1aSopenharmony_ci    int found = 0;
244cabdff1aSopenharmony_ci
245cabdff1aSopenharmony_ci    ACameraMetadata_getConstEntry(ctx->camera_metadata,
246cabdff1aSopenharmony_ci                                  ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
247cabdff1aSopenharmony_ci                                  &available_configs);
248cabdff1aSopenharmony_ci
249cabdff1aSopenharmony_ci    for (int i = 0; i < available_configs.count; i++) {
250cabdff1aSopenharmony_ci        int32_t input = available_configs.data.i32[i * 4 + 3];
251cabdff1aSopenharmony_ci        int32_t format = available_configs.data.i32[i * 4 + 0];
252cabdff1aSopenharmony_ci
253cabdff1aSopenharmony_ci        if (input) {
254cabdff1aSopenharmony_ci            continue;
255cabdff1aSopenharmony_ci        }
256cabdff1aSopenharmony_ci
257cabdff1aSopenharmony_ci        if (format == IMAGE_FORMAT_ANDROID) {
258cabdff1aSopenharmony_ci            int32_t width = available_configs.data.i32[i * 4 + 1];
259cabdff1aSopenharmony_ci            int32_t height = available_configs.data.i32[i * 4 + 2];
260cabdff1aSopenharmony_ci
261cabdff1aSopenharmony_ci            //Same ratio
262cabdff1aSopenharmony_ci            if ((ctx->requested_width == width && ctx->requested_height == height) ||
263cabdff1aSopenharmony_ci                    (ctx->requested_width == height && ctx->requested_height == width)) {
264cabdff1aSopenharmony_ci                ctx->width = width;
265cabdff1aSopenharmony_ci                ctx->height = height;
266cabdff1aSopenharmony_ci                found = 1;
267cabdff1aSopenharmony_ci                break;
268cabdff1aSopenharmony_ci            }
269cabdff1aSopenharmony_ci        }
270cabdff1aSopenharmony_ci    }
271cabdff1aSopenharmony_ci
272cabdff1aSopenharmony_ci    if (!found || ctx->width == 0 || ctx->height == 0) {
273cabdff1aSopenharmony_ci        ctx->width = available_configs.data.i32[1];
274cabdff1aSopenharmony_ci        ctx->height = available_configs.data.i32[2];
275cabdff1aSopenharmony_ci
276cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_WARNING,
277cabdff1aSopenharmony_ci               "Requested video_size %dx%d not available, falling back to %dx%d\n",
278cabdff1aSopenharmony_ci               ctx->requested_width, ctx->requested_height, ctx->width, ctx->height);
279cabdff1aSopenharmony_ci    }
280cabdff1aSopenharmony_ci
281cabdff1aSopenharmony_ci    return;
282cabdff1aSopenharmony_ci}
283cabdff1aSopenharmony_ci
284cabdff1aSopenharmony_cistatic void match_framerate(AVFormatContext *avctx)
285cabdff1aSopenharmony_ci{
286cabdff1aSopenharmony_ci    AndroidCameraCtx *ctx = avctx->priv_data;
287cabdff1aSopenharmony_ci    ACameraMetadata_const_entry available_framerates;
288cabdff1aSopenharmony_ci    int found = 0;
289cabdff1aSopenharmony_ci    int current_best_match = -1;
290cabdff1aSopenharmony_ci    int requested_framerate = av_q2d(ctx->framerate);
291cabdff1aSopenharmony_ci
292cabdff1aSopenharmony_ci    ACameraMetadata_getConstEntry(ctx->camera_metadata,
293cabdff1aSopenharmony_ci                                  ACAMERA_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
294cabdff1aSopenharmony_ci                                  &available_framerates);
295cabdff1aSopenharmony_ci
296cabdff1aSopenharmony_ci    for (int i = 0; i < available_framerates.count; i++) {
297cabdff1aSopenharmony_ci        int32_t min = available_framerates.data.i32[i * 2 + 0];
298cabdff1aSopenharmony_ci        int32_t max = available_framerates.data.i32[i * 2 + 1];
299cabdff1aSopenharmony_ci
300cabdff1aSopenharmony_ci        if (requested_framerate == max) {
301cabdff1aSopenharmony_ci            if (min == max) {
302cabdff1aSopenharmony_ci                ctx->framerate_range[0] = min;
303cabdff1aSopenharmony_ci                ctx->framerate_range[1] = max;
304cabdff1aSopenharmony_ci                found = 1;
305cabdff1aSopenharmony_ci                break;
306cabdff1aSopenharmony_ci            } else if (current_best_match >= 0) {
307cabdff1aSopenharmony_ci                int32_t current_best_match_min = available_framerates.data.i32[current_best_match * 2 + 0];
308cabdff1aSopenharmony_ci                if (min > current_best_match_min) {
309cabdff1aSopenharmony_ci                    current_best_match = i;
310cabdff1aSopenharmony_ci                }
311cabdff1aSopenharmony_ci            } else {
312cabdff1aSopenharmony_ci                current_best_match = i;
313cabdff1aSopenharmony_ci            }
314cabdff1aSopenharmony_ci        }
315cabdff1aSopenharmony_ci    }
316cabdff1aSopenharmony_ci
317cabdff1aSopenharmony_ci    if (!found) {
318cabdff1aSopenharmony_ci        if (current_best_match >= 0) {
319cabdff1aSopenharmony_ci            ctx->framerate_range[0] = available_framerates.data.i32[current_best_match * 2 + 0];
320cabdff1aSopenharmony_ci            ctx->framerate_range[1] = available_framerates.data.i32[current_best_match * 2 + 1];
321cabdff1aSopenharmony_ci
322cabdff1aSopenharmony_ci        } else {
323cabdff1aSopenharmony_ci            ctx->framerate_range[0] = available_framerates.data.i32[0];
324cabdff1aSopenharmony_ci            ctx->framerate_range[1] = available_framerates.data.i32[1];
325cabdff1aSopenharmony_ci        }
326cabdff1aSopenharmony_ci
327cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_WARNING,
328cabdff1aSopenharmony_ci               "Requested framerate %d not available, falling back to min: %d and max: %d fps\n",
329cabdff1aSopenharmony_ci               requested_framerate, ctx->framerate_range[0], ctx->framerate_range[1]);
330cabdff1aSopenharmony_ci    }
331cabdff1aSopenharmony_ci
332cabdff1aSopenharmony_ci    return;
333cabdff1aSopenharmony_ci}
334cabdff1aSopenharmony_ci
335cabdff1aSopenharmony_cistatic int get_image_format(AVFormatContext *avctx, AImage *image)
336cabdff1aSopenharmony_ci{
337cabdff1aSopenharmony_ci    AndroidCameraCtx *ctx = avctx->priv_data;
338cabdff1aSopenharmony_ci    int32_t image_pixelstrides[2];
339cabdff1aSopenharmony_ci    uint8_t *image_plane_data[2];
340cabdff1aSopenharmony_ci    int plane_data_length[2];
341cabdff1aSopenharmony_ci
342cabdff1aSopenharmony_ci    for (int i = 0; i < 2; i++) {
343cabdff1aSopenharmony_ci        AImage_getPlanePixelStride(image, i + 1, &image_pixelstrides[i]);
344cabdff1aSopenharmony_ci        AImage_getPlaneData(image, i + 1, &image_plane_data[i], &plane_data_length[i]);
345cabdff1aSopenharmony_ci    }
346cabdff1aSopenharmony_ci
347cabdff1aSopenharmony_ci    if (image_pixelstrides[0] != image_pixelstrides[1]) {
348cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR,
349cabdff1aSopenharmony_ci               "Pixel strides of U and V plane should have been the same.\n");
350cabdff1aSopenharmony_ci        return AVERROR_EXTERNAL;
351cabdff1aSopenharmony_ci    }
352cabdff1aSopenharmony_ci
353cabdff1aSopenharmony_ci    switch (image_pixelstrides[0]) {
354cabdff1aSopenharmony_ci        case 1:
355cabdff1aSopenharmony_ci            ctx->image_format = AV_PIX_FMT_YUV420P;
356cabdff1aSopenharmony_ci            break;
357cabdff1aSopenharmony_ci        case 2:
358cabdff1aSopenharmony_ci            if (image_plane_data[0] < image_plane_data[1]) {
359cabdff1aSopenharmony_ci                ctx->image_format = AV_PIX_FMT_NV12;
360cabdff1aSopenharmony_ci            } else {
361cabdff1aSopenharmony_ci                ctx->image_format = AV_PIX_FMT_NV21;
362cabdff1aSopenharmony_ci            }
363cabdff1aSopenharmony_ci            break;
364cabdff1aSopenharmony_ci        default:
365cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR,
366cabdff1aSopenharmony_ci                   "Unknown pixel stride %d of U and V plane, cannot determine camera image format.\n",
367cabdff1aSopenharmony_ci                   image_pixelstrides[0]);
368cabdff1aSopenharmony_ci            return AVERROR(ENOSYS);
369cabdff1aSopenharmony_ci    }
370cabdff1aSopenharmony_ci
371cabdff1aSopenharmony_ci    return 0;
372cabdff1aSopenharmony_ci}
373cabdff1aSopenharmony_ci
374cabdff1aSopenharmony_cistatic void image_available(void *context, AImageReader *reader)
375cabdff1aSopenharmony_ci{
376cabdff1aSopenharmony_ci    AVFormatContext *avctx = context;
377cabdff1aSopenharmony_ci    AndroidCameraCtx *ctx = avctx->priv_data;
378cabdff1aSopenharmony_ci    media_status_t media_status;
379cabdff1aSopenharmony_ci    int ret = 0;
380cabdff1aSopenharmony_ci
381cabdff1aSopenharmony_ci    AImage *image;
382cabdff1aSopenharmony_ci    int64_t image_timestamp;
383cabdff1aSopenharmony_ci    int32_t image_linestrides[4];
384cabdff1aSopenharmony_ci    uint8_t *image_plane_data[4];
385cabdff1aSopenharmony_ci    int plane_data_length[4];
386cabdff1aSopenharmony_ci
387cabdff1aSopenharmony_ci    AVPacket pkt;
388cabdff1aSopenharmony_ci    int pkt_buffer_size = 0;
389cabdff1aSopenharmony_ci
390cabdff1aSopenharmony_ci    media_status = AImageReader_acquireLatestImage(reader, &image);
391cabdff1aSopenharmony_ci    if (media_status != AMEDIA_OK) {
392cabdff1aSopenharmony_ci        if (media_status == AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE) {
393cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_WARNING,
394cabdff1aSopenharmony_ci                   "An image reader frame was discarded");
395cabdff1aSopenharmony_ci        } else {
396cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR,
397cabdff1aSopenharmony_ci                   "Failed to acquire latest image from image reader, error: %s.\n",
398cabdff1aSopenharmony_ci                   media_status_string(media_status));
399cabdff1aSopenharmony_ci            ret = AVERROR_EXTERNAL;
400cabdff1aSopenharmony_ci        }
401cabdff1aSopenharmony_ci        goto error;
402cabdff1aSopenharmony_ci    }
403cabdff1aSopenharmony_ci
404cabdff1aSopenharmony_ci    // Silently drop frames when exit is set
405cabdff1aSopenharmony_ci    if (atomic_load(&ctx->exit)) {
406cabdff1aSopenharmony_ci        goto error;
407cabdff1aSopenharmony_ci    }
408cabdff1aSopenharmony_ci
409cabdff1aSopenharmony_ci    // Determine actual image format
410cabdff1aSopenharmony_ci    if (!atomic_load(&ctx->got_image_format)) {
411cabdff1aSopenharmony_ci        ret = get_image_format(avctx, image);
412cabdff1aSopenharmony_ci        if (ret < 0) {
413cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR,
414cabdff1aSopenharmony_ci                   "Could not get image format of camera.\n");
415cabdff1aSopenharmony_ci            goto error;
416cabdff1aSopenharmony_ci        } else {
417cabdff1aSopenharmony_ci            atomic_store(&ctx->got_image_format, 1);
418cabdff1aSopenharmony_ci        }
419cabdff1aSopenharmony_ci    }
420cabdff1aSopenharmony_ci
421cabdff1aSopenharmony_ci    pkt_buffer_size = av_image_get_buffer_size(ctx->image_format, ctx->width, ctx->height, 32);
422cabdff1aSopenharmony_ci    AImage_getTimestamp(image, &image_timestamp);
423cabdff1aSopenharmony_ci
424cabdff1aSopenharmony_ci    AImage_getPlaneRowStride(image, 0, &image_linestrides[0]);
425cabdff1aSopenharmony_ci    AImage_getPlaneData(image, 0, &image_plane_data[0], &plane_data_length[0]);
426cabdff1aSopenharmony_ci
427cabdff1aSopenharmony_ci    switch (ctx->image_format) {
428cabdff1aSopenharmony_ci        case AV_PIX_FMT_YUV420P:
429cabdff1aSopenharmony_ci            AImage_getPlaneRowStride(image, 1, &image_linestrides[1]);
430cabdff1aSopenharmony_ci            AImage_getPlaneData(image, 1, &image_plane_data[1], &plane_data_length[1]);
431cabdff1aSopenharmony_ci            AImage_getPlaneRowStride(image, 2, &image_linestrides[2]);
432cabdff1aSopenharmony_ci            AImage_getPlaneData(image, 2, &image_plane_data[2], &plane_data_length[2]);
433cabdff1aSopenharmony_ci            break;
434cabdff1aSopenharmony_ci        case AV_PIX_FMT_NV12:
435cabdff1aSopenharmony_ci            AImage_getPlaneRowStride(image, 1, &image_linestrides[1]);
436cabdff1aSopenharmony_ci            AImage_getPlaneData(image, 1, &image_plane_data[1], &plane_data_length[1]);
437cabdff1aSopenharmony_ci            break;
438cabdff1aSopenharmony_ci        case AV_PIX_FMT_NV21:
439cabdff1aSopenharmony_ci            AImage_getPlaneRowStride(image, 2, &image_linestrides[1]);
440cabdff1aSopenharmony_ci            AImage_getPlaneData(image, 2, &image_plane_data[1], &plane_data_length[1]);
441cabdff1aSopenharmony_ci            break;
442cabdff1aSopenharmony_ci        default:
443cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR, "Unsupported camera image format.\n");
444cabdff1aSopenharmony_ci            ret = AVERROR(ENOSYS);
445cabdff1aSopenharmony_ci            goto error;
446cabdff1aSopenharmony_ci    }
447cabdff1aSopenharmony_ci
448cabdff1aSopenharmony_ci    ret = av_new_packet(&pkt, pkt_buffer_size);
449cabdff1aSopenharmony_ci    if (ret < 0) {
450cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR,
451cabdff1aSopenharmony_ci               "Failed to create new av packet, error: %s.\n", av_err2str(ret));
452cabdff1aSopenharmony_ci        goto error;
453cabdff1aSopenharmony_ci    }
454cabdff1aSopenharmony_ci
455cabdff1aSopenharmony_ci    pkt.stream_index = VIDEO_STREAM_INDEX;
456cabdff1aSopenharmony_ci    pkt.pts = image_timestamp;
457cabdff1aSopenharmony_ci    av_image_copy_to_buffer(pkt.data, pkt_buffer_size,
458cabdff1aSopenharmony_ci                            (const uint8_t * const *) image_plane_data,
459cabdff1aSopenharmony_ci                            image_linestrides, ctx->image_format,
460cabdff1aSopenharmony_ci                            ctx->width, ctx->height, 32);
461cabdff1aSopenharmony_ci
462cabdff1aSopenharmony_ci    ret = av_thread_message_queue_send(ctx->input_queue, &pkt, AV_THREAD_MESSAGE_NONBLOCK);
463cabdff1aSopenharmony_ci
464cabdff1aSopenharmony_cierror:
465cabdff1aSopenharmony_ci    if (ret < 0) {
466cabdff1aSopenharmony_ci        if (ret != AVERROR(EAGAIN)) {
467cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_ERROR,
468cabdff1aSopenharmony_ci                   "Error while processing new image, error: %s.\n", av_err2str(ret));
469cabdff1aSopenharmony_ci            av_thread_message_queue_set_err_recv(ctx->input_queue, ret);
470cabdff1aSopenharmony_ci            atomic_store(&ctx->exit, 1);
471cabdff1aSopenharmony_ci        } else {
472cabdff1aSopenharmony_ci            av_log(avctx, AV_LOG_WARNING,
473cabdff1aSopenharmony_ci                   "Input queue was full, dropping frame, consider raising the input_queue_size option (current value: %d)\n",
474cabdff1aSopenharmony_ci                   ctx->input_queue_size);
475cabdff1aSopenharmony_ci        }
476cabdff1aSopenharmony_ci        if (pkt_buffer_size) {
477cabdff1aSopenharmony_ci            av_packet_unref(&pkt);
478cabdff1aSopenharmony_ci        }
479cabdff1aSopenharmony_ci    }
480cabdff1aSopenharmony_ci
481cabdff1aSopenharmony_ci    AImage_delete(image);
482cabdff1aSopenharmony_ci
483cabdff1aSopenharmony_ci    return;
484cabdff1aSopenharmony_ci}
485cabdff1aSopenharmony_ci
486cabdff1aSopenharmony_cistatic int create_image_reader(AVFormatContext *avctx)
487cabdff1aSopenharmony_ci{
488cabdff1aSopenharmony_ci    AndroidCameraCtx *ctx = avctx->priv_data;
489cabdff1aSopenharmony_ci    media_status_t ret;
490cabdff1aSopenharmony_ci
491cabdff1aSopenharmony_ci    ret = AImageReader_new(ctx->width, ctx->height, IMAGE_FORMAT_ANDROID,
492cabdff1aSopenharmony_ci                           MAX_BUF_COUNT, &ctx->image_reader);
493cabdff1aSopenharmony_ci    if (ret != AMEDIA_OK) {
494cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR,
495cabdff1aSopenharmony_ci               "Failed to create image reader, error: %s.\n", media_status_string(ret));
496cabdff1aSopenharmony_ci        return AVERROR_EXTERNAL;
497cabdff1aSopenharmony_ci    }
498cabdff1aSopenharmony_ci
499cabdff1aSopenharmony_ci    ctx->image_listener.context = avctx;
500cabdff1aSopenharmony_ci    ctx->image_listener.onImageAvailable = image_available;
501cabdff1aSopenharmony_ci
502cabdff1aSopenharmony_ci    ret = AImageReader_setImageListener(ctx->image_reader, &ctx->image_listener);
503cabdff1aSopenharmony_ci    if (ret != AMEDIA_OK) {
504cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR,
505cabdff1aSopenharmony_ci               "Failed to set image listener on image reader, error: %s.\n",
506cabdff1aSopenharmony_ci               media_status_string(ret));
507cabdff1aSopenharmony_ci        return AVERROR_EXTERNAL;
508cabdff1aSopenharmony_ci    }
509cabdff1aSopenharmony_ci
510cabdff1aSopenharmony_ci    ret = AImageReader_getWindow(ctx->image_reader, &ctx->image_reader_window);
511cabdff1aSopenharmony_ci    if (ret != AMEDIA_OK) {
512cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR,
513cabdff1aSopenharmony_ci               "Could not get image reader window, error: %s.\n",
514cabdff1aSopenharmony_ci               media_status_string(ret));
515cabdff1aSopenharmony_ci        return AVERROR_EXTERNAL;
516cabdff1aSopenharmony_ci    }
517cabdff1aSopenharmony_ci
518cabdff1aSopenharmony_ci    return 0;
519cabdff1aSopenharmony_ci}
520cabdff1aSopenharmony_ci
521cabdff1aSopenharmony_cistatic void capture_session_closed(void *context, ACameraCaptureSession *session)
522cabdff1aSopenharmony_ci{
523cabdff1aSopenharmony_ci    av_log(context, AV_LOG_INFO, "Android camera capture session was closed.\n");
524cabdff1aSopenharmony_ci}
525cabdff1aSopenharmony_ci
526cabdff1aSopenharmony_cistatic void capture_session_ready(void *context, ACameraCaptureSession *session)
527cabdff1aSopenharmony_ci{
528cabdff1aSopenharmony_ci    av_log(context, AV_LOG_INFO, "Android camera capture session is ready.\n");
529cabdff1aSopenharmony_ci}
530cabdff1aSopenharmony_ci
531cabdff1aSopenharmony_cistatic void capture_session_active(void *context, ACameraCaptureSession *session)
532cabdff1aSopenharmony_ci{
533cabdff1aSopenharmony_ci    av_log(context, AV_LOG_INFO, "Android camera capture session is active.\n");
534cabdff1aSopenharmony_ci}
535cabdff1aSopenharmony_ci
536cabdff1aSopenharmony_cistatic int create_capture_session(AVFormatContext *avctx)
537cabdff1aSopenharmony_ci{
538cabdff1aSopenharmony_ci    AndroidCameraCtx *ctx = avctx->priv_data;
539cabdff1aSopenharmony_ci    camera_status_t ret;
540cabdff1aSopenharmony_ci
541cabdff1aSopenharmony_ci    ret = ACaptureSessionOutputContainer_create(&ctx->capture_session_output_container);
542cabdff1aSopenharmony_ci    if (ret != ACAMERA_OK) {
543cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR,
544cabdff1aSopenharmony_ci               "Failed to create capture session output container, error: %s.\n",
545cabdff1aSopenharmony_ci               camera_status_string(ret));
546cabdff1aSopenharmony_ci        return AVERROR_EXTERNAL;
547cabdff1aSopenharmony_ci    }
548cabdff1aSopenharmony_ci
549cabdff1aSopenharmony_ci    ANativeWindow_acquire(ctx->image_reader_window);
550cabdff1aSopenharmony_ci
551cabdff1aSopenharmony_ci    ret = ACaptureSessionOutput_create(ctx->image_reader_window, &ctx->capture_session_output);
552cabdff1aSopenharmony_ci    if (ret != ACAMERA_OK) {
553cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR,
554cabdff1aSopenharmony_ci               "Failed to create capture session container, error: %s.\n",
555cabdff1aSopenharmony_ci               camera_status_string(ret));
556cabdff1aSopenharmony_ci        return AVERROR_EXTERNAL;
557cabdff1aSopenharmony_ci    }
558cabdff1aSopenharmony_ci
559cabdff1aSopenharmony_ci    ret = ACaptureSessionOutputContainer_add(ctx->capture_session_output_container,
560cabdff1aSopenharmony_ci                                             ctx->capture_session_output);
561cabdff1aSopenharmony_ci    if (ret != ACAMERA_OK) {
562cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR,
563cabdff1aSopenharmony_ci               "Failed to add output to output container, error: %s.\n",
564cabdff1aSopenharmony_ci               camera_status_string(ret));
565cabdff1aSopenharmony_ci        return AVERROR_EXTERNAL;
566cabdff1aSopenharmony_ci    }
567cabdff1aSopenharmony_ci
568cabdff1aSopenharmony_ci    ret = ACameraOutputTarget_create(ctx->image_reader_window, &ctx->camera_output_target);
569cabdff1aSopenharmony_ci    if (ret != ACAMERA_OK) {
570cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR,
571cabdff1aSopenharmony_ci               "Failed to create camera output target, error: %s.\n",
572cabdff1aSopenharmony_ci               camera_status_string(ret));
573cabdff1aSopenharmony_ci        return AVERROR_EXTERNAL;
574cabdff1aSopenharmony_ci    }
575cabdff1aSopenharmony_ci
576cabdff1aSopenharmony_ci    ret = ACameraDevice_createCaptureRequest(ctx->camera_dev, TEMPLATE_RECORD, &ctx->capture_request);
577cabdff1aSopenharmony_ci    if (ret != ACAMERA_OK) {
578cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR,
579cabdff1aSopenharmony_ci               "Failed to create capture request, error: %s.\n",
580cabdff1aSopenharmony_ci               camera_status_string(ret));
581cabdff1aSopenharmony_ci        return AVERROR_EXTERNAL;
582cabdff1aSopenharmony_ci    }
583cabdff1aSopenharmony_ci
584cabdff1aSopenharmony_ci    ret = ACaptureRequest_setEntry_i32(ctx->capture_request, ACAMERA_CONTROL_AE_TARGET_FPS_RANGE,
585cabdff1aSopenharmony_ci                                       2, ctx->framerate_range);
586cabdff1aSopenharmony_ci    if (ret != ACAMERA_OK) {
587cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR,
588cabdff1aSopenharmony_ci               "Failed to set target fps range in capture request, error: %s.\n",
589cabdff1aSopenharmony_ci               camera_status_string(ret));
590cabdff1aSopenharmony_ci        return AVERROR_EXTERNAL;
591cabdff1aSopenharmony_ci    }
592cabdff1aSopenharmony_ci
593cabdff1aSopenharmony_ci    ret = ACaptureRequest_addTarget(ctx->capture_request, ctx->camera_output_target);
594cabdff1aSopenharmony_ci    if (ret != ACAMERA_OK) {
595cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR,
596cabdff1aSopenharmony_ci               "Failed to add capture request capture request, error: %s.\n",
597cabdff1aSopenharmony_ci               camera_status_string(ret));
598cabdff1aSopenharmony_ci        return AVERROR_EXTERNAL;
599cabdff1aSopenharmony_ci    }
600cabdff1aSopenharmony_ci
601cabdff1aSopenharmony_ci    ctx->capture_session_state_callbacks.context = avctx;
602cabdff1aSopenharmony_ci    ctx->capture_session_state_callbacks.onClosed = capture_session_closed;
603cabdff1aSopenharmony_ci    ctx->capture_session_state_callbacks.onReady = capture_session_ready;
604cabdff1aSopenharmony_ci    ctx->capture_session_state_callbacks.onActive = capture_session_active;
605cabdff1aSopenharmony_ci
606cabdff1aSopenharmony_ci    ret = ACameraDevice_createCaptureSession(ctx->camera_dev, ctx->capture_session_output_container,
607cabdff1aSopenharmony_ci                                             &ctx->capture_session_state_callbacks, &ctx->capture_session);
608cabdff1aSopenharmony_ci    if (ret != ACAMERA_OK) {
609cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR,
610cabdff1aSopenharmony_ci               "Failed to create capture session, error: %s.\n",
611cabdff1aSopenharmony_ci               camera_status_string(ret));
612cabdff1aSopenharmony_ci        return AVERROR_EXTERNAL;
613cabdff1aSopenharmony_ci    }
614cabdff1aSopenharmony_ci
615cabdff1aSopenharmony_ci    ret = ACameraCaptureSession_setRepeatingRequest(ctx->capture_session, NULL, 1, &ctx->capture_request, NULL);
616cabdff1aSopenharmony_ci    if (ret != ACAMERA_OK) {
617cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR,
618cabdff1aSopenharmony_ci               "Failed to set repeating request on capture session, error: %s.\n",
619cabdff1aSopenharmony_ci               camera_status_string(ret));
620cabdff1aSopenharmony_ci        return AVERROR_EXTERNAL;
621cabdff1aSopenharmony_ci    }
622cabdff1aSopenharmony_ci
623cabdff1aSopenharmony_ci    return 0;
624cabdff1aSopenharmony_ci}
625cabdff1aSopenharmony_ci
626cabdff1aSopenharmony_cistatic int wait_for_image_format(AVFormatContext *avctx)
627cabdff1aSopenharmony_ci{
628cabdff1aSopenharmony_ci    AndroidCameraCtx *ctx = avctx->priv_data;
629cabdff1aSopenharmony_ci
630cabdff1aSopenharmony_ci    while (!atomic_load(&ctx->got_image_format) && !atomic_load(&ctx->exit)) {
631cabdff1aSopenharmony_ci        //Wait until first frame arrived and actual image format was determined
632cabdff1aSopenharmony_ci        usleep(1000);
633cabdff1aSopenharmony_ci    }
634cabdff1aSopenharmony_ci
635cabdff1aSopenharmony_ci    return atomic_load(&ctx->got_image_format);
636cabdff1aSopenharmony_ci}
637cabdff1aSopenharmony_ci
638cabdff1aSopenharmony_cistatic int add_display_matrix(AVFormatContext *avctx, AVStream *st)
639cabdff1aSopenharmony_ci{
640cabdff1aSopenharmony_ci    AndroidCameraCtx *ctx = avctx->priv_data;
641cabdff1aSopenharmony_ci    uint8_t *side_data;
642cabdff1aSopenharmony_ci    int32_t display_matrix[9];
643cabdff1aSopenharmony_ci
644cabdff1aSopenharmony_ci    av_display_rotation_set(display_matrix, ctx->sensor_orientation);
645cabdff1aSopenharmony_ci
646cabdff1aSopenharmony_ci    if (ctx->lens_facing == ACAMERA_LENS_FACING_FRONT) {
647cabdff1aSopenharmony_ci        av_display_matrix_flip(display_matrix, 1, 0);
648cabdff1aSopenharmony_ci    }
649cabdff1aSopenharmony_ci
650cabdff1aSopenharmony_ci    side_data = av_stream_new_side_data(st,
651cabdff1aSopenharmony_ci            AV_PKT_DATA_DISPLAYMATRIX, sizeof(display_matrix));
652cabdff1aSopenharmony_ci
653cabdff1aSopenharmony_ci    if (!side_data) {
654cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
655cabdff1aSopenharmony_ci    }
656cabdff1aSopenharmony_ci
657cabdff1aSopenharmony_ci    memcpy(side_data, display_matrix, sizeof(display_matrix));
658cabdff1aSopenharmony_ci
659cabdff1aSopenharmony_ci    return 0;
660cabdff1aSopenharmony_ci}
661cabdff1aSopenharmony_ci
662cabdff1aSopenharmony_cistatic int add_video_stream(AVFormatContext *avctx)
663cabdff1aSopenharmony_ci{
664cabdff1aSopenharmony_ci    AndroidCameraCtx *ctx = avctx->priv_data;
665cabdff1aSopenharmony_ci    AVStream *st;
666cabdff1aSopenharmony_ci    AVCodecParameters *codecpar;
667cabdff1aSopenharmony_ci
668cabdff1aSopenharmony_ci    st = avformat_new_stream(avctx, NULL);
669cabdff1aSopenharmony_ci    if (!st) {
670cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
671cabdff1aSopenharmony_ci    }
672cabdff1aSopenharmony_ci
673cabdff1aSopenharmony_ci    st->id = VIDEO_STREAM_INDEX;
674cabdff1aSopenharmony_ci    st->avg_frame_rate = (AVRational) { ctx->framerate_range[1], 1 };
675cabdff1aSopenharmony_ci    st->r_frame_rate = (AVRational) { ctx->framerate_range[1], 1 };
676cabdff1aSopenharmony_ci
677cabdff1aSopenharmony_ci    if (!wait_for_image_format(avctx)) {
678cabdff1aSopenharmony_ci        return AVERROR_EXTERNAL;
679cabdff1aSopenharmony_ci    }
680cabdff1aSopenharmony_ci
681cabdff1aSopenharmony_ci    codecpar = st->codecpar;
682cabdff1aSopenharmony_ci    codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
683cabdff1aSopenharmony_ci    codecpar->codec_id = AV_CODEC_ID_RAWVIDEO;
684cabdff1aSopenharmony_ci    codecpar->format = ctx->image_format;
685cabdff1aSopenharmony_ci    codecpar->width = ctx->width;
686cabdff1aSopenharmony_ci    codecpar->height = ctx->height;
687cabdff1aSopenharmony_ci
688cabdff1aSopenharmony_ci    avpriv_set_pts_info(st, 64, 1, VIDEO_TIMEBASE_ANDROID);
689cabdff1aSopenharmony_ci
690cabdff1aSopenharmony_ci    return add_display_matrix(avctx, st);
691cabdff1aSopenharmony_ci}
692cabdff1aSopenharmony_ci
693cabdff1aSopenharmony_cistatic int android_camera_read_close(AVFormatContext *avctx)
694cabdff1aSopenharmony_ci{
695cabdff1aSopenharmony_ci    AndroidCameraCtx *ctx = avctx->priv_data;
696cabdff1aSopenharmony_ci
697cabdff1aSopenharmony_ci    atomic_store(&ctx->exit, 1);
698cabdff1aSopenharmony_ci
699cabdff1aSopenharmony_ci    if (ctx->capture_session) {
700cabdff1aSopenharmony_ci        ACameraCaptureSession_stopRepeating(ctx->capture_session);
701cabdff1aSopenharmony_ci        // Following warning is emitted, after capture session closed callback is received:
702cabdff1aSopenharmony_ci        // ACameraCaptureSession: Device is closed but session 0 is not notified
703cabdff1aSopenharmony_ci        // Seems to be a bug in Android, we can ignore this
704cabdff1aSopenharmony_ci        ACameraCaptureSession_close(ctx->capture_session);
705cabdff1aSopenharmony_ci        ctx->capture_session = NULL;
706cabdff1aSopenharmony_ci    }
707cabdff1aSopenharmony_ci
708cabdff1aSopenharmony_ci    if (ctx->capture_request) {
709cabdff1aSopenharmony_ci        ACaptureRequest_removeTarget(ctx->capture_request, ctx->camera_output_target);
710cabdff1aSopenharmony_ci        ACaptureRequest_free(ctx->capture_request);
711cabdff1aSopenharmony_ci        ctx->capture_request = NULL;
712cabdff1aSopenharmony_ci    }
713cabdff1aSopenharmony_ci
714cabdff1aSopenharmony_ci    if (ctx->camera_output_target) {
715cabdff1aSopenharmony_ci        ACameraOutputTarget_free(ctx->camera_output_target);
716cabdff1aSopenharmony_ci        ctx->camera_output_target = NULL;
717cabdff1aSopenharmony_ci    }
718cabdff1aSopenharmony_ci
719cabdff1aSopenharmony_ci    if (ctx->capture_session_output) {
720cabdff1aSopenharmony_ci        ACaptureSessionOutputContainer_remove(ctx->capture_session_output_container,
721cabdff1aSopenharmony_ci                ctx->capture_session_output);
722cabdff1aSopenharmony_ci        ACaptureSessionOutput_free(ctx->capture_session_output);
723cabdff1aSopenharmony_ci        ctx->capture_session_output = NULL;
724cabdff1aSopenharmony_ci    }
725cabdff1aSopenharmony_ci
726cabdff1aSopenharmony_ci    if (ctx->image_reader_window) {
727cabdff1aSopenharmony_ci        ANativeWindow_release(ctx->image_reader_window);
728cabdff1aSopenharmony_ci        ctx->image_reader_window = NULL;
729cabdff1aSopenharmony_ci    }
730cabdff1aSopenharmony_ci
731cabdff1aSopenharmony_ci    if (ctx->capture_session_output_container) {
732cabdff1aSopenharmony_ci        ACaptureSessionOutputContainer_free(ctx->capture_session_output_container);
733cabdff1aSopenharmony_ci        ctx->capture_session_output_container = NULL;
734cabdff1aSopenharmony_ci    }
735cabdff1aSopenharmony_ci
736cabdff1aSopenharmony_ci    if (ctx->camera_dev) {
737cabdff1aSopenharmony_ci        ACameraDevice_close(ctx->camera_dev);
738cabdff1aSopenharmony_ci        ctx->camera_dev = NULL;
739cabdff1aSopenharmony_ci    }
740cabdff1aSopenharmony_ci
741cabdff1aSopenharmony_ci    if (ctx->image_reader) {
742cabdff1aSopenharmony_ci        AImageReader_delete(ctx->image_reader);
743cabdff1aSopenharmony_ci        ctx->image_reader = NULL;
744cabdff1aSopenharmony_ci    }
745cabdff1aSopenharmony_ci
746cabdff1aSopenharmony_ci    if (ctx->camera_metadata) {
747cabdff1aSopenharmony_ci        ACameraMetadata_free(ctx->camera_metadata);
748cabdff1aSopenharmony_ci        ctx->camera_metadata = NULL;
749cabdff1aSopenharmony_ci    }
750cabdff1aSopenharmony_ci
751cabdff1aSopenharmony_ci    av_freep(&ctx->camera_id);
752cabdff1aSopenharmony_ci
753cabdff1aSopenharmony_ci    if (ctx->camera_mgr) {
754cabdff1aSopenharmony_ci        ACameraManager_delete(ctx->camera_mgr);
755cabdff1aSopenharmony_ci        ctx->camera_mgr = NULL;
756cabdff1aSopenharmony_ci    }
757cabdff1aSopenharmony_ci
758cabdff1aSopenharmony_ci    if (ctx->input_queue) {
759cabdff1aSopenharmony_ci        AVPacket pkt;
760cabdff1aSopenharmony_ci        av_thread_message_queue_set_err_send(ctx->input_queue, AVERROR_EOF);
761cabdff1aSopenharmony_ci        while (av_thread_message_queue_recv(ctx->input_queue, &pkt, AV_THREAD_MESSAGE_NONBLOCK) >= 0) {
762cabdff1aSopenharmony_ci            av_packet_unref(&pkt);
763cabdff1aSopenharmony_ci        }
764cabdff1aSopenharmony_ci        av_thread_message_queue_free(&ctx->input_queue);
765cabdff1aSopenharmony_ci    }
766cabdff1aSopenharmony_ci
767cabdff1aSopenharmony_ci    return 0;
768cabdff1aSopenharmony_ci}
769cabdff1aSopenharmony_ci
770cabdff1aSopenharmony_cistatic int android_camera_read_header(AVFormatContext *avctx)
771cabdff1aSopenharmony_ci{
772cabdff1aSopenharmony_ci    AndroidCameraCtx *ctx = avctx->priv_data;
773cabdff1aSopenharmony_ci    int ret;
774cabdff1aSopenharmony_ci
775cabdff1aSopenharmony_ci    atomic_init(&ctx->got_image_format, 0);
776cabdff1aSopenharmony_ci    atomic_init(&ctx->exit, 0);
777cabdff1aSopenharmony_ci
778cabdff1aSopenharmony_ci    ret = av_thread_message_queue_alloc(&ctx->input_queue, ctx->input_queue_size, sizeof(AVPacket));
779cabdff1aSopenharmony_ci    if (ret < 0) {
780cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR,
781cabdff1aSopenharmony_ci               "Failed to allocate input queue, error: %s.\n", av_err2str(ret));
782cabdff1aSopenharmony_ci        goto error;
783cabdff1aSopenharmony_ci    }
784cabdff1aSopenharmony_ci
785cabdff1aSopenharmony_ci    ctx->camera_mgr = ACameraManager_create();
786cabdff1aSopenharmony_ci    if (!ctx->camera_mgr) {
787cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Failed to create Android camera manager.\n");
788cabdff1aSopenharmony_ci        ret = AVERROR_EXTERNAL;
789cabdff1aSopenharmony_ci        goto error;
790cabdff1aSopenharmony_ci    }
791cabdff1aSopenharmony_ci
792cabdff1aSopenharmony_ci    ret = open_camera(avctx);
793cabdff1aSopenharmony_ci    if (ret < 0) {
794cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Failed to open camera.\n");
795cabdff1aSopenharmony_ci        goto error;
796cabdff1aSopenharmony_ci    }
797cabdff1aSopenharmony_ci
798cabdff1aSopenharmony_ci    get_sensor_orientation(avctx);
799cabdff1aSopenharmony_ci    match_video_size(avctx);
800cabdff1aSopenharmony_ci    match_framerate(avctx);
801cabdff1aSopenharmony_ci
802cabdff1aSopenharmony_ci    ret = create_image_reader(avctx);
803cabdff1aSopenharmony_ci    if (ret < 0) {
804cabdff1aSopenharmony_ci        goto error;
805cabdff1aSopenharmony_ci    }
806cabdff1aSopenharmony_ci
807cabdff1aSopenharmony_ci    ret = create_capture_session(avctx);
808cabdff1aSopenharmony_ci    if (ret < 0) {
809cabdff1aSopenharmony_ci        goto error;
810cabdff1aSopenharmony_ci    }
811cabdff1aSopenharmony_ci
812cabdff1aSopenharmony_ci    ret = add_video_stream(avctx);
813cabdff1aSopenharmony_ci
814cabdff1aSopenharmony_cierror:
815cabdff1aSopenharmony_ci    if (ret < 0) {
816cabdff1aSopenharmony_ci        android_camera_read_close(avctx);
817cabdff1aSopenharmony_ci        av_log(avctx, AV_LOG_ERROR, "Failed to open android_camera.\n");
818cabdff1aSopenharmony_ci    }
819cabdff1aSopenharmony_ci
820cabdff1aSopenharmony_ci    return ret;
821cabdff1aSopenharmony_ci}
822cabdff1aSopenharmony_ci
823cabdff1aSopenharmony_cistatic int android_camera_read_packet(AVFormatContext *avctx, AVPacket *pkt)
824cabdff1aSopenharmony_ci{
825cabdff1aSopenharmony_ci    AndroidCameraCtx *ctx = avctx->priv_data;
826cabdff1aSopenharmony_ci    int ret;
827cabdff1aSopenharmony_ci
828cabdff1aSopenharmony_ci    if (!atomic_load(&ctx->exit)) {
829cabdff1aSopenharmony_ci        ret = av_thread_message_queue_recv(ctx->input_queue, pkt,
830cabdff1aSopenharmony_ci                avctx->flags & AVFMT_FLAG_NONBLOCK ? AV_THREAD_MESSAGE_NONBLOCK : 0);
831cabdff1aSopenharmony_ci    } else {
832cabdff1aSopenharmony_ci        ret = AVERROR_EOF;
833cabdff1aSopenharmony_ci    }
834cabdff1aSopenharmony_ci
835cabdff1aSopenharmony_ci    if (ret < 0) {
836cabdff1aSopenharmony_ci        return ret;
837cabdff1aSopenharmony_ci    } else {
838cabdff1aSopenharmony_ci        return pkt->size;
839cabdff1aSopenharmony_ci    }
840cabdff1aSopenharmony_ci}
841cabdff1aSopenharmony_ci
842cabdff1aSopenharmony_ci#define OFFSET(x) offsetof(AndroidCameraCtx, x)
843cabdff1aSopenharmony_ci#define DEC AV_OPT_FLAG_DECODING_PARAM
844cabdff1aSopenharmony_cistatic const AVOption options[] = {
845cabdff1aSopenharmony_ci    { "video_size", "set video size given as a string such as 640x480 or hd720", OFFSET(requested_width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, DEC },
846cabdff1aSopenharmony_ci    { "framerate", "set video frame rate", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "30"}, 0, INT_MAX, DEC },
847cabdff1aSopenharmony_ci    { "camera_index", "set index of camera to use", OFFSET(camera_index), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC },
848cabdff1aSopenharmony_ci    { "input_queue_size", "set maximum number of frames to buffer", OFFSET(input_queue_size), AV_OPT_TYPE_INT, {.i64 = 5}, 0, INT_MAX, DEC },
849cabdff1aSopenharmony_ci    { NULL },
850cabdff1aSopenharmony_ci};
851cabdff1aSopenharmony_ci
852cabdff1aSopenharmony_cistatic const AVClass android_camera_class = {
853cabdff1aSopenharmony_ci    .class_name = "android_camera indev",
854cabdff1aSopenharmony_ci    .item_name  = av_default_item_name,
855cabdff1aSopenharmony_ci    .option     = options,
856cabdff1aSopenharmony_ci    .version    = LIBAVUTIL_VERSION_INT,
857cabdff1aSopenharmony_ci    .category   = AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT,
858cabdff1aSopenharmony_ci};
859cabdff1aSopenharmony_ci
860cabdff1aSopenharmony_ciconst AVInputFormat ff_android_camera_demuxer = {
861cabdff1aSopenharmony_ci    .name           = "android_camera",
862cabdff1aSopenharmony_ci    .long_name      = NULL_IF_CONFIG_SMALL("Android camera input device"),
863cabdff1aSopenharmony_ci    .priv_data_size = sizeof(AndroidCameraCtx),
864cabdff1aSopenharmony_ci    .read_header    = android_camera_read_header,
865cabdff1aSopenharmony_ci    .read_packet    = android_camera_read_packet,
866cabdff1aSopenharmony_ci    .read_close     = android_camera_read_close,
867cabdff1aSopenharmony_ci    .flags          = AVFMT_NOFILE,
868cabdff1aSopenharmony_ci    .priv_class     = &android_camera_class,
869cabdff1aSopenharmony_ci};
870