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