Initial release
authorJeongmo Yang <jm80.yang@samsung.com>
Tue, 24 Sep 2024 11:10:32 +0000 (20:10 +0900)
committerJeongmo Yang <jm80.yang@samsung.com>
Wed, 2 Oct 2024 11:11:48 +0000 (20:11 +0900)
- Build OK with hal-api-codec package.
- Some functions are implemented, but not completed.
 : init()
 : deinit()
 : configure()
 : release()

Signed-off-by: Jeongmo Yang <jm80.yang@samsung.com>
AUTHORS [new file with mode: 0644]
LICENSE.APLv2 [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
NOTICE [new file with mode: 0644]
autogen.sh [new file with mode: 0755]
configure.ac [new file with mode: 0644]
hal-backend-codec-v4l2.manifest [new file with mode: 0644]
packaging/hal-backend-codec-v4l2.spec [new file with mode: 0644]
src/Makefile.am [new file with mode: 0644]
src/hal_backend_codec_v4l2.c [new file with mode: 0644]
src/hal_backend_codec_v4l2_private.h [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..7e88032
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Jeongmo Yang <jm80.yang@samsung.com>
diff --git a/LICENSE.APLv2 b/LICENSE.APLv2
new file mode 100644 (file)
index 0000000..8aa906c
--- /dev/null
@@ -0,0 +1,205 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..af437a6
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = src
diff --git a/NOTICE b/NOTICE
new file mode 100644 (file)
index 0000000..0e0f016
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,3 @@
+Copyright (c) Samsung Electronics Co., Ltd. All rights reserved.
+Except as noted, this software is licensed under Apache License, Version 2.
+Please, see the LICENSE.APLv2 file for Apache License terms and conditions.
diff --git a/autogen.sh b/autogen.sh
new file mode 100755 (executable)
index 0000000..f5469d7
--- /dev/null
@@ -0,0 +1,7 @@
+#! /bin/sh
+
+libtoolize --copy --force
+aclocal
+autoheader
+autoconf
+automake -a -c
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..e18bc23
--- /dev/null
@@ -0,0 +1,54 @@
+AC_PREREQ(2.52)
+
+AC_INIT([hal-backend-codec-v4l2], [1.0.0])
+AM_INIT_AUTOMAKE([-Wall -Werror foreign])
+AC_CONFIG_HEADERS([config.h:config.hin])
+AC_CONFIG_MACRO_DIR([m4])
+
+# Checks for programs.
+m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
+AC_PROG_CC
+AC_PROG_CXX
+AM_PROG_CC_C_O
+AC_C_CONST
+AC_FUNC_MMAP
+AC_FUNC_REALLOC
+AC_FUNC_SELECT_ARGTYPES
+AC_FUNC_STAT
+AC_FUNC_VPRINTF
+AC_HEADER_STDBOOL
+AC_HEADER_STDC
+AC_HEADER_TIME
+AC_PROG_GCC_TRADITIONAL
+AC_PROG_LIBTOOL
+
+PKG_CHECK_MODULES(HAL_ROOTSTRAP, hal-rootstrap)
+AC_SUBST(HAL_ROOTSTRAP_CFLAGS)
+AC_SUBST(HAL_ROOTSTRAP_LIBS)
+
+PKG_CHECK_MODULES(HALAPI_CODEC, hal-api-codec)
+AC_SUBST(HALAPI_CODEC_CFLAGS)
+AC_SUBST(HALAPI_CODEC_LIBS)
+
+# Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS([fcntl.h memory.h stdlib.h string.h sys/time.h unistd.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_PID_T
+AC_TYPE_SIZE_T
+
+# Checks for library functions.
+AC_FUNC_ALLOCA
+AC_FUNC_FORK
+AC_FUNC_MALLOC
+AC_FUNC_MEMCMP
+AC_FUNC_SELECT_ARGTYPES
+AC_TYPE_SIGNAL
+AC_CHECK_FUNCS([memset select])
+AC_CONFIG_FILES([
+Makefile
+src/Makefile
+])
+AC_OUTPUT
diff --git a/hal-backend-codec-v4l2.manifest b/hal-backend-codec-v4l2.manifest
new file mode 100644 (file)
index 0000000..a76fdba
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+       <request>
+               <domain name="_" />
+       </request>
+</manifest>
diff --git a/packaging/hal-backend-codec-v4l2.spec b/packaging/hal-backend-codec-v4l2.spec
new file mode 100644 (file)
index 0000000..5b502c1
--- /dev/null
@@ -0,0 +1,42 @@
+Name:       hal-backend-codec-v4l2
+Summary:    Tizen Codec HAL using generic V4L2 interface
+Version:    1.0.0
+Release:    0
+Group:      Multimedia/Libraries
+License:    Apache-2.0
+Source0:    %{name}-%{version}.tar.gz
+BuildRequires:  pkgconfig(hal-rootstrap)
+BuildRequires:  pkgconfig(hal-api-codec)
+
+%description
+Tizen Codec HAL using generic V4L2 interface.
+
+
+%prep
+%setup -q
+
+
+%build
+./autogen.sh
+%configure \
+       --disable-static\
+       --libdir=%{_hal_libdir}
+make %{?jobs:-j%jobs}
+
+%install
+%make_install
+mkdir -p %{buildroot}%{_hal_licensedir}/%{name}
+cp LICENSE.APLv2 %{buildroot}%{_hal_licensedir}/%{name}
+
+
+%post
+/sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+%files
+%manifest %{name}.manifest
+%{_hal_licensedir}/%{name}/*
+%defattr(-,root,root,-)
+%{_hal_libdir}/*.so
+
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..a486df4
--- /dev/null
@@ -0,0 +1,20 @@
+ACLOCAL_AMFLAGS='-I m4'
+
+lib_LTLIBRARIES = libhal-backend-codec.la
+
+noinst_HEADERS = hal_backend_codec_v4l2_private.h
+
+libhal_backend_codec_la_SOURCES = hal_backend_codec_v4l2.c
+
+libhal_backend_codec_la_CFLAGS = \
+       -I$(srcdir)/include \
+       $(HAL_ROOTSTRAP_CFLAGS) \
+       $(HALAPI_CODEC_CFLAGS)
+
+libhal_backend_codec_la_LIBADD = \
+       $(HAL_ROOTSTRAP_LIBS) \
+       $(HALAPI_CODEC_LIBS)
+
+libhal_backend_codec_la_CFLAGS += -fdata-sections -ffunction-sections -Wl,--gc-sections
+libhal_backend_codec_la_LDFLAGS = -Wl,--gc-sections -avoid-version
+
diff --git a/src/hal_backend_codec_v4l2.c b/src/hal_backend_codec_v4l2.c
new file mode 100644 (file)
index 0000000..61dfc2d
--- /dev/null
@@ -0,0 +1,1766 @@
+/*
+ * hal_backend_codec_v4l2.c
+ *
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <glob.h>
+#include <dlog.h>
+#include <sched.h>
+#include "hal_backend_codec_v4l2_private.h"
+#include <tbm_surface.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif /* LOG_TAG */
+#define LOG_TAG "CODEC_HAL"
+
+#ifndef LOGV
+#define LOGV(fmt, arg...) dlog_print(DLOG_VERBOSE, LOG_TAG, "%s (%d) %s : " fmt, __FILE__, __LINE__, __FUNCTION__, ##arg)
+#endif
+#ifndef LOGD
+#define LOGD(fmt, arg...) dlog_print(DLOG_DEBUG, LOG_TAG, "%s (%d) %s : " fmt, __FILE__, __LINE__, __FUNCTION__, ##arg)
+#endif
+#ifndef LOGI
+#define LOGI(fmt, arg...) dlog_print(DLOG_INFO, LOG_TAG, "%s (%d) %s : " fmt, __FILE__, __LINE__, __FUNCTION__, ##arg)
+#endif
+#ifndef LOGW
+#define LOGW(fmt, arg...) dlog_print(DLOG_WARN, LOG_TAG, "%s (%d) %s : " fmt, __FILE__, __LINE__, __FUNCTION__, ##arg)
+#endif
+#ifndef LOGE
+#define LOGE(fmt, arg...) dlog_print(DLOG_ERROR, LOG_TAG, "%s (%d) %s : " fmt, __FILE__, __LINE__, __FUNCTION__, ##arg)
+#endif
+
+#define VIRTUAL_CODEC_FMT_MAX  2
+#define VIRTUAL_CODEC_RES_MAX  3
+#define DEVICE_NODE_PATH_PREFIX "/dev/video"
+#define FOURCC_FORMAT           "%c%c%c%c"
+#define FOURCC_CONVERT(fourcc)  \
+       fourcc & 0xff,\
+       (fourcc >> 8) & 0xff,\
+       (fourcc >> 16) & 0xff,\
+       (fourcc >> 24) & 0xff
+
+#define DEVICE_NODE_PATH_LENGTH_MAX     32
+#define DEVICE_MAX                      8
+#define DEVICE_FORMAT_MAX               16
+#define ERROR_STRING_LENGTH             64
+
+typedef struct _codec_v4l2_format_list_s {
+       uint32_t count;
+       enum v4l2_buf_type buf_type;
+       codec_format_type_e format_type;
+       codec_format_e formats[DEVICE_FORMAT_MAX];
+} codec_v4l2_format_list_s;
+
+typedef struct _codec_v4l2_device_s {
+       char node_path[DEVICE_NODE_PATH_LENGTH_MAX];
+       uint32_t capabilities;
+       codec_v4l2_format_list_s in_format;
+       codec_v4l2_format_list_s out_format;
+} codec_v4l2_device_s;
+
+typedef struct _codec_v4l2_device_list_s {
+       uint32_t count;
+       codec_v4l2_device_s *devices[DEVICE_MAX];
+} codec_v4l2_device_list_s;
+
+
+/* global variables */
+static codec_v4l2_device_list_s *g_codec_device_list;
+
+
+/* local functions */
+static void __codec_v4l2_constructor(void) __attribute__((constructor));
+static void __codec_v4l2_destructor(void) __attribute__((destructor));
+
+static int  __codec_v4l2_probe_device(void);
+static void __codec_v4l2_release_device_list(void);
+
+static void __codec_init_buffer_control(codec_buffer_control_s *buffer_control);
+static void __codec_deinit_buffer_control(codec_buffer_control_s *buffer_control);
+
+static int  __codec_v4l2_get_format(guint32 fourcc, codec_format_e *format);
+static int  __codec_get_fourcc_plane_num(codec_format_e format, uint32_t *fourcc, uint32_t *plane_num);
+static void __codec_v4l2_send_message(hal_codec_handle_s *handle, codec_message_type_e type, int value);
+
+
+
+static void __codec_v4l2_constructor(void)
+{
+       int ret = __codec_v4l2_probe_device();
+       LOGI("Codec HAL Loaded - probe device[0x%x]", ret);
+}
+
+
+static void __codec_v4l2_destructor(void)
+{
+       __codec_v4l2_release_device_list();
+       LOGI("Codec HAL Unloaded");
+}
+
+
+static void __codec_v4l2_get_supported_format_list(int device_fd,
+       enum v4l2_buf_type buf_type,
+       codec_v4l2_format_list_s *format_list)
+{
+       int index = 0;
+       uint32_t count = 0;
+       codec_format_e format = CODEC_FORMAT_H264;
+       struct v4l2_fmtdesc fmtdesc;
+
+       if (device_fd < 0 || !format_list) {
+               LOGE("invalid param[%d,%p]", device_fd, format_list);
+               return;
+       }
+
+       LOGI("device fd [%d], buf type [0x%08x]", device_fd, buf_type);
+
+       for (index = 0 ; ; index++) {
+               memset(&fmtdesc, 0x0, sizeof(struct v4l2_fmtdesc));
+
+               fmtdesc.index = index;
+               fmtdesc.type = buf_type;
+
+               if (ioctl(device_fd, VIDIOC_ENUM_FMT, &fmtdesc) < 0) {
+                       LOGI("no more format index[%d]", index);
+                       break;
+               }
+
+               if (__codec_v4l2_get_format(fmtdesc.pixelformat, &format) == CODEC_ERROR_NONE) {
+                       format_list->formats[count] = format;
+                       count++;
+
+                       if (format & CODEC_FORMAT_TYPE_ENCODED)
+                               format_list->format_type = CODEC_FORMAT_TYPE_ENCODED;
+                       else
+                               format_list->format_type = CODEC_FORMAT_TYPE_RAW;
+               }
+       }
+
+       format_list->count = count;
+       format_list->buf_type = buf_type;
+
+       LOGI("format count[%u]", count);
+}
+
+
+static int __codec_v4l2_probe_device(void)
+{
+       int ret = 0;
+       uint32_t device_count = 0;
+
+       size_t i = 0;
+       glob_t glob_buf;
+
+       struct v4l2_capability v4l2_cap;
+       guint32 device_caps;
+
+       memset(&glob_buf, 0x0, sizeof(glob_t));
+
+       ret = glob(DEVICE_NODE_PATH_PREFIX"*", 0, 0, &glob_buf);
+       if (ret != 0) {
+               switch (ret) {
+               case GLOB_NOSPACE:
+                       LOGE("out of memory");
+                       return CODEC_ERROR_OUT_OF_MEMORY;
+               case GLOB_ABORTED:
+                       LOGE("read error");
+                       return CODEC_ERROR_INTERNAL;
+               case GLOB_NOMATCH:
+                       LOGE("match not found");
+                       return CODEC_ERROR_INTERNAL;
+               default:
+                       LOGE("unknown error[%d]", ret);
+                       return CODEC_ERROR_INTERNAL;
+               }
+       }
+
+       g_codec_device_list = g_new0(codec_v4l2_device_list_s, 1);
+
+       LOGD("device node count[%zu]", glob_buf.gl_pathc);
+
+       for (i = 0 ; i < glob_buf.gl_pathc ; i++) {
+               int device_fd = 0;
+               bool is_mplane = false;
+               codec_v4l2_device_s *codec_device = NULL;
+
+               LOGD("[%zu] check device [%s]", i, glob_buf.gl_pathv[i]);
+
+               device_fd = open(glob_buf.gl_pathv[i], O_RDWR);
+               if (device_fd < 0) {
+                       LOGE("open failed [%s] errno %d", glob_buf.gl_pathv[i], errno);
+                       continue;
+               }
+
+               memset(&v4l2_cap, 0x0, sizeof(struct v4l2_capability));
+
+               if (ioctl(device_fd, VIDIOC_QUERYCAP, &v4l2_cap) < 0) {
+                       LOGE("querycap failed. errno %d", errno);
+                       close(device_fd);
+                       continue;
+               }
+
+               LOGI("driver [%s], card [%s], bus_info [%s]",
+                       v4l2_cap.driver, v4l2_cap.card, v4l2_cap.bus_info);
+
+               if (v4l2_cap.capabilities & V4L2_CAP_DEVICE_CAPS)
+                       device_caps = v4l2_cap.device_caps;
+               else
+                       device_caps = v4l2_cap.capabilities;
+
+               if (device_caps & V4L2_CAP_VIDEO_M2M_MPLANE) {
+                       LOGI("V4L2_CAP_VIDEO_M2M_MPLANE");
+                       is_mplane = true;
+               } else if (device_caps & V4L2_CAP_VIDEO_M2M) {
+                       LOGI("V4L2_CAP_VIDEO_M2M");
+                       is_mplane = false;
+               } else {
+                       LOGW("not M2M device [%s]", glob_buf.gl_pathv[i]);
+                       close(device_fd);
+                       continue;
+               }
+
+               codec_device = g_new0(codec_v4l2_device_s, 1);
+
+               __codec_v4l2_get_supported_format_list(device_fd,
+                       (is_mplane ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : V4L2_BUF_TYPE_VIDEO_OUTPUT),
+                       &codec_device->in_format);
+
+               __codec_v4l2_get_supported_format_list(device_fd,
+                       (is_mplane ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : V4L2_BUF_TYPE_VIDEO_CAPTURE),
+                       &codec_device->out_format);
+
+               close(device_fd);
+
+               if (codec_device->in_format.count > 0 && codec_device->out_format.count > 0 &&
+                       ((codec_device->in_format.format_type == CODEC_FORMAT_TYPE_ENCODED &&
+                               codec_device->out_format.format_type == CODEC_FORMAT_TYPE_RAW) ||
+                        (codec_device->in_format.format_type == CODEC_FORMAT_TYPE_RAW &&
+                               codec_device->out_format.format_type == CODEC_FORMAT_TYPE_ENCODED))) {
+                       strncpy(codec_device->node_path, glob_buf.gl_pathv[i], DEVICE_NODE_PATH_LENGTH_MAX - 1);
+                       codec_device->capabilities = device_caps;
+
+                       g_codec_device_list->devices[device_count] = codec_device;
+
+                       LOGI("add device[%u] %p", device_count, codec_device);
+
+                       device_count++;
+               } else {
+                       LOGW("invalid format count[in:%u,out:%u] or format type[in:0x%08x,out:0x%08x]",
+                               codec_device->in_format.count, codec_device->out_format.count,
+                               codec_device->in_format.format_type, codec_device->out_format.format_type);
+
+                       g_free(codec_device);
+               }
+       }
+
+       if (device_count > 0) {
+               g_codec_device_list->count = device_count;
+               LOGI("device count[%u]", device_count);
+       } else {
+               LOGW("no device");
+               g_free(g_codec_device_list);
+               g_codec_device_list = NULL;
+       }
+
+       return CODEC_ERROR_NONE;
+}
+
+
+static void __codec_v4l2_release_device_list(void)
+{
+       uint32_t device_index = 0;
+       uint32_t device_count = 0;
+       codec_v4l2_device_s *codec_device = NULL;
+
+       if (!g_codec_device_list) {
+               LOGW("NULL device list");
+               return;
+       }
+
+       LOGI("release device list [%p]", g_codec_device_list);
+
+       for (device_index = 0 ; device_index < device_count ; device_index++) {
+               codec_device = g_codec_device_list->devices[device_index];
+               if (!codec_device) {
+                       LOGW("NULL codec_device for index[%u]", device_index);
+                       continue;
+               }
+
+               LOGI("release codec_device[%u] %p", device_index, codec_device);
+
+               memset(codec_device, 0x0, sizeof(codec_v4l2_device_s));
+               g_free(codec_device);
+       }
+
+       memset(g_codec_device_list, 0x0, sizeof(codec_v4l2_device_list_s));
+       g_free(g_codec_device_list);
+
+       g_codec_device_list = NULL;
+
+       LOGI("done");
+}
+
+
+static int __codec_v4l2_get_buf_type_and_node_path(codec_format_e in_format, codec_format_e out_format,
+       enum v4l2_buf_type *in_buf_type, enum v4l2_buf_type *out_buf_type, char **path)
+{
+       uint32_t device_index = 0;
+       uint32_t format_index = 0;
+       codec_v4l2_device_s *codec_device = NULL;
+       codec_v4l2_format_list_s *format_list = NULL;
+
+       if (!g_codec_device_list) {
+               LOGE("no codec device list");
+               return CODEC_ERROR_INTERNAL;
+       }
+
+       if (!path || !in_buf_type || !out_buf_type) {
+               LOGE("NULL param [%p,%p,%p]", path, in_buf_type, out_buf_type);
+               return CODEC_ERROR_INVALID_PARAMETER;
+       }
+
+       for (device_index = 0 ; device_index < g_codec_device_list->count ; device_index++) {
+               codec_device = g_codec_device_list->devices[device_index];
+               if (!codec_device) {
+                       LOGW("No codec device for index[%d]", device_index);
+                       continue;
+               }
+
+               format_list = &codec_device->in_format;
+               for (format_index = 0 ; format_index < format_list->count ; format_index++) {
+                       if (format_list->formats[format_index] == in_format) {
+                               *in_buf_type = format_list->buf_type;
+                               break;
+                       }
+               }
+
+               if (format_index == format_list->count) {
+                       LOGW("in_format[%d] not found in device[%d][%s]",
+                               in_format, device_index, codec_device->node_path);
+                       continue;
+               }
+
+               format_list = &codec_device->out_format;
+               for (format_index = 0 ; format_index < format_list->count ; format_index++) {
+                       if (format_list->formats[format_index] == out_format) {
+                               *out_buf_type = format_list->buf_type;
+                               *path = codec_device->node_path;
+
+                               LOGI("found node path[%s], buf_type[in:%d, out:%d] for format[in:%d, out:%d]",
+                                       *path, *in_buf_type, *out_buf_type, in_format, out_format);
+
+                               return CODEC_ERROR_NONE;
+                       }
+               }
+       }
+
+       LOGE("node path not found for format[in:%d,out:%d]", in_format, out_format);
+
+       return CODEC_ERROR_NOT_SUPPORTED;
+}
+
+
+static void __codec_v4l2_send_message(hal_codec_handle_s *handle, codec_message_type_e type, int value)
+{
+       codec_message_s *message = NULL;
+       g_autoptr(GMutexLocker) locker = NULL;
+
+       if (!handle) {
+               LOGE("NULL handle");
+               return;
+       }
+
+       locker = g_mutex_locker_new(&handle->msg_cb_lock);
+
+       switch (type) {
+       case CODEC_MESSAGE_TYPE_INPUT_BUFFER_USED:
+               break;
+       case CODEC_MESSAGE_TYPE_OUTPUT_BUFFER:
+               break;
+       case CODEC_MESSAGE_TYPE_RESOLUTION_CHANGED:
+               break;
+       case CODEC_MESSAGE_TYPE_ERROR:
+               message->error_code = (codec_error_e)value;
+               break;
+       default:
+               LOGW("unhandled type[%d]", type);
+               return;
+       }
+
+       message = g_new0(codec_message_s, 1);
+
+       message->type = type;
+
+       LOGD("type[%d], value[0x%x]", type, value);
+
+       g_queue_push_tail(handle->msg_list, message);
+       g_cond_signal(&handle->msg_cb_cond);
+}
+
+
+static int __codec_v4l2_wait_frame(int device_fd, int wait_time)
+{
+       int ret = CODEC_ERROR_NONE;
+       fd_set fds;
+       struct timeval timeout;
+
+       if (device_fd < 0) {
+               LOGE("invalid fd %d", device_fd);
+               return CODEC_ERROR_INVALID_PARAMETER;
+       }
+
+       FD_ZERO(&fds);
+       FD_SET(device_fd, &fds);
+
+       memset(&timeout, 0x0, sizeof(struct timeval));
+
+       timeout.tv_sec = wait_time;
+       timeout.tv_usec = 0;
+
+       /*LOGD("select : %d sec", wait_time);*/
+
+       ret = select(device_fd + 1, &fds, NULL, NULL, &timeout);
+       if (ret == -1) {
+               if (EINTR == errno) {
+                       LOGD("select error : EINTR");
+                       return CODEC_ERROR_NONE;
+               }
+               LOGE("select failed. errno %d", errno);
+               return CODEC_ERROR_INTERNAL;
+       }
+
+       if (ret == 0) {
+               LOGE("select timeout.");
+               return CODEC_ERROR_INTERNAL;
+       }
+
+       /*LOGD("select done");*/
+
+       return CODEC_ERROR_NONE;
+}
+
+
+static int __codec_v4l2_g_ctrl(int device_fd, int cid, int *value)
+{
+       int ret = 0;
+       struct v4l2_control ctrl;
+
+       if (!value) {
+               LOGE("NULL param");
+               return CODEC_ERROR_INVALID_PARAMETER;
+       }
+
+       memset(&ctrl, 0x0, sizeof(struct v4l2_control));
+
+       ctrl.id = cid;
+
+       ret = ioctl(device_fd, VIDIOC_G_CTRL, &ctrl);
+
+       if (ret == 0)
+               *value = ctrl.value;
+
+       LOGD("G_CTRL id 0x%x, value %d, ret %d", cid, *value, ret);
+
+       return ret;
+}
+
+
+static int __codec_v4l2_s_ctrl(int device_fd, int cid, int value)
+{
+       int ret = 0;
+       struct v4l2_control ctrl;
+
+       memset(&ctrl, 0x0, sizeof(struct v4l2_control));
+
+       ctrl.id = cid;
+       ctrl.value = value;
+
+       ret = ioctl(device_fd, VIDIOC_S_CTRL, &ctrl);
+
+       LOGD("S_CTRL id 0x%x, value %d, ret %d", cid, value, ret);
+
+       return ret;
+}
+
+
+static int __codec_v4l2_s_fmt(int device_fd,
+       codec_format_e format, enum v4l2_buf_type buf_type,
+       int width, int height)
+{
+       uint32_t fourcc = 0;
+       uint32_t plane_num = 0;
+       struct v4l2_format v4l2_fmt;
+
+       memset(&v4l2_fmt, 0x0, sizeof(struct v4l2_format));
+
+       LOGI("S_FMT : format[%d], buf_type[%d], resolution[%dx%d]",
+               format, buf_type, width, height);
+
+       if (__codec_get_fourcc_plane_num(format, &fourcc, &plane_num) != CODEC_ERROR_NONE) {
+               LOGE("get fourcc failed for format [%d]", format);
+               return CODEC_ERROR_INVALID_PARAMETER;
+       }
+
+       memset(&v4l2_fmt, 0x0, sizeof(struct v4l2_format));
+
+       v4l2_fmt.type = buf_type;
+       if (V4L2_TYPE_IS_MULTIPLANAR(buf_type)) {
+               v4l2_fmt.fmt.pix_mp.width = width;
+               v4l2_fmt.fmt.pix_mp.height = height;
+               v4l2_fmt.fmt.pix_mp.pixelformat = fourcc;
+               v4l2_fmt.fmt.pix_mp.num_planes = plane_num;
+       } else {
+               v4l2_fmt.fmt.pix.width = width;
+               v4l2_fmt.fmt.pix.height = height;
+               v4l2_fmt.fmt.pix.pixelformat = fourcc;
+               v4l2_fmt.fmt.pix.bytesperline = width;
+       }
+
+       if (ioctl(device_fd, VIDIOC_S_FMT, &v4l2_fmt) < 0) {
+               LOGE("S_FMT failed. errno %d", errno);
+               return CODEC_ERROR_INTERNAL;
+       }
+
+       LOGI("done");
+
+       return CODEC_ERROR_NONE;
+}
+
+
+static int __codec_v4l2_stream(int device_fd, int type, gboolean onoff)
+{
+       if (device_fd < 0) {
+               LOGE("invalid fd %d", device_fd);
+               return CODEC_ERROR_INVALID_PARAMETER;
+       }
+
+       if (ioctl(device_fd, onoff ? VIDIOC_STREAMON : VIDIOC_STREAMOFF, &type) < 0) {
+               LOGE("stream %d failed. [t:%d] errno %d", onoff, type, errno);
+               return CODEC_ERROR_INTERNAL;
+       }
+
+       LOGD("stream %d done [t:%d]", onoff, type);
+
+       return CODEC_ERROR_NONE;
+}
+
+
+static int __codec_v4l2_reqbufs(int device_fd, int type, int memory, uint32_t count, uint32_t *result_count)
+{
+       struct v4l2_requestbuffers v4l2_reqbuf;
+
+       if (device_fd < 0) {
+               LOGE("invalid fd %d", device_fd);
+               return CODEC_ERROR_INVALID_PARAMETER;
+       }
+
+       LOGI("type[%d], memory[%d], count[%u]", type, memory, count);
+
+       memset(&v4l2_reqbuf, 0x0, sizeof(struct v4l2_requestbuffers));
+
+       v4l2_reqbuf.type = type;
+       v4l2_reqbuf.memory = memory;
+       v4l2_reqbuf.count = count;
+
+       if (ioctl(device_fd, VIDIOC_REQBUFS, &v4l2_reqbuf) < 0) {
+               LOGE("REQBUFS[count %d] failed. errno %d", count, errno);
+               return CODEC_ERROR_INTERNAL;
+       }
+
+       if (v4l2_reqbuf.count != count)
+               LOGW("different count [req:%d, result:%d]", count, v4l2_reqbuf.count);
+
+       if (result_count)
+               *result_count = v4l2_reqbuf.count;
+
+       return CODEC_ERROR_NONE;
+}
+
+
+static int __codec_v4l2_qbuf(int device_fd, int type, int memory, int index, int dmabuf_fd)
+{
+       struct v4l2_buffer v4l2_buf;
+       struct v4l2_plane v4l2_planes[V4L2_PLANES_MAX];
+
+       if (device_fd < 0) {
+               LOGE("invalid fd %d", device_fd);
+               return CODEC_ERROR_INVALID_PARAMETER;
+       }
+
+       memset(&v4l2_buf, 0x0, sizeof(struct v4l2_buffer));
+       memset(v4l2_planes, 0x0, sizeof(v4l2_planes));
+
+       v4l2_buf.index = index;
+       v4l2_buf.type = type;
+       v4l2_buf.memory = memory;
+       v4l2_buf.m.planes = v4l2_planes;
+
+       if (dmabuf_fd > CODEC_HAL_INITIAL_FD) {
+               if (V4L2_TYPE_IS_MULTIPLANAR(type))
+                       v4l2_buf.m.planes[0].m.fd = dmabuf_fd;
+               else
+                       v4l2_buf.m.fd = dmabuf_fd;
+       }
+
+       if (ioctl(device_fd, VIDIOC_QBUF, &v4l2_buf) < 0) {
+               LOGE("qbuf failed.  [i: %d, t: %d, m: %d] errno %d",
+                       index, type, memory, errno);
+               return CODEC_ERROR_INTERNAL;
+       }
+
+       LOGD("QBUF done [i:%d, t:%d, m:%d, fd:%d]",
+               index, type, memory, dmabuf_fd);
+
+       return CODEC_ERROR_NONE;
+}
+
+
+static int __codec_v4l2_dqbuf(int device_fd, int type, int memory, int *index, uint32_t *bytesused)
+{
+       int ret = CODEC_ERROR_NONE;
+       struct v4l2_buffer v4l2_buf;
+       struct v4l2_plane v4l2_planes[V4L2_PLANES_MAX];
+
+       if (device_fd < 0) {
+               LOGE("invalid fd %d", device_fd);
+               return CODEC_ERROR_INVALID_PARAMETER;
+       }
+
+       if (!index) {
+               LOGE("NULL parameter");
+               return CODEC_ERROR_INVALID_PARAMETER;
+       }
+
+       memset(&v4l2_buf, 0x0, sizeof(struct v4l2_buffer));
+       memset(v4l2_planes, 0x0, sizeof(v4l2_planes));
+
+       v4l2_buf.type = type;
+       v4l2_buf.memory = memory;
+       v4l2_buf.m.planes = v4l2_planes;
+
+       ret = ioctl(device_fd, VIDIOC_DQBUF, &v4l2_buf);
+       if (ret < 0) {
+               LOGE("dqbuf failed. [t: %d, m: %d] errno %d",
+                       type, memory, errno);
+               return CODEC_ERROR_DEVICE_READ;
+       }
+
+       LOGD("DQBUF[i:%d], bytesused[%u], length[%u]",
+               v4l2_buf.index, v4l2_buf.bytesused, v4l2_buf.length);
+
+       *index = v4l2_buf.index;
+       if (bytesused)
+               *bytesused = v4l2_buf.bytesused;
+
+       /*LOGD("dqbuf index %d", *index);*/
+
+       return CODEC_ERROR_NONE;
+}
+
+
+static int __codec_v4l2_get_format(guint32 fourcc, codec_format_e *format)
+{
+       if (!format) {
+               LOGE("NULL parameter");
+               return CODEC_ERROR_INVALID_PARAMETER;
+       }
+
+       switch (fourcc) {
+       case V4L2_PIX_FMT_NV12:
+       case V4L2_PIX_FMT_NV12M:
+               *format = CODEC_FORMAT_NV12;
+               break;
+       case V4L2_PIX_FMT_NV12MT:
+               *format = CODEC_FORMAT_NV12T;
+               break;
+       case V4L2_PIX_FMT_NV21:
+       case V4L2_PIX_FMT_NV21M:
+               *format = CODEC_FORMAT_NV21;
+               break;
+       case V4L2_PIX_FMT_YUV420:
+               *format = CODEC_FORMAT_I420;
+               break;
+       case V4L2_PIX_FMT_YVU420:
+               *format = CODEC_FORMAT_YV12;
+               break;
+       case V4L2_PIX_FMT_YUYV:
+               *format = CODEC_FORMAT_YUYV;
+               break;
+       case V4L2_PIX_FMT_UYVY:
+               *format = CODEC_FORMAT_UYVY;
+               break;
+       case V4L2_PIX_FMT_H264:
+               *format = CODEC_FORMAT_H264;
+               break;
+       default:
+               LOGW("unhandled fourcc ["FOURCC_FORMAT"]", FOURCC_CONVERT(fourcc));
+               return CODEC_ERROR_INTERNAL;
+       }
+
+       LOGI("fourcc ["FOURCC_FORMAT"] -> format [%d]",
+               FOURCC_CONVERT(fourcc), *format);
+
+       return CODEC_ERROR_NONE;
+}
+
+
+static int __codec_get_fourcc_plane_num(codec_format_e format, uint32_t *fourcc, uint32_t *plane_num)
+{
+       if (!fourcc || !plane_num) {
+               LOGE("NULL parameter %p %p", fourcc, plane_num);
+               return CODEC_ERROR_INVALID_PARAMETER;
+       }
+
+       switch (format) {
+       case CODEC_FORMAT_NV12:
+               *fourcc = V4L2_PIX_FMT_NV12;
+               *plane_num = 2;
+               break;
+       case CODEC_FORMAT_NV12T:
+               *fourcc = V4L2_PIX_FMT_NV12MT;
+               *plane_num = 2;
+               break;
+       case CODEC_FORMAT_NV21:
+               *fourcc = V4L2_PIX_FMT_NV21;
+               *plane_num = 2;
+               break;
+       case CODEC_FORMAT_I420:
+               *fourcc = V4L2_PIX_FMT_YUV420;
+               *plane_num = 3;
+               break;
+       case CODEC_FORMAT_YV12:
+               *fourcc = V4L2_PIX_FMT_YVU420;
+               *plane_num = 3;
+               break;
+       case CODEC_FORMAT_YUYV:
+               *fourcc = V4L2_PIX_FMT_YUYV;
+               *plane_num = 1;
+               break;
+       case CODEC_FORMAT_UYVY:
+               *fourcc = V4L2_PIX_FMT_UYVY;
+               *plane_num = 1;
+               break;
+       case CODEC_FORMAT_H264:
+               *fourcc = V4L2_PIX_FMT_H264;
+               *plane_num = 1;
+               break;
+       default:
+               LOGE("unhandled format [%d]", format);
+               return CODEC_ERROR_INTERNAL;
+       }
+
+       LOGD("format [%d] -> fourcc ["FOURCC_FORMAT"]",
+               format, FOURCC_CONVERT(*fourcc));
+
+       return CODEC_ERROR_NONE;
+}
+
+
+static int __codec_stop_stream(hal_codec_handle_s *handle)
+{
+       int ret = CODEC_ERROR_NONE;
+#if 0
+       int i = 0;
+       codec_buffer_s *buffer = NULL;
+#endif
+#ifdef TIZEN_FEATURE_ZERO_COPY_SUPPORT
+       codec_tbm_buffer_s *tbm_buffer = NULL;
+#endif
+
+       if (!handle) {
+               LOGE("NULL handle");
+               return CODEC_ERROR_INVALID_PARAMETER;
+       }
+
+       /* stream off */
+       ret = __codec_v4l2_stream(handle->device_fd, handle->input_buffer_control.buf_type, FALSE);
+       ret = __codec_v4l2_stream(handle->device_fd, handle->output_buffer_control.buf_type, FALSE);
+
+       LOGI("stream off[0x%x]", ret);
+
+       /* release buffer */
+#if 0
+       for (i = 0 ; i < buffer_count ; i++) {
+               buffer = &handle->codec_buffers[i];
+
+               LOGI("release buffer[%d]", i);
+
+#ifdef TIZEN_FEATURE_ZERO_COPY_SUPPORT
+               tbm_buffer = &handle->tbm_buffers[i];
+
+               if (tbm_buffer->dmabuf_fd > CODEC_HAL_INITIAL_FD) {
+                       LOGI("  close dmabuf fd[%d]", tbm_buffer->dmabuf_fd);
+                       close(tbm_buffer->dmabuf_fd);
+                       tbm_buffer->dmabuf_fd = CODEC_HAL_INITIAL_FD;
+               }
+
+               if (tbm_buffer->bo) {
+                       LOGI("  unref tbm bo[%p]", tbm_buffer->bo);
+                       tbm_bo_unref(tbm_buffer->bo);
+                       tbm_buffer->bo = NULL;
+               }
+
+               tbm_buffer->bo_handle.ptr = NULL;
+#endif
+
+               if (buffer->planes[0].data) {
+#ifndef TIZEN_FEATURE_ZERO_COPY_SUPPORT
+                       LOGI("  munmap %p", buffer->planes[0].data);
+                       munmap(buffer->planes[0].data, buffer->planes[0].size);
+#endif
+                       buffer->planes[0].data = NULL;
+                       buffer->planes[0].size = 0;
+               } else {
+                       LOGI("  NULL data [i:%d]", i);
+               }
+       }
+#endif
+
+       ret = __codec_v4l2_reqbufs(handle->device_fd,
+               handle->input_buffer_control.buf_type, V4L2_MEMORY_MMAP, 0, NULL);
+
+       ret = __codec_v4l2_reqbufs(handle->device_fd,
+               handle->output_buffer_control.buf_type, V4L2_MEMORY_MMAP, 0, NULL);
+
+       LOGI("reqbufs 0 [0x%x]", ret);
+
+       return ret;
+}
+
+
+static int __codec_start_stream(hal_codec_handle_s *handle,
+       uint32_t in_buffer_count, uint32_t out_buffer_count)
+{
+       int ret = CODEC_ERROR_NONE;
+#if 0
+       int i = 0;
+       codec_buffer_s *buffer = NULL;
+#endif
+#ifdef TIZEN_FEATURE_ZERO_COPY_SUPPORT
+       uint32_t buffer_size = 0;
+       codec_tbm_buffer_s *tbm_buffer = NULL;
+#else
+#if 0
+       struct v4l2_buffer v4l2_buf;
+       struct v4l2_plane v4l2_planes[V4L2_PLANES_MAX];
+#endif
+#endif
+
+       if (!handle) {
+               LOGE("NULL handle");
+               return CODEC_ERROR_INTERNAL;
+       }
+
+       /* request buffer */
+       ret = __codec_v4l2_reqbufs(handle->device_fd,
+               handle->input_buffer_control.buf_type, V4L2_MEMORY_MMAP,
+               in_buffer_count, &handle->input_buffer_control.count);
+       if (ret != CODEC_ERROR_NONE) {
+               LOGE("REQBUFS for input failed [0x%x]", ret);
+               return ret;
+       }
+
+       LOGI("input buffer count : request %d -> result %d",
+               in_buffer_count, handle->input_buffer_control.count);
+
+       ret = __codec_v4l2_reqbufs(handle->device_fd,
+               handle->output_buffer_control.buf_type, V4L2_MEMORY_MMAP,
+               out_buffer_count, &handle->output_buffer_control.count);
+       if (ret != CODEC_ERROR_NONE) {
+               LOGE("REQBUFS for output failed [0x%x]", ret);
+               return ret;
+       }
+
+       LOGI("output buffer count : request %d -> result %d",
+               out_buffer_count, handle->output_buffer_control.count);
+
+#if 0
+       /* alloc and queue buffer */
+       for (i = 0 ; i < handle->buffer_count ; i++) {
+               buffer = &handle->codec_buffers[i];
+
+               buffer->index = i;
+               buffer->format = format;
+               buffer->resolution.width = resolution->width;
+               buffer->resolution.height = resolution->height;
+               buffer->num_planes = plane_num;
+
+#ifdef TIZEN_FEATURE_ZERO_COPY_SUPPORT
+               tbm_buffer = &handle->tbm_buffers[i];
+
+               tbm_buffer->bo = tbm_bo_alloc(handle->bufmgr, (int)buffer_size, TBM_BO_DEFAULT);
+               if (!tbm_buffer->bo) {
+                       LOGE("bo alloc failed[size:%u]", buffer_size);
+                       ret = CODEC_ERROR_OUT_OF_MEMORY;
+                       goto _START_STREAM_FAILED;
+               }
+
+               tbm_buffer->bo_handle = tbm_bo_get_handle(tbm_buffer->bo, TBM_DEVICE_CPU);
+               if (!tbm_buffer->bo_handle.ptr) {
+                       LOGE("bo[%p] get handle failed", tbm_buffer->bo);
+                       ret = CODEC_ERROR_INTERNAL;
+                       goto _START_STREAM_FAILED;
+               }
+
+               tbm_buffer->dmabuf_fd = tbm_bo_export_fd(tbm_buffer->bo);
+               if (tbm_buffer->dmabuf_fd < 0) {
+                       LOGE("export fd failed from bo[%p]", tbm_buffer->bo);
+                       ret = CODEC_ERROR_INTERNAL;
+                       goto _START_STREAM_FAILED;
+               }
+
+               buffer->total_size = buffer_size;
+               buffer->planes[0].size = buffer_size;
+               buffer->planes[0].data = tbm_buffer->bo_handle.ptr;
+               buffer->num_bos = 1;
+               buffer->bos[0] = tbm_buffer->bo;
+
+               LOGD("buffer[%d], size[%d], data[%p], bo[%p], fd[%d]",
+                       i, buffer->planes[0].size, buffer->planes[0].data,
+                       tbm_buffer->bo, tbm_buffer->dmabuf_fd);
+
+               ret = __codec_v4l2_qbuf(handle->device_fd,
+                       handle->buffer_type, handle->memory_type,
+                       i, tbm_buffer->dmabuf_fd);
+#else /* TIZEN_FEATURE_ZERO_COPY_SUPPORT */
+               memset(&v4l2_buf, 0x0, sizeof(struct v4l2_buffer));
+               memset(v4l2_planes, 0x0, sizeof(v4l2_planes));
+
+               v4l2_buf.type = handle->buffer_type;
+               v4l2_buf.memory = handle->memory_type;
+               v4l2_buf.index = i;
+               v4l2_buf.m.planes = v4l2_planes;
+               v4l2_buf.length = plane_num;
+
+               if (ioctl(handle->device_fd, VIDIOC_QUERYBUF, &v4l2_buf) < 0) {
+                       LOGE("[%d] query buf failed. errno %d", i, errno);
+                       ret = CODEC_ERROR_INTERNAL;
+                       goto _START_STREAM_FAILED;
+               }
+
+               buffer->index = i;
+               buffer->format = format;
+               buffer->resolution.width = resolution->width;
+               buffer->resolution.height = resolution->height;
+               buffer->total_size = v4l2_buf.length;
+               buffer->num_planes = plane_num;
+               buffer->planes[0].size = v4l2_buf.length;
+               buffer->planes[0].data = mmap(0,
+                       v4l2_buf.length,
+                       PROT_READ | PROT_WRITE,
+                       MAP_SHARED,
+                       handle->device_fd,
+                       (off_t)v4l2_buf.m.offset);
+
+               if (buffer->planes[0].data == MAP_FAILED) {
+                       LOGE("[%d] mmap failed (errno %d)", i, errno);
+                       goto _START_STREAM_FAILED;
+               }
+
+               LOGI("buffer[%d], size[%d], data[%p]",
+                       i, buffer->planes[0].size, buffer->planes[0].data);
+
+               ret = __codec_v4l2_qbuf(handle->device_fd,
+                       handle->buffer_type, handle->memory_type,
+                       i, CODEC_HAL_INITIAL_FD);
+#endif /* TIZEN_FEATURE_ZERO_COPY_SUPPORT */
+
+               if (ret != CODEC_ERROR_NONE) {
+                       LOGE("[%d] qbuf failed (errno %d)", i, errno);
+                       goto _START_STREAM_FAILED;
+               }
+       }
+#endif
+
+       /* stream on */
+       ret = __codec_v4l2_stream(handle->device_fd, handle->input_buffer_control.buf_type, TRUE);
+       if (ret != CODEC_ERROR_NONE) {
+               LOGE("intput stream on failed");
+               goto _START_STREAM_FAILED;
+       }
+
+       ret = __codec_v4l2_stream(handle->device_fd, handle->output_buffer_control.buf_type, TRUE);
+       if (ret != CODEC_ERROR_NONE) {
+               LOGE("output stream on failed");
+               goto _START_STREAM_FAILED;
+       }
+
+       LOGI("done");
+
+       return CODEC_ERROR_NONE;
+
+_START_STREAM_FAILED:
+       __codec_stop_stream(handle);
+       return ret;
+}
+
+
+static gboolean __codec_h264_is_delta_frame(guint8 *data, uint32_t size)
+{
+       uint32_t offset = 0;
+       uint32_t zero_count = 0;
+       uint32_t nal_unit_type = 0;
+
+       if (!data) {
+               LOGW("NULL data");
+               return FALSE;
+       }
+
+CHECK_AGAIN:
+       zero_count = 0;
+       while (offset < size) {
+               if (data[offset] == 0x0) {
+                       zero_count++;
+               } else if (data[offset] == 0x1) {
+                       if (zero_count == 2 || zero_count == 3) {
+                               /* break to check NAL unit type */
+                               offset++;
+                               break;
+                       }
+                       zero_count = 0;
+               } else {
+                       zero_count = 0;
+               }
+
+               offset++;
+       }
+
+       if (offset >= size) {
+               LOGD("invalid offset[%u], size[%u]", offset, size);
+               return FALSE;
+       }
+
+       nal_unit_type = data[offset] & 0x1F;
+       offset++;
+
+       switch (nal_unit_type) {
+       case 1:
+               LOGD("non-IDR picture");
+               return TRUE;
+       case 5:
+               LOGD("IDR picture");
+               return FALSE;
+       case 7:
+               LOGD("SPS(Sequence Parameter Set)");
+               goto CHECK_AGAIN;
+       case 8:
+               LOGD("PPS(Picture Parameter Set)");
+               goto CHECK_AGAIN;
+       default:
+               LOGD("unhandled NAL unit type[%u]", nal_unit_type);
+               return FALSE;
+       }
+}
+
+
+static void __codec_message_release_func(gpointer data)
+{
+       codec_message_s *message = (codec_message_s *)data;
+
+       if (!message) {
+               LOGW("NULL message");
+               return;
+       }
+
+       LOGD("release message %p, type %d", message, message->type);
+
+       g_free(message);
+
+       return;
+}
+
+
+static void *_codec_message_handler_func(gpointer data)
+{
+       int i = 0;
+       codec_message_s *message = NULL;
+       hal_codec_handle_s *handle = (hal_codec_handle_s *)data;
+
+       if (!handle) {
+               LOGE("NULL handle for capture thread");
+               return NULL;
+       }
+
+       LOGD("enter - message thread");
+
+       g_mutex_lock(&handle->msg_cb_lock);
+
+       while (handle->msg_cb_run) {
+               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");
+               }
+
+               if (!handle->msg_cb_run) {
+                       LOGW("break message thread");
+                       break;
+               }
+
+               message = g_queue_pop_head(handle->msg_list);
+               if (!message) {
+                       LOGW("NULL message");
+                       continue;
+               }
+
+               g_mutex_unlock(&handle->msg_cb_lock);
+
+               if (handle->msg_cb) {
+                       LOGD("call message callback[%d] type[%d]", i, message->type);
+                       handle->msg_cb(message, handle->msg_cb_data);
+               }
+
+               g_free(message);
+
+               g_mutex_lock(&handle->msg_cb_lock);
+       }
+
+       g_mutex_unlock(&handle->msg_cb_lock);
+
+       LOGD("leave - message thread");
+
+       return NULL;
+}
+
+
+static void __codec_release_handle(hal_codec_handle_s *handle)
+{
+       if (!handle) {
+               LOGW("NULL handle");
+               return;
+       }
+
+       LOGD("release codec HAL handle [%p]", handle);
+
+       if (handle->msg_thread) {
+               g_mutex_lock(&handle->msg_cb_lock);
+               handle->msg_cb_run = FALSE;
+               g_cond_signal(&handle->msg_cb_cond);
+               g_mutex_unlock(&handle->msg_cb_lock);
+               g_thread_join(handle->msg_thread);
+               g_queue_free_full(handle->msg_list, (GDestroyNotify)__codec_message_release_func);
+               handle->msg_list = NULL;
+       }
+
+       __codec_deinit_buffer_control(&handle->input_buffer_control);
+       __codec_deinit_buffer_control(&handle->output_buffer_control);
+
+       g_mutex_clear(&handle->lock);
+       g_mutex_clear(&handle->msg_cb_lock);
+       g_cond_clear(&handle->msg_cb_cond);
+
+       if (handle->bufmgr) {
+               tbm_bufmgr_deinit(handle->bufmgr);
+               handle->bufmgr = NULL;
+       }
+
+       g_free(handle);
+
+       return;
+}
+
+
+static void __codec_init_buffer_control(codec_buffer_control_s *buffer_control)
+{
+       if (!buffer_control) {
+               LOGE("NULL control");
+               return;
+       }
+
+       g_mutex_init(&buffer_control->lock);
+       g_cond_init(&buffer_control->cond);
+}
+
+static void __codec_deinit_buffer_control(codec_buffer_control_s *buffer_control)
+{
+       if (!buffer_control) {
+               LOGE("NULL control");
+               return;
+       }
+
+       g_mutex_clear(&buffer_control->lock);
+       g_cond_clear(&buffer_control->cond);
+}
+
+
+int codec_v4l2_init(codec_type_e type, void **codec_handle)
+{
+       hal_codec_handle_s *new_handle = NULL;
+
+       tbm_bufmgr bufmgr = NULL;
+
+       LOGD("enter");
+
+       if (!codec_handle) {
+               LOGE("NULL pointer for handle");
+               return CODEC_ERROR_INVALID_PARAMETER;
+       }
+
+       bufmgr = tbm_bufmgr_init(-1);
+       if (bufmgr == NULL) {
+               LOGE("get tbm bufmgr failed");
+               return CODEC_ERROR_INTERNAL;
+       }
+
+       new_handle = g_new0(hal_codec_handle_s, 1);
+       if (!new_handle) {
+               LOGE("failed to alloc codec HAL handle");
+               tbm_bufmgr_deinit(bufmgr);
+               return CODEC_ERROR_OUT_OF_MEMORY;
+       }
+
+       new_handle->bufmgr = bufmgr;
+
+       g_mutex_init(&new_handle->lock);
+       g_cond_init(&new_handle->cond);
+
+       /* buffer */
+       __codec_init_buffer_control(&new_handle->input_buffer_control);
+       __codec_init_buffer_control(&new_handle->output_buffer_control);
+
+       /* message */
+       g_mutex_init(&new_handle->msg_cb_lock);
+       g_cond_init(&new_handle->msg_cb_cond);
+
+       new_handle->msg_list = g_queue_new();
+       new_handle->msg_cb_run = TRUE;
+       new_handle->msg_thread = g_thread_try_new("codecHAL:msg",
+               _codec_message_handler_func, (gpointer)new_handle, NULL);
+       if (!new_handle->msg_thread) {
+               LOGE("failed to create message thread");
+               __codec_release_handle(new_handle);
+               return CODEC_ERROR_INTERNAL;
+       }
+
+       new_handle->device_index = CODEC_HAL_INITIAL_INDEX;
+       new_handle->device_fd = CODEC_HAL_INITIAL_FD;
+       new_handle->state = CODEC_STATE_INITIALIZED;
+
+       *codec_handle = new_handle;
+
+       LOGD("codec HAL handle [%p]", new_handle);
+
+       return CODEC_ERROR_NONE;
+}
+
+
+int codec_v4l2_deinit(void *codec_handle)
+{
+       hal_codec_handle_s *handle = (hal_codec_handle_s *)codec_handle;
+
+       if (!handle) {
+               LOGE("NULL handle");
+               return CODEC_ERROR_INVALID_PARAMETER;
+       }
+
+       g_mutex_lock(&handle->lock);
+
+       if (handle->state != CODEC_STATE_INITIALIZED) {
+               LOGE("invalid state [%d]", handle->state);
+               g_mutex_unlock(&handle->lock);
+               return CODEC_ERROR_INVALID_STATE;
+       }
+
+       g_mutex_unlock(&handle->lock);
+
+       __codec_release_handle(handle);
+
+       return CODEC_ERROR_NONE;
+}
+
+
+int codec_v4l2_configure(void *codec_handle, int width, int height, codec_format_e in_format, codec_format_e out_format, bool is_secure)
+{
+       int ret = 0;
+       int device_fd = CODEC_HAL_INITIAL_FD;
+       char *node_path = NULL;
+       hal_codec_handle_s *handle = (hal_codec_handle_s *)codec_handle;
+       enum v4l2_buf_type in_buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+       enum v4l2_buf_type out_buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       g_autoptr(GMutexLocker) locker = NULL;
+
+       if (!handle) {
+               LOGE("NULL handle");
+               return CODEC_ERROR_INVALID_PARAMETER;
+       }
+
+       locker = g_mutex_locker_new(&handle->lock);
+
+       if (handle->state != CODEC_STATE_INITIALIZED) {
+               LOGE("invalid state %d", handle->state);
+               return CODEC_ERROR_INVALID_STATE;
+       }
+
+       if (((in_format & CODEC_FORMAT_TYPE_ENCODED) && (out_format & CODEC_FORMAT_TYPE_ENCODED)) ||
+               ((in_format & CODEC_FORMAT_TYPE_RAW) && (out_format & CODEC_FORMAT_TYPE_RAW))) {
+               LOGE("invalid format : in[%d], out[%d]", in_format, out_format);
+               return CODEC_ERROR_INVALID_PARAMETER;
+       }
+
+       ret = __codec_v4l2_get_buf_type_and_node_path(in_format, out_format,
+               &in_buf_type, &out_buf_type, &node_path);
+       if (ret != CODEC_ERROR_NONE)
+               return ret;
+
+       /* device open */
+       device_fd = open(node_path, O_RDWR);
+       if (device_fd < 0) {
+               char error_string[ERROR_STRING_LENGTH] = {'\0',};
+               strerror_r(errno, error_string, ERROR_STRING_LENGTH);
+               LOGE("[%s] open failed [%s]", node_path, error_string);
+               return CODEC_ERROR_DEVICE_OPEN;
+       }
+
+       /* set format for input */
+       ret = __codec_v4l2_s_fmt(device_fd, in_format, in_buf_type, width, height);
+       if (ret != CODEC_ERROR_NONE) {
+               LOGE("set format[%d] for input failed - [0x%x]", in_format, ret);
+               close(device_fd);
+               return ret;
+       }
+
+       /* set format for output */
+       ret = __codec_v4l2_s_fmt(device_fd, out_format, out_buf_type, width, height);
+       if (ret != CODEC_ERROR_NONE) {
+               LOGE("set format[%d] for output failed - [0x%x]", in_format, ret);
+               close(device_fd);
+               return ret;
+       }
+
+       handle->input_buffer_control.buf_type = in_buf_type;
+       handle->output_buffer_control.buf_type = out_buf_type;
+
+       handle->device_fd = device_fd;
+       handle->state = CODEC_STATE_CONFIGURED;
+
+       LOGD("done");
+
+       return CODEC_ERROR_NONE;
+}
+
+
+int codec_v4l2_release(void *codec_handle)
+{
+       hal_codec_handle_s *handle = (hal_codec_handle_s *)codec_handle;
+       g_autoptr(GMutexLocker) locker = NULL;
+
+       if (!handle) {
+               LOGE("NULL handle");
+               return CODEC_ERROR_INVALID_PARAMETER;
+       }
+
+       locker = g_mutex_locker_new(&handle->lock);
+
+       if (handle->state != CODEC_STATE_CONFIGURED) {
+               LOGE("invalid state %d", handle->state);
+               return CODEC_ERROR_INVALID_STATE;
+       }
+
+       if (handle->device_fd > CODEC_HAL_INITIAL_FD) {
+               LOGI("close device fd [%d]", handle->device_fd);
+               close(handle->device_fd);
+       } else {
+               LOGW("invalid device fd [%d]", handle->device_fd);
+       }
+
+       handle->device_fd = CODEC_HAL_INITIAL_FD;
+       handle->state = CODEC_STATE_INITIALIZED;
+
+       LOGD("done");
+
+       return CODEC_ERROR_NONE;
+}
+
+
+int codec_v4l2_start(void *codec_handle, hal_codec_message_cb callback, void *user_data)
+{
+       int ret = 0;
+       hal_codec_handle_s *handle = (hal_codec_handle_s *)codec_handle;
+       g_autoptr(GMutexLocker) locker = NULL;
+
+       if (!handle || !callback) {
+               LOGE("NULL param %p %p", handle, callback);
+               return CODEC_ERROR_INVALID_PARAMETER;
+       }
+
+       locker = g_mutex_locker_new(&handle->lock);
+
+       if (handle->state != CODEC_STATE_CONFIGURED) {
+               LOGE("invalid state %d", handle->state);
+               return CODEC_ERROR_INVALID_STATE;
+       }
+
+       ret = __codec_start_stream(handle, BUFFER_MIN, BUFFER_MIN);
+       if (ret != CODEC_ERROR_NONE) {
+               LOGE("__codec_start_stream failed[0x%x]", ret);
+               return ret;
+       }
+
+       handle->state = CODEC_STATE_STARTED;
+
+       LOGD("start preview done");
+
+       return CODEC_ERROR_NONE;
+}
+
+
+int codec_v4l2_stop(void *codec_handle)
+{
+       int ret = CODEC_ERROR_NONE;
+       hal_codec_handle_s *handle = (hal_codec_handle_s *)codec_handle;
+       g_autoptr(GMutexLocker) locker = NULL;
+
+       if (!handle) {
+               LOGE("NULL handle");
+               return CODEC_ERROR_INVALID_PARAMETER;
+       }
+
+       LOGD("start");
+
+       locker = g_mutex_locker_new(&handle->lock);
+
+       if (handle->state != CODEC_STATE_STARTED) {
+               LOGE("invalid state %d", handle->state);
+               return CODEC_ERROR_INVALID_STATE;
+       }
+
+       ret = __codec_stop_stream(handle);
+
+       handle->state = CODEC_STATE_CONFIGURED;
+
+       LOGD("stop done [0x%x]", ret);
+
+       return CODEC_ERROR_NONE;
+}
+
+
+int codec_v4l2_flush(void *codec_handle)
+{
+       hal_codec_handle_s *handle = (hal_codec_handle_s *)codec_handle;
+
+       if (!handle) {
+               LOGE("NULL handle");
+               return CODEC_ERROR_INVALID_PARAMETER;
+       }
+
+       g_autoptr(GMutexLocker) locker = NULL;
+
+       locker = g_mutex_locker_new(&handle->lock);
+
+       return CODEC_ERROR_NONE;
+}
+
+
+int codec_v4l2_push_input_buffer(void *codec_handle, codec_buffer_s *buffer)
+{
+       hal_codec_handle_s *handle = (hal_codec_handle_s *)codec_handle;
+
+       if (!handle) {
+               LOGE("NULL handle");
+               return CODEC_ERROR_INVALID_PARAMETER;
+       }
+
+       g_autoptr(GMutexLocker) locker = NULL;
+
+       locker = g_mutex_locker_new(&handle->lock);
+
+       return CODEC_ERROR_NONE;
+}
+
+
+int codec_v4l2_release_output_buffer(void *codec_handle, int buffer_index)
+{
+       hal_codec_handle_s *handle = (hal_codec_handle_s *)codec_handle;
+
+       if (!handle) {
+               LOGE("NULL handle");
+               return CODEC_ERROR_INVALID_PARAMETER;
+       }
+
+       g_autoptr(GMutexLocker) locker = NULL;
+
+       locker = g_mutex_locker_new(&handle->lock);
+
+       return CODEC_ERROR_NONE;
+}
+
+
+int codec_v4l2_get_state(void *codec_handle, codec_state_e *state)
+{
+       hal_codec_handle_s *handle = (hal_codec_handle_s *)codec_handle;
+
+       if (!handle) {
+               LOGE("NULL handle");
+               return CODEC_ERROR_INVALID_PARAMETER;
+       }
+
+       return CODEC_ERROR_NONE;
+}
+
+
+static int __set_command(hal_codec_handle_s *handle, int64_t command, void *value)
+{
+       int cid = 0;
+       int ctrl_ret = 0;
+       int set_value = 0;
+
+       if (!handle || !value) {
+               LOGE("NULL param %p %p", handle, value);
+               return CODEC_ERROR_INVALID_PARAMETER;
+       }
+
+       set_value = *(int *)value;
+
+       if (handle->state < CODEC_STATE_OPENED) {
+               LOGE("invalid state %d", handle->state);
+               return CODEC_ERROR_INVALID_STATE;
+       }
+
+       LOGI("command[%"PRIx64"] -> [%d]", command, set_value);
+
+       switch (command) {
+       case CODEC_COMMAND_BITRATE:
+               cid = V4L2_CID_MPEG_VIDEO_BITRATE;
+               set_value = *(int *)value;
+               break;
+       default:
+               LOGE("NOT_SUPPORTED command %"PRIx64, command);
+               return CODEC_ERROR_NOT_SUPPORTED;
+       }
+
+       ctrl_ret = __codec_v4l2_s_ctrl(handle->device_fd, cid, set_value);
+       if (ctrl_ret < 0) {
+               switch (errno) {
+               case EACCES:
+               case EPERM:
+                       LOGE("Permission denied %d", errno);
+                       return CODEC_ERROR_PERMISSION_DENIED;
+               case EINVAL:
+                       LOGE("Invalid argument");
+                       return CODEC_ERROR_INVALID_PARAMETER;
+               case EBUSY:
+                       LOGE("Device busy");
+                       return CODEC_ERROR_DEVICE_BUSY;
+               case ENOTSUP:
+                       LOGE("Not supported");
+                       return CODEC_ERROR_NOT_SUPPORTED;
+               default:
+                       LOGE("Unknown errro %d", errno);
+                       return CODEC_ERROR_INTERNAL;
+               }
+       }
+
+       return CODEC_ERROR_NONE;
+}
+
+
+int codec_v4l2_set_command(void *codec_handle, int64_t command, void *value)
+{
+       int ret = CODEC_ERROR_NONE;
+       hal_codec_handle_s *handle = (hal_codec_handle_s *)codec_handle;
+       g_autoptr(GMutexLocker) locker = NULL;
+
+       locker = g_mutex_locker_new(&handle->lock);
+
+       ret = __set_command(handle, command, value);
+
+       return ret;
+}
+
+
+int codec_v4l2_get_command(void *codec_handle, int64_t command, void **value)
+{
+       int ret = CODEC_ERROR_NONE;
+       int cid = 0;
+       int ctrl_ret = 0;
+       hal_codec_handle_s *handle = (hal_codec_handle_s *)codec_handle;
+       g_autoptr(GMutexLocker) locker = NULL;
+
+       if (!handle || !value) {
+               LOGE("NULL param %p %p", handle, value);
+               return CODEC_ERROR_INVALID_PARAMETER;
+       }
+
+       locker = g_mutex_locker_new(&handle->lock);
+
+       LOGI("command[%"PRIx64"]", command);
+
+       switch (command) {
+       case CODEC_COMMAND_BITRATE:
+               cid = V4L2_CID_MPEG_VIDEO_BITRATE;
+               break;
+       default:
+               LOGE("Not supported command[%"PRIx64"]", command);
+               return CODEC_ERROR_NOT_SUPPORTED;
+       }
+
+       ctrl_ret = __codec_v4l2_g_ctrl(handle->device_fd, cid, (int *)*value);
+       if (ctrl_ret < 0) {
+               switch (errno) {
+               case EACCES:
+               case EPERM:
+                       LOGE("Permission denied %d", errno);
+                       ret = CODEC_ERROR_PERMISSION_DENIED;
+                       break;
+               case EINVAL:
+                       LOGE("Invalid argument");
+                       ret = CODEC_ERROR_INVALID_PARAMETER;
+                       break;
+               case EBUSY:
+                       LOGE("Device busy");
+                       ret = CODEC_ERROR_DEVICE_BUSY;
+                       break;
+               case ENOTSUP:
+                       LOGE("Not supported");
+                       ret = CODEC_ERROR_NOT_SUPPORTED;
+                       break;
+               default:
+                       LOGE("Unknown errro %d", errno);
+                       ret = CODEC_ERROR_INTERNAL;
+                       break;
+               }
+       }
+
+       if (ret == CODEC_ERROR_NONE)
+               LOGI("get[%d]", **(int **)value);
+
+       return ret;
+}
+
+
+static void __dump_batch_command(codec_batch_command_control_s *batch_command)
+{
+       if (!batch_command) {
+               LOGE("NULL batch command");
+               return;
+       }
+
+#if 0
+       LOGI("[WHITE_BALANCE] %d", batch_command->white_balance);
+#endif
+}
+
+
+int codec_v4l2_set_batch_command(void *codec_handle, codec_batch_command_control_s *batch_command, int64_t *error_command)
+{
+       int ret = CODEC_ERROR_NONE;
+       int i = 0;
+       int support_count = 0;
+       hal_codec_handle_s *handle = (hal_codec_handle_s *)codec_handle;
+       g_autoptr(GMutexLocker) locker = NULL;
+       set_batch_table_s set_table[] = {
+               {CODEC_COMMAND_BITRATE, batch_command ? (void *)&batch_command->bitrate : NULL},
+               {CODEC_COMMAND_REQUEST_CODECDATA, NULL},
+               {CODEC_COMMAND_REQUEST_SYNCFRAME, NULL}
+       };
+
+       if (!handle || !batch_command) {
+               LOGE("NULL param %p %p", handle, batch_command);
+               return CODEC_ERROR_INVALID_PARAMETER;
+       }
+
+       locker = g_mutex_locker_new(&handle->lock);
+
+       support_count = sizeof(set_table) / sizeof(set_batch_table_s);
+
+       LOGD("set batch command - support count %d", support_count);
+
+       __dump_batch_command(batch_command);
+
+       for (i = 0 ; i < support_count ; i++) {
+               if (!(batch_command->command_set_flag & set_table[i].command))
+                       continue;
+
+               ret = __set_command(handle, set_table[i].command, set_table[i].value);
+               if (ret != CODEC_ERROR_NONE) {
+                       LOGE("failed command %"PRIx64", ret 0x%x", set_table[i].command, ret);
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+
+static int codec_v4l2_backend_init(void **data)
+{
+       hal_backend_codec_funcs *funcs = NULL;
+
+       if (!data || !*data) {
+               LOGE("NULL data[%p]", data);
+               return -1;
+       }
+
+       funcs = (hal_backend_codec_funcs *)*data;
+
+       LOGI("codec HAL funcs[%p]", funcs);
+
+       funcs->init = codec_v4l2_init;
+       funcs->deinit = codec_v4l2_deinit;
+       funcs->configure = codec_v4l2_configure;
+       funcs->release = codec_v4l2_release;
+       funcs->start = codec_v4l2_start;
+       funcs->stop = codec_v4l2_stop;
+       funcs->flush = codec_v4l2_flush;
+       funcs->push_input_buffer = codec_v4l2_push_input_buffer;
+       funcs->release_output_buffer = codec_v4l2_release_output_buffer;
+       funcs->get_state = codec_v4l2_get_state;
+       funcs->set_command = codec_v4l2_set_command;
+       funcs->get_command = codec_v4l2_get_command;
+       funcs->set_batch_command = codec_v4l2_set_batch_command;
+
+       return 0;
+}
+
+
+static int codec_v4l2_backend_exit(void *data)
+{
+       if (!data) {
+               LOGW("NULL data");
+               return 0;
+       }
+
+       LOGI("clear function pointer[%p] set by backend", data);
+
+       memset(data, 0x0, sizeof(hal_backend_codec_funcs));
+
+       return 0;
+}
+
+
+hal_backend hal_backend_codec_data = {
+       .name = "codec-v4l2",
+       .vendor = "TIZEN",
+       .init = codec_v4l2_backend_init,
+       .exit = codec_v4l2_backend_exit,
+       .major_version = 1,
+       .minor_version = 0,
+};
diff --git a/src/hal_backend_codec_v4l2_private.h b/src/hal_backend_codec_v4l2_private.h
new file mode 100644 (file)
index 0000000..e4b12f8
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * hal_backend_codec_v4l2_private.h
+ *
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __HAL_BACKEND_CODEC_V4L2_PRIVATE_H__
+#define __HAL_BACKEND_CODEC_V4L2_PRIVATE_H__
+
+#include <linux/videodev2.h>
+#include <glib.h>
+#include <tbm_bufmgr.h>
+#include <hal/hal-common-interface.h>
+#include <hal/hal-codec-interface.h>
+
+#define CODEC_HAL_INITIAL_INDEX         -1
+#define CODEC_HAL_INITIAL_FD            -1
+#define BUFFER_MIN                      4
+#define BUFFER_MAX                      16
+#define V4L2_PLANES_MAX                 4
+
+
+typedef struct _set_batch_table_s {
+       int64_t command;
+       void *value;
+} set_batch_table_s;
+
+typedef struct _codec_tbm_buffer_s {
+       tbm_bo bo;
+       tbm_bo_handle bo_handle;
+       int dmabuf_fd;
+} codec_tbm_buffer_s;
+
+typedef struct _codec_hal_buffer_control_s {
+       gboolean is_run;
+       guint32 count;
+       guint32 queued_count;
+       GMutex lock;
+       GCond cond;
+       codec_format_e format;
+       enum v4l2_buf_type buf_type;
+       enum v4l2_memory memory_type;
+       codec_buffer_s buffers[BUFFER_MAX];
+} codec_buffer_control_s;
+
+typedef struct _codec_hal_handle_s {
+       /* tbm */
+       tbm_bufmgr bufmgr;
+
+       /* device */
+       gint32 device_index;
+       gint32 device_fd;
+
+       /* buffer */
+       codec_buffer_control_s input_buffer_control;
+       codec_buffer_control_s output_buffer_control;
+       GThread *output_thread;
+       gboolean output_thread_run;
+
+       /* message */
+       GThread *msg_thread;
+       hal_codec_message_cb msg_cb;
+       gpointer msg_cb_data;
+       gboolean msg_cb_run;
+       GQueue *msg_list;
+       GMutex msg_cb_lock;
+       GCond msg_cb_cond;
+
+       /* settings */
+       gint32 bitrate;
+
+       /* etc */
+       GMutex lock;
+       GCond cond;
+       codec_state_e state;
+} hal_codec_handle_s;
+
+int codec_v4l2_init(codec_type_e type, void **codec_handle);
+int codec_v4l2_deinit(void *codec_handle);
+int codec_v4l2_configure(void *codec_handle, int width, int height, codec_format_e in_format, codec_format_e out_format, bool is_secure);
+int codec_v4l2_release(void *codec_handle);
+int codec_v4l2_start(void *codec_handle, hal_codec_message_cb callback, void *user_data);
+int codec_v4l2_stop(void *codec_handle);
+int codec_v4l2_flush(void *codec_handle);
+int codec_v4l2_push_input_buffer(void *codec_handle, codec_buffer_s *buffer);
+int codec_v4l2_release_output_buffer(void *codec_handle, int buffer_index);
+int codec_v4l2_get_state(void *codec_handle, codec_state_e *state);
+int codec_v4l2_set_command(void *codec_handle, int64_t command, void *value);
+int codec_v4l2_get_command(void *codec_handle, int64_t command, void **value);
+int codec_v4l2_set_batch_command(void *codec_handle, codec_batch_command_control_s *batch_command, int64_t *error_command);
+
+#endif /* __HAL_BACKEND_CODEC_V4L2_PRIVATE_H__ */