summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIliyan Malchev <malchev@google.com>2011-06-09 17:15:21 -0700
committerIliyan Malchev <malchev@google.com>2011-06-11 11:03:43 -0700
commit41f0acecab5c8e83ed081728f35024050ab1e6e6 (patch)
tree34365e15f69320bc494d8fb56971659faf13027a
parent1c5c61285a466262d67ff33f514b958540d46488 (diff)
downloaddevice_samsung_crespo-41f0acecab5c8e83ed081728f35024050ab1e6e6.zip
device_samsung_crespo-41f0acecab5c8e83ed081728f35024050ab1e6e6.tar.gz
device_samsung_crespo-41f0acecab5c8e83ed081728f35024050ab1e6e6.tar.bz2
crespo camera: software work-around to enable camcorder
This hack does two things: -- it sets preview to NV21 (YUV420SP) -- it sets gralloc to YV12 The reason being: the samsung encoder understands only yuv420sp, and gralloc does yv12 and rgb565. So what we do is we break up the interleaved UV in separate V and U planes, which makes preview look good, and enabled the encoder as well. FIXME: Samsung needs to enable support for proper yv12 coming out of the camera, and to fix their video encoder to work with yv12. FIXME: It also seems like either Samsung's YUV420SP (NV21) or img's YV12 has the color planes switched. We need to figure which side is doing it wrong and have the respective party fix it. Change-Id: Ib300b560ecce969c68105ad5e2abe88a5e33ae1f Signed-off-by: Iliyan Malchev <malchev@google.com>
-rwxr-xr-xlibcamera/SecCamera.cpp18
-rw-r--r--libcamera/SecCameraHWInterface.cpp147
2 files changed, 112 insertions, 53 deletions
diff --git a/libcamera/SecCamera.cpp b/libcamera/SecCamera.cpp
index e49dab7..40fb955 100755
--- a/libcamera/SecCamera.cpp
+++ b/libcamera/SecCamera.cpp
@@ -122,24 +122,6 @@ 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_preview_buffers(struct fimc_buffer *buffers, int width, int height, unsigned int fmt)
-{
- int i, len;
-
- 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++) {
- buffers[i].length = len;
- }
-
- return 0;
-}
-
static int fimc_poll(struct pollfd *events)
{
int ret;
diff --git a/libcamera/SecCameraHWInterface.cpp b/libcamera/SecCameraHWInterface.cpp
index b96e362..5063a12 100644
--- a/libcamera/SecCameraHWInterface.cpp
+++ b/libcamera/SecCameraHWInterface.cpp
@@ -38,6 +38,23 @@
#define BACK_CAMERA_INFINITY_FOCUS_DISTANCES_STR "0.10,1.20,Infinity"
#define FRONT_CAMERA_FOCUS_DISTANCES_STR "0.20,0.25,Infinity"
+// This hack does two things:
+// -- it sets preview to NV21 (YUV420SP)
+// -- it sets gralloc to YV12
+//
+// The reason being: the samsung encoder understands only yuv420sp, and gralloc
+// does yv12 and rgb565. So what we do is we break up the interleaved UV in
+// separate V and U planes, which makes preview look good, and enabled the
+// encoder as well.
+//
+// FIXME: Samsung needs to enable support for proper yv12 coming out of the
+// camera, and to fix their video encoder to work with yv12.
+// FIXME: It also seems like either Samsung's YUV420SP (NV21) or img's YV12 has
+// the color planes switched. We need to figure which side is doing it
+// wrong and have the respective party fix it.
+
+#define HACK 1
+
namespace android {
struct addrs {
@@ -158,20 +175,26 @@ void CameraHardwareSec::initDefaultParameters(int cameraId)
LOGE("getSnapshotMaxSize fail (%d / %d) \n",
snapshot_max_width, snapshot_max_height);
- p.setPreviewFormat(CameraParameters::PIXEL_FORMAT_RGB565);
+// p.setPreviewFormat(CameraParameters::PIXEL_FORMAT_RGB565);
+// p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS, CameraParameters::PIXEL_FORMAT_RGB565);
+// p.set(CameraParameters::KEY_VIDEO_FRAME_FORMAT, CameraParameters::PIXEL_FORMAT_RGB565);
+#if HACK
+ p.setPreviewFormat(CameraParameters::PIXEL_FORMAT_YUV420SP); mFrameSizeDelta = 16;
+ p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS, CameraParameters::PIXEL_FORMAT_YUV420SP);
+ p.set(CameraParameters::KEY_VIDEO_FRAME_FORMAT, CameraParameters::PIXEL_FORMAT_YUV420SP);
+#else
+ p.setPreviewFormat(CameraParameters::PIXEL_FORMAT_YUV420P); mFrameSizeDelta = 16;
+ p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS, CameraParameters::PIXEL_FORMAT_YUV420P);
+ p.set(CameraParameters::KEY_VIDEO_FRAME_FORMAT, CameraParameters::PIXEL_FORMAT_YUV420P);
+#endif
// p.setPreviewFormat(CameraParameters::PIXEL_FORMAT_YUV420P); mFrameSizeDelta = 16;
p.setPreviewSize(preview_max_width, preview_max_height);
p.setPictureFormat(CameraParameters::PIXEL_FORMAT_JPEG);
p.setPictureSize(snapshot_max_width, snapshot_max_height);
p.set(CameraParameters::KEY_JPEG_QUALITY, "100"); // maximum quality
-
- p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS, CameraParameters::PIXEL_FORMAT_RGB565);
-// p.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS, CameraParameters::PIXEL_FORMAT_YUV420P);
p.set(CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS,
CameraParameters::PIXEL_FORMAT_JPEG);
- p.set(CameraParameters::KEY_VIDEO_FRAME_FORMAT, CameraParameters::PIXEL_FORMAT_RGB565);
-// p.set(CameraParameters::KEY_VIDEO_FRAME_FORMAT, CameraParameters::PIXEL_FORMAT_YUV420P);
String8 parameterString;
@@ -387,6 +410,9 @@ status_t CameraHardwareSec::setPreviewWindow(preview_stream_ops *w)
const char *str_preview_format = mParameters.getPreviewFormat();
LOGV("%s: preview format %s", __func__, str_preview_format);
mFrameSizeDelta = 16;
+
+ hal_pixel_format = HAL_PIXEL_FORMAT_YV12; // default
+
if (!strcmp(str_preview_format,
CameraParameters::PIXEL_FORMAT_RGB565)) {
hal_pixel_format = HAL_PIXEL_FORMAT_RGB_565;
@@ -398,21 +424,15 @@ status_t CameraHardwareSec::setPreviewWindow(preview_stream_ops *w)
mFrameSizeDelta = 0;
}
else if (!strcmp(str_preview_format,
- CameraParameters::PIXEL_FORMAT_YUV420SP))
- hal_pixel_format = HAL_PIXEL_FORMAT_YCrCb_420_SP;
- else if (!strcmp(str_preview_format,
- CameraParameters::PIXEL_FORMAT_YUV420P))
+ CameraParameters::PIXEL_FORMAT_YUV420SP)) {
+#if HACK
hal_pixel_format = HAL_PIXEL_FORMAT_YV12;
- else if (!strcmp(str_preview_format, "yuv420sp_custom"))
- hal_pixel_format = V4L2_PIX_FMT_NV12T;
- else if (!strcmp(str_preview_format, "yuv420p"))
- hal_pixel_format = V4L2_PIX_FMT_YUV420;
- else if (!strcmp(str_preview_format, "yuv422i"))
- hal_pixel_format = V4L2_PIX_FMT_YUYV;
- else if (!strcmp(str_preview_format, "yuv422p"))
- hal_pixel_format = V4L2_PIX_FMT_YUV422P;
- else
+#else
hal_pixel_format = HAL_PIXEL_FORMAT_YCrCb_420_SP;
+#endif
+ } else if (!strcmp(str_preview_format,
+ CameraParameters::PIXEL_FORMAT_YUV420P))
+ hal_pixel_format = HAL_PIXEL_FORMAT_YV12; // HACK
if (w->set_usage(w, GRALLOC_USAGE_SW_WRITE_OFTEN)) {
LOGE("%s: could not set usage on gralloc buffer", __func__);
@@ -571,25 +591,85 @@ int CameraHardwareSec::previewThread()
if (mPreviewWindow && mGrallocHal) {
buffer_handle_t *buf_handle;
- if (0 != mPreviewWindow->dequeue_buffer(mPreviewWindow, &buf_handle)) {
+ int stride;
+ if (0 != mPreviewWindow->dequeue_buffer(mPreviewWindow, &buf_handle, &stride)) {
LOGE("Could not dequeue gralloc buffer!\n");
goto callbacks;
}
-// LOGV("%s: dequeued gralloc buffer %p (%d) from preview window!\n", __func__,
-// buf_handle, index);
void *vaddr;
if (!mGrallocHal->lock(mGrallocHal,
*buf_handle,
GRALLOC_USAGE_SW_WRITE_OFTEN,
0, 0, width, height, &vaddr)) {
- LOGV("%s: vaddr [%p, %p) <-- heap [%p, %p) (base %p offset 0x%x size 0x%x)", __func__,
- vaddr, vaddr + frame_size + mFrameSizeDelta,
- ((char *)mPreviewHeap->data) + offset, ((char *)mPreviewHeap->data) + offset + frame_size + mFrameSizeDelta,
- ((char *)mPreviewHeap->data), offset, frame_size + mFrameSizeDelta);
- memcpy(vaddr,
- ((char *)mPreviewHeap->data) + offset,
- frame_size + mFrameSizeDelta);
+ char *frame = ((char *)mPreviewHeap->data) + offset;
+ int total = frame_size + mFrameSizeDelta;
+
+// HACK or no HACK, the code below assumes YUV, not RGB
+ {
+ int h;
+ char *src = frame;
+ char *ptr = (char *)vaddr;
+
+ // Copy the Y plane, while observing the stride
+ for (h = 0; h < height; h++) {
+ memcpy(ptr, src, width);
+ ptr += stride;
+ src += width;
+ }
+
+ if (HACK) {
+ // The incoming data is in NV21 format, and we need to
+ // convert it to YV12 for the gralloc buffer.
+
+ char *uv = src;
+ const int uv_size = width * height / 2;
+ char saved_uv[uv_size];
+ memcpy(saved_uv, src, uv_size);
+
+ // first, collapse the V chroma pixels into their own plane
+ // following the Y plane.
+ h = 0;
+ while (h < width * height / 4) {
+ *ptr++ = *src;
+ src += 2;
+ h++;
+ if (!(h % (width / 2)))
+ ptr += (stride - width) / 2;
+ }
+
+ // next, use the saved_uv plane and collapse the U chroma
+ // pixels into their own plane following the newly-created
+ // V plane.
+ h = 0;
+ src = saved_uv + 1;
+ while (h < width * height / 4) {
+ *ptr++ = *src;
+ src += 2;
+ h++;
+ if (!(h % (width / 2)))
+ ptr += (stride - width) / 2;
+ }
+ }
+ else {
+ // U
+ char *v = ptr;
+ ptr += stride * height / 4;
+ for (h = 0; h < height / 2; h++) {
+ memcpy(ptr, src, width / 2);
+ ptr += stride / 2;
+ src += width / 2;
+ }
+ // V
+ ptr = v;
+ for (h = 0; h < height / 2; h++) {
+ memcpy(ptr, src, width / 2);
+ ptr += stride / 2;
+ src += width / 2;
+ }
+ }
+ }
+
mGrallocHal->unlock(mGrallocHal, *buf_handle);
}
else
@@ -599,8 +679,6 @@ int CameraHardwareSec::previewThread()
LOGE("Could not enqueue gralloc buffer!\n");
goto callbacks;
}
-// LOGV("%s: enqueued gralloc buffer %p (%d) to preview window!\n", __func__,
-// buf_handle, index);
}
callbacks:
@@ -1526,10 +1604,11 @@ status_t CameraHardwareSec::setParameters(const CameraParameters& params)
else if (!strcmp(new_str_preview_format,
CameraParameters::PIXEL_FORMAT_YUV420SP))
new_preview_format = V4L2_PIX_FMT_NV21;
+ else if (!strcmp(new_str_preview_format,
+ CameraParameters::PIXEL_FORMAT_YUV420P))
+ new_preview_format = V4L2_PIX_FMT_YUV420;
else if (!strcmp(new_str_preview_format, "yuv420sp_custom"))
new_preview_format = V4L2_PIX_FMT_NV12T;
- else if (!strcmp(new_str_preview_format, "yuv420p"))
- new_preview_format = V4L2_PIX_FMT_YUV420;
else if (!strcmp(new_str_preview_format, "yuv422i"))
new_preview_format = V4L2_PIX_FMT_YUYV;
else if (!strcmp(new_str_preview_format, "yuv422p"))
@@ -2246,14 +2325,12 @@ static camera_device_t *g_cam_device;
static int HAL_camera_device_close(struct hw_device_t* device)
{
LOGI("%s", __func__);
-#if 1
if (device) {
camera_device_t *cam_device = (camera_device_t *)device;
delete static_cast<CameraHardwareSec *>(cam_device->priv);
free(cam_device);
g_cam_device = 0;
}
-#endif
return 0;
}