From 7b447016de40b698b2ec27e4a292534b25c30ba5 Mon Sep 17 00:00:00 2001 From: Jeongmo Yang Date: Fri, 4 Apr 2025 11:44:31 +0900 Subject: [PATCH] Support H.264 encoder Signed-off-by: Jeongmo Yang --- packaging/hal-backend-codec-v4l2.spec | 4 +- src/hal_backend_codec_v4l2.c | 413 +++++++++++++++++++------- src/hal_backend_codec_v4l2_private.h | 17 +- 3 files changed, 324 insertions(+), 110 deletions(-) diff --git a/packaging/hal-backend-codec-v4l2.spec b/packaging/hal-backend-codec-v4l2.spec index fe7be4d..9abbf4a 100644 --- a/packaging/hal-backend-codec-v4l2.spec +++ b/packaging/hal-backend-codec-v4l2.spec @@ -1,8 +1,6 @@ -%define disable_hal_rootstrap_checker 1 - Name: hal-backend-codec-v4l2 Summary: Tizen Codec HAL using generic V4L2 interface -Version: 0.0.1 +Version: 1.0.0 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 34248fe..e4947d6 100644 --- a/src/hal_backend_codec_v4l2.c +++ b/src/hal_backend_codec_v4l2.c @@ -86,12 +86,10 @@ #define POLL_ERROR_TRY_COUNT_MAX 10 #define POLL_ERROR_TRY_SLEEP_US 10000 +#define CODEC_IS_DECODER(handle) ((handle)->type == HAL_CODEC_TYPE_DECODER) +#define BUFFER_CONTROL_TYPE_IS_INPUT(buffer_control) ((buffer_control)->type == CODEC_HAL_BUFFER_CONTROL_TYPE_INPUT) +#define BUFFER_CONTROL_TYPE_STRING(buffer_control) (((buffer_control)->type == CODEC_HAL_BUFFER_CONTROL_TYPE_INPUT) ? "INPUT" : "OUTPUT") -#define BUFFER_CONTROL_TYPE_STRING(buffer_control) \ - (((buffer_control)->type == CODEC_HAL_BUFFER_CONTROL_TYPE_INPUT) ? "INPUT" : "OUTPUT") - -#define BUFFER_CONTROL_TYPE_IS_INPUT(buffer_control) \ - ((buffer_control->type == CODEC_HAL_BUFFER_CONTROL_TYPE_INPUT) ? TRUE : FALSE) #define TIMESTAMP_TO_TIMEVAL(timestamp, timeval) \ do { \ @@ -162,7 +160,8 @@ static hal_codec_buffer_s *__codec_v4l2_get_idle_buffer(codec_hal_buffer_control 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, hal_codec_format_e *format); -static int __codec_get_fourcc_plane_num(hal_codec_format_e format, uint32_t *fourcc, uint32_t *plane_num); +static int __codec_v4l2_get_fourcc_plane_num(hal_codec_format_e format, uint32_t *fourcc, uint32_t *plane_num); +static const char *__codec_v4l2_get_format_string(hal_codec_format_e format); @@ -445,8 +444,8 @@ static int __codec_v4l2_get_device_info(hal_codec_format_e in_format, hal_codec_ } if (format_index == format_list->count) { - LOGW("in_format[%d] not found in device[%d][%s]", - in_format, device_index, codec_device->node_path); + LOGW("in_format[%s] not found in device[%d][%s]", + __codec_v4l2_get_format_string(in_format), device_index, codec_device->node_path); continue; } @@ -461,8 +460,10 @@ static int __codec_v4l2_get_device_info(hal_codec_format_e in_format, hal_codec_ out_max_resolution->height = format_list->max_resolution[format_index].height; } - 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); + LOGI("found node path[%s], buf_type[in:%d, out:%d] for format[in:%s, out:%s]", + *path, *in_buf_type, *out_buf_type, + __codec_v4l2_get_format_string(in_format), + __codec_v4l2_get_format_string(out_format)); return HAL_CODEC_ERROR_NONE; } @@ -595,8 +596,10 @@ static int __codec_v4l2_set_config(codec_hal_buffer_control_s *buffer_control, codec_config = &buffer_control->config; - LOGI("type[%d] v4l2[buf type:%d, memory:%d], format[0x%x], resolution[%dx%d][max:%dx%d]", - buffer_control->type, buf_type, memory, format, width, height, max_width, max_height); + LOGI("type[%d] v4l2[buf type:%d, memory:%d], format[%s], resolution[%dx%d][max:%dx%d]", + buffer_control->type, buf_type, memory, + __codec_v4l2_get_format_string(format), + width, height, max_width, max_height); codec_config->buf_type = buf_type; codec_config->memory = memory; @@ -625,7 +628,7 @@ static int __codec_v4l2_s_fmt(codec_hal_buffer_control_s *buffer_control, int de codec_config = &buffer_control->config; - if (__codec_get_fourcc_plane_num(codec_config->format, &fourcc, &num_planes) != HAL_CODEC_ERROR_NONE) { + if (__codec_v4l2_get_fourcc_plane_num(codec_config->format, &fourcc, &num_planes) != HAL_CODEC_ERROR_NONE) { LOGE("[%s] get fourcc failed for format [0x%x]", BUFFER_CONTROL_TYPE_STRING(buffer_control), codec_config->format); return HAL_CODEC_ERROR_INVALID_PARAMETER; @@ -787,7 +790,7 @@ static int __codec_v4l2_qbuf(int device_fd, if (codec_config->memory == V4L2_MEMORY_DMABUF) { if (codec_memory->num_fd == 0 || codec_memory->num_fd > HAL_CODEC_BUFFER_PLANE_MAX) { - LOGE("[%s] QBUF invalid num_fd[%u]", + LOGE("[%s] QBUF[DMABUF] invalid num_fd[%u]", BUFFER_CONTROL_TYPE_STRING(buffer_control), codec_memory->num_fd); return HAL_CODEC_ERROR_INVALID_PARAMETER; @@ -795,36 +798,56 @@ static int __codec_v4l2_qbuf(int device_fd, if (V4L2_TYPE_IS_MULTIPLANAR(codec_config->buf_type)) { for (i = 0 ; i < codec_memory->num_fd ; i++) { - LOGD("[%s] QBUF plane[%d] fd %d", + LOGD("[%s] QBUF[DMABUF] plane[%d] fd[%d], length[%u], bytesused[%u]", BUFFER_CONTROL_TYPE_STRING(buffer_control), - i, codec_memory->fd[i]); + i, codec_memory->fd[i], + codec_buffer->planes.plane[i].size, + codec_buffer->planes.plane[i].bytesused); + v4l2_buf.m.planes[i].m.fd = codec_memory->fd[i]; + v4l2_buf.m.planes[i].bytesused = codec_buffer->planes.plane[i].bytesused; + v4l2_buf.m.planes[i].length = codec_buffer->planes.plane[i].size; + } + + if (codec_memory->num_fd == 1 && + codec_buffer->planes.num_planes != codec_memory->num_fd) { + LOGD(" update planes[0].bytesused,length [%u,%u] -> [%u,%u]", + v4l2_buf.m.planes[0].bytesused, v4l2_buf.m.planes[0].length, + codec_buffer->size, codec_buffer->size); + + v4l2_buf.m.planes[0].bytesused = codec_buffer->size; + v4l2_buf.m.planes[0].length = codec_buffer->size; } + + v4l2_buf.length = codec_memory->num_fd; } else { - if (codec_memory->num_fd != 1) - LOGW("[%s] QBUF invalid num_fd[%u]", + if (codec_memory->num_fd != 1) { + LOGW("[%s] QBUF[DMABUF] invalid num_fd[%u]", BUFFER_CONTROL_TYPE_STRING(buffer_control), codec_memory->num_fd); + } v4l2_buf.m.fd = codec_memory->fd[0]; + v4l2_buf.bytesused = codec_buffer->size; + v4l2_buf.length = codec_buffer->size; } - - v4l2_buf.length = codec_memory->num_fd; } else { /* V4L2_MEMORY_MMAP */ - v4l2_buf.length = 1; if (V4L2_TYPE_IS_MULTIPLANAR(codec_config->buf_type)) { - v4l2_buf.m.planes[0].bytesused = codec_buffer->planes.plane[0].bytesused; - - LOGD("[%s] QBUF multiplanar: bytesused[%u]", + LOGD("[%s] QBUF[MMAP] multiplanar: bytesused[%u]", BUFFER_CONTROL_TYPE_STRING(buffer_control), - v4l2_buf.m.planes[0].bytesused); - } else { - v4l2_buf.bytesused = codec_buffer->planes.plane[0].bytesused; + codec_buffer->planes.plane[0].bytesused); - LOGD("[%s] QBUF singleplanar: bytesused[%u]", + v4l2_buf.m.planes[0].bytesused = codec_buffer->planes.plane[0].bytesused; + v4l2_buf.m.planes[0].length = codec_buffer->planes.plane[0].size; + v4l2_buf.length = 1; + } else { + LOGD("[%s] QBUF[MMAP] singleplanar: bytesused[%u]", BUFFER_CONTROL_TYPE_STRING(buffer_control), - v4l2_buf.bytesused); + codec_buffer->planes.plane[0].bytesused); + + v4l2_buf.bytesused = codec_buffer->planes.plane[0].bytesused; + v4l2_buf.length = codec_buffer->planes.plane[0].size; } } @@ -905,6 +928,10 @@ static int __codec_v4l2_dqbuf(int device_fd, buffer_control->buffers.queued_count); } + *out_buffer = &buffer_control->buffers.buffer[v4l2_buf.index]; + + (*out_buffer)->meta.flags = HAL_CODEC_BUFFER_FLAG_NONE; + if (V4L2_TYPE_IS_MULTIPLANAR(codec_config->buf_type)) { LOGD("[%s] DQBUF done: index[%d], length[%u], bytesused[0:%u,1:%u], queued_count[%d]", BUFFER_CONTROL_TYPE_STRING(buffer_control), @@ -912,16 +939,18 @@ static int __codec_v4l2_dqbuf(int device_fd, v4l2_buf.m.planes[0].bytesused, v4l2_buf.m.planes[1].bytesused, buffer_control->buffers.queued_count); + + if (codec_config->format & HAL_CODEC_FORMAT_TYPE_ENCODED) + (*out_buffer)->planes.plane[0].bytesused = v4l2_buf.m.planes[0].bytesused; } else { LOGD("[%s] DQBUF done: index[%d], bytesused[%u], length[%u], queued_count[%d]", BUFFER_CONTROL_TYPE_STRING(buffer_control), v4l2_buf.index, v4l2_buf.bytesused, v4l2_buf.length, buffer_control->buffers.queued_count); - } - - *out_buffer = &buffer_control->buffers.buffer[v4l2_buf.index]; - (*out_buffer)->meta.flags = HAL_CODEC_BUFFER_FLAG_NONE; + if (codec_config->format & HAL_CODEC_FORMAT_TYPE_ENCODED) + (*out_buffer)->planes.plane[0].bytesused = v4l2_buf.bytesused; + } if (!BUFFER_CONTROL_TYPE_IS_INPUT(buffer_control)) { TIMEVAL_TO_TIMESTAMP(v4l2_buf.timestamp, (*out_buffer)->meta.timestamp); @@ -980,14 +1009,54 @@ static int __codec_v4l2_get_format(guint32 fourcc, hal_codec_format_e *format) return HAL_CODEC_ERROR_INTERNAL; } - LOGI("fourcc ["FOURCC_FORMAT"] -> format [0x%x]", - FOURCC_CONVERT(fourcc), *format); + LOGI("fourcc ["FOURCC_FORMAT"] -> format [%s][0x%x]", + FOURCC_CONVERT(fourcc), __codec_v4l2_get_format_string(*format), *format); return HAL_CODEC_ERROR_NONE; } -static int __codec_get_fourcc_plane_num(hal_codec_format_e format, uint32_t *fourcc, uint32_t *plane_num) +static const char *__codec_v4l2_get_format_string(hal_codec_format_e format) +{ + switch (format) { + case HAL_CODEC_FORMAT_NV12: + return "NV12"; + case HAL_CODEC_FORMAT_NV12T: + return "NV12T"; + case HAL_CODEC_FORMAT_NV21: + return "NV21"; + case HAL_CODEC_FORMAT_I420: + return "I420"; + case HAL_CODEC_FORMAT_YV12: + return "YV12"; + case HAL_CODEC_FORMAT_YUYV: + return "YUYV"; + case HAL_CODEC_FORMAT_UYVY: + return "UYVY"; + case HAL_CODEC_FORMAT_H264: + return "H264"; + case HAL_CODEC_FORMAT_H265: + return "H265"; + case HAL_CODEC_FORMAT_H266: + return "H266"; + case HAL_CODEC_FORMAT_VP8: + return "VP8"; + case HAL_CODEC_FORMAT_VP9: + return "VP9"; + case HAL_CODEC_FORMAT_AV1: + return "AV1"; + case HAL_CODEC_FORMAT_BGRA8888: + return "BGRA8888"; + case HAL_CODEC_FORMAT_ARGB8888: + return "ARGB8888"; + default: + LOGE("unhandled format [%d]", format); + return "UNKONWN"; + } +} + + +static int __codec_v4l2_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); @@ -1032,8 +1101,8 @@ static int __codec_get_fourcc_plane_num(hal_codec_format_e format, uint32_t *fou return HAL_CODEC_ERROR_INTERNAL; } - LOGD("format [0x%x] -> fourcc ["FOURCC_FORMAT"]", - format, FOURCC_CONVERT(*fourcc)); + LOGD("format [%s][0x%x] -> fourcc ["FOURCC_FORMAT"]", + __codec_v4l2_get_format_string(format), format, FOURCC_CONVERT(*fourcc)); return HAL_CODEC_ERROR_NONE; } @@ -1066,7 +1135,8 @@ static int __codec_v4l2_stop_stream(codec_hal_handle_s *handle, codec_hal_buffer return ret; } - if (config->memory == V4L2_MEMORY_DMABUF) { + if (!BUFFER_CONTROL_TYPE_IS_INPUT(buffer_control)) { + /* DECODER+ENCODER: wait for output buffer */ g_mutex_lock(&buffer_control->lock); while (buffer_control->buffers.queued_count < buffer_control->buffers.count) { @@ -1086,25 +1156,31 @@ static int __codec_v4l2_stop_stream(codec_hal_handle_s *handle, codec_hal_buffer g_mutex_unlock(&buffer_control->lock); - for (i = 0 ; i < buffers->count ; i++) { - codec_buffer = &buffers->buffer[i]; - codec_memory = &codec_buffer->memory; - - for (k = 0 ; k < codec_memory->num_fd ; k++) { - if (codec_memory->fd[k] > CODEC_HAL_INITIAL_FD) { - LOGI("[%s][%d][%d] close fd[%d]", BUFFER_CONTROL_TYPE_STRING(buffer_control), i, k, codec_memory->fd[k]); - close(codec_memory->fd[k]); - codec_memory->fd[k] = CODEC_HAL_INITIAL_FD; - } - - if (buffers->bo[i][k]) { - LOGI("[%s][%d][%d] unref bo[%p]", BUFFER_CONTROL_TYPE_STRING(buffer_control), i, k, buffers->bo[i][k]); - tbm_bo_unref(buffers->bo[i][k]); - buffers->bo[i][k] = NULL; + if (config->memory == V4L2_MEMORY_DMABUF) { + /* DECODER: release allocated bo and fd */ + for (i = 0 ; i < buffers->count ; i++) { + codec_buffer = &buffers->buffer[i]; + codec_memory = &codec_buffer->memory; + + for (k = 0 ; k < codec_memory->num_fd ; k++) { + if (codec_memory->fd[k] > CODEC_HAL_INITIAL_FD) { + LOGI("[%s][%d][%d] close fd[%d]", BUFFER_CONTROL_TYPE_STRING(buffer_control), i, k, codec_memory->fd[k]); + close(codec_memory->fd[k]); + codec_memory->fd[k] = CODEC_HAL_INITIAL_FD; + } + + if (buffers->bo[i][k]) { + LOGI("[%s][%d][%d] unref bo[%p]", BUFFER_CONTROL_TYPE_STRING(buffer_control), i, k, buffers->bo[i][k]); + tbm_bo_unref(buffers->bo[i][k]); + buffers->bo[i][k] = NULL; + } } } } - } else { + } + + if (config->memory == V4L2_MEMORY_MMAP) { + /* DECODER+ENCODER: release mapped memory */ for (i = 0 ; i < buffers->count ; i++) { codec_buffer = &buffers->buffer[i]; @@ -1122,8 +1198,13 @@ static int __codec_v4l2_stop_stream(codec_hal_handle_s *handle, codec_hal_buffer codec_buffer->planes.plane[0].data = NULL; codec_buffer->size = 0; } + } + if (BUFFER_CONTROL_TYPE_IS_INPUT(buffer_control)) { + /* DECODER+ENCODER: clear queue for input buffers */ + g_mutex_lock(&buffer_control->lock); g_queue_clear(buffers->idle_buffers); + g_mutex_unlock(&buffer_control->lock); } ret = __codec_v4l2_reqbufs(handle->device_fd, config->buf_type, config->memory, 0, NULL); @@ -1238,40 +1319,45 @@ static int __codec_v4l2_start_stream(codec_hal_handle_s *handle, } } 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; - } + if (CODEC_IS_DECODER(handle)) { + 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; - } + 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; + } - 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; + 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; + } + + buffers->bo[i][0] = new_bo; + codec_memory->num_fd = 1; } - buffers->bo[i][0] = new_bo; - codec_memory->num_fd = 1; + if (bo_handle.ptr) { + codec_buffer->planes.plane[0].data = bo_handle.ptr; + codec_buffer->planes.plane[1].data = bo_handle.ptr + handle->ts_info.planes[0].size; + } - 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("type[%d] buffer[%d], size[%u], new bo[%p], vaddr[%p]", + type, i, codec_buffer->size, 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, @@ -1657,6 +1743,31 @@ static uint32_t __codec_v4l2_get_tbm_format(hal_codec_format_e codec_format) } +static int __codec_v4l2_get_type(hal_codec_format_e format, hal_codec_format_type_e *type) +{ + if (!type) { + LOGE("NULL type"); + return HAL_CODEC_ERROR_INVALID_PARAMETER; + } + + if (format & HAL_CODEC_FORMAT_TYPE_ENCODED) { + *type = HAL_CODEC_FORMAT_TYPE_ENCODED; + LOGI("format[%s] - ENCODED", __codec_v4l2_get_format_string(format)); + return HAL_CODEC_ERROR_NONE; + } + + if (format & HAL_CODEC_FORMAT_TYPE_RAW) { + *type = HAL_CODEC_FORMAT_TYPE_RAW; + LOGI("format[%s] - RAW", __codec_v4l2_get_format_string(format)); + return HAL_CODEC_ERROR_NONE; + } + + LOGE("invalid format[%s]", __codec_v4l2_get_format_string(format)); + + return HAL_CODEC_ERROR_INVALID_PARAMETER; +} + + 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) { @@ -1664,14 +1775,20 @@ int codec_v4l2_configure(void *codec_handle, int width, int height, int ret = 0; int device_fd = CODEC_HAL_INITIAL_FD; uint32_t input_id = 0; + hal_codec_format_e hal_format = HAL_CODEC_FORMAT_NV12; + hal_codec_format_type_e in_format_type = HAL_CODEC_FORMAT_TYPE_ENCODED; + hal_codec_format_type_e out_format_type = HAL_CODEC_FORMAT_TYPE_ENCODED; hal_codec_resolution_s in_max_resolution = {0, 0}; hal_codec_resolution_s out_max_resolution = {0, 0}; char *node_path = NULL; codec_hal_handle_s *handle = (codec_hal_handle_s *)codec_handle; + codec_hal_buffer_control_s *buffer_control = NULL; enum v4l2_buf_type in_buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT; enum v4l2_buf_type out_buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + enum v4l2_memory in_memory = V4L2_MEMORY_MMAP; + enum v4l2_memory out_memory = V4L2_MEMORY_MMAP; tbm_surface_h surface = NULL; @@ -1689,9 +1806,20 @@ int codec_v4l2_configure(void *codec_handle, int width, int height, return HAL_CODEC_ERROR_INVALID_STATE; } - 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); + ret = __codec_v4l2_get_type(in_format, &in_format_type); + if (ret != HAL_CODEC_ERROR_NONE) { + LOGE("invalid in_format[0x%x]", in_format); + return ret; + } + + ret = __codec_v4l2_get_type(out_format, &out_format_type); + if (ret != HAL_CODEC_ERROR_NONE) { + LOGE("invalid out_format[0x%x]", out_format); + return ret; + } + + if (in_format_type == out_format_type) { + LOGE("invalid format : in[0x%x], out[0x%x], type[%d]", in_format, out_format, in_format_type); return HAL_CODEC_ERROR_INVALID_PARAMETER; } @@ -1700,9 +1828,11 @@ int codec_v4l2_configure(void *codec_handle, int width, int height, if (ret != HAL_CODEC_ERROR_NONE) return ret; - surface = tbm_surface_create(width, height, __codec_v4l2_get_tbm_format(out_format)); + hal_format = CODEC_IS_DECODER(handle) ? out_format : in_format; + + surface = tbm_surface_create(width, height, __codec_v4l2_get_tbm_format(hal_format)); if (!surface) { - LOGE("create surface failed [%dx%d][format:%d]", width, height, out_format); + LOGE("create surface failed [%dx%d][format:%d]", width, height, hal_format); return HAL_CODEC_ERROR_INTERNAL; } @@ -1731,21 +1861,32 @@ int codec_v4l2_configure(void *codec_handle, int width, int height, } /* subscribe SOURCE_CHANGE event */ - if (ioctl(device_fd, VIDIOC_G_INPUT, &input_id) < 0) - LOGW("G_INPUT failed, use default input id[%d]", input_id); + if (CODEC_IS_DECODER(handle)) { + if (ioctl(device_fd, VIDIOC_G_INPUT, &input_id) < 0) + LOGW("G_INPUT failed, use default input id[%d]", input_id); - if (__codec_v4l2_subscribe_event(device_fd, V4L2_EVENT_SOURCE_CHANGE, input_id) != HAL_CODEC_ERROR_NONE) { - LOGW("subscribe event[SOURCE_CHANGE] failed"); - return HAL_CODEC_ERROR_DEVICE_READ; + if (__codec_v4l2_subscribe_event(device_fd, V4L2_EVENT_SOURCE_CHANGE, input_id) != HAL_CODEC_ERROR_NONE) { + LOGW("subscribe event[SOURCE_CHANGE] failed"); + return HAL_CODEC_ERROR_DEVICE_READ; + } + + in_memory = V4L2_MEMORY_MMAP; + out_memory = V4L2_MEMORY_DMABUF; + } else { + in_memory = V4L2_MEMORY_DMABUF; + out_memory = V4L2_MEMORY_MMAP; } /* set format for input */ - ret = __codec_v4l2_set_config(&handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_INPUT], - in_buf_type, V4L2_MEMORY_MMAP, in_format, width, height, in_max_resolution.width, in_max_resolution.height); + buffer_control = &handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_INPUT]; + + ret = __codec_v4l2_set_config(buffer_control, + in_buf_type, in_memory, in_format, width, height, + in_max_resolution.width, in_max_resolution.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); + ret = __codec_v4l2_s_fmt(buffer_control, device_fd); if (ret != HAL_CODEC_ERROR_NONE) { LOGE("set format[%d] for input failed - [0x%x]", in_format, ret); close(device_fd); @@ -1753,12 +1894,15 @@ int codec_v4l2_configure(void *codec_handle, int width, int height, } /* set format for output */ - ret = __codec_v4l2_set_config(&handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_OUTPUT], - out_buf_type, V4L2_MEMORY_DMABUF, out_format, width, height, 0, 0); + buffer_control = &handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_OUTPUT]; + + ret = __codec_v4l2_set_config(buffer_control, + out_buf_type, out_memory, out_format, width, height, + out_max_resolution.width, out_max_resolution.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); + ret = __codec_v4l2_s_fmt(buffer_control, device_fd); if (ret != HAL_CODEC_ERROR_NONE) { LOGE("set format[%d] for output failed - [0x%x]", out_format, ret); close(device_fd); @@ -1891,7 +2035,7 @@ static void __codec_v4l2_restart_output_stream(codec_hal_handle_s *handle) config->resolution.width = new_width; config->resolution.height = new_height; - ret = __codec_v4l2_start_stream(handle, buffer_control, BUFFER_NUM_OUTPUT); + ret = __codec_v4l2_start_stream(handle, buffer_control, BUFFER_NUM_DECODER_OUTPUT); if (ret != HAL_CODEC_ERROR_NONE) { LOGE("[output] __codec_start_stream failed[0x%x]", ret); return; @@ -1930,9 +2074,6 @@ static gpointer __codec_v4l2_buffer_handler_func(gpointer data) output_control = &handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_OUTPUT]; while (run_loop) { - /* exit thread with some conditions */ - ////////////////////////////////////// - poll_errno = 0; ret = __codec_v4l2_poll(handle, (POLLIN | POLLOUT | POLLPRI), OUTPUT_POLL_TIMEOUT_MS, &revents, &poll_errno); @@ -2049,13 +2190,15 @@ int codec_v4l2_start(void *codec_handle, hal_codec_message_cb callback, void *us return HAL_CODEC_ERROR_INVALID_STATE; } - ret = __codec_v4l2_start_stream(handle, &handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_INPUT], BUFFER_NUM_INPUT); + ret = __codec_v4l2_start_stream(handle, &handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_INPUT], + CODEC_IS_DECODER(handle) ? BUFFER_NUM_DECODER_INPUT : BUFFER_NUM_ENCODER_INPUT); if (ret != HAL_CODEC_ERROR_NONE) { LOGE("[input] __codec_start_stream failed[0x%x]", ret); return ret; } - ret = __codec_v4l2_start_stream(handle, &handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_OUTPUT], BUFFER_NUM_OUTPUT); + ret = __codec_v4l2_start_stream(handle, &handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_OUTPUT], + CODEC_IS_DECODER(handle) ? BUFFER_NUM_DECODER_OUTPUT : BUFFER_NUM_ENCODER_OUTPUT); if (ret != HAL_CODEC_ERROR_NONE) { LOGE("[output] __codec_start_stream failed[0x%x]", ret); return ret; @@ -2235,7 +2378,7 @@ int codec_v4l2_decode(void *codec_handle, hal_codec_buffer_s *buffer) if (buffer->meta.flags & HAL_CODEC_BUFFER_FLAG_EOS) { struct v4l2_decoder_cmd dcmd = { 0, }; - LOGW("EOS - VIDIOC_DECODER_CMD: V4L2_DEC_CMD_STOP"); + LOGW("EOS: V4L2_DEC_CMD_STOP"); dcmd.cmd = V4L2_DEC_CMD_STOP; @@ -2277,6 +2420,75 @@ int codec_v4l2_decode(void *codec_handle, hal_codec_buffer_s *buffer) } +int codec_v4l2_encode(void *codec_handle, hal_codec_buffer_s *buffer) +{ + uint32_t i = 0; + 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); + + 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]; + + if (buffer->meta.flags & HAL_CODEC_BUFFER_FLAG_EOS) { + struct v4l2_encoder_cmd ecmd = { 0, }; + + LOGW("EOS: V4L2_ENC_CMD_STOP"); + + ecmd.cmd = V4L2_ENC_CMD_STOP; + + if (ioctl(handle->device_fd, VIDIOC_ENCODER_CMD, &ecmd) < 0) + LOGE("V4L2_ENC_CMD_STOP failed %d", errno); + + __codec_v4l2_message_send(handle, HAL_CODEC_MESSAGE_TYPE_INPUT_BUFFER_USED, buffer); + + LOGW("done"); + + return HAL_CODEC_ERROR_NONE; + } + + idle_buffer = __codec_v4l2_get_idle_buffer(buffer_control, 0); + if (!idle_buffer) { + LOGE("no idle buffer"); + return HAL_CODEC_ERROR_DEVICE_BUSY; + } + + idle_buffer->memory.num_fd = buffer->memory.num_fd; + for (i = 0 ; i < buffer->memory.num_fd ; i++) { + LOGD("[INPUT] buffer[%d]: memory[%u] fd %d", buffer->index, i, buffer->memory.fd[i]); + idle_buffer->memory.fd[i] = buffer->memory.fd[i]; + } + + 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); + return ret; + } + + LOGD("QBUF[%p] done", buffer); + + return HAL_CODEC_ERROR_NONE; +} + + int codec_v4l2_release_output_buffer(void *codec_handle, int buffer_index) { int ret = HAL_CODEC_ERROR_NONE; @@ -2521,6 +2733,7 @@ static int codec_v4l2_backend_init(void **data) funcs->stop = codec_v4l2_stop; funcs->flush = codec_v4l2_flush; funcs->decode = codec_v4l2_decode; + funcs->encode = codec_v4l2_encode; 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 9bb1882..e03d8d1 100644 --- a/src/hal_backend_codec_v4l2_private.h +++ b/src/hal_backend_codec_v4l2_private.h @@ -29,10 +29,12 @@ #define CODEC_HAL_INITIAL_INDEX -1 #define CODEC_HAL_INITIAL_FD -1 -#define BUFFER_MIN 2 -#define BUFFER_MAX 16 -#define BUFFER_NUM_INPUT 4 -#define BUFFER_NUM_OUTPUT 8 +#define BUFFER_NUM_MIN 2 +#define BUFFER_NUM_MAX 16 +#define BUFFER_NUM_DECODER_INPUT 4 +#define BUFFER_NUM_DECODER_OUTPUT 8 +#define BUFFER_NUM_ENCODER_INPUT 8 +#define BUFFER_NUM_ENCODER_OUTPUT 4 #define V4L2_PLANES_MAX 4 @@ -64,9 +66,9 @@ typedef struct { typedef struct { uint32_t count; - hal_codec_buffer_s buffer[BUFFER_MAX]; - tbm_bo bo[BUFFER_MAX][HAL_CODEC_BUFFER_PLANE_MAX]; - gboolean is_queued[BUFFER_MAX]; + hal_codec_buffer_s buffer[BUFFER_NUM_MAX]; + tbm_bo bo[BUFFER_NUM_MAX][HAL_CODEC_BUFFER_PLANE_MAX]; + gboolean is_queued[BUFFER_NUM_MAX]; int queued_count; GQueue *idle_buffers; } codec_hal_buffers_s; @@ -128,6 +130,7 @@ int codec_v4l2_start(void *codec_handle, hal_codec_message_cb callback, void *us int codec_v4l2_stop(void *codec_handle); int codec_v4l2_flush(void *codec_handle); int codec_v4l2_decode(void *codec_handle, hal_codec_buffer_s *buffer); +int codec_v4l2_encode(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, hal_codec_state_e *state); int codec_v4l2_set_command(void *codec_handle, hal_codec_command_e command, void *value); -- 2.34.1