Support H.264 encoder
authorJeongmo Yang <jm80.yang@samsung.com>
Fri, 4 Apr 2025 02:44:31 +0000 (11:44 +0900)
committerJeongmo Yang <jm80.yang@samsung.com>
Fri, 4 Apr 2025 05:42:57 +0000 (14:42 +0900)
Signed-off-by: Jeongmo Yang <jm80.yang@samsung.com>
packaging/hal-backend-codec-v4l2.spec
src/hal_backend_codec_v4l2.c
src/hal_backend_codec_v4l2_private.h

index fe7be4da58b6dd8450886cbed608097002f5faef..9abbf4ac60dedccadb961ff2d3f871c5821f0997 100644 (file)
@@ -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
index 34248fed59c2d7a8900440388d55f631cc852721..e4947d6f5367bbccfaf7167892c5c72c8fe14bd7 100644 (file)
 #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;
index 9bb18825121fbbae5158b85c01da5511f3cea25b..e03d8d18e860c6af8747ef867fb1eb8fe5b2bad1 100644 (file)
 
 #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);