From: jinhyung.jo Date: Tue, 9 Apr 2013 06:05:06 +0000 (+0900) Subject: maru_camera : Sends a black frame or a previously successful frame to guest when... X-Git-Tag: Tizen_Studio_1.3_Release_p2.3.1~1020 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=818a27f003d29ed1f41159f109a50e95f7e373e9;p=sdk%2Femulator%2Fqemu.git maru_camera : Sends a black frame or a previously successful frame to guest when webcam is blocked. Sends a black frame or a previously successful frame to guest when webcam is blocked. Signed-off-by: Jinhyung Jo --- diff --git a/tizen/src/hw/maru_camera_linux_pci.c b/tizen/src/hw/maru_camera_linux_pci.c index be5dc6c6ca..08cba88089 100644 --- a/tizen/src/hw/maru_camera_linux_pci.c +++ b/tizen/src/hw/maru_camera_linux_pci.c @@ -47,7 +47,6 @@ MULTI_DEBUG_CHANNEL(tizen, camera_linux); #define CLEAR(x) memset(&(x), 0, sizeof(x)) #define MARUCAM_DEFAULT_BUFFER_COUNT 4 -#define MARUCAM_DUMMYFRAME_COUNT 2 #define MARUCAM_CTRL_VALUE_MAX 20 #define MARUCAM_CTRL_VALUE_MIN 1 @@ -65,7 +64,18 @@ typedef struct marucam_framebuffer { size_t size; } marucam_framebuffer; +struct marucam_saved_frame { + void *data; + uint32_t pixelformat; + uint32_t width; + uint32_t height; + uint32_t size; +}; + +static struct marucam_saved_frame saved_frame; +static char has_success_frame; static int n_framebuffer; +static int previous_frame_index = -1; static struct marucam_framebuffer *framebuffer; static const char *dev_name = "/dev/video0"; @@ -76,6 +86,28 @@ static int timeout_n; static struct v4l2_format dst_fmt; +static void ScalePlaneSimple(int src_width, int src_height, + int dst_width, int dst_height, + int src_stride, int dst_stride, + const uint8_t *src_ptr, uint8_t *dst_ptr) { + int i, j; + int dx = (src_width << 16) / dst_width; + int dy = (src_height << 16) / dst_height; + int y = (dy >= 65536) ? ((dy >> 1) - 32768) : (dy >> 1); + for (j = 0; j < dst_height; ++j) { + int x = (dx >= 65536) ? ((dx >> 1) - 32768) : (dx >> 1); + int yi = y >> 16; + const uint8_t *src = src_ptr + yi * src_stride; + uint8_t *dst = dst_ptr; + for (i = 0; i < dst_width; ++i) { + *dst++ = src[x >> 16]; + x += dx; + } + dst_ptr += dst_stride; + y += dy; + } +} + static void make_yu12_black(unsigned char *dest, uint32_t width, uint32_t height) { uint32_t x, y; @@ -99,6 +131,35 @@ static void make_yu12_black(unsigned char *dest, uint32_t width, uint32_t height } } +static void marucam_scale_yuv420(void *src, + uint32_t src_width, uint32_t src_height, + void *dst, uint32_t dst_width, uint32_t dst_height) +{ + uint32_t src_halfwidth = (src_width + 1) >> 1; + uint32_t src_halfheight = (src_height + 1) >> 1; + uint32_t dst_halfwidth = (dst_width + 1) >> 1; + uint32_t dst_halfheight = (dst_height + 1) >> 1; + + uint8_t *src_u = src + (src_width * src_height); + uint8_t *src_v = src_u + (src_width * src_height / 4); + + uint8_t *dst_u = dst + (dst_width * dst_height); + uint8_t *dst_v = dst_u + (dst_width * dst_height /4); + + ScalePlaneSimple(src_width, src_height, + dst_width, dst_height, + src_width, dst_width, + src, dst); + ScalePlaneSimple(src_halfwidth, src_halfheight, + dst_halfwidth, dst_halfheight, + src_halfwidth, dst_halfwidth, + src_u, dst_u); + ScalePlaneSimple(src_halfwidth, src_halfheight, + dst_halfwidth, dst_halfheight, + src_halfwidth, dst_halfwidth, + src_v, dst_v); +} + static int yioctl(int fd, int req, void *arg) { int r; @@ -324,6 +385,7 @@ static void free_framebuffers(marucam_framebuffer *fb, int buf_num) ERR("framebuffer[%d].data is NULL.\n", i); } } + previous_frame_index = -1; } static uint32_t @@ -410,15 +472,33 @@ static int is_stream_paused(MaruCamState *state) } /* sends a frame, YU12/black color */ -static void __raise_empty_intr(MaruCamState *state) +/* TODO: add other pixel format method */ +static void __raise_dummy_intr(MaruCamState *state) { void *buf = NULL; qemu_mutex_lock(&state->thread_mutex); if (state->streamon == _MC_THREAD_STREAMON && state->req_frame) { buf = state->vaddr + state->buf_size * (state->req_frame - 1); - make_yu12_black(buf, dst_fmt.fmt.pix.width, dst_fmt.fmt.pix.height); + if (saved_frame.data) { + if (saved_frame.width == dst_fmt.fmt.pix.width && + saved_frame.height == dst_fmt.fmt.pix.height) { + TRACE("Copies the previuos frame\n"); + memcpy(buf, saved_frame.data, state->buf_size); + } else { + TRACE("Resizes the previous frame\n"); + marucam_scale_yuv420(saved_frame.data, saved_frame.width, + saved_frame.height, + buf, dst_fmt.fmt.pix.width, + dst_fmt.fmt.pix.height); + } + } else { + TRACE("Sends a black frame\n"); + make_yu12_black(buf, + dst_fmt.fmt.pix.width, + dst_fmt.fmt.pix.height); + } state->req_frame = 0; /* clear request */ - state->isr = 0x01; /* set a flag of raising a interrupt */ + state->isr |= 0x01; /* set a flag of raising a interrupt */ qemu_bh_schedule(state->tx_bh); } qemu_mutex_unlock(&state->thread_mutex); @@ -436,7 +516,7 @@ static void __raise_err_intr(MaruCamState *state) } static void -notify_buffer_ready(MaruCamState *state, void *ptr, size_t size) +notify_buffer_ready(MaruCamState *state, uint32_t buf_index) { void *buf = NULL; @@ -455,7 +535,9 @@ notify_buffer_ready(MaruCamState *state, void *ptr, size_t size) return; } buf = state->vaddr + state->buf_size * (state->req_frame - 1); - memcpy(buf, ptr, state->buf_size); + memcpy(buf, framebuffer[buf_index].data, state->buf_size); + previous_frame_index = buf_index; + has_success_frame = 1; state->req_frame = 0; /* clear request */ state->isr |= 0x01; /* set a flag of rasing a interrupt */ qemu_bh_schedule(state->tx_bh); @@ -490,7 +572,7 @@ static int read_frame(MaruCamState *state) } } - notify_buffer_ready(state, framebuffer[buf.index].data, buf.bytesused); + notify_buffer_ready(state, buf.index); if (xioctl(v4l2_fd, VIDIOC_QBUF, &buf) < 0) { ERR("QBUF error: %s\n", strerror(errno)); @@ -523,12 +605,18 @@ static int __v4l2_streaming(MaruCamState *state) } else if (!ret) { timeout_n++; ERR("Select timed out: count(%u)\n", timeout_n); - if (ready_count == 0) { - if (timeout_n <= MARUCAM_DUMMYFRAME_COUNT) { + if (ready_count <= MARUCAM_SKIPFRAMES) { + switch (timeout_n) { + case 1: + ERR("Waiting for reading a frame data\n"); + return 0; + case 2: + case 3: + case 4: ERR("Sends dummy data to initialize the camera\n"); - __raise_empty_intr(state); + __raise_dummy_intr(state); return 0; - } else { + default: ERR("Webcam is busy, failed to a read frame." " Raises an error\n"); __raise_err_intr(state); @@ -540,6 +628,10 @@ static int __v4l2_streaming(MaruCamState *state) __raise_err_intr(state); return -1; } + if (previous_frame_index != -1) { + ERR("Sends previous frame data\n"); + notify_buffer_ready(state, previous_frame_index); + } return 0; } @@ -582,6 +674,7 @@ static void *marucam_worker_thread(void *thread_param) convert_trial = 10; ready_count = 0; timeout_n = 0; + has_success_frame = 0; qemu_mutex_lock(&state->thread_mutex); state->streamon = _MC_THREAD_STREAMON; qemu_mutex_unlock(&state->thread_mutex); @@ -843,6 +936,21 @@ void marucam_device_stop_preview(MaruCamState *state) } } + if (has_success_frame) { + saved_frame.width = dst_fmt.fmt.pix.width; + saved_frame.height = dst_fmt.fmt.pix.height; + saved_frame.size = dst_fmt.fmt.pix.sizeimage; + if (saved_frame.data) { + g_free(saved_frame.data); + saved_frame.data = NULL; + } + saved_frame.data = (void *)g_malloc0(saved_frame.size); + memcpy(saved_frame.data, + framebuffer[previous_frame_index].data, + saved_frame.size); + TRACE("Saves a frame data\n"); + } + param->errCode = stop_capturing(); if (framebuffer != NULL) { free_framebuffers(framebuffer, n_framebuffer); @@ -1242,6 +1350,12 @@ void marucam_device_close(MaruCamState *state) marucam_reset_controls(); + if (saved_frame.data) { + g_free(saved_frame.data); + saved_frame.data = NULL; + } + memset(&saved_frame, 0x00, sizeof(saved_frame)); + v4l2_close(v4l2_fd); v4l2_fd = 0; INFO("Closed\n");