summaryrefslogtreecommitdiff
path: root/services/camera/libcameraservice/CameraHardwareStub.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'services/camera/libcameraservice/CameraHardwareStub.cpp')
-rw-r--r--services/camera/libcameraservice/CameraHardwareStub.cpp410
1 files changed, 410 insertions, 0 deletions
diff --git a/services/camera/libcameraservice/CameraHardwareStub.cpp b/services/camera/libcameraservice/CameraHardwareStub.cpp
new file mode 100644
index 0000000..b3e0ee6
--- /dev/null
+++ b/services/camera/libcameraservice/CameraHardwareStub.cpp
@@ -0,0 +1,410 @@
+/*
+**
+** 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 "CameraHardwareStub"
+#include <utils/Log.h>
+
+#include "CameraHardwareStub.h"
+#include <utils/threads.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include "CannedJpeg.h"
+
+namespace android {
+
+CameraHardwareStub::CameraHardwareStub()
+ : mParameters(),
+ mPreviewHeap(0),
+ mRawHeap(0),
+ mFakeCamera(0),
+ mPreviewFrameSize(0),
+ mNotifyCb(0),
+ mDataCb(0),
+ mDataCbTimestamp(0),
+ mCallbackCookie(0),
+ mMsgEnabled(0),
+ mCurrentPreviewFrame(0)
+{
+ initDefaultParameters();
+}
+
+void CameraHardwareStub::initDefaultParameters()
+{
+ CameraParameters p;
+
+ p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES, "320x240");
+ p.setPreviewSize(320, 240);
+ p.setPreviewFrameRate(15);
+ p.setPreviewFormat(CameraParameters::PIXEL_FORMAT_YUV420SP);
+
+ p.set(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES, "320x240");
+ p.setPictureSize(320, 240);
+ p.setPictureFormat(CameraParameters::PIXEL_FORMAT_JPEG);
+
+ if (setParameters(p) != NO_ERROR) {
+ LOGE("Failed to set default parameters?!");
+ }
+}
+
+void CameraHardwareStub::initHeapLocked()
+{
+ // Create raw heap.
+ int picture_width, picture_height;
+ mParameters.getPictureSize(&picture_width, &picture_height);
+ mRawHeap = new MemoryHeapBase(picture_width * picture_height * 3 / 2);
+
+ int preview_width, preview_height;
+ mParameters.getPreviewSize(&preview_width, &preview_height);
+ LOGD("initHeapLocked: preview size=%dx%d", preview_width, preview_height);
+
+ // Note that we enforce yuv420sp in setParameters().
+ int how_big = preview_width * preview_height * 3 / 2;
+
+ // If we are being reinitialized to the same size as before, no
+ // work needs to be done.
+ if (how_big == mPreviewFrameSize)
+ return;
+
+ mPreviewFrameSize = how_big;
+
+ // Make a new mmap'ed heap that can be shared across processes.
+ // use code below to test with pmem
+ mPreviewHeap = new MemoryHeapBase(mPreviewFrameSize * kBufferCount);
+ // Make an IMemory for each frame so that we can reuse them in callbacks.
+ for (int i = 0; i < kBufferCount; i++) {
+ mBuffers[i] = new MemoryBase(mPreviewHeap, i * mPreviewFrameSize, mPreviewFrameSize);
+ }
+
+ // Recreate the fake camera to reflect the current size.
+ delete mFakeCamera;
+ mFakeCamera = new FakeCamera(preview_width, preview_height);
+}
+
+CameraHardwareStub::~CameraHardwareStub()
+{
+ delete mFakeCamera;
+ mFakeCamera = 0; // paranoia
+}
+
+sp<IMemoryHeap> CameraHardwareStub::getPreviewHeap() const
+{
+ return mPreviewHeap;
+}
+
+sp<IMemoryHeap> CameraHardwareStub::getRawHeap() const
+{
+ return mRawHeap;
+}
+
+void CameraHardwareStub::setCallbacks(notify_callback notify_cb,
+ data_callback data_cb,
+ data_callback_timestamp data_cb_timestamp,
+ void* user)
+{
+ Mutex::Autolock lock(mLock);
+ mNotifyCb = notify_cb;
+ mDataCb = data_cb;
+ mDataCbTimestamp = data_cb_timestamp;
+ mCallbackCookie = user;
+}
+
+void CameraHardwareStub::enableMsgType(int32_t msgType)
+{
+ Mutex::Autolock lock(mLock);
+ mMsgEnabled |= msgType;
+}
+
+void CameraHardwareStub::disableMsgType(int32_t msgType)
+{
+ Mutex::Autolock lock(mLock);
+ mMsgEnabled &= ~msgType;
+}
+
+bool CameraHardwareStub::msgTypeEnabled(int32_t msgType)
+{
+ Mutex::Autolock lock(mLock);
+ return (mMsgEnabled & msgType);
+}
+
+// ---------------------------------------------------------------------------
+
+int CameraHardwareStub::previewThread()
+{
+ mLock.lock();
+ // the attributes below can change under our feet...
+
+ int previewFrameRate = mParameters.getPreviewFrameRate();
+
+ // Find the offset within the heap of the current buffer.
+ ssize_t offset = mCurrentPreviewFrame * mPreviewFrameSize;
+
+ sp<MemoryHeapBase> heap = mPreviewHeap;
+
+ // this assumes the internal state of fake camera doesn't change
+ // (or is thread safe)
+ FakeCamera* fakeCamera = mFakeCamera;
+
+ sp<MemoryBase> buffer = mBuffers[mCurrentPreviewFrame];
+
+ mLock.unlock();
+
+ // TODO: here check all the conditions that could go wrong
+ if (buffer != 0) {
+ // Calculate how long to wait between frames.
+ int delay = (int)(1000000.0f / float(previewFrameRate));
+
+ // This is always valid, even if the client died -- the memory
+ // is still mapped in our process.
+ void *base = heap->base();
+
+ // Fill the current frame with the fake camera.
+ uint8_t *frame = ((uint8_t *)base) + offset;
+ fakeCamera->getNextFrameAsYuv420(frame);
+
+ //LOGV("previewThread: generated frame to buffer %d", mCurrentPreviewFrame);
+
+ // Notify the client of a new frame.
+ if (mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME)
+ mDataCb(CAMERA_MSG_PREVIEW_FRAME, buffer, mCallbackCookie);
+
+ // Advance the buffer pointer.
+ mCurrentPreviewFrame = (mCurrentPreviewFrame + 1) % kBufferCount;
+
+ // Wait for it...
+ usleep(delay);
+ }
+
+ return NO_ERROR;
+}
+
+status_t CameraHardwareStub::startPreview()
+{
+ Mutex::Autolock lock(mLock);
+ if (mPreviewThread != 0) {
+ // already running
+ return INVALID_OPERATION;
+ }
+ mPreviewThread = new PreviewThread(this);
+ return NO_ERROR;
+}
+
+void CameraHardwareStub::stopPreview()
+{
+ sp<PreviewThread> previewThread;
+
+ { // scope for the lock
+ Mutex::Autolock lock(mLock);
+ previewThread = mPreviewThread;
+ }
+
+ // don't hold the lock while waiting for the thread to quit
+ if (previewThread != 0) {
+ previewThread->requestExitAndWait();
+ }
+
+ Mutex::Autolock lock(mLock);
+ mPreviewThread.clear();
+}
+
+bool CameraHardwareStub::previewEnabled() {
+ return mPreviewThread != 0;
+}
+
+status_t CameraHardwareStub::startRecording()
+{
+ return UNKNOWN_ERROR;
+}
+
+void CameraHardwareStub::stopRecording()
+{
+}
+
+bool CameraHardwareStub::recordingEnabled()
+{
+ return false;
+}
+
+void CameraHardwareStub::releaseRecordingFrame(const sp<IMemory>& mem)
+{
+}
+
+// ---------------------------------------------------------------------------
+
+int CameraHardwareStub::beginAutoFocusThread(void *cookie)
+{
+ CameraHardwareStub *c = (CameraHardwareStub *)cookie;
+ return c->autoFocusThread();
+}
+
+int CameraHardwareStub::autoFocusThread()
+{
+ if (mMsgEnabled & CAMERA_MSG_FOCUS)
+ mNotifyCb(CAMERA_MSG_FOCUS, true, 0, mCallbackCookie);
+ return NO_ERROR;
+}
+
+status_t CameraHardwareStub::autoFocus()
+{
+ Mutex::Autolock lock(mLock);
+ if (createThread(beginAutoFocusThread, this) == false)
+ return UNKNOWN_ERROR;
+ return NO_ERROR;
+}
+
+status_t CameraHardwareStub::cancelAutoFocus()
+{
+ return NO_ERROR;
+}
+
+/*static*/ int CameraHardwareStub::beginPictureThread(void *cookie)
+{
+ CameraHardwareStub *c = (CameraHardwareStub *)cookie;
+ return c->pictureThread();
+}
+
+int CameraHardwareStub::pictureThread()
+{
+ if (mMsgEnabled & CAMERA_MSG_SHUTTER)
+ mNotifyCb(CAMERA_MSG_SHUTTER, 0, 0, mCallbackCookie);
+
+ if (mMsgEnabled & CAMERA_MSG_RAW_IMAGE) {
+ //FIXME: use a canned YUV image!
+ // In the meantime just make another fake camera picture.
+ int w, h;
+ mParameters.getPictureSize(&w, &h);
+ sp<MemoryBase> mem = new MemoryBase(mRawHeap, 0, w * h * 3 / 2);
+ FakeCamera cam(w, h);
+ cam.getNextFrameAsYuv420((uint8_t *)mRawHeap->base());
+ mDataCb(CAMERA_MSG_RAW_IMAGE, mem, mCallbackCookie);
+ }
+
+ if (mMsgEnabled & CAMERA_MSG_COMPRESSED_IMAGE) {
+ sp<MemoryHeapBase> heap = new MemoryHeapBase(kCannedJpegSize);
+ sp<MemoryBase> mem = new MemoryBase(heap, 0, kCannedJpegSize);
+ memcpy(heap->base(), kCannedJpeg, kCannedJpegSize);
+ mDataCb(CAMERA_MSG_COMPRESSED_IMAGE, mem, mCallbackCookie);
+ }
+ return NO_ERROR;
+}
+
+status_t CameraHardwareStub::takePicture()
+{
+ stopPreview();
+ if (createThread(beginPictureThread, this) == false)
+ return UNKNOWN_ERROR;
+ return NO_ERROR;
+}
+
+status_t CameraHardwareStub::cancelPicture()
+{
+ return NO_ERROR;
+}
+
+status_t CameraHardwareStub::dump(int fd, const Vector<String16>& args) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+ AutoMutex lock(&mLock);
+ if (mFakeCamera != 0) {
+ mFakeCamera->dump(fd);
+ mParameters.dump(fd, args);
+ snprintf(buffer, 255, " preview frame(%d), size (%d), running(%s)\n", mCurrentPreviewFrame, mPreviewFrameSize, mPreviewRunning?"true": "false");
+ result.append(buffer);
+ } else {
+ result.append("No camera client yet.\n");
+ }
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t CameraHardwareStub::setParameters(const CameraParameters& params)
+{
+ Mutex::Autolock lock(mLock);
+ // XXX verify params
+
+ if (strcmp(params.getPreviewFormat(),
+ CameraParameters::PIXEL_FORMAT_YUV420SP) != 0) {
+ LOGE("Only yuv420sp preview is supported");
+ return -1;
+ }
+
+ if (strcmp(params.getPictureFormat(),
+ CameraParameters::PIXEL_FORMAT_JPEG) != 0) {
+ LOGE("Only jpeg still pictures are supported");
+ return -1;
+ }
+
+ int w, h;
+ params.getPictureSize(&w, &h);
+ if (w != kCannedJpegWidth && h != kCannedJpegHeight) {
+ LOGE("Still picture size must be size of canned JPEG (%dx%d)",
+ kCannedJpegWidth, kCannedJpegHeight);
+ return -1;
+ }
+
+ mParameters = params;
+ initHeapLocked();
+
+ return NO_ERROR;
+}
+
+CameraParameters CameraHardwareStub::getParameters() const
+{
+ Mutex::Autolock lock(mLock);
+ return mParameters;
+}
+
+status_t CameraHardwareStub::sendCommand(int32_t command, int32_t arg1,
+ int32_t arg2)
+{
+ return BAD_VALUE;
+}
+
+void CameraHardwareStub::release()
+{
+}
+
+sp<CameraHardwareInterface> CameraHardwareStub::createInstance()
+{
+ return new CameraHardwareStub();
+}
+
+static CameraInfo sCameraInfo[] = {
+ {
+ CAMERA_FACING_BACK,
+ 90, /* orientation */
+ }
+};
+
+extern "C" int HAL_getNumberOfCameras()
+{
+ return sizeof(sCameraInfo) / sizeof(sCameraInfo[0]);
+}
+
+extern "C" void HAL_getCameraInfo(int cameraId, struct CameraInfo* cameraInfo)
+{
+ memcpy(cameraInfo, &sCameraInfo[cameraId], sizeof(CameraInfo));
+}
+
+extern "C" sp<CameraHardwareInterface> HAL_openCameraHardware(int cameraId)
+{
+ return CameraHardwareStub::createInstance();
+}
+
+}; // namespace android