From 6a921d5d8b51228899a45018441fd658b73547b9 Mon Sep 17 00:00:00 2001 From: James Dong Date: Tue, 9 Aug 2011 12:34:16 -0700 Subject: Add support NV21 preview callback o always force to use YV12 for gralloc buffer, regardless preview color format (NV21 or YV12) o for NV21 preview callback, a color conversion is performed before the preview frame is returned via the callback Change-Id: I7e5fb4de40e5f615585465f9b9c50eb3521c1c57 related-to-bug: 5121691,5122253 --- libcamera/SecCameraHWInterface.cpp | 159 +++++++++++-------------------------- 1 file changed, 45 insertions(+), 114 deletions(-) (limited to 'libcamera') diff --git a/libcamera/SecCameraHWInterface.cpp b/libcamera/SecCameraHWInterface.cpp index c316ea6..34f1009 100644 --- a/libcamera/SecCameraHWInterface.cpp +++ b/libcamera/SecCameraHWInterface.cpp @@ -39,22 +39,18 @@ #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 +// FIXME: +// -- The actual preview color is set to YV12. The preview frames +// returned via preview callback must be generated by color +// conversion if the requested preview color format for the +// preview frames is _not_ YV12. The reason that YV12 is used +// for actual preview is because that is the only color format +// supported by gralloc. Matching the preview cor format with +// gralloc color format improves performance since no color +// conversion is needed for preview. // -// 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 0 +// -- we only support two preview color formats that client +// applications can set: NV21 and YUV420/YV12. namespace android { @@ -181,20 +177,13 @@ void CameraHardwareSec::initDefaultParameters(int cameraId) &snapshot_max_height) < 0) LOGE("getSnapshotMaxSize fail (%d / %d) \n", snapshot_max_width, snapshot_max_height); - -// 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 + String8 previewColorString; + previewColorString = CameraParameters::PIXEL_FORMAT_YUV420SP; + previewColorString.append(","); + previewColorString.append(CameraParameters::PIXEL_FORMAT_YUV420P); 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_SUPPORTED_PREVIEW_FORMATS, previewColorString.string()); 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); @@ -411,36 +400,12 @@ status_t CameraHardwareSec::setPreviewWindow(preview_stream_ops *w) int preview_width; int preview_height; mParameters.getPreviewSize(&preview_width, &preview_height); - - int hal_pixel_format; + int hal_pixel_format = HAL_PIXEL_FORMAT_YV12; 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; - mFrameSizeDelta = 0; - } - else if (!strcmp(str_preview_format, - CameraParameters::PIXEL_FORMAT_RGBA8888)) { - hal_pixel_format = HAL_PIXEL_FORMAT_RGBA_8888; - mFrameSizeDelta = 0; - } - else if (!strcmp(str_preview_format, - CameraParameters::PIXEL_FORMAT_YUV420SP)) { -#if HACK - hal_pixel_format = HAL_PIXEL_FORMAT_YV12; -#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__); return INVALID_OPERATION; @@ -601,7 +566,7 @@ int CameraHardwareSec::previewThread() char *frame = ((char *)mPreviewHeap->data) + offset; int total = frame_size + mFrameSizeDelta; -// HACK or no HACK, the code below assumes YUV, not RGB + // the code below assumes YUV, not RGB { int h; char *src = frame; @@ -614,40 +579,7 @@ int CameraHardwareSec::previewThread() 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; @@ -679,8 +611,26 @@ int CameraHardwareSec::previewThread() callbacks: // Notify the client of a new frame. - if (mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME) + if (mMsgEnabled & CAMERA_MSG_PREVIEW_FRAME) { + const char * preview_format = mParameters.getPreviewFormat(); + if (!strcmp(preview_format, CameraParameters::PIXEL_FORMAT_YUV420SP)) { + // Color conversion from YUV420 to NV21 + char *vu = ((char *)mPreviewHeap->data) + offset + width * height; + const int uv_size = (width * height) >> 1; + char saved_uv[uv_size]; + memcpy(saved_uv, vu, uv_size); + char *u = saved_uv; + char *v = u + (uv_size >> 1); + + int h = 0; + while (h < width * height / 4) { + *vu++ = *v++; + *vu++ = *u++; + ++h; + } + } mDataCb(CAMERA_MSG_PREVIEW_FRAME, mPreviewHeap, index, NULL, mCallbackCookie); + } Mutex::Autolock lock(mRecordLock); if (mRecordRunning == true) { @@ -1615,36 +1565,17 @@ status_t CameraHardwareSec::setParameters(const CameraParameters& params) LOGV("%s : new_preview_width x new_preview_height = %dx%d, format = %s", __func__, new_preview_width, new_preview_height, new_str_preview_format); + if (strcmp(new_str_preview_format, CameraParameters::PIXEL_FORMAT_YUV420SP) && + strcmp(new_str_preview_format, CameraParameters::PIXEL_FORMAT_YUV420P)) { + LOGE("Unsupported preview color format: %s", new_str_preview_format); + return BAD_VALUE; + } + if (0 < new_preview_width && 0 < new_preview_height && new_str_preview_format != NULL && isSupportedPreviewSize(new_preview_width, new_preview_height)) { - int new_preview_format = 0; - + int new_preview_format = V4L2_PIX_FMT_YUV420; mFrameSizeDelta = 16; - if (!strcmp(new_str_preview_format, - CameraParameters::PIXEL_FORMAT_RGB565)) { - new_preview_format = V4L2_PIX_FMT_RGB565; - mFrameSizeDelta = 0; - } - else if (!strcmp(new_str_preview_format, - CameraParameters::PIXEL_FORMAT_RGBA8888)) { - new_preview_format = V4L2_PIX_FMT_RGB32; - mFrameSizeDelta = 0; - } - 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, "yuv422i")) - new_preview_format = V4L2_PIX_FMT_YUYV; - else if (!strcmp(new_str_preview_format, "yuv422p")) - new_preview_format = V4L2_PIX_FMT_YUV422P; - else - new_preview_format = V4L2_PIX_FMT_NV21; //for 3rd party int current_preview_width, current_preview_height, current_frame_size; mSecCamera->getPreviewSize(¤t_preview_width, -- cgit v1.1