From 7c4b2c9465026d336c3f1c77f45a60176106a350 Mon Sep 17 00:00:00 2001 From: Vishal Bhoj Date: Wed, 12 Oct 2011 22:41:43 +0530 Subject: libcamera:Initial commit The library has been taken from android-x86 draft code from https://android-x86.googlegroups.com/attach/820408521e8c3e10/libcamera.tar.bz2?part=4 Signed-off-by: Vishal Bhoj --- libcamera/Android.mk | 28 +++ libcamera/CameraHardware.cpp | 432 ++++++++++++++++++++++++++++++++++++ libcamera/CameraHardware.h | 156 +++++++++++++ libcamera/CameraService.h | 226 +++++++++++++++++++ libcamera/V4L2Camera.cpp | 505 +++++++++++++++++++++++++++++++++++++++++++ libcamera/V4L2Camera.h | 70 ++++++ libcamera/converter.cpp | 261 ++++++++++++++++++++++ libcamera/converter.h | 25 +++ 8 files changed, 1703 insertions(+) create mode 100644 libcamera/Android.mk create mode 100644 libcamera/CameraHardware.cpp create mode 100644 libcamera/CameraHardware.h create mode 100644 libcamera/CameraService.h create mode 100644 libcamera/V4L2Camera.cpp create mode 100644 libcamera/V4L2Camera.h create mode 100644 libcamera/converter.cpp create mode 100644 libcamera/converter.h diff --git a/libcamera/Android.mk b/libcamera/Android.mk new file mode 100644 index 0000000..e2a82b9 --- /dev/null +++ b/libcamera/Android.mk @@ -0,0 +1,28 @@ +ifneq ($(USE_CAMERA_STUB),true) + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + CameraHardware.cpp \ + V4L2Camera.cpp \ + converter.cpp + +LOCAL_C_INCLUDES += external/jpeg + +LOCAL_MODULE := libcamera +LOCAL_MODULE_TAGS := optional +LOCAL_PRELINK_MODULE := false + +LOCAL_SHARED_LIBRARIES := \ + libui \ + libjpeg \ + libutils \ + libbinder \ + libcutils \ + libcamera_client + +include $(BUILD_SHARED_LIBRARY) + +endif diff --git a/libcamera/CameraHardware.cpp b/libcamera/CameraHardware.cpp new file mode 100644 index 0000000..bd7f079 --- /dev/null +++ b/libcamera/CameraHardware.cpp @@ -0,0 +1,432 @@ +/* +** +** 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 CAM_SIZE "640x480" +#define PIXEL_FORMAT V4L2_PIX_FMT_YUYV + +namespace android { + +wp CameraHardware::singleton; + +CameraHardware::CameraHardware(int cameraId) + : mCameraId(cameraId), + mParameters(), + mHeap(0), + mPreviewHeap(0), + mRecordHeap(0), + mRawHeap(0), + mPreviewFrameSize(0), + mCurrentPreviewFrame(0), + mRecordRunning(false), + previewStopped(true), + nQueued(0), + nDequeued(0), + mNotifyFn(NULL), + mDataFn(NULL), + mTimestampFn(NULL), + mUser(NULL), + mMsgEnabled(0) +{ + initDefaultParameters(); +} + +void CameraHardware::initDefaultParameters() +{ + CameraParameters p; + + p.setPreviewSize(MIN_WIDTH, MIN_HEIGHT); + p.setPreviewFrameRate(15); + p.setPreviewFormat("yuv422sp"); + p.set(p.KEY_SUPPORTED_PREVIEW_SIZES, CAM_SIZE); + + p.setPictureSize(MIN_WIDTH, MIN_HEIGHT); + p.setPictureFormat("jpeg"); + p.set(p.KEY_SUPPORTED_PICTURE_SIZES, CAM_SIZE); + + 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) || + (mMsgEnabled & CAMERA_MSG_VIDEO_FRAME)) { + if (mMsgEnabled & CAMERA_MSG_VIDEO_FRAME) { + camera.GrabRecordFrame(mRecordHeap->getBase()); + nsecs_t timeStamp = systemTime(SYSTEM_TIME_MONOTONIC); + mTimestampFn(timeStamp, CAMERA_MSG_VIDEO_FRAME,mRecordBuffer, mUser); + } + mDataFn(CAMERA_MSG_PREVIEW_FRAME,mBuffer, mUser); + } + } + + return NO_ERROR; +} + +status_t CameraHardware::startPreview() +{ + int ret; + int width, height; + + Mutex::Autolock lock(mLock); + if (mPreviewThread != 0) { + //already running + return INVALID_OPERATION; + } + + LOGI("startPreview: in startpreview \n"); + 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); + + ret = camera.Init(); + if (ret != 0) { + LOGI("startPreview: Camera.Init failed\n"); + camera.Close(); + return ret; + } + + ret = camera.StartStreaming(); + if (ret != 0) { + LOGI("startPreview: Camera.StartStreaming failed\n"); + camera.Uninit(); + camera.Close(); + return ret; + } + + 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() +{ + Mutex::Autolock lock(mLock); + + mRecordHeap = new MemoryHeapBase(mPreviewFrameSize); + mRecordBuffer = new MemoryBase(mRecordHeap, 0, mPreviewFrameSize); + mRecordRunning = true; + + return NO_ERROR; +} + +void CameraHardware::stopRecording() +{ + mRecordRunning = false; +} + +bool CameraHardware::recordingEnabled() +{ + return mRecordRunning; +} + +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() +{ + LOGD ("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(int cameraId) +{ + if (singleton != 0) { + sp hardware = singleton.promote(); + if (hardware != 0) { + return hardware; + } + } + sp hardware(new CameraHardware(cameraId)); + singleton = hardware; + return hardware; +} + +static CameraInfo sCameraInfo[] = { + { + facing: CAMERA_FACING_BACK, + orientation: 0 + }, +/* + { + facing: CAMERA_FACING_FRONT, + orientation: 0 + } +*/ +}; + +extern "C" int HAL_getNumberOfCameras() +{ + return sizeof(sCameraInfo) / sizeof(sCameraInfo[0]); +} + +extern "C" void HAL_getCameraInfo(int cameraId, struct CameraInfo* cameraInfo) +{ +LOGD("HAL_getCameraInfo: %d", cameraId); + memcpy(cameraInfo, &sCameraInfo[cameraId], sizeof(CameraInfo)); +} + +extern "C" sp HAL_openCameraHardware(int cameraId) +{ +LOGD("HAL_openCameraHardware: %d", cameraId); + return CameraHardware::createInstance(cameraId); +} + +}; // namespace android diff --git a/libcamera/CameraHardware.h b/libcamera/CameraHardware.h new file mode 100644 index 0000000..7491cce --- /dev/null +++ b/libcamera/CameraHardware.h @@ -0,0 +1,156 @@ +/* +** +** 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(int cameraId); + +private: + CameraHardware(int cameraId); + 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; + + int mCameraId; + CameraParameters mParameters; + + sp mHeap; + sp mBuffer; + + sp mPreviewHeap; + sp mRawHeap; + sp mRecordHeap; + sp mRecordBuffer; + + bool mPreviewRunning; + bool mRecordRunning; + 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/libcamera/CameraService.h b/libcamera/CameraService.h new file mode 100644 index 0000000..75e96c6 --- /dev/null +++ b/libcamera/CameraService.h @@ -0,0 +1,226 @@ +/* +** +** Copyright (C) 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_SERVERS_CAMERA_CAMERASERVICE_H +#define ANDROID_SERVERS_CAMERA_CAMERASERVICE_H + +#include +#include +#include + +namespace android { + +class MemoryHeapBase; +class MediaPlayer; + +// ---------------------------------------------------------------------------- + +#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) +#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) + +// When enabled, this feature allows you to send an event to the CameraService +// so that you can cause all references to the heap object gWeakHeap, defined +// below, to be printed. You will also need to set DEBUG_REFS=1 and +// DEBUG_REFS_ENABLED_BY_DEFAULT=0 in libutils/RefBase.cpp. You just have to +// set gWeakHeap to the appropriate heap you want to track. + +#define DEBUG_HEAP_LEAKS 0 + +// ---------------------------------------------------------------------------- + +class CameraService : public BnCameraService +{ + class Client; + +public: + static void instantiate(); + + // ICameraService interface + virtual sp connect(const sp& cameraClient); + + virtual status_t dump(int fd, const Vector& args); + + void removeClient(const sp& cameraClient); + + virtual status_t onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); + +private: + +// ---------------------------------------------------------------------------- + + class Client : public BnCamera { + + public: + virtual void disconnect(); + + // connect new client with existing camera remote + virtual status_t connect(const sp& client); + + // prevent other processes from using this ICamera interface + virtual status_t lock(); + + // allow other processes to use this ICamera interface + virtual status_t unlock(); + + // pass the buffered ISurface to the camera service + virtual status_t setPreviewDisplay(const sp& surface); + + // set the preview callback flag to affect how the received frames from + // preview are handled. + virtual void setPreviewCallbackFlag(int callback_flag); + + // start preview mode, must call setPreviewDisplay first + virtual status_t startPreview(); + + // stop preview mode + virtual void stopPreview(); + + // get preview state + virtual bool previewEnabled(); + + // start recording mode + virtual status_t startRecording(); + + // stop recording mode + virtual void stopRecording(); + + // get recording state + virtual bool recordingEnabled(); + + // release a recording frame + virtual void releaseRecordingFrame(const sp& mem); + + // auto focus + virtual status_t autoFocus(); + + // cancel auto focus + virtual status_t cancelAutoFocus(); + + // take a picture - returns an IMemory (ref-counted mmap) + virtual status_t takePicture(); + + // set preview/capture parameters - key/value pairs + virtual status_t setParameters(const String8& params); + + // get preview/capture parameters - key/value pairs + virtual String8 getParameters() const; + + // send command to camera driver + virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2); + + // our client... + const sp& getCameraClient() const { return mCameraClient; } + + private: + friend class CameraService; + Client(const sp& cameraService, + const sp& cameraClient, + pid_t clientPid); + Client(); + virtual ~Client(); + + status_t checkPid(); + + static void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2, void* user); + static void dataCallback(int32_t msgType, const sp& dataPtr, void* user); + static void dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, + const sp& dataPtr, void* user); + + static sp getClientFromCookie(void* user); + + void handlePreviewData(const sp&); + void handleShutter(image_rect_type *image); + void handlePostview(const sp&); + void handleRawPicture(const sp&); + void handleCompressedPicture(const sp&); + + void copyFrameAndPostCopiedFrame(const sp& client, + const sp& heap, size_t offset, size_t size); + + // camera operation mode + enum camera_mode { + CAMERA_PREVIEW_MODE = 0, // frame automatically released + CAMERA_RECORDING_MODE = 1, // frame has to be explicitly released by releaseRecordingFrame() + }; + status_t startCameraMode(camera_mode mode); + status_t startPreviewMode(); + status_t startRecordingMode(); + status_t setOverlay(); + status_t registerPreviewBuffers(); + + // Ensures atomicity among the public methods + mutable Mutex mLock; + + // mSurfaceLock synchronizes access to mSurface between + // setPreviewSurface() and postPreviewFrame(). Note that among + // the public methods, all accesses to mSurface are + // syncrhonized by mLock. However, postPreviewFrame() is called + // by the CameraHardwareInterface callback, and needs to + // access mSurface. It cannot hold mLock, however, because + // stopPreview() may be holding that lock while attempting + // to stop preview, and stopPreview itself will block waiting + // for a callback from CameraHardwareInterface. If this + // happens, it will cause a deadlock. + mutable Mutex mSurfaceLock; + mutable Condition mReady; + sp mCameraService; + sp mSurface; + int mPreviewCallbackFlag; + int mOrientation; + + sp mMediaPlayerClick; + sp mMediaPlayerBeep; + + // these are immutable once the object is created, + // they don't need to be protected by a lock + sp mCameraClient; + sp mHardware; + pid_t mClientPid; + bool mUseOverlay; + + sp mOverlayRef; + int mOverlayW; + int mOverlayH; + + mutable Mutex mPreviewLock; + sp mPreviewBuffer; + }; + +// ---------------------------------------------------------------------------- + + CameraService(); + virtual ~CameraService(); + + // We use a count for number of clients (shoule only be 0 or 1). + volatile int32_t mUsers; + virtual void incUsers(); + virtual void decUsers(); + + mutable Mutex mServiceLock; + wp mClient; + +#if DEBUG_HEAP_LEAKS + wp gWeakHeap; +#endif +}; + +// ---------------------------------------------------------------------------- + +}; // namespace android + +#endif diff --git a/libcamera/V4L2Camera.cpp b/libcamera/V4L2Camera.cpp new file mode 100644 index 0000000..6c0ed4b --- /dev/null +++ b/libcamera/V4L2Camera.cpp @@ -0,0 +1,505 @@ +/* + * 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 "converter.h" +#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); + 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); +} + +void V4L2Camera::GrabRecordFrame (void *recordBuffer) +{ + 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("GrabRecordFrame: VIDIOC_DQBUF Failed"); + + return; + } + nDequeued++; + + memcpy (tmpBuffer, videoIn->mem[videoIn->buf.index], (size_t) videoIn->buf.bytesused); + + yuyv422_to_yuv420((unsigned char *)tmpBuffer, (unsigned char *)recordBuffer, videoIn->width, videoIn->height); + + ret = ioctl(fd, VIDIOC_QBUF, &videoIn->buf); + if (ret < 0) { + LOGE("GrabRecordFrame: 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; +} + +// a helper class for jpeg compression in memory +class MemoryStream { +public: + MemoryStream(char* buf, size_t sz); + ~MemoryStream() { closeStream(); } + + void closeStream(); + size_t getOffset() const { return bytesWritten; } + operator FILE *() { return file; } + +private: + static int runThread(void *); + int readPipe(); + + char *buffer; + size_t size; + size_t bytesWritten; + int pipefd[2]; + FILE *file; + Mutex lock; + Condition exitedCondition; +}; + +MemoryStream::MemoryStream(char* buf, size_t sz) + : buffer(buf), size(sz), bytesWritten(0) +{ + if ((file = pipe(pipefd) ? NULL : fdopen(pipefd[1], "w"))) + createThread(runThread, this); +} + +void MemoryStream::closeStream() +{ + if (file) { + AutoMutex l(lock); + fclose(file); + file = NULL; + exitedCondition.wait(lock); + } +} + +int MemoryStream::runThread(void *self) +{ + return static_cast(self)->readPipe(); +} + +int MemoryStream::readPipe() +{ + char *buf = buffer; + ssize_t sz; + while ((sz = read(pipefd[0], buf, size - bytesWritten)) > 0) { + bytesWritten += sz; + buf += sz; + } + close(pipefd[0]); + AutoMutex l(lock); + exitedCondition.signal(); + return 0; +} + +sp V4L2Camera::GrabJpegFrame () +{ + 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++; + + size_t bytesused = videoIn->buf.bytesused; + if (char *tmpBuf = new char[bytesused]) { + MemoryStream strm(tmpBuf, bytesused); + saveYUYVtoJPEG((unsigned char *)videoIn->mem[videoIn->buf.index], videoIn->width, videoIn->height, strm, 100); + strm.closeStream(); + size_t fileSize = strm.getOffset(); + + sp mjpegPictureHeap = new MemoryHeapBase(fileSize); + sp jpegmemBase = new MemoryBase(mjpegPictureHeap, 0, fileSize); + memcpy(mjpegPictureHeap->base(), tmpBuf, fileSize); + delete[] tmpBuf; + + 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/libcamera/V4L2Camera.h b/libcamera/V4L2Camera.h new file mode 100644 index 0000000..a4cf55b --- /dev/null +++ b/libcamera/V4L2Camera.h @@ -0,0 +1,70 @@ +/* + * 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); + void GrabRecordFrame (void *recordBuffer); + 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 diff --git a/libcamera/converter.cpp b/libcamera/converter.cpp new file mode 100644 index 0000000..f0dc54d --- /dev/null +++ b/libcamera/converter.cpp @@ -0,0 +1,261 @@ +/* +** +** Copyright (C) 2009 0xlab.org - http://0xlab.org/ +** Copyright 2008, The Android Open Source Project +** +** This work is based on yuvconverter 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 "converter.h" + +void +yuyv422_to_yuv420(unsigned char *bufsrc, unsigned char *bufdest, int width, int height) +{ + unsigned char *ptrsrcy1, *ptrsrcy2; + unsigned char *ptrsrcy3, *ptrsrcy4; + unsigned char *ptrsrccb1, *ptrsrccb2; + unsigned char *ptrsrccb3, *ptrsrccb4; + unsigned char *ptrsrccr1, *ptrsrccr2; + unsigned char *ptrsrccr3, *ptrsrccr4; + int srcystride, srcccstride; + + ptrsrcy1 = bufsrc ; + ptrsrcy2 = bufsrc + (width<<1) ; + ptrsrcy3 = bufsrc + (width<<1)*2 ; + ptrsrcy4 = bufsrc + (width<<1)*3 ; + + ptrsrccb1 = bufsrc + 1; + ptrsrccb2 = bufsrc + (width<<1) + 1; + ptrsrccb3 = bufsrc + (width<<1)*2 + 1; + ptrsrccb4 = bufsrc + (width<<1)*3 + 1; + + ptrsrccr1 = bufsrc + 3; + ptrsrccr2 = bufsrc + (width<<1) + 3; + ptrsrccr3 = bufsrc + (width<<1)*2 + 3; + ptrsrccr4 = bufsrc + (width<<1)*3 + 3; + + srcystride = (width<<1)*3; + srcccstride = (width<<1)*3; + + unsigned char *ptrdesty1, *ptrdesty2; + unsigned char *ptrdesty3, *ptrdesty4; + unsigned char *ptrdestcb1, *ptrdestcb2; + unsigned char *ptrdestcr1, *ptrdestcr2; + int destystride, destccstride; + + ptrdesty1 = bufdest; + ptrdesty2 = bufdest + width; + ptrdesty3 = bufdest + width*2; + ptrdesty4 = bufdest + width*3; + + ptrdestcb1 = bufdest + width*height; + ptrdestcb2 = bufdest + width*height + (width>>1); + + ptrdestcr1 = bufdest + width*height + ((width*height) >> 2); + ptrdestcr2 = bufdest + width*height + ((width*height) >> 2) + (width>>1); + + destystride = (width)*3; + destccstride = (width>>1); + + int i, j; + + for(j=0; j<(height/4); j++) + { + for(i=0;i<(width/2);i++) + { + (*ptrdesty1++) = (*ptrsrcy1); + (*ptrdesty2++) = (*ptrsrcy2); + (*ptrdesty3++) = (*ptrsrcy3); + (*ptrdesty4++) = (*ptrsrcy4); + + ptrsrcy1 += 2; + ptrsrcy2 += 2; + ptrsrcy3 += 2; + ptrsrcy4 += 2; + + (*ptrdesty1++) = (*ptrsrcy1); + (*ptrdesty2++) = (*ptrsrcy2); + (*ptrdesty3++) = (*ptrsrcy3); + (*ptrdesty4++) = (*ptrsrcy4); + + ptrsrcy1 += 2; + ptrsrcy2 += 2; + ptrsrcy3 += 2; + ptrsrcy4 += 2; + + (*ptrdestcb1++) = (*ptrsrccb1); + (*ptrdestcb2++) = (*ptrsrccb3); + + ptrsrccb1 += 4; + ptrsrccb3 += 4; + + (*ptrdestcr1++) = (*ptrsrccr1); + (*ptrdestcr2++) = (*ptrsrccr3); + + ptrsrccr1 += 4; + ptrsrccr3 += 4; + + } + + + /* Update src pointers */ + ptrsrcy1 += srcystride; + ptrsrcy2 += srcystride; + ptrsrcy3 += srcystride; + ptrsrcy4 += srcystride; + + ptrsrccb1 += srcccstride; + ptrsrccb3 += srcccstride; + + ptrsrccr1 += srcccstride; + ptrsrccr3 += srcccstride; + + + /* Update dest pointers */ + ptrdesty1 += destystride; + ptrdesty2 += destystride; + ptrdesty3 += destystride; + ptrdesty4 += destystride; + + ptrdestcb1 += destccstride; + ptrdestcb2 += destccstride; + + ptrdestcr1 += destccstride; + ptrdestcr2 += destccstride; + + } +} + +void +yuyv422_to_yuv420sp(unsigned char *bufsrc, unsigned char *bufdest, int width, int height) +{ + unsigned char *ptrsrcy1, *ptrsrcy2; + unsigned char *ptrsrcy3, *ptrsrcy4; + unsigned char *ptrsrccb1, *ptrsrccb2; + unsigned char *ptrsrccb3, *ptrsrccb4; + unsigned char *ptrsrccr1, *ptrsrccr2; + unsigned char *ptrsrccr3, *ptrsrccr4; + int srcystride, srcccstride; + + ptrsrcy1 = bufsrc ; + ptrsrcy2 = bufsrc + (width<<1) ; + ptrsrcy3 = bufsrc + (width<<1)*2 ; + ptrsrcy4 = bufsrc + (width<<1)*3 ; + + ptrsrccb1 = bufsrc + 1; + ptrsrccb2 = bufsrc + (width<<1) + 1; + ptrsrccb3 = bufsrc + (width<<1)*2 + 1; + ptrsrccb4 = bufsrc + (width<<1)*3 + 1; + + ptrsrccr1 = bufsrc + 3; + ptrsrccr2 = bufsrc + (width<<1) + 3; + ptrsrccr3 = bufsrc + (width<<1)*2 + 3; + ptrsrccr4 = bufsrc + (width<<1)*3 + 3; + + srcystride = (width<<1)*3; + srcccstride = (width<<1)*3; + + unsigned char *ptrdesty1, *ptrdesty2; + unsigned char *ptrdesty3, *ptrdesty4; + unsigned char *ptrdestcb1, *ptrdestcb2; + unsigned char *ptrdestcr1, *ptrdestcr2; + int destystride, destccstride; + + ptrdesty1 = bufdest; + ptrdesty2 = bufdest + width; + ptrdesty3 = bufdest + width*2; + ptrdesty4 = bufdest + width*3; + + ptrdestcb1 = bufdest + width*height; + ptrdestcb2 = bufdest + width*height + width; + + ptrdestcr1 = bufdest + width*height + 1; + ptrdestcr2 = bufdest + width*height + width + 1; + + destystride = (width)*3; + destccstride = width; + + int i, j; + + for(j=0; j<(height/4); j++) + { + for(i=0;i<(width/2);i++) + { + (*ptrdesty1++) = (*ptrsrcy1); + (*ptrdesty2++) = (*ptrsrcy2); + (*ptrdesty3++) = (*ptrsrcy3); + (*ptrdesty4++) = (*ptrsrcy4); + + ptrsrcy1 += 2; + ptrsrcy2 += 2; + ptrsrcy3 += 2; + ptrsrcy4 += 2; + + (*ptrdesty1++) = (*ptrsrcy1); + (*ptrdesty2++) = (*ptrsrcy2); + (*ptrdesty3++) = (*ptrsrcy3); + (*ptrdesty4++) = (*ptrsrcy4); + + ptrsrcy1 += 2; + ptrsrcy2 += 2; + ptrsrcy3 += 2; + ptrsrcy4 += 2; + + (*ptrdestcb1) = (*ptrsrccb1); + (*ptrdestcb2) = (*ptrsrccb3); + ptrdestcb1 += 2; + ptrdestcb2 += 2; + + ptrsrccb1 += 4; + ptrsrccb3 += 4; + + (*ptrdestcr1) = (*ptrsrccr1); + (*ptrdestcr2) = (*ptrsrccr3); + ptrdestcr1 += 2; + ptrdestcr2 += 2; + + ptrsrccr1 += 4; + ptrsrccr3 += 4; + + } + + + /* Update src pointers */ + ptrsrcy1 += srcystride; + ptrsrcy2 += srcystride; + ptrsrcy3 += srcystride; + ptrsrcy4 += srcystride; + + ptrsrccb1 += srcccstride; + ptrsrccb3 += srcccstride; + + ptrsrccr1 += srcccstride; + ptrsrccr3 += srcccstride; + + + /* Update dest pointers */ + ptrdesty1 += destystride; + ptrdesty2 += destystride; + ptrdesty3 += destystride; + ptrdesty4 += destystride; + + ptrdestcb1 += destccstride; + ptrdestcb2 += destccstride; + + ptrdestcr1 += destccstride; + ptrdestcr2 += destccstride; + + } +} diff --git a/libcamera/converter.h b/libcamera/converter.h new file mode 100644 index 0000000..e7ecf40 --- /dev/null +++ b/libcamera/converter.h @@ -0,0 +1,25 @@ +/* +** +** Copyright (C) 2009 0xlab.org - http://0xlab.org/ +** 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 CONVERTER_H +#define CONVERTER_H + +void yuyv422_to_yuv420(unsigned char *bufsrc, unsigned char *bufdest, int width, int height); +void yuyv422_to_yuv420sp(unsigned char *bufsrc, unsigned char *bufdest, int width, int height); + +#endif -- cgit v1.2.3