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 <harishpres...@gmail.com> wrote: > >> Hi, >> i am using logitech webcam >> >> Thanks and Regards, >> HarishKumar.V >> >> On Wed, Sep 9, 2009 at 4:00 PM, deepak singal <deesin...@gmail.com> wrote: >> >>> Hi Harish, >>> >>> Can you share your USB Webcam name and specification. >>> >>> Thanks & Regards >>> Deepak >>> >> -- >> Thanks and Regards, >> Harish Kumar. V >> > > > > >
--~--~---------~--~----~------------~-------~--~----~ unsubscribe: android-porting+unsubscr...@googlegroups.com 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