From: Jeongmo Yang Date: Fri, 15 Nov 2024 11:37:13 +0000 (+0900) Subject: Update functions X-Git-Tag: accepted/tizen/unified/20250610.081745~15 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=afc3a028a820de8761e1656a4af297a34020c352;p=platform%2Fhal%2Fbackend%2Fcodec-v4l2.git Update functions 1. Implement decode(). 2. Rename internal functions. 3. Handle buffers for input and output. Signed-off-by: Jeongmo Yang --- diff --git a/packaging/hal-backend-codec-v4l2.spec b/packaging/hal-backend-codec-v4l2.spec index 5b502c1..d4cc836 100644 --- a/packaging/hal-backend-codec-v4l2.spec +++ b/packaging/hal-backend-codec-v4l2.spec @@ -1,6 +1,8 @@ +%define disable_hal_rootstrap_checker 1 + Name: hal-backend-codec-v4l2 Summary: Tizen Codec HAL using generic V4L2 interface -Version: 1.0.0 +Version: 0.0.1 Release: 0 Group: Multimedia/Libraries License: Apache-2.0 diff --git a/src/hal_backend_codec_v4l2.c b/src/hal_backend_codec_v4l2.c index 840c44e..c88471f 100644 --- a/src/hal_backend_codec_v4l2.c +++ b/src/hal_backend_codec_v4l2.c @@ -33,8 +33,8 @@ #include #include #include +#include #include "hal_backend_codec_v4l2_private.h" -#include #ifdef LOG_TAG #undef LOG_TAG @@ -67,17 +67,39 @@ (fourcc >> 16) & 0xff,\ (fourcc >> 24) & 0xff -#define DEVICE_TYPE_MAX (CODEC_TYPE_ENCODER + 1) +#define DEVICE_TYPE_MAX (HAL_CODEC_TYPE_ENCODER + 1) #define DEVICE_NODE_PATH_LENGTH_MAX 32 #define DEVICE_MAX 8 #define DEVICE_FORMAT_MAX 16 #define ERROR_STRING_LENGTH 64 +#define IDLE_BUFFER_INDEX_INIT -1 +#define IDLE_BUFFER_TIME_OUT_MS 1000 +#define NSEC_PER_SEC (G_USEC_PER_SEC * 1000) +#define OUTPUT_POLL_TIMEOUT_MS 3000 +#define POLL_ERROR_TRY_COUNT_MAX 3 +#define POLL_ERROR_TRY_SLEEP_US 100000 + + +#define TIMESTAMP_TO_TIMEVAL(timestamp, timeval) \ + do { \ + timeval.tv_sec = (glong)(timestamp / NSEC_PER_SEC); \ + timeval.tv_usec = (glong)((timestamp % NSEC_PER_SEC) / 1000); \ + } while (0) + +#define TIMEVAL_TO_TIMESTAMP(timeval, timestamp) \ + do { \ + timestamp = timeval.tv_sec * NSEC_PER_SEC; \ + timestamp += timeval.tv_usec * 1000; \ + } while (0) + +#define CODEC_THREAD_NAME_HANDLE_BUFFER "handle_buffer" + typedef struct _codec_v4l2_format_list_s { uint32_t count; enum v4l2_buf_type buf_type; - codec_format_type_e format_type; - codec_format_e formats[DEVICE_FORMAT_MAX]; + hal_codec_format_type_e format_type; + hal_codec_format_e formats[DEVICE_FORMAT_MAX]; } codec_v4l2_format_list_s; typedef struct _codec_v4l2_device_s { @@ -96,8 +118,8 @@ typedef struct _codec_v4l2_device_list_s { /* global variables */ static codec_v4l2_device_list_s *g_codec_device_list; static char *g_decoder_type_string[DEVICE_TYPE_MAX] = { - [CODEC_TYPE_DECODER] = "DECODER", - [CODEC_TYPE_ENCODER] = "ENCODER" + [HAL_CODEC_TYPE_DECODER] = "DECODER", + [HAL_CODEC_TYPE_ENCODER] = "ENCODER" }; @@ -105,15 +127,28 @@ static char *g_decoder_type_string[DEVICE_TYPE_MAX] = { static void __codec_v4l2_constructor(void) __attribute__((constructor)); static void __codec_v4l2_destructor(void) __attribute__((destructor)); +static void __codec_v4l2_release_handle(codec_hal_handle_s *handle); + static int __codec_v4l2_probe_device(void); static void __codec_v4l2_release_device_list(void); -static void __codec_init_buffer_control(codec_buffer_control_s *buffer_control); -static void __codec_deinit_buffer_control(codec_buffer_control_s *buffer_control); +static void __codec_v4l2_init_buffer_control(codec_hal_handle_s *handle); +static void __codec_v4l2_deinit_buffer_control(codec_hal_handle_s *handle); + +static void *__codec_v4l2_message_handler_func(gpointer data); +static void __codec_v4l2_message_release_func(gpointer data); +static void __codec_v4l2_message_send(codec_hal_handle_s *handle, hal_codec_message_type_e type, gpointer value); + +static int __codec_v4l2_start_stream(codec_hal_handle_s *handle, codec_hal_buffer_control_s *buffer_control, uint32_t buffer_count); +static int __codec_v4l2_stop_stream(codec_hal_handle_s *handle); + +static int __codec_v4l2_set_command(codec_hal_handle_s *handle, int64_t command, void *value); + +static hal_codec_buffer_s *__codec_v4l2_get_idle_buffer(codec_hal_buffer_control_s *buffer_control, gint64 timeout_ms); +static void __codec_v4l2_add_idle_buffer(codec_hal_buffer_control_s *buffer_control, hal_codec_buffer_s *buffer); -static int __codec_v4l2_get_format(guint32 fourcc, codec_format_e *format); -static int __codec_get_fourcc_plane_num(codec_format_e format, uint32_t *fourcc, uint32_t *plane_num); -static void __codec_v4l2_send_message(hal_codec_handle_s *handle, codec_message_type_e type, int value); +static int __codec_v4l2_get_format(guint32 fourcc, hal_codec_format_e *format); +static int __codec_get_fourcc_plane_num(hal_codec_format_e format, uint32_t *fourcc, uint32_t *plane_num); @@ -137,7 +172,7 @@ static void __codec_v4l2_get_supported_format_list(int device_fd, { int index = 0; uint32_t count = 0; - codec_format_e format = CODEC_FORMAT_H264; + hal_codec_format_e format = HAL_CODEC_FORMAT_H264; struct v4l2_fmtdesc fmtdesc; if (device_fd < 0 || !format_list) { @@ -158,14 +193,14 @@ static void __codec_v4l2_get_supported_format_list(int device_fd, break; } - if (__codec_v4l2_get_format(fmtdesc.pixelformat, &format) == CODEC_ERROR_NONE) { + if (__codec_v4l2_get_format(fmtdesc.pixelformat, &format) == HAL_CODEC_ERROR_NONE) { format_list->formats[count] = format; count++; - if (format & CODEC_FORMAT_TYPE_ENCODED) - format_list->format_type = CODEC_FORMAT_TYPE_ENCODED; + if (format & HAL_CODEC_FORMAT_TYPE_ENCODED) + format_list->format_type = HAL_CODEC_FORMAT_TYPE_ENCODED; else - format_list->format_type = CODEC_FORMAT_TYPE_RAW; + format_list->format_type = HAL_CODEC_FORMAT_TYPE_RAW; } } @@ -194,16 +229,16 @@ static int __codec_v4l2_probe_device(void) switch (ret) { case GLOB_NOSPACE: LOGE("out of memory"); - return CODEC_ERROR_OUT_OF_MEMORY; + return HAL_CODEC_ERROR_OUT_OF_MEMORY; case GLOB_ABORTED: LOGE("read error"); - return CODEC_ERROR_INTERNAL; + return HAL_CODEC_ERROR_INTERNAL; case GLOB_NOMATCH: LOGE("match not found"); - return CODEC_ERROR_INTERNAL; + return HAL_CODEC_ERROR_INTERNAL; default: LOGE("unknown error[%d]", ret); - return CODEC_ERROR_INTERNAL; + return HAL_CODEC_ERROR_INTERNAL; } } @@ -265,10 +300,10 @@ static int __codec_v4l2_probe_device(void) close(device_fd); if (codec_device->in_format.count > 0 && codec_device->out_format.count > 0 && - ((codec_device->in_format.format_type == CODEC_FORMAT_TYPE_ENCODED && - codec_device->out_format.format_type == CODEC_FORMAT_TYPE_RAW) || - (codec_device->in_format.format_type == CODEC_FORMAT_TYPE_RAW && - codec_device->out_format.format_type == CODEC_FORMAT_TYPE_ENCODED))) { + ((codec_device->in_format.format_type == HAL_CODEC_FORMAT_TYPE_ENCODED && + codec_device->out_format.format_type == HAL_CODEC_FORMAT_TYPE_RAW) || + (codec_device->in_format.format_type == HAL_CODEC_FORMAT_TYPE_RAW && + codec_device->out_format.format_type == HAL_CODEC_FORMAT_TYPE_ENCODED))) { strncpy(codec_device->node_path, glob_buf.gl_pathv[i], DEVICE_NODE_PATH_LENGTH_MAX - 1); codec_device->capabilities = device_caps; @@ -295,7 +330,7 @@ static int __codec_v4l2_probe_device(void) g_codec_device_list = NULL; } - return CODEC_ERROR_NONE; + return HAL_CODEC_ERROR_NONE; } @@ -334,7 +369,7 @@ static void __codec_v4l2_release_device_list(void) } -static int __codec_v4l2_get_buf_type_and_node_path(codec_format_e in_format, codec_format_e out_format, +static int __codec_v4l2_get_buf_type_and_node_path(hal_codec_format_e in_format, hal_codec_format_e out_format, enum v4l2_buf_type *in_buf_type, enum v4l2_buf_type *out_buf_type, char **path) { uint32_t device_index = 0; @@ -344,12 +379,12 @@ static int __codec_v4l2_get_buf_type_and_node_path(codec_format_e in_format, cod if (!g_codec_device_list) { LOGE("no codec device list"); - return CODEC_ERROR_INTERNAL; + return HAL_CODEC_ERROR_INTERNAL; } if (!path || !in_buf_type || !out_buf_type) { LOGE("NULL param [%p,%p,%p]", path, in_buf_type, out_buf_type); - return CODEC_ERROR_INVALID_PARAMETER; + return HAL_CODEC_ERROR_INVALID_PARAMETER; } for (device_index = 0 ; device_index < g_codec_device_list->count ; device_index++) { @@ -382,20 +417,20 @@ static int __codec_v4l2_get_buf_type_and_node_path(codec_format_e in_format, cod LOGI("found node path[%s], buf_type[in:%d, out:%d] for format[in:0x%x, out:0x%x]", *path, *in_buf_type, *out_buf_type, in_format, out_format); - return CODEC_ERROR_NONE; + return HAL_CODEC_ERROR_NONE; } } } LOGE("node path not found for format[in:%d,out:%d]", in_format, out_format); - return CODEC_ERROR_NOT_SUPPORTED; + return HAL_CODEC_ERROR_NOT_SUPPORTED; } -static void __codec_v4l2_send_message(hal_codec_handle_s *handle, codec_message_type_e type, int value) +static void __codec_v4l2_message_send(codec_hal_handle_s *handle, hal_codec_message_type_e type, gpointer value) { - codec_message_s *message = NULL; + hal_codec_message_s *message = NULL; g_autoptr(GMutexLocker) locker = NULL; if (!handle) { @@ -403,73 +438,34 @@ static void __codec_v4l2_send_message(hal_codec_handle_s *handle, codec_message_ return; } + message = g_new0(hal_codec_message_s, 1); + message->type = type; + locker = g_mutex_locker_new(&handle->msg_cb_lock); switch (type) { - case CODEC_MESSAGE_TYPE_INPUT_BUFFER_USED: + case HAL_CODEC_MESSAGE_TYPE_INPUT_BUFFER_USED: + message->buffer = (hal_codec_buffer_s *)value; + LOGD("InputBufferUsed : buffer[i:%d] %p", message->buffer->index, message->buffer); break; - case CODEC_MESSAGE_TYPE_OUTPUT_BUFFER: + case HAL_CODEC_MESSAGE_TYPE_OUTPUT_BUFFER: + message->buffer = (hal_codec_buffer_s *)value; + LOGD("OutputBuffer : buffer[i:%d] %p", message->buffer->index, message->buffer); break; - case CODEC_MESSAGE_TYPE_RESOLUTION_CHANGED: + case HAL_CODEC_MESSAGE_TYPE_RESOLUTION_CHANGED: break; - case CODEC_MESSAGE_TYPE_ERROR: - message->error_code = (codec_error_e)value; + case HAL_CODEC_MESSAGE_TYPE_ERROR: + message->error_code = GPOINTER_TO_INT(value); + LOGE("error code[%d]", message->error_code); break; default: LOGW("unhandled type[%d]", type); + g_free(message); return; } - message = g_new0(codec_message_s, 1); - - message->type = type; - - LOGD("type[%d], value[0x%x]", type, value); - g_queue_push_tail(handle->msg_list, message); - g_cond_signal(&handle->msg_cb_cond); -} - - -static int __codec_v4l2_wait_frame(int device_fd, int wait_time) -{ - int ret = CODEC_ERROR_NONE; - fd_set fds; - struct timeval timeout; - - if (device_fd < 0) { - LOGE("invalid fd %d", device_fd); - return CODEC_ERROR_INVALID_PARAMETER; - } - - FD_ZERO(&fds); - FD_SET(device_fd, &fds); - - memset(&timeout, 0x0, sizeof(struct timeval)); - - timeout.tv_sec = wait_time; - timeout.tv_usec = 0; - - /*LOGD("select : %d sec", wait_time);*/ - - ret = select(device_fd + 1, &fds, NULL, NULL, &timeout); - if (ret == -1) { - if (EINTR == errno) { - LOGD("select error : EINTR"); - return CODEC_ERROR_NONE; - } - LOGE("select failed. errno %d", errno); - return CODEC_ERROR_INTERNAL; - } - - if (ret == 0) { - LOGE("select timeout."); - return CODEC_ERROR_INTERNAL; - } - - /*LOGD("select done");*/ - - return CODEC_ERROR_NONE; + g_cond_broadcast(&handle->msg_cb_cond); } @@ -480,7 +476,7 @@ static int __codec_v4l2_g_ctrl(int device_fd, int cid, int *value) if (!value) { LOGE("NULL param"); - return CODEC_ERROR_INVALID_PARAMETER; + return HAL_CODEC_ERROR_INVALID_PARAMETER; } memset(&ctrl, 0x0, sizeof(struct v4l2_control)); @@ -516,75 +512,92 @@ static int __codec_v4l2_s_ctrl(int device_fd, int cid, int value) } -static int __codec_v4l2_s_fmt(codec_buffer_control_s *buffer_control, - int device_fd, codec_format_e format, enum v4l2_buf_type buf_type, - int width, int height) +static int __codec_v4l2_set_config(codec_hal_buffer_control_s *buffer_control, + enum v4l2_buf_type buf_type, enum v4l2_memory memory, + hal_codec_format_e format, int width, int height) +{ + codec_hal_config_s *codec_config = NULL; + + if (!buffer_control) { + LOGE("NULL control"); + return HAL_CODEC_ERROR_INVALID_PARAMETER; + } + + codec_config = &buffer_control->config; + + LOGI("type[%d] v4l2[buf type:%d, memory:%d], format[0x%x], resolution[%dx%d]", + buffer_control->type, buf_type, memory, format, width, height); + + codec_config->buf_type = buf_type; + codec_config->memory = memory; + codec_config->format = format; + codec_config->resolution.width = width; + codec_config->resolution.height = height; + + return HAL_CODEC_ERROR_NONE; +} + + +static int __codec_v4l2_s_fmt(codec_hal_buffer_control_s *buffer_control, int device_fd) { int i = 0; uint32_t fourcc = 0; - uint32_t plane_num = 0; + uint32_t num_planes = 0; + codec_hal_config_s *codec_config = NULL; + codec_hal_buffer_control_type_e type; struct v4l2_format v4l2_fmt; - codec_buffer_s *codec_buffer = NULL; if (!buffer_control) { - LOGE("NULL buffer control"); - return CODEC_ERROR_INVALID_PARAMETER; + LOGE("NULL control"); + return HAL_CODEC_ERROR_INVALID_PARAMETER; } - memset(&v4l2_fmt, 0x0, sizeof(struct v4l2_format)); + codec_config = &buffer_control->config; + type = buffer_control->type; - LOGI("S_FMT : format[0x%x], buf_type[%d], resolution[%dx%d]", - format, buf_type, width, height); - - if (__codec_get_fourcc_plane_num(format, &fourcc, &plane_num) != CODEC_ERROR_NONE) { - LOGE("get fourcc failed for format [0x%x]", format); - return CODEC_ERROR_INVALID_PARAMETER; + if (__codec_get_fourcc_plane_num(codec_config->format, &fourcc, &num_planes) != HAL_CODEC_ERROR_NONE) { + LOGE("type[%d] get fourcc failed for format [0x%x]", type, codec_config->format); + return HAL_CODEC_ERROR_INVALID_PARAMETER; } + codec_config->num_planes = num_planes; + memset(&v4l2_fmt, 0x0, sizeof(struct v4l2_format)); - v4l2_fmt.type = buf_type; - if (V4L2_TYPE_IS_MULTIPLANAR(buf_type)) { - v4l2_fmt.fmt.pix_mp.width = width; - v4l2_fmt.fmt.pix_mp.height = height; + v4l2_fmt.type = codec_config->buf_type; + + if (V4L2_TYPE_IS_MULTIPLANAR(codec_config->buf_type)) { + v4l2_fmt.fmt.pix_mp.width = codec_config->resolution.width; + v4l2_fmt.fmt.pix_mp.height = codec_config->resolution.height; v4l2_fmt.fmt.pix_mp.pixelformat = fourcc; - v4l2_fmt.fmt.pix_mp.num_planes = plane_num; + v4l2_fmt.fmt.pix_mp.num_planes = num_planes; } else { - v4l2_fmt.fmt.pix.width = width; - v4l2_fmt.fmt.pix.height = height; + v4l2_fmt.fmt.pix.width = codec_config->resolution.width; + v4l2_fmt.fmt.pix.height = codec_config->resolution.height; v4l2_fmt.fmt.pix.pixelformat = fourcc; - v4l2_fmt.fmt.pix.bytesperline = width; + v4l2_fmt.fmt.pix.bytesperline = codec_config->resolution.width; } if (ioctl(device_fd, VIDIOC_S_FMT, &v4l2_fmt) < 0) { - LOGE("S_FMT failed. errno %d", errno); - return CODEC_ERROR_INTERNAL; + LOGE("type[%d] S_FMT failed. errno %d", type, errno); + return HAL_CODEC_ERROR_INTERNAL; } - codec_buffer = &buffer_control->buffers[0]; - - codec_buffer->format = format; - codec_buffer->resolution.width = width; - codec_buffer->resolution.height = height; - codec_buffer->num_planes = plane_num; - - codec_buffer->total_size = 0; - - if (V4L2_TYPE_IS_MULTIPLANAR(buf_type)) { + if (V4L2_TYPE_IS_MULTIPLANAR(codec_config->buf_type)) { for (i = 0 ; i < v4l2_fmt.fmt.pix_mp.num_planes ; i++) { - codec_buffer->planes[i].size = v4l2_fmt.fmt.pix_mp.plane_fmt[i].sizeimage; - codec_buffer->total_size += codec_buffer->planes[i].size; - LOGI(" plane[%d] size [%u]", i, codec_buffer->planes[i].size); + LOGI("type[%d] plane[%d] size [%u]", + type, i, v4l2_fmt.fmt.pix_mp.plane_fmt[i].sizeimage); + codec_config->buffer_size += v4l2_fmt.fmt.pix_mp.plane_fmt[i].sizeimage; } } else { /* TODO: get size of each plane */ - codec_buffer->total_size = v4l2_fmt.fmt.pix.sizeimage; + codec_config->buffer_size = v4l2_fmt.fmt.pix.sizeimage; } - LOGI("format[0x%x], resolution[%dx%d] buffer size[%u]", - format, width, height, codec_buffer->total_size); + LOGI("type[%d] buffer size[%u], num planes[%u]", + type, codec_config->buffer_size, codec_config->num_planes); - return CODEC_ERROR_NONE; + return HAL_CODEC_ERROR_NONE; } @@ -592,17 +605,17 @@ static int __codec_v4l2_stream(int device_fd, int type, gboolean onoff) { if (device_fd < 0) { LOGE("invalid fd %d", device_fd); - return CODEC_ERROR_INVALID_PARAMETER; + return HAL_CODEC_ERROR_INVALID_PARAMETER; } if (ioctl(device_fd, onoff ? VIDIOC_STREAMON : VIDIOC_STREAMOFF, &type) < 0) { LOGE("stream %d failed. [t:%d] errno %d", onoff, type, errno); - return CODEC_ERROR_INTERNAL; + return HAL_CODEC_ERROR_INTERNAL; } LOGD("stream %d done [t:%d]", onoff, type); - return CODEC_ERROR_NONE; + return HAL_CODEC_ERROR_NONE; } @@ -612,10 +625,10 @@ static int __codec_v4l2_reqbufs(int device_fd, int type, int memory, uint32_t co if (device_fd < 0) { LOGE("invalid fd %d", device_fd); - return CODEC_ERROR_INVALID_PARAMETER; + return HAL_CODEC_ERROR_INVALID_PARAMETER; } - LOGI("type[%d], memory[%d], count[%u]", type, memory, count); + LOGI("type[%d] memory[%d], count[%u]", type, memory, count); memset(&v4l2_reqbuf, 0x0, sizeof(struct v4l2_requestbuffers)); @@ -625,7 +638,7 @@ static int __codec_v4l2_reqbufs(int device_fd, int type, int memory, uint32_t co if (ioctl(device_fd, VIDIOC_REQBUFS, &v4l2_reqbuf) < 0) { LOGE("REQBUFS[count %d] failed. errno %d", count, errno); - return CODEC_ERROR_INTERNAL; + return HAL_CODEC_ERROR_INTERNAL; } if (v4l2_reqbuf.count != count) @@ -634,461 +647,487 @@ static int __codec_v4l2_reqbufs(int device_fd, int type, int memory, uint32_t co if (result_count) *result_count = v4l2_reqbuf.count; - return CODEC_ERROR_NONE; + return HAL_CODEC_ERROR_NONE; } -static int __codec_v4l2_qbuf(int device_fd, int type, int memory, int index, int dmabuf_fd) +static int __codec_v4l2_qbuf(int device_fd, + codec_hal_buffer_control_s *buffer_control, + hal_codec_buffer_s *codec_buffer) { + uint32_t i = 0; + + codec_hal_config_s *codec_config = NULL; + hal_codec_memory_s *codec_memory = NULL; + struct v4l2_buffer v4l2_buf; struct v4l2_plane v4l2_planes[V4L2_PLANES_MAX]; - if (device_fd < 0) { - LOGE("invalid fd %d", device_fd); - return CODEC_ERROR_INVALID_PARAMETER; + if (device_fd < 0 || !buffer_control || !codec_buffer) { + LOGE("invalid device fd[%d]/buffer control[%p]/codec buffer[%p]", + device_fd, buffer_control, codec_buffer); + return HAL_CODEC_ERROR_INVALID_PARAMETER; } + codec_config = &buffer_control->config; + codec_memory = &codec_buffer->memory; + memset(&v4l2_buf, 0x0, sizeof(struct v4l2_buffer)); memset(v4l2_planes, 0x0, sizeof(v4l2_planes)); - v4l2_buf.index = index; - v4l2_buf.type = type; - v4l2_buf.memory = memory; + v4l2_buf.index = codec_buffer->index; + v4l2_buf.type = codec_config->buf_type; + v4l2_buf.memory = codec_config->memory; v4l2_buf.m.planes = v4l2_planes; - v4l2_buf.length = 1; - if (dmabuf_fd > CODEC_HAL_INITIAL_FD) { - if (V4L2_TYPE_IS_MULTIPLANAR(type)) - v4l2_buf.m.planes[0].m.fd = dmabuf_fd; - else - v4l2_buf.m.fd = dmabuf_fd; + if (codec_config->memory == V4L2_MEMORY_DMABUF) { + if (codec_memory->num_fd == 0 || + codec_memory->num_fd > HAL_CODEC_BUFFER_PLANE_MAX) { + LOGE("invalid num_fd[%u]", codec_memory->num_fd); + return HAL_CODEC_ERROR_INVALID_PARAMETER; + } + + if (V4L2_TYPE_IS_MULTIPLANAR(codec_config->buf_type)) { + for (i = 0 ; i < codec_memory->num_fd ; i++) { + LOGD("plane[%d] fd %d", i, codec_memory->fd[i]); + v4l2_buf.m.planes[i].m.fd = codec_memory->fd[i]; + } + } else { + if (codec_memory->num_fd != 1) + LOGW("invalid num_fd[%u]", codec_memory->num_fd); + + v4l2_buf.m.fd = codec_memory->fd[0]; + } + + v4l2_buf.length = codec_memory->num_fd; + } else { + /* V4L2_MEMORY_MMAP */ + v4l2_buf.length = 1; + } + + if (codec_buffer->meta.timestamp > 0) { + TIMESTAMP_TO_TIMEVAL(codec_buffer->meta.timestamp, v4l2_buf.timestamp); + LOGD("timeval sec:%lu, usec:%lu", v4l2_buf.timestamp.tv_sec, v4l2_buf.timestamp.tv_usec); } if (ioctl(device_fd, VIDIOC_QBUF, &v4l2_buf) < 0) { - LOGE("qbuf failed. [i: %d, t: %d, m: %d] errno %d", - index, type, memory, errno); - return CODEC_ERROR_INTERNAL; + LOGE("QBUF failed. control[%d] buffer[%d], errno[%d]", + buffer_control->type, codec_buffer->index, errno); + return HAL_CODEC_ERROR_INTERNAL; } - LOGD("QBUF done [i:%d, t:%d, m:%d, fd:%d]", - index, type, memory, dmabuf_fd); + LOGD("QBUF done - control[%d] buffer[%d]", + buffer_control->type, codec_buffer->index); - return CODEC_ERROR_NONE; + return HAL_CODEC_ERROR_NONE; } -static int __codec_v4l2_dqbuf(int device_fd, int type, int memory, int *index, uint32_t *bytesused) +static int __codec_v4l2_dqbuf(int device_fd, + codec_hal_buffer_control_s *buffer_control, + hal_codec_buffer_s **out_buffer) { - int ret = CODEC_ERROR_NONE; + int ret = HAL_CODEC_ERROR_NONE; + + codec_hal_config_s *codec_config = NULL; + struct v4l2_buffer v4l2_buf; struct v4l2_plane v4l2_planes[V4L2_PLANES_MAX]; - if (device_fd < 0) { - LOGE("invalid fd %d", device_fd); - return CODEC_ERROR_INVALID_PARAMETER; + if (device_fd < 0 || !buffer_control || !out_buffer) { + LOGE("invalid device fd[%d]/buffer control[%p]/out_buffer[%p]", + device_fd, buffer_control, out_buffer); + return HAL_CODEC_ERROR_INVALID_PARAMETER; } - if (!index) { - LOGE("NULL parameter"); - return CODEC_ERROR_INVALID_PARAMETER; - } + codec_config = &buffer_control->config; memset(&v4l2_buf, 0x0, sizeof(struct v4l2_buffer)); memset(v4l2_planes, 0x0, sizeof(v4l2_planes)); - v4l2_buf.type = type; - v4l2_buf.memory = memory; + v4l2_buf.type = codec_config->buf_type; + v4l2_buf.memory = codec_config->memory; v4l2_buf.m.planes = v4l2_planes; + v4l2_buf.length = codec_config->num_planes; ret = ioctl(device_fd, VIDIOC_DQBUF, &v4l2_buf); if (ret < 0) { - LOGE("dqbuf failed. [t: %d, m: %d] errno %d", - type, memory, errno); - return CODEC_ERROR_DEVICE_READ; + LOGE("control[%d] DQBUF failed. [t: %d, m: %d] errno %d", + buffer_control->type, codec_config->buf_type, codec_config->memory, errno); + return HAL_CODEC_ERROR_DEVICE_READ; } - LOGD("DQBUF[i:%d], bytesused[%u], length[%u]", - v4l2_buf.index, v4l2_buf.bytesused, v4l2_buf.length); + LOGD("control[%d] DQBUF[i:%d], bytesused[%u], length[%u]", + buffer_control->type, v4l2_buf.index, v4l2_buf.bytesused, v4l2_buf.length); - *index = v4l2_buf.index; - if (bytesused) - *bytesused = v4l2_buf.bytesused; + *out_buffer = &buffer_control->buffers.buffer[v4l2_buf.index]; - /*LOGD("dqbuf index %d", *index);*/ - - return CODEC_ERROR_NONE; + return HAL_CODEC_ERROR_NONE; } -static int __codec_v4l2_get_format(guint32 fourcc, codec_format_e *format) +static int __codec_v4l2_get_format(guint32 fourcc, hal_codec_format_e *format) { if (!format) { LOGE("NULL parameter"); - return CODEC_ERROR_INVALID_PARAMETER; + return HAL_CODEC_ERROR_INVALID_PARAMETER; } switch (fourcc) { case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV12M: - *format = CODEC_FORMAT_NV12; + *format = HAL_CODEC_FORMAT_NV12; break; case V4L2_PIX_FMT_NV12MT: - *format = CODEC_FORMAT_NV12T; + *format = HAL_CODEC_FORMAT_NV12T; break; case V4L2_PIX_FMT_NV21: case V4L2_PIX_FMT_NV21M: - *format = CODEC_FORMAT_NV21; + *format = HAL_CODEC_FORMAT_NV21; break; case V4L2_PIX_FMT_YUV420: - *format = CODEC_FORMAT_I420; + *format = HAL_CODEC_FORMAT_I420; break; case V4L2_PIX_FMT_YVU420: - *format = CODEC_FORMAT_YV12; + *format = HAL_CODEC_FORMAT_YV12; break; case V4L2_PIX_FMT_YUYV: - *format = CODEC_FORMAT_YUYV; + *format = HAL_CODEC_FORMAT_YUYV; break; case V4L2_PIX_FMT_UYVY: - *format = CODEC_FORMAT_UYVY; + *format = HAL_CODEC_FORMAT_UYVY; break; case V4L2_PIX_FMT_H264: - *format = CODEC_FORMAT_H264; + *format = HAL_CODEC_FORMAT_H264; break; default: LOGW("unhandled fourcc ["FOURCC_FORMAT"]", FOURCC_CONVERT(fourcc)); - return CODEC_ERROR_INTERNAL; + return HAL_CODEC_ERROR_INTERNAL; } LOGI("fourcc ["FOURCC_FORMAT"] -> format [0x%x]", FOURCC_CONVERT(fourcc), *format); - return CODEC_ERROR_NONE; + return HAL_CODEC_ERROR_NONE; } -static int __codec_get_fourcc_plane_num(codec_format_e format, uint32_t *fourcc, uint32_t *plane_num) +static int __codec_get_fourcc_plane_num(hal_codec_format_e format, uint32_t *fourcc, uint32_t *plane_num) { if (!fourcc || !plane_num) { LOGE("NULL parameter %p %p", fourcc, plane_num); - return CODEC_ERROR_INVALID_PARAMETER; + return HAL_CODEC_ERROR_INVALID_PARAMETER; } switch (format) { - case CODEC_FORMAT_NV12: + case HAL_CODEC_FORMAT_NV12: *fourcc = V4L2_PIX_FMT_NV12; *plane_num = 2; break; - case CODEC_FORMAT_NV12T: + case HAL_CODEC_FORMAT_NV12T: *fourcc = V4L2_PIX_FMT_NV12MT; *plane_num = 2; break; - case CODEC_FORMAT_NV21: + case HAL_CODEC_FORMAT_NV21: *fourcc = V4L2_PIX_FMT_NV21; *plane_num = 2; break; - case CODEC_FORMAT_I420: + case HAL_CODEC_FORMAT_I420: *fourcc = V4L2_PIX_FMT_YUV420; *plane_num = 3; break; - case CODEC_FORMAT_YV12: + case HAL_CODEC_FORMAT_YV12: *fourcc = V4L2_PIX_FMT_YVU420; *plane_num = 3; break; - case CODEC_FORMAT_YUYV: + case HAL_CODEC_FORMAT_YUYV: *fourcc = V4L2_PIX_FMT_YUYV; *plane_num = 1; break; - case CODEC_FORMAT_UYVY: + case HAL_CODEC_FORMAT_UYVY: *fourcc = V4L2_PIX_FMT_UYVY; *plane_num = 1; break; - case CODEC_FORMAT_H264: + case HAL_CODEC_FORMAT_H264: *fourcc = V4L2_PIX_FMT_H264; *plane_num = 1; break; default: LOGE("unhandled format [%d]", format); - return CODEC_ERROR_INTERNAL; + return HAL_CODEC_ERROR_INTERNAL; } LOGD("format [0x%x] -> fourcc ["FOURCC_FORMAT"]", format, FOURCC_CONVERT(*fourcc)); - return CODEC_ERROR_NONE; + return HAL_CODEC_ERROR_NONE; } -static int __codec_stop_stream(hal_codec_handle_s *handle) +static int __codec_v4l2_stop_stream(codec_hal_handle_s *handle) { int i = 0; - int ret = CODEC_ERROR_NONE; - codec_memory_s *codec_memory = NULL; - codec_buffer_s *codec_buffer = NULL; - codec_buffer_control_s *buffer_control = NULL; + int k = 0; + int ret = HAL_CODEC_ERROR_NONE; + hal_codec_memory_s *codec_memory = NULL; + codec_hal_buffer_control_s *buffer_control = NULL; + hal_codec_buffer_s *codec_buffer = NULL; if (!handle) { LOGE("NULL handle"); - return CODEC_ERROR_INVALID_PARAMETER; + return HAL_CODEC_ERROR_INVALID_PARAMETER; } LOGI("start"); /* stream off */ - ret = __codec_v4l2_stream(handle->device_fd, - handle->input_buffer_control.buf_type, FALSE); - ret |= __codec_v4l2_stream(handle->device_fd, - handle->output_buffer_control.buf_type, FALSE); - if (ret != CODEC_ERROR_NONE) { - LOGE("STREAMOFF failed[0x%x]", ret); - return ret; + for (i = 0 ; i < CODEC_HAL_BUFFER_CONTROL_TYPE_MAX ; i++) { + ret = __codec_v4l2_stream(handle->device_fd, + handle->buffer_control[i].config.buf_type, FALSE); + if (ret != HAL_CODEC_ERROR_NONE) { + LOGE("buffer_control[%d] STREAMOFF failed[0x%x]", i, ret); + return ret; + } } /* decoder */ /* release output buffer */ - buffer_control = &handle->output_buffer_control; + buffer_control = &handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_OUTPUT]; - for (i = 0 ; i < buffer_control->count ; i++) { - codec_buffer = &buffer_control->buffers[i]; + for (i = 0 ; i < buffer_control->buffers.count ; i++) { + codec_buffer = &buffer_control->buffers.buffer[i]; codec_memory = &codec_buffer->memory; - if (codec_memory->fd[0] <= CODEC_HAL_INITIAL_FD || !codec_memory->bo[0]) { - LOGW("[output][%d] invalid fd[%d], bo[%p]", - i, codec_memory->fd[0], codec_memory->bo[0]); - continue; - } - - LOGI("[output][%d] close fd[%d], unref bo[%p]", - i, codec_memory->fd[0], codec_memory->bo[0]); - - close(codec_memory->fd[0]); - tbm_bo_unref(codec_memory->bo[0]); + for (k = 0 ; k < codec_memory->num_fd ; k++) { + if (codec_memory->fd[k] > CODEC_HAL_INITIAL_FD) { + LOGI("[output][%d][%d] close fd[%d]", i, k, codec_memory->fd[k]); + close(codec_memory->fd[k]); + codec_memory->fd[k] = CODEC_HAL_INITIAL_FD; + } - codec_memory->fd[0] = CODEC_HAL_INITIAL_FD; - codec_memory->bo[0] = NULL; + if (buffer_control->buffers.bo[i][k]) { + LOGI("[output][%d][%d] unref bo[%p]", i, k, buffer_control->buffers.bo[i][k]); + tbm_bo_unref(buffer_control->buffers.bo[i][k]); + buffer_control->buffers.bo[i][k] = NULL; + } + } } ret = __codec_v4l2_reqbufs(handle->device_fd, - handle->output_buffer_control.buf_type, V4L2_MEMORY_MMAP, 0, NULL); - if (ret != CODEC_ERROR_NONE) { + buffer_control->config.buf_type, V4L2_MEMORY_MMAP, 0, NULL); + if (ret != HAL_CODEC_ERROR_NONE) { LOGE("[output] REQBUFS 0 failed[0x%x]", ret); return ret; } /* release input buffer */ - buffer_control = &handle->input_buffer_control; + buffer_control = &handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_INPUT]; - for (i = 0 ; i < buffer_control->count ; i++) { - codec_buffer = &buffer_control->buffers[i]; + for (i = 0 ; i < buffer_control->buffers.count ; i++) { + codec_buffer = &buffer_control->buffers.buffer[i]; - if (!codec_buffer->planes[0].data || codec_buffer->total_size == 0) { + if (!codec_buffer->planes.plane[0].data || codec_buffer->size == 0) { LOGW("[input][%d] invalid data[%p], size[%u]", - i, codec_buffer->planes[0].data, codec_buffer->total_size); + i, codec_buffer->planes.plane[0].data, codec_buffer->size); continue; } LOGI("[input][%d] munmap[%p], size[%u]", - i, codec_buffer->planes[0].data, codec_buffer->total_size); - munmap(codec_buffer->planes[0].data, codec_buffer->total_size); + i, codec_buffer->planes.plane[0].data, codec_buffer->size); - codec_buffer->planes[0].data = NULL; - codec_buffer->total_size = 0; + munmap(codec_buffer->planes.plane[0].data, codec_buffer->size); + + codec_buffer->planes.plane[0].data = NULL; + codec_buffer->size = 0; } ret = __codec_v4l2_reqbufs(handle->device_fd, - handle->input_buffer_control.buf_type, V4L2_MEMORY_MMAP, 0, NULL); - if (ret != CODEC_ERROR_NONE) { + buffer_control->config.buf_type, V4L2_MEMORY_MMAP, 0, NULL); + if (ret != HAL_CODEC_ERROR_NONE) { LOGE("[input] REQBUFS 0 failed[0x%x]", ret); return ret; } LOGI("done"); - return CODEC_ERROR_NONE; + return HAL_CODEC_ERROR_NONE; } -static int __codec_start_stream(hal_codec_handle_s *handle, - uint32_t in_buffer_count, uint32_t out_buffer_count) +static int __codec_v4l2_start_stream(codec_hal_handle_s *handle, + codec_hal_buffer_control_s *buffer_control, uint32_t buffer_count) { int i = 0; - int width = 0; - int height = 0; + int k = 0; int num_planes = 0; - int ret = CODEC_ERROR_NONE; - codec_format_e format = CODEC_FORMAT_NV12; - codec_memory_s *codec_memory = NULL; - codec_buffer_s *codec_buffer = NULL; - codec_buffer_control_s *buffer_control = NULL; - uint32_t buffer_size = 0; - uint32_t plane_size[V4L2_PLANES_MAX] = {0, }; - tbm_bo_handle bo_handle = {NULL, }; + int ret = HAL_CODEC_ERROR_NONE; + + hal_codec_memory_s *codec_memory = NULL; + hal_codec_buffer_s *codec_buffer = NULL; + codec_hal_config_s *codec_config = NULL; + codec_hal_buffer_control_type_e type; + struct v4l2_buffer v4l2_buf; struct v4l2_plane v4l2_planes[V4L2_PLANES_MAX]; - if (!handle) { - LOGE("NULL handle"); - return CODEC_ERROR_INTERNAL; - } - - /* input buffer */ - buffer_control = &handle->input_buffer_control; + tbm_bo new_bo = NULL; + tbm_bo_handle bo_handle = {NULL, }; - ret = __codec_v4l2_reqbufs(handle->device_fd, - buffer_control->buf_type, V4L2_MEMORY_MMAP, - in_buffer_count, &buffer_control->count); - if (ret != CODEC_ERROR_NONE) { - LOGE("[input] REQBUFS failed [0x%x]", ret); - return ret; + if (!handle || !buffer_control) { + LOGE("NULL param [%p,%p]", handle, buffer_control); + return HAL_CODEC_ERROR_INVALID_PARAMETER; } - LOGI("[input] buffer count : request %u -> result %u", - in_buffer_count, buffer_control->count); + type = buffer_control->type; + codec_config = &buffer_control->config; - format = buffer_control->buffers[0].format; - width = buffer_control->buffers[0].resolution.width; - height = buffer_control->buffers[0].resolution.height; - num_planes = buffer_control->buffers[0].num_planes; - - for (i = 0 ; i < buffer_control->count ; i++) { - codec_buffer = &buffer_control->buffers[i]; - - codec_buffer->index = i; - codec_buffer->format = format; - codec_buffer->resolution.width = width; - codec_buffer->resolution.height = height; - codec_buffer->num_planes = num_planes; - - /* decoder input */ - memset(&v4l2_buf, 0x0, sizeof(struct v4l2_buffer)); - memset(v4l2_planes, 0x0, sizeof(v4l2_planes)); - - v4l2_buf.type = buffer_control->buf_type; - v4l2_buf.memory = buffer_control->memory_type; - v4l2_buf.index = i; - v4l2_buf.m.planes = v4l2_planes; - v4l2_buf.length = num_planes; - - if (ioctl(handle->device_fd, VIDIOC_QUERYBUF, &v4l2_buf) < 0) { - LOGE("[input][%d] query buf failed. errno %d", i, errno); - ret = CODEC_ERROR_INTERNAL; - goto _START_STREAM_FAILED; - } - - codec_buffer->total_size = v4l2_planes[0].length; - codec_buffer->planes[0].size = v4l2_planes[0].length; - codec_buffer->planes[0].data = mmap(0, - v4l2_planes[0].length, - PROT_READ | PROT_WRITE, - MAP_SHARED, - handle->device_fd, - (off_t)v4l2_planes[0].m.mem_offset); - if (codec_buffer->planes[0].data == MAP_FAILED) { - LOGE("[input][%d] mmap failed, size[%d], offset[%u] for mmap(errno %d)", - i, v4l2_planes[0].length, v4l2_planes[0].m.mem_offset, errno); - ret = CODEC_ERROR_INTERNAL; - goto _START_STREAM_FAILED; - } - - LOGI("[input][%d] buffer size[%d], data[%p]", - i, codec_buffer->planes[0].size, codec_buffer->planes[0].data); - } - - /* output buffer */ - buffer_control = &handle->output_buffer_control; + LOGI("type[%d] buf_type[%d], memory[%d], plane num[%u], buffer count[%u]", + type, codec_config->buf_type, codec_config->memory, + codec_config->num_planes, buffer_count); ret = __codec_v4l2_reqbufs(handle->device_fd, - buffer_control->buf_type, V4L2_MEMORY_DMABUF, - out_buffer_count, &buffer_control->count); - if (ret != CODEC_ERROR_NONE) { - LOGE("[output] REQBUFS failed [0x%x]", ret); + codec_config->buf_type, codec_config->memory, + buffer_count, &buffer_control->buffers.count); + if (ret != HAL_CODEC_ERROR_NONE) { + LOGE("type[%d] REQBUFS failed [0x%x]", type, ret); return ret; } - LOGI("[output] buffer count : request[%u] -> result[%u]", - out_buffer_count, buffer_control->count); - - format = buffer_control->buffers[0].format; - width = buffer_control->buffers[0].resolution.width; - height = buffer_control->buffers[0].resolution.height; - num_planes = buffer_control->buffers[0].num_planes; + LOGI("type[%d] buffer count - request[%u] -> result[%u]", + type, buffer_count, buffer_control->buffers.count); - buffer_size = buffer_control->buffers[0].total_size; - plane_size[0] = buffer_control->buffers[0].planes[0].size; - plane_size[1] = buffer_control->buffers[0].planes[1].size; + num_planes = codec_config->num_planes; - for (i = 0 ; i < buffer_control->count ; i++) { - codec_buffer = &buffer_control->buffers[i]; + for (i = 0 ; i < buffer_control->buffers.count ; i++) { + codec_buffer = &buffer_control->buffers.buffer[i]; codec_buffer->index = i; - codec_buffer->format = format; - codec_buffer->resolution.width = width; - codec_buffer->resolution.height = height; - codec_buffer->num_planes = num_planes; + codec_buffer->meta.format = codec_config->format; + codec_buffer->meta.resolution.width = codec_config->resolution.width; + codec_buffer->meta.resolution.height = codec_config->resolution.height; + codec_buffer->planes.num_planes = num_planes; + codec_buffer->size = codec_config->buffer_size; codec_memory = &codec_buffer->memory; - codec_memory->bo[0] = tbm_bo_alloc(handle->bufmgr, (int)buffer_size, TBM_BO_DEFAULT); - if (!codec_memory->bo[0]) { - LOGE("[output][%d] bo alloc failed[size:%u]", i, buffer_size); - ret = CODEC_ERROR_OUT_OF_MEMORY; - goto _START_STREAM_FAILED; - } + if (codec_config->memory == V4L2_MEMORY_MMAP) { + memset(&v4l2_buf, 0x0, sizeof(struct v4l2_buffer)); + memset(v4l2_planes, 0x0, sizeof(v4l2_planes)); - bo_handle = tbm_bo_get_handle(codec_memory->bo[0], TBM_DEVICE_CPU); - if (!bo_handle.ptr) { - LOGE("[output][%d] bo[%p] get handle failed", i, codec_memory->bo[0]); - ret = CODEC_ERROR_INTERNAL; - goto _START_STREAM_FAILED; - } + v4l2_buf.type = codec_config->buf_type; + v4l2_buf.memory = codec_config->memory; + v4l2_buf.index = i; + v4l2_buf.m.planes = v4l2_planes; + v4l2_buf.length = num_planes; - codec_buffer->planes[0].data = bo_handle.ptr; - codec_buffer->planes[0].size = plane_size[0]; - codec_buffer->planes[1].data = codec_buffer->planes[0].data + codec_buffer->planes[0].size; - codec_buffer->planes[1].size = plane_size[1]; + if (ioctl(handle->device_fd, VIDIOC_QUERYBUF, &v4l2_buf) < 0) { + LOGE("type[%d] buffer[i:%d] query buf failed (errno %d)", type, i, errno); + ret = HAL_CODEC_ERROR_INTERNAL; + goto _START_STREAM_FAILED; + } - codec_memory->fd[0] = tbm_bo_export_fd(codec_memory->bo[0]); - if (codec_memory->fd[0] < 0) { - LOGE("[output][%d] export fd failed from bo[%p]", i, codec_memory->bo[0]); - ret = CODEC_ERROR_INTERNAL; - goto _START_STREAM_FAILED; - } + for (k = 0 ; k < v4l2_buf.length ; k++) { + codec_buffer->planes.plane[k].size = v4l2_planes[k].length; + codec_buffer->planes.plane[k].data = mmap(0, + v4l2_planes[k].length, + PROT_READ | PROT_WRITE, + MAP_SHARED, + handle->device_fd, + (off_t)v4l2_planes[k].m.mem_offset); + + if (codec_buffer->planes.plane[k].data == MAP_FAILED) { + LOGE("type[%d] buffer[i:%d][plane:%d] mmap failed, size[%d], offset[%u] for mmap (errno %d)", + type, i, k, v4l2_planes[k].length, v4l2_planes[k].m.mem_offset, errno); + ret = HAL_CODEC_ERROR_INTERNAL; + goto _START_STREAM_FAILED; + } + + LOGI("type[%d] buffer[i:%d][%d] buffer size[%d], data[%p]", + type, i, k, codec_buffer->planes.plane[k].size, codec_buffer->planes.plane[k].data); + } + } else { + /* V4L2_MEMORY_DMABUF */ + new_bo = tbm_bo_alloc(handle->bufmgr, (int)codec_buffer->size, TBM_BO_DEFAULT); + if (!new_bo) { + LOGE("type[%d] buffer[i:%d] bo alloc failed, size[%u]", type, i, codec_buffer->size); + goto _START_STREAM_FAILED; + } + + bo_handle = tbm_bo_get_handle(new_bo, TBM_DEVICE_CPU); + if (!bo_handle.ptr) { + LOGE("type[%d] buffer[i:%d] bo get handle failed for bo[%p]", type, i, new_bo); + tbm_bo_unref(new_bo); + goto _START_STREAM_FAILED; + } - LOGI("[output][%d] size[%u], bo[%p], fd[%d]", - i, buffer_size, codec_memory->bo[0], codec_memory->fd[0]); + codec_memory->fd[0] = tbm_bo_export_fd(new_bo); + if (codec_memory->fd[0] < 0) { + LOGE("type[%d] buffer[i:%d] get fd handle failed for bo[%p]", type, i, new_bo); + tbm_bo_unref(new_bo); + goto _START_STREAM_FAILED; + } - ret = __codec_v4l2_qbuf(handle->device_fd, - buffer_control->buf_type, buffer_control->memory_type, - i, codec_memory->fd[0]); - if (ret != CODEC_ERROR_NONE) { - LOGE("[output][%d] qbuf failed (fd %d, errno %d)", - i, codec_memory->fd[0], errno); - goto _START_STREAM_FAILED; + buffer_control->buffers.bo[i][0] = new_bo; + codec_memory->num_fd = 1; + + codec_buffer->planes.plane[0].data = bo_handle.ptr; + codec_buffer->planes.plane[0].stride = handle->ts_info.planes[0].stride; + codec_buffer->planes.plane[0].size = handle->ts_info.planes[0].size; + codec_buffer->planes.plane[0].bytesused = handle->ts_info.planes[0].stride * codec_config->resolution.height; + + codec_buffer->planes.plane[1].data = bo_handle.ptr + handle->ts_info.planes[0].size; + codec_buffer->planes.plane[1].stride = handle->ts_info.planes[1].stride; + codec_buffer->planes.plane[1].size = handle->ts_info.planes[1].size; + codec_buffer->planes.plane[1].bytesused = handle->ts_info.planes[1].stride * (codec_config->resolution.height >> 1); + + LOGI("type[%d] buffer[i:%d] new bo[%p], vaddr[%p]", type, i, new_bo, bo_handle.ptr); + LOGI(" plane[0] data[%p], stride[%u], size[%u], bytesused[%u]", + codec_buffer->planes.plane[0].data, + codec_buffer->planes.plane[0].stride, + codec_buffer->planes.plane[0].size, + codec_buffer->planes.plane[0].bytesused); + LOGI(" plane[1] data[%p], stride[%u], size[%u], bytesused[%u]", + codec_buffer->planes.plane[1].data, + codec_buffer->planes.plane[1].stride, + codec_buffer->planes.plane[1].size, + codec_buffer->planes.plane[1].bytesused); } - } - /* stream on */ - ret = __codec_v4l2_stream(handle->device_fd, handle->input_buffer_control.buf_type, TRUE); - if (ret != CODEC_ERROR_NONE) { - LOGE("[input] stream on failed"); - goto _START_STREAM_FAILED; + if (buffer_control->type == CODEC_HAL_BUFFER_CONTROL_TYPE_INPUT) { + g_mutex_lock(&buffer_control->lock); + LOGI("[input] push idle buffer[%d]", i); + g_queue_push_tail(buffer_control->buffers.idle_buffers, GINT_TO_POINTER(i)); + g_mutex_unlock(&buffer_control->lock); + } else { + /* CODEC_HAL_BUFFER_CONTROL_TYPE_OUTPUT */ + ret = __codec_v4l2_qbuf(handle->device_fd, + buffer_control, codec_buffer); + + if (ret != HAL_CODEC_ERROR_NONE) { + LOGE("[output][%d] qbuf failed (fd %d, errno %d)", + i, codec_memory->fd[0], errno); + goto _START_STREAM_FAILED; + } + } } - ret = __codec_v4l2_stream(handle->device_fd, handle->output_buffer_control.buf_type, TRUE); - if (ret != CODEC_ERROR_NONE) { - LOGE("[output] stream on failed"); + ret = __codec_v4l2_stream(handle->device_fd, codec_config->buf_type, TRUE); + if (ret != HAL_CODEC_ERROR_NONE) { + LOGE("type[%d] stream on failed", codec_config->buf_type); goto _START_STREAM_FAILED; } - LOGI("done"); + LOGI("type[%d] done", codec_config->buf_type); - return CODEC_ERROR_NONE; + return HAL_CODEC_ERROR_NONE; _START_STREAM_FAILED: - __codec_stop_stream(handle); + __codec_v4l2_stop_stream(handle); return ret; } +#if 0 static gboolean __codec_h264_is_delta_frame(guint8 *data, uint32_t size) { uint32_t offset = 0; @@ -1145,18 +1184,19 @@ CHECK_AGAIN: return FALSE; } } +#endif -static void __codec_message_release_func(gpointer data) +static void __codec_v4l2_message_release_func(gpointer data) { - codec_message_s *message = (codec_message_s *)data; + hal_codec_message_s *message = (hal_codec_message_s *)data; if (!message) { LOGW("NULL message"); return; } - LOGD("release message %p, type %d", message, message->type); + LOGD("release message[%p] type[%d]", message, message->type); g_free(message); @@ -1164,11 +1204,10 @@ static void __codec_message_release_func(gpointer data) } -static void *_codec_message_handler_func(gpointer data) +static void *__codec_v4l2_message_handler_func(gpointer data) { - int i = 0; - codec_message_s *message = NULL; - hal_codec_handle_s *handle = (hal_codec_handle_s *)data; + hal_codec_message_s *message = NULL; + codec_hal_handle_s *handle = (codec_hal_handle_s *)data; if (!handle) { LOGE("NULL handle for capture thread"); @@ -1200,7 +1239,7 @@ static void *_codec_message_handler_func(gpointer data) g_mutex_unlock(&handle->msg_cb_lock); if (handle->msg_cb) { - LOGD("call message callback[%d] type[%d]", i, message->type); + LOGD("call message callback - type[%d]", message->type); handle->msg_cb(message, handle->msg_cb_data); } @@ -1217,7 +1256,7 @@ static void *_codec_message_handler_func(gpointer data) } -static void __codec_release_handle(hal_codec_handle_s *handle) +static void __codec_v4l2_release_handle(codec_hal_handle_s *handle) { if (!handle) { LOGW("NULL handle"); @@ -1226,18 +1265,21 @@ static void __codec_release_handle(hal_codec_handle_s *handle) LOGD("release codec HAL handle [%p]", handle); - if (handle->msg_thread) { + if (handle->msg_handler) { g_mutex_lock(&handle->msg_cb_lock); + handle->msg_cb_run = FALSE; - g_cond_signal(&handle->msg_cb_cond); + g_cond_broadcast(&handle->msg_cb_cond); + g_mutex_unlock(&handle->msg_cb_lock); - g_thread_join(handle->msg_thread); - g_queue_free_full(handle->msg_list, (GDestroyNotify)__codec_message_release_func); + + g_thread_join(handle->msg_handler); + + g_queue_free_full(handle->msg_list, (GDestroyNotify)__codec_v4l2_message_release_func); handle->msg_list = NULL; } - __codec_deinit_buffer_control(&handle->input_buffer_control); - __codec_deinit_buffer_control(&handle->output_buffer_control); + __codec_v4l2_deinit_buffer_control(handle); g_mutex_clear(&handle->lock); g_mutex_clear(&handle->msg_cb_lock); @@ -1254,32 +1296,58 @@ static void __codec_release_handle(hal_codec_handle_s *handle) } -static void __codec_init_buffer_control(codec_buffer_control_s *buffer_control) +static void __codec_v4l2_init_buffer_control(codec_hal_handle_s *handle) { - if (!buffer_control) { - LOGE("NULL control"); + int i = 0; + codec_hal_buffer_control_s *buffer_control = NULL; + + if (!handle) { + LOGE("NULL handle"); return; } - g_mutex_init(&buffer_control->lock); - g_cond_init(&buffer_control->cond); + for (i = 0 ; i < CODEC_HAL_BUFFER_CONTROL_TYPE_MAX ; i++) { + buffer_control = &handle->buffer_control[i]; + + buffer_control->codec_handle = handle; + buffer_control->type = i; + + g_mutex_init(&buffer_control->lock); + g_cond_init(&buffer_control->cond); + + buffer_control->buffers.idle_buffers = g_queue_new(); + + LOGI("buffer_control[%d] init done", i); + } } -static void __codec_deinit_buffer_control(codec_buffer_control_s *buffer_control) +static void __codec_v4l2_deinit_buffer_control(codec_hal_handle_s *handle) { - if (!buffer_control) { - LOGE("NULL control"); + int i = 0; + codec_hal_buffer_control_s *buffer_control = NULL; + + if (!handle) { + LOGE("NULL handle"); return; } - g_mutex_clear(&buffer_control->lock); - g_cond_clear(&buffer_control->cond); + for (i = 0 ; i < CODEC_HAL_BUFFER_CONTROL_TYPE_MAX ; i++) { + buffer_control = &handle->buffer_control[i]; + + g_mutex_clear(&buffer_control->lock); + g_cond_clear(&buffer_control->cond); + + g_queue_free(buffer_control->buffers.idle_buffers); + buffer_control->buffers.idle_buffers = NULL; + + LOGI("buffer_control[%d] deinit done", i); + } } -int codec_v4l2_init(codec_type_e type, void **codec_handle) +int codec_v4l2_init(hal_codec_type_e type, void **codec_handle) { - hal_codec_handle_s *new_handle = NULL; + codec_hal_handle_s *new_handle = NULL; tbm_bufmgr bufmgr = NULL; @@ -1287,16 +1355,16 @@ int codec_v4l2_init(codec_type_e type, void **codec_handle) if (!codec_handle) { LOGE("NULL pointer for handle"); - return CODEC_ERROR_INVALID_PARAMETER; + return HAL_CODEC_ERROR_INVALID_PARAMETER; } bufmgr = tbm_bufmgr_init(-1); if (bufmgr == NULL) { LOGE("get tbm bufmgr failed"); - return CODEC_ERROR_INTERNAL; + return HAL_CODEC_ERROR_INTERNAL; } - new_handle = g_new0(hal_codec_handle_s, 1); + new_handle = g_new0(codec_hal_handle_s, 1); new_handle->type = type; new_handle->bufmgr = bufmgr; @@ -1305,8 +1373,7 @@ int codec_v4l2_init(codec_type_e type, void **codec_handle) g_cond_init(&new_handle->cond); /* buffer */ - __codec_init_buffer_control(&new_handle->input_buffer_control); - __codec_init_buffer_control(&new_handle->output_buffer_control); + __codec_v4l2_init_buffer_control(new_handle); /* message */ g_mutex_init(&new_handle->msg_cb_lock); @@ -1314,140 +1381,191 @@ int codec_v4l2_init(codec_type_e type, void **codec_handle) new_handle->msg_list = g_queue_new(); new_handle->msg_cb_run = TRUE; - new_handle->msg_thread = g_thread_try_new("codecHAL:msg", - _codec_message_handler_func, (gpointer)new_handle, NULL); - if (!new_handle->msg_thread) { - LOGE("failed to create message thread"); - __codec_release_handle(new_handle); - return CODEC_ERROR_INTERNAL; + new_handle->msg_handler = g_thread_try_new("codecHAL:msg", + __codec_v4l2_message_handler_func, (gpointer)new_handle, NULL); + if (!new_handle->msg_handler) { + LOGE("failed to create message handler"); + __codec_v4l2_release_handle(new_handle); + return HAL_CODEC_ERROR_INTERNAL; } new_handle->device_index = CODEC_HAL_INITIAL_INDEX; new_handle->device_fd = CODEC_HAL_INITIAL_FD; - new_handle->state = CODEC_STATE_INITIALIZED; + new_handle->state = HAL_CODEC_STATE_INITIALIZED; *codec_handle = new_handle; LOGD("codec HAL handle [%p] - type[%s]", new_handle, g_decoder_type_string[type]); - return CODEC_ERROR_NONE; + return HAL_CODEC_ERROR_NONE; } int codec_v4l2_deinit(void *codec_handle) { - hal_codec_handle_s *handle = (hal_codec_handle_s *)codec_handle; + codec_hal_handle_s *handle = (codec_hal_handle_s *)codec_handle; if (!handle) { LOGE("NULL handle"); - return CODEC_ERROR_INVALID_PARAMETER; + return HAL_CODEC_ERROR_INVALID_PARAMETER; } g_mutex_lock(&handle->lock); - if (handle->state != CODEC_STATE_INITIALIZED) { + if (handle->state != HAL_CODEC_STATE_INITIALIZED) { LOGE("invalid state [%d]", handle->state); g_mutex_unlock(&handle->lock); - return CODEC_ERROR_INVALID_STATE; + return HAL_CODEC_ERROR_INVALID_STATE; } g_mutex_unlock(&handle->lock); - __codec_release_handle(handle); + __codec_v4l2_release_handle(handle); - return CODEC_ERROR_NONE; + return HAL_CODEC_ERROR_NONE; } -int codec_v4l2_configure(void *codec_handle, int width, int height, codec_format_e in_format, codec_format_e out_format, bool is_secure) +static uint32_t __codec_v4l2_get_tbm_format(hal_codec_format_e codec_format) { + switch (codec_format) { + case HAL_CODEC_FORMAT_NV12: + return TBM_FORMAT_NV12; + case HAL_CODEC_FORMAT_I420: + return TBM_FORMAT_YUV420; + default: + break; + } + + LOGW("unhandled format[%d], return TBM_FORMAT_NV12", codec_format); + + return TBM_FORMAT_NV12; +} + + +int codec_v4l2_configure(void *codec_handle, int width, int height, + hal_codec_format_e in_format, hal_codec_format_e out_format, bool is_secure) +{ + int i = 0; int ret = 0; int device_fd = CODEC_HAL_INITIAL_FD; char *node_path = NULL; - hal_codec_handle_s *handle = (hal_codec_handle_s *)codec_handle; + + codec_hal_handle_s *handle = (codec_hal_handle_s *)codec_handle; + enum v4l2_buf_type in_buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT; enum v4l2_buf_type out_buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + tbm_surface_h surface = NULL; + g_autoptr(GMutexLocker) locker = NULL; if (!handle) { LOGE("NULL handle"); - return CODEC_ERROR_INVALID_PARAMETER; + return HAL_CODEC_ERROR_INVALID_PARAMETER; } locker = g_mutex_locker_new(&handle->lock); - if (handle->state != CODEC_STATE_INITIALIZED) { + if (handle->state != HAL_CODEC_STATE_INITIALIZED) { LOGE("invalid state %d", handle->state); - return CODEC_ERROR_INVALID_STATE; + return HAL_CODEC_ERROR_INVALID_STATE; } - if (((in_format & CODEC_FORMAT_TYPE_ENCODED) && (out_format & CODEC_FORMAT_TYPE_ENCODED)) || - ((in_format & CODEC_FORMAT_TYPE_RAW) && (out_format & CODEC_FORMAT_TYPE_RAW))) { + if (((in_format & HAL_CODEC_FORMAT_TYPE_ENCODED) && (out_format & HAL_CODEC_FORMAT_TYPE_ENCODED)) || + ((in_format & HAL_CODEC_FORMAT_TYPE_RAW) && (out_format & HAL_CODEC_FORMAT_TYPE_RAW))) { LOGE("invalid format : in[%d], out[%d]", in_format, out_format); - return CODEC_ERROR_INVALID_PARAMETER; + return HAL_CODEC_ERROR_INVALID_PARAMETER; } ret = __codec_v4l2_get_buf_type_and_node_path(in_format, out_format, &in_buf_type, &out_buf_type, &node_path); - if (ret != CODEC_ERROR_NONE) + if (ret != HAL_CODEC_ERROR_NONE) return ret; + surface = tbm_surface_create(width, height, __codec_v4l2_get_tbm_format(out_format)); + if (!surface) { + LOGE("create surface failed [%dx%d][format:%d]", width, height, out_format); + return HAL_CODEC_ERROR_INTERNAL; + } + + ret = tbm_surface_get_info(surface, &handle->ts_info); + + tbm_surface_destroy(surface); + surface = NULL; + + if (ret != TBM_SURFACE_ERROR_NONE) { + LOGE("get surface info failed[0x%x]", ret); + return HAL_CODEC_ERROR_INTERNAL; + } + + for (i = 0 ; i < handle->ts_info.num_planes ; i++) { + LOGI("TBM surface plane[%d] stride[%u], size[%u], offset[%u]", i, + handle->ts_info.planes[i].stride, + handle->ts_info.planes[i].size, + handle->ts_info.planes[i].offset); + } + /* device open */ device_fd = open(node_path, O_RDWR); if (device_fd < 0) { char error_string[ERROR_STRING_LENGTH] = {'\0',}; strerror_r(errno, error_string, ERROR_STRING_LENGTH); LOGE("[%s] open failed [%s]", node_path, error_string); - return CODEC_ERROR_DEVICE_OPEN; + return HAL_CODEC_ERROR_DEVICE_OPEN; } /* set format for input */ - ret = __codec_v4l2_s_fmt(&handle->input_buffer_control, - device_fd, in_format, in_buf_type, width, height); - if (ret != CODEC_ERROR_NONE) { + ret = __codec_v4l2_set_config(&handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_INPUT], + in_buf_type, V4L2_MEMORY_MMAP, in_format, width, height); + if (ret != HAL_CODEC_ERROR_NONE) + return ret; + + ret = __codec_v4l2_s_fmt(&handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_INPUT], device_fd); + if (ret != HAL_CODEC_ERROR_NONE) { LOGE("set format[%d] for input failed - [0x%x]", in_format, ret); close(device_fd); return ret; } /* set format for output */ - ret = __codec_v4l2_s_fmt(&handle->output_buffer_control, - device_fd, out_format, out_buf_type, width, height); - if (ret != CODEC_ERROR_NONE) { - LOGE("set format[%d] for output failed - [0x%x]", in_format, ret); + ret = __codec_v4l2_set_config(&handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_OUTPUT], + out_buf_type, V4L2_MEMORY_DMABUF, out_format, width, height); + if (ret != HAL_CODEC_ERROR_NONE) + return ret; + + ret = __codec_v4l2_s_fmt(&handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_OUTPUT], device_fd); + if (ret != HAL_CODEC_ERROR_NONE) { + LOGE("set format[%d] for output failed - [0x%x]", out_format, ret); close(device_fd); return ret; } - handle->input_buffer_control.buf_type = in_buf_type; - handle->input_buffer_control.memory_type = V4L2_MEMORY_MMAP; - handle->output_buffer_control.buf_type = out_buf_type; - handle->output_buffer_control.memory_type = V4L2_MEMORY_DMABUF; - + handle->is_secure = is_secure; handle->device_fd = device_fd; - handle->state = CODEC_STATE_CONFIGURED; + handle->state = HAL_CODEC_STATE_CONFIGURED; - LOGD("done"); + LOGD("done - secure[%d]", is_secure); - return CODEC_ERROR_NONE; + return HAL_CODEC_ERROR_NONE; } int codec_v4l2_release(void *codec_handle) { - hal_codec_handle_s *handle = (hal_codec_handle_s *)codec_handle; + codec_hal_handle_s *handle = (codec_hal_handle_s *)codec_handle; g_autoptr(GMutexLocker) locker = NULL; if (!handle) { LOGE("NULL handle"); - return CODEC_ERROR_INVALID_PARAMETER; + return HAL_CODEC_ERROR_INVALID_PARAMETER; } locker = g_mutex_locker_new(&handle->lock); - if (handle->state != CODEC_STATE_CONFIGURED) { + if (handle->state != HAL_CODEC_STATE_CONFIGURED) { LOGE("invalid state %d", handle->state); - return CODEC_ERROR_INVALID_STATE; + return HAL_CODEC_ERROR_INVALID_STATE; } if (handle->device_fd > CODEC_HAL_INITIAL_FD) { @@ -1458,141 +1576,384 @@ int codec_v4l2_release(void *codec_handle) } handle->device_fd = CODEC_HAL_INITIAL_FD; - handle->state = CODEC_STATE_INITIALIZED; + handle->state = HAL_CODEC_STATE_INITIALIZED; LOGD("done"); - return CODEC_ERROR_NONE; + return HAL_CODEC_ERROR_NONE; +} + + +static int __codec_v4l2_poll(codec_hal_handle_s *handle, short events, int timeout_ms, short *revents) +{ + int ret = 0; + struct pollfd poll_fd; + char error_string[ERROR_STRING_LENGTH] = {'\0',}; + + if (!handle) { + LOGE("NULL handle"); + return -1; + } + + LOGI("device fd[%d] - events[0x%x]", handle->device_fd, events); + + poll_fd.fd = handle->device_fd; + poll_fd.events = events; + + ret = poll(&poll_fd, 1, timeout_ms); + + if (ret < 0) { + strerror_r(errno, error_string, ERROR_STRING_LENGTH); + LOGE("poll[events 0x%x] failed[%s]", events, error_string); + } else if (ret == 0) { + LOGW("poll[events 0x%x] time out for %d ms", events, timeout_ms); + } else { + LOGD("poll[events 0x%x -> revents 0x%x] success[%d]", events, poll_fd.revents, ret); + if (revents) + *revents = poll_fd.revents; + } + + return ret; +} + + +static gpointer __codec_v4l2_buffer_handler_func(gpointer data) +{ + int ret = 0; + int error_count = 0; + + short revents = 0; + codec_hal_handle_s *handle = (codec_hal_handle_s *)data; + hal_codec_buffer_s *input_buffer = NULL; + hal_codec_buffer_s *output_buffer = NULL; + codec_hal_buffer_control_s *input_control = NULL; + codec_hal_buffer_control_s *output_control = NULL; + + if (!handle) { + LOGE("NULL handle"); + return NULL; + } + + LOGI("start - fd[%d]", handle->device_fd); + + input_control = &handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_INPUT]; + output_control = &handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_OUTPUT]; + + while (TRUE) { + /* exit thread with some conditions */ + ////////////////////////////////////// + + ret = __codec_v4l2_poll(handle, (POLLIN | POLLOUT | POLLPRI), OUTPUT_POLL_TIMEOUT_MS, &revents); + + if (ret == 0) + continue; + + if (ret < 0) + break; + + if (revents & POLLERR) { + char error_string[ERROR_STRING_LENGTH] = {'\0',}; + strerror_r(errno, error_string, ERROR_STRING_LENGTH); + LOGW("POLLERR[%s]", error_string); + + if (handle->is_stopping) { + LOGW("now stopping... stop buffer handler"); + break; + } else { + if (error_count++ < POLL_ERROR_TRY_COUNT_MAX) { + LOGW("try[count:%d] poll after %d ms", error_count, POLL_ERROR_TRY_SLEEP_US); + usleep(POLL_ERROR_TRY_SLEEP_US); + continue; + } else { + LOGE("error count[%d] exceeded", POLL_ERROR_TRY_COUNT_MAX); + break; + } + } + } + + error_count = 0; + + if (revents & POLLIN) { + output_buffer = NULL; + + ret = __codec_v4l2_dqbuf(handle->device_fd, + output_control, &output_buffer); + if (ret != HAL_CODEC_ERROR_NONE || !output_buffer) { + LOGE("[OUTPUT] DQBUF failed[0x%x], buffer[%p]", ret, output_buffer); + continue; + } + + LOGD("[OUTPUT] DQBUF index[%d]", output_buffer->index); + + __codec_v4l2_message_send(handle, HAL_CODEC_MESSAGE_TYPE_OUTPUT_BUFFER, output_buffer); + } + + if (revents & POLLOUT) { + input_buffer = NULL; + + ret = __codec_v4l2_dqbuf(handle->device_fd, + input_control, &input_buffer); + if (ret != HAL_CODEC_ERROR_NONE || !input_buffer) { + LOGE("INPUT DQBUF failed[0x%x], buffer[%p]", ret, input_buffer); + continue; + } + + LOGD("[INPUT] DQBUF index[%d]", input_buffer->index); + + __codec_v4l2_add_idle_buffer(input_control, input_buffer); + } + } + + LOGI("leave"); + + return NULL; } int codec_v4l2_start(void *codec_handle, hal_codec_message_cb callback, void *user_data) { int ret = 0; - hal_codec_handle_s *handle = (hal_codec_handle_s *)codec_handle; + codec_hal_handle_s *handle = (codec_hal_handle_s *)codec_handle; g_autoptr(GMutexLocker) locker = NULL; if (!handle || !callback) { LOGE("NULL param %p %p", handle, callback); - return CODEC_ERROR_INVALID_PARAMETER; + return HAL_CODEC_ERROR_INVALID_PARAMETER; } locker = g_mutex_locker_new(&handle->lock); - if (handle->state != CODEC_STATE_CONFIGURED) { + if (handle->state != HAL_CODEC_STATE_CONFIGURED) { LOGE("invalid state %d", handle->state); - return CODEC_ERROR_INVALID_STATE; + return HAL_CODEC_ERROR_INVALID_STATE; } - ret = __codec_start_stream(handle, BUFFER_MIN, BUFFER_MIN); - if (ret != CODEC_ERROR_NONE) { - LOGE("__codec_start_stream failed[0x%x]", ret); + ret = __codec_v4l2_start_stream(handle, &handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_INPUT], BUFFER_MIN); + if (ret != HAL_CODEC_ERROR_NONE) { + LOGE("[input] __codec_start_stream failed[0x%x]", ret); return ret; } - handle->state = CODEC_STATE_STARTED; + ret = __codec_v4l2_start_stream(handle, &handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_OUTPUT], BUFFER_MIN); + if (ret != HAL_CODEC_ERROR_NONE) { + LOGE("[output] __codec_start_stream failed[0x%x]", ret); + return ret; + } + + handle->msg_cb = callback; + handle->msg_cb_data = user_data; + + handle->buffer_handler = g_thread_try_new(CODEC_THREAD_NAME_HANDLE_BUFFER, + __codec_v4l2_buffer_handler_func, (gpointer)handle, NULL); + if (!handle->buffer_handler) { + LOGE("failed to create buffer handler"); + return HAL_CODEC_ERROR_INTERNAL; + } + + handle->state = HAL_CODEC_STATE_STARTED; - LOGD("start preview done"); + LOGD("start codec[type:%d] done", handle->type); - return CODEC_ERROR_NONE; + return HAL_CODEC_ERROR_NONE; } int codec_v4l2_stop(void *codec_handle) { - int ret = CODEC_ERROR_NONE; - hal_codec_handle_s *handle = (hal_codec_handle_s *)codec_handle; + int ret = HAL_CODEC_ERROR_NONE; + codec_hal_handle_s *handle = (codec_hal_handle_s *)codec_handle; g_autoptr(GMutexLocker) locker = NULL; if (!handle) { LOGE("NULL handle"); - return CODEC_ERROR_INVALID_PARAMETER; + return HAL_CODEC_ERROR_INVALID_PARAMETER; } LOGD("start"); locker = g_mutex_locker_new(&handle->lock); - if (handle->state != CODEC_STATE_STARTED) { + if (handle->state != HAL_CODEC_STATE_STARTED) { LOGE("invalid state %d", handle->state); - return CODEC_ERROR_INVALID_STATE; + ret = HAL_CODEC_ERROR_INVALID_STATE; + goto _STOP_DONE; + } + + handle->is_stopping = TRUE; + + ret = __codec_v4l2_stop_stream(handle); + if (ret != HAL_CODEC_ERROR_NONE) { + LOGE("__codec_stop_stream failed[0x%x]", ret); + goto _STOP_DONE; } - ret = __codec_stop_stream(handle); + LOGI("join output thread"); - handle->state = CODEC_STATE_CONFIGURED; + g_thread_join(handle->buffer_handler); + handle->buffer_handler = NULL; + handle->state = HAL_CODEC_STATE_CONFIGURED; + +_STOP_DONE: + handle->is_stopping = FALSE; LOGD("stop done [0x%x]", ret); - return CODEC_ERROR_NONE; + return ret; } int codec_v4l2_flush(void *codec_handle) { - hal_codec_handle_s *handle = (hal_codec_handle_s *)codec_handle; + codec_hal_handle_s *handle = (codec_hal_handle_s *)codec_handle; + g_autoptr(GMutexLocker) locker = NULL; if (!handle) { LOGE("NULL handle"); - return CODEC_ERROR_INVALID_PARAMETER; + return HAL_CODEC_ERROR_INVALID_PARAMETER; } + locker = g_mutex_locker_new(&handle->lock); + + return HAL_CODEC_ERROR_NONE; +} + + +static hal_codec_buffer_s *__codec_v4l2_get_idle_buffer(codec_hal_buffer_control_s *buffer_control, gint64 timeout_ms) +{ + int index = IDLE_BUFFER_INDEX_INIT; + gint64 end_time = 0; g_autoptr(GMutexLocker) locker = NULL; - locker = g_mutex_locker_new(&handle->lock); + if (!buffer_control) { + LOGE("NULL buffer control"); + return NULL; + } - return CODEC_ERROR_NONE; + locker = g_mutex_locker_new(&buffer_control->lock); + + while (g_queue_is_empty(buffer_control->buffers.idle_buffers)) { + LOGD("type[%d] wait for idle buffer for %"G_GINT64_FORMAT" ms", + buffer_control->type, timeout_ms); + + end_time = g_get_monotonic_time() + (G_TIME_SPAN_MILLISECOND * timeout_ms); + + if (!g_cond_wait_until(&buffer_control->cond, &buffer_control->lock, end_time)) { + LOGE("type[%d] wait timed out for %"G_GINT64_FORMAT" ms", buffer_control->type, timeout_ms); + return NULL; + } + } + + index = GPOINTER_TO_INT(g_queue_pop_head(buffer_control->buffers.idle_buffers)); + + LOGD("type[%d] popped buffer[%d]", buffer_control->type, index); + + return &buffer_control->buffers.buffer[index]; } -int codec_v4l2_push_input_buffer(void *codec_handle, codec_buffer_s *buffer) +static void __codec_v4l2_add_idle_buffer(codec_hal_buffer_control_s *buffer_control, hal_codec_buffer_s *buffer) { - hal_codec_handle_s *handle = (hal_codec_handle_s *)codec_handle; + g_autoptr(GMutexLocker) locker = NULL; - if (!handle) { - LOGE("NULL handle"); - return CODEC_ERROR_INVALID_PARAMETER; + if (!buffer_control || !buffer) { + LOGE("NULL param[%p,%p]", buffer_control, buffer); + return; } + locker = g_mutex_locker_new(&buffer_control->lock); + + LOGD("add idle buffer[%d]", buffer->index); + + g_queue_push_tail(buffer_control->buffers.idle_buffers, GINT_TO_POINTER(buffer->index)); + + g_cond_broadcast(&buffer_control->cond); +} + + +int codec_v4l2_decode(void *codec_handle, hal_codec_buffer_s *buffer) +{ + int ret = HAL_CODEC_ERROR_NONE; + hal_codec_buffer_s *idle_buffer = NULL; + codec_hal_buffer_control_s *buffer_control; + codec_hal_handle_s *handle = (codec_hal_handle_s *)codec_handle; g_autoptr(GMutexLocker) locker = NULL; + if (!handle) { + LOGE("NULL handle"); + return HAL_CODEC_ERROR_INVALID_PARAMETER; + } + locker = g_mutex_locker_new(&handle->lock); - return CODEC_ERROR_NONE; + if (handle->state < HAL_CODEC_STATE_STARTED) { + LOGE("invalid state[%d]", handle->state); + return HAL_CODEC_ERROR_INVALID_STATE; + } + + buffer_control = &handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_INPUT]; + + idle_buffer = __codec_v4l2_get_idle_buffer(buffer_control, IDLE_BUFFER_TIME_OUT_MS); + if (!idle_buffer) { + LOGE("no idle buffer"); + return HAL_CODEC_ERROR_INTERNAL; + } + + memcpy(idle_buffer->planes.plane[0].data, buffer->planes.plane[0].data, buffer->planes.plane[0].bytesused); + memcpy(&idle_buffer->meta, &buffer->meta, sizeof(hal_codec_meta_s)); + + ret = __codec_v4l2_qbuf(handle->device_fd, + buffer_control, idle_buffer); + if (ret != HAL_CODEC_ERROR_NONE) { + LOGE("QBUF[%p] failed[i:%d], 0x%x", + buffer, idle_buffer->index, ret); + } else { + LOGD("QBUF[%p] done", buffer); + __codec_v4l2_message_send(handle, HAL_CODEC_MESSAGE_TYPE_INPUT_BUFFER_USED, buffer); + } + + return ret; } int codec_v4l2_release_output_buffer(void *codec_handle, int buffer_index) { - hal_codec_handle_s *handle = (hal_codec_handle_s *)codec_handle; + int ret = HAL_CODEC_ERROR_NONE; + codec_hal_handle_s *handle = (codec_hal_handle_s *)codec_handle; + codec_hal_buffer_control_s *buffer_control = NULL; + //g_autoptr(GMutexLocker) locker = NULL; if (!handle) { LOGE("NULL handle"); - return CODEC_ERROR_INVALID_PARAMETER; + return HAL_CODEC_ERROR_INVALID_PARAMETER; } - g_autoptr(GMutexLocker) locker = NULL; + buffer_control = &handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_OUTPUT]; - locker = g_mutex_locker_new(&handle->lock); + //locker = g_mutex_locker_new(&handle->lock); + + ret = __codec_v4l2_qbuf(handle->device_fd, + buffer_control, &buffer_control->buffers.buffer[buffer_index]); + + LOGI("ret[0x%x]", ret); - return CODEC_ERROR_NONE; + return HAL_CODEC_ERROR_NONE; } -int codec_v4l2_get_state(void *codec_handle, codec_state_e *state) +int codec_v4l2_get_state(void *codec_handle, hal_codec_state_e *state) { - hal_codec_handle_s *handle = (hal_codec_handle_s *)codec_handle; + codec_hal_handle_s *handle = (codec_hal_handle_s *)codec_handle; if (!handle) { LOGE("NULL handle"); - return CODEC_ERROR_INVALID_PARAMETER; + return HAL_CODEC_ERROR_INVALID_PARAMETER; } - return CODEC_ERROR_NONE; + return HAL_CODEC_ERROR_NONE; } -static int __set_command(hal_codec_handle_s *handle, int64_t command, void *value) +static int __codec_v4l2_set_command(codec_hal_handle_s *handle, int64_t command, void *value) { int cid = 0; int ctrl_ret = 0; @@ -1600,26 +1961,26 @@ static int __set_command(hal_codec_handle_s *handle, int64_t command, void *valu if (!handle || !value) { LOGE("NULL param %p %p", handle, value); - return CODEC_ERROR_INVALID_PARAMETER; + return HAL_CODEC_ERROR_INVALID_PARAMETER; } set_value = *(int *)value; - if (handle->state < CODEC_STATE_OPENED) { + if (handle->state < HAL_CODEC_STATE_OPENED) { LOGE("invalid state %d", handle->state); - return CODEC_ERROR_INVALID_STATE; + return HAL_CODEC_ERROR_INVALID_STATE; } LOGI("command[%"PRIx64"] -> [%d]", command, set_value); switch (command) { - case CODEC_COMMAND_BITRATE: + case HAL_CODEC_COMMAND_BITRATE: cid = V4L2_CID_MPEG_VIDEO_BITRATE; set_value = *(int *)value; break; default: LOGE("NOT_SUPPORTED command %"PRIx64, command); - return CODEC_ERROR_NOT_SUPPORTED; + return HAL_CODEC_ERROR_NOT_SUPPORTED; } ctrl_ret = __codec_v4l2_s_ctrl(handle->device_fd, cid, set_value); @@ -1628,64 +1989,64 @@ static int __set_command(hal_codec_handle_s *handle, int64_t command, void *valu case EACCES: case EPERM: LOGE("Permission denied %d", errno); - return CODEC_ERROR_PERMISSION_DENIED; + return HAL_CODEC_ERROR_PERMISSION_DENIED; case EINVAL: LOGE("Invalid argument"); - return CODEC_ERROR_INVALID_PARAMETER; + return HAL_CODEC_ERROR_INVALID_PARAMETER; case EBUSY: LOGE("Device busy"); - return CODEC_ERROR_DEVICE_BUSY; + return HAL_CODEC_ERROR_DEVICE_BUSY; case ENOTSUP: LOGE("Not supported"); - return CODEC_ERROR_NOT_SUPPORTED; + return HAL_CODEC_ERROR_NOT_SUPPORTED; default: LOGE("Unknown errro %d", errno); - return CODEC_ERROR_INTERNAL; + return HAL_CODEC_ERROR_INTERNAL; } } - return CODEC_ERROR_NONE; + return HAL_CODEC_ERROR_NONE; } -int codec_v4l2_set_command(void *codec_handle, int64_t command, void *value) +int codec_v4l2_set_command(void *codec_handle, hal_codec_command_e command, void *value) { - int ret = CODEC_ERROR_NONE; - hal_codec_handle_s *handle = (hal_codec_handle_s *)codec_handle; + int ret = HAL_CODEC_ERROR_NONE; + codec_hal_handle_s *handle = (codec_hal_handle_s *)codec_handle; g_autoptr(GMutexLocker) locker = NULL; locker = g_mutex_locker_new(&handle->lock); - ret = __set_command(handle, command, value); + ret = __codec_v4l2_set_command(handle, command, value); return ret; } -int codec_v4l2_get_command(void *codec_handle, int64_t command, void **value) +int codec_v4l2_get_command(void *codec_handle, hal_codec_command_e command, void **value) { - int ret = CODEC_ERROR_NONE; + int ret = HAL_CODEC_ERROR_NONE; int cid = 0; int ctrl_ret = 0; - hal_codec_handle_s *handle = (hal_codec_handle_s *)codec_handle; + codec_hal_handle_s *handle = (codec_hal_handle_s *)codec_handle; g_autoptr(GMutexLocker) locker = NULL; if (!handle || !value) { LOGE("NULL param %p %p", handle, value); - return CODEC_ERROR_INVALID_PARAMETER; + return HAL_CODEC_ERROR_INVALID_PARAMETER; } locker = g_mutex_locker_new(&handle->lock); - LOGI("command[%"PRIx64"]", command); + LOGI("command[0x%x]", command); switch (command) { - case CODEC_COMMAND_BITRATE: + case HAL_CODEC_COMMAND_BITRATE: cid = V4L2_CID_MPEG_VIDEO_BITRATE; break; default: - LOGE("Not supported command[%"PRIx64"]", command); - return CODEC_ERROR_NOT_SUPPORTED; + LOGE("Not supported command[0x%x]", command); + return HAL_CODEC_ERROR_NOT_SUPPORTED; } ctrl_ret = __codec_v4l2_g_ctrl(handle->device_fd, cid, (int *)*value); @@ -1694,35 +2055,35 @@ int codec_v4l2_get_command(void *codec_handle, int64_t command, void **value) case EACCES: case EPERM: LOGE("Permission denied %d", errno); - ret = CODEC_ERROR_PERMISSION_DENIED; + ret = HAL_CODEC_ERROR_PERMISSION_DENIED; break; case EINVAL: LOGE("Invalid argument"); - ret = CODEC_ERROR_INVALID_PARAMETER; + ret = HAL_CODEC_ERROR_INVALID_PARAMETER; break; case EBUSY: LOGE("Device busy"); - ret = CODEC_ERROR_DEVICE_BUSY; + ret = HAL_CODEC_ERROR_DEVICE_BUSY; break; case ENOTSUP: LOGE("Not supported"); - ret = CODEC_ERROR_NOT_SUPPORTED; + ret = HAL_CODEC_ERROR_NOT_SUPPORTED; break; default: LOGE("Unknown errro %d", errno); - ret = CODEC_ERROR_INTERNAL; + ret = HAL_CODEC_ERROR_INTERNAL; break; } } - if (ret == CODEC_ERROR_NONE) + if (ret == HAL_CODEC_ERROR_NONE) LOGI("get[%d]", **(int **)value); return ret; } -static void __dump_batch_command(codec_batch_command_control_s *batch_command) +static void __dump_batch_command(hal_codec_batch_command_control_s *batch_command) { if (!batch_command) { LOGE("NULL batch command"); @@ -1735,22 +2096,22 @@ static void __dump_batch_command(codec_batch_command_control_s *batch_command) } -int codec_v4l2_set_batch_command(void *codec_handle, codec_batch_command_control_s *batch_command, int64_t *error_command) +int codec_v4l2_set_batch_command(void *codec_handle, hal_codec_batch_command_control_s *batch_command, hal_codec_command_e *error_command) { - int ret = CODEC_ERROR_NONE; + int ret = HAL_CODEC_ERROR_NONE; int i = 0; int support_count = 0; - hal_codec_handle_s *handle = (hal_codec_handle_s *)codec_handle; + codec_hal_handle_s *handle = (codec_hal_handle_s *)codec_handle; g_autoptr(GMutexLocker) locker = NULL; set_batch_table_s set_table[] = { - {CODEC_COMMAND_BITRATE, batch_command ? (void *)&batch_command->bitrate : NULL}, - {CODEC_COMMAND_REQUEST_CODECDATA, NULL}, - {CODEC_COMMAND_REQUEST_SYNCFRAME, NULL} + {HAL_CODEC_COMMAND_BITRATE, batch_command ? (void *)&batch_command->bitrate : NULL}, + {HAL_CODEC_COMMAND_REQUEST_CODECDATA, NULL}, + {HAL_CODEC_COMMAND_REQUEST_SYNCFRAME, NULL} }; if (!handle || !batch_command) { LOGE("NULL param %p %p", handle, batch_command); - return CODEC_ERROR_INVALID_PARAMETER; + return HAL_CODEC_ERROR_INVALID_PARAMETER; } locker = g_mutex_locker_new(&handle->lock); @@ -1765,9 +2126,9 @@ int codec_v4l2_set_batch_command(void *codec_handle, codec_batch_command_control if (!(batch_command->command_set_flag & set_table[i].command)) continue; - ret = __set_command(handle, set_table[i].command, set_table[i].value); - if (ret != CODEC_ERROR_NONE) { - LOGE("failed command %"PRIx64", ret 0x%x", set_table[i].command, ret); + ret = __codec_v4l2_set_command(handle, set_table[i].command, set_table[i].value); + if (ret != HAL_CODEC_ERROR_NONE) { + LOGE("failed command 0x%x, ret 0x%x", set_table[i].command, ret); break; } } @@ -1796,7 +2157,7 @@ static int codec_v4l2_backend_init(void **data) funcs->start = codec_v4l2_start; funcs->stop = codec_v4l2_stop; funcs->flush = codec_v4l2_flush; - funcs->push_input_buffer = codec_v4l2_push_input_buffer; + funcs->decode = codec_v4l2_decode; funcs->release_output_buffer = codec_v4l2_release_output_buffer; funcs->get_state = codec_v4l2_get_state; funcs->set_command = codec_v4l2_set_command; diff --git a/src/hal_backend_codec_v4l2_private.h b/src/hal_backend_codec_v4l2_private.h index b9e3c0f..51acde6 100644 --- a/src/hal_backend_codec_v4l2_private.h +++ b/src/hal_backend_codec_v4l2_private.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -33,30 +34,50 @@ #define V4L2_PLANES_MAX 4 -typedef struct _set_batch_table_s { - int64_t command; +typedef enum { + CODEC_HAL_BUFFER_CONTROL_TYPE_INPUT = 0, + CODEC_HAL_BUFFER_CONTROL_TYPE_OUTPUT, + CODEC_HAL_BUFFER_CONTROL_TYPE_MAX +} codec_hal_buffer_control_type_e; + +typedef enum { + CODEC_HAL_QUEUE_ELEMENT_TYPE_NONE = 0, + CODEC_HAL_QUEUE_ELEMENT_TYPE_BUFFER +} codec_hal_queue_element_type_e; + +typedef struct { + hal_codec_command_e command; void *value; } set_batch_table_s; -typedef struct _codec_tbm_buffer_s { - tbm_bo bo; - tbm_bo_handle bo_handle; - int dmabuf_fd; -} codec_tbm_buffer_s; - -typedef struct _codec_hal_buffer_control_s { - gboolean is_run; - guint32 count; - guint32 queued_count; +typedef struct { + enum v4l2_buf_type buf_type; + enum v4l2_memory memory; + hal_codec_format_e format; + hal_codec_resolution_s resolution; + uint32_t num_planes; + uint32_t buffer_size; +} codec_hal_config_s; + +typedef struct { + uint32_t count; + hal_codec_buffer_s buffer[BUFFER_MAX]; + tbm_bo bo[BUFFER_MAX][HAL_CODEC_BUFFER_PLANE_MAX]; + GQueue *idle_buffers; +} codec_hal_buffers_s; + +typedef struct { + int device_fd; + codec_hal_buffer_control_type_e type; GMutex lock; GCond cond; - enum v4l2_buf_type buf_type; - enum v4l2_memory memory_type; - codec_buffer_s buffers[BUFFER_MAX]; -} codec_buffer_control_s; + codec_hal_config_s config; + codec_hal_buffers_s buffers; + void *codec_handle; +} codec_hal_buffer_control_s; -typedef struct _codec_hal_handle_s { - codec_type_e type; +typedef struct { + hal_codec_type_e type; /* tbm */ tbm_bufmgr bufmgr; @@ -66,13 +87,12 @@ typedef struct _codec_hal_handle_s { gint32 device_fd; /* buffer */ - codec_buffer_control_s input_buffer_control; - codec_buffer_control_s output_buffer_control; - GThread *output_thread; - gboolean output_thread_run; + codec_hal_buffer_control_s buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_MAX]; + tbm_surface_info_s ts_info; + GThread *buffer_handler; /* message */ - GThread *msg_thread; + GThread *msg_handler; hal_codec_message_cb msg_cb; gpointer msg_cb_data; gboolean msg_cb_run; @@ -86,21 +106,27 @@ typedef struct _codec_hal_handle_s { /* etc */ GMutex lock; GCond cond; - codec_state_e state; -} hal_codec_handle_s; + hal_codec_state_e state; + gboolean is_stopping; + + /* secure */ + gboolean is_secure; +} codec_hal_handle_s; + -int codec_v4l2_init(codec_type_e type, void **codec_handle); +int codec_v4l2_init(hal_codec_type_e type, void **codec_handle); int codec_v4l2_deinit(void *codec_handle); -int codec_v4l2_configure(void *codec_handle, int width, int height, codec_format_e in_format, codec_format_e out_format, bool is_secure); +int codec_v4l2_configure(void *codec_handle, int width, int height, + hal_codec_format_e in_format, hal_codec_format_e out_format, bool is_secure); int codec_v4l2_release(void *codec_handle); int codec_v4l2_start(void *codec_handle, hal_codec_message_cb callback, void *user_data); int codec_v4l2_stop(void *codec_handle); int codec_v4l2_flush(void *codec_handle); -int codec_v4l2_push_input_buffer(void *codec_handle, codec_buffer_s *buffer); +int codec_v4l2_decode(void *codec_handle, hal_codec_buffer_s *buffer); int codec_v4l2_release_output_buffer(void *codec_handle, int buffer_index); -int codec_v4l2_get_state(void *codec_handle, codec_state_e *state); -int codec_v4l2_set_command(void *codec_handle, int64_t command, void *value); -int codec_v4l2_get_command(void *codec_handle, int64_t command, void **value); -int codec_v4l2_set_batch_command(void *codec_handle, codec_batch_command_control_s *batch_command, int64_t *error_command); +int codec_v4l2_get_state(void *codec_handle, hal_codec_state_e *state); +int codec_v4l2_set_command(void *codec_handle, hal_codec_command_e command, void *value); +int codec_v4l2_get_command(void *codec_handle, hal_codec_command_e command, void **value); +int codec_v4l2_set_batch_command(void *codec_handle, hal_codec_batch_command_control_s *batch_command, hal_codec_command_e *error_command); #endif /* __HAL_BACKEND_CODEC_V4L2_PRIVATE_H__ */