From: Jeongmo Yang Date: Thu, 13 Feb 2025 02:49:11 +0000 (+0900) Subject: Support SOURCE_CHANGE event X-Git-Tag: accepted/tizen/unified/20250610.081745~6 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c6f84d60af56cc22d1b3b946f4d99ef95de142f8;p=platform%2Fhal%2Fbackend%2Fcodec-v4l2.git Support SOURCE_CHANGE event Signed-off-by: Jeongmo Yang --- diff --git a/src/hal_backend_codec_v4l2.c b/src/hal_backend_codec_v4l2.c index 67d284f..128518d 100644 --- a/src/hal_backend_codec_v4l2.c +++ b/src/hal_backend_codec_v4l2.c @@ -499,6 +499,9 @@ static void __codec_v4l2_message_send(codec_hal_handle_s *handle, hal_codec_mess message, message->buffer->index, message->buffer); break; case HAL_CODEC_MESSAGE_TYPE_RESOLUTION_CHANGED: + message->resolution.width = ((hal_codec_resolution_s *)value)->width; + message->resolution.height = ((hal_codec_resolution_s *)value)->height; + LOGI("ResolutionChanged[%dx%d]", message->resolution.width, message->resolution.height); break; case HAL_CODEC_MESSAGE_TYPE_ERROR: message->error_code = GPOINTER_TO_INT(value); @@ -561,6 +564,21 @@ static int __codec_v4l2_s_ctrl(int device_fd, int cid, int value) } +static int __codec_v4l2_subscribe_event(int device_fd, uint32_t event, uint32_t input_id) +{ + struct v4l2_event_subscription subscription = {.type = event, .id = input_id, }; + + LOGI("subscribe event[%u], input_id[%u]", subscription.type, subscription.id); + + if (ioctl(device_fd, VIDIOC_SUBSCRIBE_EVENT, &subscription) < 0) { + LOGW("failed[%s]", __codec_v4l2_get_error_string(errno)); + return HAL_CODEC_ERROR_INTERNAL; + } + + return HAL_CODEC_ERROR_NONE; +} + + 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, int max_width, int max_height) @@ -1038,19 +1056,16 @@ static int __codec_v4l2_stop_stream(codec_hal_handle_s *handle) LOGI("start"); - /* stream off */ - 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; - } - } - - /* wait for output buffer */ + /* output */ buffer_control = &handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_OUTPUT]; + ret = __codec_v4l2_stream(handle->device_fd, + buffer_control->config.buf_type, FALSE); + if (ret != HAL_CODEC_ERROR_NONE) { + LOGE("[OUTPUT] STREAMOFF failed[0x%x]", ret); + return ret; + } + g_mutex_lock(&buffer_control->lock); while (buffer_control->buffers.queued_count < buffer_control->buffers.count) { @@ -1071,7 +1086,6 @@ static int __codec_v4l2_stop_stream(codec_hal_handle_s *handle) g_mutex_unlock(&buffer_control->lock); /* release output buffer */ - buffer_control = &handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_OUTPUT]; buffers = &buffer_control->buffers; for (i = 0 ; i < buffers->count ; i++) { @@ -1100,10 +1114,17 @@ static int __codec_v4l2_stop_stream(codec_hal_handle_s *handle) return ret; } - /* release input buffer */ + /* input */ buffer_control = &handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_INPUT]; buffers = &buffer_control->buffers; + ret = __codec_v4l2_stream(handle->device_fd, + buffer_control->config.buf_type, FALSE); + if (ret != HAL_CODEC_ERROR_NONE) { + LOGE("[INPUT] STREAMOFF failed[0x%x]", ret); + return ret; + } + for (i = 0 ; i < buffers->count ; i++) { codec_buffer = &buffers->buffer[i]; @@ -1662,6 +1683,7 @@ int codec_v4l2_configure(void *codec_handle, int width, int height, int i = 0; int ret = 0; int device_fd = CODEC_HAL_INITIAL_FD; + uint32_t input_id = 0; hal_codec_resolution_s in_max_resolution = {0, 0}; hal_codec_resolution_s out_max_resolution = {0, 0}; char *node_path = NULL; @@ -1728,6 +1750,15 @@ int codec_v4l2_configure(void *codec_handle, int width, int height, return HAL_CODEC_ERROR_DEVICE_OPEN; } + /* 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_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; + } + /* 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); @@ -1833,6 +1864,119 @@ static int __codec_v4l2_poll(codec_hal_handle_s *handle, short events, int timeo } +static void __codec_v4l2_restart_output_stream(codec_hal_handle_s *handle) +{ + int i = 0; + int k = 0; + int ret = 0; + int new_width = 0; + int new_height = 0; + gint64 end_time = 0; + struct v4l2_format v4l2_fmt; + hal_codec_memory_s *codec_memory = NULL; + hal_codec_buffer_s *codec_buffer = NULL; + codec_hal_buffer_control_s *buffer_control = NULL; + codec_hal_buffers_s *buffers = NULL; + + if (!handle) { + LOGE("NULL handle"); + return; + } + + LOGI("start"); + + buffer_control = &handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_OUTPUT]; + + ret = __codec_v4l2_stream(handle->device_fd, + buffer_control->config.buf_type, FALSE); + if (ret != HAL_CODEC_ERROR_NONE) { + LOGE("[OUTPUT] STREAMOFF failed[0x%x]", ret); + return; + } + + g_mutex_lock(&buffer_control->lock); + + while (buffer_control->buffers.queued_count < buffer_control->buffers.count) { + LOGW("wait for output buffer[queued:%d vs count:%u]", + buffer_control->buffers.queued_count, buffer_control->buffers.count); + + end_time = g_get_monotonic_time() + G_TIME_SPAN_SECOND; + + if (!g_cond_wait_until(&buffer_control->cond, &buffer_control->lock, end_time)) { + LOGE("timeout: wait for output buffer"); + break; + } + + LOGW("signal received, check it again[queued:%d,count:%u]", + buffer_control->buffers.queued_count, buffer_control->buffers.count); + } + + g_mutex_unlock(&buffer_control->lock); + + /* release output buffer */ + buffers = &buffer_control->buffers; + + 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("[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; + } + + if (buffers->bo[i][k]) { + LOGI("[OUTPUT][%d][%d] unref bo[%p]", i, k, buffers->bo[i][k]); + tbm_bo_unref(buffers->bo[i][k]); + buffers->bo[i][k] = NULL; + } + } + } + + ret = __codec_v4l2_reqbufs(handle->device_fd, + 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; + } + + memset(&v4l2_fmt, 0x0, sizeof(struct v4l2_format)); + + v4l2_fmt.type = buffer_control->config.buf_type; + + if (ioctl(handle->device_fd, VIDIOC_G_FMT, &v4l2_fmt) < 0) { + LOGE("G_FMT failed"); + return; + } + + if (V4L2_TYPE_IS_MULTIPLANAR(buffer_control->config.buf_type)) { + new_width = v4l2_fmt.fmt.pix_mp.width; + new_height = v4l2_fmt.fmt.pix_mp.height; + } else { + new_width = v4l2_fmt.fmt.pix.width; + new_height = v4l2_fmt.fmt.pix.height; + } + + LOGI("new resolution[%dx%d]", new_width, new_height); + + buffer_control->config.resolution.width = new_width; + buffer_control->config.resolution.height = new_height; + + ret = __codec_v4l2_start_stream(handle, buffer_control, BUFFER_NUM_OUTPUT); + if (ret != HAL_CODEC_ERROR_NONE) { + LOGE("[output] __codec_start_stream failed[0x%x]", ret); + return; + } + + __codec_v4l2_message_send(handle, HAL_CODEC_MESSAGE_TYPE_RESOLUTION_CHANGED, + &buffer_control->config.resolution); + + LOGI("done"); +} + + static gpointer __codec_v4l2_buffer_handler_func(gpointer data) { int ret = 0; @@ -1871,6 +2015,21 @@ static gpointer __codec_v4l2_buffer_handler_func(gpointer data) if (ret < 0) break; + if (revents & POLLPRI) { + struct v4l2_event event = { 0, }; + + if (ioctl(handle->device_fd, VIDIOC_DQEVENT, &event) == 0) { + if (event.type == V4L2_EVENT_SOURCE_CHANGE) { + LOGW("SOURCE_CHANGE event detected, restart stream with new resolution"); + __codec_v4l2_restart_output_stream(handle); + } else { + LOGW("Unknown event[%u]", event.type); + } + } else { + LOGI("VIDIOC_DQEVENT failed"); + } + } + if (revents & POLLERR) { LOGE("POLLERR[errno:%d,%s]", poll_errno, __codec_v4l2_get_error_string(poll_errno)); @@ -2170,7 +2329,6 @@ int codec_v4l2_decode(void *codec_handle, hal_codec_buffer_s *buffer) 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);