14ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine/*
24ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine * Copyright (C) 2011 The Android Open Source Project
34ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine *
44ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine * Licensed under the Apache License, Version 2.0 (the "License");
54ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine * you may not use this file except in compliance with the License.
64ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine * You may obtain a copy of the License at
74ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine *
84ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine *      http://www.apache.org/licenses/LICENSE-2.0
94ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine *
104ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine * Unless required by applicable law or agreed to in writing, software
114ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine * distributed under the License is distributed on an "AS IS" BASIS,
124ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine * See the License for the specific language governing permissions and
144ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine * limitations under the License.
154ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine */
164ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
174ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine/*
184ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine * Contains code that is used to capture video frames from a camera device
194ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine * on Linux. This code uses V4L2 API to work with camera devices, and requires
204ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine * Linux kernel version at least 2.5
214ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine */
224ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
234ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine#include <sys/mman.h>
244ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine#include <sys/stat.h>
254ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine#include <sys/ioctl.h>
264ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine#include "android/camera/camera-capture.h"
274ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine#include "android/camera/camera-format-converters.h"
28af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner#include "android/utils/eintr_wrapper.h"
294ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
30c68dbbef0118eab4256acfc0d9430f0e557a82a1Vladimir Chtchetkine#define  E(...)    derror(__VA_ARGS__)
31c68dbbef0118eab4256acfc0d9430f0e557a82a1Vladimir Chtchetkine#define  W(...)    dwarning(__VA_ARGS__)
324ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine#define  D(...)    VERBOSE_PRINT(camera,__VA_ARGS__)
334ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine#define  D_ACTIVE  VERBOSE_CHECK(camera)
344ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
354ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine/* the T(...) macro is used to dump traffic */
364ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine#define  T_ACTIVE   0
374ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
384ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine#if T_ACTIVE
394ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine#define  T(...)    VERBOSE_PRINT(camera,__VA_ARGS__)
404ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine#else
414ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine#define  T(...)    ((void)0)
424ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine#endif
434ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
444ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine#define CLEAR(x) memset (&(x), 0, sizeof(x))
454ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
46cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Pixel format descriptor.
47cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Instances of this descriptor are created during camera device enumeration, and
48cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * an instance of this structure describing pixel format chosen for the camera
49cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * emulation is saved by the camera factory service to represent an emulating
50cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * camera properties.
51cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine */
52cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkinetypedef struct QemuPixelFormat {
53cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    /* Pixel format in V4L2_PIX_FMT_XXX form. */
54cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    uint32_t        format;
55cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    /* Frame dimensions supported by this format. */
56cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    CameraFrameDim* dims;
57cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    /* Number of frame dimensions supported by this format. */
58cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    int             dim_num;
59cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine} QemuPixelFormat;
60cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine
614ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine/* Describes a framebuffer. */
624ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkinetypedef struct CameraFrameBuffer {
634ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* Framebuffer data. */
644ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    uint8_t*    data;
654ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* Framebuffer data size. */
664ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    size_t      size;
674ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine} CameraFrameBuffer;
684ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
694ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine/* Defines type of the I/O used to obtain frames from the device. */
704ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkinetypedef enum CameraIoType {
714ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* Framebuffers are shared via memory mapping. */
724ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    CAMERA_IO_MEMMAP,
734ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* Framebuffers are available via user pointers. */
744ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    CAMERA_IO_USERPTR,
754ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* Framebuffers are to be read from the device. */
764ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    CAMERA_IO_DIRECT
774ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine} CameraIoType;
784ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
794ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkinetypedef struct LinuxCameraDevice LinuxCameraDevice;
804ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine/*
814ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine * Describes a connection to an actual camera device.
824ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine */
834ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkinestruct LinuxCameraDevice {
844ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* Common header. */
854ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    CameraDevice                header;
864ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
874ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* Camera device name. (default is /dev/video0) */
884ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    char*                       device_name;
894ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* Input channel. (default is 0) */
904ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    int                         input_channel;
914ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
924ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /*
934ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine     * Set by the framework after initializing camera connection.
944ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine     */
954ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
964ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* Handle to the opened camera device. */
974ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    int                         handle;
984ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* Device capabilities. */
994ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    struct v4l2_capability      caps;
100cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    /* Actual pixel format reported by the device when capturing is started. */
1014ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    struct v4l2_pix_format      actual_pixel_format;
1024ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* Defines type of the I/O to use to retrieve frames from the device. */
1034ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    CameraIoType                io_type;
1044ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* Allocated framebuffers. */
1054ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    struct CameraFrameBuffer*   framebuffers;
1064ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* Actual number of allocated framebuffers. */
1074ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    int                         framebuffer_num;
1084ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine};
1094ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
110cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Preferred pixel formats arranged from the most to the least desired.
111cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *
112cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * More than anything else this array is defined by an existance of format
113cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * conversion between the camera supported formats, and formats that are
114cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * supported by camera framework in the guest system. Currently, guest supports
115cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * only YV12 pixel format for data, and RGB32 for preview. So, this array should
116cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * contain only those formats, for which converters are implemented. Generally
117cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * speaking, the order in which entries should be arranged in this array matters
118cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * only as far as conversion speed is concerned. So, formats with the fastest
119cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * converters should be put closer to the top of the array, while slower ones
120cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * should be put closer to the bottom. But as far as functionality is concerned,
121cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * the orser doesn't matter, and any format can be placed anywhere in this array,
122cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * as long as conversion for it exists.
123cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine */
124cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkinestatic const uint32_t _preferred_formats[] =
125cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine{
126cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    /* Native format for the emulated camera: no conversion at all. */
127ddd59b14583126d6282d2fab3142171934981e85Vladimir Chtchetkine    V4L2_PIX_FMT_YUV420,
128cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    V4L2_PIX_FMT_YVU420,
129cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    /* Continue with YCbCr: less math than with RGB */
130cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    V4L2_PIX_FMT_NV12,
131cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    V4L2_PIX_FMT_NV21,
132cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    V4L2_PIX_FMT_YUYV,
133cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    /* End with RGB. */
134cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    V4L2_PIX_FMT_RGB32,
135cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    V4L2_PIX_FMT_RGB24,
136cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    V4L2_PIX_FMT_RGB565,
137cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine};
138cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Number of entries in _preferred_formats array. */
139cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkinestatic const int _preferred_format_num =
140cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    sizeof(_preferred_formats)/sizeof(*_preferred_formats);
141cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine
1424ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine/*******************************************************************************
1434ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine *                     Helper routines
1444ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine ******************************************************************************/
1454ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
1464ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine/* IOCTL wrapper. */
1474ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkinestatic int
1484ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine_xioctl(int fd, int request, void *arg) {
149af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner    return HANDLE_EINTR(ioctl(fd, request, arg));
1504ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine}
1514ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
152cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Frees resource allocated for QemuPixelFormat instance, excluding the instance
153cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * itself.
154cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine */
155cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkinestatic void _qemu_pixel_format_free(QemuPixelFormat* fmt)
156cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine{
157cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    if (fmt != NULL) {
158cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        if (fmt->dims != NULL)
159cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            free(fmt->dims);
160cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    }
161cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine}
162cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine
163cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Returns an index of the given pixel format in an array containing pixel
164cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * format descriptors.
165cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * This routine is used to choose a pixel format for a camera device. The idea
166cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * is that when the camera service enumerates all pixel formats for all cameras
167cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * connected to the host, we need to choose just one, which would be most
168cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * appropriate for camera emulation. To do that, the camera service will run
169cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * formats, contained in _preferred_formats array against enumerated pixel
170cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * formats to pick the first format that match.
171cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Param:
172cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *  fmt - Pixel format, for which to obtain the index.
173cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *  formats - Array containing list of pixel formats, supported by the camera
174cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *      device.
175cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *  size - Number of elements in the 'formats' array.
176cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Return:
177cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *  Index of the matched entry in the array, or -1 if no entry has been found.
178cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine */
179cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkinestatic int
180cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine_get_format_index(uint32_t fmt, QemuPixelFormat* formats, int size)
181cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine{
182cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    int f;
183cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    for (f = 0; f < size && formats[f].format != fmt; f++);
184cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    return f < size ? f : -1;
185cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine}
186cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine
1874ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine/*******************************************************************************
1884ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine *                     CameraFrameBuffer routines
1894ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine ******************************************************************************/
1904ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
1914ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine/* Frees array of framebuffers, depending on the I/O method the array has been
1924ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine * initialized for.
1934ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine * Note that this routine doesn't frees the array itself.
1944ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine * Param:
1954ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine *  fb, num - Array data, and its size.
1964ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine *  io_type - Type of the I/O the array has been initialized for.
1974ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine */
1984ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkinestatic void
1994ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine_free_framebuffers(CameraFrameBuffer* fb, int num, CameraIoType io_type)
2004ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine{
2014ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    if (fb != NULL) {
2024ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        int n;
2034ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
2044ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        switch (io_type) {
2054ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            case CAMERA_IO_MEMMAP:
2064ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                /* Unmap framebuffers. */
2074ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                for (n = 0; n < num; n++) {
2084ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                    if (fb[n].data != NULL) {
2094ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                        munmap(fb[n].data, fb[n].size);
2104ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                        fb[n].data = NULL;
2114ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                        fb[n].size = 0;
2124ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                    }
2134ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                }
2144ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                break;
2154ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
2164ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            case CAMERA_IO_USERPTR:
2174ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            case CAMERA_IO_DIRECT:
2184ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                /* Free framebuffers. */
2194ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                for (n = 0; n < num; n++) {
2204ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                    if (fb[n].data != NULL) {
2214ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                        free(fb[n].data);
2224ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                        fb[n].data = NULL;
2234ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                        fb[n].size = 0;
2244ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                    }
2254ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                }
2264ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                break;
2274ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
2284ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            default:
229cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                E("%s: Invalid I/O type %d", __FUNCTION__, io_type);
2304ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                break;
2314ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        }
2324ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    }
2334ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine}
2344ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
2354ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine/*******************************************************************************
2364ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine *                     CameraDevice routines
2374ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine ******************************************************************************/
2384ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
2394ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine/* Allocates an instance of LinuxCameraDevice structure.
2404ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine * Return:
2414ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine *  Allocated instance of LinuxCameraDevice structure. Note that this routine
2424ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine *  also sets 'opaque' field in the 'header' structure to point back to the
2434ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine *  containing LinuxCameraDevice instance.
2444ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine */
2454ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkinestatic LinuxCameraDevice*
2464ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine_camera_device_alloc(void)
2474ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine{
2484ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    LinuxCameraDevice* cd;
2494ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
2504ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    ANEW0(cd);
2514ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    memset(cd, 0, sizeof(*cd));
2524ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    cd->header.opaque = cd;
2534ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    cd->handle = -1;
2544ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
2554ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    return cd;
2564ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine}
2574ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
2584ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine/* Uninitializes and frees CameraDevice structure.
2594ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine */
2604ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkinestatic void
2614ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine_camera_device_free(LinuxCameraDevice* lcd)
2624ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine{
2634ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    if (lcd != NULL) {
2644ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        /* Closing handle will also disconnect from the driver. */
2654ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        if (lcd->handle >= 0) {
2664ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            close(lcd->handle);
2674ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        }
2684ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        if (lcd->device_name != NULL) {
2694ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            free(lcd->device_name);
2704ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        }
2714ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        if (lcd->framebuffers != NULL) {
2724ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            _free_framebuffers(lcd->framebuffers, lcd->framebuffer_num,
2734ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                               lcd->io_type);
2744ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            free(lcd->framebuffers);
2754ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        }
2764ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        AFREE(lcd);
2774ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    } else {
278cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        E("%s: No descriptor", __FUNCTION__);
2794ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    }
2804ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine}
2814ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
282e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine/* Resets camera device after capturing.
283e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine * Since new capture request may require different frame dimensions we must
284e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine * reset camera device by reopening its handle. Otherwise attempts to set up new
285e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine * frame properties (different from the previous one) may fail. */
286e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkinestatic void
287e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine_camera_device_reset(LinuxCameraDevice* cd)
288e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine{
289e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine    struct v4l2_cropcap cropcap;
290e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine    struct v4l2_crop crop;
291e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine
292e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine    /* Free capturing framebuffers first. */
293e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine    if (cd->framebuffers != NULL) {
294e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine        _free_framebuffers(cd->framebuffers, cd->framebuffer_num, cd->io_type);
295e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine        free(cd->framebuffers);
296e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine        cd->framebuffers = NULL;
297e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine        cd->framebuffer_num = 0;
298e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine    }
299e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine
300e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine    /* Reset device handle. */
301e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine    close(cd->handle);
302e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine    cd->handle = open(cd->device_name, O_RDWR | O_NONBLOCK, 0);
303e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine
304e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine    if (cd->handle >= 0) {
305e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine        /* Select video input, video standard and tune here. */
306e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine        cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
307e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine        _xioctl(cd->handle, VIDIOC_CROPCAP, &cropcap);
308e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine        crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
309e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine        crop.c = cropcap.defrect; /* reset to default */
310e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine        _xioctl (cd->handle, VIDIOC_S_CROP, &crop);
311e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine    }
312e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine}
313e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine
3144ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine/* Memory maps buffers and shares mapped memory with the device.
3154ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine * Return:
3164ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine *  0 Framebuffers have been mapped.
3174ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine *  -1 A critical error has ocurred.
3184ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine *  1 Memory mapping is not available.
3194ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine */
3204ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkinestatic int
3214ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine_camera_device_mmap_framebuffer(LinuxCameraDevice* cd)
3224ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine{
3234ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    struct v4l2_requestbuffers req;
3244ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    CLEAR(req);
3254ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    req.count   = 4;
3264ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    req.type    = V4L2_BUF_TYPE_VIDEO_CAPTURE;
3274ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    req.memory  = V4L2_MEMORY_MMAP;
3284ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
3294ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* Request memory mapped buffers. Note that device can return less buffers
3304ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine     * than requested. */
3314ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    if(_xioctl(cd->handle, VIDIOC_REQBUFS, &req)) {
3324ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        if (EINVAL == errno) {
333cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            D("%s: Device '%s' does not support memory mapping",
3344ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine              __FUNCTION__, cd->device_name);
3354ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            return 1;
3364ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        } else {
3374ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            E("%s: VIDIOC_REQBUFS has failed: %s",
3384ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine              __FUNCTION__, strerror(errno));
3394ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            return -1;
3404ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        }
3414ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    }
3424ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
3434ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* Allocate framebuffer array. */
3444ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    cd->framebuffers = calloc(req.count, sizeof(CameraFrameBuffer));
3454ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    if (cd->framebuffers == NULL) {
3464ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        E("%s: Not enough memory to allocate framebuffer array", __FUNCTION__);
3474ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        return -1;
3484ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    }
3494ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
3504ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* Map every framebuffer to the shared memory, and queue it
3514ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine     * with the device. */
3524ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    for(cd->framebuffer_num = 0; cd->framebuffer_num < req.count;
3534ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        cd->framebuffer_num++) {
3544ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        /* Map framebuffer. */
3554ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        struct v4l2_buffer buf;
3564ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        CLEAR(buf);
3574ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        buf.type    = V4L2_BUF_TYPE_VIDEO_CAPTURE;
3584ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        buf.memory  = V4L2_MEMORY_MMAP;
3594ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        buf.index   = cd->framebuffer_num;
3604ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        if(_xioctl(cd->handle, VIDIOC_QUERYBUF, &buf) < 0) {
3614ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            E("%s: VIDIOC_QUERYBUF has failed: %s",
3624ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine              __FUNCTION__, strerror(errno));
3634ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            return -1;
3644ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        }
3654ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        cd->framebuffers[cd->framebuffer_num].size = buf.length;
3664ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        cd->framebuffers[cd->framebuffer_num].data =
3674ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED,
3684ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                 cd->handle, buf.m.offset);
3694ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        if (MAP_FAILED == cd->framebuffers[cd->framebuffer_num].data) {
3704ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            E("%s: Memory mapping has failed: %s",
3714ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine              __FUNCTION__, strerror(errno));
3724ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            return -1;
3734ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        }
3744ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
3754ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        /* Queue the mapped buffer. */
3764ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        CLEAR(buf);
3774ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
3784ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        buf.memory = V4L2_MEMORY_MMAP;
3794ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        buf.index = cd->framebuffer_num;
3804ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        if (_xioctl(cd->handle, VIDIOC_QBUF, &buf) < 0) {
3814ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            E("%s: VIDIOC_QBUF has failed: %s", __FUNCTION__, strerror(errno));
3824ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            return -1;
3834ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        }
3844ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    }
3854ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
3864ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    cd->io_type = CAMERA_IO_MEMMAP;
3874ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
3884ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    return 0;
3894ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine}
3904ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
3914ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine/* Allocates frame buffers and registers them with the device.
3924ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine * Return:
3934ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine *  0 Framebuffers have been mapped.
3944ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine *  -1 A critical error has ocurred.
3954ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine *  1 Device doesn't support user pointers.
3964ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine */
3974ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkinestatic int
3984ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine_camera_device_user_framebuffer(LinuxCameraDevice* cd)
3994ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine{
4004ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    struct v4l2_requestbuffers req;
4014ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    CLEAR (req);
4024ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    req.count   = 4;
4034ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    req.type    = V4L2_BUF_TYPE_VIDEO_CAPTURE;
4044ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    req.memory  = V4L2_MEMORY_USERPTR;
4054ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
4064ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* Request user buffers. Note that device can return less buffers
4074ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine     * than requested. */
4084ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    if(_xioctl(cd->handle, VIDIOC_REQBUFS, &req)) {
4094ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        if (EINVAL == errno) {
410cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            D("%s: Device '%s' does not support user pointers",
4114ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine              __FUNCTION__, cd->device_name);
4124ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            return 1;
4134ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        } else {
4144ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            E("%s: VIDIOC_REQBUFS has failed: %s",
4154ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine              __FUNCTION__, strerror(errno));
4164ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            return -1;
4174ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        }
4184ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    }
4194ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
4204ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* Allocate framebuffer array. */
4214ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    cd->framebuffers = calloc(req.count, sizeof(CameraFrameBuffer));
4224ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    if (cd->framebuffers == NULL) {
4234ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        E("%s: Not enough memory to allocate framebuffer array", __FUNCTION__);
4244ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        return -1;
4254ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    }
4264ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
4274ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* Allocate buffers, queueing them wit the device at the same time */
4284ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    for(cd->framebuffer_num = 0; cd->framebuffer_num < req.count;
4294ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        cd->framebuffer_num++) {
4304ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        cd->framebuffers[cd->framebuffer_num].size =
4314ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            cd->actual_pixel_format.sizeimage;
4324ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        cd->framebuffers[cd->framebuffer_num].data =
4334ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            malloc(cd->framebuffers[cd->framebuffer_num].size);
4344ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        if (cd->framebuffers[cd->framebuffer_num].data == NULL) {
4354ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            E("%s: Not enough memory to allocate framebuffer", __FUNCTION__);
4364ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            return -1;
4374ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        }
4384ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
4394ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        /* Queue the user buffer. */
4404ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        struct v4l2_buffer buf;
4414ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        CLEAR(buf);
4424ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
4434ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        buf.memory = V4L2_MEMORY_USERPTR;
444cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        buf.m.userptr = (unsigned long)cd->framebuffers[cd->framebuffer_num].data;
4454ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        buf.length = cd->framebuffers[cd->framebuffer_num].size;
4464ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        if (_xioctl(cd->handle, VIDIOC_QBUF, &buf) < 0) {
4474ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            E("%s: VIDIOC_QBUF has failed: %s", __FUNCTION__, strerror(errno));
4484ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            return -1;
4494ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        }
4504ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    }
4514ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
4524ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    cd->io_type = CAMERA_IO_USERPTR;
4534ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
4544ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    return 0;
4554ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine}
4564ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
4574ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine/* Allocate frame buffer for direct read from the device.
4584ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine * Return:
4594ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine *  0 Framebuffers have been mapped.
4604ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine *  -1 A critical error has ocurred.
4614ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine *  1 Memory mapping is not available.
4624ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine */
4634ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkinestatic int
4644ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine_camera_device_direct_framebuffer(LinuxCameraDevice* cd)
4654ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine{
4664ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* Allocate framebuffer array. */
4674ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    cd->framebuffer_num = 1;
4684ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    cd->framebuffers = malloc(sizeof(CameraFrameBuffer));
4694ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    if (cd->framebuffers == NULL) {
4704ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        E("%s: Not enough memory to allocate framebuffer array", __FUNCTION__);
4714ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        return -1;
4724ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    }
4734ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
4744ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    cd->framebuffers[0].size = cd->actual_pixel_format.sizeimage;
4754ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    cd->framebuffers[0].data = malloc(cd->framebuffers[0].size);
4764ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    if (cd->framebuffers[0].data == NULL) {
4774ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        E("%s: Not enough memory to allocate framebuffer", __FUNCTION__);
4784ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        return -1;
4794ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    }
4804ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
4814ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    cd->io_type = CAMERA_IO_DIRECT;
4824ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
4834ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    return 0;
4844ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine}
4854ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
486cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Opens camera device.
487cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Param:
488cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *  cd - Camera device descriptor to open the camera for.
489cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Return:
490cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *  0 on success, != 0 on failure.
491cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine */
4924ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkinestatic int
4934ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine_camera_device_open(LinuxCameraDevice* cd)
4944ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine{
4954ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    struct stat st;
4964ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
4974ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    if (stat(cd->device_name, &st)) {
4984ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        return -1;
4994ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    }
5004ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
5014ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    if (!S_ISCHR(st.st_mode)) {
502cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        E("%s: '%s' is not a device", __FUNCTION__, cd->device_name);
5034ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        return -1;
5044ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    }
5054ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
5064ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* Open handle to the device, and query device capabilities. */
5074ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    cd->handle = open(cd->device_name, O_RDWR | O_NONBLOCK, 0);
5084ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    if (cd->handle < 0) {
509cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        E("%s: Cannot open camera device '%s': %s",
5104ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine          __FUNCTION__, cd->device_name, strerror(errno));
5114ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        return -1;
5124ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    }
5134ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    if (_xioctl(cd->handle, VIDIOC_QUERYCAP, &cd->caps) < 0) {
5144ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        if (EINVAL == errno) {
5154ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            E("%s: Camera '%s' is not a V4L2 device",
5164ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine              __FUNCTION__, cd->device_name);
5174ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            close(cd->handle);
5184ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            cd->handle = -1;
5194ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            return -1;
5204ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        } else {
521cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            E("%s: Unable to query capabilities for camera device '%s'",
5224ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine              __FUNCTION__, cd->device_name);
5234ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            close(cd->handle);
5244ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            cd->handle = -1;
5254ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            return -1;
5264ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        }
5274ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    }
5284ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
5294ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* Make sure that camera supports minimal requirements. */
5304ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    if (!(cd->caps.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
5314ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        E("%s: Camera '%s' is not a video capture device",
5324ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine          __FUNCTION__, cd->device_name);
5334ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        close(cd->handle);
5344ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        cd->handle = -1;
5354ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        return -1;
5364ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    }
5374ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
5384ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    return 0;
5394ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine}
5404ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
541cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Enumerates frame sizes for the given pixel format.
542cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Param:
543cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *  cd - Opened camera device descriptor.
544cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *  fmt - Pixel format to enum frame sizes for.
545cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *  sizes - Upon success contains an array of supported frame sizes. The size of
546cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *      the array is defined by the value, returned from this routine. The caller
547cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *      is responsible for freeing memory allocated for this array.
548cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Return:
549cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *  On success returns number of entries in the 'sizes' array. On failure returns
550cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *  a negative value.
551cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine */
552cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkinestatic int
553cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine_camera_device_enum_format_sizes(LinuxCameraDevice* cd,
554cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                                 uint32_t fmt,
555cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                                 CameraFrameDim** sizes)
556cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine{
557cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    int n;
558cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    int sizes_num = 0;
559cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    int out_num = 0;
560cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    struct v4l2_frmsizeenum size_enum;
561cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    CameraFrameDim* arr;
562cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine
563cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    /* Calculate number of supported sizes for the given format. */
564cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    for (n = 0; ; n++) {
565cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        size_enum.index = n;
566cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        size_enum.pixel_format = fmt;
567cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        if(_xioctl(cd->handle, VIDIOC_ENUM_FRAMESIZES, &size_enum)) {
568cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            break;
569cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        }
570cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        if (size_enum.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
571cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            /* Size is in the simpe width, height form. */
572cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            sizes_num++;
573cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        } else if (size_enum.type == V4L2_FRMSIZE_TYPE_STEPWISE) {
574cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            /* Sizes are represented as min/max width and height with a step for
575cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine             * each dimension. Since at the end we want to list each supported
576cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine             * size in the array (that's the only format supported by the guest
577cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine             * camera framework), we need to calculate how many array entries
578cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine             * this will generate. */
579cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            const uint32_t dif_widths =
580cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                (size_enum.stepwise.max_width - size_enum.stepwise.min_width) /
581cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                size_enum.stepwise.step_width + 1;
582cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            const uint32_t dif_heights =
583cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                (size_enum.stepwise.max_height - size_enum.stepwise.min_height) /
584cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                size_enum.stepwise.step_height + 1;
585cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            sizes_num += dif_widths * dif_heights;
586cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        } else if (size_enum.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) {
587cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            /* Special stepwise case, when steps are set to 1. We still need to
588cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine             * flatten this for the guest, but the array may be too big.
589cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine             * Fortunately, we don't need to be fancy, so three sizes would be
590cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine             * sufficient here: min, max, and one in the middle. */
591cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            sizes_num += 3;
592cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        }
593cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine
594cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    }
595cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    if (sizes_num == 0) {
596cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        return 0;
597cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    }
598cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine
599cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    /* Allocate, and initialize the array of supported entries. */
600cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    *sizes = (CameraFrameDim*)malloc(sizes_num * sizeof(CameraFrameDim));
601cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    if (*sizes == NULL) {
602cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        E("%s: Memory allocation failure", __FUNCTION__);
603cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        return -1;
604cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    }
605cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    arr = *sizes;
606cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    for (n = 0; out_num < sizes_num; n++) {
607cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        size_enum.index = n;
608cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        size_enum.pixel_format = fmt;
609cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        if(_xioctl(cd->handle, VIDIOC_ENUM_FRAMESIZES, &size_enum)) {
610cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            /* Errors are not welcome here anymore. */
611cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            E("%s: Unexpected failure while getting pixel dimensions: %s",
612cdd8d78b202e005691467296b9be98816ed4d4a9Vladimir Chtchetkine              __FUNCTION__, strerror(errno));
613cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            free(arr);
614cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            return -1;
615cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        }
616cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine
617cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        if (size_enum.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
618cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            arr[out_num].width = size_enum.discrete.width;
619cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            arr[out_num].height = size_enum.discrete.height;
620cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            out_num++;
621cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        } else if (size_enum.type == V4L2_FRMSIZE_TYPE_STEPWISE) {
622cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            uint32_t w;
623cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            for (w = size_enum.stepwise.min_width;
624cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                 w <= size_enum.stepwise.max_width;
625cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                 w += size_enum.stepwise.step_width) {
626cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                uint32_t h;
627cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                for (h = size_enum.stepwise.min_height;
628cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                     h <= size_enum.stepwise.max_height;
629cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                     h += size_enum.stepwise.step_height) {
630cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                    arr[out_num].width = w;
631cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                    arr[out_num].height = h;
632cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                    out_num++;
633cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                }
634cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            }
635cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        } else if (size_enum.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) {
636cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            /* min */
637cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            arr[out_num].width = size_enum.stepwise.min_width;
638cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            arr[out_num].height = size_enum.stepwise.min_height;
639cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            out_num++;
640cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            /* one in the middle */
641cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            arr[out_num].width =
642cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                (size_enum.stepwise.min_width + size_enum.stepwise.max_width) / 2;
643cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            arr[out_num].height =
644cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                (size_enum.stepwise.min_height + size_enum.stepwise.max_height) / 2;
645cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            out_num++;
646cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            /* max */
647cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            arr[out_num].width = size_enum.stepwise.max_width;
648cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            arr[out_num].height = size_enum.stepwise.max_height;
649cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            out_num++;
650cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        }
651cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    }
652cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine
653cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    return out_num;
654cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine}
655cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine
656cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Enumerates pixel formats, supported by the device.
657cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Note that this routine will enumerate only raw (uncompressed) formats.
658cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Param:
659cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *  cd - Opened camera device descriptor.
660cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *  fmts - Upon success contains an array of supported pixel formats. The size of
661cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *      the array is defined by the value, returned from this routine. The caller
662cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *      is responsible for freeing memory allocated for this array.
663cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Return:
664cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *  On success returns number of entries in the 'fmts' array. On failure returns
665cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *  a negative value.
666cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine */
667cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkinestatic int
668cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine_camera_device_enum_pixel_formats(LinuxCameraDevice* cd, QemuPixelFormat** fmts)
669cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine{
67079570c3532503840855517494978082a99543a30Vladimir Chtchetkine    int n, max_fmt;
671cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    int fmt_num = 0;
672cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    int out_num = 0;
673cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    struct v4l2_fmtdesc fmt_enum;
674cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    QemuPixelFormat* arr;
675cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine
676cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    /* Calculate number of supported formats. */
67779570c3532503840855517494978082a99543a30Vladimir Chtchetkine    for (max_fmt = 0; ; max_fmt++) {
67879570c3532503840855517494978082a99543a30Vladimir Chtchetkine        memset(&fmt_enum, 0, sizeof(fmt_enum));
67979570c3532503840855517494978082a99543a30Vladimir Chtchetkine        fmt_enum.index = max_fmt;
680cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        fmt_enum.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
681cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        if(_xioctl(cd->handle, VIDIOC_ENUM_FMT, &fmt_enum)) {
682cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            break;
683cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        }
684cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        /* Skip the compressed ones. */
685cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        if ((fmt_enum.flags & V4L2_FMT_FLAG_COMPRESSED) == 0) {
686cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            fmt_num++;
687cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        }
688cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    }
689cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    if (fmt_num == 0) {
690cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        return 0;
691cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    }
692cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine
693cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    /* Allocate, and initialize array for enumerated formats. */
694cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    *fmts = (QemuPixelFormat*)malloc(fmt_num * sizeof(QemuPixelFormat));
695cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    if (*fmts == NULL) {
696cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        E("%s: Memory allocation failure", __FUNCTION__);
697cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        return -1;
698cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    }
699cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    arr = *fmts;
700cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    memset(arr, 0, fmt_num * sizeof(QemuPixelFormat));
70179570c3532503840855517494978082a99543a30Vladimir Chtchetkine    for (n = 0; n < max_fmt && out_num < fmt_num; n++) {
70279570c3532503840855517494978082a99543a30Vladimir Chtchetkine        memset(&fmt_enum, 0, sizeof(fmt_enum));
703cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        fmt_enum.index = n;
704cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        fmt_enum.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
705cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        if(_xioctl(cd->handle, VIDIOC_ENUM_FMT, &fmt_enum)) {
706cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            int nn;
707cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            /* Errors are not welcome here anymore. */
708cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            E("%s: Unexpected failure while getting pixel format: %s",
709cdd8d78b202e005691467296b9be98816ed4d4a9Vladimir Chtchetkine              __FUNCTION__, strerror(errno));
710cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            for (nn = 0; nn < out_num; nn++) {
711cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                _qemu_pixel_format_free(arr + nn);
712cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            }
713cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            free(arr);
714cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            return -1;
715cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        }
716cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        /* Skip the compressed ones. */
717cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        if ((fmt_enum.flags & V4L2_FMT_FLAG_COMPRESSED) == 0) {
718cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            arr[out_num].format = fmt_enum.pixelformat;
719cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            /* Enumerate frame dimensions supported for this format. */
720cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            arr[out_num].dim_num =
721cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                _camera_device_enum_format_sizes(cd, fmt_enum.pixelformat,
722cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                                                 &arr[out_num].dims);
723cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            if (arr[out_num].dim_num > 0) {
724cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                out_num++;
725cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            } else if (arr[out_num].dim_num < 0) {
726cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                int nn;
727cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                E("Unable to enumerate supported dimensions for pixel format %d",
728cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                  fmt_enum.pixelformat);
729cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                for (nn = 0; nn < out_num; nn++) {
730cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                    _qemu_pixel_format_free(arr + nn);
731cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                }
732cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                free(arr);
733cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                return -1;
734cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            }
735cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        }
736cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    }
737cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine
738cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    return out_num;
739cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine}
740cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine
741cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine/* Collects information about an opened camera device.
742cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * The information collected in this routine contains list of pixel formats,
743cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * supported by the device, and list of frame dimensions supported by the camera
744cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * for each pixel format.
745cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Param:
746cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *  cd - Opened camera device descriptor.
747cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *  cis - Upon success contains information collected from the camera device.
748cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine * Return:
749cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine *  0 on success, != 0 on failure.
750cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine */
751cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkinestatic int
752cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine_camera_device_get_info(LinuxCameraDevice* cd, CameraInfo* cis)
753cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine{
754cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    int f;
755cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    int chosen = -1;
756cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    QemuPixelFormat* formats = NULL;
757cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    int num_pix_fmts = _camera_device_enum_pixel_formats(cd, &formats);
758cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    if (num_pix_fmts <= 0) {
75979570c3532503840855517494978082a99543a30Vladimir Chtchetkine        return -1;
760cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    }
761cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine
762cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    /* Lets see if camera supports preferred formats */
763cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    for (f = 0; f < _preferred_format_num; f++) {
764cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        chosen = _get_format_index(_preferred_formats[f], formats, num_pix_fmts);
765cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        if (chosen >= 0) {
766cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            break;
767cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        }
768cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    }
769cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    if (chosen < 0) {
770cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        /* Camera doesn't support any of the chosen formats. Then it doesn't
771cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine         * matter which one we choose. Lets choose the first one. */
772cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        chosen = 0;
773cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    }
774cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine
775cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    cis->device_name = ASTRDUP(cd->device_name);
776cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    cis->inp_channel = cd->input_channel;
777cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    cis->pixel_format = formats[chosen].format;
778cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    cis->frame_sizes_num = formats[chosen].dim_num;
779cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    /* Swap instead of copy. */
780cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    cis->frame_sizes = formats[chosen].dims;
781cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    formats[chosen].dims = NULL;
782cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    cis->in_use = 0;
783cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine
784cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    for (f = 0; f < num_pix_fmts; f++) {
785cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        _qemu_pixel_format_free(formats + f);
786cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    }
787cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    free(formats);
788cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine
789cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    return 0;
790cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine}
791cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine
7924ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine/*******************************************************************************
7934ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine *                     CameraDevice API
7944ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine ******************************************************************************/
7954ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
7964ed09fd35085c96ae8edbda87757187f75eeac8dVladimir ChtchetkineCameraDevice*
797cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkinecamera_device_open(const char* name, int inp_channel)
7984ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine{
7994ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    struct v4l2_cropcap cropcap;
8004ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    struct v4l2_crop crop;
8014ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    LinuxCameraDevice* cd;
8024ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
8034ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* Allocate and initialize the descriptor. */
8044ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    cd = _camera_device_alloc();
8054ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    cd->device_name = name != NULL ? ASTRDUP(name) : ASTRDUP("/dev/video0");
8064ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    cd->input_channel = inp_channel;
8074ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
8084ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* Open the device. */
8094ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    if (_camera_device_open(cd)) {
8104ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        _camera_device_free(cd);
8114ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        return NULL;
8124ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    }
8134ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
8144ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* Select video input, video standard and tune here. */
8154ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
8164ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    _xioctl(cd->handle, VIDIOC_CROPCAP, &cropcap);
8174ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
8184ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    crop.c = cropcap.defrect; /* reset to default */
8194ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    _xioctl (cd->handle, VIDIOC_S_CROP, &crop);
8204ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
8214ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    return &cd->header;
8224ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine}
8234ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
8244ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkineint
825cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkinecamera_device_start_capturing(CameraDevice* ccd,
826cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                              uint32_t pixel_format,
827cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                              int frame_width,
828cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                              int frame_height)
8294ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine{
830cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    struct v4l2_format fmt;
8314ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    LinuxCameraDevice* cd;
832cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    char fmt_str[5];
833cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    int r;
8344ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
8354ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* Sanity checks. */
8364ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    if (ccd == NULL || ccd->opaque == NULL) {
8374ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine      E("%s: Invalid camera device descriptor", __FUNCTION__);
8384ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine      return -1;
8394ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    }
8404ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    cd = (LinuxCameraDevice*)ccd->opaque;
841ce31fbc48a43ea4265be1d20f157e8749b3e11ddVladimir Chtchetkine    if (cd->handle < 0) {
842ce31fbc48a43ea4265be1d20f157e8749b3e11ddVladimir Chtchetkine      E("%s: Camera device is not opened", __FUNCTION__);
843ce31fbc48a43ea4265be1d20f157e8749b3e11ddVladimir Chtchetkine      return -1;
844ce31fbc48a43ea4265be1d20f157e8749b3e11ddVladimir Chtchetkine    }
8454ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
846cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    /* Try to set pixel format with the given dimensions. */
847cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    CLEAR(fmt);
848cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
849cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    fmt.fmt.pix.width       = frame_width;
850cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    fmt.fmt.pix.height      = frame_height;
851cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    fmt.fmt.pix.pixelformat = pixel_format;
852cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    if (_xioctl(cd->handle, VIDIOC_S_FMT, &fmt) < 0) {
853cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        memcpy(fmt_str, &pixel_format, 4);
854cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        fmt_str[4] = '\0';
855cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        E("%s: Camera '%s' does not support pixel format '%s' with dimensions %dx%d",
856cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine          __FUNCTION__, cd->device_name, fmt_str, frame_width, frame_height);
857e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine        _camera_device_reset(cd);
858cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        return -1;
859cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    }
860cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    /* VIDIOC_S_FMT may has changed some properties of the structure. Make sure
861cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine     * that dimensions didn't change. */
862cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    if (fmt.fmt.pix.width != frame_width || fmt.fmt.pix.height != frame_height) {
863cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        memcpy(fmt_str, &pixel_format, 4);
864cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        fmt_str[4] = '\0';
865cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        E("%s: Dimensions %dx%d are wrong for pixel format '%s'",
866cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine          __FUNCTION__, frame_width, frame_height, fmt_str);
867e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine        _camera_device_reset(cd);
868cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        return -1;
869cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    }
870cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    memcpy(&cd->actual_pixel_format, &fmt.fmt.pix, sizeof(struct v4l2_pix_format));
871cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine
8724ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /*
8734ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine     * Lets initialize frame buffers, and see what kind of I/O we're going to
8744ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine     * use to retrieve frames.
8754ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine     */
8764ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
8774ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* First, lets see if we can do mapped I/O (as most performant one). */
878cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    r = _camera_device_mmap_framebuffer(cd);
8794ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    if (r < 0) {
8804ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        /* Some critical error has ocurred. Bail out. */
881e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine        _camera_device_reset(cd);
8824ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        return -1;
8834ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    } else if (r > 0) {
8844ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        /* Device doesn't support memory mapping. Retrieve to the next performant
8854ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine         * one: preallocated user buffers. */
8864ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        r = _camera_device_user_framebuffer(cd);
8874ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        if (r < 0) {
8884ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            /* Some critical error has ocurred. Bail out. */
889e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine            _camera_device_reset(cd);
8904ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            return -1;
8914ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        } else if (r > 0) {
8924ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            /* The only thing left for us is direct reading from the device. */
8934ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            if (!(cd->caps.capabilities & V4L2_CAP_READWRITE)) {
894cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                E("%s: Don't know how to access frames on device '%s'",
8954ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                  __FUNCTION__, cd->device_name);
896e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine                _camera_device_reset(cd);
8974ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                return -1;
8984ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            }
8994ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            r = _camera_device_direct_framebuffer(cd);
9004ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            if (r != 0) {
9014ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                /* Any error at this point is a critical one. */
902e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine                _camera_device_reset(cd);
9034ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                return -1;
9044ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            }
9054ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        }
9064ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    }
9074ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
9084ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* Start capturing from the device. */
9094ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    if (cd->io_type != CAMERA_IO_DIRECT) {
9104ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        enum v4l2_buf_type type;
9114ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
9124ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        if (_xioctl (cd->handle, VIDIOC_STREAMON, &type) < 0) {
913cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            E("%s: VIDIOC_STREAMON on camera '%s' has failed: %s",
914cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine              __FUNCTION__, cd->device_name, strerror(errno));
915e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine            _camera_device_reset(cd);
9164ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            return -1;
9174ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        }
9184ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    }
9194ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    return 0;
9204ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine}
9214ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
9224ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkineint
9234ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkinecamera_device_stop_capturing(CameraDevice* ccd)
9244ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine{
9254ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    enum v4l2_buf_type type;
9264ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    LinuxCameraDevice* cd;
9274ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
9284ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* Sanity checks. */
9294ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    if (ccd == NULL || ccd->opaque == NULL) {
9304ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine      E("%s: Invalid camera device descriptor", __FUNCTION__);
9314ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine      return -1;
9324ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    }
9334ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    cd = (LinuxCameraDevice*)ccd->opaque;
934ce31fbc48a43ea4265be1d20f157e8749b3e11ddVladimir Chtchetkine    if (cd->handle < 0) {
935ce31fbc48a43ea4265be1d20f157e8749b3e11ddVladimir Chtchetkine      E("%s: Camera device is not opened", __FUNCTION__);
936ce31fbc48a43ea4265be1d20f157e8749b3e11ddVladimir Chtchetkine      return -1;
937ce31fbc48a43ea4265be1d20f157e8749b3e11ddVladimir Chtchetkine    }
9384ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
9394ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    switch (cd->io_type) {
9404ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        case CAMERA_IO_DIRECT:
9414ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            /* Nothing to do. */
9424ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            break;
9434ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
9444ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        case CAMERA_IO_MEMMAP:
9454ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        case CAMERA_IO_USERPTR:
9464ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
9474ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            if (_xioctl(cd->handle, VIDIOC_STREAMOFF, &type) < 0) {
948cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine	            E("%s: VIDIOC_STREAMOFF on camera '%s' has failed: %s",
949cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                  __FUNCTION__, cd->device_name, strerror(errno));
9504ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                return -1;
9514ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            }
9524ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            break;
9534ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        default:
9544ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            E("%s: Unknown I/O method: %d", __FUNCTION__, cd->io_type);
9554ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            return -1;
9564ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    }
9574ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
958ce31fbc48a43ea4265be1d20f157e8749b3e11ddVladimir Chtchetkine    /* Reopen the device to reset its internal state. It seems that if we don't
959ce31fbc48a43ea4265be1d20f157e8749b3e11ddVladimir Chtchetkine     * do that, an attempt to reinit the device with different frame dimensions
960ce31fbc48a43ea4265be1d20f157e8749b3e11ddVladimir Chtchetkine     * would fail. */
961e3b840cfa695c2f0b26625cf01149b9cc9079ce9Vladimir Chtchetkine    _camera_device_reset(cd);
962ce31fbc48a43ea4265be1d20f157e8749b3e11ddVladimir Chtchetkine
9634ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    return 0;
9644ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine}
9654ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
9664ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkineint
967cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkinecamera_device_read_frame(CameraDevice* ccd,
968cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                         ClientFrameBuffer* framebuffers,
96937fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine                         int fbs_num,
97037fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine                         float r_scale,
97137fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine                         float g_scale,
97237fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine                         float b_scale,
97337fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine                         float exp_comp)
9744ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine{
9754ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    LinuxCameraDevice* cd;
9764ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
9774ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* Sanity checks. */
9784ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    if (ccd == NULL || ccd->opaque == NULL) {
9794ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine      E("%s: Invalid camera device descriptor", __FUNCTION__);
9804ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine      return -1;
9814ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    }
9824ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    cd = (LinuxCameraDevice*)ccd->opaque;
983ce31fbc48a43ea4265be1d20f157e8749b3e11ddVladimir Chtchetkine    if (cd->handle < 0) {
984ce31fbc48a43ea4265be1d20f157e8749b3e11ddVladimir Chtchetkine      E("%s: Camera device is not opened", __FUNCTION__);
985ce31fbc48a43ea4265be1d20f157e8749b3e11ddVladimir Chtchetkine      return -1;
986ce31fbc48a43ea4265be1d20f157e8749b3e11ddVladimir Chtchetkine    }
9874ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
9884ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    if (cd->io_type == CAMERA_IO_DIRECT) {
9894ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        /* Read directly from the device. */
9904ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        size_t total_read_bytes = 0;
991cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        /* There is one framebuffer allocated for direct read. */
992cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        void* buff = cd->framebuffers[0].data;
9934ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        do {
9944ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            int read_bytes =
9954ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                read(cd->handle, buff + total_read_bytes,
9964ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                     cd->actual_pixel_format.sizeimage - total_read_bytes);
9974ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            if (read_bytes < 0) {
9984ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                switch (errno) {
9994ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                    case EIO:
10004ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                    case EAGAIN:
10014ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                        continue;
10024ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                    default:
1003cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                        E("%s: Unable to read from the camera device '%s': %s",
1004cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                          __FUNCTION__, cd->device_name, strerror(errno));
10054ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                        return -1;
10064ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                }
10074ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            }
10084ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            total_read_bytes += read_bytes;
10094ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        } while (total_read_bytes < cd->actual_pixel_format.sizeimage);
1010cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        /* Convert the read frame into the caller's framebuffers. */
1011cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        return convert_frame(buff, cd->actual_pixel_format.pixelformat,
1012cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                             cd->actual_pixel_format.sizeimage,
1013cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                             cd->actual_pixel_format.width,
1014cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                             cd->actual_pixel_format.height,
101537fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine                             framebuffers, fbs_num,
101637fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine                             r_scale, g_scale, b_scale, exp_comp);
10174ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    } else {
10184ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        /* Dequeue next buffer from the device. */
10194ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        struct v4l2_buffer buf;
1020cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        int res;
10214ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        CLEAR(buf);
10224ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
10234ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        buf.memory = cd->io_type == CAMERA_IO_MEMMAP ? V4L2_MEMORY_MMAP :
10244ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine                                                       V4L2_MEMORY_USERPTR;
1025cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        for (;;) {
1026cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            const int res = _xioctl(cd->handle, VIDIOC_DQBUF, &buf);
1027cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            if (res >= 0) {
1028cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                break;
1029cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            } else if (errno == EAGAIN) {
1030cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                return 1;   // Tells the caller to repeat.
1031af81d7432594d8459c4fb9f76c5e8a981f69a94cDavid 'Digit' Turner            } else if (errno != EIO) {
1032cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                E("%s: VIDIOC_DQBUF on camera '%s' has failed: %s",
1033cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                  __FUNCTION__, cd->device_name, strerror(errno));
1034cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                return -1;
10354ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine            }
10364ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        }
1037cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine
1038cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        /* Convert frame to the receiving buffers. */
1039cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        res = convert_frame(cd->framebuffers[buf.index].data,
1040cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                            cd->actual_pixel_format.pixelformat,
1041cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                            cd->actual_pixel_format.sizeimage,
1042cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                            cd->actual_pixel_format.width,
1043cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                            cd->actual_pixel_format.height,
104437fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine                            framebuffers, fbs_num,
104537fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine                            r_scale, g_scale, b_scale, exp_comp);
1046cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine
1047cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        /* Requeue the buffer back to the device. */
10484ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        if (_xioctl(cd->handle, VIDIOC_QBUF, &buf) < 0) {
1049cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            W("%s: VIDIOC_QBUF on camera '%s' has failed: %s",
1050cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine              __FUNCTION__, cd->device_name, strerror(errno));
10514ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        }
1052cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine
1053cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        return res;
10544ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    }
10554ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine}
10564ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
10574ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkinevoid
10584ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkinecamera_device_close(CameraDevice* ccd)
10594ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine{
10604ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    LinuxCameraDevice* cd;
10614ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine
10624ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    /* Sanity checks. */
10634ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    if (ccd != NULL && ccd->opaque != NULL) {
10644ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        cd = (LinuxCameraDevice*)ccd->opaque;
10654ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        _camera_device_free(cd);
10664ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    } else {
10674ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine        E("%s: Invalid camera device descriptor", __FUNCTION__);
10684ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine    }
10694ed09fd35085c96ae8edbda87757187f75eeac8dVladimir Chtchetkine}
1070cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine
1071cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkineint
1072cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkineenumerate_camera_devices(CameraInfo* cis, int max)
1073cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine{
1074cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    char dev_name[24];
1075cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    int found = 0;
1076cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    int n;
1077cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine
1078cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    for (n = 0; n < max; n++) {
1079cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        CameraDevice* cd;
1080cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine
1081cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        sprintf(dev_name, "/dev/video%d", n);
1082cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        cd = camera_device_open(dev_name, 0);
1083cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        if (cd != NULL) {
1084cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            LinuxCameraDevice* lcd = (LinuxCameraDevice*)cd->opaque;
1085cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            if (!_camera_device_get_info(lcd, cis + found)) {
1086b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine                char user_name[24];
1087b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine                sprintf(user_name, "webcam%d", found);
1088b8dcaffaf7dcb0c795d2776abf3bb75196f8527cVladimir Chtchetkine                cis[found].display_name = ASTRDUP(user_name);
1089cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                cis[found].in_use = 0;
1090cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine                found++;
1091cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            }
1092cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            camera_device_close(cd);
1093cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        } else {
1094cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine            break;
1095cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine        }
1096cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    }
1097cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine
1098cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine    return found;
1099cf1c2c70dd99e7d78816ba9a558f9ed8c016862bVladimir Chtchetkine}
1100