From 4ed09fd35085c96ae8edbda87757187f75eeac8d Mon Sep 17 00:00:00 2001 From: Vladimir Chtchetkine Date: Thu, 18 Aug 2011 09:42:40 -0700 Subject: Video capturing code for Linux, and Windows Contains API that connects to a camera device, and pulls video frames from it on request from the client. Change-Id: If1d80c57611afff637a7734ce5c3a2c874cfc85a --- android/camera/camera-capture-linux.c | 678 ++++++++++++++++++++++++++++++ android/camera/camera-capture-windows.c | 409 ++++++++++++++++++ android/camera/camera-capture.h | 86 ++++ android/camera/camera-common.h | 53 +++ android/camera/camera-format-converters.c | 126 ++++++ android/camera/camera-format-converters.h | 51 +++ android/camera/camera-win.h | 64 +++ 7 files changed, 1467 insertions(+) create mode 100644 android/camera/camera-capture-linux.c create mode 100755 android/camera/camera-capture-windows.c create mode 100644 android/camera/camera-capture.h create mode 100755 android/camera/camera-common.h create mode 100755 android/camera/camera-format-converters.c create mode 100755 android/camera/camera-format-converters.h create mode 100644 android/camera/camera-win.h (limited to 'android/camera') diff --git a/android/camera/camera-capture-linux.c b/android/camera/camera-capture-linux.c new file mode 100644 index 0000000..8944270 --- /dev/null +++ b/android/camera/camera-capture-linux.c @@ -0,0 +1,678 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Contains code that is used to capture video frames from a camera device + * on Linux. This code uses V4L2 API to work with camera devices, and requires + * Linux kernel version at least 2.5 + */ + +#include +#include +#include +#include +#include "qemu-common.h" +#include "android/utils/debug.h" +#include "android/utils/misc.h" +#include "android/utils/system.h" +#include "android/camera/camera-capture.h" +#include "android/camera/camera-format-converters.h" + +#define D(...) VERBOSE_PRINT(camera,__VA_ARGS__) +#define W(...) VERBOSE_PRINT(camera,__VA_ARGS__) +#define E(...) VERBOSE_PRINT(camera,__VA_ARGS__) +#define D_ACTIVE VERBOSE_CHECK(camera) + +/* the T(...) macro is used to dump traffic */ +#define T_ACTIVE 0 + +#if T_ACTIVE +#define T(...) VERBOSE_PRINT(camera,__VA_ARGS__) +#else +#define T(...) ((void)0) +#endif + +#define CLEAR(x) memset (&(x), 0, sizeof(x)) + +/* Describes a framebuffer. */ +typedef struct CameraFrameBuffer { + /* Framebuffer data. */ + uint8_t* data; + /* Framebuffer data size. */ + size_t size; +} CameraFrameBuffer; + +/* Defines type of the I/O used to obtain frames from the device. */ +typedef enum CameraIoType { + /* Framebuffers are shared via memory mapping. */ + CAMERA_IO_MEMMAP, + /* Framebuffers are available via user pointers. */ + CAMERA_IO_USERPTR, + /* Framebuffers are to be read from the device. */ + CAMERA_IO_DIRECT +} CameraIoType; + +typedef struct LinuxCameraDevice LinuxCameraDevice; +/* + * Describes a connection to an actual camera device. + */ +struct LinuxCameraDevice { + /* Common header. */ + CameraDevice header; + + /* Camera device name. (default is /dev/video0) */ + char* device_name; + /* Input channel. (default is 0) */ + int input_channel; + /* Requested pixel format. */ + uint32_t req_pixel_format; + + /* + * Set by the framework after initializing camera connection. + */ + + /* Handle to the opened camera device. */ + int handle; + /* Device capabilities. */ + struct v4l2_capability caps; + /* Actual pixel format reported by the device. */ + struct v4l2_pix_format actual_pixel_format; + /* Defines type of the I/O to use to retrieve frames from the device. */ + CameraIoType io_type; + /* Allocated framebuffers. */ + struct CameraFrameBuffer* framebuffers; + /* Actual number of allocated framebuffers. */ + int framebuffer_num; +}; + +/******************************************************************************* + * Helper routines + ******************************************************************************/ + +/* IOCTL wrapper. */ +static int +_xioctl(int fd, int request, void *arg) { + int r; + do { + r = ioctl(fd, request, arg); + } while (-1 == r && EINTR == errno); + return r; +} + +/******************************************************************************* + * CameraFrameBuffer routines + ******************************************************************************/ + +/* Frees array of framebuffers, depending on the I/O method the array has been + * initialized for. + * Note that this routine doesn't frees the array itself. + * Param: + * fb, num - Array data, and its size. + * io_type - Type of the I/O the array has been initialized for. + */ +static void +_free_framebuffers(CameraFrameBuffer* fb, int num, CameraIoType io_type) +{ + if (fb != NULL) { + int n; + + switch (io_type) { + case CAMERA_IO_MEMMAP: + /* Unmap framebuffers. */ + for (n = 0; n < num; n++) { + if (fb[n].data != NULL) { + munmap(fb[n].data, fb[n].size); + fb[n].data = NULL; + fb[n].size = 0; + } + } + break; + + case CAMERA_IO_USERPTR: + case CAMERA_IO_DIRECT: + /* Free framebuffers. */ + for (n = 0; n < num; n++) { + if (fb[n].data != NULL) { + free(fb[n].data); + fb[n].data = NULL; + fb[n].size = 0; + } + } + break; + + default: + E("Invalid I/O type %d", io_type); + break; + } + } +} + +/******************************************************************************* + * CameraDevice routines + ******************************************************************************/ + +/* Allocates an instance of LinuxCameraDevice structure. + * Return: + * Allocated instance of LinuxCameraDevice structure. Note that this routine + * also sets 'opaque' field in the 'header' structure to point back to the + * containing LinuxCameraDevice instance. + */ +static LinuxCameraDevice* +_camera_device_alloc(void) +{ + LinuxCameraDevice* cd; + + ANEW0(cd); + memset(cd, 0, sizeof(*cd)); + cd->header.opaque = cd; + cd->handle = -1; + + return cd; +} + +/* Uninitializes and frees CameraDevice structure. + */ +static void +_camera_device_free(LinuxCameraDevice* lcd) +{ + if (lcd != NULL) { + /* Closing handle will also disconnect from the driver. */ + if (lcd->handle >= 0) { + close(lcd->handle); + } + if (lcd->device_name != NULL) { + free(lcd->device_name); + } + if (lcd->framebuffers != NULL) { + _free_framebuffers(lcd->framebuffers, lcd->framebuffer_num, + lcd->io_type); + free(lcd->framebuffers); + } + AFREE(lcd); + } else { + W("%s: No descriptor", __FUNCTION__); + } +} + +/* Memory maps buffers and shares mapped memory with the device. + * Return: + * 0 Framebuffers have been mapped. + * -1 A critical error has ocurred. + * 1 Memory mapping is not available. + */ +static int +_camera_device_mmap_framebuffer(LinuxCameraDevice* cd) +{ + struct v4l2_requestbuffers req; + CLEAR(req); + req.count = 4; + req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + req.memory = V4L2_MEMORY_MMAP; + + /* Request memory mapped buffers. Note that device can return less buffers + * than requested. */ + if(_xioctl(cd->handle, VIDIOC_REQBUFS, &req)) { + if (EINVAL == errno) { + D("%s: %s does not support memory mapping", + __FUNCTION__, cd->device_name); + return 1; + } else { + E("%s: VIDIOC_REQBUFS has failed: %s", + __FUNCTION__, strerror(errno)); + return -1; + } + } + + /* Allocate framebuffer array. */ + cd->framebuffers = calloc(req.count, sizeof(CameraFrameBuffer)); + if (cd->framebuffers == NULL) { + E("%s: Not enough memory to allocate framebuffer array", __FUNCTION__); + return -1; + } + + /* Map every framebuffer to the shared memory, and queue it + * with the device. */ + for(cd->framebuffer_num = 0; cd->framebuffer_num < req.count; + cd->framebuffer_num++) { + /* Map framebuffer. */ + struct v4l2_buffer buf; + CLEAR(buf); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = cd->framebuffer_num; + if(_xioctl(cd->handle, VIDIOC_QUERYBUF, &buf) < 0) { + E("%s: VIDIOC_QUERYBUF has failed: %s", + __FUNCTION__, strerror(errno)); + return -1; + } + cd->framebuffers[cd->framebuffer_num].size = buf.length; + cd->framebuffers[cd->framebuffer_num].data = + mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, + cd->handle, buf.m.offset); + if (MAP_FAILED == cd->framebuffers[cd->framebuffer_num].data) { + E("%s: Memory mapping has failed: %s", + __FUNCTION__, strerror(errno)); + return -1; + } + + /* Queue the mapped buffer. */ + CLEAR(buf); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = cd->framebuffer_num; + if (_xioctl(cd->handle, VIDIOC_QBUF, &buf) < 0) { + E("%s: VIDIOC_QBUF has failed: %s", __FUNCTION__, strerror(errno)); + return -1; + } + } + + cd->io_type = CAMERA_IO_MEMMAP; + + return 0; +} + +/* Allocates frame buffers and registers them with the device. + * Return: + * 0 Framebuffers have been mapped. + * -1 A critical error has ocurred. + * 1 Device doesn't support user pointers. + */ +static int +_camera_device_user_framebuffer(LinuxCameraDevice* cd) +{ + struct v4l2_requestbuffers req; + CLEAR (req); + req.count = 4; + req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + req.memory = V4L2_MEMORY_USERPTR; + + /* Request user buffers. Note that device can return less buffers + * than requested. */ + if(_xioctl(cd->handle, VIDIOC_REQBUFS, &req)) { + if (EINVAL == errno) { + D("%s: %s does not support user pointers", + __FUNCTION__, cd->device_name); + return 1; + } else { + E("%s: VIDIOC_REQBUFS has failed: %s", + __FUNCTION__, strerror(errno)); + return -1; + } + } + + /* Allocate framebuffer array. */ + cd->framebuffers = calloc(req.count, sizeof(CameraFrameBuffer)); + if (cd->framebuffers == NULL) { + E("%s: Not enough memory to allocate framebuffer array", __FUNCTION__); + return -1; + } + + /* Allocate buffers, queueing them wit the device at the same time */ + for(cd->framebuffer_num = 0; cd->framebuffer_num < req.count; + cd->framebuffer_num++) { + cd->framebuffers[cd->framebuffer_num].size = + cd->actual_pixel_format.sizeimage; + cd->framebuffers[cd->framebuffer_num].data = + malloc(cd->framebuffers[cd->framebuffer_num].size); + if (cd->framebuffers[cd->framebuffer_num].data == NULL) { + E("%s: Not enough memory to allocate framebuffer", __FUNCTION__); + return -1; + } + + /* Queue the user buffer. */ + struct v4l2_buffer buf; + CLEAR(buf); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_USERPTR; + buf.m.userptr = cd->framebuffers[cd->framebuffer_num].data; + buf.length = cd->framebuffers[cd->framebuffer_num].size; + if (_xioctl(cd->handle, VIDIOC_QBUF, &buf) < 0) { + E("%s: VIDIOC_QBUF has failed: %s", __FUNCTION__, strerror(errno)); + return -1; + } + } + + cd->io_type = CAMERA_IO_USERPTR; + + return 0; +} + +/* Allocate frame buffer for direct read from the device. + * Return: + * 0 Framebuffers have been mapped. + * -1 A critical error has ocurred. + * 1 Memory mapping is not available. + */ +static int +_camera_device_direct_framebuffer(LinuxCameraDevice* cd) +{ + /* Allocate framebuffer array. */ + cd->framebuffer_num = 1; + cd->framebuffers = malloc(sizeof(CameraFrameBuffer)); + if (cd->framebuffers == NULL) { + E("%s: Not enough memory to allocate framebuffer array", __FUNCTION__); + return -1; + } + + cd->framebuffers[0].size = cd->actual_pixel_format.sizeimage; + cd->framebuffers[0].data = malloc(cd->framebuffers[0].size); + if (cd->framebuffers[0].data == NULL) { + E("%s: Not enough memory to allocate framebuffer", __FUNCTION__); + return -1; + } + + cd->io_type = CAMERA_IO_DIRECT; + + return 0; +} + +static int +_camera_device_open(LinuxCameraDevice* cd) +{ + struct stat st; + + if (stat(cd->device_name, &st)) { + E("%s: Cannot identify camera device '%s': %s", + __FUNCTION__, cd->device_name, strerror(errno)); + return -1; + } + + if (!S_ISCHR(st.st_mode)) { + E("%s: %s is not a device", __FUNCTION__, cd->device_name); + return -1; + } + + /* Open handle to the device, and query device capabilities. */ + cd->handle = open(cd->device_name, O_RDWR | O_NONBLOCK, 0); + if (cd->handle < 0) { + E("%s: Cannot open camera device '%s': %s\n", + __FUNCTION__, cd->device_name, strerror(errno)); + return -1; + } + if (_xioctl(cd->handle, VIDIOC_QUERYCAP, &cd->caps) < 0) { + if (EINVAL == errno) { + E("%s: Camera '%s' is not a V4L2 device", + __FUNCTION__, cd->device_name); + close(cd->handle); + cd->handle = -1; + return -1; + } else { + E("%s: Unable to query camera '%s' capabilities", + __FUNCTION__, cd->device_name); + close(cd->handle); + cd->handle = -1; + return -1; + } + } + + /* Make sure that camera supports minimal requirements. */ + if (!(cd->caps.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { + E("%s: Camera '%s' is not a video capture device", + __FUNCTION__, cd->device_name); + close(cd->handle); + cd->handle = -1; + return -1; + } + + return 0; +} + +/******************************************************************************* + * CameraDevice API + ******************************************************************************/ + +CameraDevice* +camera_device_open(const char* name, + int inp_channel, + uint32_t pixel_format) +{ + struct v4l2_cropcap cropcap; + struct v4l2_crop crop; + struct v4l2_format fmt; + LinuxCameraDevice* cd; + + /* Allocate and initialize the descriptor. */ + cd = _camera_device_alloc(); + cd->device_name = name != NULL ? ASTRDUP(name) : ASTRDUP("/dev/video0"); + cd->input_channel = inp_channel; + cd->req_pixel_format = pixel_format; + + /* Open the device. */ + if (_camera_device_open(cd)) { + _camera_device_free(cd); + return NULL; + } + + /* Select video input, video standard and tune here. */ + cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + _xioctl(cd->handle, VIDIOC_CROPCAP, &cropcap); + crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + crop.c = cropcap.defrect; /* reset to default */ + _xioctl (cd->handle, VIDIOC_S_CROP, &crop); + + /* Image settings. */ + CLEAR(fmt); + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + fmt.fmt.pix.width = 0; + fmt.fmt.pix.height = 0; + fmt.fmt.pix.pixelformat = 0; + if (_xioctl(cd->handle, VIDIOC_G_FMT, &fmt) < 0) { + E("%s: Unable to obtain pixel format", __FUNCTION__); + _camera_device_free(cd); + return NULL; + } + if (_xioctl(cd->handle, VIDIOC_S_FMT, &fmt) < 0) { + char fmt_str[5]; + memcpy(fmt_str, &cd->req_pixel_format, 4); + fmt_str[4] = '\0'; + E("%s: Camera '%s' does not support requested pixel format '%s'", + __FUNCTION__, cd->device_name, fmt_str); + _camera_device_free(cd); + return NULL; + } + /* VIDIOC_S_FMT has changed some properties of the structure, adjusting them + * to the actual values, supported by the device. */ + memcpy(&cd->actual_pixel_format, &fmt.fmt.pix, + sizeof(cd->actual_pixel_format)); + { + char fmt_str[5]; + memcpy(fmt_str, &cd->req_pixel_format, 4); + fmt_str[4] = '\0'; + D("%s: Camera '%s' uses pixel format '%s'", + __FUNCTION__, cd->device_name, fmt_str); + } + + return &cd->header; +} + +int +camera_device_start_capturing(CameraDevice* ccd) +{ + LinuxCameraDevice* cd; + + /* Sanity checks. */ + if (ccd == NULL || ccd->opaque == NULL) { + E("%s: Invalid camera device descriptor", __FUNCTION__); + return -1; + } + cd = (LinuxCameraDevice*)ccd->opaque; + + /* + * Lets initialize frame buffers, and see what kind of I/O we're going to + * use to retrieve frames. + */ + + /* First, lets see if we can do mapped I/O (as most performant one). */ + int r = _camera_device_mmap_framebuffer(cd); + if (r < 0) { + /* Some critical error has ocurred. Bail out. */ + return -1; + } else if (r > 0) { + /* Device doesn't support memory mapping. Retrieve to the next performant + * one: preallocated user buffers. */ + r = _camera_device_user_framebuffer(cd); + if (r < 0) { + /* Some critical error has ocurred. Bail out. */ + return -1; + } else if (r > 0) { + /* The only thing left for us is direct reading from the device. */ + if (!(cd->caps.capabilities & V4L2_CAP_READWRITE)) { + E("%s: Device '%s' doesn't support direct read", + __FUNCTION__, cd->device_name); + return -1; + } + r = _camera_device_direct_framebuffer(cd); + if (r != 0) { + /* Any error at this point is a critical one. */ + return -1; + } + } + } + + /* Start capturing from the device. */ + if (cd->io_type != CAMERA_IO_DIRECT) { + enum v4l2_buf_type type; + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (_xioctl (cd->handle, VIDIOC_STREAMON, &type) < 0) { + E("%s: VIDIOC_STREAMON has failed: %s", + __FUNCTION__, strerror(errno)); + return -1; + } + } + + return 0; +} + +int +camera_device_stop_capturing(CameraDevice* ccd) +{ + enum v4l2_buf_type type; + LinuxCameraDevice* cd; + + /* Sanity checks. */ + if (ccd == NULL || ccd->opaque == NULL) { + E("%s: Invalid camera device descriptor", __FUNCTION__); + return -1; + } + cd = (LinuxCameraDevice*)ccd->opaque; + + switch (cd->io_type) { + case CAMERA_IO_DIRECT: + /* Nothing to do. */ + break; + + case CAMERA_IO_MEMMAP: + case CAMERA_IO_USERPTR: + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (_xioctl(cd->handle, VIDIOC_STREAMOFF, &type) < 0) { + E("%s: VIDIOC_STREAMOFF has failed: %s", + __FUNCTION__, strerror(errno)); + return -1; + } + break; + default: + E("%s: Unknown I/O method: %d", __FUNCTION__, cd->io_type); + return -1; + } + + if (cd->framebuffers != NULL) { + _free_framebuffers(cd->framebuffers, cd->framebuffer_num, cd->io_type); + free(cd->framebuffers); + cd->framebuffers = NULL; + cd->framebuffer_num = 0; + } + return 0; +} + +int +camera_device_read_frame(CameraDevice* ccd, uint8_t* buff) +{ + LinuxCameraDevice* cd; + + /* Sanity checks. */ + if (ccd == NULL || ccd->opaque == NULL) { + E("%s: Invalid camera device descriptor", __FUNCTION__); + return -1; + } + cd = (LinuxCameraDevice*)ccd->opaque; + + if (cd->io_type == CAMERA_IO_DIRECT) { + /* Read directly from the device. */ + size_t total_read_bytes = 0; + do { + int read_bytes = + read(cd->handle, buff + total_read_bytes, + cd->actual_pixel_format.sizeimage - total_read_bytes); + if (read_bytes < 0) { + switch (errno) { + case EIO: + case EAGAIN: + continue; + default: + E("%s: Unable to read from the device: %s", + __FUNCTION__, strerror(errno)); + return -1; + } + } + total_read_bytes += read_bytes; + } while (total_read_bytes < cd->actual_pixel_format.sizeimage); + return 0; + } else { + /* Dequeue next buffer from the device. */ + struct v4l2_buffer buf; + CLEAR(buf); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = cd->io_type == CAMERA_IO_MEMMAP ? V4L2_MEMORY_MMAP : + V4L2_MEMORY_USERPTR; + if (_xioctl(cd->handle, VIDIOC_DQBUF, &buf) < 0) { + switch (errno) { + case EAGAIN: + return 1; + + case EIO: + /* Could ignore EIO, see spec. */ + /* fall through */ + default: + E("%s: VIDIOC_DQBUF has failed: %s", + __FUNCTION__, strerror(errno)); + return 1; + } + } + /* Copy frame to the buffer. */ + memcpy(buff, cd->framebuffers[buf.index].data, + cd->framebuffers[buf.index].size); + /* Requeue the buffer with the device. */ + if (_xioctl(cd->handle, VIDIOC_QBUF, &buf) < 0) { + D("%s: VIDIOC_QBUF has failed: %s", + __FUNCTION__, strerror(errno)); + } + return 0; + } +} + +void +camera_device_close(CameraDevice* ccd) +{ + LinuxCameraDevice* cd; + + /* Sanity checks. */ + if (ccd != NULL && ccd->opaque != NULL) { + cd = (LinuxCameraDevice*)ccd->opaque; + _camera_device_free(cd); + } else { + E("%s: Invalid camera device descriptor", __FUNCTION__); + } +} diff --git a/android/camera/camera-capture-windows.c b/android/camera/camera-capture-windows.c new file mode 100755 index 0000000..ac571ce --- /dev/null +++ b/android/camera/camera-capture-windows.c @@ -0,0 +1,409 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Contains code capturing video frames from a camera device on Windows. + * This code uses capXxx API, available via capCreateCaptureWindow. + */ +/* +#include +#include +#include +#include +#include +*/ +#include "qemu-common.h" +#include "android/utils/debug.h" +#include "android/utils/misc.h" +#include "android/utils/system.h" +#include +#include "android/camera/camera-capture.h" +#include "android/camera/camera-format-converters.h" + +#define D(...) VERBOSE_PRINT(camera,__VA_ARGS__) +#define W(...) VERBOSE_PRINT(camera,__VA_ARGS__) +#define E(...) VERBOSE_PRINT(camera,__VA_ARGS__) +#define D_ACTIVE VERBOSE_CHECK(camera) + +/* the T(...) macro is used to dump traffic */ +#define T_ACTIVE 0 + +#if T_ACTIVE +#define T(...) VERBOSE_PRINT(camera,__VA_ARGS__) +#else +#define T(...) ((void)0) +#endif + +/* Default name for the capture window. */ +static const char* _default_window_name = "AndroidEmulatorVC"; + +typedef struct WndCameraDevice WndCameraDevice; +/* Windows-specific camera device descriptor. */ +struct WndCameraDevice { + /* Common camera device descriptor. */ + CameraDevice header; + /* Capture window name. (default is AndroidEmulatorVC) */ + char* window_name; + /* Input channel (video driver index). (default is 0) */ + int input_channel; + /* Requested pixel format. */ + uint32_t req_pixel_format; + + /* + * Set when framework gets initialized. + */ + + /* Video capturing window. Null indicates that device is not connected. */ + HWND cap_window; + /* DC for frame bitmap manipulation. Null indicates that frames are not + * being capturing. */ + HDC dc; + /* Bitmap info for the frames obtained from the video capture driver. + * This information will be used when we get bitmap bits via + * GetDIBits API. */ + BITMAPINFO* frame_bitmap; + /* Framebuffer large enough to fit the frame. */ + uint8_t* framebuffer; + /* Converter used to convert camera frames to the format + * expected by the client. */ + FormatConverter converter; +}; + +/******************************************************************************* + * CameraDevice routines + ******************************************************************************/ + +/* Allocates an instance of WndCameraDevice structure. + * Return: + * Allocated instance of WndCameraDevice structure. Note that this routine + * also sets 'opaque' field in the 'header' structure to point back to the + * containing WndCameraDevice instance. + */ +static WndCameraDevice* +_camera_device_alloc(void) +{ + WndCameraDevice* cd = (WndCameraDevice*)malloc(sizeof(WndCameraDevice)); + if (cd != NULL) { + memset(cd, 0, sizeof(WndCameraDevice)); + cd->header.opaque = cd; + } else { + E("%s: Unable to allocate WndCameraDevice instance", __FUNCTION__); + } + return cd; +} + +/* Uninitializes and frees WndCameraDevice descriptor. + * Note that upon return from this routine memory allocated for the descriptor + * will be freed. + */ +static void +_camera_device_free(WndCameraDevice* cd) +{ + if (cd != NULL) { + if (cd->cap_window != NULL) { + /* Since connecting to the driver is part of the successful + * camera initialization, we're safe to assume that driver + * is connected to the capture window. */ + capDriverDisconnect(cd->cap_window); + + if (cd->dc != NULL) { + W("%s: Frames should not be capturing at this point", + __FUNCTION__); + ReleaseDC(cd->cap_window, cd->dc); + cd->dc = NULL; + } + /* Destroy the capturing window. */ + DestroyWindow(cd->cap_window); + cd->cap_window = NULL; + } + if (cd->frame_bitmap != NULL) { + free(cd->frame_bitmap); + } + if (cd->window_name != NULL) { + free(cd->window_name); + } + if (cd->framebuffer != NULL) { + free(cd->framebuffer); + } + AFREE(cd); + } else { + W("%s: No descriptor", __FUNCTION__); + } +} + +static uint32_t +_camera_device_convertable_format(WndCameraDevice* cd) +{ + if (cd != NULL) { + switch (cd->header.pixel_format) { + case BI_RGB: + switch (cd->frame_bitmap->bmiHeader.biBitCount) { + case 24: + return V4L2_PIX_FMT_RGB24; + default: + E("%s: Camera API uses unsupported RGB format RGB%d", + __FUNCTION__, cd->frame_bitmap->bmiHeader.biBitCount * 3); + return 0; + } + break; + default: + E("%s: Camera API uses unsupported format %d", + __FUNCTION__, cd->header.pixel_format); + break; + } + } else { + E("%s: No descriptor", __FUNCTION__); + } + + return 0; +} + +/******************************************************************************* + * CameraDevice API + ******************************************************************************/ + +CameraDevice* +camera_device_open(const char* name, + int inp_channel, + uint32_t pixel_format) +{ + WndCameraDevice* wcd; + size_t format_info_size; + + /* Allocate descriptor and initialize windows-specific fields. */ + wcd = _camera_device_alloc(); + if (wcd == NULL) { + E("%s: Unable to allocate WndCameraDevice instance", __FUNCTION__); + return NULL; + } + wcd->window_name = (name != NULL) ? ASTRDUP(name) : + ASTRDUP(_default_window_name); + if (wcd->window_name == NULL) { + E("%s: Unable to save window name", __FUNCTION__); + _camera_device_free(wcd); + return NULL; + } + wcd->input_channel = inp_channel; + wcd->req_pixel_format = pixel_format; + + /* Create capture window that is a child of HWND_MESSAGE window. + * We make it invisible, so it doesn't mess with the UI. Also + * note that we supply standard HWND_MESSAGE window handle as + * the parent window, since we don't want video capturing + * machinery to be dependent on the details of our UI. */ + wcd->cap_window = capCreateCaptureWindow(wcd->window_name, WS_CHILD, 0, 0, + 0, 0, HWND_MESSAGE, 1); + if (wcd->cap_window == NULL) { + E("%s: Unable to create video capturing window: %d", + __FUNCTION__, GetLastError()); + _camera_device_free(wcd); + return NULL; + } + + /* Connect capture window to the video capture driver. */ + if (!capDriverConnect(wcd->cap_window, wcd->input_channel)) { + /* Unable to connect to a driver. Need to cleanup everything + * now since we're not going to receive camera_cleanup() call + * after unsuccessful camera initialization. */ + E("%s: Unable to connect to the video capturing driver #%d: %d", + __FUNCTION__, wcd->input_channel, GetLastError()); + DestroyWindow(wcd->cap_window); + wcd->cap_window = NULL; + _camera_device_free(wcd); + return NULL; + } + + /* Get frame information from the driver. */ + format_info_size = capGetVideoFormatSize(wcd->cap_window); + if (format_info_size == 0) { + E("%s: Unable to get video format size: %d", + __FUNCTION__, GetLastError()); + return NULL; + } + wcd->frame_bitmap = (BITMAPINFO*)malloc(format_info_size); + if (wcd->frame_bitmap == NULL) { + E("%s: Unable to allocate frame bitmap info buffer", __FUNCTION__); + _camera_device_free(wcd); + return NULL; + } + if (!capGetVideoFormat(wcd->cap_window, wcd->frame_bitmap, + format_info_size)) { + E("%s: Unable to obtain video format: %d", __FUNCTION__, GetLastError()); + _camera_device_free(wcd); + return NULL; + } + + /* Initialize the common header. */ + wcd->header.width = wcd->frame_bitmap->bmiHeader.biWidth; + wcd->header.height = wcd->frame_bitmap->bmiHeader.biHeight; + wcd->header.bpp = wcd->frame_bitmap->bmiHeader.biBitCount; + wcd->header.pixel_format = wcd->frame_bitmap->bmiHeader.biCompression; + wcd->header.bpl = (wcd->header.width * wcd->header.bpp) / 8; + if ((wcd->header.width * wcd->header.bpp) % 8) { + // TODO: Is this correct to assume that new line in framebuffer is aligned + // to a byte, or is it alogned to a multiple of bytes occupied by a pixel? + wcd->header.bpl++; + } + wcd->header.framebuffer_size = wcd->header.bpl * wcd->header.height; + + /* Lets see if we have a convertor for the format. */ + wcd->converter = get_format_converted(_camera_device_convertable_format(wcd), + wcd->req_pixel_format); + if (wcd->converter == NULL) { + E("%s: No converter available", __FUNCTION__); + _camera_device_free(wcd); + return NULL; + } + + /* Allocate framebuffer. */ + wcd->framebuffer = (uint8_t*)malloc(wcd->header.framebuffer_size); + if (wcd->framebuffer == NULL) { + E("%s: Unable to allocate framebuffer", __FUNCTION__); + _camera_device_free(wcd); + return NULL; + } + + return &wcd->header; +} + +int +camera_device_start_capturing(CameraDevice* cd) +{ + WndCameraDevice* wcd; + if (cd == NULL || cd->opaque == NULL) { + E("%s: Invalid camera device descriptor", __FUNCTION__); + return -1; + } + wcd = (WndCameraDevice*)cd->opaque; + + /* wcd->dc is an indicator of capturin: !NULL - capturing, NULL - not */ + if (wcd->dc != NULL) { + /* It's already capturing. */ + W("%s: Capturing is already on %s", __FUNCTION__, wcd->window_name); + return 0; + } + + /* Get DC for the capturing window that will be used when we deal with + * bitmaps obtained from the camera device during frame capturing. */ + wcd->dc = GetDC(wcd->cap_window); + if (wcd->dc == NULL) { + E("%s: Unable to obtain DC for %s: %d", + __FUNCTION__, wcd->window_name, GetLastError()); + return -1; + } + + return 0; +} + +int +camera_device_stop_capturing(CameraDevice* cd) +{ + WndCameraDevice* wcd; + if (cd == NULL || cd->opaque == NULL) { + E("%s: Invalid camera device descriptor", __FUNCTION__); + return -1; + } + wcd = (WndCameraDevice*)cd->opaque; + if (wcd->dc == NULL) { + W("%s: Windows %s is not captuing video", __FUNCTION__, wcd->window_name); + return 0; + } + ReleaseDC(wcd->cap_window, wcd->dc); + wcd->dc = NULL; + + return 0; +} + +int +camera_device_read_frame(CameraDevice* cd, uint8_t* buffer) +{ + WndCameraDevice* wcd; + /* Bitmap handle taken from the clipboard. */ + HBITMAP bm_handle; + /* Pitmap placed to the clipboard. */ + BITMAP bitmap; + + /* Sanity checks. */ + if (cd == NULL || cd->opaque == NULL) { + E("%s: Invalid camera device descriptor", __FUNCTION__); + return -1; + } + wcd = (WndCameraDevice*)cd->opaque; + if (wcd->dc == NULL) { + W("%s: Windows %s is not captuing video", + __FUNCTION__, wcd->window_name); + return -1; + } + + /* Grab a frame, and post it to the clipboard. Not very effective, but this + * is how capXxx API is operating. */ + if (!capGrabFrameNoStop(wcd->cap_window) || + !capEditCopy(wcd->cap_window) || + !OpenClipboard(wcd->cap_window)) { + E("%s: %s: Unable to save frame to the clipboard: %d", + __FUNCTION__, wcd->window_name, GetLastError()); + return -1; + } + + /* Get bitmap handle saved into clipboard. Note that bitmap is still + * owned by the clipboard here! */ + bm_handle = (HBITMAP)GetClipboardData(CF_BITMAP); + CloseClipboard(); + if (bm_handle == NULL) { + E("%s: %s: Unable to obtain frame from the clipboard: %d", + __FUNCTION__, wcd->window_name, GetLastError()); + return -1; + } + + /* Get bitmap information */ + if (!GetObject(bm_handle, sizeof(BITMAP), &bitmap)) { + E("%s: %s Unable to obtain frame's bitmap: %d", + __FUNCTION__, wcd->window_name, GetLastError()); + return -1; + } + + /* Save bitmap bits to the framebuffer. */ + if (!GetDIBits(wcd->dc, bm_handle, 0, wcd->frame_bitmap->bmiHeader.biHeight, + wcd->framebuffer, wcd->frame_bitmap, DIB_RGB_COLORS)) { + E("%s: %s: Unable to transfer frame to the framebuffer: %d", + __FUNCTION__, wcd->window_name, GetLastError()); + return -1; + } + + /* Lets see if conversion is required. */ + if (_camera_device_convertable_format(wcd) == wcd->req_pixel_format) { + /* Formats match. Just copy framebuffer over. */ + memcpy(buffer, wcd->framebuffer, wcd->header.framebuffer_size); + } else { + /* Formats do not match. Use the converter. */ + wcd->converter(wcd->framebuffer, wcd->header.width, wcd->header.height, + buffer); + } + + return 0; +} + +void +camera_device_close(CameraDevice* cd) +{ + /* Sanity checks. */ + if (cd == NULL || cd->opaque == NULL) { + E("%s: Invalid camera device descriptor", __FUNCTION__); + } else { + WndCameraDevice* wcd = (WndCameraDevice*)cd->opaque; + _camera_device_free(wcd); + } +} diff --git a/android/camera/camera-capture.h b/android/camera/camera-capture.h new file mode 100644 index 0000000..f9ac2c9 --- /dev/null +++ b/android/camera/camera-capture.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_CAMERA_CAMERA_CAPTURE_H +#define ANDROID_CAMERA_CAMERA_CAPTURE_H + +/* + * Contains declarations for video capturing API that is used by the camera + * emulator. + */ + +#include "camera-common.h" + +/* Initializes camera device descriptor, and connects to the camera device. + * Param: + * name - On Linux contains name of the device to be used to capture video. + * On Windows contains name to assign to the capturing window. This parameter + * can be NULL, in which case '/dev/video0' will be used as device name on + * Linux, or 'AndroidEmulatorVC' on Windows. + * inp_channel - On Linux defines input channel to use when communicating with + * the camera driver. On Windows contains an index (up to 10) of the driver + * to use to communicate with the camera device. + * pixel_format - Defines pixel format in which the client of the camera API + * expects the frames. Note that is this format doesn't match pixel formats + * supported by the camera device, the camera API will provide a conversion. + * If such conversion is not available, this routine will fail. + * Return: + * Initialized camera device descriptor on success, or NULL on failure. + */ +extern CameraDevice* camera_device_open(const char* name, + int inp_channel, + uint32_t pixel_format); + +/* Starts capturing frames from the camera device. + * Param: + * cd - Camera descriptor representing a camera device opened in + * camera_device_open routine. + * Return: + * 0 on success, or non-zero value on failure. + */ +extern int camera_device_start_capturing(CameraDevice* cd); + +/* Stops capturing frames from the camera device. + * Param: + * cd - Camera descriptor representing a camera device opened in + * camera_device_open routine. + * Return: + * 0 on success, or non-zero value on failure. + */ +extern int camera_device_stop_capturing(CameraDevice* cd); + +/* Captures a frame from the camera device. + * Param: + * cd - Camera descriptor representing a camera device opened in + * camera_device_open routine. + * buffer - Address of the buffer where to read the frame. Note that the buffer + * must be large enough to contain the entire frame. Also note that due to + * possible format conversion, required buffer size may differ from the + * framebuffer size as reported by framebuffer_size int the CameraDevice + * structure. + * Return: + * 0 on success, or non-zero value on failure. + */ +extern int camera_device_read_frame(CameraDevice* cd, uint8_t* buffer); + +/* Closes camera device, opened in camera_device_open routine. + * Param: + * cd - Camera descriptor representing a camera device opened in + * camera_device_open routine. + */ +extern void camera_device_close(CameraDevice* cd); + +#endif /* ANDROID_CAMERA_CAMERA_CAPTURE_H */ diff --git a/android/camera/camera-common.h b/android/camera/camera-common.h new file mode 100755 index 0000000..ff5ce0a --- /dev/null +++ b/android/camera/camera-common.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_CAMERA_CAMERA_COMMON_H_ +#define ANDROID_CAMERA_CAMERA_COMMON_H_ + +/* + * Contains declarations of platform-independent the stuff that is used in + * camera emulation. + */ + +#ifdef _WIN32 +/* Include declarations that are missing in Windows SDK headers. */ +#include "android/camera/camera-win.h" +#endif /* _WIN32 */ + +/* Describes a connected camera device. + * This is a pratform-independent camera device descriptor that is used in + * the camera API. This descriptor also contains some essential camera + * properties, so the client of this API can use them to properly prepare to + * handle frame capturing. + */ +typedef struct CameraDevice { + /* Opaque pointer used by the camera capturing API. */ + void* opaque; + /* Frame's width in number of pixels. */ + int width; + /* Frame's height in number of pixels. */ + int height; + /* Number of bytes encoding each pixel. */ + uint32_t bpp; + /* Number of bytes encoding each line. */ + uint32_t bpl; + /* Pixel format of the frame captured from the camera device. */ + uint32_t pixel_format; + /* Total size in bytes of the framebuffer. */ + size_t framebuffer_size; +} CameraDevice; + +#endif /* ANDROID_CAMERA_CAMERA_COMMON_H_ */ diff --git a/android/camera/camera-format-converters.c b/android/camera/camera-format-converters.c new file mode 100755 index 0000000..e966e59 --- /dev/null +++ b/android/camera/camera-format-converters.c @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#ifndef _WIN32 +#include +#endif /* _WIN32 */ +#include "android/camera/camera-format-converters.h" + +/* Describes a convertor for one pixel format to another. */ +typedef struct FormatConverterEntry { + /* Pixel format to convert from. */ + uint32_t from_format; + /* Pixel format to convert to. */ + uint32_t to_format; + /* Address of the conversion routine. */ + FormatConverter converter; +} FormatConverterEntry; + +/* Converts frame from RGB24 (8 bits per color) to NV12 (YUV420) + * Param: + * rgb - RGB frame to convert. + * width, height - Width, and height of the RGB frame. + * yuv - Buffer to receive the converted frame. Note that this buffer must + * be big enough to contain all the converted pixels! + */ +static void +_RGB8_to_YUV420(const uint8_t* rgb, + int width, + int height, + uint8_t* yuv) +{ + const uint8_t* rgb_current = rgb; + int x, y, yi = 0; + const int num_pixels = width * height; + int ui = num_pixels; + int vi = num_pixels + num_pixels / 4; + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + const uint32_t b = rgb_current[0]; + const uint32_t g = rgb_current[1]; + const uint32_t r = rgb_current[2]; + rgb_current += 3; + yuv[yi++] = (uint8_t)((66*r + 129*g + 25*b + 128) >> 8) + 16; + if((x % 2 ) == 0 && (y % 2) == 0) { + yuv[ui++] = (uint8_t)((-38*r - 74*g + 112*b + 128) >> 8 ) + 128; + yuv[vi++] = (uint8_t)((112*r - 94*g - 18*b + 128) >> 8 ) + 128; + } + } + } +} + +/* Converts frame from RGB24 (8 bits per color) to NV21 (YVU420) + * Param: + * rgb - RGB frame to convert. + * width, height - Width, and height of the RGB frame. + * yuv - Buffer to receive the converted frame. Note that this buffer must + * be big enough to contain all the converted pixels! + */ +static void +_RGB8_to_YVU420(const uint8_t* rgb, + int width, + int height, + uint8_t* yuv) +{ + const uint8_t* rgb_current = rgb; + int x, y, yi = 0; + const int num_pixels = width * height; + int vi = num_pixels; + int ui = num_pixels + num_pixels / 4; + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + const uint32_t b = rgb_current[0]; + const uint32_t g = rgb_current[1]; + const uint32_t r = rgb_current[2]; + rgb_current += 3; + yuv[yi++] = (uint8_t)((66*r + 129*g + 25*b + 128) >> 8) + 16; + if((x % 2 ) == 0 && (y % 2) == 0) { + yuv[ui++] = (uint8_t)((-38*r - 74*g + 112*b + 128) >> 8 ) + 128; + yuv[vi++] = (uint8_t)((112*r - 94*g - 18*b + 128) >> 8 ) + 128; + } + } + } +} + +/* Lists currently implemented converters. */ +static const FormatConverterEntry _converters[] = { + /* RGB24 -> NV12 */ + { V4L2_PIX_FMT_RGB24, V4L2_PIX_FMT_NV12, _RGB8_to_YUV420 }, + /* RGB24 -> YUV420 */ + { V4L2_PIX_FMT_RGB24, V4L2_PIX_FMT_YUV420, _RGB8_to_YUV420 }, + /* RGB24 -> NV21 */ + { V4L2_PIX_FMT_RGB24, V4L2_PIX_FMT_NV21, _RGB8_to_YVU420 }, +}; + +FormatConverter +get_format_converted(uint32_t from, uint32_t to) +{ + const int num_converters = sizeof(_converters) / sizeof(*_converters); + int n; + for (n = 0; n < num_converters; n++) { + if (_converters[n].from_format == from && + _converters[n].to_format == to) { + return _converters[n].converter; + } + } + + return NULL; +} diff --git a/android/camera/camera-format-converters.h b/android/camera/camera-format-converters.h new file mode 100755 index 0000000..797ad48 --- /dev/null +++ b/android/camera/camera-format-converters.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_CAMERA_CAMERA_FORMAT_CONVERTERS_H +#define ANDROID_CAMERA_CAMERA_FORMAT_CONVERTERS_H + +/* + * Contains declaration of the API that allows converting frames from one + * pixel format to another. + */ + +#include "camera-common.h" + +/* Prototype of a routine that converts frame from one pixel format to another. + * Param: + * from - Frame to convert. + * width, height - Width, and height of the frame to convert. + * to - Buffer to receive the converted frame. Note that this buffer must + * be big enough to contain all the converted pixels! + */ +typedef void (*FormatConverter)(const uint8_t* from, + int width, + int height, + uint8_t* to); + + +/* Gets an address of a routine that provides frame conversion for the + * given pixel format. + * Param: + * from - Pixel format to convert from. + * to - Pixel format to convert to. + * Return: + * Address of an appropriate conversion routine, or NULL if no conversion + * routine exsits for the given pair of pixel formats. + */ +extern FormatConverter get_format_converted(uint32_t from, uint32_t to); + +#endif /* ANDROID_CAMERA_CAMERA_FORMAT_CONVERTERS_H */ diff --git a/android/camera/camera-win.h b/android/camera/camera-win.h new file mode 100644 index 0000000..3c04eb2 --- /dev/null +++ b/android/camera/camera-win.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_CAMERA_CAMERA_WIN_H_ +#define ANDROID_CAMERA_CAMERA_WIN_H_ + +/* + * Contains declarations that are missing in Windows SDK headers. + */ + +/* Four-character-code (FOURCC) */ +#define v4l2_fourcc(a,b,c,d)\ + (((uint32_t)(a)<<0)|((uint32_t)(b)<<8)|((uint32_t)(c)<<16)|((uint32_t)(d)<<24)) + +/* Pixel format FOURCC depth Description */ +#define V4L2_PIX_FMT_RGB332 v4l2_fourcc('R','G','B','1') /* 8 RGB-3-3-2 */ +#define V4L2_PIX_FMT_RGB444 v4l2_fourcc('R','4','4','4') /* 16 xxxxrrrr ggggbbbb */ +#define V4L2_PIX_FMT_RGB555 v4l2_fourcc('R','G','B','O') /* 16 RGB-5-5-5 */ +#define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R','G','B','P') /* 16 RGB-5-6-5 */ +#define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R','G','B','Q') /* 16 RGB-5-5-5 BE */ +#define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R','G','B','R') /* 16 RGB-5-6-5 BE */ +#define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B','G','R','3') /* 24 BGR-8-8-8 */ +#define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R','G','B','3') /* 24 RGB-8-8-8 */ +#define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B','G','R','4') /* 32 BGR-8-8-8-8 */ +#define V4L2_PIX_FMT_RGB32 v4l2_fourcc('R','G','B','4') /* 32 RGB-8-8-8-8 */ +#define V4L2_PIX_FMT_GREY v4l2_fourcc('G','R','E','Y') /* 8 Greyscale */ +#define V4L2_PIX_FMT_PAL8 v4l2_fourcc('P','A','L','8') /* 8 8-bit palette */ +#define V4L2_PIX_FMT_YVU410 v4l2_fourcc('Y','V','U','9') /* 9 YVU 4:1:0 */ +#define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y','V','1','2') /* 12 YVU 4:2:0 */ +#define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y','U','Y','V') /* 16 YUV 4:2:2 */ +#define V4L2_PIX_FMT_UYVY v4l2_fourcc('U','Y','V','Y') /* 16 YUV 4:2:2 */ +#define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4','2','2','P') /* 16 YVU422 planar */ +#define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4','1','1','P') /* 16 YVU411 planar */ +#define V4L2_PIX_FMT_Y41P v4l2_fourcc('Y','4','1','P') /* 12 YUV 4:1:1 */ +#define V4L2_PIX_FMT_YUV444 v4l2_fourcc('Y','4','4','4') /* 16 xxxxyyyy uuuuvvvv */ +#define V4L2_PIX_FMT_YUV555 v4l2_fourcc('Y','U','V','O') /* 16 YUV-5-5-5 */ +#define V4L2_PIX_FMT_YUV565 v4l2_fourcc('Y','U','V','P') /* 16 YUV-5-6-5 */ +#define V4L2_PIX_FMT_YUV32 v4l2_fourcc('Y','U','V','4') /* 32 YUV-8-8-8-8 */ + +/* two planes -- one Y, one Cr + Cb interleaved */ +#define V4L2_PIX_FMT_NV12 v4l2_fourcc('N','V','1','2') /* 12 Y/CbCr 4:2:0 */ +#define V4L2_PIX_FMT_NV21 v4l2_fourcc('N','V','2','1') /* 12 Y/CrCb 4:2:0 */ + +/* The following formats are not defined in the V4L2 specification */ +#define V4L2_PIX_FMT_YUV410 v4l2_fourcc('Y','U','V','9') /* 9 YUV 4:1:0 */ +#define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y','U','1','2') /* 12 YUV 4:2:0 */ +#define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y','Y','U','V') /* 16 YUV 4:2:2 */ +#define V4L2_PIX_FMT_HI240 v4l2_fourcc('H','I','2','4') /* 8 8-bit color */ +#define V4L2_PIX_FMT_HM12 v4l2_fourcc('H','M','1','2') /* 8 YUV 4:2:0 16x16 macroblocks */ + +#endif /* ANDROID_CAMERA_CAMERA_WIN_H_ */ -- cgit v1.1