summaryrefslogtreecommitdiffstats
path: root/libcamera/SecCamera.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/SecCamera.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/SecCamera.cpp')
-rwxr-xr-xlibcamera/SecCamera.cpp254
1 files changed, 126 insertions, 128 deletions
diff --git a/libcamera/SecCamera.cpp b/libcamera/SecCamera.cpp
index 38f675c..6998a5d 100755
--- a/libcamera/SecCamera.cpp
+++ b/libcamera/SecCamera.cpp
@@ -81,21 +81,6 @@ unsigned long measure_time(struct timeval *start, struct timeval *stop)
return time;
}
-static int close_buffers(struct fimc_buffer *buffers)
-{
- int i;
-
- for (i = 0; i < MAX_BUFFERS; i++) {
- if (buffers[i].start) {
- munmap(buffers[i].start, buffers[i].length);
- //LOGV("munmap():virt. addr[%d]: 0x%x size = %d\n", i, (unsigned int) buffers[i].start, buffers[i].length);
- buffers[i].start = NULL;
- }
- }
-
- return 0;
-}
-
static int get_pixel_depth(unsigned int fmt)
{
int depth = 0;
@@ -137,21 +122,19 @@ static int get_pixel_depth(unsigned int fmt)
#define ALIGN_H(x) (((x) + 0x1F) & (~0x1F)) // Set as multiple of 32
#define ALIGN_BUF(x) (((x) + 0x1FFF)& (~0x1FFF)) // Set as multiple of 8K
-static int init_yuv_buffers(struct fimc_buffer *buffers, int width, int height, unsigned int fmt)
+static int init_preview_buffers(struct fimc_buffer *buffers, int width, int height, unsigned int fmt)
{
int i, len;
- len = (width * height * get_pixel_depth(fmt)) / 8;
+ if (fmt==V4L2_PIX_FMT_NV12T) {
+ len = ALIGN_BUF(ALIGN_W(width) * ALIGN_H(height)) +
+ ALIGN_BUF(ALIGN_W(width) * ALIGN_H(height / 2));
+ } else {
+ len = (width * height * get_pixel_depth(fmt)) / 8;
+ }
for (i = 0; i < MAX_BUFFERS; i++) {
- if (fmt==V4L2_PIX_FMT_NV12T) {
- buffers[i].start = NULL;
- buffers[i].length = ALIGN_BUF(ALIGN_W(width) * ALIGN_H(height)) +
- ALIGN_BUF(ALIGN_W(width) * ALIGN_H(height / 2));
- } else {
- buffers[i].start = NULL;
- buffers[i].length = len;
- }
+ buffers[i].length = len;
}
return 0;
@@ -178,11 +161,28 @@ static int fimc_poll(struct pollfd *events)
return ret;
}
-static int fimc_esd_poll(struct pollfd *events)
+int SecCamera::previewPoll(bool preview)
{
int ret;
- ret = poll(events, 1, 1000);
+ if (preview) {
+#ifdef ENABLE_ESD_PREVIEW_CHECK
+ int status = 0;
+
+ if (!(++m_esd_check_count % 60)) {
+ status = getCameraSensorESDStatus();
+ m_esd_check_count = 0;
+ if (status) {
+ LOGE("ERR(%s) ESD status(%d)", __func__, status);
+ return status;
+ }
+ }
+#endif
+
+ ret = poll(&m_events_c, 1, 1000);
+ } else {
+ ret = poll(&m_events_c2, 1, 1000);
+ }
if (ret < 0) {
LOGE("ERR(%s):poll error\n", __func__);
@@ -355,34 +355,34 @@ static int fimc_v4l2_reqbufs(int fp, enum v4l2_buf_type type, int nr_bufs)
return req.count;
}
-static int fimc_v4l2_querybuf(int fp, struct fimc_buffer *buffers, enum v4l2_buf_type type, int nr_frames)
+static int fimc_v4l2_querybuf(int fp, struct fimc_buffer *buffer, enum v4l2_buf_type type)
{
struct v4l2_buffer v4l2_buf;
- int i, ret;
+ int ret;
- for (i = 0; i < nr_frames; i++) {
- v4l2_buf.type = type;
- v4l2_buf.memory = V4L2_MEMORY_MMAP;
- v4l2_buf.index = i;
+ LOGI("%s :", __func__);
- ret = ioctl(fp , VIDIOC_QUERYBUF, &v4l2_buf);
- if (ret < 0) {
- LOGE("ERR(%s):VIDIOC_QUERYBUF failed\n", __func__);
- return -1;
- }
+ v4l2_buf.type = type;
+ v4l2_buf.memory = V4L2_MEMORY_MMAP;
+ v4l2_buf.index = 0;
- if (nr_frames == 1) {
- buffers[i].length = v4l2_buf.length;
- if ((buffers[i].start = (char *)mmap(0, v4l2_buf.length, PROT_READ | PROT_WRITE, MAP_SHARED,
- fp, v4l2_buf.m.offset)) < 0) {
- LOGE("%s %d] mmap() failed\n",__func__, __LINE__);
- return -1;
- }
+ ret = ioctl(fp , VIDIOC_QUERYBUF, &v4l2_buf);
+ if (ret < 0) {
+ LOGE("ERR(%s):VIDIOC_QUERYBUF failed\n", __func__);
+ return -1;
+ }
- //LOGV("buffers[%d].start = %p v4l2_buf.length = %d", i, buffers[i].start, v4l2_buf.length);
- }
+ buffer->length = v4l2_buf.length;
+ if ((buffer->start = (char *)mmap(0, v4l2_buf.length,
+ PROT_READ | PROT_WRITE, MAP_SHARED,
+ fp, v4l2_buf.m.offset)) < 0) {
+ LOGE("%s %d] mmap() failed\n",__func__, __LINE__);
+ return -1;
}
+ LOGI("%s: buffer->start = %p v4l2_buf.length = %d",
+ __func__, buffer->start, v4l2_buf.length);
+
return 0;
}
@@ -443,7 +443,7 @@ static int fimc_v4l2_dqbuf(int fp)
ret = ioctl(fp, VIDIOC_DQBUF, &v4l2_buf);
if (ret < 0) {
- LOGE("ERR(%s):VIDIOC_DQBUF failed\n", __func__);
+ LOGE("ERR(%s):VIDIOC_DQBUF failed, dropped frame\n", __func__);
return ret;
}
@@ -604,6 +604,8 @@ SecCamera::SecCamera() :
m_params->sharpness = -1;
m_params->white_balance = -1;
+ memset(&m_capture_buf, 0, sizeof(m_capture_buf));
+
LOGV("%s :", __func__);
}
@@ -756,9 +758,9 @@ void SecCamera::DeinitCamera()
stopRecord();
- /* close m_cam_fd after stopRecord() because stopRecord()
- * uses m_cam_fd to change frame rate
- */
+ /* close m_cam_fd after stopRecord() because stopRecord()
+ * uses m_cam_fd to change frame rate
+ */
LOGI("DeinitCamera: m_cam_fd(%d)", m_cam_fd);
if (m_cam_fd > -1) {
close(m_cam_fd);
@@ -822,11 +824,8 @@ int SecCamera::startPreview(void)
ret = fimc_v4l2_s_fmt(m_cam_fd, m_preview_width,m_preview_height,m_preview_v4lformat, 0);
CHECK(ret);
- init_yuv_buffers(m_buffers_c, m_preview_width, m_preview_height, m_preview_v4lformat);
ret = fimc_v4l2_reqbufs(m_cam_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, MAX_BUFFERS);
CHECK(ret);
- ret = fimc_v4l2_querybuf(m_cam_fd, m_buffers_c, V4L2_BUF_TYPE_VIDEO_CAPTURE, MAX_BUFFERS);
- CHECK(ret);
LOGV("%s : m_preview_width: %d m_preview_height: %d m_angle: %d\n",
__func__, m_preview_width, m_preview_height, m_angle);
@@ -880,10 +879,8 @@ int SecCamera::stopPreview(void)
LOGV("%s :", __func__);
- close_buffers(m_buffers_c);
-
if (m_flag_camera_start == 0) {
- LOGV("%s: doing nothing because m_flag_camera_start is zero", __func__);
+ LOGW("%s: doing nothing because m_flag_camera_start is zero", __func__);
return 0;
}
@@ -896,9 +893,9 @@ int SecCamera::stopPreview(void)
}
ret = fimc_v4l2_streamoff(m_cam_fd);
+ CHECK(ret);
m_flag_camera_start = 0;
- CHECK(ret);
return ret;
}
@@ -906,6 +903,8 @@ int SecCamera::stopPreview(void)
//Recording
int SecCamera::startRecord(void)
{
+ int ret, i;
+
LOGV("%s :", __func__);
// aleady started
@@ -919,30 +918,22 @@ int SecCamera::startRecord(void)
return -1;
}
- memset(&m_events_c2, 0, sizeof(m_events_c2));
- m_events_c2.fd = m_cam_fd2;
- m_events_c2.events = POLLIN | POLLERR;
-
- int m_record_v4lformat = V4L2_PIX_FMT_NV12T;
/* enum_fmt, s_fmt sample */
- int ret = fimc_v4l2_enum_fmt(m_cam_fd2,m_record_v4lformat);
+ ret = fimc_v4l2_enum_fmt(m_cam_fd2, V4L2_PIX_FMT_NV12T);
CHECK(ret);
- LOGE("%s: m_recording_width = %d, m_recording_height = %d\n", __func__, m_recording_width, m_recording_height);
-
- ret = fimc_v4l2_s_fmt(m_cam_fd2, m_recording_width, m_recording_height, m_record_v4lformat, 0);
+ LOGI("%s: m_recording_width = %d, m_recording_height = %d\n",
+ __func__, m_recording_width, m_recording_height);
+ ret = fimc_v4l2_s_fmt(m_cam_fd2, m_recording_width,
+ m_recording_height, V4L2_PIX_FMT_NV12T, 0);
CHECK(ret);
- init_yuv_buffers(m_buffers_c2, m_recording_width, m_recording_height, m_record_v4lformat);
-
ret = fimc_v4l2_reqbufs(m_cam_fd2, V4L2_BUF_TYPE_VIDEO_CAPTURE, MAX_BUFFERS);
CHECK(ret);
- ret = fimc_v4l2_querybuf(m_cam_fd2, m_buffers_c2, V4L2_BUF_TYPE_VIDEO_CAPTURE, MAX_BUFFERS);
- CHECK(ret);
/* start with all buffers in queue */
- for (int i = 0; i < MAX_BUFFERS; i++) {
+ for (i = 0; i < MAX_BUFFERS; i++) {
ret = fimc_v4l2_qbuf(m_cam_fd2, i);
CHECK(ret);
}
@@ -950,7 +941,10 @@ int SecCamera::startRecord(void)
ret = fimc_v4l2_streamon(m_cam_fd2);
CHECK(ret);
- // It is a delay for a new frame, not to show the previous bigger ugly picture frame.
+ // Get and throw away the first frame since it is often garbled.
+ memset(&m_events_c2, 0, sizeof(m_events_c2));
+ m_events_c2.fd = m_cam_fd2;
+ m_events_c2.events = POLLIN | POLLERR;
ret = fimc_poll(&m_events_c2);
CHECK(ret);
@@ -963,21 +957,21 @@ int SecCamera::stopRecord(void)
{
int ret;
- if (m_flag_record_start == 0)
- return 0;
-
LOGV("%s :", __func__);
- close_buffers(m_buffers_c2);
+ if (m_flag_record_start == 0) {
+ LOGW("%s: doing nothing because m_flag_record_start is zero", __func__);
+ return 0;
+ }
if (m_cam_fd2 <= 0) {
LOGE("ERR(%s):Camera was closed\n", __func__);
return -1;
}
- ret = fimc_v4l2_streamoff(m_cam_fd2);
-
m_flag_record_start = 0;
+
+ ret = fimc_v4l2_streamoff(m_cam_fd2);
CHECK(ret);
return 0;
@@ -1029,20 +1023,7 @@ int SecCamera::getPreview()
int index;
int ret;
-#ifdef ENABLE_ESD_PREVIEW_CHECK
- int status = 0;
-
- if (!(++m_esd_check_count % 60)) {
- status = getCameraSensorESDStatus();
- m_esd_check_count = 0;
- }
-#endif // ENABLE_ESD_PREVIEW_CHECK
-
-#ifdef ENABLE_ESD_PREVIEW_CHECK
- if (m_flag_camera_start == 0 || fimc_esd_poll(&m_events_c) == 0 || status) {
-#else
- if (m_flag_camera_start == 0 || fimc_esd_poll(&m_events_c) == 0) {
-#endif
+ if (m_flag_camera_start == 0 || previewPoll(true) == 0) {
LOGE("ERR(%s):Start Camera Device Reset \n", __func__);
/* GAUDI Project([arun.c@samsung.com]) 2010.05.20. [Implemented ESD code] */
/*
@@ -1060,12 +1041,12 @@ int SecCamera::getPreview()
ret = fimc_v4l2_s_input(m_cam_fd, 1000);
CHECK(ret);
ret = startPreview();
-
if (ret < 0) {
LOGE("ERR(%s): startPreview() return %d\n", __func__, ret);
return 0;
}
}
+
index = fimc_v4l2_dqbuf(m_cam_fd);
if (!(0 <= index && index < MAX_BUFFERS)) {
LOGE("ERR(%s):wrong index = %d\n", __func__, index);
@@ -1078,25 +1059,31 @@ int SecCamera::getPreview()
return index;
}
-int SecCamera::getRecord()
+int SecCamera::getRecordFrame()
{
- int index;
-
if (m_flag_record_start == 0) {
LOGE("%s: m_flag_record_start is 0", __func__);
- startRecord();
- }
- fimc_poll(&m_events_c2);
- index = fimc_v4l2_dqbuf(m_cam_fd2);
- if (!(0 <= index && index < MAX_BUFFERS)) {
- LOGE("ERR(%s):wrong index = %d\n", __func__, index);
return -1;
}
- int ret = fimc_v4l2_qbuf(m_cam_fd2, index);
- CHECK(ret);
+ previewPoll(false);
+ return fimc_v4l2_dqbuf(m_cam_fd2);
+}
- return index;
+int SecCamera::releaseRecordFrame(int index)
+{
+ if (!m_flag_record_start) {
+ /* this can happen when recording frames are returned after
+ * the recording is stopped at the driver level. we don't
+ * need to return the buffers in this case and we've seen
+ * cases where fimc could crash if we called qbuf and it
+ * wasn't expecting it.
+ */
+ LOGI("%s: recording not in progress, ignoring", __func__);
+ return 0;
+ }
+
+ return fimc_v4l2_qbuf(m_cam_fd2, index);
}
int SecCamera::setPreviewSize(int width, int height, int pixel_format)
@@ -1175,6 +1162,7 @@ int SecCamera::setSnapshotCmd(void)
if (m_flag_camera_start > 0) {
LOG_TIME_START(0)
+ LOGW("WARN(%s):Camera was in preview, should have been stopped\n", __func__);
stopPreview();
LOG_TIME_END(0)
}
@@ -1190,11 +1178,9 @@ int SecCamera::setSnapshotCmd(void)
CHECK(ret);
ret = fimc_v4l2_s_fmt_cap(m_cam_fd, m_snapshot_width, m_snapshot_height, V4L2_PIX_FMT_JPEG);
CHECK(ret);
- init_yuv_buffers(m_buffers_c, m_snapshot_width, m_snapshot_height, m_snapshot_v4lformat);
-
ret = fimc_v4l2_reqbufs(m_cam_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, nframe);
CHECK(ret);
- ret = fimc_v4l2_querybuf(m_cam_fd, m_buffers_c, V4L2_BUF_TYPE_VIDEO_CAPTURE, nframe);
+ ret = fimc_v4l2_querybuf(m_cam_fd, &m_capture_buf, V4L2_BUF_TYPE_VIDEO_CAPTURE);
CHECK(ret);
ret = fimc_v4l2_qbuf(m_cam_fd, 0);
@@ -1207,6 +1193,21 @@ int SecCamera::setSnapshotCmd(void)
return 0;
}
+int SecCamera::endSnapshot(void)
+{
+ int ret;
+
+ LOGI("%s :", __func__);
+ if (m_capture_buf.start) {
+ munmap(m_capture_buf.start, m_capture_buf.length);
+ LOGI("munmap():virt. addr %p size = %d\n",
+ m_capture_buf.start, m_capture_buf.length);
+ m_capture_buf.start = NULL;
+ m_capture_buf.length = 0;
+ }
+ return 0;
+}
+
/*
* Set Jpeg quality & exif info and get JPEG data from camera ISP
*/
@@ -1223,7 +1224,7 @@ unsigned char* SecCamera::getJpeg(int *jpeg_size, unsigned int *phyaddr)
ret = fimc_poll(&m_events_c);
CHECK_PTR(ret);
index = fimc_v4l2_dqbuf(m_cam_fd);
- if (!(0 <= index && index < MAX_BUFFERS)) {
+ if (index != 0) {
LOGE("ERR(%s):wrong index = %d\n", __func__, index);
return NULL;
}
@@ -1241,7 +1242,7 @@ unsigned char* SecCamera::getJpeg(int *jpeg_size, unsigned int *phyaddr)
LOGV("\nsnapshot dqueued buffer = %d snapshot_width = %d snapshot_height = %d, size = %d\n\n",
index, m_snapshot_width, m_snapshot_height, *jpeg_size);
- addr = (unsigned char*)(m_buffers_c[index].start) + main_offset;
+ addr = (unsigned char*)(m_capture_buf.start) + main_offset;
*phyaddr = getPhyAddrY(index) + m_postview_offset;
LOG_TIME_START(2) // post
@@ -1381,6 +1382,7 @@ int SecCamera::getSnapshotAndJpeg(unsigned char *yuv_buf, unsigned char *jpeg_bu
if (m_flag_camera_start > 0) {
LOG_TIME_START(0)
+ LOGW("WARN(%s):Camera was in preview, should have been stopped\n", __func__);
stopPreview();
LOG_TIME_END(0)
}
@@ -1417,11 +1419,9 @@ int SecCamera::getSnapshotAndJpeg(unsigned char *yuv_buf, unsigned char *jpeg_bu
CHECK(ret);
ret = fimc_v4l2_s_fmt_cap(m_cam_fd, m_snapshot_width, m_snapshot_height, m_snapshot_v4lformat);
CHECK(ret);
- init_yuv_buffers(m_buffers_c, m_snapshot_width, m_snapshot_height, m_snapshot_v4lformat);
-
ret = fimc_v4l2_reqbufs(m_cam_fd, V4L2_BUF_TYPE_VIDEO_CAPTURE, nframe);
CHECK(ret);
- ret = fimc_v4l2_querybuf(m_cam_fd, m_buffers_c, V4L2_BUF_TYPE_VIDEO_CAPTURE, nframe);
+ ret = fimc_v4l2_querybuf(m_cam_fd, &m_capture_buf, V4L2_BUF_TYPE_VIDEO_CAPTURE);
CHECK(ret);
ret = fimc_v4l2_qbuf(m_cam_fd, 0);
@@ -1440,7 +1440,8 @@ int SecCamera::getSnapshotAndJpeg(unsigned char *yuv_buf, unsigned char *jpeg_bu
LOG_TIME_END(2)
- memcpy(yuv_buf, (unsigned char*)m_buffers_c[index].start, m_snapshot_width * m_snapshot_height * 2);
+ LOGI("%s : calling memcpy from m_capture_buf", __func__);
+ memcpy(yuv_buf, (unsigned char*)m_capture_buf.start, m_snapshot_width * m_snapshot_height * 2);
LOG_TIME_START(5) // post
fimc_v4l2_streamoff(m_cam_fd);
LOG_TIME_END(5)
@@ -1579,21 +1580,21 @@ int SecCamera::setSnapshotPixelFormat(int pixel_format)
if (m_snapshot_v4lformat == V4L2_PIX_FMT_YUV420)
LOGE("%s : SnapshotFormat:V4L2_PIX_FMT_YUV420", __func__);
else if (m_snapshot_v4lformat == V4L2_PIX_FMT_NV12)
- LOGE("%s : SnapshotFormat:V4L2_PIX_FMT_NV12", __func__);
+ LOGD("%s : SnapshotFormat:V4L2_PIX_FMT_NV12", __func__);
else if (m_snapshot_v4lformat == V4L2_PIX_FMT_NV12T)
- LOGE("%s : SnapshotFormat:V4L2_PIX_FMT_NV12T", __func__);
+ LOGD("%s : SnapshotFormat:V4L2_PIX_FMT_NV12T", __func__);
else if (m_snapshot_v4lformat == V4L2_PIX_FMT_NV21)
- LOGE("%s : SnapshotFormat:V4L2_PIX_FMT_NV21", __func__);
+ LOGD("%s : SnapshotFormat:V4L2_PIX_FMT_NV21", __func__);
else if (m_snapshot_v4lformat == V4L2_PIX_FMT_YUV422P)
- LOGE("%s : SnapshotFormat:V4L2_PIX_FMT_YUV422P", __func__);
+ LOGD("%s : SnapshotFormat:V4L2_PIX_FMT_YUV422P", __func__);
else if (m_snapshot_v4lformat == V4L2_PIX_FMT_YUYV)
- LOGE("%s : SnapshotFormat:V4L2_PIX_FMT_YUYV", __func__);
+ LOGD("%s : SnapshotFormat:V4L2_PIX_FMT_YUYV", __func__);
else if (m_snapshot_v4lformat == V4L2_PIX_FMT_UYVY)
- LOGE("%s : SnapshotFormat:V4L2_PIX_FMT_UYVY", __func__);
+ LOGD("%s : SnapshotFormat:V4L2_PIX_FMT_UYVY", __func__);
else if (m_snapshot_v4lformat == V4L2_PIX_FMT_RGB565)
- LOGE("%s : SnapshotFormat:V4L2_PIX_FMT_RGB565", __func__);
+ LOGD("%s : SnapshotFormat:V4L2_PIX_FMT_RGB565", __func__);
else
- LOGE("SnapshotFormat:UnknownFormat");
+ LOGD("SnapshotFormat:UnknownFormat");
#endif
return 0;
}
@@ -1603,11 +1604,6 @@ int SecCamera::getSnapshotPixelFormat(void)
return m_snapshot_v4lformat;
}
-int SecCamera::cancelPicture(void)
-{
- return close_buffers(m_buffers_c);
-}
-
// ======================================================================
// Settings
@@ -1752,6 +1748,7 @@ int SecCamera::SetRotate(int angle)
}
}
}
+
return 0;
}
@@ -1777,6 +1774,7 @@ int SecCamera::setFrameRate(int frame_rate)
}
}
}
+
return 0;
}