aboutsummaryrefslogtreecommitdiffstats
path: root/android/camera
diff options
context:
space:
mode:
authorVladimir Chtchetkine <vchtchetkine@google.com>2011-08-18 09:42:40 -0700
committerVladimir Chtchetkine <vchtchetkine@google.com>2011-08-18 09:42:40 -0700
commit4ed09fd35085c96ae8edbda87757187f75eeac8d (patch)
treea4dee9e44deda454b6d2187a0fb408271b3c565c /android/camera
parentd4d22aef7ff40a47002ee1d53fbbbd7562f05596 (diff)
downloadexternal_qemu-4ed09fd35085c96ae8edbda87757187f75eeac8d.zip
external_qemu-4ed09fd35085c96ae8edbda87757187f75eeac8d.tar.gz
external_qemu-4ed09fd35085c96ae8edbda87757187f75eeac8d.tar.bz2
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
Diffstat (limited to 'android/camera')
-rw-r--r--android/camera/camera-capture-linux.c678
-rwxr-xr-xandroid/camera/camera-capture-windows.c409
-rw-r--r--android/camera/camera-capture.h86
-rwxr-xr-xandroid/camera/camera-common.h53
-rwxr-xr-xandroid/camera/camera-format-converters.c126
-rwxr-xr-xandroid/camera/camera-format-converters.h51
-rw-r--r--android/camera/camera-win.h64
7 files changed, 1467 insertions, 0 deletions
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 <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <linux/videodev2.h>
+#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 <stddef.h>
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <tchar.h>
+*/
+#include "qemu-common.h"
+#include "android/utils/debug.h"
+#include "android/utils/misc.h"
+#include "android/utils/system.h"
+#include <vfw.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
+
+/* 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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef _WIN32
+#include <linux/videodev2.h>
+#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_ */