Update buffer handling
authorJeongmo Yang <jm80.yang@samsung.com>
Fri, 7 Feb 2025 08:41:15 +0000 (17:41 +0900)
committerJeongmo Yang <jm80.yang@samsung.com>
Fri, 7 Feb 2025 08:41:15 +0000 (17:41 +0900)
Signed-off-by: Jeongmo Yang <jm80.yang@samsung.com>
src/hal_backend_codec_v4l2.c
src/hal_backend_codec_v4l2_private.h

index 2fa1139d4dcb0cb442aa3b28ef492cc004316f71..d0ae4e42941c77566eaaf2e2b8d274417d2f3185 100644 (file)
@@ -490,11 +490,13 @@ static void __codec_v4l2_message_send(codec_hal_handle_s *handle, hal_codec_mess
        switch (type) {
        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);
+               LOGD("InputBufferUsed[message:%p]: buffer[i:%d,HAL:%p]",
+                       message, message->buffer->index, message->buffer);
                break;
        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);
+               LOGD("OutputBuffer[message:%p]: buffer[i:%d,HAL:%p]",
+                       message, message->buffer->index, message->buffer);
                break;
        case HAL_CODEC_MESSAGE_TYPE_RESOLUTION_CHANGED:
                break;
@@ -509,6 +511,9 @@ static void __codec_v4l2_message_send(codec_hal_handle_s *handle, hal_codec_mess
        }
 
        g_queue_push_tail(handle->msg_list, message);
+
+       LOGD("message length[%u]", g_queue_get_length(handle->msg_list));
+
        g_cond_broadcast(&handle->msg_cb_cond);
 }
 
@@ -721,12 +726,16 @@ static int __codec_v4l2_qbuf(int device_fd,
        struct v4l2_buffer v4l2_buf;
        struct v4l2_plane v4l2_planes[V4L2_PLANES_MAX];
 
+       g_autoptr(GMutexLocker) locker = NULL;
+
        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;
        }
 
+       locker = g_mutex_locker_new(&buffer_control->lock);
+
        codec_config = &buffer_control->config;
        codec_memory = &codec_buffer->memory;
 
@@ -797,9 +806,15 @@ static int __codec_v4l2_qbuf(int device_fd,
                return HAL_CODEC_ERROR_INTERNAL;
        }
 
-       LOGD("[%s] QBUF done: buffer[%d]",
+       buffer_control->buffers.is_queued[codec_buffer->index] = TRUE;
+       buffer_control->buffers.queued_count++;
+
+       LOGD("[%s] QBUF done: buffer[%d], queued_count[%d]",
                BUFFER_CONTROL_TYPE_STRING(buffer_control->type),
-               codec_buffer->index);
+               codec_buffer->index, buffer_control->buffers.queued_count);
+
+       if (buffer_control->type == CODEC_HAL_BUFFER_CONTROL_TYPE_OUTPUT)
+               g_cond_broadcast(&buffer_control->cond);
 
        return HAL_CODEC_ERROR_NONE;
 }
@@ -816,12 +831,16 @@ static int __codec_v4l2_dqbuf(int device_fd,
        struct v4l2_buffer v4l2_buf;
        struct v4l2_plane v4l2_planes[V4L2_PLANES_MAX];
 
+       g_autoptr(GMutexLocker) locker = NULL;
+
        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;
        }
 
+       locker = g_mutex_locker_new(&buffer_control->lock);
+
        codec_config = &buffer_control->config;
 
        memset(&v4l2_buf, 0x0, sizeof(struct v4l2_buffer));
@@ -841,16 +860,26 @@ static int __codec_v4l2_dqbuf(int device_fd,
                return HAL_CODEC_ERROR_DEVICE_READ;
        }
 
+       buffer_control->buffers.is_queued[v4l2_buf.index] = FALSE;
+       buffer_control->buffers.queued_count--;
+       if (buffer_control->buffers.queued_count < 0) {
+               LOGW("[%s] invalid queued_count[%d], check it.",
+                       BUFFER_CONTROL_TYPE_STRING(buffer_control->type),
+                       buffer_control->buffers.queued_count);
+       }
+
        if (V4L2_TYPE_IS_MULTIPLANAR(codec_config->buf_type)) {
-               LOGD("[%s] DQBUF done: index[%d], length[%u], bytesused[%u,%u]",
+               LOGD("[%s] DQBUF done: index[%d], length[%u], bytesused[0:%u,1:%u], queued_count[%d]",
                        BUFFER_CONTROL_TYPE_STRING(buffer_control->type),
                        v4l2_buf.index, v4l2_buf.length,
                        v4l2_buf.m.planes[0].bytesused,
-                       v4l2_buf.m.planes[1].bytesused);
+                       v4l2_buf.m.planes[1].bytesused,
+                       buffer_control->buffers.queued_count);
        } else {
-               LOGD("[%s] DQBUF done: index[%d], bytesused[%u], length[%u]",
+               LOGD("[%s] DQBUF done: index[%d], bytesused[%u], length[%u], queued_count[%d]",
                        BUFFER_CONTROL_TYPE_STRING(buffer_control->type),
-                       v4l2_buf.index, v4l2_buf.bytesused, v4l2_buf.length);
+                       v4l2_buf.index, v4l2_buf.bytesused, v4l2_buf.length,
+                       buffer_control->buffers.queued_count);
        }
 
        *out_buffer = &buffer_control->buffers.buffer[v4l2_buf.index];
@@ -978,8 +1007,10 @@ static int __codec_v4l2_stop_stream(codec_hal_handle_s *handle)
        int i = 0;
        int k = 0;
        int ret = HAL_CODEC_ERROR_NONE;
+       gint64 end_time = 0;
        hal_codec_memory_s *codec_memory = NULL;
        codec_hal_buffer_control_s *buffer_control = NULL;
+       codec_hal_buffers_s *buffers = NULL;
        hal_codec_buffer_s *codec_buffer = NULL;
 
        if (!handle) {
@@ -999,12 +1030,34 @@ static int __codec_v4l2_stop_stream(codec_hal_handle_s *handle)
                }
        }
 
-       /* decoder */
+       /* wait for output buffer */
+       buffer_control = &handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_OUTPUT];
+
+       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 */
        buffer_control = &handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_OUTPUT];
+       buffers = &buffer_control->buffers;
 
-       for (i = 0 ; i < buffer_control->buffers.count ; i++) {
-               codec_buffer = &buffer_control->buffers.buffer[i];
+       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++) {
@@ -1014,10 +1067,10 @@ static int __codec_v4l2_stop_stream(codec_hal_handle_s *handle)
                                codec_memory->fd[k] = CODEC_HAL_INITIAL_FD;
                        }
 
-                       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;
+                       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;
                        }
                }
        }
@@ -1032,8 +1085,8 @@ static int __codec_v4l2_stop_stream(codec_hal_handle_s *handle)
        /* release input buffer */
        buffer_control = &handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_INPUT];
 
-       for (i = 0 ; i < buffer_control->buffers.count ; i++) {
-               codec_buffer = &buffer_control->buffers.buffer[i];
+       for (i = 0 ; i < buffers->count ; i++) {
+               codec_buffer = &buffers->buffer[i];
 
                if (!codec_buffer->planes.plane[0].data || codec_buffer->size == 0) {
                        LOGW("[INPUT][%d] invalid data[%p], size[%u]",
@@ -1075,6 +1128,7 @@ static int __codec_v4l2_start_stream(codec_hal_handle_s *handle,
        hal_codec_buffer_s *codec_buffer = NULL;
        codec_hal_config_s *codec_config = NULL;
        codec_hal_buffer_control_type_e type;
+       codec_hal_buffers_s *buffers = NULL;
 
        struct v4l2_buffer v4l2_buf;
        struct v4l2_plane v4l2_planes[V4L2_PLANES_MAX];
@@ -1088,6 +1142,7 @@ static int __codec_v4l2_start_stream(codec_hal_handle_s *handle,
        }
 
        type = buffer_control->type;
+       buffers = &buffer_control->buffers;
        codec_config = &buffer_control->config;
 
        LOGI("type[%d] buf_type[%d], memory[%d], plane num[%u], buffer count[%u]",
@@ -1096,19 +1151,22 @@ static int __codec_v4l2_start_stream(codec_hal_handle_s *handle,
 
        ret = __codec_v4l2_reqbufs(handle->device_fd,
                codec_config->buf_type, codec_config->memory,
-               buffer_count, &buffer_control->buffers.count);
+               buffer_count, &buffers->count);
        if (ret != HAL_CODEC_ERROR_NONE) {
                LOGE("type[%d] REQBUFS failed [0x%x]", type, ret);
                return ret;
        }
 
        LOGI("type[%d] buffer count - request[%u] -> result[%u]",
-               type, buffer_count, buffer_control->buffers.count);
+               type, buffer_count, buffers->count);
 
        num_planes = codec_config->num_planes;
 
-       for (i = 0 ; i < buffer_control->buffers.count ; i++) {
-               codec_buffer = &buffer_control->buffers.buffer[i];
+       buffers->queued_count = 0;
+
+       for (i = 0 ; i < buffers->count ; i++) {
+
+               codec_buffer = &buffers->buffer[i];
 
                codec_buffer->index = i;
                codec_buffer->meta.format = codec_config->format;
@@ -1178,7 +1236,7 @@ static int __codec_v4l2_start_stream(codec_hal_handle_s *handle,
                                goto _START_STREAM_FAILED;
                        }
 
-                       buffer_control->buffers.bo[i][0] = new_bo;
+                       buffers->bo[i][0] = new_bo;
                        codec_memory->num_fd = 1;
 
                        codec_buffer->planes.plane[0].data = bo_handle.ptr;
@@ -1207,7 +1265,7 @@ static int __codec_v4l2_start_stream(codec_hal_handle_s *handle,
                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_queue_push_tail(buffers->idle_buffers, GINT_TO_POINTER(i));
                        g_mutex_unlock(&buffer_control->lock);
                } else {
                        /* CODEC_HAL_BUFFER_CONTROL_TYPE_OUTPUT */
@@ -1333,7 +1391,7 @@ static void *__codec_v4l2_message_handler_func(gpointer data)
                if (g_queue_is_empty(handle->msg_list)) {
                        LOGD("wait for message");
                        g_cond_wait(&handle->msg_cb_cond, &handle->msg_cb_lock);
-                       LOGD("message signal received");
+                       LOGD("message[length:%u] signal received", g_queue_get_length(handle->msg_list));
                }
 
                if (!handle->msg_cb_run) {
@@ -1347,10 +1405,33 @@ static void *__codec_v4l2_message_handler_func(gpointer data)
                        continue;
                }
 
+               switch (message->type) {
+               case HAL_CODEC_MESSAGE_TYPE_INPUT_BUFFER_USED:
+                       LOGD("INPUT_BUFFER_USED[message:%p]: buffer[index:%d,HAL:%p]",
+                               message, message->buffer->index, message->buffer);
+                       break;
+               case HAL_CODEC_MESSAGE_TYPE_OUTPUT_BUFFER:
+                       LOGD("OUTPUT_BUFFER[message:%p]: buffer[index:%d,HAL:%p]",
+                               message, message->buffer->index, message->buffer);
+                       break;
+               case HAL_CODEC_MESSAGE_TYPE_RESOLUTION_CHANGED:
+                       LOGD("[message:%p] RESOLUTION_CHANGED [%dx%d]",
+                               message, message->resolution.width, message->resolution.height);
+                       break;
+               default:
+                       break;
+               }
+
                g_mutex_unlock(&handle->msg_cb_lock);
 
-               if (handle->msg_cb) {
-                       LOGD("call message callback - type[%d]", message->type);
+               if (!handle->msg_cb) {
+                       LOGW("NULL callback for message");
+
+                       if (message->type == HAL_CODEC_MESSAGE_TYPE_OUTPUT_BUFFER) {
+                               LOGI("release output buffer[index:%d]", message->buffer->index);
+                               codec_v4l2_release_output_buffer(handle, message->buffer->index);
+                       }
+               } else {
                        handle->msg_cb(message, handle->msg_cb_data);
                }
 
@@ -1695,13 +1776,13 @@ int codec_v4l2_release(void *codec_handle)
 }
 
 
-static int __codec_v4l2_poll(codec_hal_handle_s *handle, short events, int timeout_ms, short *revents)
+static int __codec_v4l2_poll(codec_hal_handle_s *handle, short events, int timeout_ms, short *revents, int *poll_errno)
 {
        int ret = 0;
        struct pollfd poll_fd;
 
-       if (!handle) {
-               LOGE("NULL handle");
+       if (!handle || !revents || !poll_errno) {
+               LOGE("NULL param[%p,%p,%p]", handle, revents, poll_errno);
                return -1;
        }
 
@@ -1713,13 +1794,18 @@ static int __codec_v4l2_poll(codec_hal_handle_s *handle, short events, int timeo
        ret = poll(&poll_fd, 1, timeout_ms);
 
        if (ret < 0) {
-               LOGE("poll[events 0x%x] failed[%s]", events, __codec_v4l2_get_error_string(errno));
+               *poll_errno = errno;
+               LOGE("poll[events 0x%x] failed[errno:%d,%s]",
+                       events, *poll_errno, __codec_v4l2_get_error_string(*poll_errno));
        } 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;
+
+               if (poll_fd.revents & POLLERR)
+                       *poll_errno = errno;
+
+               *revents = poll_fd.revents;
        }
 
        return ret;
@@ -1729,6 +1815,7 @@ static int __codec_v4l2_poll(codec_hal_handle_s *handle, short events, int timeo
 static gpointer __codec_v4l2_buffer_handler_func(gpointer data)
 {
        int ret = 0;
+       int poll_errno = 0;
        int error_count = 0;
        gboolean run_loop = TRUE;
 
@@ -1753,7 +1840,9 @@ static gpointer __codec_v4l2_buffer_handler_func(gpointer data)
                /* exit thread with some conditions */
                //////////////////////////////////////
 
-               ret = __codec_v4l2_poll(handle, (POLLIN | POLLOUT | POLLPRI), OUTPUT_POLL_TIMEOUT_MS, &revents);
+               poll_errno = 0;
+
+               ret = __codec_v4l2_poll(handle, (POLLIN | POLLOUT | POLLPRI), OUTPUT_POLL_TIMEOUT_MS, &revents, &poll_errno);
 
                if (ret == 0)
                        continue;
@@ -1762,19 +1851,29 @@ static gpointer __codec_v4l2_buffer_handler_func(gpointer data)
                        break;
 
                if (revents & POLLERR) {
-                       LOGW("POLLERR[%s]", __codec_v4l2_get_error_string(errno));
+                       LOGE("POLLERR[errno:%d,%s]", poll_errno, __codec_v4l2_get_error_string(poll_errno));
+
+                       g_mutex_lock(&output_control->lock);
+
+                       if (output_control->buffers.queued_count == 0) {
+                               LOGW("wait for dequeued output buffer");
+                               g_cond_wait(&output_control->cond, &output_control->lock);
+                               LOGW("signal received");
+                       }
+
+                       g_mutex_unlock(&output_control->lock);
 
                        if (handle->is_stopping) {
                                LOGW("now stopping... stop buffer handler");
                                break;
+                       }
+
+                       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 {
-                               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][max:%d] exceeded", error_count, POLL_ERROR_TRY_COUNT_MAX);
-                               }
+                               LOGE("error count[%d][max:%d] exceeded", error_count, POLL_ERROR_TRY_COUNT_MAX);
                        }
                }
 
@@ -1899,9 +1998,13 @@ int codec_v4l2_stop(void *codec_handle)
                goto _STOP_DONE;
        }
 
-       LOGI("join output thread");
+       LOGI("join buffer thread");
 
        if (handle->buffer_handler) {
+               g_mutex_lock(&handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_OUTPUT].lock);
+               g_cond_broadcast(&handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_OUTPUT].cond);
+               g_mutex_unlock(&handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_OUTPUT].lock);
+
                g_thread_join(handle->buffer_handler);
                handle->buffer_handler = NULL;
        }
@@ -2062,7 +2165,6 @@ int codec_v4l2_release_output_buffer(void *codec_handle, int buffer_index)
        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");
@@ -2071,8 +2173,6 @@ int codec_v4l2_release_output_buffer(void *codec_handle, int buffer_index)
 
        buffer_control = &handle->buffer_control[CODEC_HAL_BUFFER_CONTROL_TYPE_OUTPUT];
 
-       //locker = g_mutex_locker_new(&handle->lock);
-
        ret = __codec_v4l2_qbuf(handle->device_fd,
                buffer_control, &buffer_control->buffers.buffer[buffer_index]);
 
index c27867b9e357cfc7c24496e72cdb76280b867e5d..d9e22186ca16f1b77fc449b699e0dd2b8e1b14f7 100644 (file)
@@ -64,6 +64,8 @@ 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];
+       int queued_count;
        GQueue *idle_buffers;
 } codec_hal_buffers_s;