summaryrefslogtreecommitdiff
path: root/src/py/cam/cam_qtgl.py
blob: 6cfbd3476edd7351836f5f2e38c1942936ae1e91 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
# SPDX-License-Identifier: GPL-2.0-or-later
# Copyright (C) 2022, Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>

from PyQt5 import QtCore, QtWidgets
from PyQt5.QtCore import Qt

import math
import os
import sys

os.environ['PYOPENGL_PLATFORM'] = 'egl'

from OpenGL.EGL.EXT.image_dma_buf_import import *
from OpenGL.EGL.KHR.image import *
from OpenGL.EGL.VERSION.EGL_1_0 import *
from OpenGL.EGL.VERSION.EGL_1_2 import *
from OpenGL.EGL.VERSION.EGL_1_3 import *

from OpenGL.GLES2.OES.EGL_image import *
from OpenGL.GLES2.OES.EGL_image_external import *
from OpenGL.GLES2.VERSION.GLES2_2_0 import *
from OpenGL.GLES3.VERSION.GLES3_3_0 import *

from OpenGL.GL import shaders

from gl_helpers import *


class EglState:
    def __init__(self):
        self.create_display()
        self.choose_config()
        self.create_context()
        self.check_extensions()

    def create_display(self):
        xdpy = getEGLNativeDisplay()
        dpy = eglGetDisplay(xdpy)
        self.display = dpy

    def choose_config(self):
        dpy = self.display

        major, minor = EGLint(), EGLint()

        b = eglInitialize(dpy, major, minor)
        assert(b)

        print('EGL {} {}'.format(
              eglQueryString(dpy, EGL_VENDOR).decode(),
              eglQueryString(dpy, EGL_VERSION).decode()))

        check_egl_extensions(dpy, ['EGL_EXT_image_dma_buf_import'])

        b = eglBindAPI(EGL_OPENGL_ES_API)
        assert(b)

        def print_config(dpy, cfg):

            def getconf(a):
                value = ctypes.c_long()
                eglGetConfigAttrib(dpy, cfg, a, value)
                return value.value

            print('EGL Config {}: color buf {}/{}/{}/{} = {}, depth {}, stencil {}, native visualid {}, native visualtype {}'.format(
                getconf(EGL_CONFIG_ID),
                getconf(EGL_ALPHA_SIZE),
                getconf(EGL_RED_SIZE),
                getconf(EGL_GREEN_SIZE),
                getconf(EGL_BLUE_SIZE),
                getconf(EGL_BUFFER_SIZE),
                getconf(EGL_DEPTH_SIZE),
                getconf(EGL_STENCIL_SIZE),
                getconf(EGL_NATIVE_VISUAL_ID),
                getconf(EGL_NATIVE_VISUAL_TYPE)))

        if False:
            num_configs = ctypes.c_long()
            eglGetConfigs(dpy, None, 0, num_configs)
            print('{} configs'.format(num_configs.value))

            configs = (EGLConfig * num_configs.value)()
            eglGetConfigs(dpy, configs, num_configs.value, num_configs)
            for config_id in configs:
                print_config(dpy, config_id)

        config_attribs = [
            EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
            EGL_RED_SIZE, 8,
            EGL_GREEN_SIZE, 8,
            EGL_BLUE_SIZE, 8,
            EGL_ALPHA_SIZE, 0,
            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
            EGL_NONE,
        ]

        n = EGLint()
        configs = (EGLConfig * 1)()
        b = eglChooseConfig(dpy, config_attribs, configs, 1, n)
        assert(b and n.value == 1)
        config = configs[0]

        print('Chosen Config:')
        print_config(dpy, config)

        self.config = config

    def create_context(self):
        dpy = self.display

        context_attribs = [
            EGL_CONTEXT_CLIENT_VERSION, 2,
            EGL_NONE,
        ]

        context = eglCreateContext(dpy, self.config, EGL_NO_CONTEXT, context_attribs)
        assert(context)

        b = eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, context)
        assert(b)

        self.context = context

    def check_extensions(self):
        check_gl_extensions(['GL_OES_EGL_image'])

        assert(eglCreateImageKHR)
        assert(eglDestroyImageKHR)
        assert(glEGLImageTargetTexture2DOES)


class QtRenderer:
    def __init__(self, state):
        self.state = state

    def setup(self):
        self.app = QtWidgets.QApplication([])

        window = MainWindow(self.state)
        window.show()

        self.window = window

    def run(self):
        camnotif = QtCore.QSocketNotifier(self.state.cm.event_fd, QtCore.QSocketNotifier.Read)
        camnotif.activated.connect(lambda _: self.readcam())

        keynotif = QtCore.QSocketNotifier(sys.stdin.fileno(), QtCore.QSocketNotifier.Read)
        keynotif.activated.connect(lambda _: self.readkey())

        print('Capturing...')

        self.app.exec()

        print('Exiting...')

    def readcam(self):
        running = self.state.event_handler()

        if not running:
            self.app.quit()

    def readkey(self):
        sys.stdin.readline()
        self.app.quit()

    def request_handler(self, ctx, req):
        self.window.handle_request(ctx, req)

    def cleanup(self):
        self.window.close()


class MainWindow(QtWidgets.QWidget):
    def __init__(self, state):
        super().__init__()

        self.setAttribute(Qt.WA_PaintOnScreen)
        self.setAttribute(Qt.WA_NativeWindow)

        self.state = state

        self.textures = {}
        self.reqqueue = {}
        self.current = {}

        for ctx in self.state.contexts:

            self.reqqueue[ctx.idx] = []
            self.current[ctx.idx] = []

            for stream in ctx.streams:
                self.textures[stream] = None

        num_tiles = len(self.textures)
        self.num_columns = math.ceil(math.sqrt(num_tiles))
        self.num_rows = math.ceil(num_tiles / self.num_columns)

        self.egl = EglState()

        self.surface = None

    def paintEngine(self):
        return None

    def create_surface(self):
        native_surface = c_void_p(self.winId().__int__())
        surface = eglCreateWindowSurface(self.egl.display, self.egl.config,
                                         native_surface, None)

        b = eglMakeCurrent(self.egl.display, self.surface, self.surface, self.egl.context)
        assert(b)

        self.surface = surface

    def init_gl(self):
        self.create_surface()

        vertShaderSrc = '''
            attribute vec2 aPosition;
            varying vec2 texcoord;

            void main()
            {
                gl_Position = vec4(aPosition * 2.0 - 1.0, 0.0, 1.0);
                texcoord.x = aPosition.x;
                texcoord.y = 1.0 - aPosition.y;
            }
        '''
        fragShaderSrc = '''
            #extension GL_OES_EGL_image_external : enable
            precision mediump float;
            varying vec2 texcoord;
            uniform samplerExternalOES texture;

            void main()
            {
                gl_FragColor = texture2D(texture, texcoord);
            }
        '''

        program = shaders.compileProgram(
            shaders.compileShader(vertShaderSrc, GL_VERTEX_SHADER),
            shaders.compileShader(fragShaderSrc, GL_FRAGMENT_SHADER)
        )

        glUseProgram(program)

        glClearColor(0.5, 0.8, 0.7, 1.0)

        vertPositions = [
            0.0, 0.0,
            1.0, 0.0,
            1.0, 1.0,
            0.0, 1.0
        ]

        inputAttrib = glGetAttribLocation(program, 'aPosition')
        glVertexAttribPointer(inputAttrib, 2, GL_FLOAT, GL_FALSE, 0, vertPositions)
        glEnableVertexAttribArray(inputAttrib)

    def create_texture(self, stream, fb):
        cfg = stream.configuration
        fmt = cfg.pixel_format.fourcc
        w = cfg.size.width
        h = cfg.size.height

        attribs = [
            EGL_WIDTH, w,
            EGL_HEIGHT, h,
            EGL_LINUX_DRM_FOURCC_EXT, fmt,
            EGL_DMA_BUF_PLANE0_FD_EXT, fb.planes[0].fd,
            EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,
            EGL_DMA_BUF_PLANE0_PITCH_EXT, cfg.stride,
            EGL_NONE,
        ]

        image = eglCreateImageKHR(self.egl.display,
                                  EGL_NO_CONTEXT,
                                  EGL_LINUX_DMA_BUF_EXT,
                                  None,
                                  attribs)
        assert(image)

        textures = glGenTextures(1)
        glBindTexture(GL_TEXTURE_EXTERNAL_OES, textures)
        glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
        glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
        glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
        glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
        glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, image)

        return textures

    def resizeEvent(self, event):
        size = event.size()

        print('Resize', size)

        super().resizeEvent(event)

        if self.surface is None:
            return

        glViewport(0, 0, size.width() // 2, size.height())

    def paintEvent(self, event):
        if self.surface is None:
            self.init_gl()

        for ctx_idx, queue in self.reqqueue.items():
            if len(queue) == 0:
                continue

            ctx = next(ctx for ctx in self.state.contexts if ctx.idx == ctx_idx)

            if self.current[ctx_idx]:
                old = self.current[ctx_idx]
                self.current[ctx_idx] = None
                self.state.request_processed(ctx, old)

            next_req = queue.pop(0)
            self.current[ctx_idx] = next_req

            stream, fb = next(iter(next_req.buffers.items()))

            self.textures[stream] = self.create_texture(stream, fb)

        self.paint_gl()

    def paint_gl(self):
        b = eglMakeCurrent(self.egl.display, self.surface, self.surface, self.egl.context)
        assert(b)

        glClear(GL_COLOR_BUFFER_BIT)

        size = self.size()

        for idx, ctx in enumerate(self.state.contexts):
            for stream in ctx.streams:
                if self.textures[stream] is None:
                    continue

                w = size.width() // self.num_columns
                h = size.height() // self.num_rows

                x = idx % self.num_columns
                y = idx // self.num_columns

                x *= w
                y *= h

                glViewport(x, y, w, h)

                glBindTexture(GL_TEXTURE_EXTERNAL_OES, self.textures[stream])
                glDrawArrays(GL_TRIANGLE_FAN, 0, 4)

        b = eglSwapBuffers(self.egl.display, self.surface)
        assert(b)

    def handle_request(self, ctx, req):
        self.reqqueue[ctx.idx].append(req)
        self.update()
ass="hl opt">*name; }; /* * \var camera3FormatsMap * \brief Associate Android format code with ancillary data */ const std::map<int, const Camera3Format> camera3FormatsMap = { { HAL_PIXEL_FORMAT_BLOB, { { formats::MJPEG }, true, "BLOB" } }, { HAL_PIXEL_FORMAT_YCbCr_420_888, { { formats::NV12, formats::NV21 }, true, "YCbCr_420_888" } }, { /* * \todo Translate IMPLEMENTATION_DEFINED inspecting the gralloc * usage flag. For now, copy the YCbCr_420 configuration. */ HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, { { formats::NV12, formats::NV21 }, true, "IMPLEMENTATION_DEFINED" } }, { HAL_PIXEL_FORMAT_RAW10, { { formats::SBGGR10_CSI2P, formats::SGBRG10_CSI2P, formats::SGRBG10_CSI2P, formats::SRGGB10_CSI2P }, false, "RAW10" } }, { HAL_PIXEL_FORMAT_RAW12, { { formats::SBGGR12_CSI2P, formats::SGBRG12_CSI2P, formats::SGRBG12_CSI2P, formats::SRGGB12_CSI2P }, false, "RAW12" } }, { HAL_PIXEL_FORMAT_RAW16, { { formats::SBGGR16, formats::SGBRG16, formats::SGRBG16, formats::SRGGB16 }, false, "RAW16" } }, { HAL_PIXEL_FORMAT_RAW_OPAQUE, { { formats::SBGGR10_IPU3, formats::SGBRG10_IPU3, formats::SGRBG10_IPU3, formats::SRGGB10_IPU3 }, false, "RAW_OPAQUE" } }, }; } /* namespace */ LOG_DECLARE_CATEGORY(HAL); /* * \struct Camera3RequestDescriptor * * A utility structure that groups information about a capture request to be * later re-used at request complete time to notify the framework. */ CameraDevice::Camera3RequestDescriptor::Camera3RequestDescriptor( unsigned int frameNumber, unsigned int numBuffers) : frameNumber(frameNumber), numBuffers(numBuffers) { buffers = new camera3_stream_buffer_t[numBuffers]; frameBuffers.reserve(numBuffers); } CameraDevice::Camera3RequestDescriptor::~Camera3RequestDescriptor() { delete[] buffers; } /* * \class CameraDevice * * The CameraDevice class wraps a libcamera::Camera instance, and implements * the camera3_device_t interface, bridging calls received from the Android * camera service to the CameraDevice. * * The class translates parameters and operations from the Camera HALv3 API to * the libcamera API to provide static information for a Camera, create request * templates for it, process capture requests and then deliver capture results * back to the framework using the designated callbacks. */ CameraDevice::CameraDevice(unsigned int id, const std::shared_ptr<Camera> &camera) : id_(id), running_(false), camera_(camera), staticMetadata_(nullptr), facing_(CAMERA_FACING_FRONT), orientation_(0) { camera_->requestCompleted.connect(this, &CameraDevice::requestComplete); } CameraDevice::~CameraDevice() { if (staticMetadata_) delete staticMetadata_; for (auto &it : requestTemplates_) delete it.second; } /* * Initialize the camera static information. * This method is called before the camera device is opened. */ int CameraDevice::initialize() { /* Initialize orientation and facing side of the camera. */ const ControlList &properties = camera_->properties(); if (properties.contains(properties::Location)) { int32_t location = properties.get(properties::Location); switch (location) { case properties::CameraLocationFront: facing_ = CAMERA_FACING_FRONT; break; case properties::CameraLocationBack: facing_ = CAMERA_FACING_BACK; break; case properties::CameraLocationExternal: facing_ = CAMERA_FACING_EXTERNAL; break; } } /* * The Android orientation metadata and libcamera rotation property are * defined differently but have identical numerical values for Android * devices such as phones and tablets. */ if (properties.contains(properties::Rotation)) orientation_ = properties.get(properties::Rotation); int ret = camera_->acquire(); if (ret) { LOG(HAL, Error) << "Failed to temporarily acquire the camera"; return ret; } ret = initializeStreamConfigurations(); camera_->release(); return ret; } /* * Initialize the format conversion map to translate from Android format * identifier to libcamera pixel formats and fill in the list of supported * stream configurations to be reported to the Android camera framework through * the static stream configuration metadata. */ int CameraDevice::initializeStreamConfigurations() { /* * Get the maximum output resolutions * \todo Get this from the camera properties once defined */ std::unique_ptr<CameraConfiguration> cameraConfig = camera_->generateConfiguration({ StillCapture }); if (!cameraConfig) { LOG(HAL, Error) << "Failed to get maximum resolution"; return -EINVAL; } StreamConfiguration &cfg = cameraConfig->at(0); /* * \todo JPEG - Adjust the maximum available resolution by taking the * JPEG encoder requirements into account (alignment and aspect ratio). */ const Size maxRes = cfg.size; LOG(HAL, Debug) << "Maximum supported resolution: " << maxRes.toString(); /* * Build the list of supported image resolutions. * * The resolutions listed in camera3Resolution are mandatory to be * supported, up to the camera maximum resolution. * * Augment the list by adding resolutions calculated from the camera * maximum one. */ std::vector<Size> cameraResolutions; std::copy_if(camera3Resolutions.begin(), camera3Resolutions.end(), std::back_inserter(cameraResolutions), [&](const Size &res) { return res < maxRes; }); /* * The Camera3 specification suggests adding 1/2 and 1/4 of the maximum * resolution. */ for (unsigned int divider = 2;; divider <<= 1) { Size derivedSize{ maxRes.width / divider, maxRes.height / divider, }; if (derivedSize.width < 320 || derivedSize.height < 240) break; cameraResolutions.push_back(derivedSize); } cameraResolutions.push_back(maxRes); /* Remove duplicated entries from the list of supported resolutions. */ std::sort(cameraResolutions.begin(), cameraResolutions.end()); auto last = std::unique(cameraResolutions.begin(), cameraResolutions.end()); cameraResolutions.erase(last, cameraResolutions.end()); /* * Build the list of supported camera formats. * * To each Android format a list of compatible libcamera formats is * associated. The first libcamera format that tests successful is added * to the format translation map used when configuring the streams. * It is then tested against the list of supported camera resolutions to * build the stream configuration map reported through the camera static * metadata. */ for (const auto &format : camera3FormatsMap) { int androidFormat = format.first; const Camera3Format &camera3Format = format.second; const std::vector<PixelFormat> &libcameraFormats = camera3Format.libcameraFormats; /* * Test the libcamera formats that can produce images * compatible with the format defined by Android. */ PixelFormat mappedFormat; for (const PixelFormat &pixelFormat : libcameraFormats) { /* \todo Fixed mapping for JPEG. */ if (androidFormat == HAL_PIXEL_FORMAT_BLOB) { mappedFormat = formats::MJPEG; break; } /* * The stream configuration size can be adjusted, * not the pixel format. * * \todo This could be simplified once all pipeline * handlers will report the StreamFormats list of * supported formats. */ cfg.pixelFormat = pixelFormat; CameraConfiguration::Status status = cameraConfig->validate(); if (status != CameraConfiguration::Invalid && cfg.pixelFormat == pixelFormat) { mappedFormat = pixelFormat; break; } } if (camera3Format.mandatory && !mappedFormat.isValid()) { LOG(HAL, Error) << "Failed to map Android format " << camera3Format.name << " (" << utils::hex(androidFormat) << ")"; return -EINVAL; } /* * Record the mapping and then proceed to generate the * stream configurations map, by testing the image resolutions. */ formatsMap_[androidFormat] = mappedFormat; for (const Size &res : cameraResolutions) { cfg.pixelFormat = mappedFormat; cfg.size = res; CameraConfiguration::Status status = cameraConfig->validate(); /* * Unconditionally report we can produce JPEG. * * \todo The JPEG stream will be implemented as an * HAL-only stream, but some cameras can produce it * directly. As of now, claim support for JPEG without * inspecting where the JPEG stream is produced. */ if (androidFormat != HAL_PIXEL_FORMAT_BLOB && status != CameraConfiguration::Valid) continue; streamConfigurations_.push_back({ res, androidFormat }); } } LOG(HAL, Debug) << "Collected stream configuration map: "; for (const auto &entry : streamConfigurations_) LOG(HAL, Debug) << "{ " << entry.resolution.toString() << " - " << utils::hex(entry.androidFormat) << " }"; return 0; } /* * Open a camera device. The static information on the camera shall have been * initialized with a call to CameraDevice::initialize(). */ int CameraDevice::open(const hw_module_t *hardwareModule) { int ret = camera_->acquire(); if (ret) { LOG(HAL, Error) << "Failed to acquire the camera"; return ret; } /* Initialize the hw_device_t in the instance camera3_module_t. */ camera3Device_.common.tag = HARDWARE_DEVICE_TAG; camera3Device_.common.version = CAMERA_DEVICE_API_VERSION_3_3; camera3Device_.common.module = (hw_module_t *)hardwareModule; camera3Device_.common.close = hal_dev_close; /* * The camera device operations. These actually implement * the Android Camera HALv3 interface. */ camera3Device_.ops = &hal_dev_ops; camera3Device_.priv = this; return 0; } void CameraDevice::close() { camera_->stop(); camera_->release(); running_ = false; } void CameraDevice::setCallbacks(const camera3_callback_ops_t *callbacks) { callbacks_ = callbacks; } std::tuple<uint32_t, uint32_t> CameraDevice::calculateStaticMetadataSize() { /* * \todo Keep this in sync with the actual number of entries. * Currently: 50 entries, 671 bytes of static metadata */ uint32_t numEntries = 50; uint32_t byteSize = 671; /* * Calculate space occupation in bytes for dynamically built metadata * entries. * * Each stream configuration entry requires 52 bytes: * 4 32bits integers for ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS * 4 64bits integers for ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS */ byteSize += streamConfigurations_.size() * 48; return std::make_tuple(numEntries, byteSize); } /* * Return static information for the camera. */ const camera_metadata_t *CameraDevice::getStaticMetadata() { if (staticMetadata_) return staticMetadata_->get(); /* * The here reported metadata are enough to implement a basic capture * example application, but a real camera implementation will require * more. */ uint32_t numEntries; uint32_t byteSize; std::tie(numEntries, byteSize) = calculateStaticMetadataSize(); staticMetadata_ = new CameraMetadata(numEntries, byteSize); if (!staticMetadata_->isValid()) { LOG(HAL, Error) << "Failed to allocate static metadata"; delete staticMetadata_; staticMetadata_ = nullptr; return nullptr; } /* Color correction static metadata. */ std::vector<uint8_t> aberrationModes = { ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF, }; staticMetadata_->addEntry(ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES, aberrationModes.data(), aberrationModes.size()); /* Control static metadata. */ std::vector<uint8_t> aeAvailableAntiBandingModes = { ANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF, ANDROID_CONTROL_AE_ANTIBANDING_MODE_50HZ, ANDROID_CONTROL_AE_ANTIBANDING_MODE_60HZ, ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO, }; staticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES, aeAvailableAntiBandingModes.data(), aeAvailableAntiBandingModes.size()); std::vector<uint8_t> aeAvailableModes = { ANDROID_CONTROL_AE_MODE_ON, }; staticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_MODES, aeAvailableModes.data(), aeAvailableModes.size()); std::vector<int32_t> availableAeFpsTarget = { 15, 30, }; staticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, availableAeFpsTarget.data(), availableAeFpsTarget.size()); std::vector<int32_t> aeCompensationRange = { 0, 0, }; staticMetadata_->addEntry(ANDROID_CONTROL_AE_COMPENSATION_RANGE, aeCompensationRange.data(), aeCompensationRange.size()); const camera_metadata_rational_t aeCompensationStep[] = { { 0, 1 } }; staticMetadata_->addEntry(ANDROID_CONTROL_AE_COMPENSATION_STEP, aeCompensationStep, 1); std::vector<uint8_t> availableAfModes = { ANDROID_CONTROL_AF_MODE_OFF, }; staticMetadata_->addEntry(ANDROID_CONTROL_AF_AVAILABLE_MODES, availableAfModes.data(), availableAfModes.size()); std::vector<uint8_t> availableEffects = { ANDROID_CONTROL_EFFECT_MODE_OFF, }; staticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_EFFECTS, availableEffects.data(), availableEffects.size()); std::vector<uint8_t> availableSceneModes = { ANDROID_CONTROL_SCENE_MODE_DISABLED, }; staticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_SCENE_MODES, availableSceneModes.data(), availableSceneModes.size()); std::vector<uint8_t> availableStabilizationModes = { ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF, }; staticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES, availableStabilizationModes.data(), availableStabilizationModes.size()); std::vector<uint8_t> availableAwbModes = { ANDROID_CONTROL_AWB_MODE_OFF, }; staticMetadata_->addEntry(ANDROID_CONTROL_AWB_AVAILABLE_MODES, availableAwbModes.data(), availableAwbModes.size()); std::vector<int32_t> availableMaxRegions = { 0, 0, 0, }; staticMetadata_->addEntry(ANDROID_CONTROL_MAX_REGIONS, availableMaxRegions.data(), availableMaxRegions.size()); std::vector<uint8_t> sceneModesOverride = { ANDROID_CONTROL_AE_MODE_ON, ANDROID_CONTROL_AWB_MODE_AUTO, ANDROID_CONTROL_AF_MODE_AUTO, }; staticMetadata_->addEntry(ANDROID_CONTROL_SCENE_MODE_OVERRIDES, sceneModesOverride.data(), sceneModesOverride.size()); uint8_t aeLockAvailable = ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE; staticMetadata_->addEntry(ANDROID_CONTROL_AE_LOCK_AVAILABLE, &aeLockAvailable, 1); uint8_t awbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE; staticMetadata_->addEntry(ANDROID_CONTROL_AWB_LOCK_AVAILABLE, &awbLockAvailable, 1); char availableControlModes = ANDROID_CONTROL_MODE_AUTO; staticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_MODES, &availableControlModes, 1); /* JPEG static metadata. */ std::vector<int32_t> availableThumbnailSizes = { 0, 0, }; staticMetadata_->addEntry(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES, availableThumbnailSizes.data(), availableThumbnailSizes.size()); /* Sensor static metadata. */ int32_t pixelArraySize[] = { 2592, 1944, }; staticMetadata_->addEntry(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE, &pixelArraySize, 2); int32_t sensorSizes[] = { 0, 0, 2560, 1920, }; staticMetadata_->addEntry(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE, &sensorSizes, 4); int32_t sensitivityRange[] = { 32, 2400, }; staticMetadata_->addEntry(ANDROID_SENSOR_INFO_SENSITIVITY_RANGE, &sensitivityRange, 2); uint16_t filterArr = ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG; staticMetadata_->addEntry(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT, &filterArr, 1); int64_t exposureTimeRange[] = { 100000, 200000000, }; staticMetadata_->addEntry(ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE, &exposureTimeRange, 2); staticMetadata_->addEntry(ANDROID_SENSOR_ORIENTATION, &orientation_, 1); std::vector<int32_t> testPatterModes = { ANDROID_SENSOR_TEST_PATTERN_MODE_OFF, }; staticMetadata_->addEntry(ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES, testPatterModes.data(), testPatterModes.size()); std::vector<float> physicalSize = { 2592, 1944, }; staticMetadata_->addEntry(ANDROID_SENSOR_INFO_PHYSICAL_SIZE, physicalSize.data(), physicalSize.size()); uint8_t timestampSource = ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN; staticMetadata_->addEntry(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE, &timestampSource, 1); /* Statistics static metadata. */ uint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF; staticMetadata_->addEntry(ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES, &faceDetectMode, 1); int32_t maxFaceCount = 0; staticMetadata_->addEntry(ANDROID_STATISTICS_INFO_MAX_FACE_COUNT, &maxFaceCount, 1); /* Sync static metadata. */ int32_t maxLatency = ANDROID_SYNC_MAX_LATENCY_UNKNOWN; staticMetadata_->addEntry(ANDROID_SYNC_MAX_LATENCY, &maxLatency, 1); /* Flash static metadata. */ char flashAvailable = ANDROID_FLASH_INFO_AVAILABLE_FALSE; staticMetadata_->addEntry(ANDROID_FLASH_INFO_AVAILABLE, &flashAvailable, 1); /* Lens static metadata. */ std::vector<float> lensApertures = { 2.53 / 100, }; staticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_APERTURES, lensApertures.data(), lensApertures.size()); uint8_t lensFacing; switch (facing_) { default: case CAMERA_FACING_FRONT: lensFacing = ANDROID_LENS_FACING_FRONT; break; case CAMERA_FACING_BACK: lensFacing = ANDROID_LENS_FACING_BACK; break; case CAMERA_FACING_EXTERNAL: lensFacing = ANDROID_LENS_FACING_EXTERNAL; break; } staticMetadata_->addEntry(ANDROID_LENS_FACING, &lensFacing, 1); std::vector<float> lensFocalLenghts = { 1, }; staticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS, lensFocalLenghts.data(), lensFocalLenghts.size()); std::vector<uint8_t> opticalStabilizations = { ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF, }; staticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION, opticalStabilizations.data(), opticalStabilizations.size()); float hypeFocalDistance = 0; staticMetadata_->addEntry(ANDROID_LENS_INFO_HYPERFOCAL_DISTANCE, &hypeFocalDistance, 1); float minFocusDistance = 0; staticMetadata_->addEntry(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE, &minFocusDistance, 1); /* Noise reduction modes. */ uint8_t noiseReductionModes = ANDROID_NOISE_REDUCTION_MODE_OFF; staticMetadata_->addEntry(ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES, &noiseReductionModes, 1); /* Scaler static metadata. */ float maxDigitalZoom = 1; staticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM, &maxDigitalZoom, 1); std::vector<uint32_t> availableStreamConfigurations; availableStreamConfigurations.reserve(streamConfigurations_.size() * 4); for (const auto &entry : streamConfigurations_) { availableStreamConfigurations.push_back(entry.androidFormat); availableStreamConfigurations.push_back(entry.resolution.width); availableStreamConfigurations.push_back(entry.resolution.height); availableStreamConfigurations.push_back( ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT); } staticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, availableStreamConfigurations.data(), availableStreamConfigurations.size()); std::vector<int64_t> availableStallDurations = { ANDROID_SCALER_AVAILABLE_FORMATS_BLOB, 2560, 1920, 33333333, }; staticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS, availableStallDurations.data(), availableStallDurations.size()); /* \todo Collect the minimum frame duration from the camera. */ std::vector<int64_t> minFrameDurations; minFrameDurations.reserve(streamConfigurations_.size() * 4); for (const auto &entry : streamConfigurations_) { minFrameDurations.push_back(entry.androidFormat); minFrameDurations.push_back(entry.resolution.width); minFrameDurations.push_back(entry.resolution.height); minFrameDurations.push_back(33333333); } staticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS, minFrameDurations.data(), minFrameDurations.size()); uint8_t croppingType = ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY; staticMetadata_->addEntry(ANDROID_SCALER_CROPPING_TYPE, &croppingType, 1); /* Info static metadata. */ uint8_t supportedHWLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED; staticMetadata_->addEntry(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL, &supportedHWLevel, 1); /* Request static metadata. */ int32_t partialResultCount = 1; staticMetadata_->addEntry(ANDROID_REQUEST_PARTIAL_RESULT_COUNT, &partialResultCount, 1); uint8_t maxPipelineDepth = 2; staticMetadata_->addEntry(ANDROID_REQUEST_PIPELINE_MAX_DEPTH, &maxPipelineDepth, 1); /* LIMITED does not support reprocessing. */ uint32_t maxNumInputStreams = 0; staticMetadata_->addEntry(ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS, &maxNumInputStreams, 1); std::vector<uint8_t> availableCapabilities = { ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE, }; /* Report if camera supports RAW. */ std::unique_ptr<CameraConfiguration> cameraConfig = camera_->generateConfiguration({ StillCaptureRaw }); if (cameraConfig && !cameraConfig->empty()) { const PixelFormatInfo &info = PixelFormatInfo::info(cameraConfig->at(0).pixelFormat); if (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW) availableCapabilities.push_back(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW); } staticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_CAPABILITIES, availableCapabilities.data(), availableCapabilities.size()); std::vector<int32_t> availableCharacteristicsKeys = { ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES, ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES, ANDROID_CONTROL_AE_AVAILABLE_MODES, ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, ANDROID_CONTROL_AE_COMPENSATION_RANGE, ANDROID_CONTROL_AE_COMPENSATION_STEP, ANDROID_CONTROL_AF_AVAILABLE_MODES, ANDROID_CONTROL_AVAILABLE_EFFECTS, ANDROID_CONTROL_AVAILABLE_SCENE_MODES, ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES, ANDROID_CONTROL_AWB_AVAILABLE_MODES, ANDROID_CONTROL_MAX_REGIONS, ANDROID_CONTROL_SCENE_MODE_OVERRIDES, ANDROID_CONTROL_AE_LOCK_AVAILABLE, ANDROID_CONTROL_AWB_LOCK_AVAILABLE, ANDROID_CONTROL_AVAILABLE_MODES, ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES, ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE, ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE, ANDROID_SENSOR_INFO_SENSITIVITY_RANGE, ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT, ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE, ANDROID_SENSOR_ORIENTATION, ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES, ANDROID_SENSOR_INFO_PHYSICAL_SIZE, ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE, ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES, ANDROID_STATISTICS_INFO_MAX_FACE_COUNT, ANDROID_SYNC_MAX_LATENCY, ANDROID_FLASH_INFO_AVAILABLE, ANDROID_LENS_INFO_AVAILABLE_APERTURES, ANDROID_LENS_FACING, ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS, ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION, ANDROID_LENS_INFO_HYPERFOCAL_DISTANCE, ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE, ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES, ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM, ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, ANDROID_SCALER_AVAILABLE_STALL_DURATIONS, ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS, ANDROID_SCALER_CROPPING_TYPE, ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL, ANDROID_REQUEST_PARTIAL_RESULT_COUNT, ANDROID_REQUEST_PIPELINE_MAX_DEPTH, ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS, ANDROID_REQUEST_AVAILABLE_CAPABILITIES, }; staticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, availableCharacteristicsKeys.data(), availableCharacteristicsKeys.size()); std::vector<int32_t> availableRequestKeys = { ANDROID_CONTROL_AE_MODE, ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION, ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER, ANDROID_CONTROL_AE_TARGET_FPS_RANGE, ANDROID_CONTROL_AE_ANTIBANDING_MODE, ANDROID_CONTROL_AE_LOCK, ANDROID_CONTROL_AF_TRIGGER, ANDROID_CONTROL_AWB_MODE, ANDROID_CONTROL_AWB_LOCK, ANDROID_FLASH_MODE, ANDROID_STATISTICS_FACE_DETECT_MODE, ANDROID_NOISE_REDUCTION_MODE, ANDROID_COLOR_CORRECTION_ABERRATION_MODE, ANDROID_LENS_APERTURE, ANDROID_LENS_OPTICAL_STABILIZATION_MODE, ANDROID_CONTROL_MODE, ANDROID_CONTROL_CAPTURE_INTENT, }; staticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, availableRequestKeys.data(), availableRequestKeys.size()); std::vector<int32_t> availableResultKeys = { ANDROID_CONTROL_AE_STATE, ANDROID_CONTROL_AE_LOCK, ANDROID_CONTROL_AF_STATE, ANDROID_CONTROL_AWB_STATE, ANDROID_CONTROL_AWB_LOCK, ANDROID_LENS_STATE, ANDROID_SCALER_CROP_REGION, ANDROID_SENSOR_TIMESTAMP, ANDROID_SENSOR_ROLLING_SHUTTER_SKEW, ANDROID_SENSOR_EXPOSURE_TIME, ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, ANDROID_STATISTICS_SCENE_FLICKER, }; staticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, availableResultKeys.data(), availableResultKeys.size()); if (!staticMetadata_->isValid()) { LOG(HAL, Error) << "Failed to construct static metadata"; delete staticMetadata_; staticMetadata_ = nullptr; return nullptr; } return staticMetadata_->get(); } CameraMetadata *CameraDevice::requestTemplatePreview() { /* * \todo Keep this in sync with the actual number of entries. * Currently: 20 entries, 35 bytes */ CameraMetadata *requestTemplate = new CameraMetadata(20, 35); if (!requestTemplate->isValid()) { delete requestTemplate; return nullptr; } uint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON; requestTemplate->addEntry(ANDROID_CONTROL_AE_MODE, &aeMode, 1); int32_t aeExposureCompensation = 0; requestTemplate->addEntry(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION, &aeExposureCompensation, 1); uint8_t aePrecaptureTrigger = ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE; requestTemplate->addEntry(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER, &aePrecaptureTrigger, 1); uint8_t aeLock = ANDROID_CONTROL_AE_LOCK_OFF; requestTemplate->addEntry(ANDROID_CONTROL_AE_LOCK, &aeLock, 1); std::vector<int32_t> aeFpsTarget = { 15, 30, }; requestTemplate->addEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE, aeFpsTarget.data(), aeFpsTarget.size()); uint8_t aeAntibandingMode = ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO; requestTemplate->addEntry(ANDROID_CONTROL_AE_ANTIBANDING_MODE, &aeAntibandingMode, 1); uint8_t afTrigger = ANDROID_CONTROL_AF_TRIGGER_IDLE; requestTemplate->addEntry(ANDROID_CONTROL_AF_TRIGGER, &afTrigger, 1); uint8_t awbMode = ANDROID_CONTROL_AWB_MODE_AUTO; requestTemplate->addEntry(ANDROID_CONTROL_AWB_MODE, &awbMode, 1); uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF; requestTemplate->addEntry(ANDROID_CONTROL_AWB_LOCK, &awbLock, 1); uint8_t flashMode = ANDROID_FLASH_MODE_OFF; requestTemplate->addEntry(ANDROID_FLASH_MODE, &flashMode, 1); uint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF; requestTemplate->addEntry(ANDROID_STATISTICS_FACE_DETECT_MODE, &faceDetectMode, 1); uint8_t noiseReduction = ANDROID_NOISE_REDUCTION_MODE_OFF; requestTemplate->addEntry(ANDROID_NOISE_REDUCTION_MODE, &noiseReduction, 1); uint8_t aberrationMode = ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF; requestTemplate->addEntry(ANDROID_COLOR_CORRECTION_ABERRATION_MODE, &aberrationMode, 1); uint8_t controlMode = ANDROID_CONTROL_MODE_AUTO; requestTemplate->addEntry(ANDROID_CONTROL_MODE, &controlMode, 1); float lensAperture = 2.53 / 100; requestTemplate->addEntry(ANDROID_LENS_APERTURE, &lensAperture, 1); uint8_t opticalStabilization = ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF; requestTemplate->addEntry(ANDROID_LENS_OPTICAL_STABILIZATION_MODE, &opticalStabilization, 1); uint8_t captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW; requestTemplate->addEntry(ANDROID_CONTROL_CAPTURE_INTENT, &captureIntent, 1); return requestTemplate; } /* * Produce a metadata pack to be used as template for a capture request. */ const camera_metadata_t *CameraDevice::constructDefaultRequestSettings(int type) { auto it = requestTemplates_.find(type); if (it != requestTemplates_.end()) return it->second->get(); /* Use the capture intent matching the requested template type. */ CameraMetadata *requestTemplate; uint8_t captureIntent; switch (type) { case CAMERA3_TEMPLATE_PREVIEW: captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW; break; case CAMERA3_TEMPLATE_STILL_CAPTURE: captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE; break; case CAMERA3_TEMPLATE_VIDEO_RECORD: captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD; break; case CAMERA3_TEMPLATE_VIDEO_SNAPSHOT: captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT; break; case CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG: captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_ZERO_SHUTTER_LAG; break; case CAMERA3_TEMPLATE_MANUAL: captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_MANUAL; break; default: LOG(HAL, Error) << "Invalid template request type: " << type; return nullptr; } requestTemplate = requestTemplatePreview(); if (!requestTemplate || !requestTemplate->isValid()) { LOG(HAL, Error) << "Failed to construct request template"; delete requestTemplate; return nullptr; } requestTemplate->updateEntry(ANDROID_CONTROL_CAPTURE_INTENT, &captureIntent, 1); requestTemplates_[type] = requestTemplate; return requestTemplate->get(); } PixelFormat CameraDevice::toPixelFormat(int format) { /* Translate Android format code to libcamera pixel format. */ auto it = formatsMap_.find(format); if (it == formatsMap_.end()) { LOG(HAL, Error) << "Requested format " << utils::hex(format) << " not supported"; return PixelFormat(); } return it->second; } /* * Inspect the stream_list to produce a list of StreamConfiguration to * be use to configure the Camera. */ int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list) { /* * Generate an empty configuration, and construct a StreamConfiguration * for each camera3_stream to add to it. */ config_ = camera_->generateConfiguration(); if (!config_) { LOG(HAL, Error) << "Failed to generate camera configuration"; return -EINVAL; } /* * Clear and remove any existing configuration from previous calls, and * ensure the required entries are available without further * re-allcoation. */ streams_.clear(); streams_.reserve(stream_list->num_streams); /* * Track actually created streams, as there may not be a 1:1 mapping of * camera3 streams to libcamera streams. */ unsigned int streamIndex = 0; for (unsigned int i = 0; i < stream_list->num_streams; ++i) { camera3_stream_t *stream = stream_list->streams[i]; PixelFormat format = toPixelFormat(stream->format); LOG(HAL, Info) << "Stream #" << i << ", direction: " << stream->stream_type << ", width: " << stream->width << ", height: " << stream->height << ", format: " << utils::hex(stream->format) << " (" << format.toString() << ")"; if (!format.isValid()) return -EINVAL; StreamConfiguration streamConfiguration; streamConfiguration.size.width = stream->width; streamConfiguration.size.height = stream->height; streamConfiguration.pixelFormat = format; config_->addConfiguration(streamConfiguration); streams_[i].index = streamIndex++; stream->priv = static_cast<void *>(&streams_[i]); } switch (config_->validate()) { case CameraConfiguration::Valid: break; case CameraConfiguration::Adjusted: LOG(HAL, Info) << "Camera configuration adjusted"; config_.reset(); return -EINVAL; case CameraConfiguration::Invalid: LOG(HAL, Info) << "Camera configuration invalid"; config_.reset(); return -EINVAL; } for (unsigned int i = 0; i < stream_list->num_streams; ++i) { camera3_stream_t *stream = stream_list->streams[i]; CameraStream *cameraStream = &streams_[i]; StreamConfiguration &cfg = config_->at(cameraStream->index); /* Use the bufferCount confirmed by the validation process. */ stream->max_buffers = cfg.bufferCount; } /* * Once the CameraConfiguration has been adjusted/validated * it can be applied to the camera. */ int ret = camera_->configure(config_.get()); if (ret) { LOG(HAL, Error) << "Failed to configure camera '" << camera_->id() << "'"; return ret; } return 0; } FrameBuffer *CameraDevice::createFrameBuffer(const buffer_handle_t camera3buffer) { std::vector<FrameBuffer::Plane> planes; for (int i = 0; i < camera3buffer->numFds; i++) { /* Skip unused planes. */ if (camera3buffer->data[i] == -1) break; FrameBuffer::Plane plane; plane.fd = FileDescriptor(camera3buffer->data[i]); if (!plane.fd.isValid()) { LOG(HAL, Error) << "Failed to obtain FileDescriptor (" << camera3buffer->data[i] << ") " << " on plane " << i; return nullptr; } off_t length = lseek(plane.fd.fd(), 0, SEEK_END); if (length == -1) { LOG(HAL, Error) << "Failed to query plane length"; return nullptr; } plane.length = length; planes.push_back(std::move(plane)); } return new FrameBuffer(std::move(planes)); } int CameraDevice::processCaptureRequest(camera3_capture_request_t *camera3Request) { if (!camera3Request->num_output_buffers) { LOG(HAL, Error) << "No output buffers provided"; return -EINVAL; } /* Start the camera if that's the first request we handle. */ if (!running_) { int ret = camera_->start(); if (ret) { LOG(HAL, Error) << "Failed to start camera"; return ret; } running_ = true; } /* * Queue a request for the Camera with the provided dmabuf file * descriptors. */ const camera3_stream_buffer_t *camera3Buffers = camera3Request->output_buffers; /* * Save the request descriptors for use at completion time. * The descriptor and the associated memory reserved here are freed * at request complete time. */ Camera3RequestDescriptor *descriptor = new Camera3RequestDescriptor(camera3Request->frame_number, camera3Request->num_output_buffers); Request *request = camera_->createRequest(reinterpret_cast<uint64_t>(descriptor)); for (unsigned int i = 0; i < descriptor->numBuffers; ++i) { CameraStream *cameraStream = static_cast<CameraStream *>(camera3Buffers[i].stream->priv); /* * Keep track of which stream the request belongs to and store * the native buffer handles. */ descriptor->buffers[i].stream = camera3Buffers[i].stream; descriptor->buffers[i].buffer = camera3Buffers[i].buffer; /* * Create a libcamera buffer using the dmabuf descriptors of * the camera3Buffer for each stream. The FrameBuffer is * directly associated with the Camera3RequestDescriptor for * lifetime management only. */ FrameBuffer *buffer = createFrameBuffer(*camera3Buffers[i].buffer); if (!buffer) { LOG(HAL, Error) << "Failed to create buffer"; delete request; delete descriptor; return -ENOMEM; } descriptor->frameBuffers.emplace_back(buffer); StreamConfiguration *streamConfiguration = &config_->at(cameraStream->index); Stream *stream = streamConfiguration->stream(); request->addBuffer(stream, buffer); } int ret = camera_->queueRequest(request); if (ret) { LOG(HAL, Error) << "Failed to queue request"; delete request; delete descriptor; return ret; } return 0; } void CameraDevice::requestComplete(Request *request) { const std::map<Stream *, FrameBuffer *> &buffers = request->buffers(); camera3_buffer_status status = CAMERA3_BUFFER_STATUS_OK; std::unique_ptr<CameraMetadata> resultMetadata; if (request->status() != Request::RequestComplete) { LOG(HAL, Error) << "Request not successfully completed: " << request->status(); status = CAMERA3_BUFFER_STATUS_ERROR; } /* Prepare to call back the Android camera stack. */ Camera3RequestDescriptor *descriptor = reinterpret_cast<Camera3RequestDescriptor *>(request->cookie()); camera3_capture_result_t captureResult = {}; captureResult.frame_number = descriptor->frameNumber; captureResult.num_output_buffers = descriptor->numBuffers; for (unsigned int i = 0; i < descriptor->numBuffers; ++i) { descriptor->buffers[i].acquire_fence = -1; descriptor->buffers[i].release_fence = -1; descriptor->buffers[i].status = status; } captureResult.output_buffers = const_cast<const camera3_stream_buffer_t *>(descriptor->buffers); /* * \todo The timestamp used for the metadata is currently always taken