praj wrote:
> Hi Harish,
>
> I'm trying out something similar. I'm able to see /dev/video0.
>
> Can you pass me a link to the V4L2 patch?
>
> Thanks in advance.
>
>
> On Sep 13, 1:55 pm, Harishkumar V <[email protected]> wrote:
>
>> Hi,
>> i am using logitech webcam
>>
>> Thanks and Regards,
>> HarishKumar.V
>>
>> On Wed, Sep 9, 2009 at 4:00 PM, deepak singal <[email protected]> wrote:
>>
>>> Hi Harish,
>>>
>>> Can you share your USB Webcam name and specification.
>>>
>>> Thanks & Regards
>>> Deepak
>>>
>> --
>> Thanks and Regards,
>> Harish Kumar. V
>>
>
> >
>
>
--~--~---------~--~----~------------~-------~--~----~
unsubscribe: [email protected]
website: http://groups.google.com/group/android-porting
-~----------~----~----~----~------~----~------~--~---
camera/libcameraservice/Android.mk | 34 +--
camera/libcameraservice/CameraHardware.cpp | 362 +++++++++++++++++++++++
camera/libcameraservice/CameraHardware.h | 136 +++++++++
camera/libcameraservice/CameraService.cpp | 3 +-
camera/libcameraservice/V4L2Camera.cpp | 430 ++++++++++++++++++++++++++++
camera/libcameraservice/V4L2Camera.h | 67 +++++
6 files changed, 1010 insertions(+), 22 deletions(-)
create mode 100644 camera/libcameraservice/CameraHardware.cpp
create mode 100644 camera/libcameraservice/CameraHardware.h
create mode 100644 camera/libcameraservice/V4L2Camera.cpp
create mode 100644 camera/libcameraservice/V4L2Camera.h
diff --git a/camera/libcameraservice/Android.mk b/camera/libcameraservice/Android.mk
index 96cc512..03b9ff6 100644
--- a/camera/libcameraservice/Android.mk
+++ b/camera/libcameraservice/Android.mk
@@ -1,34 +1,26 @@
LOCAL_PATH:= $(call my-dir)
#
-# Set USE_CAMERA_STUB for non-emulator and non-simulator builds, if you want
-# the camera service to use the fake camera. For emulator or simulator builds,
-# we always use the fake camera.
-
-ifeq ($(USE_CAMERA_STUB),)
-USE_CAMERA_STUB:=false
-ifneq ($(filter sooner generic sim,$(TARGET_DEVICE)),)
-USE_CAMERA_STUB:=true
-endif #libcamerastub
-endif
-
-ifeq ($(USE_CAMERA_STUB),true)
-#
-# libcamerastub
+# libcamera
#
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- CameraHardwareStub.cpp \
- FakeCamera.cpp
+ CameraHardware.cpp \
+ V4L2Camera.cpp
+
+LOCAL_MODULE:= libcamera
-LOCAL_MODULE:= libcamerastub
+LOCAL_SHARED_LIBRARIES:= \
+ libui \
+ libutils \
+ libcutils
-LOCAL_SHARED_LIBRARIES:= libui
+LOCAL_STATIC_LIBRARIES:= \
+ libjpeg
-include $(BUILD_STATIC_LIBRARY)
-endif # USE_CAMERA_STUB
+include $(BUILD_SHARED_LIBRARY)
#
# libcameraservice
@@ -43,7 +35,7 @@ LOCAL_SHARED_LIBRARIES:= \
libui \
libutils \
libcutils \
- libmedia
+ libmedia
LOCAL_MODULE:= libcameraservice
diff --git a/camera/libcameraservice/CameraHardware.cpp b/camera/libcameraservice/CameraHardware.cpp
new file mode 100644
index 0000000..ac76514
--- /dev/null
+++ b/camera/libcameraservice/CameraHardware.cpp
@@ -0,0 +1,362 @@
+/*
+**
+** Copyright 2008, 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.
+*/
+
+#define LOG_TAG "CameraHardware"
+#include <utils/Log.h>
+
+#include "CameraHardware.h"
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#define VIDEO_DEVICE "/dev/video0"
+#define MIN_WIDTH 640
+
+#define MIN_HEIGHT 480
+#define PIXEL_FORMAT V4L2_PIX_FMT_YUYV
+
+namespace android {
+
+wp<CameraHardwareInterface> CameraHardware::singleton;
+
+CameraHardware::CameraHardware()
+ : mParameters(),
+ mHeap(0),
+ mPreviewHeap(0),
+ mRawHeap(0),
+ mPreviewFrameSize(0),
+ mRawPictureCallback(0),
+ mJpegPictureCallback(0),
+ mPictureCallbackCookie(0),
+ mPreviewCallback(0),
+ mPreviewCallbackCookie(0),
+ mAutoFocusCallback(0),
+ mAutoFocusCallbackCookie(0),
+ mCurrentPreviewFrame(0),
+ previewStopped(true),
+ nQueued(0),
+ nDequeued(0)
+{
+ initDefaultParameters();
+}
+
+void CameraHardware::initDefaultParameters()
+{
+ CameraParameters p;
+
+ p.setPreviewSize(MIN_WIDTH, MIN_HEIGHT);
+ p.setPreviewFrameRate(15);
+ p.setPreviewFormat("yuv422sp");
+
+ p.setPictureSize(MIN_WIDTH, MIN_HEIGHT);
+ p.setPictureFormat("jpeg");
+
+ if (setParameters(p) != NO_ERROR) {
+ LOGE("Failed to set default parameters?!");
+ }
+}
+
+CameraHardware::~CameraHardware()
+{
+ singleton.clear();
+}
+
+sp<IMemoryHeap> CameraHardware::getPreviewHeap() const
+{
+ return mHeap;
+}
+
+sp<IMemoryHeap> CameraHardware::getRawHeap() const
+{
+ return mRawHeap;
+}
+
+// ---------------------------------------------------------------------------
+
+int CameraHardware::previewThread()
+{
+ if (!previewStopped) {
+ // Get preview frame
+ camera.GrabPreviewFrame(mHeap->getBase());
+ mPreviewCallback(mBuffer, mPreviewCallbackCookie);
+ }
+
+ return NO_ERROR;
+}
+
+status_t CameraHardware::startPreview(preview_callback cb, void* user)
+{
+ int width, height;
+
+ Mutex::Autolock lock(mLock);
+ if (mPreviewThread != 0) {
+ //already running
+ return INVALID_OPERATION;
+ }
+
+ camera.Open(VIDEO_DEVICE, MIN_WIDTH, MIN_HEIGHT, PIXEL_FORMAT);
+
+ mPreviewFrameSize = MIN_WIDTH * MIN_HEIGHT * 2;
+
+ mHeap = new MemoryHeapBase(mPreviewFrameSize);
+ mBuffer = new MemoryBase(mHeap, 0, mPreviewFrameSize);
+
+ camera.Init();
+ camera.StartStreaming();
+
+ previewStopped = false;
+
+ mPreviewCallback = cb;
+ mPreviewCallbackCookie = user;
+ mPreviewThread = new PreviewThread(this);
+
+ return NO_ERROR;
+}
+
+void CameraHardware::stopPreview()
+{
+ sp<PreviewThread> previewThread;
+
+ { // scope for the lock
+ Mutex::Autolock lock(mLock);
+ previewStopped = true;
+ }
+
+ if (mPreviewThread != 0) {
+ camera.Uninit();
+ camera.StopStreaming();
+ camera.Close();
+ }
+
+ {
+ Mutex::Autolock lock(mLock);
+ previewThread = mPreviewThread;
+ }
+
+ if (previewThread != 0) {
+ previewThread->requestExitAndWait();
+ }
+
+ Mutex::Autolock lock(mLock);
+ mPreviewThread.clear();
+}
+
+bool CameraHardware::previewEnabled()
+{
+ return mPreviewThread != 0;
+}
+
+status_t CameraHardware::startRecording(recording_callback cb, void* user)
+{
+ return UNKNOWN_ERROR;
+}
+
+void CameraHardware::stopRecording()
+{
+}
+
+bool CameraHardware::recordingEnabled()
+{
+ return false;
+}
+
+void CameraHardware::releaseRecordingFrame(const sp<IMemory>& mem)
+{
+}
+
+// ---------------------------------------------------------------------------
+
+int CameraHardware::beginAutoFocusThread(void *cookie)
+{
+ CameraHardware *c = (CameraHardware *)cookie;
+ return c->autoFocusThread();
+}
+
+int CameraHardware::autoFocusThread()
+{
+ if (mAutoFocusCallback != NULL) {
+ mAutoFocusCallback(true, mAutoFocusCallbackCookie);
+ mAutoFocusCallback = NULL;
+ return NO_ERROR;
+ }
+ return UNKNOWN_ERROR;
+}
+
+status_t CameraHardware::autoFocus(autofocus_callback af_cb,
+ void *user)
+{
+ Mutex::Autolock lock(mLock);
+
+ if (mAutoFocusCallback != NULL) {
+ return mAutoFocusCallback == af_cb ? NO_ERROR : INVALID_OPERATION;
+ }
+
+ mAutoFocusCallback = af_cb;
+ mAutoFocusCallbackCookie = user;
+ if (createThread(beginAutoFocusThread, this) == false)
+ return UNKNOWN_ERROR;
+ return NO_ERROR;
+}
+
+/*static*/ int CameraHardware::beginPictureThread(void *cookie)
+{
+ CameraHardware *c = (CameraHardware *)cookie;
+ return c->pictureThread();
+}
+
+int CameraHardware::pictureThread()
+{
+ unsigned char *frame;
+ int bufferSize;
+ int w,h;
+ int ret;
+ struct v4l2_buffer buffer;
+ struct v4l2_format format;
+ struct v4l2_buffer cfilledbuffer;
+ struct v4l2_requestbuffers creqbuf;
+ struct v4l2_capability cap;
+
+ if (mShutterCallback)
+ mShutterCallback(mPictureCallbackCookie);
+
+ mParameters.getPictureSize(&w, &h);
+ LOGD("Picture Size: Width = %d \t Height = %d", w, h);
+
+ int width, height;
+ mParameters.getPictureSize(&width, &height);
+ camera.Open(VIDEO_DEVICE, MIN_WIDTH, MIN_HEIGHT, PIXEL_FORMAT);
+ camera.Init();
+ camera.StartStreaming();
+
+ if (mRawPictureCallback) {
+ LOGD("mRawPictureCallback");
+
+// mRawPictureCallback(camera.GrabRawFrame(), mPictureCallbackCookie);
+ }
+
+ if (mJpegPictureCallback) {
+ LOGD ("mJpegPictureCallback");
+
+ mJpegPictureCallback(camera.GrabJpegFrame(), mPictureCallbackCookie);
+ }
+
+ camera.Uninit();
+ camera.StopStreaming();
+ camera.Close();
+
+ return NO_ERROR;
+}
+
+status_t CameraHardware::takePicture(shutter_callback shutter_cb,
+ raw_callback raw_cb,
+ jpeg_callback jpeg_cb,
+ void* user)
+{
+ stopPreview();
+ mShutterCallback = shutter_cb;
+ mRawPictureCallback = raw_cb;
+ mJpegPictureCallback = jpeg_cb;
+ mPictureCallbackCookie = user;
+ //if (createThread(beginPictureThread, this) == false)
+ // return -1;
+
+ pictureThread();
+
+ return NO_ERROR;
+}
+
+status_t CameraHardware::cancelPicture(bool cancel_shutter,
+ bool cancel_raw,
+ bool cancel_jpeg)
+{
+ if (cancel_shutter) mShutterCallback = NULL;
+ if (cancel_raw) mRawPictureCallback = NULL;
+ if (cancel_jpeg) mJpegPictureCallback = NULL;
+
+ return NO_ERROR;
+}
+
+status_t CameraHardware::dump(int fd, const Vector<String16>& args) const
+{
+ return NO_ERROR;
+}
+
+status_t CameraHardware::setParameters(const CameraParameters& params)
+{
+ Mutex::Autolock lock(mLock);
+
+ if (strcmp(params.getPreviewFormat(), "yuv422sp") != 0) {
+ LOGE("Only yuv422sp preview is supported");
+ return -1;
+ }
+
+ if (strcmp(params.getPictureFormat(), "jpeg") != 0) {
+ LOGE("Only jpeg still pictures are supported");
+ return -1;
+ }
+
+ int w, h;
+ int framerate;
+
+ params.getPreviewSize(&w, &h);
+ framerate = params.getPreviewFrameRate();
+ LOGD("PREVIEW SIZE: w=%d h=%d framerate=%d", w, h, framerate);
+
+ params.getPictureSize(&w, &h);
+
+ mParameters = params;
+
+ // Set to fixed sizes
+ mParameters.setPreviewSize(MIN_WIDTH,MIN_HEIGHT);
+
+ return NO_ERROR;
+}
+
+CameraParameters CameraHardware::getParameters() const
+{
+ CameraParameters params;
+
+ {
+ Mutex::Autolock lock(mLock);
+ params = mParameters;
+ }
+
+ return params;
+}
+
+void CameraHardware::release()
+{
+ close(camera_device);
+}
+
+sp<CameraHardwareInterface> CameraHardware::createInstance()
+{
+ if (singleton != 0) {
+ sp<CameraHardwareInterface> hardware = singleton.promote();
+ if (hardware != 0) {
+ return hardware;
+ }
+ }
+ sp<CameraHardwareInterface> hardware(new CameraHardware());
+ singleton = hardware;
+ return hardware;
+}
+
+extern "C" sp<CameraHardwareInterface> openCameraHardware()
+{
+ return CameraHardware::createInstance();
+}
+}; // namespace android
diff --git a/camera/libcameraservice/CameraHardware.h b/camera/libcameraservice/CameraHardware.h
new file mode 100644
index 0000000..8cd9b5c
--- /dev/null
+++ b/camera/libcameraservice/CameraHardware.h
@@ -0,0 +1,136 @@
+/*
+**
+** Copyright 2008, 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_HARDWARE_CAMERA_HARDWARE_H
+#define ANDROID_HARDWARE_CAMERA_HARDWARE_H
+
+#include <utils/threads.h>
+#include <ui/CameraHardwareInterface.h>
+#include <utils/MemoryBase.h>
+#include <utils/MemoryHeapBase.h>
+#include <utils/threads.h>
+
+#include <sys/ioctl.h>
+#include <jpeglib.h>
+#include "V4L2Camera.h"
+
+namespace android {
+
+class CameraHardware : public CameraHardwareInterface {
+public:
+ virtual sp<IMemoryHeap> getPreviewHeap() const;
+ virtual sp<IMemoryHeap> getRawHeap() const;
+
+ virtual status_t startPreview(preview_callback cb, void* user);
+ virtual void stopPreview();
+ virtual bool previewEnabled();
+
+ virtual status_t startRecording(recording_callback cb, void* user);
+ virtual void stopRecording();
+ virtual bool recordingEnabled();
+ virtual void releaseRecordingFrame(const sp<IMemory>& mem);
+
+ virtual status_t autoFocus(autofocus_callback, void *user);
+ virtual status_t takePicture(shutter_callback,
+ raw_callback,
+ jpeg_callback,
+ void* user);
+ virtual status_t cancelPicture(bool cancel_shutter,
+ bool cancel_raw,
+ bool cancel_jpeg);
+ virtual status_t dump(int fd, const Vector<String16>& args) const;
+ virtual status_t setParameters(const CameraParameters& params);
+ virtual CameraParameters getParameters() const;
+ virtual void release();
+
+ static sp<CameraHardwareInterface> createInstance();
+
+private:
+ CameraHardware();
+ virtual ~CameraHardware();
+
+ static wp<CameraHardwareInterface> singleton;
+
+ static const int kBufferCount = 4;
+
+ class PreviewThread : public Thread {
+ CameraHardware* mHardware;
+ public:
+ PreviewThread(CameraHardware* hw)
+ : Thread(false), mHardware(hw) { }
+ virtual void onFirstRef() {
+ run("CameraPreviewThread", PRIORITY_URGENT_DISPLAY);
+ }
+ virtual bool threadLoop() {
+ mHardware->previewThread();
+ // loop until we need to quit
+ return true;
+ }
+ };
+
+ void initDefaultParameters();
+ bool initHeapLocked();
+
+ int previewThread();
+
+ static int beginAutoFocusThread(void *cookie);
+ int autoFocusThread();
+
+ static int beginPictureThread(void *cookie);
+ int pictureThread();
+
+ mutable Mutex mLock;
+
+ CameraParameters mParameters;
+
+ sp<MemoryHeapBase> mHeap;
+ sp<MemoryBase> mBuffer;
+
+ sp<MemoryHeapBase> mPreviewHeap;
+ sp<MemoryHeapBase> mRawHeap;
+
+ bool mPreviewRunning;
+ int mPreviewFrameSize;
+
+ shutter_callback mShutterCallback;
+ raw_callback mRawPictureCallback;
+ jpeg_callback mJpegPictureCallback;
+ void *mPictureCallbackCookie;
+
+ // protected by mLock
+ sp<PreviewThread> mPreviewThread;
+ preview_callback mPreviewCallback;
+ void *mPreviewCallbackCookie;
+
+ autofocus_callback mAutoFocusCallback;
+ void *mAutoFocusCallbackCookie;
+
+ // only used from PreviewThread
+ int mCurrentPreviewFrame;
+
+ void * framebuffer;
+ bool previewStopped;
+ int camera_device;
+ void* mem[4];
+ int nQueued;
+ int nDequeued;
+ V4L2Camera camera;
+};
+
+}; // namespace android
+
+#endif
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
index cb8ab58..7f7d4b7 100644
--- a/camera/libcameraservice/CameraService.cpp
+++ b/camera/libcameraservice/CameraService.cpp
@@ -479,7 +479,8 @@ status_t CameraService::Client::startPreviewMode()
transform = ISurface::BufferHeap::ROT_90;
}
ISurface::BufferHeap buffers(w, h, w, h,
- PIXEL_FORMAT_YCbCr_420_SP,
+ //PIXEL_FORMAT_YCbCr_420_SP,
+ PIXEL_FORMAT_RGB_565,
transform,
0,
mHardware->getPreviewHeap());
diff --git a/camera/libcameraservice/V4L2Camera.cpp b/camera/libcameraservice/V4L2Camera.cpp
new file mode 100644
index 0000000..87f950d
--- /dev/null
+++ b/camera/libcameraservice/V4L2Camera.cpp
@@ -0,0 +1,430 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#define LOG_TAG "V4L2Camera"
+#include <utils/Log.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/select.h>
+
+#include <linux/videodev.h>
+
+#include <jpeglib.h>
+
+#include "V4L2Camera.h"
+
+namespace android {
+
+V4L2Camera::V4L2Camera ()
+ : nQueued(0), nDequeued(0)
+{
+ videoIn = (struct vdIn *) calloc (1, sizeof (struct vdIn));
+}
+
+V4L2Camera::~V4L2Camera()
+{
+ free(videoIn);
+}
+
+int V4L2Camera::Open (const char *device, int width, int height, int pixelformat)
+{
+ int ret;
+
+ if ((fd = open(device, O_RDWR)) == -1) {
+ LOGE("ERROR opening V4L interface: %s", strerror(errno));
+ return -1;
+ }
+
+ ret = ioctl (fd, VIDIOC_QUERYCAP, &videoIn->cap);
+ if (ret < 0) {
+ LOGE("Error opening device: unable to query device.");
+ return -1;
+ }
+
+ if ((videoIn->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) {
+ LOGE("Error opening device: video capture not supported.");
+ return -1;
+ }
+
+ if (!(videoIn->cap.capabilities & V4L2_CAP_STREAMING)) {
+ LOGE("Capture device does not support streaming i/o");
+ return -1;
+ }
+
+ videoIn->width = width;
+ videoIn->height = height;
+ videoIn->framesizeIn = (width * height << 1);
+ videoIn->formatIn = pixelformat;
+
+ videoIn->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ videoIn->format.fmt.pix.width = width;
+ videoIn->format.fmt.pix.height = height;
+ videoIn->format.fmt.pix.pixelformat = pixelformat;
+
+ ret = ioctl(fd, VIDIOC_S_FMT, &videoIn->format);
+ if (ret < 0) {
+ LOGE("Open: VIDIOC_S_FMT Failed: %s", strerror(errno));
+ return ret;
+ }
+
+ return 0;
+}
+
+void V4L2Camera::Close ()
+{
+ close(fd);
+}
+
+int V4L2Camera::Init()
+{
+ int ret;
+
+ /* Check if camera can handle NB_BUFFER buffers */
+ videoIn->rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ videoIn->rb.memory = V4L2_MEMORY_MMAP;
+ videoIn->rb.count = NB_BUFFER;
+
+ ret = ioctl(fd, VIDIOC_REQBUFS, &videoIn->rb);
+ if (ret < 0) {
+ LOGE("Init: VIDIOC_REQBUFS failed: %s", strerror(errno));
+ return ret;
+ }
+
+ for (int i = 0; i < NB_BUFFER; i++) {
+
+ memset (&videoIn->buf, 0, sizeof (struct v4l2_buffer));
+
+ videoIn->buf.index = i;
+ videoIn->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ videoIn->buf.memory = V4L2_MEMORY_MMAP;
+
+ ret = ioctl (fd, VIDIOC_QUERYBUF, &videoIn->buf);
+ if (ret < 0) {
+ LOGE("Init: Unable to query buffer (%s)", strerror(errno));
+ return ret;
+ }
+
+ videoIn->mem[i] = mmap (0,
+ videoIn->buf.length,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ fd,
+ videoIn->buf.m.offset);
+
+ if (videoIn->mem[i] == MAP_FAILED) {
+ LOGE("Init: Unable to map buffer (%s)", strerror(errno));
+ return -1;
+ }
+
+ ret = ioctl(fd, VIDIOC_QBUF, &videoIn->buf);
+ if (ret < 0) {
+ LOGE("Init: VIDIOC_QBUF Failed");
+ return -1;
+ }
+
+ nQueued++;
+ }
+
+ return 0;
+}
+
+void V4L2Camera::Uninit ()
+{
+ int ret;
+
+ videoIn->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ videoIn->buf.memory = V4L2_MEMORY_MMAP;
+
+ /* Dequeue everything */
+ int DQcount = nQueued - nDequeued;
+
+ for (int i = 0; i < DQcount-1; i++) {
+ ret = ioctl(fd, VIDIOC_DQBUF, &videoIn->buf);
+ if (ret < 0)
+ LOGE("Uninit: VIDIOC_DQBUF Failed");
+ }
+ nQueued = 0;
+ nDequeued = 0;
+
+ /* Unmap buffers */
+ for (int i = 0; i < NB_BUFFER; i++)
+ if (munmap(videoIn->mem[i], videoIn->buf.length) < 0)
+ LOGE("Uninit: Unmap failed");
+}
+
+int V4L2Camera::StartStreaming ()
+{
+ enum v4l2_buf_type type;
+ int ret;
+
+ if (!videoIn->isStreaming) {
+ type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ ret = ioctl (fd, VIDIOC_STREAMON, &type);
+ if (ret < 0) {
+ LOGE("StartStreaming: Unable to start capture: %s", strerror(errno));
+ return ret;
+ }
+
+ videoIn->isStreaming = true;
+ }
+
+ return 0;
+}
+
+int V4L2Camera::StopStreaming ()
+{
+ enum v4l2_buf_type type;
+ int ret;
+
+ if (videoIn->isStreaming) {
+ type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ ret = ioctl (fd, VIDIOC_STREAMOFF, &type);
+ if (ret < 0) {
+ LOGE("StopStreaming: Unable to stop capture: %s", strerror(errno));
+ return ret;
+ }
+
+ videoIn->isStreaming = false;
+ }
+
+ return 0;
+}
+
+void V4L2Camera::GrabPreviewFrame (void *previewBuffer)
+{
+ unsigned char *tmpBuffer;
+ int ret;
+
+ tmpBuffer = (unsigned char *) calloc (1, videoIn->width * videoIn->height * 2);
+
+ videoIn->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ videoIn->buf.memory = V4L2_MEMORY_MMAP;
+
+ /* DQ */
+ ret = ioctl(fd, VIDIOC_DQBUF, &videoIn->buf);
+ if (ret < 0) {
+ //LOGE("GrabPreviewFrame: VIDIOC_DQBUF Failed");
+
+ return;
+ }
+ nDequeued++;
+
+ memcpy (tmpBuffer, videoIn->mem[videoIn->buf.index], (size_t) videoIn->buf.bytesused);
+
+ //convertYUYVtoYUV422SP((uint8_t *)tmpBuffer, (uint8_t *)previewBuffer, videoIn->width, videoIn->height);
+ convert((unsigned char *)tmpBuffer, (unsigned char *)previewBuffer, videoIn->width, videoIn->height);
+
+ ret = ioctl(fd, VIDIOC_QBUF, &videoIn->buf);
+ if (ret < 0) {
+ LOGE("GrabPreviewFrame: VIDIOC_QBUF Failed");
+ return;
+ }
+
+ nQueued++;
+
+ free(tmpBuffer);
+}
+
+sp<IMemory> V4L2Camera::GrabRawFrame ()
+{
+ sp<MemoryHeapBase> memHeap = new MemoryHeapBase(videoIn->width * videoIn->height * 2);
+ sp<MemoryBase> memBase = new MemoryBase(memHeap, 0, videoIn->width * videoIn->height * 2);
+
+ // Not yet implemented, do I have to?
+
+ return memBase;
+}
+
+sp<IMemory> V4L2Camera::GrabJpegFrame ()
+{
+ FILE *output;
+ FILE *input;
+ int fileSize;
+ int ret;
+
+ videoIn->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ videoIn->buf.memory = V4L2_MEMORY_MMAP;
+
+ /* Dequeue buffer */
+ ret = ioctl(fd, VIDIOC_DQBUF, &videoIn->buf);
+ if (ret < 0) {
+ LOGE("GrabJpegFrame: VIDIOC_DQBUF Failed");
+ return NULL;
+ }
+ nDequeued++;
+
+ LOGI("GrabJpegFrame: Generated a frame from capture device");
+
+ /* Enqueue buffer */
+ ret = ioctl(fd, VIDIOC_QBUF, &videoIn->buf);
+ if (ret < 0) {
+ LOGE("GrabJpegFrame: VIDIOC_QBUF Failed");
+ return NULL;
+ }
+ nQueued++;
+
+ output = fopen("/sdcard/tmp.jpg", "wb");
+
+ if (output == NULL) {
+ LOGE("GrabJpegFrame: Ouput file == NULL");
+ return NULL;
+ }
+
+ fileSize = saveYUYVtoJPEG((unsigned char *)videoIn->mem[videoIn->buf.index], videoIn->width, videoIn->height, output, 85);
+
+ fclose(output);
+
+ input = fopen("/sdcard/tmp.jpg", "rb");
+
+ if (input == NULL)
+ LOGE("GrabJpegFrame: Input file == NULL");
+ else {
+ sp<MemoryHeapBase> mjpegPictureHeap = new MemoryHeapBase(fileSize);
+ sp<MemoryBase> jpegmemBase = new MemoryBase(mjpegPictureHeap, 0, fileSize);
+
+ fread((uint8_t *)mjpegPictureHeap->base(), 1, fileSize, input);
+ fclose(input);
+
+ return jpegmemBase;
+ }
+
+ return NULL;
+}
+
+int V4L2Camera::saveYUYVtoJPEG (unsigned char *inputBuffer, int width, int height, FILE *file, int quality)
+{
+ struct jpeg_compress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ JSAMPROW row_pointer[1];
+ unsigned char *line_buffer, *yuyv;
+ int z;
+ int fileSize;
+
+ line_buffer = (unsigned char *) calloc (width * 3, 1);
+ yuyv = inputBuffer;
+
+ cinfo.err = jpeg_std_error (&jerr);
+ jpeg_create_compress (&cinfo);
+ jpeg_stdio_dest (&cinfo, file);
+
+ LOGI("JPEG PICTURE WIDTH AND HEIGHT: %dx%d", width, height);
+
+ cinfo.image_width = width;
+ cinfo.image_height = height;
+ cinfo.input_components = 3;
+ cinfo.in_color_space = JCS_RGB;
+
+ jpeg_set_defaults (&cinfo);
+ jpeg_set_quality (&cinfo, quality, TRUE);
+
+ jpeg_start_compress (&cinfo, TRUE);
+
+ z = 0;
+ while (cinfo.next_scanline < cinfo.image_height) {
+ int x;
+ unsigned char *ptr = line_buffer;
+
+ for (x = 0; x < width; x++) {
+ int r, g, b;
+ int y, u, v;
+
+ if (!z)
+ y = yuyv[0] << 8;
+ else
+ y = yuyv[2] << 8;
+
+ u = yuyv[1] - 128;
+ v = yuyv[3] - 128;
+
+ r = (y + (359 * v)) >> 8;
+ g = (y - (88 * u) - (183 * v)) >> 8;
+ b = (y + (454 * u)) >> 8;
+
+ *(ptr++) = (r > 255) ? 255 : ((r < 0) ? 0 : r);
+ *(ptr++) = (g > 255) ? 255 : ((g < 0) ? 0 : g);
+ *(ptr++) = (b > 255) ? 255 : ((b < 0) ? 0 : b);
+
+ if (z++) {
+ z = 0;
+ yuyv += 4;
+ }
+ }
+
+ row_pointer[0] = line_buffer;
+ jpeg_write_scanlines (&cinfo, row_pointer, 1);
+ }
+
+ jpeg_finish_compress (&cinfo);
+ fileSize = ftell(file);
+ jpeg_destroy_compress (&cinfo);
+
+ free (line_buffer);
+
+ return fileSize;
+}
+
+void V4L2Camera::convert(unsigned char *buf, unsigned char *rgb, int width, int height)
+{
+ int x,y,z=0;
+ int blocks;
+
+ blocks = (width * height) * 2;
+
+ for (y = 0; y < blocks; y+=4) {
+ unsigned char Y1, Y2, U, V;
+
+ Y1 = buf[y + 0];
+ U = buf[y + 1];
+ Y2 = buf[y + 2];
+ V = buf[y + 3];
+
+ yuv_to_rgb16(Y1, U, V, &rgb[y]);
+ yuv_to_rgb16(Y2, U, V, &rgb[y + 2]);
+ }
+
+}
+
+void V4L2Camera::yuv_to_rgb16(unsigned char y, unsigned char u, unsigned char v, unsigned char *rgb)
+{
+ int r,g,b;
+ int z;
+ int rgb16;
+
+ z = 0;
+
+ r = 1.164 * (y - 16) + 1.596 * (v - 128);
+ g = 1.164 * (y - 16) - 0.813 * (v - 128) - 0.391 * (u -128);
+ b = 1.164 * (y - 16) + 2.018 * (u - 128);
+
+ if (r > 255) r = 255;
+ if (g > 255) g = 255;
+ if (b > 255) b = 255;
+
+ if (r < 0) r = 0;
+ if (g < 0) g = 0;
+ if (b < 0) b = 0;
+
+ rgb16 = (int)(((r >> 3)<<11) | ((g >> 2) << 5)| ((b >> 3) << 0));
+
+ *rgb = (unsigned char)(rgb16 & 0xFF);
+ rgb++;
+ *rgb = (unsigned char)((rgb16 & 0xFF00) >> 8);
+
+}
+
+
+}; // namespace android
diff --git a/camera/libcameraservice/V4L2Camera.h b/camera/libcameraservice/V4L2Camera.h
new file mode 100644
index 0000000..56eea30
--- /dev/null
+++ b/camera/libcameraservice/V4L2Camera.h
@@ -0,0 +1,67 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#ifndef _V4L2CAMERA_H
+#define _V4L2CAMERA_H
+
+#define NB_BUFFER 4
+
+#include <utils/MemoryBase.h>
+#include <utils/MemoryHeapBase.h>
+#include <linux/videodev.h>
+
+namespace android {
+
+struct vdIn {
+ struct v4l2_capability cap;
+ struct v4l2_format format;
+ struct v4l2_buffer buf;
+ struct v4l2_requestbuffers rb;
+ void *mem[NB_BUFFER];
+ bool isStreaming;
+ int width;
+ int height;
+ int formatIn;
+ int framesizeIn;
+};
+
+class V4L2Camera {
+
+public:
+ V4L2Camera();
+ ~V4L2Camera();
+
+ int Open (const char *device, int width, int height, int pixelformat);
+ void Close ();
+
+ int Init ();
+ void Uninit ();
+
+ int StartStreaming ();
+ int StopStreaming ();
+
+ void GrabPreviewFrame (void *previewBuffer);
+ sp<IMemory> GrabRawFrame ();
+ sp<IMemory> GrabJpegFrame ();
+
+private:
+ struct vdIn *videoIn;
+ int fd;
+
+ int nQueued;
+ int nDequeued;
+
+ int saveYUYVtoJPEG (unsigned char *inputBuffer, int width, int height, FILE *file, int quality);
+
+ void convert(unsigned char *buf, unsigned char *rgb, int width, int height);
+ void yuv_to_rgb16(unsigned char y, unsigned char u, unsigned char v, unsigned char *rgb);
+};
+
+}; // namespace android
+
+#endif
--
1.5.6.3