summaryrefslogtreecommitdiffstats
path: root/libcamera/SecCameraHWInterface.cpp
diff options
context:
space:
mode:
authorMike J. Chen <mjchen@sta.samsung.com>2010-11-03 10:19:37 -0700
committerSimon Wilson <simonwilson@google.com>2011-01-19 18:27:02 -0800
commit050e57e0f0738fa9c7312de75c6223572ba5d529 (patch)
treed7a6d5cfa7e6c55970070dcecd2a9029c476158a /libcamera/SecCameraHWInterface.cpp
parent0bd85d7b37790a2486319001d5bdd2e86a866c4f (diff)
downloaddevice_samsung_crespo-050e57e0f0738fa9c7312de75c6223572ba5d529.zip
device_samsung_crespo-050e57e0f0738fa9c7312de75c6223572ba5d529.tar.gz
device_samsung_crespo-050e57e0f0738fa9c7312de75c6223572ba5d529.tar.bz2
S5PC11X: libcamera: buffer cleanup
Cleanup how buffers are managed. Before, buffers for preview and capture and record were mixed together, with one thread cleaning up buffers for another. Now, each mode cleans up its own buffers. Implement asychronous buffer release for record case to fix a bug where we allowed FIMC to update a buffer that was still in use by encoder, resulting in encoding a frame that was part one image and part another. Change-Id: I42d0032cea61197a1f3a665a7248b700599d5a6a Signed-off-by: Mike J. Chen <mjchen@sta.samsung.com>
Diffstat (limited to 'libcamera/SecCameraHWInterface.cpp')
-rw-r--r--libcamera/SecCameraHWInterface.cpp241
1 files changed, 137 insertions, 104 deletions
diff --git a/libcamera/SecCameraHWInterface.cpp b/libcamera/SecCameraHWInterface.cpp
index bbbb48c..7e36a9d 100644
--- a/libcamera/SecCameraHWInterface.cpp
+++ b/libcamera/SecCameraHWInterface.cpp
@@ -64,7 +64,6 @@ static const int EFFECT_SKIP_FRAME = 1;
CameraHardwareSec::CameraHardwareSec(int cameraId)
:
- mPreviewRunning(false),
mCaptureInProgress(false),
mParameters(),
mPreviewHeap(0),
@@ -129,6 +128,11 @@ CameraHardwareSec::CameraHardwareSec(int cameraId)
initDefaultParameters(cameraId);
mExitAutoFocusThread = false;
+ mExitPreviewThread = false;
+ /* whether the PreviewThread is active in preview or stopped. we
+ * create the thread but it is initially in stopped state.
+ */
+ mPreviewRunning = false;
mPreviewThread = new PreviewThread(this);
mAutoFocusThread = new AutoFocusThread(this);
mPictureThread = new PictureThread(this);
@@ -414,9 +418,37 @@ void CameraHardwareSec::setSkipFrame(int frame)
mSkipFrame = frame;
}
+int CameraHardwareSec::previewThreadWrapper()
+{
+ LOGI("%s: starting", __func__);
+ while (1) {
+ mPreviewLock.lock();
+ while (!mPreviewRunning) {
+ LOGI("%s: calling mSecCamera->stopPreview() and waiting", __func__);
+ mSecCamera->stopPreview();
+ /* signal that we're stopping */
+ mPreviewStoppedCondition.signal();
+ mPreviewCondition.wait(mPreviewLock);
+ LOGI("%s: return from wait", __func__);
+ }
+ mPreviewLock.unlock();
+
+ if (mExitPreviewThread) {
+ LOGI("%s: exiting", __func__);
+ mSecCamera->stopPreview();
+ return 0;
+ }
+ previewThread();
+ }
+}
+
int CameraHardwareSec::previewThread()
{
int index;
+ nsecs_t timestamp;
+ unsigned int phyYAddr;
+ unsigned int phyCAddr;
+ struct addrs *addrs;
index = mSecCamera->getPreview();
if (index < 0) {
@@ -431,7 +463,15 @@ int CameraHardwareSec::previewThread()
}
mSkipFrameLock.unlock();
- nsecs_t timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
+ timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
+
+ phyYAddr = mSecCamera->getPhyAddrY(index);
+ phyCAddr = mSecCamera->getPhyAddrC(index);
+
+ if (phyYAddr == 0xffffffff || phyCAddr == 0xffffffff) {
+ LOGE("ERR(%s):Fail on SecCamera getPhyAddr Y addr = %0x C addr = %0x", __func__, phyYAddr, phyCAddr);
+ return UNKNOWN_ERROR;
+ }
int width, height, frame_size, offset;
@@ -440,45 +480,29 @@ int CameraHardwareSec::previewThread()
offset = (frame_size + 16) * index;
sp<MemoryBase> buffer = new MemoryBase(mPreviewHeap, offset, frame_size);
- unsigned int phyYAddr = mSecCamera->getPhyAddrY(index);
- unsigned int phyCAddr = mSecCamera->getPhyAddrC(index);
-
- if (phyYAddr == 0xffffffff || phyCAddr == 0xffffffff) {
- LOGE("ERR(%s):Fail on SecCamera. Invalid PhyAddr, Y addr = %0x C addr = %0x",
- __func__, phyYAddr, phyCAddr);
- return UNKNOWN_ERROR;
- }
memcpy(static_cast<unsigned char *>(mPreviewHeap->base()) + (offset + frame_size ), &phyYAddr, 4);
memcpy(static_cast<unsigned char *>(mPreviewHeap->base()) + (offset + frame_size + 4), &phyCAddr, 4);
#if defined(BOARD_USES_OVERLAY)
if (mUseOverlay) {
int ret;
+ overlay_buffer_t overlay_buffer;
+
mOverlayBufferIdx ^= 1;
memcpy(static_cast<unsigned char*>(mPreviewHeap->base()) + offset + frame_size + sizeof(phyYAddr) + sizeof(phyCAddr),
- &mOverlayBufferIdx, sizeof(mOverlayBufferIdx));
+ &mOverlayBufferIdx, sizeof(mOverlayBufferIdx));
ret = mOverlay->queueBuffer((void*)(static_cast<unsigned char *>(mPreviewHeap->base()) + (offset + frame_size)));
- if (ret == ALL_BUFFERS_FLUSHED) {
- goto OverlayEnd;
- } else if (ret == -1) {
+ if (ret == -1 ) {
LOGE("ERR(%s):overlay queueBuffer fail", __func__);
- goto OverlayEnd;
- }
-
- overlay_buffer_t overlay_buffer;
- ret = mOverlay->dequeueBuffer(&overlay_buffer);
-
- if (ret == ALL_BUFFERS_FLUSHED) {
- goto OverlayEnd;
- } else if (ret == -1) {
- LOGE("ERR(%s):overlay dequeueBuffer fail", __func__);
- goto OverlayEnd;
- }
- }
-
-OverlayEnd:
+ } else if (ret != ALL_BUFFERS_FLUSHED) {
+ ret = mOverlay->dequeueBuffer(&overlay_buffer);
+ if (ret == -1) {
+ LOGE("ERR(%s):overlay dequeueBuffer fail", __func__);
+ }
+ }
+ }
#endif
// Notify the client of a new frame.
@@ -487,35 +511,32 @@ OverlayEnd:
}
if (mRecordRunning == true) {
- int index = mSecCamera->getRecord();
-
+ index = mSecCamera->getRecordFrame();
if (index < 0) {
LOGE("ERR(%s):Fail on SecCamera->getRecord()", __func__);
return UNKNOWN_ERROR;
}
- unsigned int phyYAddr = mSecCamera->getRecPhyAddrY(index);
- unsigned int phyCAddr = mSecCamera->getRecPhyAddrC(index);
+ phyYAddr = mSecCamera->getRecPhyAddrY(index);
+ phyCAddr = mSecCamera->getRecPhyAddrC(index);
if (phyYAddr == 0xffffffff || phyCAddr == 0xffffffff) {
LOGE("ERR(%s):Fail on SecCamera getRectPhyAddr Y addr = %0x C addr = %0x", __func__, phyYAddr, phyCAddr);
return UNKNOWN_ERROR;
}
- struct addrs *addrs = (struct addrs *)mRecordHeap->base();
+
+ addrs = (struct addrs *)mRecordHeap->base();
sp<MemoryBase> buffer = new MemoryBase(mRecordHeap, index * sizeof(struct addrs), sizeof(struct addrs));
addrs[index].addr_y = phyYAddr;
addrs[index].addr_cbcr = phyCAddr;
+ addrs[index].buf_index = index;
// Notify the client of a new frame.
if (mMsgEnabled & CAMERA_MSG_VIDEO_FRAME) {
- //nsecs_t timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
mDataCbTimestamp(timestamp, CAMERA_MSG_VIDEO_FRAME, buffer, mCallbackCookie);
- }
- } else if (mRecordRunning == false) {
- if (mSecCamera->stopRecord() < 0) {
- LOGE("ERR(%s):Fail on mSecCamera->stopRecord()", __func__);
- return UNKNOWN_ERROR;
+ } else {
+ mSecCamera->releaseRecordFrame(index);
}
}
@@ -529,18 +550,18 @@ status_t CameraHardwareSec::startPreview()
LOGV("%s :", __func__);
Mutex::Autolock lock(mStateLock);
- if (mPreviewRunning) {
- // already running
- LOGE("%s : preview thread already running", __func__);
- return INVALID_OPERATION;
- }
-
if (mCaptureInProgress) {
LOGE("%s : capture in progress, not allowed", __func__);
return INVALID_OPERATION;
}
- mSecCamera->stopPreview();
+ mPreviewLock.lock();
+ if (mPreviewRunning) {
+ // already running
+ LOGE("%s : preview thread already running", __func__);
+ mPreviewLock.unlock();
+ return INVALID_OPERATION;
+ }
setSkipFrame(INITIAL_SKIP_FRAME);
@@ -568,7 +589,8 @@ status_t CameraHardwareSec::startPreview()
LOGV("CameraHardwareSec: mPostViewWidth = %d mPostViewHeight = %d mPostViewSize = %d",mPostViewWidth,mPostViewHeight,mPostViewSize);
mPreviewRunning = true;
- mPreviewThread->run("CameraPreviewThread", PRIORITY_URGENT_DISPLAY);
+ mPreviewCondition.signal();
+ mPreviewLock.unlock();
return NO_ERROR;
}
@@ -636,24 +658,22 @@ void CameraHardwareSec::stopPreview()
{
LOGV("%s :", __func__);
- if (!previewEnabled())
- return;
-
- /* request that the preview thread exit. we can wait because we're
- * called by CameraServices with a lock but it has disabled all preview
- * related callbacks so previewThread should not invoke any callbacks.
- */
- mPreviewThread->requestExitAndWait();
-
- if (mSecCamera->stopPreview() < 0)
- LOGE("ERR(%s):Fail on mSecCamera->stopPreview()", __func__);
-
- mPreviewRunning = false;
+ /* request that the preview thread stop. */
+ mPreviewLock.lock();
+ if (mPreviewRunning) {
+ mPreviewRunning = false;
+ mPreviewCondition.signal();
+ /* wait until preview thread is stopped */
+ mPreviewStoppedCondition.wait(mPreviewLock);
+ } else {
+ LOGI("%s : preview not running, doing nothing", __func__);
+ }
+ mPreviewLock.unlock();
}
bool CameraHardwareSec::previewEnabled()
{
- Mutex::Autolock lock(mStateLock);
+ Mutex::Autolock lock(mPreviewLock);
LOGV("%s : %d", __func__, mPreviewRunning);
return mPreviewRunning;
}
@@ -678,7 +698,13 @@ void CameraHardwareSec::stopRecording()
{
LOGV("%s :", __func__);
- mRecordRunning = false;
+ if (mRecordRunning == true) {
+ if (mSecCamera->stopRecord() < 0) {
+ LOGE("ERR(%s):Fail on mSecCamera->stopRecord()", __func__);
+ return;
+ }
+ mRecordRunning = false;
+ }
}
bool CameraHardwareSec::recordingEnabled()
@@ -690,15 +716,11 @@ bool CameraHardwareSec::recordingEnabled()
void CameraHardwareSec::releaseRecordingFrame(const sp<IMemory>& mem)
{
- LOG_CAMERA_PREVIEW("%s :", __func__);
+ ssize_t offset;
+ sp<IMemoryHeap> heap = mem->getMemory(&offset, NULL);
+ struct addrs *addrs = (struct addrs *)((uint8_t *)heap->base() + offset);
-// ssize_t offset; size_t size;
-// sp<MemoryBase> mem1 = mem;
-// sp<MemoryHeapBase> heap = mem->getMemory(&offset, &size);
-// sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
-
-// mem1.clear();
-// heap.clear();
+ mSecCamera->releaseRecordFrame(addrs->buf_index);
}
// ---------------------------------------------------------------------------
@@ -717,12 +739,20 @@ int CameraHardwareSec::autoFocusThread()
* in CameraServices layer.
*/
mFocusLock.lock();
- mCondition.wait(mFocusLock);
- mFocusLock.unlock();
-
/* check early exit request */
- if (mExitAutoFocusThread)
+ if (mExitAutoFocusThread) {
+ mFocusLock.unlock();
+ LOGV("%s : exiting on request0", __func__);
+ return NO_ERROR;
+ }
+ mFocusCondition.wait(mFocusLock);
+ /* check early exit request */
+ if (mExitAutoFocusThread) {
+ mFocusLock.unlock();
+ LOGV("%s : exiting on request1", __func__);
return NO_ERROR;
+ }
+ mFocusLock.unlock();
LOGV("%s : calling setAutoFocus", __func__);
if (mSecCamera->setAutofocus() < 0) {
@@ -752,6 +782,7 @@ int CameraHardwareSec::autoFocusThread()
mNotifyCb(CAMERA_MSG_FOCUS, false, 0, mCallbackCookie);
}
+ LOGV("%s : exiting with no error", __func__);
return NO_ERROR;
}
@@ -759,7 +790,7 @@ status_t CameraHardwareSec::autoFocus()
{
LOGV("%s :", __func__);
/* signal autoFocusThread to run once */
- mCondition.signal();
+ mFocusCondition.signal();
return NO_ERROR;
}
@@ -983,14 +1014,6 @@ int CameraHardwareSec::pictureThread()
LOG_CAMERA("getSnapshotAndJpeg interval: %lu us", LOG_TIME(1));
}
- /* the capture is done at this point so we can allow sensor commands
- * again, we still need to do jpeg and thumbnail processing, but the
- * sensor is available for something else
- */
- mStateLock.lock();
- mCaptureInProgress = false;
- mStateLock.unlock();
-
int JpegImageSize, JpegExifSize;
bool isLSISensor = false;
@@ -1046,21 +1069,14 @@ int CameraHardwareSec::pictureThread()
ret = mOverlay->queueBuffer((void*)(static_cast<unsigned char *>(mPreviewHeap->base()) + offset +
(mPostViewWidth*mPostViewHeight * 3 / 2)));
- if (ret == ALL_BUFFERS_FLUSHED) {
- goto PostviewOverlayEnd;
- } else if (ret == -1) {
+ if (ret == -1) {
LOGE("ERR(%s):overlay queueBuffer fail", __func__);
- goto PostviewOverlayEnd;
- }
-
- overlay_buffer_t overlay_buffer;
- ret = mOverlay->dequeueBuffer(&overlay_buffer);
-
- if (ret == ALL_BUFFERS_FLUSHED) {
- goto PostviewOverlayEnd;
- } else if (ret == -1) {
- LOGE("ERR(%s):overlay dequeueBuffer fail", __func__);
- goto PostviewOverlayEnd;
+ } else if (ret != ALL_BUFFERS_FLUSHED) {
+ overlay_buffer_t overlay_buffer;
+ ret = mOverlay->dequeueBuffer(&overlay_buffer);
+ if (ret == -1) {
+ LOGE("ERR(%s):overlay dequeueBuffer fail", __func__);
+ }
}
PostviewOverlayEnd:
@@ -1076,7 +1092,8 @@ PostviewOverlayEnd:
LOGV("JpegExifSize=%d", JpegExifSize);
if (JpegExifSize < 0) {
- return UNKNOWN_ERROR;
+ ret = UNKNOWN_ERROR;
+ goto out;
}
unsigned char *ExifStart = (unsigned char *)JpegHeap->base() + 2;
@@ -1093,6 +1110,12 @@ PostviewOverlayEnd:
LOG_CAMERA("pictureThread interval: %lu us", LOG_TIME(0));
LOGV("%s : pictureThread end", __func__);
+
+out:
+ mStateLock.lock();
+ mCaptureInProgress = false;
+ mStateLock.unlock();
+
return ret;
}
@@ -1121,9 +1144,6 @@ status_t CameraHardwareSec::cancelPicture()
{
mPictureThread->requestExitAndWait();
- mSecCamera->cancelPicture();
-
- LOGW("%s : not supported, just returning NO_ERROR", __func__);
return NO_ERROR;
}
@@ -2038,6 +2058,14 @@ void CameraHardwareSec::release()
* for ourself to exit, which is a deadlock.
*/
if (mPreviewThread != NULL) {
+ /* this thread is normally already in it's threadLoop but blocked
+ * on the condition variable or running. signal it so it wakes
+ * up and can exit.
+ */
+ mPreviewThread->requestExit();
+ mExitPreviewThread = true;
+ mPreviewRunning = true; /* let it run so it can exit */
+ mPreviewCondition.signal();
mPreviewThread->requestExitAndWait();
mPreviewThread.clear();
}
@@ -2045,9 +2073,11 @@ void CameraHardwareSec::release()
/* this thread is normally already in it's threadLoop but blocked
* on the condition variable. signal it so it wakes up and can exit.
*/
+ mFocusLock.lock();
mAutoFocusThread->requestExit();
mExitAutoFocusThread = true;
- mCondition.signal();
+ mFocusCondition.signal();
+ mFocusLock.unlock();
mAutoFocusThread->requestExitAndWait();
mAutoFocusThread.clear();
}
@@ -2061,8 +2091,11 @@ void CameraHardwareSec::release()
if (mJpegHeap != NULL)
mJpegHeap.clear();
- if (mPreviewHeap != NULL)
+ if (mPreviewHeap != NULL) {
+ LOGI("%s: calling mPreviewHeap.dispose()", __func__);
+ mPreviewHeap->dispose();
mPreviewHeap.clear();
+ }
if (mRecordHeap != NULL)
mRecordHeap.clear();