diff options
Diffstat (limited to 'camera')
-rw-r--r-- | camera/libcameraservice/CameraHardwareStub.cpp | 18 | ||||
-rw-r--r-- | camera/libcameraservice/CameraHardwareStub.h | 6 | ||||
-rw-r--r-- | camera/libcameraservice/CameraService.cpp | 328 | ||||
-rw-r--r-- | camera/libcameraservice/CameraService.h | 39 |
4 files changed, 313 insertions, 78 deletions
diff --git a/camera/libcameraservice/CameraHardwareStub.cpp b/camera/libcameraservice/CameraHardwareStub.cpp index 3d6b0b1..9a47705 100644 --- a/camera/libcameraservice/CameraHardwareStub.cpp +++ b/camera/libcameraservice/CameraHardwareStub.cpp @@ -187,6 +187,24 @@ bool CameraHardwareStub::previewEnabled() { return mPreviewThread != 0; } +status_t CameraHardwareStub::startRecording(recording_callback cb, void* user) +{ + return UNKNOWN_ERROR; +} + +void CameraHardwareStub::stopRecording() +{ +} + +bool CameraHardwareStub::recordingEnabled() +{ + return false; +} + +void CameraHardwareStub::releaseRecordingFrame(const sp<IMemory>& mem) +{ +} + // --------------------------------------------------------------------------- int CameraHardwareStub::beginAutoFocusThread(void *cookie) diff --git a/camera/libcameraservice/CameraHardwareStub.h b/camera/libcameraservice/CameraHardwareStub.h index 9f5ddf1..cdd6011 100644 --- a/camera/libcameraservice/CameraHardwareStub.h +++ b/camera/libcameraservice/CameraHardwareStub.h @@ -34,6 +34,12 @@ public: 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, diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp index 36c5ada..e5d4220 100644 --- a/camera/libcameraservice/CameraService.cpp +++ b/camera/libcameraservice/CameraService.cpp @@ -86,18 +86,19 @@ sp<ICamera> CameraService::connect(const sp<ICameraClient>& cameraClient) LOGD("Connect E from ICameraClient %p", cameraClient->asBinder().get()); Mutex::Autolock lock(mLock); + sp<Client> client; if (mClient != 0) { sp<Client> currentClient = mClient.promote(); if (currentClient != 0) { sp<ICameraClient> currentCameraClient(currentClient->getCameraClient()); if (cameraClient->asBinder() == currentCameraClient->asBinder()) { // this is the same client reconnecting... - LOGD("Connect X same client is reconnecting..."); + LOGD("Connect X same client (%p) is reconnecting...", cameraClient->asBinder().get()); return currentClient; } else { - // it's another client... boot the previous one... - LOGD("new client connecting, booting the old one..."); - mClient.clear(); + // it's another client... reject it + LOGD("new client (%p) attempting to connect - rejected", cameraClient->asBinder().get()); + return client; } } else { // can't promote, the previous client has died... @@ -107,7 +108,7 @@ sp<ICamera> CameraService::connect(const sp<ICameraClient>& cameraClient) } // create a new Client object - sp<Client> client = new Client(this, cameraClient, IPCThreadState::self()->getCallingPid()); + client = new Client(this, cameraClient, IPCThreadState::self()->getCallingPid()); mClient = client; #if DEBUG_CLIENT_REFERENCES // Enable tracking for this object, and track increments and decrements of @@ -158,21 +159,23 @@ CameraService::Client::Client(const sp<CameraService>& cameraService, mCameraClient = cameraClient; mClientPid = clientPid; mHardware = openCameraHardware(); + mUseOverlay = mHardware->useOverlay(); // Callback is disabled by default - mFrameCallbackFlag = FRAME_CALLBACK_FLAG_NOOP; + mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP; LOGD("Client X constructor"); } status_t CameraService::Client::checkPid() { if (mClientPid == IPCThreadState::self()->getCallingPid()) return NO_ERROR; - LOGW("Attempt to use locked camera from different process"); + LOGW("Attempt to use locked camera (%p) from different process", getCameraClient()->asBinder().get()); return -EBUSY; } status_t CameraService::Client::lock() { + Mutex::Autolock _l(mLock); // lock camera to this client if the the camera is unlocked if (mClientPid == 0) { mClientPid = IPCThreadState::self()->getCallingPid(); @@ -184,8 +187,9 @@ status_t CameraService::Client::lock() status_t CameraService::Client::unlock() { + Mutex::Autolock _l(mLock); // allow anyone to use camera - LOGV("unlock"); + LOGV("unlock (%p)", getCameraClient()->asBinder().get()); status_t result = checkPid(); if (result == NO_ERROR) mClientPid = 0; return result; @@ -194,27 +198,40 @@ status_t CameraService::Client::unlock() status_t CameraService::Client::connect(const sp<ICameraClient>& client) { // connect a new process to the camera - LOGV("connect"); - - // hold a reference to the old client or we will deadlock if the client is - // in the same process and we hold the lock when we remove the reference - sp<ICameraClient> oldClient; + LOGV("connect (%p)", client->asBinder().get()); + + // I hate this hack, but things get really ugly when the media recorder + // service is handing back the camera to the app. The ICameraClient + // destructor will be called during the same IPC, making it look like + // the remote client is trying to disconnect. This hack temporarily + // sets the mClientPid to an invalid pid to prevent the hardware from + // being torn down. { - Mutex::Autolock _l(mLock); - if (mClientPid != 0) { - LOGW("Tried to connect to locked camera"); - return -EBUSY; - } - oldClient = mCameraClient; - // did the client actually change? - if (client->asBinder() == mCameraClient->asBinder()) return NO_ERROR; + // hold a reference to the old client or we will deadlock if the client is + // in the same process and we hold the lock when we remove the reference + sp<ICameraClient> oldClient; + { + Mutex::Autolock _l(mLock); + if (mClientPid != 0) { + LOGW("Tried to connect to locked camera"); + return -EBUSY; + } + oldClient = mCameraClient; + + // did the client actually change? + if (client->asBinder() == mCameraClient->asBinder()) return NO_ERROR; + + mCameraClient = client; + mClientPid = -1; + mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP; + LOGV("connect new process (%d) to existing camera client", mClientPid); + } - LOGV("connect new process to existing camera client"); - mCameraClient = client; - mClientPid = IPCThreadState::self()->getCallingPid(); - mFrameCallbackFlag = FRAME_CALLBACK_FLAG_NOOP; } + // the old client destructor is called when oldClient goes out of scope + // now we set the new PID to lock the interface again + mClientPid = IPCThreadState::self()->getCallingPid(); return NO_ERROR; } @@ -232,8 +249,8 @@ static void *unregister_surface(void *arg) CameraService::Client::~Client() { // tear down client - LOGD("Client E destructor"); - if (mSurface != 0) { + LOGD("Client (%p) E destructor", getCameraClient()->asBinder().get()); + if (mSurface != 0 && !mUseOverlay) { #if HAVE_ANDROID_OS pthread_t thr; // We unregister the buffers in a different thread because binder does @@ -244,7 +261,7 @@ CameraService::Client::~Client() mSurface.get()); pthread_join(thr, NULL); #else - mSurface->unregisterBuffers(); + mSurface->unregisterBuffers(); #endif } @@ -256,16 +273,22 @@ CameraService::Client::~Client() void CameraService::Client::disconnect() { - LOGD("Client E disconnect"); + LOGD("Client (%p) E disconnect from (%d)", + getCameraClient()->asBinder().get(), + IPCThreadState::self()->getCallingPid()); Mutex::Autolock lock(mLock); - if (mClientPid == 0) { + if (mClientPid <= 0) { LOGV("camera is unlocked, don't tear down hardware"); return; } - if (checkPid() != NO_ERROR) return; + if (checkPid() != NO_ERROR) { + LOGV("Different client - don't disconnect"); + return; + } mCameraService->removeClient(mCameraClient); if (mHardware != 0) { + LOGV("hardware teardown"); // Before destroying mHardware, we must make sure it's in the // idle state. mHardware->stopPreview(); @@ -288,7 +311,7 @@ status_t CameraService::Client::setPreviewDisplay(const sp<ISurface>& surface) Mutex::Autolock surfaceLock(mSurfaceLock); // asBinder() is safe on NULL (returns NULL) if (surface->asBinder() != mSurface->asBinder()) { - if (mSurface != 0) { + if (mSurface != 0 && !mUseOverlay) { LOGD("clearing old preview surface %p", mSurface.get()); mSurface->unregisterBuffers(); } @@ -297,19 +320,20 @@ status_t CameraService::Client::setPreviewDisplay(const sp<ISurface>& surface) return NO_ERROR; } -// set the frame callback flag to affect how the received frames from +// set the preview callback flag to affect how the received frames from // preview are handled. -void CameraService::Client::setFrameCallbackFlag(int frame_callback_flag) +void CameraService::Client::setPreviewCallbackFlag(int callback_flag) { + LOGV("setPreviewCallbackFlag"); Mutex::Autolock lock(mLock); if (checkPid() != NO_ERROR) return; - mFrameCallbackFlag = frame_callback_flag; + mPreviewCallbackFlag = callback_flag; } // start preview mode, must call setPreviewDisplay first -status_t CameraService::Client::startPreview() +status_t CameraService::Client::startCameraMode(camera_mode mode) { - LOGD("startPreview()"); + LOGD("startCameraMode(%d)", mode); /* we cannot call into mHardware with mLock held because * mHardware has callbacks onto us which acquire this lock @@ -325,37 +349,124 @@ status_t CameraService::Client::startPreview() } if (mSurface == 0) { - LOGE("setPreviewDisplay must be called before startPreview!"); + LOGE("setPreviewDisplay must be called before startCameraMode!"); return INVALID_OPERATION; } - // do nothing if preview is already started - if (mHardware->previewEnabled()) return NO_ERROR; + switch(mode) { + case CAMERA_RECORDING_MODE: + return startRecordingMode(); - // XXX: This needs to be improved. remove all hardcoded stuff + default: // CAMERA_PREVIEW_MODE + return startPreviewMode(); + } +} - int w, h; - CameraParameters params(mHardware->getParameters()); - params.getPreviewSize(&w, &h); +status_t CameraService::Client::startRecordingMode() +{ + LOGV("startRecordingMode"); + + status_t ret = UNKNOWN_ERROR; + // if preview has not been started, start preview first + if (!mHardware->previewEnabled()) { + ret = startPreviewMode(); + if (ret != NO_ERROR) { + return ret; + } + } + + // if recording has been enabled, nothing needs to be done + if (mHardware->recordingEnabled()) { + return NO_ERROR; + } + + // start recording mode + ret = mHardware->startRecording(recordingCallback, + mCameraService.get()); + if (ret != NO_ERROR) { + LOGE("mHardware->startRecording() failed with status %d", ret); + } + return ret; +} + +status_t CameraService::Client::startPreviewMode() +{ + LOGV("startPreviewMode"); + + // if preview has been enabled, nothing needs to be done + if (mHardware->previewEnabled()) { + return NO_ERROR; + } + + // start preview mode #if DEBUG_DUMP_PREVIEW_FRAME_TO_FILE debug_frame_cnt = 0; #endif + status_t ret = UNKNOWN_ERROR; + int w, h; + CameraParameters params(mHardware->getParameters()); + params.getPreviewSize(&w, &h); - status_t ret = mHardware->startPreview(previewCallback, - mCameraService.get()); - if (ret == NO_ERROR) { - mSurface->unregisterBuffers(); - mSurface->registerBuffers(w,h,w,h, - PIXEL_FORMAT_YCbCr_420_SP, - mHardware->getPreviewHeap()); - } - else LOGE("mHardware->startPreview() failed with status %d\n", - ret); + if (mUseOverlay) { + const char *format = params.getPreviewFormat(); + int fmt; + LOGD("Use Overlays"); + if (!strcmp(format, "yuv422i")) + fmt = OVERLAY_FORMAT_YCbCr_422_I; + else if (!strcmp(format, "rgb565")) + fmt = OVERLAY_FORMAT_RGB_565; + else { + LOGE("Invalid preview format for overlays"); + return -EINVAL; + } + sp<OverlayRef> ref = mSurface->createOverlay(w, h, fmt); + ret = mHardware->setOverlay(new Overlay(ref)); + if (ret != NO_ERROR) { + LOGE("mHardware->setOverlay() failed with status %d\n", ret); + return ret; + } + ret = mHardware->startPreview(NULL, mCameraService.get()); + if (ret != NO_ERROR) + LOGE("mHardware->startPreview() failed with status %d\n", ret); + + } else { + ret = mHardware->startPreview(previewCallback, + mCameraService.get()); + if (ret == NO_ERROR) { + mSurface->unregisterBuffers(); + + uint32_t transform = 0; + if (params.getOrientation() == + CameraParameters::CAMERA_ORIENTATION_PORTRAIT) { + LOGV("portrait mode"); + transform = ISurface::BufferHeap::ROT_90; + } + ISurface::BufferHeap buffers(w, h, w, h, + PIXEL_FORMAT_YCbCr_420_SP, + transform, + 0, + mHardware->getPreviewHeap()); + + mSurface->registerBuffers(buffers); + } else { + LOGE("mHardware->startPreview() failed with status %d", ret); + } + } return ret; } +status_t CameraService::Client::startPreview() +{ + return startCameraMode(CAMERA_PREVIEW_MODE); +} + +status_t CameraService::Client::startRecording() +{ + return startCameraMode(CAMERA_RECORDING_MODE); +} + // stop preview mode void CameraService::Client::stopPreview() { @@ -372,12 +483,46 @@ void CameraService::Client::stopPreview() mHardware->stopPreview(); LOGD("stopPreview(), hardware stopped OK"); - if (mSurface != 0) { + if (mSurface != 0 && !mUseOverlay) { mSurface->unregisterBuffers(); } mPreviewBuffer.clear(); } +// stop recording mode +void CameraService::Client::stopRecording() +{ + LOGV("stopRecording()"); + + Mutex::Autolock lock(mLock); + if (checkPid() != NO_ERROR) return; + + if (mHardware == 0) { + LOGE("mHardware is NULL, returning."); + return; + } + + mHardware->stopRecording(); + LOGV("stopRecording(), hardware stopped OK"); + mPreviewBuffer.clear(); +} + +// release a recording frame +void CameraService::Client::releaseRecordingFrame(const sp<IMemory>& mem) +{ + LOGV("releaseRecordingFrame()"); + + Mutex::Autolock lock(mLock); + if (checkPid() != NO_ERROR) return; + + if (mHardware == 0) { + LOGE("mHardware is NULL, returning."); + return; + } + + mHardware->releaseRecordingFrame(mem); +} + bool CameraService::Client::previewEnabled() { Mutex::Autolock lock(mLock); @@ -385,6 +530,13 @@ bool CameraService::Client::previewEnabled() return mHardware->previewEnabled(); } +bool CameraService::Client::recordingEnabled() +{ + Mutex::Autolock lock(mLock); + if (mHardware == 0) return false; + return mHardware->recordingEnabled(); +} + // Safely retrieves a strong pointer to the client during a hardware callback. sp<CameraService::Client> CameraService::Client::getClientFromCookie(void* user) { @@ -476,7 +628,7 @@ void CameraService::Client::previewCallback(const sp<IMemory>& mem, void* user) #endif // The strong pointer guarantees the client will exist, but no lock is held. - client->postFrame(mem); + client->postPreviewFrame(mem); #if DEBUG_CLIENT_REFERENCES //**** if the client's refcount is 1, then we are about to destroy it here, @@ -488,6 +640,18 @@ void CameraService::Client::previewCallback(const sp<IMemory>& mem, void* user) #endif } +// recording callback +void CameraService::Client::recordingCallback(const sp<IMemory>& mem, void* user) +{ + LOGV("recordingCallback"); + sp<Client> client = getClientFromCookie(user); + if (client == 0) { + return; + } + // The strong pointer guarantees the client will exist, but no lock is held. + client->postRecordingFrame(mem); +} + // take a picture - image is returned in callback status_t CameraService::Client::autoFocus() { @@ -520,7 +684,7 @@ status_t CameraService::Client::takePicture() return INVALID_OPERATION; } - if (mSurface != NULL) + if (mSurface != NULL && !mUseOverlay) mSurface->unregisterBuffers(); return mHardware->takePicture(shutterCallback, @@ -573,10 +737,18 @@ void CameraService::Client::yuvPictureCallback(const sp<IMemory>& mem, params.getPictureSize(&w, &h); // Mutex::Autolock clientLock(client->mLock); - if (client->mSurface != 0) { + if (client->mSurface != 0 && !client->mUseOverlay) { client->mSurface->unregisterBuffers(); - client->mSurface->registerBuffers(w,h,w,h, - PIXEL_FORMAT_YCbCr_420_SP, heap); + + uint32_t transform = 0; + if (params.getOrientation() == CameraParameters::CAMERA_ORIENTATION_PORTRAIT) { + LOGV("portrait mode"); + transform = ISurface::BufferHeap::ROT_90; + } + ISurface::BufferHeap buffers(w, h, w, h, + PIXEL_FORMAT_YCbCr_420_SP, transform, 0, heap); + + client->mSurface->registerBuffers(buffers); client->mSurface->postBuffer(offset); } @@ -730,12 +902,22 @@ void CameraService::Client::copyFrameAndPostCopiedFrame(sp<IMemoryHeap> heap, si LOGE("failed to allocate space for frame callback"); return; } - mCameraClient->frameCallback(frame); + mCameraClient->previewCallback(frame); } -void CameraService::Client::postFrame(const sp<IMemory>& mem) +void CameraService::Client::postRecordingFrame(const sp<IMemory>& frame) { - LOGV("postFrame"); + LOGV("postRecordingFrame"); + if (frame == 0) { + LOGW("frame is a null pointer"); + return; + } + mCameraClient->recordingCallback(frame); +} + +void CameraService::Client::postPreviewFrame(const sp<IMemory>& mem) +{ + LOGV("postPreviewFrame"); if (mem == 0) { LOGW("mem is a null pointer"); return; @@ -752,31 +934,32 @@ void CameraService::Client::postFrame(const sp<IMemory>& mem) } // Is the callback enabled or not? - if (!(mFrameCallbackFlag & FRAME_CALLBACK_FLAG_ENABLE_MASK)) { + if (!(mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ENABLE_MASK)) { // If the enable bit is off, the copy-out and one-shot bits are ignored LOGV("frame callback is diabled"); return; } // Is the received frame copied out or not? - if (mFrameCallbackFlag & FRAME_CALLBACK_FLAG_COPY_OUT_MASK) { + if (mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_COPY_OUT_MASK) { LOGV("frame is copied out"); copyFrameAndPostCopiedFrame(heap, offset, size); } else { LOGV("frame is directly sent out without copying"); - mCameraClient->frameCallback(mem); + mCameraClient->previewCallback(mem); } // Is this is one-shot only? - if (mFrameCallbackFlag & FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) { + if (mPreviewCallbackFlag & FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) { LOGV("One-shot only, thus clear the bits and disable frame callback"); - mFrameCallbackFlag &= ~(FRAME_CALLBACK_FLAG_ONE_SHOT_MASK | + mPreviewCallbackFlag &= ~(FRAME_CALLBACK_FLAG_ONE_SHOT_MASK | FRAME_CALLBACK_FLAG_COPY_OUT_MASK | FRAME_CALLBACK_FLAG_ENABLE_MASK); } } -void CameraService::Client::postError(status_t error) { +void CameraService::Client::postError(status_t error) +{ mCameraClient->errorCallback(error); } @@ -796,6 +979,11 @@ status_t CameraService::dump(int fd, const Vector<String16>& args) AutoMutex lock(&mLock); if (mClient != 0) { sp<Client> currentClient = mClient.promote(); + sprintf(buffer, "Client (%p) PID: %d", + currentClient->getCameraClient()->asBinder().get(), + currentClient->mClientPid); + result.append(buffer); + write(fd, result.string(), result.size()); currentClient->mHardware->dump(fd, args); } else { result.append("No camera client yet.\n"); @@ -880,5 +1068,3 @@ status_t CameraService::onTransact( #endif // DEBUG_HEAP_LEAKS }; // namespace android - - diff --git a/camera/libcameraservice/CameraService.h b/camera/libcameraservice/CameraService.h index cd8c1e9..d9b7927 100644 --- a/camera/libcameraservice/CameraService.h +++ b/camera/libcameraservice/CameraService.h @@ -82,9 +82,9 @@ private: // pass the buffered ISurface to the camera service virtual status_t setPreviewDisplay(const sp<ISurface>& surface); - // set the frame callback flag to affect how the received frames from + // set the preview callback flag to affect how the received frames from // preview are handled. - virtual void setFrameCallbackFlag(int frame_callback_flag); + virtual void setPreviewCallbackFlag(int callback_flag); // start preview mode, must call setPreviewDisplay first virtual status_t startPreview(); @@ -95,6 +95,18 @@ private: // 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<IMemory>& mem); + // auto focus virtual status_t autoFocus(); @@ -120,6 +132,7 @@ private: status_t checkPid(); + static void recordingCallback(const sp<IMemory>& mem, void* user); static void previewCallback(const sp<IMemory>& mem, void* user); static void shutterCallback(void *user); static void yuvPictureCallback(const sp<IMemory>& mem, void* user); @@ -130,17 +143,28 @@ private: void postShutter(); void postRaw(const sp<IMemory>& mem); void postJpeg(const sp<IMemory>& mem); - void postFrame(const sp<IMemory>& mem); + void postPreviewFrame(const sp<IMemory>& mem); + void postRecordingFrame(const sp<IMemory>& frame); void copyFrameAndPostCopiedFrame(sp<IMemoryHeap> heap, size_t offset, size_t size); void postError(status_t error); void postAutoFocus(bool focused); - // Ensures atomicity among the public methods + // 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(); + + // Ensures atomicity among the public methods mutable Mutex mLock; + // mSurfaceLock synchronizes access to mSurface between - // setPreviewSurface() and postFrame(). Note that among + // setPreviewSurface() and postPreviewFrame(). Note that among // the public methods, all accesses to mSurface are - // syncrhonized by mLock. However, postFrame() is called + // 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 @@ -152,13 +176,14 @@ private: sp<CameraService> mCameraService; sp<ISurface> mSurface; sp<MemoryHeapBase> mPreviewBuffer; - int mFrameCallbackFlag; + int mPreviewCallbackFlag; // these are immutable once the object is created, // they don't need to be protected by a lock sp<ICameraClient> mCameraClient; sp<CameraHardwareInterface> mHardware; pid_t mClientPid; + bool mUseOverlay; }; // ---------------------------------------------------------------------------- |