From c504d07048be857d485b757ceaa1a1219597a495 Mon Sep 17 00:00:00 2001 From: Chih-Wei Huang Date: Wed, 30 Jun 2010 18:56:01 +0800 Subject: [PATCH] merge the v4l2 camera works from android-m912 project by Niels Keeman --- camera/libcameraservice/Android.mk | 27 +- camera/libcameraservice/CameraHardware.cpp | 373 +++++++++++++++++++++++++ camera/libcameraservice/CameraHardware.h | 152 ++++++++++ camera/libcameraservice/CameraService.cpp | 2 +- camera/libcameraservice/V4L2Camera.cpp | 434 +++++++++++++++++++++++++++++ camera/libcameraservice/V4L2Camera.h | 69 +++++ 6 files changed, 1053 insertions(+), 4 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 df5c166b2794..7fc4b54fb95e 100644 --- a/camera/libcameraservice/Android.mk +++ b/camera/libcameraservice/Android.mk @@ -12,13 +12,13 @@ USE_CAMERA_STUB:=true endif #libcamerastub endif +include $(CLEAR_VARS) + ifeq ($(USE_CAMERA_STUB),true) # # libcamerastub # -include $(CLEAR_VARS) - LOCAL_SRC_FILES:= \ CameraHardwareStub.cpp \ FakeCamera.cpp @@ -32,6 +32,27 @@ endif LOCAL_SHARED_LIBRARIES:= libui include $(BUILD_STATIC_LIBRARY) + +else + +LOCAL_SRC_FILES:= \ + CameraHardware.cpp \ + V4L2Camera.cpp + +LOCAL_CFLAGS += -Iexternal/jpeg + +LOCAL_MODULE:= libcamera + +LOCAL_SHARED_LIBRARIES:= \ + libui \ + libjpeg \ + libutils \ + libbinder \ + libcutils \ + libcamera_client + +include $(BUILD_SHARED_LIBRARY) + endif # USE_CAMERA_STUB # @@ -60,7 +81,7 @@ ifeq ($(TARGET_SIMULATOR),true) LOCAL_CFLAGS += -DSINGLE_PROCESS endif -ifeq ($(USE_CAMERA_STUB), true) +ifeq ($(USE_CAMERA_STUB),true) LOCAL_STATIC_LIBRARIES += libcamerastub LOCAL_CFLAGS += -include CameraHardwareStub.h else diff --git a/camera/libcameraservice/CameraHardware.cpp b/camera/libcameraservice/CameraHardware.cpp new file mode 100644 index 000000000000..258c8a3c984b --- /dev/null +++ b/camera/libcameraservice/CameraHardware.cpp @@ -0,0 +1,373 @@ +/* +** +** Copyright 2009, The Android-x86 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. +** +** Author: Niels Keeman +** +*/ + +#define LOG_TAG "CameraHardware" +#include + +#include "CameraHardware.h" +#include +#include + +#define VIDEO_DEVICE "/dev/video0" +#define MIN_WIDTH 640 + +#define MIN_HEIGHT 480 +#define PIXEL_FORMAT V4L2_PIX_FMT_YUYV + +namespace android { + +wp CameraHardware::singleton; + +CameraHardware::CameraHardware() + : mParameters(), + mHeap(0), + mPreviewHeap(0), + mRawHeap(0), + mPreviewFrameSize(0), + mCurrentPreviewFrame(0), + previewStopped(true), + nQueued(0), + nDequeued(0), + mNotifyFn(NULL), + mDataFn(NULL), + mTimestampFn(NULL), + mUser(NULL) +{ + 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 CameraHardware::getPreviewHeap() const +{ + return mHeap; +} + +sp CameraHardware::getRawHeap() const +{ + return mRawHeap; +} + +// --------------------------------------------------------------------------- + +void CameraHardware::setCallbacks(notify_callback notify_cb, + data_callback data_cb, + data_callback_timestamp data_cb_timestamp, + void *arg) { + Mutex::Autolock lock(mLock); + mNotifyFn = notify_cb; + mDataFn = data_cb; + mTimestampFn = data_cb_timestamp; + mUser = arg; +} + +void CameraHardware::enableMsgType(int32_t msgType) +{ + Mutex::Autolock lock(mLock); + mMsgEnabled |= msgType; +} + +void CameraHardware::disableMsgType(int32_t msgType) +{ + Mutex::Autolock lock(mLock); + mMsgEnabled &= ~msgType; +} + +bool CameraHardware::msgTypeEnabled(int32_t msgType) +{ + Mutex::Autolock lock(mLock); + return (mMsgEnabled & msgType); +} + + +//------------------------------------------------------------- +int CameraHardware::previewThread() +{ + if (!previewStopped) { + // Get preview frame + camera.GrabPreviewFrame(mHeap->getBase()); + if (mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME) + mDataFn(CAMERA_MSG_PREVIEW_FRAME,mBuffer, mUser); + } + + return NO_ERROR; +} + +status_t CameraHardware::startPreview() +{ + 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; + mPreviewThread = new PreviewThread(this); + + return NO_ERROR; +} + +void CameraHardware::stopPreview() +{ + sp 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() +{ + return UNKNOWN_ERROR; +} + +void CameraHardware::stopRecording() +{ +} + +bool CameraHardware::recordingEnabled() +{ + return false; +} + +void CameraHardware::releaseRecordingFrame(const sp& mem) +{ +} + +// --------------------------------------------------------------------------- + +int CameraHardware::beginAutoFocusThread(void *cookie) +{ + CameraHardware *c = (CameraHardware *)cookie; + return c->autoFocusThread(); +} + +int CameraHardware::autoFocusThread() +{ + if (mMsgEnabled & CAMERA_MSG_FOCUS) + mNotifyFn(CAMERA_MSG_FOCUS, true, 0, mUser); + return NO_ERROR; +} + +status_t CameraHardware::autoFocus() +{ + Mutex::Autolock lock(mLock); + if (createThread(beginAutoFocusThread, this) == false) + return UNKNOWN_ERROR; + return NO_ERROR; +} + +status_t CameraHardware::cancelAutoFocus() +{ + 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 (mMsgEnabled & CAMERA_MSG_SHUTTER) + mNotifyFn(CAMERA_MSG_SHUTTER, 0, 0, mUser); + + 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 (mMsgEnabled & CAMERA_MSG_COMPRESSED_IMAGE) { + LOGD ("mJpegPictureCallback"); + mDataFn(CAMERA_MSG_COMPRESSED_IMAGE, camera.GrabJpegFrame(),mUser); + } + + camera.Uninit(); + camera.StopStreaming(); + camera.Close(); + + return NO_ERROR; +} + +status_t CameraHardware::takePicture() +{ + stopPreview(); + //if (createThread(beginPictureThread, this) == false) + // return -1; + + pictureThread(); + + return NO_ERROR; +} + +status_t CameraHardware::cancelPicture() +{ + + return NO_ERROR; +} + +status_t CameraHardware::dump(int fd, const Vector& 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; +} + +status_t CameraHardware::sendCommand(int32_t command, int32_t arg1, + int32_t arg2) +{ + return BAD_VALUE; +} + +CameraParameters CameraHardware::getParameters() const +{ + CameraParameters params; + + { + Mutex::Autolock lock(mLock); + params = mParameters; + } + + return params; +} + +void CameraHardware::release() +{ + close(camera_device); +} + +sp CameraHardware::createInstance() +{ + if (singleton != 0) { + sp hardware = singleton.promote(); + if (hardware != 0) { + return hardware; + } + } + sp hardware(new CameraHardware()); + singleton = hardware; + return hardware; +} + +extern "C" sp openCameraHardware() +{ + return CameraHardware::createInstance(); +} +}; // namespace android diff --git a/camera/libcameraservice/CameraHardware.h b/camera/libcameraservice/CameraHardware.h new file mode 100644 index 000000000000..7f05255bea0b --- /dev/null +++ b/camera/libcameraservice/CameraHardware.h @@ -0,0 +1,152 @@ +/* +** +** Copyright 2009, The Android-x86 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. +** +** Author: Niels Keeman +** +*/ + +#ifndef ANDROID_HARDWARE_CAMERA_HARDWARE_H +#define ANDROID_HARDWARE_CAMERA_HARDWARE_H + +#include +#include +#include +#include +#include + +#include +#include "V4L2Camera.h" + +namespace android { + +class CameraHardware : public CameraHardwareInterface { +public: + virtual sp getPreviewHeap() const; + virtual sp getRawHeap() const; + + virtual status_t startPreview(); + virtual void setCallbacks(notify_callback notify_cb, + data_callback data_cb, + data_callback_timestamp data_cb_timestamp, + void* arg); + /** + * Enable a message, or set of messages. + */ + virtual void enableMsgType(int32_t msgType); + + /** + * Disable a message, or a set of messages. + */ + virtual void disableMsgType(int32_t msgType); + + /** + * Query whether a message, or a set of messages, is enabled. + * Note that this is operates as an AND, if any of the messages + * queried are off, this will return false. + */ + virtual bool msgTypeEnabled(int32_t msgType); + + virtual void stopPreview(); + virtual bool previewEnabled(); + + virtual status_t startRecording(); + virtual void stopRecording(); + virtual bool recordingEnabled(); + virtual void releaseRecordingFrame(const sp& mem); + + virtual status_t autoFocus(); + virtual status_t cancelAutoFocus(); + virtual status_t takePicture(); + virtual status_t cancelPicture(); + virtual status_t dump(int fd, const Vector& args) const; + virtual status_t setParameters(const CameraParameters& params); + virtual CameraParameters getParameters() const; + virtual void release(); + virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2); + + static sp createInstance(); + +private: + CameraHardware(); + virtual ~CameraHardware(); + + static wp 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 mHeap; + sp mBuffer; + + sp mPreviewHeap; + sp mRawHeap; + + bool mPreviewRunning; + int mPreviewFrameSize; + + // protected by mLock + sp mPreviewThread; + + // only used from PreviewThread + int mCurrentPreviewFrame; + + void * framebuffer; + bool previewStopped; + int camera_device; + void* mem[4]; + int nQueued; + int nDequeued; + V4L2Camera camera; + notify_callback mNotifyFn; + data_callback mDataFn; + data_callback_timestamp mTimestampFn; + void* mUser; + int32_t mMsgEnabled; + +}; + +}; // namespace android + +#endif diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp index 118249e02fa2..80435d7bae50 100644 --- a/camera/libcameraservice/CameraService.cpp +++ b/camera/libcameraservice/CameraService.cpp @@ -608,7 +608,7 @@ status_t CameraService::Client::registerPreviewBuffers() // don't use a hardcoded format here ISurface::BufferHeap buffers(w, h, w, h, - HAL_PIXEL_FORMAT_YCrCb_420_SP, + PIXEL_FORMAT_RGB_565, mOrientation, 0, mHardware->getPreviewHeap()); diff --git a/camera/libcameraservice/V4L2Camera.cpp b/camera/libcameraservice/V4L2Camera.cpp new file mode 100644 index 000000000000..0fdc14693f64 --- /dev/null +++ b/camera/libcameraservice/V4L2Camera.cpp @@ -0,0 +1,434 @@ +/* + * 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. + * + * Author: Niels Keeman + * + */ + +#define LOG_TAG "V4L2Camera" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "V4L2Camera.h" + +extern "C" { /* Android jpeglib.h missed extern "C" */ +#include +} + +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 V4L2Camera::GrabRawFrame () +{ + sp memHeap = new MemoryHeapBase(videoIn->width * videoIn->height * 2); + sp memBase = new MemoryBase(memHeap, 0, videoIn->width * videoIn->height * 2); + + // Not yet implemented, do I have to? + + return memBase; +} + +sp V4L2Camera::GrabJpegFrame () +{ + FILE *output; + FILE *input; + size_t 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 mjpegPictureHeap = new MemoryHeapBase(fileSize); + sp 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 000000000000..97255ec10615 --- /dev/null +++ b/camera/libcameraservice/V4L2Camera.h @@ -0,0 +1,69 @@ +/* + * 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. + * + * Author: Niels Keeman + * + */ + +#ifndef _V4L2CAMERA_H +#define _V4L2CAMERA_H + +#define NB_BUFFER 4 + +#include +#include +#include + +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 GrabRawFrame (); + sp 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 -- 2.11.0