Browse Source

Linux_SDK_V0.9.5

thead_admin 1 year ago
commit
b68c608415
100 changed files with 15930 additions and 0 deletions
  1. 21 0
      .gitignore
  2. 54 0
      Makefile
  3. 8 0
      README.md
  4. 63 0
      build.param
  5. 107 0
      common_target.mk
  6. 52 0
      examples/Makefile
  7. 5 0
      examples/camera/.gitignore
  8. 85 0
      examples/camera/Makefile
  9. 678 0
      examples/camera/cam_demo_ir.c
  10. 807 0
      examples/camera/cam_demo_multi.c
  11. 710 0
      examples/camera/cam_demo_simple.c
  12. 303 0
      examples/camera/camera_demo1.c
  13. 357 0
      examples/camera/camera_demo2.c
  14. 302 0
      examples/camera/camera_demo3.c
  15. 11 0
      examples/camera/camera_demo3.conf
  16. 59 0
      examples/camera/camera_demo3_srcs/app_dialogs.h
  17. 17 0
      examples/camera/camera_demo3_srcs/camera_ops.c
  18. 18 0
      examples/camera/camera_demo3_srcs/camera_ops.h
  19. 337 0
      examples/camera/camera_demo3_srcs/checkbox.c
  20. 355 0
      examples/camera/camera_demo3_srcs/checklist.c
  21. 276 0
      examples/camera/camera_demo3_srcs/dialog.h
  22. 80 0
      examples/camera/camera_demo3_srcs/dialog_camera_close.c
  23. 90 0
      examples/camera/camera_demo3_srcs/dialog_camera_list.c
  24. 156 0
      examples/camera/camera_demo3_srcs/dialog_camera_open.c
  25. 101 0
      examples/camera/camera_demo3_srcs/dialog_camera_property_bitmask.c
  26. 88 0
      examples/camera/camera_demo3_srcs/dialog_camera_property_boolean.c
  27. 95 0
      examples/camera/camera_demo3_srcs/dialog_camera_property_enum.c
  28. 73 0
      examples/camera/camera_demo3_srcs/dialog_camera_property_integer.c
  29. 418 0
      examples/camera/camera_demo3_srcs/dialog_camera_property_list.c
  30. 151 0
      examples/camera/camera_demo3_srcs/dialog_camera_set_mode.c
  31. 90 0
      examples/camera/camera_demo3_srcs/dialog_channel_list.c
  32. 573 0
      examples/camera/camera_demo3_srcs/dialog_channel_open.c
  33. 339 0
      examples/camera/camera_demo3_srcs/dialog_channel_run.c
  34. 150 0
      examples/camera/camera_demo3_srcs/dialog_channel_select.c
  35. 135 0
      examples/camera/camera_demo3_srcs/dialog_event_subscribe_action_camera.c
  36. 132 0
      examples/camera/camera_demo3_srcs/dialog_event_subscribe_action_channel.c
  37. 135 0
      examples/camera/camera_demo3_srcs/dialog_event_subscribe_action_list.c
  38. 302 0
      examples/camera/camera_demo3_srcs/inputbox.c
  39. 153 0
      examples/camera/camera_demo3_srcs/menu_process.c
  40. 30 0
      examples/camera/camera_demo3_srcs/menu_process.h
  41. 442 0
      examples/camera/camera_demo3_srcs/menubox.c
  42. 66 0
      examples/camera/camera_demo3_srcs/param.c
  43. 42 0
      examples/camera/camera_demo3_srcs/param.h
  44. 414 0
      examples/camera/camera_demo3_srcs/textbox.c
  45. 735 0
      examples/camera/camera_demo3_srcs/util.c
  46. 123 0
      examples/camera/camera_demo3_srcs/yesno.c
  47. 297 0
      examples/camera/camera_demo4.c
  48. 438 0
      examples/camera/camera_frame_display.c
  49. 391 0
      examples/camera/camera_test1.c
  50. 41 0
      examples/camera/opencv/Makefile
  51. 24 0
      examples/camera/opencv/apputilities.cpp
  52. 16 0
      examples/camera/opencv/apputilities.h
  53. 3 0
      examples/camera/run_camera_demo3.sh
  54. 1 0
      examples/common/.gitignore
  55. 27 0
      examples/common/Makefile
  56. 25 0
      examples/common/mtrace_demo.c
  57. 13 0
      examples/common/run_mtrace_demo.sh
  58. 3 0
      examples/frame/.gitignore
  59. 33 0
      examples/frame/Makefile
  60. 109 0
      examples/frame/frame_demo1.c
  61. 104 0
      examples/frame/frame_demo2.c
  62. 187 0
      examples/frame/frame_demo2_consumer.c
  63. 171 0
      examples/frame/frame_demo2_producer.c
  64. 214 0
      examples/frame/frame_demo_common.c
  65. 50 0
      examples/frame/frame_demo_common.h
  66. 1070 0
      examples/g2d/g2d_demo.c
  67. 0 0
      examples/resource/yuv420_1280x720_csky2016.yuv
  68. 3 0
      examples/vdec/.gitignore
  69. 30 0
      examples/vdec/Makefile
  70. 172 0
      examples/vdec/vdec_demo1.c
  71. 1 0
      examples/venc/.gitignore
  72. 30 0
      examples/venc/Makefile
  73. 179 0
      examples/venc/venc_demo1.c
  74. 42 0
      include/common/camera_string.h
  75. 65 0
      include/common/common.h
  76. 58 0
      include/common/common_datatype.h
  77. 34 0
      include/common/common_errno.h
  78. 20 0
      include/common/dump_utils.h
  79. 19 0
      include/common/ipc_fd_transfer.h
  80. 154 0
      include/common/list.h
  81. 50 0
      include/common/llist.h
  82. 104 0
      include/common/producer_consumer_async.h
  83. 47 0
      include/common/ringbuffer.h
  84. 111 0
      include/common/syslog.h
  85. 50 0
      include/hal/csi_allocator.h
  86. 135 0
      include/hal/csi_audio_ai.h
  87. 113 0
      include/hal/csi_audio_ao.h
  88. 168 0
      include/hal/csi_audio_common.h
  89. 61 0
      include/hal/csi_audio_dec.h
  90. 63 0
      include/hal/csi_audio_enc.h
  91. 297 0
      include/hal/csi_camera.h
  92. 62 0
      include/hal/csi_camera_frame.h
  93. 62 0
      include/hal/csi_camera_platform_spec.h
  94. 93 0
      include/hal/csi_camera_property.h
  95. 68 0
      include/hal/csi_common.h
  96. 54 0
      include/hal/csi_fce.h
  97. 94 0
      include/hal/csi_fce_cfg.h
  98. 156 0
      include/hal/csi_frame.h
  99. 176 0
      include/hal/csi_frame_ex.h
  100. 204 0
      include/hal/csi_g2d.h

+ 21 - 0
.gitignore

@@ -0,0 +1,21 @@
+/.auto.deps
+*.tmp
+*.bak
+*.depend
+*.o
+*.a
+*.o.d
+*.o.cmd
+*.a.cmd
+*.ko.cmd
+*.ko
+*.mod
+*.mod.c
+*.mod.cmd
+*.order
+*.orig
+*.log
+Module.symvers
+modules.order
+output/
+obj/

+ 54 - 0
Makefile

@@ -0,0 +1,54 @@
+##
+ # Copyright (C) 2021 Alibaba Group Holding Limited
+ # Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ #
+ # This program is free software; you can redistribute it and/or modify
+ # it under the terms of the GNU General Public License version 2 as
+ # published by the Free Software Foundation.
+##
+
+include build.param
+
+all: info common platform tests examples
+
+info:
+	@echo $(BUILD_LOG_START)
+	@echo "  ========== Build Info =========="
+	@echo "    Platform: "$(PLATFORM)
+	@echo "    ROOT_DIR: "$(ROOT_DIR)
+	@echo $(BUILD_LOG_END)
+
+common:
+	@echo $(BUILD_LOG_START)
+	make -C src/common
+	@echo $(BUILD_LOG_END)
+
+platform: common
+	@echo $(BUILD_LOG_START)
+	make -C src/platform
+	@echo $(BUILD_LOG_END)
+
+libs: platform
+	@echo $(BUILD_LOG_START)
+	make -C src/lib_camera
+	@echo $(BUILD_LOG_END)
+
+tests: platform libs
+	@echo $(BUILD_LOG_START)
+	make -C tests
+	@echo $(BUILD_LOG_END)
+
+examples: platform libs
+	@echo $(BUILD_LOG_START)
+	make -C examples
+	@echo $(BUILD_LOG_END)
+
+clean:
+	rm -rf .obj
+	make -C src/common/ clean
+	make -C src/platform/ clean
+	make -C src/lib_camera clean
+	make -C tests/ clean
+	make -C examples/ clean
+
+.PHONY: clean all info common platform tests examples

+ 8 - 0
README.md

@@ -0,0 +1,8 @@
+# How to get the code
+- git clone git@gitlab.alibaba-inc.com:thead-linux/csi_hal.git
+
+# How to build
+- https://yuque.antfin.com/occ/software/fhcekb
+
+# Description
+- Maintainer: Lu Chongzhi (chongzhi.lcz@alibaba-inc.com)

+ 63 - 0
build.param

@@ -0,0 +1,63 @@
+##
+ # Copyright (C) 2021 Alibaba Group Holding Limited
+ # Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ #
+ # This program is free software; you can redistribute it and/or modify
+ # it under the terms of the GNU General Public License version 2 as
+ # published by the Free Software Foundation.
+##
+
+BUILD_LOG_START="\n\033[47;30m>>> $(MODULE_NAME) $@ begin  >>>\033[0m"
+BUILD_LOG_END  ="\033[47;30m<<< $(MODULE_NAME) $@ end    <<<\033[0m"
+
+PLATFORM ?= simulator
+
+ROOT_DIR=$(dir $(abspath $(lastword $(MAKEFILE_LIST))))
+SO_LIB_DIR=lib_so
+
+ifeq ($(PLATFORM),simulator)
+  CFLAGS := -O0 -g -Werror -fPIC -DPLATFORM_SIMULATOR
+else
+  CFLAGS := -O2 -g -Werror -fPIC
+endif
+LFLAGS := -no-pie
+
+LIBS := -L$(ROOT_DIR)/output/common \
+           -L$(ROOT_DIR)/output/hal
+
+ifeq ($(PLATFORM),light)
+INCLUDE := -I$(ROOT_DIR)/include/common \
+           -I$(ROOT_DIR)/include/hal \
+           -I$(ROOT_DIR)/include/lib_camera \
+           -I$(ROOT_DIR)/src/lib_camera/camera_action/include\
+           -I$(ROOT_DIR)/examples/camera/camera_demo3_srcs \
+           -I$(ROOT_DIR)/src/lib_camera \
+           -I$(ROOT_DIR)/../recipe-sysroot/usr/include/csi_hal/
+
+else
+INCLUDE := -I$(ROOT_DIR)/include/common \
+           -I$(ROOT_DIR)/include/hal \
+           -I$(ROOT_DIR)/include/lib_camera \
+           -I$(ROOT_DIR)/src/lib_camera/camera_action/include
+endif
+
+ifeq ($(PLATFORM),simulator)
+  CC  := gcc
+  CXX := g++
+  CPP := g++
+  AR  := ar
+  LD  := ld
+  RAN := ranlib
+  LIBOPENCV_INC = $(shell pkg-config --cflags opencv)
+  LIBOPENCV_LIBS = $(shell pkg-config --libs opencv)
+else ifeq ($(PLATFORM),light)
+#  PARAM_FILE  = ../.param
+#  -include $(PARAM_FILE)
+test = $(shell if [ -f "../.param" ]; then echo "exist"; else echo "noexist"; fi)
+ifeq ("$(test)", "exist")
+  -include ../.param
+endif
+else
+  $(error PLATFORM undefined)
+endif
+

+ 107 - 0
common_target.mk

@@ -0,0 +1,107 @@
+##
+ # Copyright (C) 2021 Alibaba Group Holding Limited
+ # Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ #
+ # This program is free software; you can redistribute it and/or modify
+ # it under the terms of the GNU General Public License version 2 as
+ # published by the Free Software Foundation.
+##
+
+OBJS_1 = $(SRCS_1:.c=.o)
+$(TARGET_1): $(OBJS_1) $(PREPARE)
+	@mkdir -p $(OUTPUT_DIR)
+	@echo ">>> Linking" $@ "..."
+	$(CC) $(LFLAGS) -o $@ $(addprefix .obj/,$(notdir $(OBJS_1))) -Wl,--start-group $(LIBS) $(LIBS_1) -Wl,--end-group
+	cp $@ $(OUTPUT_DIR)
+
+$(OBJS_1): %.o:%.c
+	@mkdir -p .obj
+	@echo ">>> Compiling" $< "..."
+	$(CC) $(CFLAGS) $(INCLUDE) -c -o .obj/$(notdir $@) $<
+
+OBJS_2 = $(SRCS_2:.c=.o)
+$(TARGET_2): $(OBJS_2) $(PREPARE)
+	@mkdir -p $(OUTPUT_DIR)
+	@echo ">>> Linking" $@ "..."
+	$(CC) $(LFLAGS) -o $@ $(addprefix .obj/,$(notdir $(OBJS_2))) -Wl,--start-group $(LIBS) $(LIBS_2) -Wl,--end-group
+	cp $@ $(OUTPUT_DIR)
+
+$(OBJS_2): %.o:%.c
+	@mkdir -p .obj
+	@echo ">>> Compiling" $< "..."
+	$(CC) $(CFLAGS) $(INCLUDE) -c -o .obj/$(notdir $@) $<
+
+OBJS_3 = $(SRCS_3:.c=.o)
+$(TARGET_3): $(OBJS_3) $(PREPARE)
+	@mkdir -p $(OUTPUT_DIR)
+	@echo ">>> Linking" $@ "..."
+	$(CC) $(LFLAGS) -o $@ $(addprefix .obj/,$(notdir $(OBJS_3))) -Wl,--start-group $(LIBS) $(LIBS_3) -Wl,--end-group
+	cp $@ $(OUTPUT_DIR)
+
+$(OBJS_3): %.o:%.c
+	@mkdir -p .obj
+	@echo ">>> Compiling" $< "..."
+	$(CC) $(CFLAGS) $(INCLUDE) -c -o .obj/$(notdir $@) $<
+
+OBJS_4 = $(SRCS_4:.c=.o)
+$(TARGET_4): $(OBJS_4) $(PREPARE)
+	@mkdir -p $(OUTPUT_DIR)
+	@echo ">>> Linking" $@ "..."
+	$(CC) $(LFLAGS) -o $@ $(addprefix .obj/,$(notdir $(OBJS_4))) -Wl,--start-group $(LIBS) $(LIBS_4) -Wl,--end-group
+	cp $@ $(OUTPUT_DIR)
+
+$(OBJS_4): %.o:%.c
+	@mkdir -p .obj
+	@echo ">>> Compiling" $< "..."
+	$(CC) $(CFLAGS) $(INCLUDE) -c -o .obj/$(notdir $@) $<
+
+
+OBJS_5 = $(SRCS_5:.c=.o)
+$(TARGET_5): $(OBJS_5) $(PREPARE)
+	@mkdir -p $(OUTPUT_DIR)
+	@echo ">>> Linking" $@ "..."
+	$(CC) $(LFLAGS) -o $@ $(addprefix .obj/,$(notdir $(OBJS_5))) -Wl,--start-group $(LIBS) $(LIBS_5) -Wl,--end-group
+	cp $@ $(OUTPUT_DIR)
+
+$(OBJS_5): %.o:%.c
+	@mkdir -p .obj
+	@echo ">>> Compiling" $< "..."
+	$(CC) $(CFLAGS) $(INCLUDE) -c -o .obj/$(notdir $@) $<
+
+OBJS_6 = $(SRCS_6:.c=.o)
+$(TARGET_6): $(OBJS_6) $(PREPARE)
+	@mkdir -p $(OUTPUT_DIR)
+	@echo ">>> Linking" $@ "..."
+	$(CC) $(LFLAGS) -o $@ $(addprefix .obj/,$(notdir $(OBJS_6))) -Wl,--start-group $(LIBS) $(LIBS_6) -Wl,--end-group
+	cp $@ $(OUTPUT_DIR)
+
+$(OBJS_6): %.o:%.c
+	@mkdir -p .obj
+	@echo ">>> Compiling" $< "..."
+	$(CC) $(CFLAGS) $(INCLUDE) -c -o .obj/$(notdir $@) $<
+
+
+OBJS_7 = $(SRCS_7:.c=.o)
+$(TARGET_7): $(OBJS_7) $(PREPARE)
+	@mkdir -p $(OUTPUT_DIR)
+	@echo ">>> Linking" $@ "..."
+	$(CC) $(LFLAGS) -o $@ $(addprefix .obj/,$(notdir $(OBJS_7))) -Wl,--start-group $(LIBS) $(LIBS_7) -Wl,--end-group
+	cp $@ $(OUTPUT_DIR)
+
+$(OBJS_7): %.o:%.c
+	@mkdir -p .obj
+	@echo ">>> Compiling" $< "..."
+	$(CC) $(CFLAGS) $(INCLUDE) -c -o .obj/$(notdir $@) $<
+
+OBJS_8 = $(SRCS_8:.c=.o)
+$(TARGET_8): $(OBJS_8) $(PREPARE)
+	@mkdir -p $(OUTPUT_DIR)
+	@echo ">>> Linking" $@ "..."
+	$(CC) $(LFLAGS) -o $@ $(addprefix .obj/,$(notdir $(OBJS_8))) -Wl,--start-group $(LIBS) $(LIBS_8) -Wl,--end-group
+	cp $@ $(OUTPUT_DIR)
+
+$(OBJS_8): %.o:%.c
+	@mkdir -p .obj
+	@echo ">>> Compiling" $< "..."
+	$(CC) $(CFLAGS) $(INCLUDE) -c -o .obj/$(notdir $@) $<
+

+ 52 - 0
examples/Makefile

@@ -0,0 +1,52 @@
+##
+ # Copyright (C) 2021 Alibaba Group Holding Limited
+ # Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ #
+ # This program is free software; you can redistribute it and/or modify
+ # it under the terms of the GNU General Public License version 2 as
+ # published by the Free Software Foundation.
+##
+DIR_TO_ROOT=..
+include $(DIR_TO_ROOT)/build.param
+
+ALL_TARGETS := common camera frame
+ifeq ($(PLATFORM),simulator)
+  ALL_TARGETS += vdec venc
+endif
+
+all: $(ALL_TARGETS)
+
+common:
+	@echo $(BUILD_LOG_START)
+	make -C common/
+	@echo $(BUILD_LOG_END)
+
+camera:
+	@echo $(BUILD_LOG_START)
+	make -C camera/
+	@echo $(BUILD_LOG_END)
+
+frame:
+	@echo $(BUILD_LOG_START)
+	make -C frame/
+	@echo $(BUILD_LOG_END)
+
+vdec:
+	@echo $(BUILD_LOG_START)
+	make -C vdec/
+	@echo $(BUILD_LOG_END)
+
+venc:
+	@echo $(BUILD_LOG_START)
+	make -C venc/
+	@echo $(BUILD_LOG_END)
+
+clean:
+	make -C common/ clean
+	make -C camera/ clean
+	make -C frame/ clean
+	make -C vdec/ clean
+	make -C venc/ clean
+	rm -rf $(DIR_TO_ROOT)/output/examples/resource
+
+.PHONY: clean all common camera frame vdec venc

+ 5 - 0
examples/camera/.gitignore

@@ -0,0 +1,5 @@
+camera_demo1
+camera_demo2
+camera_demo3
+camera_demo4
+camera_demo5

+ 85 - 0
examples/camera/Makefile

@@ -0,0 +1,85 @@
+##
+ # Copyright (C) 2021 Alibaba Group Holding Limited
+ # Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ #
+ # This program is free software; you can redistribute it and/or modify
+ # it under the terms of the GNU General Public License version 2 as
+ # published by the Free Software Foundation.
+##
+DIR_TO_ROOT=../..
+include $(DIR_TO_ROOT)/build.param
+
+CFLAGS  += -Wno-error=unused-result -Icamera_demo3_srcs -I./camera_demo3_srcs -I$(DIR_TO_ROOT)/src/lib_camera/
+LIBS	+= -lhal_common -lhal_camera -lhal_platform -lpthread -lcamera_action
+OUTPUT_DIR := $(DIR_TO_ROOT)/output/examples/camera
+PREPARE := lib_camera
+
+ifeq ($(PLATFORM),light)
+  CFLAGS +=  -I$(VISYS_SYM_PATH)/usr/include/plink/
+  CFLAGS +=  -I$(VISYS_SYM_PATH)/usr/include/vidmem/
+  LIBS += -lstdc++ -lpthread 
+  LIBS += -lvmem -lplink
+ 
+endif
+
+ifeq ($(PLATFORM),simulator)
+  LIBS += -lcamera_platform -lapp_utilities -lcamera_utilities  $(LIBOPENCV_LIBS) -lstdc++
+  CFLAGS += $(LIBOPENCV_INC) -I ./opencv
+  PREPARE += opencv
+endif
+
+TARGET_1 := camera_demo1
+SRCS_1 = camera_demo1.c
+
+TARGET_2 := camera_demo2
+SRCS_2 = camera_demo2.c
+
+TARGET_3 := camera_demo3
+SRCS_3 := camera_demo3.c $(wildcard camera_demo3_srcs/*.c)
+LIBS_3 += -lcurses
+
+TARGET_4 := camera_demo4
+SRCS_4 = camera_demo4.c
+
+TARGET_5 := camera_test1
+SRCS_5 = camera_test1.c
+
+TARGET_6 := cam_demo_simple
+SRCS_6 = cam_demo_simple.c camera_frame_display.c
+
+TARGET_7 := cam_demo_ir
+SRCS_7 = cam_demo_ir.c camera_frame_display.c
+
+TARGET_8 := cam_demo_multi
+SRCS_8 = cam_demo_multi.c camera_frame_display.c
+
+ifeq ($(PLATFORM),simulator)
+TARGET_ALL := $(TARGET_1) $(TARGET_2) $(TARGET_3) $(TARGET_4)
+else
+TARGET_ALL := $(TARGET_1) $(TARGET_2) $(TARGET_3) $(TARGET_5)  $(TARGET_6) $(TARGET_7) $(TARGET_8) 
+endif
+
+all: $(TARGET_ALL)
+	cp run_camera_demo3.sh $(OUTPUT_DIR)
+	cp camera_demo3.conf $(OUTPUT_DIR)
+
+lib_camera:
+	make -C $(DIR_TO_ROOT)/src/lib_camera
+
+opencv:
+	make -C opencv
+
+clean:
+	rm -rf .obj
+	rm -f $(TARGET_1) $(OUTPUT_DIR)/$(TARGET_1)
+	rm -f $(TARGET_2) $(OUTPUT_DIR)/$(TARGET_2)
+	rm -f $(TARGET_3) $(OUTPUT_DIR)/$(TARGET_3)
+	rm -f $(TARGET_3) $(OUTPUT_DIR)/run_camera_demo3.sh
+	rm -f $(TARGET_3) $(OUTPUT_DIR)/camera_demo3.conf
+	rm -f $(TARGET_4) $(OUTPUT_DIR)/$(TARGET_4)
+	rm -f $(TARGET_5) $(OUTPUT_DIR)/$(TARGET_5)
+	make -C ./opencv clean
+
+include $(DIR_TO_ROOT)/common_target.mk
+
+.PHONY: opencv clean all

+ 678 - 0
examples/camera/cam_demo_ir.c

@@ -0,0 +1,678 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "pthread.h"
+#include <sys/mman.h>
+#define LOG_LEVEL 2
+#define LOG_PREFIX "cam_demo_ir"
+#include <syslog.h>
+
+
+#include <csi_frame.h>
+#include <csi_camera.h>
+#include "csi_camera_dev_api.h"
+#define TEST_DEVICE_NAME "/dev/video12"
+typedef struct frame_fps {
+	uint64_t frameNumber;
+	struct timeval initTick;
+	float fps;
+} frame_fps_t;
+static void dump_camera_meta(csi_frame_s *frame);
+static void dump_camera_frame(csi_frame_s *frame, int ch_id);
+
+
+typedef struct event_queue_item{
+    struct csi_camera_event evet;
+    struct event_queue_item *next;
+}event_queue_item_t;
+
+typedef struct channel_handle_ctx{
+
+        struct event_queue{
+         event_queue_item_t *head;
+         event_queue_item_t *tail;
+         int exit;
+        pthread_mutex_t mutex;
+        pthread_cond_t cond;
+    }event_queue;
+    csi_cam_handle_t cam_handle;
+    pthread_t  chan_thread;
+    int frame_num;
+}channel_handle_ctx_t;
+
+static  event_queue_item_t *dequeue_event(channel_handle_ctx_t *ctx)
+{
+	event_queue_item_t *ev = ctx->event_queue.head;
+    pthread_mutex_lock(&ctx->event_queue.mutex);
+	if(!ev)
+    {
+        pthread_mutex_unlock(&ctx->event_queue.mutex);
+        return NULL;
+    }
+
+	if(ev == ctx->event_queue.tail)
+		ctx->event_queue.tail = NULL;
+	ctx->event_queue.head = ev->next;
+    pthread_mutex_unlock(&ctx->event_queue.mutex);
+    return ev;
+}
+
+static int test_flag =0;
+static void enqueue_event(channel_handle_ctx_t *ctx,event_queue_item_t * item)
+{
+
+	if(!item || !ctx)
+		return;
+    item->next = NULL;
+	LOG_D("%s enter \n", __func__);
+	pthread_mutex_lock(&ctx->event_queue.mutex);
+	if (ctx->event_queue.tail) {
+		ctx->event_queue.tail->next = item;
+	} else {
+		ctx->event_queue.head = item;
+        // pthread_cond_broadcast(&ctx->cond.cond);
+	}
+	ctx->event_queue.tail = item;
+	pthread_mutex_unlock(&ctx->event_queue.mutex);
+}
+static void* camera_channle_process(void* arg)
+{
+
+	struct timeval init_time, cur_time;
+    frame_fps_t demo_fps;
+    csi_frame_s frame;
+	memset(&init_time, 0, sizeof(init_time));
+	memset(&cur_time, 0, sizeof(cur_time));
+    channel_handle_ctx_t * ctx = (channel_handle_ctx_t *)arg;
+    int timeout = -1; // unit: ms, -1 means wait forever, or until error occurs
+    LOG_D("Channel process running........\n");
+    while(ctx->event_queue.exit == 0)
+    {
+        event_queue_item_t *item = dequeue_event(ctx);
+        if(item==NULL)
+        {
+            continue;
+        }
+
+	switch (item->evet.type) {
+		case CSI_CAMERA_EVENT_TYPE_CHANNEL0:
+		case CSI_CAMERA_EVENT_TYPE_CHANNEL1:
+			switch (item->evet.id) {
+			case CSI_CAMERA_CHANNEL_EVENT_FRAME_READY: {
+                csi_camera_channel_id_e ch_id = item->evet.type-CSI_CAMERA_EVENT_TYPE_CHANNEL0+CSI_CAMERA_CHANNEL_0;
+				int read_frame_count = csi_camera_get_frame_count(ctx->cam_handle,
+						       ch_id);
+				for (int i = 0; i < read_frame_count; i++) {
+					csi_camera_get_frame(ctx->cam_handle, ch_id, &frame, timeout);
+                    demo_fps.frameNumber++;
+                    ctx->frame_num++;
+                    dump_camera_meta(&frame);
+                    if(test_flag ==0)
+                    {
+                        dump_camera_frame(&frame,ch_id);
+                    }
+
+                    // csi_camera_frame_unlock(cam_handle, &frame);
+                    csi_camera_put_frame(&frame);
+					csi_frame_release(&frame);
+				}
+                unsigned  long diff;
+				if (init_time.tv_usec == 0)
+					gettimeofday(&init_time,0);//osGetTick();
+				gettimeofday(&cur_time, 0);
+				diff = 1000000 * (cur_time.tv_sec-init_time.tv_sec)+ cur_time.tv_usec-init_time.tv_usec;
+		
+				if (diff != 0)
+					demo_fps.fps = (float)demo_fps.frameNumber / diff * 1000000.0f;
+				LOG_O("ch id:%d read_frame_count = %d, frame_count = %d, fps = %.2f diff = %ld\n",ch_id, read_frame_count, ctx->frame_num, demo_fps.fps, diff);
+
+				break;
+			}
+			default:
+				break;
+			}
+		default:
+			break;
+		}
+        free(item);
+    }
+    LOG_O("exit\n");
+    pthread_exit(0);
+}
+channel_handle_ctx_t  channel_ctx[2];
+/***********************DSP ALGO *******************************/
+
+typedef struct cb_context{
+    int id;
+    csi_cam_handle_t cam_handle;
+    int dsp_id;
+    int dsp_path;
+    void *ref_buf;
+    int buf_size;
+}cb_context_t;
+
+typedef struct cb_args{
+    char lib_name[8];
+    char setting[16];
+    uint32_t frame_id;
+    uint64_t timestap;
+    uint32_t  temp_projector;   //投射器温度
+	uint32_t  temp_sensor;     //sensor 温度
+}cb_args_t;
+cb_context_t cb_context[2];
+void dsp_algo_result_cb(void*context,void*arg)
+{
+   cb_context_t *ctx = (cb_context_t *)context;
+    cb_args_t *cb_args= (cb_args_t*)arg;    
+    char update_setting[16];
+    struct timeval times_value;
+    uint32_t frame_id = cb_args->frame_id;
+    uint64_t frame_timestap =  cb_args->timestap;
+    times_value.tv_sec = cb_args->timestap/1000000;
+    times_value.tv_usec = cb_args->timestap%1000000;
+
+    LOG_O("cb:%d,%s,setting:%s,frame :%d,timestad:(%ld s,%ld us)\n",ctx->id,cb_args->lib_name,cb_args->setting,
+                                                            frame_id,times_value.tv_sec,times_value.tv_usec);
+    LOG_O("temperate projector:%d,sensor:%d\n",cb_args->temp_projector,cb_args->temp_sensor);
+
+    if(test_flag!=0)
+    {
+        sprintf(update_setting, "update_%d", frame_id);
+        csi_camera_update_dsp_algo_setting(ctx->cam_handle,ctx->dsp_id,ctx->dsp_path,update_setting);
+        if(frame_id%20==0)
+        {
+            void *replace_buf;
+            *((uint32_t*)ctx->ref_buf) = frame_id;
+            csi_camera_update_dsp_algo_buf(ctx->cam_handle, ctx->dsp_id,ctx->dsp_path,ctx->ref_buf,&replace_buf);
+            LOG_D("cb:%d,old buffer:0x%llx,new buffer:0x%llx\n",ctx->id,ctx->ref_buf,replace_buf);
+            ctx->ref_buf = replace_buf;
+        }
+    }
+}
+static void usage(void)
+{
+	printf("    1 : video id  cases\n");
+    printf("    2 : [0]dump frame or [1] algo loop test\n");
+    printf("    3 : frame num to stop ,0: for not stop\n");
+	printf("    4 : channel 0 algo\n");
+	printf("    5 : channel 1 algo\n");
+
+}
+
+int main(int argc, char *argv[])
+{
+	uint32_t i;
+	bool running = true;
+	csi_camera_info_s camera_info;
+	frame_fps_t demo_fps;
+    char *algo_1;
+    char *algo_2;
+    int video_id = -1;
+    char dev_name[64];
+    int frame_num = 0;
+    algo_2 = "dsp1_dummy_algo_flo";
+    algo_1 = "dsp1_dummy_algo_flo_1";
+	switch(argc)
+    {
+        case 0:
+        case 1:
+                 LOG_E("input ERROR:vidoe id is mandatory\n");
+                 usage();
+                 return -1;
+        
+        case 6:
+                algo_2 = (argv[5]);
+        case 5:
+                algo_1 = (argv[4]);
+        case 4:
+                frame_num = atoi(argv[3]);
+        case 3:
+                test_flag = atoi(argv[2]);
+        case 2:
+                video_id = atoi(argv[1]);
+                break;
+        default:
+            LOG_E("input ERROR:too many param\n");
+            usage();
+            return -1;
+    }
+    LOG_O("Demo: video id:%d,test type:%d,frame number:%d,algo1:%s,algo2:%s\n",video_id,test_flag,frame_num,algo_1,algo_2);
+    sprintf(dev_name, "/dev/video%d", video_id);
+	memset(&demo_fps, 0, sizeof(demo_fps));
+	struct timeval init_time, cur_time;
+	memset(&init_time, 0, sizeof(init_time));
+	memset(&cur_time, 0, sizeof(cur_time));
+	// 获取设备中,所有的Camera
+	struct csi_camera_infos camera_infos;
+	memset(&camera_infos, 0, sizeof(camera_infos));
+	csi_camera_query_list(&camera_infos);
+	LOG_O("csi_camera_query_list() OK\n");
+
+	// 打印所有设备所支持的Camera
+	for (i = 0; i < camera_infos.count; i++) {
+		printf("Camera[%d]: camera_name='%s', device_name='%s', bus_info='%s', capabilities=0x%08x\n",
+		       i, camera_infos.info[i].camera_name, camera_infos.info[i].device_name,
+		       camera_infos.info[i].bus_info, camera_infos.info[i].capabilities);
+	}
+	/*  Camera[0]: camera_name='RGB_Camera', device_name='/dev/video0', bus_info='CSI-MIPI', capabilities=0x00800001
+	 *  Camera[1]: camera_name:'Mono_Camera', device_name:'/dev/video8', bus_info='USB', capabilities=0x00000001
+	 */
+
+	bool found_camera = false;
+	for (i = 0; i < camera_infos.count; i++) {
+		if (strcmp(camera_infos.info[i].device_name, dev_name) == 0) {
+			camera_info = camera_infos.info[i];
+			printf("found device_name:'%s'\n", camera_info.device_name);
+			found_camera = true;
+			break;
+		}
+	}
+	if (!found_camera) {
+		LOG_E("Can't find camera_name:'%s'\n", dev_name);
+		exit(-1);
+	}
+
+	printf("The caps are:\n");
+	for (i = 1; i < 0x80000000; i = i << 1) {
+		switch (camera_info.capabilities & i) {
+		case CSI_CAMERA_CAP_VIDEO_CAPTURE:
+			printf("\t Video capture\n");
+			break;
+		case CSI_CAMERA_CAP_META_CAPTURE:
+			printf("\t metadata capture\n");
+			break;
+		default:
+			if (camera_info.capabilities & i) {
+				printf("\t unknown capabilities(0x%08x)\n", camera_info.capabilities & i);
+			}
+			break;
+		}
+	}
+
+	/*  The caps are: Video capture, metadata capture */
+	// 打开Camera设备获取句柄,作为后续操对象
+	csi_cam_handle_t cam_handle;
+	csi_camera_open(&cam_handle, camera_info.device_name);
+	LOG_O("csi_camera_open() OK\n");
+
+	// 获取Camera支持的工作模式
+	struct csi_camera_modes camera_modes;
+	camera_modes.count = 0;
+	csi_camera_get_modes(cam_handle, &camera_modes);
+	LOG_O("csi_camera_get_modes() OK\n");
+
+	// 打印camera所支持的所有工作模式
+	printf(" Camera:'%s' modes are:{\n", dev_name);
+	for (i = 0; i < camera_modes.count; i++) {
+		printf("\t mode_id=%d: description:'%s'\n",
+		       camera_modes.modes[i].mode_id, camera_modes.modes[i].description);
+	}
+	printf("}\n");
+
+	
+	csi_camera_channel_cfg_s chn_cfg;
+
+	chn_cfg.chn_id = CSI_CAMERA_CHANNEL_0;
+	chn_cfg.frm_cnt = 4;
+	chn_cfg.img_fmt.width = 1080;
+	chn_cfg.img_fmt.height = 1280;
+	chn_cfg.img_fmt.pix_fmt = CSI_PIX_FMT_RAW_12BIT;
+	chn_cfg.img_type = CSI_IMG_TYPE_DMA_BUF;
+	chn_cfg.meta_fields = CSI_CAMERA_META_DEFAULT_FIELDS;
+	chn_cfg.capture_type = CSI_CAMERA_CHANNEL_CAPTURE_VIDEO |
+			       CSI_CAMERA_CHANNEL_CAPTURE_META;
+	csi_camera_channel_open(cam_handle, &chn_cfg);
+	LOG_O("CSI_CAMERA_CHANNEL_0: csi_camera_channel_open() OK\n");
+
+
+	// 打开输出channel_1
+	chn_cfg.chn_id = CSI_CAMERA_CHANNEL_1;
+	chn_cfg.frm_cnt = 4;
+	chn_cfg.img_fmt.width = 1080;
+	chn_cfg.img_fmt.height = 1280;
+	chn_cfg.img_fmt.pix_fmt = CSI_PIX_FMT_RAW_12BIT;
+	chn_cfg.img_type = CSI_IMG_TYPE_DMA_BUF;
+	chn_cfg.meta_fields = CSI_CAMERA_META_DEFAULT_FIELDS;
+	chn_cfg.capture_type = CSI_CAMERA_CHANNEL_CAPTURE_VIDEO |
+			       CSI_CAMERA_CHANNEL_CAPTURE_META;
+	csi_camera_channel_open(cam_handle, &chn_cfg);
+	LOG_O("CSI_CAMERA_CHANNEL_1: csi_camera_channel_open() OK\n");
+
+	// 订阅Event
+	csi_cam_event_handle_t event_handle;
+	csi_camera_create_event(&event_handle, cam_handle);
+	struct csi_camera_event_subscription subscribe;
+	subscribe.type =
+		CSI_CAMERA_EVENT_TYPE_CAMERA;      // 订阅Camera的ERROR事件
+	subscribe.id = CSI_CAMERA_EVENT_WARNING | CSI_CAMERA_EVENT_ERROR;
+	csi_camera_subscribe_event(event_handle, &subscribe);
+
+	subscribe.type =
+		CSI_CAMERA_EVENT_TYPE_CHANNEL0;    // 订阅Channel0的FRAME_READY事件
+	subscribe.id = CSI_CAMERA_CHANNEL_EVENT_FRAME_READY |
+		       CSI_CAMERA_CHANNEL_EVENT_OVERFLOW;
+	csi_camera_subscribe_event(event_handle, &subscribe);
+    memset(&channel_ctx[0],0x0,sizeof(channel_handle_ctx_t));
+    channel_ctx[0].cam_handle = cam_handle;
+    pthread_mutex_init(&channel_ctx[0].event_queue.mutex,NULL);
+    pthread_cond_init(&channel_ctx[0].event_queue.cond,NULL);
+   pthread_create(&channel_ctx[0].chan_thread,NULL,camera_channle_process,&channel_ctx[0]);
+
+	subscribe.type =
+		CSI_CAMERA_EVENT_TYPE_CHANNEL1;    // 订阅Channel0的FRAME_READY事件
+	subscribe.id = CSI_CAMERA_CHANNEL_EVENT_FRAME_READY |
+		       CSI_CAMERA_CHANNEL_EVENT_OVERFLOW;
+	csi_camera_subscribe_event(event_handle, &subscribe);
+    memset(&channel_ctx[1],0x0,sizeof(channel_handle_ctx_t));
+    channel_ctx[1].cam_handle = cam_handle;
+    pthread_mutex_init(&channel_ctx[1].event_queue.mutex,NULL);
+    pthread_cond_init(&channel_ctx[1].event_queue.cond,NULL);
+    pthread_create(&channel_ctx[1].chan_thread,NULL,camera_channle_process,&channel_ctx[1]);
+	LOG_O("Event subscript OK\n");
+    
+    cb_context[0].id=0;
+    cb_context[0].cam_handle = cam_handle;
+    cb_context[0].dsp_id = 1;
+    cb_context[0].dsp_path = 3;    
+    char test_set[16]="init";
+    cb_context[0].buf_size = 1920*1080;
+    cb_context[0].ref_buf=NULL;
+    csi_camera_dsp_algo_param_t algo_param_1={
+        .algo_name = algo_1,
+        .algo_cb.cb = dsp_algo_result_cb,
+        .algo_cb.context = &cb_context[0],
+        .algo_cb.arg_size =  sizeof(cb_args_t),
+        .sett_ptr = test_set,
+        .sett_size =sizeof(test_set),
+        .extra_buf_num =1,
+        .extra_buf_sizes = &cb_context[0].buf_size,
+        .extra_bufs = &cb_context[0].ref_buf,
+    };
+    
+    if(csi_camera_set_dsp_algo_param(cam_handle, cb_context[0].dsp_id,cb_context[0].dsp_path, &algo_param_1))
+    {
+        LOG_E("set DSP algo fail\n");
+        
+    }
+
+
+    cb_context[1].id=1;
+    cb_context[1].cam_handle = cam_handle;
+    cb_context[1].dsp_id = 1;
+    cb_context[1].dsp_path = 4;    
+    cb_context[1].buf_size = 1920*1080;
+    cb_context[1].ref_buf=NULL;
+    csi_camera_dsp_algo_param_t algo_param_2={
+        .algo_name = algo_2,
+        .algo_cb.cb = dsp_algo_result_cb,
+        .algo_cb.context = &cb_context[1],
+        .algo_cb.arg_size = sizeof(cb_args_t),
+        .sett_ptr = test_set,
+        .sett_size =sizeof(test_set),
+        .extra_buf_num =1,
+        .extra_buf_sizes = &cb_context[1].buf_size,
+        .extra_bufs = &cb_context[1].ref_buf,
+    };
+    
+    if(csi_camera_set_dsp_algo_param(cam_handle, cb_context[1].dsp_id,cb_context[1].dsp_path, &algo_param_2))
+    {
+        LOG_E("set DSP algo fail\n");
+        
+    }
+
+    csi_camera_floodlight_led_set_flash_bright(cam_handle, 500); //500ma
+    csi_camera_projection_led_set_flash_bright(cam_handle, 500); //500ma
+    csi_camera_projection_led_set_mode(cam_handle, LED_IR_ENABLE);
+    csi_camera_floodlight_led_set_mode(cam_handle, LED_IR_ENABLE);
+    csi_camera_led_enable(cam_handle, LED_FLOODLIGHT_PROJECTION);
+
+    // 开始从channel中取出准备好的frame
+	csi_camera_channel_start(cam_handle, CSI_CAMERA_CHANNEL_0);
+	csi_camera_channel_start(cam_handle, CSI_CAMERA_CHANNEL_1);
+	LOG_O("Channel start OK\n");
+
+	// 处理订阅的Event
+	csi_frame_s frame;
+	event_queue_item_t *event_item;
+
+	LOG_O("Starting get frame...\n");
+	while (running) {
+		int timeout = -1; // unit: ms, -1 means wait forever, or until error occurs
+        event_item = malloc(sizeof( event_queue_item_t));   
+		csi_camera_get_event(event_handle, &event_item->evet, timeout);
+       LOG_O("event.type = %d, event.id = %d\n",event_item->evet.type, event_item->evet.id);
+
+		switch (event_item->evet.type) {
+		case CSI_CAMERA_EVENT_TYPE_CAMERA:
+			switch (event_item->evet.id) {
+			case CSI_CAMERA_EVENT_ERROR:
+				// do sth.
+				break;
+			default:
+				break;
+            free(event_item);
+            break;
+			}
+
+		case CSI_CAMERA_EVENT_TYPE_CHANNEL0:
+		case CSI_CAMERA_EVENT_TYPE_CHANNEL1:
+			switch (event_item->evet.id) {
+			case CSI_CAMERA_CHANNEL_EVENT_FRAME_READY: {
+                csi_camera_channel_id_e ch_id = event_item->evet.type-CSI_CAMERA_EVENT_TYPE_CHANNEL0+CSI_CAMERA_CHANNEL_0;
+				 
+                 if(event_item && ch_id<2)
+                 {
+                     enqueue_event(&channel_ctx[ch_id],event_item);
+                 }
+				break;
+			}
+			default:
+                free(event_item);
+				break;
+			}
+            break;
+		default:
+            free(event_item);
+			break;
+		}
+
+    //    LOG_O("stop:%d,frame:(%d,%d)(%llx,%llx)\n",frame_num ,channel_ctx[0].frame_num ,channel_ctx[1].frame_num,&(channel_ctx[0].frame_num),&(channel_ctx[1].frame_num));
+
+        if((frame_num >0) &&
+            (channel_ctx[0].frame_num >frame_num) &&
+            (channel_ctx[1].frame_num >frame_num))
+        {
+                csi_camera_channel_stop(cam_handle, CSI_CAMERA_CHANNEL_0);
+                csi_camera_channel_stop(cam_handle, CSI_CAMERA_CHANNEL_1);
+                channel_ctx[0].event_queue.exit = 1;
+                channel_ctx[1].event_queue.exit = 1;
+                pthread_join(channel_ctx[0].chan_thread,NULL);
+                pthread_join(channel_ctx[1].chan_thread,NULL);
+                running = false;
+        }
+	}
+
+	// 取消订阅某一个event, 也可以直接调用csi_camera_destory_event,结束所有的订阅
+	subscribe.type = CSI_CAMERA_EVENT_TYPE_CHANNEL0;
+	subscribe.id = CSI_CAMERA_CHANNEL_EVENT_FRAME_READY |
+		       CSI_CAMERA_CHANNEL_EVENT_OVERFLOW;;
+	csi_camera_unsubscribe_event(event_handle, &subscribe);
+
+	subscribe.type = CSI_CAMERA_EVENT_TYPE_CHANNEL1;
+	subscribe.id = CSI_CAMERA_CHANNEL_EVENT_FRAME_READY |
+		       CSI_CAMERA_CHANNEL_EVENT_OVERFLOW;;
+	csi_camera_unsubscribe_event(event_handle, &subscribe);
+
+	subscribe.type = CSI_CAMERA_EVENT_TYPE_CAMERA;
+	subscribe.id = CSI_CAMERA_EVENT_WARNING | CSI_CAMERA_EVENT_ERROR;
+	csi_camera_unsubscribe_event(event_handle, &subscribe);
+
+	csi_camera_destory_event(event_handle);
+
+	csi_camera_channel_close(cam_handle, CSI_CAMERA_CHANNEL_0);
+	csi_camera_close(cam_handle);
+}
+
+static void dump_camera_meta(csi_frame_s *frame)
+{
+	int i;
+	if (frame->meta.type != CSI_META_TYPE_CAMERA)
+		return;
+
+	csi_camera_meta_s *meta_data = (csi_camera_meta_s *)frame->meta.data;
+	csi_camrea_meta_unit_s meta_frame_id,meta_frame_ts;
+
+
+	csi_camera_frame_get_meta_unit(
+		&meta_frame_id, meta_data, CSI_CAMERA_META_ID_FRAME_ID);
+    csi_camera_frame_get_meta_unit(
+		&meta_frame_ts, meta_data, CSI_CAMERA_META_ID_TIMESTAMP);
+	LOG_O("meta frame id=%d,time stap:(%ld,%ld)\n",
+			 meta_frame_id.int_value,meta_frame_ts.time_value.tv_sec,meta_frame_ts.time_value.tv_usec);
+}
+
+static void dump_camera_frame(csi_frame_s *frame,  int ch_id)
+{
+	char file[128];
+	static int file_indx=0;
+	int size,buf_size;
+	uint32_t indexd, j;
+    void *buf[3];
+
+	sprintf(file,"demo_save_img_ch_%d_%d", ch_id,file_indx++%6);
+	int fd = open(file, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IROTH);
+	if(fd == -1) {
+		LOG_E("%s, %d, open file error!!!!!!!!!!!!!!!\n", __func__, __LINE__);
+		return ;
+	}
+    if (frame->img.type == CSI_IMG_TYPE_DMA_BUF) {
+
+        buf_size = frame->img.strides[0]*frame->img.height;
+        switch(frame->img.pix_format) {
+                case CSI_PIX_FMT_NV12:
+		        case CSI_PIX_FMT_YUV_SEMIPLANAR_420:
+                        if(frame->img.num_planes ==2)
+                        { 
+                            buf_size+=frame->img.strides[1]*frame->img.height/2;
+                        }
+                        else{
+                            LOG_E("img fomrat is not match with frame planes:%d\n",frame->img.num_planes);
+                            return;
+                        }
+                        break;
+                case CSI_PIX_FMT_YUV_SEMIPLANAR_422:
+                        if(frame->img.num_planes ==2)
+                        { 
+                            buf_size+=frame->img.strides[1]*frame->img.height;
+                        }
+                        else{
+                            LOG_E("img fomrat is not match with frame planes:%d\n",frame->img.num_planes);
+                            return;
+                        }
+                        break;
+                default:
+                        break;
+                
+        }
+
+        buf[0]= mmap(0, buf_size, PROT_READ | PROT_WRITE,
+                    MAP_SHARED, frame->img.dmabuf[0].fds, frame->img.dmabuf[0].offset);
+        // plane_size[1] = frame->img.strides[1]*frame->img.height;
+        // printf("frame plane 1 stride:%d,offset:%d\n", frame->img.strides[1],(uint32_t)frame->img.dmabuf[1].offset);
+        if(frame->img.num_planes ==2)
+        {
+            // buf[1] = mmap(0, plane_size[1]/2, PROT_READ | PROT_WRITE,
+            //             MAP_SHARED, frame->img.dmabuf[1].fds, frame->img.dmabuf[1].offset);
+            buf[1] = buf[0]+frame->img.dmabuf[1].offset;
+        }
+
+    }
+    else{
+            buf[0] = frame->img.usr_addr[0];
+            buf[1] = frame->img.usr_addr[1];
+    }
+
+	LOG_O("save img from :%d, to %s, fmt:%d width:%d stride:%d height:%d\n",frame->img.dmabuf[0].fds, file, frame->img.pix_format , frame->img.width, frame->img.strides[0], frame->img.height);
+    frame->img.pix_format = CSI_PIX_FMT_RAW_12BIT;
+	switch(frame->img.pix_format) {
+		case CSI_PIX_FMT_NV12:
+		case CSI_PIX_FMT_YUV_SEMIPLANAR_420:
+            if (frame->img.strides[0] == 0) {
+				frame->img.strides[0] = frame->img.width;
+			}
+			for (j = 0; j < frame->img.height; j++) { //Y
+				indexd = j*frame->img.strides[0];
+				write(fd, buf[0] + indexd, frame->img.width);
+			}
+			for (j = 0; j < frame->img.height / 2; j++) { //UV
+				indexd = j*frame->img.strides[0];
+				write(fd, buf[1] + indexd, frame->img.width);
+			}
+			break;
+		case CSI_PIX_FMT_RGB_INTEVLEAVED_888:
+		case CSI_PIX_FMT_YUV_TEVLEAVED_444:
+            size = frame->img.width*3;
+            for (j = 0; j < frame->img.height; j++) {
+				indexd = j*frame->img.strides[0];
+				write(fd, buf[0] + indexd, size);
+			}
+			break;
+		case CSI_PIX_FMT_BGR:
+		case CSI_PIX_FMT_RGB_PLANAR_888:
+		case CSI_PIX_FMT_YUV_PLANAR_444:
+			size = frame->img.width * frame->img.height * 3;
+			write(fd, buf[0], size);
+			break;
+        case CSI_PIX_FMT_RAW_8BIT:
+            size = frame->img.width;
+            for (j = 0; j < frame->img.height; j++) {
+				indexd = j*frame->img.strides[0];
+				write(fd, buf[0] + indexd, size);
+			}
+			break;
+		case CSI_PIX_FMT_YUV_TEVLEAVED_422:
+        case CSI_PIX_FMT_RAW_10BIT:
+	    case CSI_PIX_FMT_RAW_12BIT:
+	    case CSI_PIX_FMT_RAW_14BIT:
+	    case CSI_PIX_FMT_RAW_16BIT:
+            size = frame->img.width*2;
+            for (j = 0; j < frame->img.height; j++) {
+				indexd = j*frame->img.strides[0];
+				write(fd, buf[0] + indexd, size);
+			}
+			break;
+		case CSI_PIX_FMT_YUV_SEMIPLANAR_422:
+			if (frame->img.strides[0] == 0) {
+				frame->img.strides[0] = frame->img.width;
+			}
+			for (j = 0; j < frame->img.height; j++) { //Y
+				indexd = j*frame->img.strides[0];
+				write(fd,buf[0] + indexd, frame->img.width);
+			}
+			for (j = 0; j < frame->img.height; j++) { //UV
+				indexd = j*frame->img.strides[0];
+				write(fd, buf[1]+ indexd, frame->img.width);
+			}
+			break;
+		default:
+			LOG_E("%s unsupported format to save\n", __func__);
+			exit(-1);
+			break;
+	}
+
+	close(fd);
+    munmap(buf[0],buf_size);
+    // munmap(buf[1],plane_size[1]);
+	LOG_O("%s exit\n", __func__);
+}

+ 807 - 0
examples/camera/cam_demo_multi.c

@@ -0,0 +1,807 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: ShenWuYi <shenwuyi.swy@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#define LOG_LEVEL 2
+#define LOG_PREFIX "cam_demo_multi"
+#include <syslog.h>
+
+#include <csi_frame.h>
+#include <csi_camera.h>
+#include <csi_camera_dev_api.h>
+#ifdef PLATFORM_SIMULATOR
+#include "apputilities.h"
+#endif
+#define  MAX_CAM_NUM    3
+#define  MAX_CHANNEL_NUM 3 
+static void dump_camera_meta(csi_frame_s *frame);
+static void dump_camera_frame(csi_frame_s *frame, csi_pixel_fmt_e fmt, int camera_id);
+
+// extern int csi_camera_frame_unlock(csi_cam_handle_t cam_handle, csi_frame_s *frame);
+
+#define TEST_DEVICE_NAME "/dev/video0"
+#define CSI_CAMERA_TRUE  1
+#define CSI_CAMERA_FALSE 0
+
+typedef struct frame_fps {
+	uint64_t frameNumber;
+	struct timeval initTick;
+	float fps;
+} frame_fps_t;
+typedef enum _frame_mode{
+    FRAME_NONE =0,
+    FRAME_SAVE_IMG =1,
+    FRAME_SAVE_STREAM =2,
+    FRAME_SAVE_DISPLAY,
+    FRAME_INVALID,
+}frame_mode_t;
+
+typedef enum _cam_type{
+    CAM_TYEP_RGB =0,
+    CAM_TYEP_IR,
+    CAM_TYEP_INVALID,
+
+}cam_type_e;
+
+
+typedef struct _camera_param{
+    int video_id;
+    int channel_num;
+    struct {
+        int width;
+        int height;
+        csi_pixel_fmt_e fmt;
+
+    }out_pic[MAX_CHANNEL_NUM];
+
+    cam_type_e  type;
+    frame_mode_t  mode;
+    int frames_to_stop;
+}camera_param_t;
+
+typedef struct event_queue_item{
+    struct csi_camera_event evet;
+    struct event_queue_item *next;
+}event_queue_item_t;
+
+typedef struct _camera_ctx{
+
+    int cam_id;
+    pthread_t  cam_thread;
+    int exit;
+    csi_cam_handle_t cam_handle;
+    int  channel_num;
+    csi_cam_event_handle_t event_handle;
+    csi_camera_event_subscription_s event_subscribe;
+ 	csi_camera_channel_cfg_s chn_cfg[MAX_CHANNEL_NUM];
+    void * disaply_plink[MAX_CHANNEL_NUM];
+    int frame_num;
+    frame_mode_t  frame_mode[MAX_CHANNEL_NUM];
+}camera_ctx_t;
+
+int file_id = 0;
+extern void *vi_plink_create(csi_camera_channel_cfg_s *chn_cfg);
+extern void vi_plink_release(void * plink);
+extern void display_camera_frame(void * plink, csi_frame_s *frame);
+
+static void usage(void)
+{
+	printf("    1 : RGB Camera id \n");
+	printf("    2 : RGB Camera id channel num\n");
+	printf("    3 : RGB Camera frame mode :0 none ,1 dump enable,2 display \n");
+    printf("    4 : RGB Camera frame num :0 not stop ,else frame num to stop \n");
+	printf("    5 : IR Camera id \n");
+	printf("    6 : IR Camera id channel num\n");
+	printf("    7 : IR Camera frame mode :0 none ,1 dump enable,2 display \n");
+    printf("    8 : IR Camera frame num :0 not stop ,else frame num to stop \n");
+}
+
+void printUsage(char *name)
+{
+    printf("usage: %s [options]\n"
+           "\n"
+           "  Available options:\n"
+           "    -f      fisrt camera device 5 param \n"
+           "            1:video id 2: channel num  3: camrea type (0->rgb ;1->IR)  (mandatory)\n"
+           "            3: mode【0->none ,1->save image,2->display 】(default 1) \n"
+           "            4: frame num to stop 【0 not stop】(default 0) \n"
+           "    -s      second camera device 5 param)\n"
+           "            same param setting as above)\n"
+           "    -t      third camera device 5 param)\n"
+           "           same param setting  above)\n"
+
+           "\n", name);
+}
+
+static int  parseParams(int argc, char **argv, camera_param_t *params)
+{
+        int index =0;
+        params[index].video_id = 2;
+        params[index].type = CAM_TYEP_RGB;
+
+        params[index].channel_num =1;
+        params[index].out_pic[0].width = 1920;
+        params[index].out_pic[0].height = 1080;
+        params[index].out_pic[0].fmt = CSI_PIX_FMT_NV12;
+        params[index].mode = FRAME_SAVE_IMG;
+        params[index].frames_to_stop = 0;
+        index++;
+
+        params[index].video_id = 6;
+        params[index].type = CAM_TYEP_IR;
+
+        params[index].channel_num = 2;
+        params[index].out_pic[0].width = 1080;
+        params[index].out_pic[0].height = 1280;
+        params[index].out_pic[0].fmt =CSI_PIX_FMT_RAW_12BIT;
+        params[index].out_pic[1].width = 1080;
+        params[index].out_pic[1].height = 1280;
+        params[index].out_pic[1].fmt =CSI_PIX_FMT_RAW_12BIT;
+
+        params[index].mode = FRAME_SAVE_IMG;
+        params[index].frames_to_stop = 0;
+        index++;
+        return index;   
+}
+
+static void get_system_time(const char *func, int line_num)
+{
+	struct timeval cur_time;
+
+	memset(&cur_time, 0, sizeof(cur_time));
+	gettimeofday(&cur_time, 0);
+	printf("%s %s line_num = %d, cur_time.tv_sec = %ld, cur_time.tv_usec = %ld\n",
+		__func__, func, line_num, cur_time.tv_sec, cur_time.tv_usec);
+}
+
+
+static int camera_get_chl_id(int env_type, int *chl_id)
+{
+	if (chl_id == NULL) {
+		LOG_E("fail to check param chl_id = %p\n", chl_id);
+		return -1;
+	}
+	switch (env_type) {
+		case CSI_CAMERA_EVENT_TYPE_CHANNEL0:
+			*chl_id = CSI_CAMERA_CHANNEL_0;
+			break;
+		case CSI_CAMERA_EVENT_TYPE_CHANNEL1:
+			*chl_id = CSI_CAMERA_CHANNEL_1;
+			break;
+		case CSI_CAMERA_EVENT_TYPE_CHANNEL2:
+			*chl_id = CSI_CAMERA_CHANNEL_2;
+			break;
+		default:
+			LOG_D("%s fail to check env_type = %d unsupport\n", env_type);
+			break;
+	}
+	return 0;
+}
+
+/***********************DSP ALGO *******************************/
+
+typedef struct cb_context{
+    int id;
+    csi_cam_handle_t cam_handle;
+    int dsp_id;
+    int dsp_path;
+    void *ref_buf;
+    int buf_size;
+}cb_context_t;
+
+typedef struct cb_args{
+    char lib_name[8];
+    char setting[16];
+    uint32_t frame_id;
+    uint64_t timestap;
+    uint32_t  temp_projector;   //投射器温度
+	uint32_t  temp_sensor;     //sensor 温度
+}cb_args_t;
+cb_context_t cb_context[2];
+void dsp_algo_result_cb(void*context,void*arg)
+{
+   cb_context_t *ctx = (cb_context_t *)context;
+    cb_args_t *cb_args= (cb_args_t*)arg;    
+    char update_setting[16];
+    struct timeval times_value;
+    uint32_t frame_id = cb_args->frame_id;
+    uint64_t frame_timestap =  cb_args->timestap;
+    times_value.tv_sec = cb_args->timestap/1000000;
+    times_value.tv_usec = cb_args->timestap%1000000;
+
+    LOG_O("cb:%d,%s,setting:%s,frame :%d,timestad:(%ld s,%ld us)\n",ctx->id,cb_args->lib_name,cb_args->setting,
+                                                            frame_id,times_value.tv_sec,times_value.tv_usec);
+    LOG_O("temperate projector:%d,sensor:%d\n",cb_args->temp_projector,cb_args->temp_sensor);
+
+    // if(test_flag!=0)
+    {
+        sprintf(update_setting, "update_%d", frame_id);
+        csi_camera_update_dsp_algo_setting(ctx->cam_handle,ctx->dsp_id,ctx->dsp_path,update_setting);
+        if(frame_id%20==0)
+        {
+            void *replace_buf;
+            *((uint32_t*)ctx->ref_buf) = frame_id;
+            csi_camera_update_dsp_algo_buf(ctx->cam_handle, ctx->dsp_id,ctx->dsp_path,ctx->ref_buf,&replace_buf);
+            LOG_D("cb:%d,old buffer:0x%llx,new buffer:0x%llx\n",ctx->id,ctx->ref_buf,replace_buf);
+            ctx->ref_buf = replace_buf;
+        }
+    }
+}
+static void *camera_event_thread(void *arg)
+{
+	int ret = 0;
+	if (arg == NULL) {
+		LOG_E("NULL Ptr\n");
+        pthread_exit(0);
+	}
+	camera_ctx_t* ctx = (camera_ctx_t*)arg;
+	csi_cam_event_handle_t ev_handle = ctx->event_handle;
+    csi_camera_channel_cfg_s  *ch_cfg=NULL;
+	struct timeval init_time, cur_time;
+	memset(&init_time, 0, sizeof(init_time));
+	memset(&cur_time, 0, sizeof(cur_time));
+
+	frame_fps_t demo_fps;
+	memset(&demo_fps, 0, sizeof(demo_fps));
+	csi_frame_s frame;
+
+	if (ev_handle == NULL) {
+		LOG_E("fail to get ev_handle ev_handle\n");
+		pthread_exit(0);
+	}
+	int timeout = -1; // unit: ms, -1 means wait forever, or until error occurs
+	int loop_count = 0;
+	struct csi_camera_event event;
+    LOG_O("Theard is runing............\n");
+	while (ctx->exit==0) {
+		int timeout = -1; // unit: ms, -1 means wait forever, or until error occurs
+		csi_camera_get_event(ev_handle, &event, timeout);
+		LOG_D("Camera_%d event.type = %d, event.id = %d\n",ctx->cam_id ,event.type, event.id);
+		switch (event.type) {
+		case CSI_CAMERA_EVENT_TYPE_CAMERA:
+			switch (event.id) {
+			case CSI_CAMERA_EVENT_ERROR:
+				// do sth.
+				    LOG_E("get CAMERA EVENT CSI_CAMERA_EVENT_ERROR!\n");
+				    break;
+            case CSI_CAMERA_EVENT_WARNING:
+            		LOG_W("get CAMERA EVENT CSI_CAMERA_EVENT_WRN,RC: %s\n",event.bin);
+				    break;
+			default:
+				break;
+			}
+			break;
+		case CSI_CAMERA_EVENT_TYPE_CHANNEL0:
+		case CSI_CAMERA_EVENT_TYPE_CHANNEL1:
+		case CSI_CAMERA_EVENT_TYPE_CHANNEL2:
+		case CSI_CAMERA_EVENT_TYPE_CHANNEL3:
+			switch (event.id) {
+			case CSI_CAMERA_CHANNEL_EVENT_FRAME_READY: {
+				int chn_id = 0;
+				ret = camera_get_chl_id(event.type, &chn_id);
+				if (ret) {
+					LOG_E("fail to get chl_id = %d\n", chn_id);
+					continue;
+				}
+                ch_cfg = &ctx->chn_cfg[chn_id];
+				get_system_time(__func__, __LINE__);
+				int read_frame_count = csi_camera_get_frame_count(ctx->cam_handle,
+						       chn_id);
+
+				unsigned  long diff;
+				if (init_time.tv_usec == 0)
+					gettimeofday(&init_time,0);//osGetTick();
+				gettimeofday(&cur_time, 0);
+				diff = 1000000 * (cur_time.tv_sec-init_time.tv_sec)+ cur_time.tv_usec-init_time.tv_usec;
+				demo_fps.frameNumber++;
+				if (diff != 0)
+					demo_fps.fps = (float)demo_fps.frameNumber / diff * 1000000.0f;
+				LOG_O("cam:%d,channle:%d ,read_frame_count = %d, frame_count = %ld, fps = %.2f diff = %ld\n", ctx->cam_id, chn_id, read_frame_count, demo_fps.frameNumber, demo_fps.fps, diff);
+
+				for (int i = 0; i < read_frame_count; i++) {
+					csi_camera_get_frame(ctx->cam_handle, chn_id, &frame, timeout);
+					dump_camera_meta(&frame);
+					if (ctx->frame_mode[chn_id] == FRAME_SAVE_IMG) {
+						dump_camera_frame(&frame, ch_cfg->img_fmt.pix_fmt, chn_id);
+					}
+					if (ctx->disaply_plink && ctx->frame_mode[chn_id]==FRAME_SAVE_DISPLAY) {
+						frame.img.pix_format = ch_cfg->img_fmt.pix_fmt;
+						display_camera_frame(ctx->disaply_plink, &frame);
+                    }
+                    csi_camera_put_frame(&frame);
+                    ctx->frame_num++;
+				}
+				break;
+			}
+			default:
+				break;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+	LOG_O("exit!\n");
+	pthread_exit(0);
+}
+
+
+static void camera_start_all(camera_ctx_t *  ctx)
+{
+    camera_ctx_t * cam_ctx = ctx;
+    int loop_ch;
+    for(loop_ch=0;loop_ch<cam_ctx->channel_num;loop_ch++)
+    {
+	    csi_camera_channel_start(cam_ctx->cam_handle, cam_ctx->chn_cfg[loop_ch].chn_id);
+    }
+}
+
+static void camera_stop_all(camera_ctx_t *  ctx)
+{
+    camera_ctx_t * cam_ctx = ctx;
+    int loop_ch;
+    for(loop_ch=0;loop_ch<cam_ctx->channel_num;loop_ch++)
+    {
+	    csi_camera_channel_stop(cam_ctx->cam_handle, cam_ctx->chn_cfg[loop_ch].chn_id);
+    }
+}
+static camera_ctx_t * camera_open(camera_param_t *params)
+{
+	int ret = 0;
+	char dev_name[128];
+    camera_ctx_t * cam_ctx = NULL;
+    int loop_ch;
+	LOG_O("Open Camera %d\n",params->video_id);
+    if(params==NULL || params->video_id <0)
+    {
+        LOG_E("param err\n");
+        return NULL;
+    }
+    if(params->channel_num> MAX_CHANNEL_NUM)
+    {
+        LOG_E("unsupoort channle num:%d \n",params->channel_num);
+        return NULL;
+    }
+
+    if(params->mode >=FRAME_INVALID)
+    {
+        LOG_E("unsupoort frame process mode:%d \n",params->mode);
+        return NULL;
+    }
+
+    cam_ctx = malloc(sizeof(camera_ctx_t));
+    if(!cam_ctx)
+    {
+        return NULL;
+    }
+    memset(cam_ctx,0x0,sizeof(camera_ctx_t));
+
+  
+	// 打开Camera设备获取句柄,作为后续操对象
+    sprintf(dev_name, "/dev/video%d", params->video_id);
+	if(csi_camera_open(&cam_ctx->cam_handle, dev_name))
+    {
+        LOG_E("Fail to open cam :%s\n",dev_name);
+        goto ONE_ERR; 
+    }
+
+    for(loop_ch= CSI_CAMERA_CHANNEL_0;loop_ch<params->channel_num;loop_ch++)
+    {
+        cam_ctx->chn_cfg[loop_ch].chn_id = loop_ch;
+        cam_ctx->chn_cfg[loop_ch].img_fmt.pix_fmt = params->out_pic[loop_ch].fmt;
+        cam_ctx->chn_cfg[loop_ch].img_fmt.width= params->out_pic[loop_ch].width;
+        cam_ctx->chn_cfg[loop_ch].img_fmt.height = params->out_pic[loop_ch].height;
+        cam_ctx->chn_cfg[loop_ch].img_type = CSI_IMG_TYPE_DMA_BUF;
+        cam_ctx->chn_cfg[loop_ch].meta_fields = CSI_CAMERA_META_DEFAULT_FIELDS;
+        if(csi_camera_channel_open(cam_ctx->cam_handle,&cam_ctx->chn_cfg[loop_ch]))
+        {
+            LOG_E("Fail to open cam %s,channel :%d\n",dev_name,loop_ch);
+            goto TWO_ERR; 
+        }
+
+        if(params->mode == FRAME_SAVE_DISPLAY)
+        {
+            cam_ctx->disaply_plink[loop_ch] = vi_plink_create(&cam_ctx->chn_cfg[loop_ch]);
+            if(!cam_ctx->disaply_plink[loop_ch]&& loop_ch== CSI_CAMERA_CHANNEL_0)  //temp only channel to display
+            {
+                LOG_E("Fail to create plink for cam %s,channel :%d\n",dev_name,loop_ch);
+                goto TWO_ERR; 
+            }
+        }
+        cam_ctx->frame_mode[loop_ch]=params->mode;
+        cam_ctx->channel_num++;
+    }
+
+    if(csi_camera_create_event(&cam_ctx->event_handle,cam_ctx->cam_handle))
+    {
+            LOG_E("Fail to create event handler for cam %s\n",dev_name);
+            goto TWO_ERR; 
+    }
+
+    cam_ctx->event_subscribe.type = CSI_CAMERA_EVENT_TYPE_CAMERA;
+    cam_ctx->event_subscribe.id =  CSI_CAMERA_EVENT_WARNING | CSI_CAMERA_EVENT_ERROR;
+    if(csi_camera_subscribe_event(cam_ctx->event_handle,&cam_ctx->event_subscribe))
+    {
+        LOG_E("Fail to subscribe eventfor cam %s\n",dev_name);
+        goto TWO_ERR; 
+    }
+
+
+    for(loop_ch=0;loop_ch<cam_ctx->channel_num;loop_ch++)
+    {
+        cam_ctx->event_subscribe.type = CSI_CAMERA_EVENT_TYPE_CHANNEL0+loop_ch;
+        cam_ctx->event_subscribe.id =  CSI_CAMERA_CHANNEL_EVENT_FRAME_READY;
+        if(csi_camera_subscribe_event(cam_ctx->event_handle,&cam_ctx->event_subscribe))
+        {
+            LOG_E("Fail to subscribe eventfor cam %s\n",dev_name);
+            goto TWO_ERR; 
+        }
+    }
+
+	LOG_O("%s open successfully\n",dev_name);
+	ret = pthread_create(&cam_ctx->cam_thread, NULL,
+			     (void *)camera_event_thread, cam_ctx);
+	if (ret != 0) {
+		LOG_E("pthread_create() failed, ret=%d", ret);
+		goto TWO_ERR;
+	}
+
+    if(params->type == CAM_TYEP_IR)
+    {
+            cb_context[0].id=0;
+            cb_context[0].cam_handle = cam_ctx->cam_handle;
+            cb_context[0].dsp_id = 1;
+            cb_context[0].dsp_path = 3;    
+            char test_set[16]="init";
+            cb_context[0].buf_size = 1920*1080;
+            cb_context[0].ref_buf=NULL;
+            csi_camera_dsp_algo_param_t algo_param_1={
+                .algo_name = "dsp1_dummy_algo_flo_1",
+                .algo_cb.cb = dsp_algo_result_cb,
+                .algo_cb.context = &cb_context[0],
+                .algo_cb.arg_size =  sizeof(cb_args_t),
+                .sett_ptr = test_set,
+                .sett_size =sizeof(test_set),
+                .extra_buf_num =1,
+                .extra_buf_sizes = &cb_context[0].buf_size,
+                .extra_bufs = &cb_context[0].ref_buf,
+            };
+            
+            if(csi_camera_set_dsp_algo_param(cam_ctx->cam_handle, cb_context[0].dsp_id,cb_context[0].dsp_path, &algo_param_1))
+            {
+                LOG_E("set DSP algo fail\n");
+                goto TWO_ERR;
+            }
+
+            cb_context[1].id=1;
+            cb_context[1].cam_handle = cam_ctx->cam_handle;
+            cb_context[1].dsp_id = 1;
+            cb_context[1].dsp_path = 4;    
+            cb_context[1].buf_size = 1920*1080;
+            cb_context[1].ref_buf=NULL;
+            csi_camera_dsp_algo_param_t algo_param_2={
+                .algo_name = "dsp1_dummy_algo_flo",
+                .algo_cb.cb = dsp_algo_result_cb,
+                .algo_cb.context = &cb_context[1],
+                .algo_cb.arg_size = sizeof(cb_args_t),
+                .sett_ptr = test_set,
+                .sett_size =sizeof(test_set),
+                .extra_buf_num =1,
+                .extra_buf_sizes = &cb_context[1].buf_size,
+                .extra_bufs = &cb_context[1].ref_buf,
+            };
+            
+            if(csi_camera_set_dsp_algo_param(cam_ctx->cam_handle, cb_context[1].dsp_id,cb_context[1].dsp_path, &algo_param_2))
+            {
+                LOG_E("set DSP algo fail\n");
+                 goto TWO_ERR;
+            }
+            csi_camera_floodlight_led_set_flash_bright(cam_ctx->cam_handle, 500); //500ma
+            csi_camera_projection_led_set_flash_bright(cam_ctx->cam_handle, 500); //500ma
+            csi_camera_projection_led_set_mode(cam_ctx->cam_handle, LED_IR_ENABLE);
+            csi_camera_floodlight_led_set_mode(cam_ctx->cam_handle, LED_IR_ENABLE);
+            csi_camera_led_enable(cam_ctx->cam_handle, LED_FLOODLIGHT_PROJECTION);
+    }
+
+    // for(loop_ch=0;loop_ch<cam_ctx->channel_num;loop_ch++)
+    // {
+	//     csi_camera_channel_start(cam_ctx->cam_handle, cam_ctx->chn_cfg[loop_ch].chn_id);
+    // }
+
+	get_system_time(__func__, __LINE__);
+
+
+    return cam_ctx;
+
+
+TWO_ERR:
+        for(loop_ch=0;loop_ch<cam_ctx->channel_num;loop_ch++)
+        {
+            csi_camera_channel_close(cam_ctx->cam_handle, cam_ctx->chn_cfg[loop_ch].chn_id);
+        }
+        csi_camera_close(cam_ctx->cam_handle);
+ONE_ERR:
+        free(cam_ctx);
+        return NULL;
+}
+
+static void camera_close(camera_ctx_t *ctx)
+{
+    int loop_ch;
+
+    if(ctx->cam_handle==NULL)
+    {
+        return;
+    }
+
+	if (pthread_join(ctx->cam_thread, NULL)) {
+		LOG_E("pthread_join() failed\n");
+	}
+
+    csi_camera_unsubscribe_event(ctx->event_handle, &ctx->event_subscribe);
+
+	csi_camera_destory_event(ctx->event_handle);
+    // int loop_ch;
+    // for(loop_ch=0;loop_ch<ctx->channel_num;loop_ch++)
+    // {
+    //     csi_camera_channel_stop(cam_ctx->cam_handle, cam_ctx->chn_cfg[loop_ch].chn_id);
+    // }
+
+    for(loop_ch=0;loop_ch<ctx->channel_num;loop_ch++)
+    {
+        csi_camera_channel_close(ctx->cam_handle, ctx->chn_cfg[loop_ch].chn_id);
+    }
+    csi_camera_close(ctx->cam_handle);
+    free(ctx);
+}
+
+
+int main(int argc, char *argv[])
+{
+
+	char dev_name[128];
+	int camera_id = 0;
+	// 打印HAL接口版本号
+	csi_api_version_u version;
+	csi_camera_get_version(&version);
+    camera_param_t params[MAX_CAM_NUM];
+    camera_ctx_t * ctx[MAX_CAM_NUM]={NULL,NULL,NULL};
+    int cam_num=0;
+    bool running = false;
+    cam_num =parseParams(argc,argv,params);
+    if(cam_num <=0 || cam_num>MAX_CAM_NUM)
+    {
+        LOG_E("not camera is active\n");
+        exit(0);
+    }
+    for(int i =0;i<cam_num;i++)
+    {
+        switch(params[i].type)
+        {
+            case CAM_TYEP_RGB:
+                   ctx[i]=camera_open(&params[i]);
+                   break;
+            case CAM_TYEP_IR:
+                   ctx[i]=camera_open(&params[i]);
+                    break;
+            default:
+                 LOG_E("unspuoort camera :%d\n",i);
+                 continue;
+        }
+        if(ctx[i]==NULL)
+        {
+            LOG_E("camera_%d open %d fail\n",i,params[i].type);
+            goto ONR_ERR;
+        }
+        ctx[i]->cam_id = i;
+        ctx[i]->frame_num =0;
+        ctx[i]->exit = 0;
+        camera_start_all(ctx[i]);
+        running = true;
+    }
+    int all_exit;
+    do{
+        sleep(1);
+        all_exit = 1;
+        for(int i =0;i<cam_num;i++)
+        {
+            if(ctx[i]&&
+               ctx[i]->exit==0 && 
+               params[i].frames_to_stop>0 && 
+                ctx[i]->frame_num >=params[i].frames_to_stop)
+            {
+                camera_stop_all(ctx[i]);
+                ctx[i]->exit=1;
+            }
+            if(ctx[i])
+                all_exit &= ctx[i]->exit;
+        }
+        if(all_exit ==1)
+        {
+            LOG_O("all_exit\n");
+            running = false;
+        }
+
+    }while(running);
+    
+ONR_ERR:
+    for(int i =0;i<cam_num;i++)
+    {
+        if(ctx[i])
+            camera_close(ctx[i]);
+    }
+    exit(0);
+}
+
+static void dump_camera_meta(csi_frame_s *frame)
+{
+	int i;
+	//printf("%s\n", __func__);
+	if (frame->meta.type != CSI_META_TYPE_CAMERA)
+		return;
+
+	csi_camera_meta_s *meta_data = (csi_camera_meta_s *)frame->meta.data;
+	int meta_count = meta_data->count;
+	csi_camrea_meta_unit_s meta_unit;
+
+
+	csi_camera_frame_get_meta_unit(
+		&meta_unit, meta_data, CSI_CAMERA_META_ID_FRAME_ID);
+	LOG_I("meta_id=%d, meta_type=%d, meta_value=%d\n",
+			meta_unit.id, meta_unit.type, meta_unit.int_value);
+}
+
+static void dump_camera_frame(csi_frame_s *frame, csi_pixel_fmt_e fmt, int chan_id)
+{
+	char file[128];
+	static int file_indx=0;
+	int size;
+	uint32_t indexd, j;
+    void *buf[3];
+    int buf_size;
+    csi_camera_meta_s *meta_data = (csi_camera_meta_s *)frame->meta.data;
+	csi_camrea_meta_unit_s meta_unit;
+
+
+	csi_camera_frame_get_meta_unit(
+		&meta_unit, meta_data, CSI_CAMERA_META_ID_CAMERA_NAME);
+
+              
+	sprintf(file,"demo_save_img%s_%d_%d",meta_unit.str_value,chan_id, file_indx++%10);
+	int fd = open(file, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IROTH);
+	if(fd == -1) {
+		LOG_E("%s, %d, open file error!!!!!!!!!!!!!!!\n", __func__, __LINE__);
+		return ;
+	}
+    if (frame->img.type == CSI_IMG_TYPE_DMA_BUF) {
+
+        buf_size = frame->img.strides[0]*frame->img.height;
+         switch(fmt) {
+                case CSI_PIX_FMT_NV12:
+		        case CSI_PIX_FMT_YUV_SEMIPLANAR_420:
+                        if(frame->img.num_planes ==2)
+                        { 
+                            buf_size+=frame->img.strides[1]*frame->img.height/2;
+                        }
+                        else{
+                            LOG_O("img fomrat is not match with frame planes:%d\n",frame->img.num_planes);
+                            return;
+                        }
+                        break;
+                case CSI_PIX_FMT_YUV_SEMIPLANAR_422:
+                        if(frame->img.num_planes ==2)
+                        { 
+                            buf_size+=frame->img.strides[1]*frame->img.height;
+                        }
+                        else{
+                            LOG_O("img fomrat is not match with frame planes:%d\n",frame->img.num_planes);
+                            return;
+                        }
+                        break;
+                default:
+                        break;
+                
+        }
+
+        buf[0]= mmap(0, buf_size, PROT_READ | PROT_WRITE,
+                    MAP_SHARED, frame->img.dmabuf[0].fds, frame->img.dmabuf[0].offset);
+        // plane_size[1] = frame->img.strides[1]*frame->img.height;
+        // printf("frame plane 1 stride:%d,offset:%d\n", frame->img.strides[1],(uint32_t)frame->img.dmabuf[1].offset);
+        if(frame->img.num_planes ==2)
+        {
+            // buf[1] = mmap(0, plane_size[1]/2, PROT_READ | PROT_WRITE,
+            //             MAP_SHARED, frame->img.dmabuf[1].fds, frame->img.dmabuf[1].offset);
+            buf[1] = buf[0]+frame->img.dmabuf[1].offset;
+        }
+
+    }
+    else{
+            buf[0] = frame->img.usr_addr[0];
+            buf[1] = frame->img.usr_addr[1];
+    }
+
+	LOG_O("%s,save img from : (%lx,%lx)size:%d to %s, fmt:%d width:%d stride:%d height:%d\n",__FUNCTION__, (uint64_t)buf[0],(uint64_t)buf[1],size, file, fmt, frame->img.width, frame->img.strides[0], frame->img.height);
+
+	if (frame->img.strides[0] == 0) {
+		frame->img.strides[0] = frame->img.width;
+	}
+	switch(fmt) {
+		case CSI_PIX_FMT_NV12:
+		case CSI_PIX_FMT_YUV_SEMIPLANAR_420:
+			for (j = 0; j < frame->img.height; j++) { //Y
+				indexd = j*frame->img.strides[0];
+				write(fd, buf[0] + indexd, frame->img.width);
+			}
+			for (j = 0; j < frame->img.height / 2; j++) { //UV
+				indexd = j*frame->img.strides[0];
+				write(fd, buf[1] + indexd, frame->img.width);
+			}
+			break;
+		case CSI_PIX_FMT_RGB_INTEVLEAVED_888:
+		case CSI_PIX_FMT_YUV_TEVLEAVED_444:
+            size = frame->img.width*3;
+            for (j = 0; j < frame->img.height; j++) {
+				indexd = j*frame->img.strides[0];
+				write(fd, buf[0] + indexd, size);
+			}
+			break;
+		case CSI_PIX_FMT_BGR:
+		case CSI_PIX_FMT_RGB_PLANAR_888:
+		case CSI_PIX_FMT_YUV_PLANAR_444:
+			size = frame->img.width * frame->img.height * 3;
+			write(fd, buf[0], size);
+			break;
+        case CSI_PIX_FMT_RAW_8BIT:
+            size = frame->img.width;
+            for (j = 0; j < frame->img.height; j++) {
+				indexd = j*frame->img.strides[0];
+				write(fd, buf[0] + indexd, size);
+			}
+			break;
+		case CSI_PIX_FMT_YUV_TEVLEAVED_422:
+        case CSI_PIX_FMT_RAW_10BIT:
+	    case CSI_PIX_FMT_RAW_12BIT:
+	    case CSI_PIX_FMT_RAW_14BIT:
+	    case CSI_PIX_FMT_RAW_16BIT:
+            size = frame->img.width*2;
+            for (j = 0; j < frame->img.height; j++) {
+				indexd = j*frame->img.strides[0];
+				write(fd, buf[0] + indexd, size);
+			}
+			break;
+		case CSI_PIX_FMT_YUV_SEMIPLANAR_422:
+			if (frame->img.strides[0] == 0) {
+				frame->img.strides[0] = frame->img.width;
+			}
+			for (j = 0; j < frame->img.height; j++) { //Y
+				indexd = j*frame->img.strides[0];
+				write(fd,buf[0] + indexd, frame->img.width);
+			}
+			for (j = 0; j < frame->img.height; j++) { //UV
+				indexd = j*frame->img.strides[0];
+				write(fd, buf[1]+ indexd, frame->img.width);
+			}
+			break;
+		default:
+			LOG_E("%s unsupported format to save\n", __func__);
+			exit(-1);
+			break;
+	}
+
+	close(fd);
+    munmap(buf[0],buf_size);
+    // munmap(buf[1],plane_size[1]);
+	LOG_O("%s exit\n", __func__);
+}

+ 710 - 0
examples/camera/cam_demo_simple.c

@@ -0,0 +1,710 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#define LOG_LEVEL 2
+#define LOG_PREFIX "cam_demo_simple"
+#include <syslog.h>
+
+#include <csi_frame.h>
+#include <csi_camera.h>
+#include "csi_camera_dev_api.h"
+// #include "vi_mem.h"
+#ifdef PLATFORM_SIMULATOR
+#include "apputilities.h"
+#endif
+
+static void dump_camera_meta(csi_frame_s *frame);
+static void dump_camera_frame(csi_frame_s *frame, csi_pixel_fmt_e fmt);
+
+
+#define TEST_DEVICE_NAME "/dev/video0"
+#define CSI_CAMERA_TRUE  1
+#define CSI_CAMERA_FALSE 0
+
+typedef struct frame_fps {
+	uint64_t frameNumber;
+	struct timeval initTick;
+	float fps;
+} frame_fps_t;
+
+typedef struct cb_context{
+    int id;
+    csi_cam_handle_t cam_handle;
+    int dsp_id;
+    int dsp_path;
+    void *ref_buf;
+    int buf_size;
+}cb_context_t;
+
+typedef struct cb_args{
+    char setting[16];
+    uint32_t frame_id;
+    uint32_t timestap;
+}cb_args_t;
+cb_context_t cb_context[2];
+
+void dsp_algo_result_cb(void*context,void*arg)
+{
+    cb_context_t *ctx = (cb_context_t *)context;
+    cb_args_t *cb_args= (cb_args_t*)arg;
+    char update_setting[16];
+    uint32_t frame_id = cb_args->frame_id;
+    uint32_t frame_timestap =  cb_args->timestap;
+    LOG_O("cb:%d,setting:%s,frame :%d,timestad:0x%x\n",ctx->id,cb_args->setting,frame_id,frame_timestap);
+    sprintf(update_setting, "update_%d", frame_id);
+    csi_camera_update_dsp_algo_setting(ctx->cam_handle,ctx->dsp_id,ctx->dsp_path,update_setting);
+    if(frame_id%20)
+    {
+        void *replace_buf;
+        csi_camera_update_dsp_algo_buf(ctx->cam_handle, ctx->dsp_id,ctx->dsp_path,ctx->ref_buf,&replace_buf);
+        LOG_O("cb:%d,old buffer:0x%lx,new buffer:0x%lx\n",ctx->id,(uint64_t)ctx->ref_buf,(uint64_t)replace_buf);
+        ctx->ref_buf = replace_buf;
+    }
+}
+
+
+static void usage(void)
+{
+	printf("    1 : video id  cases\n");
+	printf("    2 : channel cases\n");
+	printf("    3 : dump enable\n");
+	printf("    4 : display enable\n");
+	printf("    5 : width\n");
+	printf("    6 : heithg\n");
+	printf("    7 : fmt\n");
+	printf("    8 : frame_num\n");
+	printf("    9 : file_id\n");
+}
+
+static void get_system_time(const char *func, int line_num)
+{
+	struct timeval cur_time;
+
+	memset(&cur_time, 0, sizeof(cur_time));
+	gettimeofday(&cur_time, 0);
+	LOG_O("%s %s line_num = %d, cur_time.tv_sec = %ld, cur_time.tv_usec = %ld\n",
+		__func__, func, line_num, cur_time.tv_sec, cur_time.tv_usec);
+}
+
+
+int file_id = 0;
+extern void *vi_plink_create(csi_camera_channel_cfg_s *chn_cfg);
+extern void vi_plink_release(void * plink);
+extern void display_camera_frame(void * plink, csi_frame_s *frame);
+int main(int argc, char *argv[])
+{
+	bool running = true;
+	int channel_id = -1;
+	int video_id = -1;
+	int dump_enable = -1;
+	int display_enable = -1;
+	int width = 0, height = 0, fmt = -1;
+	int ret = 0;
+	uint64_t frame_num = 0;
+	csi_camera_info_s camera_info;
+	memset(&camera_info, 0, sizeof(camera_info));
+	int chn_id = CSI_CAMERA_CHANNEL_0;
+	int env_type = CSI_CAMERA_EVENT_TYPE_CHANNEL0;
+	frame_fps_t demo_fps;
+	memset(&demo_fps, 0, sizeof(demo_fps));
+	struct timeval init_time, cur_time;
+	memset(&init_time, 0, sizeof(init_time));
+	memset(&cur_time, 0, sizeof(cur_time));
+	get_system_time(__func__, __LINE__);
+	char dev_name[128];
+	// 打印HAL接口版本号
+	csi_api_version_u version;
+	csi_camera_get_version(&version);
+	if (argc == 5)
+	{
+		video_id = atoi(argv[1]);
+		channel_id = atoi(argv[2]);
+		dump_enable = atoi(argv[3]);
+		display_enable = atoi(argv[4]);
+		width = 640;
+		height = 480;
+		fmt = 1;
+		printf("%s, %s, %s, %s \n", argv[1],argv[2],argv[3],argv[4]);
+		printf("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$, %d, display_enable is %d\n", __LINE__, display_enable );
+	} else if (argc == 8) {
+		video_id = atoi(argv[1]);
+		channel_id = atoi(argv[2]);
+		dump_enable = atoi(argv[3]);
+		display_enable = atoi(argv[4]);
+		width = atoi(argv[5]);
+		height = atoi(argv[6]);
+		fmt = atoi(argv[7]);
+	}else if (argc == 9) {
+		video_id = atoi(argv[1]);
+		channel_id = atoi(argv[2]);
+		dump_enable = atoi(argv[3]);
+		display_enable = atoi(argv[4]);
+		width = atoi(argv[5]);
+		height = atoi(argv[6]);
+		fmt = atoi(argv[7]);
+		frame_num = atoi(argv[8]);
+	}else if (argc == 10) {
+		video_id = atoi(argv[1]);
+		channel_id = atoi(argv[2]);
+		dump_enable = atoi(argv[3]);
+		display_enable = atoi(argv[4]);
+		width = atoi(argv[5]);
+		height = atoi(argv[6]);
+		fmt = atoi(argv[7]);
+		frame_num = atoi(argv[8]);
+		file_id = atoi(argv[9]);
+	} else {
+		usage();
+		video_id = 0;
+		channel_id = 0;
+		dump_enable = 0;
+		display_enable = 0;
+		width = 640;
+		height = 480;
+		fmt = 1;
+		printf("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$, %d, display_enable is %d\n", __LINE__, display_enable );
+	}
+	sprintf(dev_name, "/dev/video%d", video_id);
+	LOG_O("Camera HAL version: %d.%d video_id = %d channel_id = %d size{%d, %d} fmt = %d\n", version.major, version.minor, video_id, channel_id, width, height, fmt);
+
+	// 获取设备中,所有的Camera
+	struct csi_camera_infos camera_infos;
+	memset(&camera_infos, 0, sizeof(camera_infos));
+	csi_camera_query_list(&camera_infos);
+
+	// 打印所有设备所支持的Camera
+	for (int i = 0; i < camera_infos.count; i++) {
+		camera_info = camera_infos.info[i];
+		printf("Camera[%d]: camera_name='%s', device_name='%s', bus_info='%s', capabilities=0x%08x\n",
+				i,
+				camera_info.camera_name, camera_info.device_name, camera_info.bus_info,
+				camera_info.capabilities);
+		printf("Camera[%d] caps are:\n", i); /*  The caps are: Video capture, metadata capture */
+		for (int j = 1; j <= 0x08000000; j = j << 1) {
+			switch (camera_info.capabilities & j) {
+			case CSI_CAMERA_CAP_VIDEO_CAPTURE:
+				printf("\t camera_infos.info[%d]:Video capture,\n", i);
+				break;
+			case CSI_CAMERA_CAP_META_CAPTURE:
+				printf("\t camera_infos.info[%d] metadata capture,\n", i);
+				break;
+			default:
+				if (camera_info.capabilities & j) {
+					printf("\t camera_infos.info[%d] unknown capabilities(0x%08x)\n", i,
+							camera_info.capabilities & j);
+				}
+				break;
+			}
+		}
+	}
+	/*  Camera[0]: camera_name='RGB_Camera', device_name='/dev/video0', bus_info='CSI-MIPI', capabilities=0x00800001
+	 *  Camera[1]: camera_name:'Mono_Camera', device_name:'/dev/video8', bus_info='USB', capabilities=0x00000001
+	 */
+
+	bool found_camera = false;
+	for (int i = 0; i < camera_infos.count; i++) {
+		if (strcmp(camera_infos.info[i].device_name, dev_name) == 0) {
+			camera_info = camera_infos.info[i];
+			printf("found device_name:'%s'\n", camera_info.device_name);
+			found_camera = true;
+			break;
+		}
+	}
+	if (!found_camera) {
+		LOG_E("Can't find camera_name:'%s'\n", dev_name);
+		exit(-1);
+	}
+	get_system_time(__func__, __LINE__);
+	// 打开Camera设备获取句柄,作为后续操对象
+	csi_cam_handle_t cam_handle;
+	csi_camera_open(&cam_handle, camera_info.device_name);
+	get_system_time(__func__, __LINE__);
+	// 获取Camera支持的工作模式
+	struct csi_camera_modes camera_modes;
+	csi_camera_get_modes(cam_handle, &camera_modes);
+
+	// 打印camera所支持的所有工作模式
+	printf("Camera:'%s' modes are:\n", dev_name);
+	printf("{\n");
+	for (int i = 0; i < camera_modes.count; i++) {
+		printf("\t mode_id=%d: description:'%s'\n",
+			camera_modes.modes[i].mode_id, camera_modes.modes[i].description);
+	}
+	printf("}\n");
+
+	// 设置camera的工作模式及其配置
+	csi_camera_mode_cfg_s camera_cfg;
+	camera_cfg.mode_id = 1;
+	camera_cfg.calibriation = NULL; // 采用系统默认配置
+	camera_cfg.lib3a = NULL;	// 采用系统默认配置
+	csi_camera_set_mode(cam_handle, &camera_cfg);
+
+	// 获取单个可控单元的属性
+	csi_camera_property_description_s description;
+	/* id=0x0098090x, type=2 default=0 value=1 */
+	/* Other example:
+	 * id=0x0098090y, type=3 min=0 max=255 step=1 default=127 value=116
+	 * id=0x0098090z, type=4 min=0 max=3 default=0 value=2
+	 *                                0: IDLE
+	 *                                1: BUSY
+	 *                                2: REACHED
+	 *                                3: FAILED
+	 */
+
+	// 轮询获取所有可控制的单元
+	printf("all properties are:\n");
+	description.id = CSI_CAMERA_PID_HFLIP;
+	while (!csi_camera_query_property(cam_handle, &description)) {
+		switch (description.type) {
+		case (CSI_CAMERA_PROPERTY_TYPE_INTEGER):
+			printf("id=0x%08x type=%d default=%d value=%d\n",
+			       description.id, description.type,
+			       description.default_value.int_value, description.value.int_value);
+			break;
+		case (CSI_CAMERA_PROPERTY_TYPE_BOOLEAN):
+			printf("id=0x%08x type=%d default=%d value=%d\n",
+			       description.id, description.type,
+			       description.default_value.bool_value, description.value.bool_value);
+			break;
+		case (CSI_CAMERA_PROPERTY_TYPE_ENUM):
+			printf("id=0x%08x type=%d default=%d value=%d\n",
+			       description.id, description.type,
+			       description.default_value.enum_value, description.value.enum_value);
+			break;
+		case (CSI_CAMERA_PROPERTY_TYPE_STRING):
+			printf("id=0x%08x type=%d default=%s value=%s\n",
+			       description.id, description.type,
+			       description.default_value.str_value, description.value.str_value);
+			break;
+		case (CSI_CAMERA_PROPERTY_TYPE_BITMASK):
+			printf("id=0x%08x type=%d default=%x value=%x\n",
+			       description.id, description.type,
+			       description.default_value.bitmask_value, description.value.bitmask_value);
+			break;
+		default:
+			LOG_E("error type!\n");
+			break;
+		}
+		description.id |= CSI_CAMERA_FLAG_NEXT_CTRL;
+	}
+
+	// 同时配置多个参数
+	csi_camera_properties_s properties;
+	csi_camera_property_s property[3];
+	property[0].id = CSI_CAMERA_PID_HFLIP;
+	property[0].type = CSI_CAMERA_PROPERTY_TYPE_BOOLEAN;
+	property[0].value.bool_value = false;
+	property[1].id = CSI_CAMERA_PID_VFLIP;
+	property[1].type = CSI_CAMERA_PROPERTY_TYPE_BOOLEAN;
+	property[1].value.bool_value = false;
+	property[2].id = CSI_CAMERA_PID_ROTATE;
+	property[2].type = CSI_CAMERA_PROPERTY_TYPE_INTEGER;
+	property[2].value.int_value = 0;
+	properties.count = 3;
+	properties.property = property;
+	if (csi_camera_set_property(cam_handle, &properties) < 0) {
+		LOG_O("set_property fail!\n");
+	}
+	LOG_O("set_property ok!\n");
+
+
+
+    // extern int csi_camera_set_pp_path_param(csi_cam_handle_t cam_handle, uint16_t line_num,uint16_t buf_mode);
+    // csi_camera_set_pp_path_param(cam_handle,80,0);
+	// 查询输出channel
+	switch (channel_id) {
+		case 0:
+			chn_id = CSI_CAMERA_CHANNEL_0;
+			env_type = CSI_CAMERA_EVENT_TYPE_CHANNEL0;
+			break;
+		case 1:
+			chn_id = CSI_CAMERA_CHANNEL_1;
+			env_type = CSI_CAMERA_EVENT_TYPE_CHANNEL1;
+			break;
+		case 2:
+			chn_id = CSI_CAMERA_CHANNEL_2;
+			env_type = CSI_CAMERA_EVENT_TYPE_CHANNEL2;
+			break;
+		case 3:
+			chn_id = CSI_CAMERA_CHANNEL_3;
+			env_type = CSI_CAMERA_EVENT_TYPE_CHANNEL3;
+			break;
+		case 4:
+			chn_id = CSI_CAMERA_CHANNEL_4;
+			env_type = CSI_CAMERA_EVENT_TYPE_CHANNEL4;
+			break;
+		case 5:
+			chn_id = CSI_CAMERA_CHANNEL_5;
+			env_type = CSI_CAMERA_EVENT_TYPE_CHANNEL5;
+			break;
+		case 6:
+			chn_id = CSI_CAMERA_CHANNEL_6;
+			env_type = CSI_CAMERA_EVENT_TYPE_CHANNEL6;
+			break;
+		case 7:
+			chn_id = CSI_CAMERA_CHANNEL_7;
+			env_type = CSI_CAMERA_EVENT_TYPE_CHANNEL7;
+			break;
+		default:
+			LOG_E("fail to check chn_id = %d unsupport\n", chn_id);
+			exit(-1);
+	}
+	csi_camera_channel_cfg_s chn_cfg;
+	chn_cfg.chn_id = chn_id;
+	csi_camera_channel_query(cam_handle, &chn_cfg);
+	if (chn_cfg.status != CSI_CAMERA_CHANNEL_CLOSED) {
+		LOG_E("Can't open chn_id = %d\n", chn_id);
+		exit(-1);
+	}
+
+    extern int csi_camera_set_pp_path_param(csi_cam_handle_t cam_handle, uint16_t line_num,uint16_t buf_mode);
+    /*set PP line num to default and enable sram*/
+    csi_camera_set_pp_path_param(cam_handle,0,1);
+	// 打开输出channel
+	chn_cfg.chn_id = chn_id;
+	chn_cfg.frm_cnt = 1;
+	chn_cfg.img_fmt.width = width;
+	chn_cfg.img_fmt.height = height;
+
+	chn_cfg.img_fmt.pix_fmt = fmt;
+	chn_cfg.img_type = CSI_IMG_TYPE_DMA_BUF;
+	chn_cfg.meta_fields = CSI_CAMERA_META_DEFAULT_FIELDS;
+	chn_cfg.capture_type = CSI_CAMERA_CHANNEL_CAPTURE_VIDEO |
+			       CSI_CAMERA_CHANNEL_CAPTURE_META;
+	ret = csi_camera_channel_open(cam_handle, &chn_cfg);
+	if (ret) {
+		exit(-1);
+	}
+	get_system_time(__func__, __LINE__);
+	/*init for vi->vo plink*/
+      void * display_plink = NULL;
+	if (display_enable == 1) {
+		chn_cfg.chn_id = chn_id;
+		display_plink = vi_plink_create(&chn_cfg);
+        if(display_plink==NULL)
+        {
+            LOG_E("plink create fail\n");
+            exit(-1);
+        }
+    }
+	// 订阅Event
+	csi_cam_event_handle_t event_handle;
+	csi_camera_create_event(&event_handle, cam_handle);
+	csi_camera_event_subscription_s subscribe;
+	subscribe.type =
+		CSI_CAMERA_EVENT_TYPE_CAMERA;      // 订阅Camera的ERROR事件
+	subscribe.id = CSI_CAMERA_EVENT_WARNING | CSI_CAMERA_EVENT_ERROR;
+	csi_camera_subscribe_event(event_handle, &subscribe);
+	subscribe.type =
+		env_type;    // 订阅Channel0的FRAME_READY事件
+	subscribe.id = CSI_CAMERA_CHANNEL_EVENT_FRAME_READY |
+		       CSI_CAMERA_CHANNEL_EVENT_OVERFLOW;
+	csi_camera_subscribe_event(event_handle, &subscribe);
+
+/*  for dsp algo setting
+    cb_context[0].id=0;
+    cb_context[0].cam_handle = cam_handle;
+    cb_context[0].dsp_id = 1;
+    cb_context[0].dsp_path = 2;
+    char test_set[16]="init";
+    cb_context[0].buf_size = 1920*1080;
+    cb_context[0].ref_buf=NULL;
+    csi_camera_dsp_algo_param_t algo_param_1={
+        .algo_name = "dsp1_dummy_algo_flo",
+        .algo_cb.cb = dsp_algo_result_cb,
+        .algo_cb.context = &cb_context[0],
+        .algo_cb.arg_size = sizeof(cb_args_t),
+        .sett_ptr = test_set,
+        .sett_size =16,
+        .extra_buf_num =1,
+        .extra_buf_sizes = &cb_context[0].buf_size,
+        .extra_bufs = &cb_context[0].ref_buf,
+    };
+    
+    if(csi_camera_set_dsp_algo_param(cam_handle,cb_context[0].dsp_id,cb_context[0].dsp_path, &algo_param_1))
+    {
+        LOG_E("set DSP algo fail\n");
+        
+    }
+*/
+	// 开始从channel中取出准备好的frame
+	csi_camera_channel_start(cam_handle, chn_id);
+	get_system_time(__func__, __LINE__);
+	// 处理订阅的Event
+	csi_frame_s frame;
+	struct csi_camera_event event;
+
+	while (running) {
+		if (frame_num != 0) {
+			if (demo_fps.frameNumber > frame_num) {
+				running = false;
+			}
+		}
+		int timeout = -1; // unit: ms, -1 means wait forever, or until error occurs
+		csi_camera_get_event(event_handle, &event, timeout);
+		// printf("%s event.type = %d, event.id = %d\n", __func__, event.type, event.id);
+		switch (event.type) {
+		case CSI_CAMERA_EVENT_TYPE_CAMERA:
+			switch (event.id) {
+			case CSI_CAMERA_EVENT_ERROR:
+				// do sth.
+				    LOG_O("get CAMERA EVENT CSI_CAMERA_EVENT_ERROR!\n");
+				break;
+            case CSI_CAMERA_EVENT_WARNING:
+            		LOG_O("get CAMERA EVENT CSI_CAMERA_EVENT_WRN,RC: %s\n",event.bin);
+				    break;
+			default:
+				break;
+			}
+			break;
+		case CSI_CAMERA_EVENT_TYPE_CHANNEL0:
+		case CSI_CAMERA_EVENT_TYPE_CHANNEL1:
+		case CSI_CAMERA_EVENT_TYPE_CHANNEL2:
+		case CSI_CAMERA_EVENT_TYPE_CHANNEL3:
+		case CSI_CAMERA_EVENT_TYPE_CHANNEL4:
+		case CSI_CAMERA_EVENT_TYPE_CHANNEL5:
+		case CSI_CAMERA_EVENT_TYPE_CHANNEL6:
+		case CSI_CAMERA_EVENT_TYPE_CHANNEL7:
+			switch (event.id) {
+			case CSI_CAMERA_CHANNEL_EVENT_FRAME_READY: {
+				get_system_time(__func__, __LINE__);
+				int read_frame_count = csi_camera_get_frame_count(cam_handle,
+						       chn_id);
+				unsigned  long diff;
+				if (init_time.tv_usec == 0)
+					gettimeofday(&init_time,0);//osGetTick();
+				gettimeofday(&cur_time, 0);
+				diff = 1000000 * (cur_time.tv_sec-init_time.tv_sec)+ cur_time.tv_usec-init_time.tv_usec;
+				demo_fps.frameNumber++;
+				if (diff != 0)
+					demo_fps.fps = (float)demo_fps.frameNumber / diff * 1000000.0f;
+				LOG_O("%s %d read_frame_count = %d, frame_count = %ld, fps = %.2f diff = %ld\n", __func__, __LINE__, read_frame_count, demo_fps.frameNumber, demo_fps.fps, diff);
+
+				for (int i = 0; i < read_frame_count; i++) {
+					csi_camera_get_frame(cam_handle, chn_id, &frame, timeout);
+#ifdef PLATFORM_SIMULATOR
+                    if (frame.img.type == CSI_IMG_TYPE_DMA_BUF) {
+                        void *phyaddr = vi_mem_import(frame.img.dmabuf[0].fds);
+                        void *p = vi_mem_map(phyaddr) + frame.img.dmabuf[0].offset;
+					    show_frame_image(p, frame.img.height, frame.img.width);
+                        vi_mem_release(phyaddr);
+                    } else {
+					    show_frame_image(frame.img.usr_addr[0], frame.img.height, frame.img.width);
+                    }
+#endif
+					// printf("main 443 phyaddr=%p\n", vi_mem_import(frame.img.dmabuf[0].fds));
+					dump_camera_meta(&frame);
+					chn_cfg.chn_id = chn_id;
+					csi_camera_channel_query(cam_handle, &chn_cfg);
+					frame.img.pix_format = chn_cfg.img_fmt.pix_fmt;
+
+					if (dump_enable) {
+						dump_camera_frame(&frame, chn_cfg.img_fmt.pix_fmt);
+					}
+					if (display_enable == 1) {
+                        display_camera_frame(display_plink, &frame);
+                    }
+                    // csi_camera_frame_unlock(cam_handle, &frame);
+                    csi_camera_put_frame(&frame);
+
+					csi_frame_release(&frame);
+				}
+				break;
+			}
+			default:
+				break;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+	csi_camera_channel_stop(cam_handle, chn_id);
+	usleep (1000000);
+	// 取消订阅某一个event, 也可以直接调用csi_camera_destory_event,结束所有的订阅
+	subscribe.type = env_type;
+	subscribe.id = CSI_CAMERA_CHANNEL_EVENT_FRAME_READY;
+	csi_camera_unsubscribe_event(event_handle, &subscribe);
+
+	csi_camera_destory_event(event_handle);
+
+	csi_camera_channel_close(cam_handle, chn_id);
+	csi_camera_close(cam_handle);
+    if(display_plink)
+    {
+        vi_plink_release(display_plink);
+    }
+}
+
+static void dump_camera_meta(csi_frame_s *frame)
+{
+	int i;
+
+	if (frame->meta.type != CSI_META_TYPE_CAMERA)
+		return;
+
+	csi_camera_meta_s *meta_data = (csi_camera_meta_s *)frame->meta.data;
+	int meta_count = meta_data->count;
+	csi_camrea_meta_unit_s meta_unit;
+
+
+	csi_camera_frame_get_meta_unit(
+		&meta_unit, meta_data, CSI_CAMERA_META_ID_FRAME_ID);
+	LOG_O("meta_id=%d, meta_type=%d, meta_value=%d\n",
+			meta_unit.id, meta_unit.type, meta_unit.int_value);
+}
+
+static void dump_camera_frame(csi_frame_s *frame, csi_pixel_fmt_e fmt)
+{
+	char file[128];
+	static int file_indx=0;
+	int size;
+	uint32_t indexd, j;
+    void *buf[3];
+    int buf_size;
+    csi_camera_meta_s *meta_data = (csi_camera_meta_s *)frame->meta.data;
+	csi_camrea_meta_unit_s meta_unit;
+
+
+	csi_camera_frame_get_meta_unit(
+		&meta_unit, meta_data, CSI_CAMERA_META_ID_CAMERA_NAME);
+
+              
+	sprintf(file,"demo_save_img%s_%d_%d",meta_unit.str_value,file_id, file_indx++%10);
+	int fd = open(file, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IROTH);
+	if(fd == -1) {
+		LOG_E("%s, %d, open file error!!!!!!!!!!!!!!!\n", __func__, __LINE__);
+		return ;
+	}
+    if (frame->img.type == CSI_IMG_TYPE_DMA_BUF) {
+
+        buf_size = frame->img.strides[0]*frame->img.height;
+        switch(fmt) {
+                case CSI_PIX_FMT_NV12:
+		        case CSI_PIX_FMT_YUV_SEMIPLANAR_420:
+                        if(frame->img.num_planes ==2)
+                        { 
+                            buf_size+=frame->img.strides[1]*frame->img.height/2;
+                        }
+                        else{
+                            LOG_E("img fomrat is not match with frame planes:%d\n",frame->img.num_planes);
+                            return;
+                        }
+                        break;
+                case CSI_PIX_FMT_YUV_SEMIPLANAR_422:
+                        if(frame->img.num_planes ==2)
+                        { 
+                            buf_size+=frame->img.strides[1]*frame->img.height;
+                        }
+                        else{
+                            LOG_E("img fomrat is not match with frame planes:%d\n",frame->img.num_planes);
+                            return;
+                        }
+                        break;
+                default:
+                        break;
+                
+        }
+
+        buf[0]= mmap(0, buf_size, PROT_READ | PROT_WRITE,
+                    MAP_SHARED, frame->img.dmabuf[0].fds, frame->img.dmabuf[0].offset);
+        // plane_size[1] = frame->img.strides[1]*frame->img.height;
+        // printf("frame plane 1 stride:%d,offset:%d\n", frame->img.strides[1],(uint32_t)frame->img.dmabuf[1].offset);
+        if(frame->img.num_planes ==2)
+        {
+            // buf[1] = mmap(0, plane_size[1]/2, PROT_READ | PROT_WRITE,
+            //             MAP_SHARED, frame->img.dmabuf[1].fds, frame->img.dmabuf[1].offset);
+            buf[1] = buf[0]+frame->img.dmabuf[1].offset;
+        }
+
+    }
+    else{
+            buf[0] = frame->img.usr_addr[0];
+            buf[1] = frame->img.usr_addr[1];
+    }
+
+	LOG_O("%s,save img from : (%lx,%lx)size:%d to %s, fmt:%d width:%d stride:%d height:%d\n",__FUNCTION__, (uint64_t)buf[0],(uint64_t)buf[1],size, file, fmt, frame->img.width, frame->img.strides[0], frame->img.height);
+
+	if (frame->img.strides[0] == 0) {
+		frame->img.strides[0] = frame->img.width;
+	}
+	switch(fmt) {
+		case CSI_PIX_FMT_NV12:
+		case CSI_PIX_FMT_YUV_SEMIPLANAR_420:
+			for (j = 0; j < frame->img.height; j++) { //Y
+				indexd = j*frame->img.strides[0];
+				write(fd, buf[0] + indexd, frame->img.width);
+			}
+			for (j = 0; j < frame->img.height / 2; j++) { //UV
+				indexd = j*frame->img.strides[0];
+				write(fd, buf[1] + indexd, frame->img.width);
+			}
+			break;
+		case CSI_PIX_FMT_RGB_INTEVLEAVED_888:
+		case CSI_PIX_FMT_YUV_TEVLEAVED_444:
+            size = frame->img.width*3;
+            for (j = 0; j < frame->img.height; j++) {
+				indexd = j*frame->img.strides[0];
+				write(fd, buf[0] + indexd, size);
+			}
+			break;
+		case CSI_PIX_FMT_BGR:
+		case CSI_PIX_FMT_RGB_PLANAR_888:
+		case CSI_PIX_FMT_YUV_PLANAR_444:
+			size = frame->img.width * frame->img.height * 3;
+			write(fd, buf[0], size);
+			break;
+        case CSI_PIX_FMT_RAW_8BIT:
+            size = frame->img.width;
+            for (j = 0; j < frame->img.height; j++) {
+				indexd = j*frame->img.strides[0];
+				write(fd, buf[0] + indexd, size);
+			}
+			break;
+		case CSI_PIX_FMT_YUV_TEVLEAVED_422:
+        case CSI_PIX_FMT_RAW_10BIT:
+	    case CSI_PIX_FMT_RAW_12BIT:
+	    case CSI_PIX_FMT_RAW_14BIT:
+	    case CSI_PIX_FMT_RAW_16BIT:
+            size = frame->img.width*2;
+            for (j = 0; j < frame->img.height; j++) {
+				indexd = j*frame->img.strides[0];
+				write(fd, buf[0] + indexd, size);
+			}
+			break;
+		case CSI_PIX_FMT_YUV_SEMIPLANAR_422:
+			if (frame->img.strides[0] == 0) {
+				frame->img.strides[0] = frame->img.width;
+			}
+			for (j = 0; j < frame->img.height; j++) { //Y
+				indexd = j*frame->img.strides[0];
+				write(fd,buf[0] + indexd, frame->img.width);
+			}
+			for (j = 0; j < frame->img.height; j++) { //UV
+				indexd = j*frame->img.strides[0];
+				write(fd, buf[1]+ indexd, frame->img.width);
+			}
+			break;
+		default:
+			LOG_E("%s unsupported format to save\n", __func__);
+			exit(-1);
+			break;
+	}
+
+	close(fd);
+    munmap(buf[0],buf_size);
+    // munmap(buf[1],plane_size[1]);
+	LOG_O("%s exit\n", __func__);
+}

+ 303 - 0
examples/camera/camera_demo1.c

@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LOG_LEVEL 3
+#define LOG_PREFIX "camera_demo1"
+#include <syslog.h>
+
+#include <csi_frame.h>
+#include <csi_camera.h>
+
+#ifdef PLATFORM_SIMULATOR
+#include "apputilities.h"
+#include "platform_action.h"
+#endif
+
+static void dump_camera_meta(csi_frame_s *frame);
+
+//#define TEST_DEVICE_NAME "/dev/fake"
+#define TEST_DEVICE_NAME "/dev/video0"
+
+int main(int argc, char *argv[])
+{
+	bool running = true;
+	csi_camera_info_s camera_info;
+
+	// 打印HAL接口版本号
+	csi_api_version_u version;
+	csi_camera_get_version(&version);
+	printf("Camera HAL version: %d.%d\n", version.major, version.minor);
+
+	// 获取设备中,所有的Camera
+	struct csi_camera_infos camera_infos;
+	csi_camera_query_list(&camera_infos);
+
+	// 打印所有设备所支持的Camera
+	for (int i = 0; i < camera_infos.count; i++) {
+		camera_info = camera_infos.info[i];
+		printf("Camera[%d]: camera_name='%s', device_name='%s', bus_info='%s', capabilities=0x%08x\n",
+		       i,
+		       camera_info.camera_name, camera_info.device_name, camera_info.bus_info,
+		       camera_info.capabilities);
+		printf("Camera[%d] caps are:\n",
+		       i); /*  The caps are: Video capture, metadata capture */
+		for (int j = 1; j <= 0x08000000; j = j << 1) {
+			switch (camera_info.capabilities & j) {
+			case CSI_CAMERA_CAP_VIDEO_CAPTURE:
+				printf("\t camera_infos.info[%d]:Video capture,\n", i);
+				break;
+			case CSI_CAMERA_CAP_META_CAPTURE:
+				printf("\t camera_infos.info[%d] metadata capture,\n", i);
+				break;
+			default:
+				if (camera_info.capabilities & j) {
+					printf("\t camera_infos.info[%d] unknown capabilities(0x%08x)\n", i,
+					       camera_info.capabilities & j);
+				}
+				break;
+			}
+		}
+	}
+	/*  Camera[0]: camera_name='RGB_Camera', device_name='/dev/video0', bus_info='CSI-MIPI', capabilities=0x00800001
+	 *  Camera[1]: camera_name:'Mono_Camera', device_name:'/dev/video8', bus_info='USB', capabilities=0x00000001
+	 */
+
+	bool found_camera = false;
+	for (int i = 0; i < camera_infos.count; i++) {
+		if (strcmp(camera_infos.info[i].device_name, TEST_DEVICE_NAME) == 0) {
+			camera_info = camera_infos.info[i];
+			printf("found device_name:'%s'\n", camera_info.device_name);
+			found_camera = true;
+			break;
+		}
+	}
+	if (!found_camera) {
+		LOG_E("Can't find camera_name:'%s'\n", TEST_DEVICE_NAME);
+		exit(-1);
+	}
+
+
+	// 打开Camera设备获取句柄,作为后续操对象
+	csi_cam_handle_t cam_handle;
+	csi_camera_open(&cam_handle, camera_info.device_name);
+
+	// 获取Camera支持的工作模式
+	struct csi_camera_modes camera_modes;
+	csi_camera_get_modes(cam_handle, &camera_modes);
+
+	// 打印camera所支持的所有工作模式
+	printf("Camera:'%s' modes are:\n", TEST_DEVICE_NAME);
+	printf("{\n");
+	for (int i = 0; i < camera_modes.count; i++) {
+		printf("\t mode_id=%d: description:'%s'\n",
+		       camera_modes.modes[i].mode_id, camera_modes.modes[i].description);
+	}
+	printf("}\n");
+
+	// 设置camera的工作模式及其配置
+	csi_camera_mode_cfg_s camera_cfg;
+	camera_cfg.mode_id = 1;
+	camera_cfg.calibriation = NULL; // 采用系统默认配置
+	camera_cfg.lib3a = NULL;	// 采用系统默认配置
+	csi_camera_set_mode(cam_handle, &camera_cfg);
+
+	// 获取单个可控单元的属性
+	csi_camera_property_description_s description;
+	description.id = CSI_CAMERA_PID_HFLIP;
+	csi_camera_query_property(cam_handle, &description);
+	printf("id=0x%08x type=%d default=%d value=%d\n",
+	       description.id, description.type,
+	       description.default_value.bool_value, description.value.bool_value);
+	/* id=0x0098090x, type=2 default=0 value=1 */
+	/* Other example:
+	 * id=0x0098090y, type=3 min=0 max=255 step=1 default=127 value=116
+	 * id=0x0098090z, type=4 min=0 max=3 default=0 value=2
+	 *                                0: IDLE
+	 *                                1: BUSY
+	 *                                2: REACHED
+	 *                                3: FAILED
+	 */
+
+	// 轮询获取所有可控制的单元
+	printf("all properties are:\n");
+	description.id = CSI_CAMERA_PID_HFLIP;
+	while (!csi_camera_query_property(cam_handle, &description)) {
+		switch (description.type) {
+		case (CSI_CAMERA_PROPERTY_TYPE_INTEGER):
+			printf("id=0x%08x type=%d default=%d value=%d\n",
+			       description.id, description.type,
+			       description.default_value.int_value, description.value.int_value);
+			break;
+		case (CSI_CAMERA_PROPERTY_TYPE_BOOLEAN):
+			printf("id=0x%08x type=%d default=%d value=%d\n",
+			       description.id, description.type,
+			       description.default_value.bool_value, description.value.bool_value);
+			break;
+		case (CSI_CAMERA_PROPERTY_TYPE_ENUM):
+			printf("id=0x%08x type=%d default=%d value=%d\n",
+			       description.id, description.type,
+			       description.default_value.enum_value, description.value.enum_value);
+			break;
+		case (CSI_CAMERA_PROPERTY_TYPE_STRING):
+			printf("id=0x%08x type=%d default=%s value=%s\n",
+			       description.id, description.type,
+			       description.default_value.str_value, description.value.str_value);
+			break;
+		case (CSI_CAMERA_PROPERTY_TYPE_BITMASK):
+			printf("id=0x%08x type=%d default=%x value=%x\n",
+			       description.id, description.type,
+			       description.default_value.bitmask_value, description.value.bitmask_value);
+			break;
+		default:
+			LOG_E("error type!\n");
+			break;
+		}
+		description.id |= CSI_CAMERA_FLAG_NEXT_CTRL;
+	}
+
+	// 同时配置多个参数
+	csi_camera_properties_s properties;
+	csi_camera_property_s property[2];
+	property[0].id = CSI_CAMERA_PID_HFLIP;
+	property[0].type = CSI_CAMERA_PROPERTY_TYPE_BOOLEAN;
+	property[0].value.bool_value = true;
+	property[1].id = CSI_CAMERA_PID_VFLIP;
+	property[1].type = CSI_CAMERA_PROPERTY_TYPE_BOOLEAN;
+	property[1].value.bool_value = false;
+	properties.count = 2;
+	properties.property = property;
+	csi_camera_set_property(cam_handle, &properties);
+	LOG_O("set_property ok!\n");
+
+	csi_camera_get_property(cam_handle, &properties);
+
+
+
+	// 查询输出channel
+	csi_camera_channel_cfg_s chn_cfg;
+	chn_cfg.chn_id = CSI_CAMERA_CHANNEL_0;
+	csi_camera_channel_query(cam_handle, &chn_cfg);
+	if (chn_cfg.status != CSI_CAMERA_CHANNEL_CLOSED) {
+		printf("Can't open CSI_CAMERA_CHANNEL_0\n");
+		exit(-1);
+	}
+
+	// 打开输出channel
+	chn_cfg.chn_id = CSI_CAMERA_CHANNEL_0;
+	chn_cfg.frm_cnt = 4;
+	chn_cfg.img_fmt.width =  1280;
+	chn_cfg.img_fmt.height = 720;
+	chn_cfg.img_fmt.pix_fmt = CSI_PIX_FMT_BGR;
+	chn_cfg.img_type = CSI_IMG_TYPE_DMA_BUF;
+	chn_cfg.meta_fields = CSI_CAMERA_META_DEFAULT_FIELDS;
+	chn_cfg.capture_type = CSI_CAMERA_CHANNEL_CAPTURE_VIDEO |
+			       CSI_CAMERA_CHANNEL_CAPTURE_META;
+	csi_camera_channel_open(cam_handle, &chn_cfg);
+
+	// 订阅Event
+	csi_cam_event_handle_t event_handle;
+	csi_camera_create_event(&event_handle, cam_handle);
+	csi_camera_event_subscription_s subscribe;
+	subscribe.type =
+		CSI_CAMERA_EVENT_TYPE_CAMERA;      // 订阅Camera的ERROR事件
+	subscribe.id = CSI_CAMERA_EVENT_WARNING | CSI_CAMERA_EVENT_ERROR;
+	csi_camera_subscribe_event(event_handle, &subscribe);
+	subscribe.type =
+		CSI_CAMERA_EVENT_TYPE_CHANNEL0;    // 订阅Channel0的FRAME_READY事件
+	subscribe.id = CSI_CAMERA_CHANNEL_EVENT_FRAME_READY |
+		       CSI_CAMERA_CHANNEL_EVENT_OVERFLOW;
+	csi_camera_subscribe_event(event_handle, &subscribe);
+
+	// 开始从channel中取出准备好的frame
+	csi_camera_channel_start(cam_handle, CSI_CAMERA_CHANNEL_0);
+
+	// 处理订阅的Event
+	csi_frame_s frame;
+	struct csi_camera_event event;
+
+	while (running) {
+		int timeout = -1; // unit: ms, -1 means wait forever, or until error occurs
+		csi_camera_get_event(event_handle, &event, timeout);
+
+		switch (event.type) {
+		case CSI_CAMERA_EVENT_TYPE_CAMERA:
+			switch (event.id) {
+			case CSI_CAMERA_EVENT_ERROR:
+				// do sth.
+				LOG_D("get CAMERA EVENT CSI_CAMERA_EVENT_ERROR!\n");
+				break;
+			default:
+				break;
+			}
+		case CSI_CAMERA_EVENT_TYPE_CHANNEL0:
+			switch (event.id) {
+			case CSI_CAMERA_CHANNEL_EVENT_FRAME_READY: {
+				int read_frame_count = csi_camera_get_frame_count(cam_handle,
+						       CSI_CAMERA_CHANNEL_0);
+				for (int i = 0; i < read_frame_count; i++) {
+					csi_camera_get_frame(cam_handle, CSI_CAMERA_CHANNEL_0, &frame, timeout);
+
+					// frame.image: {.width, .height, .pix_fmt, .dma-buf}
+					//show_frame_image(frame.image); // 伪代码
+#ifdef PLATFORM_SIMULATOR
+					camera_action_image_display(&frame);
+					csi_camera_put_frame(&frame);
+#endif
+
+					// frame.meta: {.count,
+					//              .meta_data[]={meta_id, type,
+					//                            union{int_value, str_value, ...}}}
+
+					dump_camera_meta(&frame);
+
+					//csi_camera_put_frame(&frame);
+				}
+				break;
+			}
+			default:
+				break;
+			}
+		default:
+			break;
+		}
+	}
+
+	// 取消订阅某一个event, 也可以直接调用csi_camera_destory_event,结束所有的订阅
+	subscribe.type = CSI_CAMERA_EVENT_TYPE_CHANNEL0;
+	subscribe.id = CSI_CAMERA_CHANNEL_EVENT_FRAME_READY;
+	csi_camera_unsubscribe_event(event_handle, &subscribe);
+
+	csi_camera_destory_event(event_handle);
+	csi_camera_channel_stop(cam_handle, CSI_CAMERA_CHANNEL_0);
+	csi_camera_channel_close(cam_handle, CSI_CAMERA_CHANNEL_0);
+	csi_camera_close(cam_handle);
+}
+
+static void dump_camera_meta(csi_frame_s *frame)
+{
+	int i;
+	if (frame->meta.type != CSI_META_TYPE_CAMERA)
+		return;
+
+	csi_camera_meta_s *meta_data = (csi_camera_meta_s *)frame->meta.data;
+	int meta_count = meta_data->count;
+	csi_camrea_meta_unit_s meta_unit;
+
+	for (i = 0; i < meta_count; i++) {
+		csi_camera_frame_get_meta_unit(
+			&meta_unit, meta_data, CSI_CAMERA_META_ID_FRAME_ID);
+		printf("meta_id=%d, meta_type=%d, meta_value=%d",
+		       meta_unit.id, meta_unit.type, meta_unit.int_value);
+	}
+}
+

+ 357 - 0
examples/camera/camera_demo2.c

@@ -0,0 +1,357 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LOG_LEVEL 2
+#define LOG_PREFIX "camera_demo2"
+#include <syslog.h>
+
+
+#include <csi_frame.h>
+#include <csi_camera.h>
+
+#ifdef PLATFORM_SIMULATOR
+#include "apputilities.h"
+#include "platform_action.h"
+#endif
+
+static void dump_camera_meta(csi_frame_s *frame);
+
+#define TEST_DEVICE_NAME "/dev/video0"
+int main(int argc, char *argv[])
+{
+	uint32_t i;
+	bool running = true;
+	csi_camera_info_s camera_info;
+
+	// 获取设备中,所有的Camera
+	struct csi_camera_infos camera_infos;
+	csi_camera_query_list(&camera_infos);
+	LOG_O("csi_camera_query_list() OK\n");
+
+	// 打印所有设备所支持的Camera
+	for (i = 0; i < camera_infos.count; i++) {
+		printf("Camera[%d]: camera_name='%s', device_name='%s', bus_info='%s', capabilities=0x%08x\n",
+		       i, camera_infos.info[i].camera_name, camera_infos.info[i].device_name,
+		       camera_infos.info[i].bus_info, camera_infos.info[i].capabilities);
+	}
+	/*  Camera[0]: camera_name='RGB_Camera', device_name='/dev/video0', bus_info='CSI-MIPI', capabilities=0x00800001
+	 *  Camera[1]: camera_name:'Mono_Camera', device_name:'/dev/video8', bus_info='USB', capabilities=0x00000001
+	 */
+
+	bool found_camera = false;
+	for (i = 0; i < camera_infos.count; i++) {
+		if (strcmp(camera_infos.info[i].device_name, TEST_DEVICE_NAME) == 0) {
+			camera_info = camera_infos.info[i];
+			printf("found device_name:'%s'\n", camera_info.device_name);
+			found_camera = true;
+			break;
+		}
+	}
+	if (!found_camera) {
+		LOG_E("Can't find camera_name:'%s'\n", TEST_DEVICE_NAME);
+		exit(-1);
+	}
+
+	printf("The caps are:\n");
+	for (i = 1; i < 0x80000000; i = i << 1) {
+		switch (camera_info.capabilities & i) {
+		case CSI_CAMERA_CAP_VIDEO_CAPTURE:
+			printf("\t Video capture\n");
+			break;
+		case CSI_CAMERA_CAP_META_CAPTURE:
+			printf("\t metadata capture\n");
+			break;
+		default:
+			if (camera_info.capabilities & i) {
+				printf("\t unknown capabilities(0x%08x)\n", camera_info.capabilities & i);
+			}
+			break;
+		}
+	}
+	/*  The caps are: Video capture, metadata capture */
+
+	// 打开Camera设备获取句柄,作为后续操对象
+	csi_cam_handle_t cam_handle;
+	csi_camera_open(&cam_handle, camera_info.device_name);
+	LOG_O("csi_camera_open() OK\n");
+
+	// 获取Camera支持的工作模式
+	struct csi_camera_modes camera_modes;
+	camera_modes.count = 0;
+	csi_camera_get_modes(cam_handle, &camera_modes);
+	LOG_O("csi_camera_get_modes() OK\n");
+
+	// 打印camera所支持的所有工作模式
+	printf(" Camera:'%s' modes are:{\n", TEST_DEVICE_NAME);
+	for (i = 0; i < camera_modes.count; i++) {
+		printf("\t mode_id=%d: description:'%s'\n",
+		       camera_modes.modes[i].mode_id, camera_modes.modes[i].description);
+	}
+	printf("}\n");
+
+	// 设置camera的工作模式及其配置
+	csi_camera_mode_cfg_s camera_cfg;
+	camera_cfg.mode_id = 1;
+	camera_cfg.calibriation = NULL; // 采用系统默认配置
+	camera_cfg.lib3a = NULL;	// 采用系统默认配置
+	csi_camera_set_mode(cam_handle, &camera_cfg);
+
+	// 获取单个可控单元的属性
+	csi_camera_property_description_s description;
+	description.id = CSI_CAMERA_PID_HFLIP;
+	csi_camera_query_property(cam_handle, &description);
+	printf("properity id=0x%08x type=%d default=%d value=%d\n",
+	       description.id, description.type,
+	       description.default_value.bool_value, description.value.bool_value);
+	/* id=0x0098090x, type=2 default=0 value=1 */
+	/* Other example:
+	 * id=0x0098090y, type=3 min=0 max=255 step=1 default=127 value=116
+	 * id=0x0098090z, type=4 min=0 max=3 default=0 value=2
+	 *                                0: IDLE
+	 *                                1: BUSY
+	 *                                2: REACHED
+	 *                                3: FAILED
+	 */
+
+	// 轮询获取所有可控制的单元
+	description.id = CSI_CAMERA_FLAG_NEXT_CTRL;
+	while (!csi_camera_query_property(cam_handle, &description)) {
+		//printf(...); // 打印属性
+		switch (description.type) {
+		case (CSI_CAMERA_PROPERTY_TYPE_INTEGER):
+			printf("id=0x%08x type=%d default=%d value=%d\n",
+			       description.id, description.type,
+			       description.default_value.int_value, description.value.int_value);
+			break;
+		case (CSI_CAMERA_PROPERTY_TYPE_BOOLEAN):
+			printf("id=0x%08x type=%d default=%d value=%d\n",
+			       description.id, description.type,
+			       description.default_value.bool_value, description.value.bool_value);
+			break;
+		case (CSI_CAMERA_PROPERTY_TYPE_ENUM):
+			printf("id=0x%08x type=%d default=%d value=%d\n",
+			       description.id, description.type,
+			       description.default_value.enum_value, description.value.enum_value);
+			break;
+		case (CSI_CAMERA_PROPERTY_TYPE_STRING):
+			printf("id=0x%08x type=%d default=%s value=%s\n",
+			       description.id, description.type,
+			       description.default_value.str_value, description.value.str_value);
+			break;
+		case (CSI_CAMERA_PROPERTY_TYPE_BITMASK):
+			printf("id=0x%08x type=%d default=%x value=%x\n",
+			       description.id, description.type,
+			       description.default_value.bitmask_value, description.value.bitmask_value);
+			break;
+		default:
+			LOG_E("error type!\n");
+			break;
+		}
+		description.id |= CSI_CAMERA_FLAG_NEXT_CTRL;
+	}
+	LOG_O("csi_camera_query_property() OK\n");
+
+	// 同时配置多个参数
+	csi_camera_properties_s properties;
+	csi_camera_property_s property[2];
+	property[0].id = CSI_CAMERA_PID_EXPOSURE_MODE;
+	property[0].type = CSI_CAMERA_PROPERTY_TYPE_ENUM;
+	property[0].value.enum_value = CSI_CAMERA_EXPOSURE_MODE_AUTO;
+	property[1].id = CSI_CAMERA_PID_EXPOSURE_MODE;
+	property[1].type = CSI_CAMERA_PROPERTY_TYPE_ENUM;
+	property[1].value.enum_value = CSI_CAMERA_EXPOSURE_MANUAL;
+	properties.count = 2;
+	properties.property = property;
+	csi_camera_get_property(cam_handle, &properties);
+	LOG_O("csi_camera_get_property() OK\n");
+
+	// 查询输出channel
+	csi_camera_channel_cfg_s chn_cfg;
+	chn_cfg.chn_id = CSI_CAMERA_CHANNEL_0;
+	csi_camera_channel_query(cam_handle, &chn_cfg);
+	if (chn_cfg.status != CSI_CAMERA_CHANNEL_CLOSED) {
+		printf("Can't open CSI_CAMERA_CHANNEL_0\n");
+		exit(-1);
+	}
+	LOG_O("csi_camera_channel_query() OK\n");
+
+	// 打开输出channel_0
+	chn_cfg.chn_id = CSI_CAMERA_CHANNEL_0;
+	chn_cfg.frm_cnt = 4;
+	chn_cfg.img_fmt.width = 640;
+	chn_cfg.img_fmt.height = 480;
+	chn_cfg.img_fmt.pix_fmt = CSI_PIX_FMT_I420;
+	chn_cfg.img_type = CSI_IMG_TYPE_DMA_BUF;
+	chn_cfg.meta_fields = CSI_CAMERA_META_DEFAULT_FIELDS;
+	chn_cfg.capture_type = CSI_CAMERA_CHANNEL_CAPTURE_VIDEO |
+			       CSI_CAMERA_CHANNEL_CAPTURE_META;
+	csi_camera_channel_open(cam_handle, &chn_cfg);
+	LOG_O("CSI_CAMERA_CHANNEL_0: csi_camera_channel_open() OK\n");
+
+
+	// 打开输出channel_1
+	chn_cfg.chn_id = CSI_CAMERA_CHANNEL_1;
+	chn_cfg.frm_cnt = 4;
+	chn_cfg.img_fmt.width = 1280;
+	chn_cfg.img_fmt.height = 720;
+	chn_cfg.img_fmt.pix_fmt = CSI_PIX_FMT_BGR;
+	chn_cfg.img_type = CSI_IMG_TYPE_DMA_BUF;
+	chn_cfg.meta_fields = CSI_CAMERA_META_DEFAULT_FIELDS;
+	chn_cfg.capture_type = CSI_CAMERA_CHANNEL_CAPTURE_VIDEO |
+			       CSI_CAMERA_CHANNEL_CAPTURE_META;
+	csi_camera_channel_open(cam_handle, &chn_cfg);
+	LOG_O("CSI_CAMERA_CHANNEL_1: csi_camera_channel_open() OK\n");
+
+	// 订阅Event
+	csi_cam_event_handle_t event_handle;
+	csi_camera_create_event(&event_handle, cam_handle);
+	struct csi_camera_event_subscription subscribe;
+	subscribe.type =
+		CSI_CAMERA_EVENT_TYPE_CAMERA;      // 订阅Camera的ERROR事件
+	subscribe.id = CSI_CAMERA_EVENT_WARNING | CSI_CAMERA_EVENT_ERROR;
+	csi_camera_subscribe_event(event_handle, &subscribe);
+
+	subscribe.type =
+		CSI_CAMERA_EVENT_TYPE_CHANNEL0;    // 订阅Channel0的FRAME_READY事件
+	subscribe.id = CSI_CAMERA_CHANNEL_EVENT_FRAME_READY |
+		       CSI_CAMERA_CHANNEL_EVENT_OVERFLOW;
+	csi_camera_subscribe_event(event_handle, &subscribe);
+
+	subscribe.type =
+		CSI_CAMERA_EVENT_TYPE_CHANNEL1;    // 订阅Channel0的FRAME_READY事件
+	subscribe.id = CSI_CAMERA_CHANNEL_EVENT_FRAME_READY |
+		       CSI_CAMERA_CHANNEL_EVENT_OVERFLOW;
+	csi_camera_subscribe_event(event_handle, &subscribe);
+	LOG_O("Event subscript OK\n");
+
+	// 开始从channel中取出准备好的frame
+	csi_camera_channel_start(cam_handle, CSI_CAMERA_CHANNEL_0);
+	csi_camera_channel_start(cam_handle, CSI_CAMERA_CHANNEL_1);
+	LOG_O("Channel start OK\n");
+
+	// 处理订阅的Event
+	csi_frame_s frame;
+	struct csi_camera_event event;
+
+	LOG_O("Starting get frame...\n");
+	while (running) {
+		int timeout = -1; // unit: ms, -1 means wait forever, or until error occurs
+
+		csi_camera_get_event(event_handle, &event, timeout);
+
+		switch (event.type) {
+		case CSI_CAMERA_EVENT_TYPE_CAMERA:
+			switch (event.id) {
+			case CSI_CAMERA_EVENT_ERROR:
+				// do sth.
+				break;
+			default:
+				break;
+			}
+		case CSI_CAMERA_EVENT_TYPE_CHANNEL0:
+			switch (event.id) {
+			case CSI_CAMERA_CHANNEL_EVENT_FRAME_READY: {
+				int read_frame_count = csi_camera_get_frame_count(cam_handle,
+						       CSI_CAMERA_CHANNEL_0);
+				csi_camera_get_frame(cam_handle,CSI_CAMERA_CHANNEL_0, &frame, timeout);
+
+				// frame.image: {.width, .height, .pix_fmt, .dma-buf}
+				//show_frame_image(frame.image); // 伪代码
+				// frame.meta: {.count,
+				//              .meta_data[]={meta_id, type,
+				//                            union{int_value, str_value, ...}}}
+
+#ifdef PLATFORM_SIMULATOR
+				camera_action_image_display(&frame);
+				csi_camera_put_frame(&frame);
+#endif
+				dump_camera_meta(&frame);
+
+				csi_frame_release(&frame);
+				break;
+			}
+			default:
+				break;
+			}
+			break;
+		case CSI_CAMERA_EVENT_TYPE_CHANNEL1:
+			switch (event.id) {
+			case CSI_CAMERA_CHANNEL_EVENT_FRAME_READY: {
+				int read_frame_count = csi_camera_get_frame_count(cam_handle,
+						       CSI_CAMERA_CHANNEL_1);
+				for (int i = 0; i < read_frame_count; i++) {
+					csi_camera_get_frame(cam_handle,CSI_CAMERA_CHANNEL_1, &frame, timeout);
+
+					// frame.image: {.width, .height, .pix_fmt, .dma-buf}
+					//show_frame_image(frame.image); // 伪代码
+					// frame.meta: {.count,
+					//              .meta_data[]={meta_id, type,
+					//                            union{int_value, str_value, ...}}}
+
+#ifdef PLATFORM_SIMULATOR
+					camera_action_image_display(&frame);
+					csi_camera_put_frame(&frame);
+#endif
+					dump_camera_meta(&frame);
+
+					csi_frame_release(&frame);
+				}
+				break;
+			}
+			default:
+				break;
+			}
+		default:
+			break;
+		}
+	}
+
+	// 取消订阅某一个event, 也可以直接调用csi_camera_destory_event,结束所有的订阅
+	subscribe.type = CSI_CAMERA_EVENT_TYPE_CHANNEL0;
+	subscribe.id = CSI_CAMERA_CHANNEL_EVENT_FRAME_READY |
+		       CSI_CAMERA_CHANNEL_EVENT_OVERFLOW;;
+	csi_camera_unsubscribe_event(event_handle, &subscribe);
+
+	subscribe.type = CSI_CAMERA_EVENT_TYPE_CHANNEL1;
+	subscribe.id = CSI_CAMERA_CHANNEL_EVENT_FRAME_READY |
+		       CSI_CAMERA_CHANNEL_EVENT_OVERFLOW;;
+	csi_camera_unsubscribe_event(event_handle, &subscribe);
+
+	subscribe.type = CSI_CAMERA_EVENT_TYPE_CAMERA;
+	subscribe.id = CSI_CAMERA_EVENT_WARNING | CSI_CAMERA_EVENT_ERROR;
+	csi_camera_unsubscribe_event(event_handle, &subscribe);
+
+	csi_camera_destory_event(event_handle);
+	csi_camera_channel_stop(cam_handle, CSI_CAMERA_CHANNEL_0);
+	csi_camera_channel_close(cam_handle, CSI_CAMERA_CHANNEL_0);
+	csi_camera_close(cam_handle);
+}
+
+static void dump_camera_meta(csi_frame_s *frame)
+{
+	int i;
+	if (frame->meta.type != CSI_META_TYPE_CAMERA)
+		return;
+
+	csi_camera_meta_s *meta_data = (csi_camera_meta_s *)frame->meta.data;
+	int meta_count = meta_data->count;
+	csi_camrea_meta_unit_s meta_unit;
+
+	for (i = 0; i < meta_count; i++) {
+		csi_camera_frame_get_meta_unit(
+			&meta_unit, meta_data, CSI_CAMERA_META_ID_FRAME_ID);
+		printf("meta_id=%d, meta_type=%d, meta_value=%d",
+		       meta_unit.id, meta_unit.type, meta_unit.int_value);
+	}
+}
+

+ 302 - 0
examples/camera/camera_demo3.c

@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <curses.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define LOG_LEVEL 3
+#define LOG_PREFIX "camera_demo3"
+#include <syslog.h>
+
+#include "camera_manager.h"
+#include "param.h"
+#include "app_dialogs.h"
+#include "menu_process.h"
+
+cams_t *cam_session;
+
+WINDOW *menubar;
+WINDOW *messagebar;
+WINDOW *win_border;
+WINDOW *win_content;
+
+void init_curses()
+{
+	initscr();		/* init curses */
+
+	FILE *f = fopen("/dev/tty", "r+");
+	SCREEN *screen = newterm(NULL, f, f);
+	set_term(screen);
+
+	start_color();		/* color init, then init color pair */
+
+	init_pair(1, COLOR_WHITE,  COLOR_BLACK);
+	init_pair(2, COLOR_BLACK,  COLOR_WHITE);
+	init_pair(3, COLOR_RED,    COLOR_WHITE);
+	init_pair(4, COLOR_WHITE,  COLOR_BLUE);		// menu font
+	init_pair(5, COLOR_YELLOW, COLOR_BLACK);
+	init_pair(6, COLOR_GREEN,  COLOR_WHITE);
+	init_pair(7, COLOR_YELLOW, COLOR_WHITE);
+
+	curs_set(0);		/* Cursor mode: 0:hide/1:normal/2:hilight */
+	noecho();		/* Do not display on screen */
+	keypad(stdscr, TRUE);	/* allow keypad map */
+}
+
+void uninit_curses()
+{
+	echo();
+	endwin();
+}
+
+void draw_menubar(WINDOW *menubar)
+{
+	wbkgd(menubar, COLOR_PAIR(2));
+
+	for (int i = 0; i < atoi(param[0][0]); i++) {
+		wattron(menubar, COLOR_PAIR(3));
+		mvwprintw(menubar, 0, i * 14 + 2, "%1d.", i + 1);
+		wattroff(menubar, COLOR_PAIR(3));
+		mvwprintw(menubar, 0, i * 14 + 4, "%-12s", param[0][i + 1]);
+	}
+}
+
+WINDOW **draw_menu(int menu)
+{
+	int i, start_col;
+	WINDOW **items;
+	items = (WINDOW **)malloc((atoi(param[menu][0]) + 1) * sizeof(WINDOW *));
+	start_col = (menu - 1) * 14 + 2;
+	items[0] = newwin(atoi(param[menu][0]) + 2, MENU_ITEM_MAX_LEN+2, 3, start_col);
+	wbkgd(items[0], COLOR_PAIR(2));
+	box(items[0], ACS_VLINE, ACS_HLINE);
+	for (i = 1; i <= atoi(param[menu][0]); i++) {
+		items[i] = subwin(items[0], 1, MENU_ITEM_MAX_LEN, 3 + i, start_col + 1);
+		wprintw(items[i], "%s", param[menu][i]);
+	}
+	wbkgd(items[1], COLOR_PAIR(4));
+	wrefresh(items[0]);
+	return items;
+}
+
+void delete_menu(WINDOW **items, int count)
+{
+	int i;
+	for (i = 0; i < count; i++)
+		delwin(items[i]);
+	free(items);
+}
+
+int scroll_menu(WINDOW **items, int menu, int *menu_returned)
+{
+	int key, count, selected = 0;
+	count = atoi(param[menu][0]);
+	LOG_D("Active: menu=%d, item=%d\n", menu, selected);
+
+	while (1) {
+		key = getch();
+		if (key == KEY_DOWN || key == KEY_UP) {
+			wbkgd(items[selected + 1], COLOR_PAIR(2));
+
+			wnoutrefresh(items[selected + 1]);
+			if (key == KEY_DOWN)
+				selected = (selected + 1) % count;
+			else
+				selected = (selected + count - 1) % count;
+			wbkgd(items[selected + 1], COLOR_PAIR(4));
+			wnoutrefresh(items[selected + 1]);
+			doupdate();
+		} else if (key == KEY_LEFT || key == KEY_RIGHT) {
+			delete_menu(items, count + 1);
+			touchwin(stdscr);
+			refresh();
+			if (key == KEY_LEFT) {
+				menu -= 1;
+				if (menu <= 0) menu = atoi(param[0][0]);
+				items = draw_menu(menu);
+				*menu_returned = menu;
+				LOG_D("Active: menu=%d, item=%d\n", *menu_returned, selected);
+				return scroll_menu(items, menu, menu_returned);
+			}
+			if (key == KEY_RIGHT) {
+				menu += 1;
+				if (menu > atoi(param[0][0])) menu = 1;
+				items = draw_menu(menu);
+				*menu_returned = menu;
+				LOG_D("Active: menu=%d, item=%d\n", *menu_returned, selected);
+				return scroll_menu(items, menu, menu_returned);
+			}
+		} else if (key == ESCAPE || key == '0' || key == 'q') {
+			delete_menu(items, count + 1);
+			return -1;
+		} else if (key == ENTER) {
+			delete_menu(items, count + 1);
+			return selected;
+		}
+		LOG_D("Active: menu=%d, item=%d\n", *menu_returned, selected);
+	}
+}
+
+/* ss:     display string,
+ * status: 0:Normal, 1:OK, 2:Failed, 3:Warning */
+void message(char *ss, int status)
+{
+	int color_pair;
+	switch (status) {
+	case 1:
+		color_pair = 6; // GREEN:WHITE
+		break;
+	case 2:
+		color_pair = 3;	// RED:WHITE
+		break;
+	case 3:
+		color_pair = 7;	// YELLOW:WHITE
+		break;
+	default:
+		color_pair = 2;	// BLACK:WHITE
+		break;
+	};
+	wbkgd(messagebar, COLOR_PAIR(2));
+	wattron(messagebar, COLOR_PAIR(color_pair));
+	mvwprintw(messagebar, 0, 0, "%80s", " ");
+	mvwprintw(messagebar, 0, 1, "%s", ss);
+	wattroff(messagebar, COLOR_PAIR(color_pair));
+	wrefresh(messagebar);
+}
+
+void copyright()
+{
+	char *str[] = { "Copyright (C) 2021 Alibaba Group Holding Limited",
+			"Author: LuChongzhi, T-Head / IOT / OS Team",
+			"mailto:[chongzhi.lcz@alibaba-inc.com]"};
+
+	attron(A_UNDERLINE | COLOR_PAIR(1));
+	for (int i = 0; i < sizeof(str) / sizeof(char *); i++)
+		mvaddstr((WIN_ROWS - 2) / 2 + i, (WIN_COLS - strlen(str[0])) / 2, str[i]);
+
+	attroff(A_UNDERLINE | COLOR_PAIR(1));
+	refresh();
+}
+
+int main(int argc, char **argv)
+{
+	int ret = -1;
+	int key;
+	WINDOW **menu_items;
+
+	if (get_param(argv[0])) {
+		LOG_E("\n Open %s.conf failed!\n", argv[0]);
+		goto LAB_EXIT;
+	}
+
+	if (camera_create_session(&cam_session) != 0 || cam_session == NULL) {
+		LOG_E("camera_create_session() failed\n");
+		goto LAB_EXIT;
+	}
+
+	init_curses();
+
+	if (init_dialog(NULL)) {
+		fprintf(stderr, N_("Your display is too small to run Menuconfig!\n"));
+		fprintf(stderr, N_("It must be at least 19 lines by 80 columns.\n"));
+		goto LAB_EXIT_CURSES_INITED;
+	}
+
+	bkgd(COLOR_PAIR(1));	/* COLOR_WHITE, COLOR_BLACK */
+
+	/* set windows postion: (win, lines, cols, begin_y, begin_x) */
+	menubar = subwin(stdscr, 1, WIN_COLS, 1, 0);			/* Menu bar line */
+	messagebar = subwin(stdscr, 1, WIN_COLS, WIN_ROWS - 1, 0);	/* Bottom line */
+	win_border = subwin(stdscr, WIN_ROWS - 3, WIN_COLS, 2, 0);	/* Content win with border */
+	win_content = subwin(stdscr, WIN_ROWS - 5, WIN_COLS - 2, 3, 1);	/* Content win without border */
+
+	/* Set window title */
+	char str_title[81];
+	strcpy(str_title, "<<< CSI Camera Test Tool >>>");
+	wattron(stdscr, COLOR_PAIR(5));
+	mvwprintw(stdscr, 0, (80 - strlen(str_title)) / 2 - 1, "%s", str_title);
+	wattroff(stdscr, COLOR_PAIR(5));
+
+	/* Draw menu */
+	draw_menubar(menubar);
+	message("Use number key to choses menu. 'q' or '0' to Exit", 0);
+
+	/* Draw box border */
+	box(win_border, ACS_VLINE, ACS_HLINE);
+
+	/* Show copyright */
+	copyright();
+
+	refresh();
+
+	/* menu operate loop */
+	do {
+		key = wgetch(stdscr);
+		if (isdigit(key) && key > '0' && key <= atoi(param[0][0]) + '0') {
+			werase(messagebar);
+			wrefresh(messagebar);
+
+			int menu_init = key - '0';	// first press menu id
+			int menu_final = menu_init;	// return from scroll_menu
+			menu_items = draw_menu(menu_init);
+			int item_selected = scroll_menu(menu_items, menu_init, &menu_final);
+			LOG_D("menu_final=%d, selected_item=%d\n",
+				menu_final, item_selected);
+
+			switch(menu_final) {
+			case MENU_CAMERA:
+				menu_camera_process(item_selected);
+				break;
+			case MENU_CHANNEL:
+				menu_channel_process(item_selected);
+				break;
+			case MENU_EVENT_RUN:
+				menu_event_run_process(item_selected);
+				break;
+			default:
+				LOG_W("Not supported menu: %d\n", menu_final);
+				break;
+			}
+
+			if (item_selected == 13) {
+				LOG_D("Test dialog_inputbox\n");
+				dialog_inputbox("inputbox", "prompt", 16, 80,
+					"const char init");
+			}
+
+			touchwin(stdscr);
+			refresh();
+		} else if (key == KEY_RESIZE) {
+			box(win_border, ACS_VLINE, ACS_HLINE);
+			wrefresh(messagebar);
+		}
+	} while (key != 'q' && key != '0');
+
+	ret = 0;
+
+LAB_EXIT_WIN_CREATED:
+	delwin(win_content);
+	delwin(win_border);
+	delwin(menubar);
+	delwin(messagebar);
+
+LAB_EXIT_CURSES_INITED:
+	uninit_curses();
+
+LAB_EXIT_CAM_MGR_CREATED:
+	camera_destory_session(&cam_session);
+
+LAB_EXIT:
+	return ret;
+}
+

+ 11 - 0
examples/camera/camera_demo3.conf

@@ -0,0 +1,11 @@
+#
+#   格式为: 菜单号|项目个数|项目名称......
+#           菜单数量最大为10个
+#
+0|5|Camera|Channel|Event&Run|Capture|Help|
+1|5|List Cameras|Open Camera|Set Mode|Set Property|Close Camera|
+2|3|List Channels|Open Channel|Close Channel|
+3|2|Subscribe&Action|Start/Stop|
+4|4|menu41|menu42|menu43|menu44|
+5|2|menu51|menu52|
+6|1|menu61|

+ 59 - 0
examples/camera/camera_demo3_srcs/app_dialogs.h

@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __APP_DIALOGS_H__
+#define __APP_DIALOGS_H__
+
+#include <curses.h>
+#include <csi_camera_property.h>
+
+#include "dialog.h"
+#include "param.h"
+#include "camera_manager.h"
+
+extern cams_t *cam_session;	/* camera manager */
+
+/* curses window */
+#define WIN_COLS 100
+#define WIN_ROWS 40
+
+/* key defination */
+#define  ENTER 10
+#define  ESCAPE 27
+
+/* windoes created by main */
+extern WINDOW *menubar;
+extern WINDOW *messagebar;
+extern WINDOW *win_border;
+extern WINDOW *win_content;
+
+void message(char *ss, int status);
+
+int dialog_camera_list(void);
+int dialog_camera_open(void);
+int dialog_camera_set_mode(void);
+int dialog_camera_property_list(void);
+int dialog_camera_close(void);
+
+int dialog_camera_property_boolean(csi_camera_property_description_s *property);
+int dialog_camera_property_integer(csi_camera_property_description_s *property);
+int dialog_camera_property_enum(csi_camera_property_description_s *property);
+int dialog_camera_property_bitmask(csi_camera_property_description_s *property);
+
+int dialog_channel_list(void);
+int dialog_channel_select(csi_camera_channel_cfg_s **selected_chn, int action);
+int dialog_channel_open(csi_camera_channel_cfg_s *channel);
+
+int dialog_event_subscribe_action_list(camera_event_action_union_t **event_action);
+int dialog_event_subscribe_action_camera(camera_event_action_union_t *event_action);
+int dialog_event_subscribe_action_channel(camera_event_action_union_t *event_action);
+
+int dialog_channel_run(void);
+
+#endif /* __APP_DIALOGS_H__ */

+ 17 - 0
examples/camera/camera_demo3_srcs/camera_ops.c

@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+
+#define LOG_LEVEL 3
+#define LOG_PREFIX "camera_ops"
+#include <syslog.h>
+
+#include "camera_ops.h"
+

+ 18 - 0
examples/camera/camera_demo3_srcs/camera_ops.h

@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __CAMERA_OPS_H__
+#define __CAMERA_OPS_H__
+
+#include <stdio.h>
+#include <csi_camera.h>
+#include <camera_manager.h>
+
+
+#endif /* __CAMERA_OPS_H__ */

+ 337 - 0
examples/camera/camera_demo3_srcs/checkbox.c

@@ -0,0 +1,337 @@
+/*
+ *  checklist.c -- implements the checklist box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *     Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension
+ *     Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+#include "app_dialogs.h"
+
+#define LOG_LEVEL 2
+#define LOG_PREFIX "camera_demo3"
+#include <syslog.h>
+
+
+static int list_width, check_x, item_x;
+
+/*
+ * Print list item
+ */
+static void print_item(WINDOW * win, int choice, int selected)
+{
+	int i;
+	char *list_item = malloc(list_width + 1);
+
+	strncpy(list_item, item_str(), list_width - item_x);
+	list_item[list_width - item_x] = '\0';
+
+	/* Clear 'residue' of last item */
+	wattrset(win, dlg.menubox.atr);
+	wmove(win, choice, 0);
+	for (i = 0; i < list_width; i++)
+		waddch(win, ' ');
+
+	wmove(win, choice, check_x);
+	wattrset(win, selected ? dlg.check_selected.atr
+		 : dlg.check.atr);
+	if (!item_is_tag(':'))
+		wprintw(win, "[%c]", item_is_tag('*') ? '*' : ' ');
+
+	wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr);
+	mvwaddch(win, choice, item_x, list_item[0]);
+	wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
+	waddstr(win, list_item + 1);
+	if (selected) {
+		wmove(win, choice, check_x + 1);
+		wrefresh(win);
+	}
+	free(list_item);
+}
+
+/*
+ * Print the scroll indicators.
+ */
+static void print_arrows(WINDOW * win, int choice, int item_no, int scroll,
+	     int y, int x, int height)
+{
+	wmove(win, y, x);
+
+	if (scroll > 0) {
+		wattrset(win, dlg.uarrow.atr);
+		waddch(win, ACS_UARROW);
+		waddstr(win, "[-]");
+	} else {
+		wattrset(win, dlg.menubox.atr);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+	}
+
+	y = y + height + 1;
+	wmove(win, y, x);
+
+	if ((height < item_no) && (scroll + choice < item_no - 1)) {
+		wattrset(win, dlg.darrow.atr);
+		waddch(win, ACS_DARROW);
+		waddstr(win, "[+]");
+	} else {
+		wattrset(win, dlg.menubox_border.atr);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+	}
+}
+
+/*
+ *  Display the termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected)
+{
+	int x = width / 2 - 11;
+	int y = height - 2;
+
+	print_button(dialog, gettext("Select"), y, x - 7, selected == 0);
+	print_button(dialog, gettext("Return"), y, x + 7, selected == 1);
+	print_button(dialog, gettext(" Help "), y, x + 21, selected == 2);
+
+	wmove(dialog, y, x - 7 + 1 + 14 * selected);
+	wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box with a list of options that can be turned on or off
+ * in the style of radiolist (only one option turned on at a time).
+ */
+int dialog_checkbox(const char *title, const char *prompt, int height,
+		     int width, int list_height, int init_choice)
+{
+	int i, x, y, box_x, box_y;
+	int key = 0, button = 0, choice = init_choice, scroll = 0, max_choice;
+	WINDOW *dialog, *list;
+
+do_resize:
+	if (WIN_ROWS < (height + CHECKLIST_HEIGTH_MIN)) {
+		LOG_E("WIN_ROWS(%d) < (height(%d) + CHECKLIST_HEIGTH_MIN(%d)\n",
+			WIN_ROWS, height, CHECKLIST_HEIGTH_MIN);
+		return -ERRDISPLAYTOOSMALL;
+	}
+	if (WIN_COLS < (width + CHECKLIST_WIDTH_MIN)) {
+		LOG_E("WIN_COLS(%d) < (width(%d) + CHECKLIST_WIDTH_MIN(%d)\n",
+			WIN_COLS, width, CHECKLIST_WIDTH_MIN);
+		return -ERRDISPLAYTOOSMALL;
+	}
+
+	max_choice = MIN(list_height, item_count());
+
+	/* center dialog box on screen */
+	x = (WIN_COLS - width) / 2;
+	y = (WIN_ROWS - height) / 2;
+
+	draw_shadow(stdscr, y, x, height, width);
+
+	dialog = newwin(height, width, y, x);
+	keypad(dialog, TRUE);
+
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
+	wattrset(dialog, dlg.border.atr);
+	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+	for (i = 0; i < width - 2; i++)
+		waddch(dialog, ACS_HLINE);
+	wattrset(dialog, dlg.dialog.atr);
+	waddch(dialog, ACS_RTEE);
+
+	print_title(dialog, title, width);
+
+	wattrset(dialog, dlg.dialog.atr);
+	print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+	list_width = width - 6;
+	box_y = height - list_height - 5;
+	box_x = (width - list_width) / 2 - 1;
+
+	/* create new window for the list */
+	list = subwin(dialog, list_height, list_width, y + box_y + 1,
+		      x + box_x + 1);
+
+	keypad(list, TRUE);
+
+	/* draw a box around the list items */
+	draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2,
+		 dlg.menubox_border.atr, dlg.menubox.atr);
+
+	/* Find length of longest item in order to center checklist */
+	check_x = 0;
+	item_foreach()
+		check_x = MAX(check_x, strlen(item_str()) + 4);
+	check_x = MIN(check_x, list_width);
+
+	check_x = (list_width - check_x) / 2 - 4;
+	item_x = check_x + 4;
+
+	if (choice >= list_height) {
+		scroll = choice - list_height + 1;
+		choice -= scroll;
+	}
+
+	/* Print the list */
+	for (i = 0; i < max_choice; i++) {
+		item_set(scroll + i);
+		print_item(list, i, i == choice);
+	}
+
+	print_arrows(dialog, choice, item_count(), scroll,
+		     box_y, box_x + check_x + 5, list_height);
+
+	print_buttons(dialog, height, width, 0);
+
+	wnoutrefresh(dialog);
+	wnoutrefresh(list);
+	doupdate();
+
+	while (key != KEY_ESC) {
+		key = wgetch(dialog);
+
+		for (i = 0; i < max_choice; i++) {
+			item_set(i + scroll);
+			if (toupper(key) == toupper(item_str()[0]))
+				break;
+		}
+
+		if (i < max_choice || key == KEY_UP || key == KEY_DOWN ||
+		    key == '+' || key == '-') {
+			if (key == KEY_UP || key == '-') {
+				if (!choice) {
+					if (!scroll)
+						continue;
+					/* Scroll list down */
+					if (list_height > 1) {
+						/* De-highlight current first item */
+						item_set(scroll);
+						print_item(list, 0, FALSE);
+						scrollok(list, TRUE);
+						wscrl(list, -1);
+						scrollok(list, FALSE);
+					}
+					scroll--;
+					item_set(scroll);
+					print_item(list, 0, TRUE);
+					print_arrows(dialog, choice, item_count(),
+						     scroll, box_y, box_x + check_x + 5, list_height);
+
+					wnoutrefresh(dialog);
+					wrefresh(list);
+
+					continue;	/* wait for another key press */
+				} else
+					i = choice - 1;
+			} else if (key == KEY_DOWN || key == '+') {
+				if (choice == max_choice - 1) {
+					if (scroll + choice >= item_count() - 1)
+						continue;
+					/* Scroll list up */
+					if (list_height > 1) {
+						/* De-highlight current last item before scrolling up */
+						item_set(scroll + max_choice - 1);
+						print_item(list,
+							    max_choice - 1,
+							    FALSE);
+						scrollok(list, TRUE);
+						wscrl(list, 1);
+						scrollok(list, FALSE);
+					}
+					scroll++;
+					item_set(scroll + max_choice - 1);
+					print_item(list, max_choice - 1, TRUE);
+
+					print_arrows(dialog, choice, item_count(),
+						     scroll, box_y, box_x + check_x + 5, list_height);
+
+					wnoutrefresh(dialog);
+					wrefresh(list);
+
+					continue;	/* wait for another key press */
+				} else
+					i = choice + 1;
+			}
+			if (i != choice) {
+				/* De-highlight current item */
+				item_set(scroll + choice);
+				print_item(list, choice, FALSE);
+				/* Highlight new item */
+				choice = i;
+				item_set(scroll + choice);
+				print_item(list, choice, TRUE);
+				wnoutrefresh(dialog);
+				wrefresh(list);
+			}
+			continue;	/* wait for another key press */
+		}
+		switch (key) {
+		case 'H':
+		case 'h':
+			button = 1;
+			/* fall-through */
+		case 'S':
+		case 's':
+		case ' ':
+		case '\n':
+			item_set(scroll + choice);
+			if (item_is_selected()) {
+				item_set_selected(0);
+			}
+			else {
+				item_set_selected(1);
+			}
+			delwin(list);
+			delwin(dialog);
+			return button;
+		case TAB:
+		case KEY_LEFT:
+		case KEY_RIGHT:
+			button = ((key == KEY_LEFT ? --button : ++button) < 0)
+			    ? 2 : (button > 2 ? 0 : button);
+
+			print_buttons(dialog, height, width, button);
+			wrefresh(dialog);
+			break;
+		case 'X':
+		case 'x':
+			key = KEY_ESC;
+			break;
+		case KEY_ESC:
+			key = on_key_esc(dialog);
+			break;
+		case KEY_RESIZE:
+			delwin(list);
+			delwin(dialog);
+			on_key_resize();
+			goto do_resize;
+		}
+
+		/* Now, update everything... */
+		doupdate();
+	}
+	delwin(list);
+	delwin(dialog);
+	return key;		/* ESC pressed */
+}

+ 355 - 0
examples/camera/camera_demo3_srcs/checklist.c

@@ -0,0 +1,355 @@
+/*
+ *  checklist.c -- implements the checklist box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *     Stuart Herbert - S.Herbert@sheffield.ac.uk: radiolist extension
+ *     Alessandro Rubini - rubini@ipvvis.unipv.it: merged the two
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+#include "app_dialogs.h"
+
+#define LOG_LEVEL 2
+#define LOG_PREFIX "camera_demo3"
+#include <syslog.h>
+
+
+static int list_width, check_x, item_x;
+
+/*
+ * Print list item
+ */
+static void print_item(WINDOW * win, int choice, int selected)
+{
+	int i;
+	char *list_item = malloc(list_width + 1);
+
+	strncpy(list_item, item_str(), list_width - item_x);
+	list_item[list_width - item_x] = '\0';
+
+	/* Clear 'residue' of last item */
+	wattrset(win, dlg.menubox.atr);
+	wmove(win, choice, 0);
+	for (i = 0; i < list_width; i++)
+		waddch(win, ' ');
+
+	wmove(win, choice, check_x);
+	wattrset(win, selected ? dlg.check_selected.atr
+		 : dlg.check.atr);
+	if (!item_is_tag(':'))
+		wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' ');
+
+	wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr);
+	mvwaddch(win, choice, item_x, list_item[0]);
+	wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
+	waddstr(win, list_item + 1);
+	if (selected) {
+		wmove(win, choice, check_x + 1);
+		wrefresh(win);
+	}
+	free(list_item);
+}
+
+/*
+ * Print the scroll indicators.
+ */
+static void print_arrows(WINDOW * win, int choice, int item_no, int scroll,
+	     int y, int x, int height)
+{
+	wmove(win, y, x);
+
+	if (scroll > 0) {
+		wattrset(win, dlg.uarrow.atr);
+		waddch(win, ACS_UARROW);
+		waddstr(win, "(-)");
+	} else {
+		wattrset(win, dlg.menubox.atr);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+	}
+
+	y = y + height + 1;
+	wmove(win, y, x);
+
+	if ((height < item_no) && (scroll + choice < item_no - 1)) {
+		wattrset(win, dlg.darrow.atr);
+		waddch(win, ACS_DARROW);
+		waddstr(win, "(+)");
+	} else {
+		wattrset(win, dlg.menubox_border.atr);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+	}
+}
+
+/*
+ *  Display the termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected,
+			  char *button_names[], int button_count)
+{
+	int x = width / 2 - 11;
+	int y = height - 2;
+
+	if (button_names == NULL) {
+		print_button(dialog, gettext("Select"), y, x, selected == 0);
+		print_button(dialog, gettext(" Help "), y, x + 14, selected == 1);
+	} else {
+		for (int i = 0; i < button_count; i++) {
+			print_button(dialog, gettext(button_names[i]), y, x + 14*i, selected == i);
+		}
+	}
+
+	wmove(dialog, y, x + 1 + 14 * selected);
+	wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box with a list of options that can be turned on or off
+ * in the style of radiolist (only one option turned on at a time).
+ */
+int dialog_checklist(const char *title, const char *prompt, int height,
+		     int width, int list_height, char *button_names[], int button_count)
+{
+	int i, x, y, box_x, box_y;
+	int key = 0, button = 0, choice = 0, scroll = 0, max_choice;
+	WINDOW *dialog, *list;
+
+	/* which item to highlight */
+	item_foreach() {
+		if (item_is_tag('X'))
+			choice = item_n();
+		if (item_is_selected()) {
+			choice = item_n();
+			break;
+		}
+	}
+
+do_resize:
+	if (WIN_ROWS < (height + CHECKLIST_HEIGTH_MIN)) {
+		LOG_E("WIN_ROWS(%d) < (height(%d) + CHECKLIST_HEIGTH_MIN(%d)\n",
+			WIN_ROWS, height, CHECKLIST_HEIGTH_MIN);
+		return -ERRDISPLAYTOOSMALL;
+	}
+	if (WIN_COLS < (width + CHECKLIST_WIDTH_MIN)) {
+		LOG_E("WIN_COLS(%d) < (width(%d) + CHECKLIST_WIDTH_MIN(%d)\n",
+			WIN_COLS, width, CHECKLIST_WIDTH_MIN);
+		return -ERRDISPLAYTOOSMALL;
+	}
+
+	max_choice = MIN(list_height, item_count());
+
+	/* center dialog box on screen */
+	x = (WIN_COLS - width) / 2;
+	y = (WIN_ROWS - height) / 2;
+
+	draw_shadow(stdscr, y, x, height, width);
+
+	dialog = newwin(height, width, y, x);
+	keypad(dialog, TRUE);
+
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
+	wattrset(dialog, dlg.border.atr);
+	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+	for (i = 0; i < width - 2; i++)
+		waddch(dialog, ACS_HLINE);
+	wattrset(dialog, dlg.dialog.atr);
+	waddch(dialog, ACS_RTEE);
+
+	print_title(dialog, title, width);
+
+	wattrset(dialog, dlg.dialog.atr);
+	print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+	list_width = width - 6;
+	box_y = height - list_height - 5;
+	box_x = (width - list_width) / 2 - 1;
+
+	/* create new window for the list */
+	list = subwin(dialog, list_height, list_width, y + box_y + 1,
+		      x + box_x + 1);
+
+	keypad(list, TRUE);
+
+	/* draw a box around the list items */
+	draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2,
+		 dlg.menubox_border.atr, dlg.menubox.atr);
+
+	/* Find length of longest item in order to center checklist */
+	check_x = 0;
+	item_foreach()
+		check_x = MAX(check_x, strlen(item_str()) + 4);
+	check_x = MIN(check_x, list_width);
+
+	check_x = (list_width - check_x) / 2 - 4;
+	item_x = check_x + 4;
+
+	if (choice >= list_height) {
+		scroll = choice - list_height + 1;
+		choice -= scroll;
+	}
+
+	/* Print the list */
+	for (i = 0; i < max_choice; i++) {
+		item_set(scroll + i);
+		print_item(list, i, i == choice);
+	}
+
+	print_arrows(dialog, choice, item_count(), scroll,
+		     box_y, box_x + check_x + 5, list_height);
+
+	print_buttons(dialog, height, width, 0, button_names, button_count);
+
+	wnoutrefresh(dialog);
+	wnoutrefresh(list);
+	doupdate();
+
+	while (key != KEY_ESC) {
+		key = wgetch(dialog);
+
+		for (i = 0; i < max_choice; i++) {
+			item_set(i + scroll);
+			if (toupper(key) == toupper(item_str()[0]))
+				break;
+		}
+
+		if (i < max_choice || key == KEY_UP || key == KEY_DOWN ||
+		    key == '+' || key == '-') {
+			if (key == KEY_UP || key == '-') {
+				if (!choice) {
+					if (!scroll)
+						continue;
+					/* Scroll list down */
+					if (list_height > 1) {
+						/* De-highlight current first item */
+						item_set(scroll);
+						print_item(list, 0, FALSE);
+						scrollok(list, TRUE);
+						wscrl(list, -1);
+						scrollok(list, FALSE);
+					}
+					scroll--;
+					item_set(scroll);
+					print_item(list, 0, TRUE);
+					print_arrows(dialog, choice, item_count(),
+						     scroll, box_y, box_x + check_x + 5, list_height);
+
+					wnoutrefresh(dialog);
+					wrefresh(list);
+
+					continue;	/* wait for another key press */
+				} else
+					i = choice - 1;
+			} else if (key == KEY_DOWN || key == '+') {
+				if (choice == max_choice - 1) {
+					if (scroll + choice >= item_count() - 1)
+						continue;
+					/* Scroll list up */
+					if (list_height > 1) {
+						/* De-highlight current last item before scrolling up */
+						item_set(scroll + max_choice - 1);
+						print_item(list,
+							    max_choice - 1,
+							    FALSE);
+						scrollok(list, TRUE);
+						wscrl(list, 1);
+						scrollok(list, FALSE);
+					}
+					scroll++;
+					item_set(scroll + max_choice - 1);
+					print_item(list, max_choice - 1, TRUE);
+
+					print_arrows(dialog, choice, item_count(),
+						     scroll, box_y, box_x + check_x + 5, list_height);
+
+					wnoutrefresh(dialog);
+					wrefresh(list);
+
+					continue;	/* wait for another key press */
+				} else
+					i = choice + 1;
+			}
+			if (i != choice) {
+				/* De-highlight current item */
+				item_set(scroll + choice);
+				print_item(list, choice, FALSE);
+				/* Highlight new item */
+				choice = i;
+				item_set(scroll + choice);
+				print_item(list, choice, TRUE);
+				wnoutrefresh(dialog);
+				wrefresh(list);
+			}
+			continue;	/* wait for another key press */
+		}
+		switch (key) {
+		case 'H':
+		case 'h':
+			button = 1;
+			/* fall-through */
+		case 'S':
+		case 's':
+		case ' ':
+		case '\n':
+			item_foreach()
+				item_set_selected(0);
+			item_set(scroll + choice);
+			item_set_selected(1);
+			delwin(list);
+			delwin(dialog);
+			return button;
+		case TAB:
+		case KEY_LEFT:
+		case KEY_RIGHT:
+			if (button_names != NULL || button_count > 0) {
+				button = ((key == KEY_LEFT ? --button : ++button) < 0)
+				    ? (button_count - 1) : (button > (button_count - 1)  ? 0 : button);
+			} else {
+				button = ((key == KEY_LEFT ? --button : ++button) < 0)
+				    ? 1 : (button > 1 ? 0 : button);
+			}
+
+			print_buttons(dialog, height, width, button, button_names, button_count);
+			wrefresh(dialog);
+			break;
+		case 'X':
+		case 'x':
+			key = KEY_ESC;
+			break;
+		case KEY_ESC:
+			key = on_key_esc(dialog);
+			break;
+		case KEY_RESIZE:
+			delwin(list);
+			delwin(dialog);
+			on_key_resize();
+			goto do_resize;
+		}
+
+		/* Now, update everything... */
+		doupdate();
+	}
+	delwin(list);
+	delwin(dialog);
+	return key;		/* ESC pressed */
+}

+ 276 - 0
examples/camera/camera_demo3_srcs/dialog.h

@@ -0,0 +1,276 @@
+/*
+ *  dialog.h -- common declarations for all dialog modules
+ *
+ *  AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __DIALOG_H__
+#define __DIALOG_H__
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+////////// lucz add begin
+#define N_(text) (text)
+////////// lucz add end
+
+#ifndef KBUILD_NO_NLS
+# include <libintl.h>
+#else
+# define gettext(Msgid) ((const char *) (Msgid))
+#endif
+
+#ifdef __sun__
+#define CURS_MACROS
+#endif
+#include <ncurses.h>
+
+/*
+ * Colors in ncurses 1.9.9e do not work properly since foreground and
+ * background colors are OR'd rather than separately masked.  This version
+ * of dialog was hacked to work with ncurses 1.9.9e, making it incompatible
+ * with standard curses.  The simplest fix (to make this work with standard
+ * curses) uses the wbkgdset() function, not used in the original hack.
+ * Turn it off if we're building with 1.9.9e, since it just confuses things.
+ */
+#if defined(NCURSES_VERSION) && defined(_NEED_WRAP) && !defined(GCC_PRINTFLIKE)
+#define OLD_NCURSES 1
+#undef  wbkgdset
+#define wbkgdset(w,p)		/*nothing */
+#else
+#define OLD_NCURSES 0
+#endif
+
+#define TR(params) _tracef params
+
+#define KEY_ESC 27
+#define TAB 9
+#define MAX_LEN 2048
+#define BUF_SIZE (10*1024)
+#define MIN(x,y) (x < y ? x : y)
+#define MAX(x,y) (x > y ? x : y)
+
+#ifndef ACS_ULCORNER
+#define ACS_ULCORNER '+'
+#endif
+#ifndef ACS_LLCORNER
+#define ACS_LLCORNER '+'
+#endif
+#ifndef ACS_URCORNER
+#define ACS_URCORNER '+'
+#endif
+#ifndef ACS_LRCORNER
+#define ACS_LRCORNER '+'
+#endif
+#ifndef ACS_HLINE
+#define ACS_HLINE '-'
+#endif
+#ifndef ACS_VLINE
+#define ACS_VLINE '|'
+#endif
+#ifndef ACS_LTEE
+#define ACS_LTEE '+'
+#endif
+#ifndef ACS_RTEE
+#define ACS_RTEE '+'
+#endif
+#ifndef ACS_UARROW
+#define ACS_UARROW '^'
+#endif
+#ifndef ACS_DARROW
+#define ACS_DARROW 'v'
+#endif
+
+/* error return codes */
+#define ERRDISPLAYTOOSMALL (KEY_MAX + 1)
+
+/*
+ *   Color definitions
+ */
+struct dialog_color {
+	chtype atr;	/* Color attribute */
+	int fg;		/* foreground */
+	int bg;		/* background */
+	int hl;		/* highlight this item */
+};
+
+struct subtitle_list {
+	struct subtitle_list *next;
+	const char *text;
+};
+
+struct dialog_info {
+	const char *backtitle;
+	struct subtitle_list *subtitles;
+	struct dialog_color screen;
+	struct dialog_color shadow;
+	struct dialog_color dialog;
+	struct dialog_color title;
+	struct dialog_color border;
+	struct dialog_color button_active;
+	struct dialog_color button_inactive;
+	struct dialog_color button_key_active;
+	struct dialog_color button_key_inactive;
+	struct dialog_color button_label_active;
+	struct dialog_color button_label_inactive;
+	struct dialog_color inputbox;
+	struct dialog_color inputbox_border;
+	struct dialog_color searchbox;
+	struct dialog_color searchbox_title;
+	struct dialog_color searchbox_border;
+	struct dialog_color position_indicator;
+	struct dialog_color menubox;
+	struct dialog_color menubox_border;
+	struct dialog_color item;
+	struct dialog_color item_selected;
+	struct dialog_color tag;
+	struct dialog_color tag_selected;
+	struct dialog_color tag_key;
+	struct dialog_color tag_key_selected;
+	struct dialog_color check;
+	struct dialog_color check_selected;
+	struct dialog_color uarrow;
+	struct dialog_color darrow;
+};
+
+/*
+ * Global variables
+ */
+extern struct dialog_info dlg;
+extern char dialog_input_result[];
+extern int saved_x, saved_y;		/* Needed in signal handler in mconf.c */
+
+/*
+ * Function prototypes
+ */
+
+/* item list as used by checklist and menubox */
+void item_reset(void);
+void item_make(const char *fmt, ...);
+void item_add_str(const char *fmt, ...);
+void item_set_tag(char tag);
+void item_set_int(int int_value);
+void item_set_data(void *p);
+void item_set_selected(int val);
+int item_activate_selected(void);
+int item_activate_selected_pos(void);
+void *item_data(void);
+char item_tag(void);
+int item_int(void);
+
+/* item list manipulation for lxdialog use */
+#define MAXITEMSTR 200
+struct dialog_item {
+	char str[MAXITEMSTR];	/* prompt displayed */
+	char tag;
+	void *data;	/* pointer to menu item - used by menubox+checklist */
+	int int_value;	/* the int value of the item */
+	int selected;	/* Set to 1 by dialog_*() function if selected. */
+};
+
+/* list of lialog_items */
+struct dialog_list {
+	struct dialog_item node;
+	struct dialog_list *next;
+};
+
+extern struct dialog_list *item_cur;
+extern struct dialog_list item_nil;
+extern struct dialog_list *item_head;
+
+int item_count(void);
+void item_set(int n);
+int item_n(void);
+const char *item_str(void);
+int item_is_selected(void);
+int item_is_tag(char tag);
+#define item_foreach() \
+	for (item_cur = item_head ? item_head: item_cur; \
+	     item_cur && (item_cur != &item_nil); item_cur = item_cur->next)
+
+/* generic key handlers */
+int on_key_esc(WINDOW *win);
+int on_key_resize(void);
+
+/* minimum (re)size values */
+#define CHECKLIST_HEIGTH_MIN 6	/* For dialog_checklist() */
+#define CHECKLIST_WIDTH_MIN 6
+#define INPUTBOX_HEIGTH_MIN 2	/* For dialog_inputbox() */
+#define INPUTBOX_WIDTH_MIN 2
+#define MENUBOX_HEIGTH_MIN 15	/* For dialog_menu() */
+#define MENUBOX_WIDTH_MIN 65
+#define TEXTBOX_HEIGTH_MIN 8	/* For dialog_textbox() */
+#define TEXTBOX_WIDTH_MIN 8
+#define YESNO_HEIGTH_MIN 4	/* For dialog_yesno() */
+#define YESNO_WIDTH_MIN 4
+#define WINDOW_HEIGTH_MIN 19	/* For init_dialog() */
+#define WINDOW_WIDTH_MIN 80
+
+int init_dialog(const char *backtitle);
+void set_dialog_backtitle(const char *backtitle);
+void set_dialog_subtitles(struct subtitle_list *subtitles);
+void end_dialog(int x, int y);
+void attr_clear(WINDOW * win, int height, int width, chtype attr);
+void dialog_clear(void);
+void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x);
+void print_button(WINDOW * win, const char *label, int y, int x, int selected);
+void print_title(WINDOW *dialog, const char *title, int width);
+void draw_box(WINDOW * win, int y, int x, int height, int width, chtype box,
+	      chtype border);
+void draw_shadow(WINDOW * win, int y, int x, int height, int width);
+
+int first_alpha(const char *string, const char *exempt);
+int dialog_yesno(const char *title, const char *prompt, int height, int width);
+int dialog_msgbox(const char *title, const char *prompt, int height,
+		  int width, int pause);
+
+
+typedef void (*update_text_fn)(char *buf, size_t start, size_t end, void
+			       *_data);
+int dialog_textbox(const char *title, char *tbuf, int initial_height,
+		   int initial_width, int *keys, int *_vscroll, int *_hscroll,
+		   update_text_fn update_text, void *data);
+int dialog_textbox_simple(const char *title, char *tbuf, int initial_height, int initial_width);
+
+int dialog_menu(const char *title, const char *prompt, int height, int width,
+		const void *selected, int selected_pos, int *s_scroll,
+		char *button_names[], int button_count);
+int dialog_checklist(const char *title, const char *prompt, int height,
+		     int width, int list_height, char *button_names[], int button_count);
+int dialog_checkbox(const char *title, const char *prompt, int height,
+		     int width, int list_height, int init_choice);
+int dialog_inputbox(const char *title, const char *prompt, int height,
+		    int width, const char *init);
+
+/*
+ * This is the base for fictitious keys, which activate
+ * the buttons.
+ *
+ * Mouse-generated keys are the following:
+ *   -- the first 32 are used as numbers, in addition to '0'-'9'
+ *   -- the lowercase are used to signal mouse-enter events (M_EVENT + 'o')
+ *   -- uppercase chars are used to invoke the button (M_EVENT + 'O')
+ */
+#define M_EVENT (KEY_MAX+1)
+
+#endif /* __DIALOG_H__ */
+

+ 80 - 0
examples/camera/camera_demo3_srcs/dialog_camera_close.c

@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <curses.h>
+
+#define LOG_LEVEL 3
+#define LOG_PREFIX "dlg_close_camera"
+#include <syslog.h>
+#include <camera_manager.h>
+
+#include "param.h"
+#include "app_dialogs.h"
+
+extern cams_t *cam_session;
+
+int dialog_camera_close(void)
+{
+	int ret_key = KEY_ESC;
+	int ret;
+
+	if (cam_session == NULL) {
+		LOG_E("cam_session is NULL\n");
+		return -1;
+	}
+
+	if (cam_session->camera_handle == NULL) {
+		LOG_I("The camera has not been opened yet\n");
+		dialog_textbox_simple("Infomation", "There's No camera opened yet", 10, 40);
+		return -1;
+	}
+
+
+	char str_buf[256];
+	int cam_id = cam_session->camera_id;
+	snprintf(str_buf, sizeof(str_buf),
+		"The camera below is to be closed:\n"
+		"\t id=%d \n\t name='%s' \n\t device='%s' \n\t bus='%s'\n",
+		cam_id,
+		cam_session->camera_infos.info[cam_id].camera_name,
+		cam_session->camera_infos.info[cam_id].device_name,
+		cam_session->camera_infos.info[cam_id].bus_info);
+
+	ret_key = dialog_yesno("Infomation", str_buf, 10, 50);
+	LOG_D("dialog_yesno() return %d\n", ret);
+
+	if (ret_key != 0) {	// 0 is the button position of 'yes'
+		LOG_D("close camera is canceled\n");
+		return 0;
+	}
+
+	ret = camera_close(cam_session);
+	if (ret != 0) {
+		LOG_E("camera_close() failed\n");
+		ret = -1;
+	}
+
+	snprintf(str_buf, sizeof(str_buf),
+		"The camera close %s: {%d, %s, %s, %s}\n",
+		(ret == 0) ? "OK" : "Failed",
+		cam_id,
+		cam_session->camera_infos.info[cam_id].camera_name,
+		cam_session->camera_infos.info[cam_id].device_name,
+		cam_session->camera_infos.info[cam_id].bus_info);
+
+	message(str_buf, (ret == 0) ? 1 : 2);
+	return ret;
+}
+

+ 90 - 0
examples/camera/camera_demo3_srcs/dialog_camera_list.c

@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <curses.h>
+
+#define LOG_LEVEL 3
+#define LOG_PREFIX "dlg_camera_list"
+#include <syslog.h>
+#include <camera_manager.h>
+
+#include "param.h"
+#include "app_dialogs.h"
+
+extern cams_t *cam_session;
+
+int dialog_camera_list(void)
+{
+	int ret_key = KEY_ESC;
+	int ret;
+
+	if (cam_session == NULL) {
+		LOG_E("cam_session is NULL\n");
+		return KEY_ESC;
+	}
+
+	/* Get camera list */
+	if (camera_query_list(cam_session) != 0) {
+		LOG_E("camera_query_list() failed\n");
+		return KEY_ESC;
+	}
+
+	char str_buf[1024] = "";
+	char str_item[256];
+
+	/* Prepare for checklist nodes */
+	csi_camera_infos_s *cam_infos = &cam_session->camera_infos;
+	for (int i = 0; i < cam_infos->count; i++) {
+		csi_camera_info_s *info = &(cam_infos->info[i]);
+		snprintf(str_item, sizeof(str_item),
+			"Camera[%d] info:\n"
+			"\t name = %s\n"
+			"\t dev  = %s\n"
+			"\t bus  = %s\n",
+			i,
+			info->camera_name,
+			info->device_name,
+			info->bus_info);
+		strcat(str_buf, str_item);
+
+
+		strcat(str_buf, "\t caps = ");
+		for (unsigned int j = 1; j < 0x80000000; j = j << 1) {
+			switch (info->capabilities & j) {
+			case CSI_CAMERA_CAP_VIDEO_CAPTURE:
+				strcat(str_buf,"VIDEO_CAPTURE | ");
+				break;
+			case CSI_CAMERA_CAP_META_CAPTURE:
+				strcat(str_buf, "META_CAPTURE | ");
+				break;
+			default:
+				if (info->capabilities & j) {
+					strcat(str_buf, "Unknown");
+				}
+				break;
+			}
+		}
+
+		strcat(str_buf, "\n\n");
+	}
+
+	dialog_textbox_simple("System Camera List",
+			str_buf,
+			20,	//int initial_height,
+			80);	//int initial_width
+
+	return ret;
+}
+

+ 156 - 0
examples/camera/camera_demo3_srcs/dialog_camera_open.c

@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <curses.h>
+
+#define LOG_LEVEL 3
+#define LOG_PREFIX "dlg_open_camera"
+#include <syslog.h>
+#include <camera_manager.h>
+
+#include "param.h"
+#include "app_dialogs.h"
+
+extern cams_t *cam_session;
+
+int dialog_camera_open(void)
+{
+	int ret_key = KEY_ESC;
+	int ret;
+
+	if (cam_session == NULL) {
+		LOG_E("cam_session is NULL\n");
+		return KEY_ESC;
+	}
+
+	if (cam_session->camera_handle != NULL) {
+		csi_camera_info_s *info =
+			&(cam_session->camera_infos.info[cam_session->camera_id]);
+		char textbox_content[256];
+		snprintf(textbox_content, sizeof(textbox_content),
+			"Please close camera below first:\n"
+			" camera: %s\n device:%s\n bus:%s\n",
+			info->camera_name, info->device_name, info->bus_info);
+		dialog_textbox("Error",
+				textbox_content,
+				10, //int initial_height,
+				40, //int initial_width,
+				(int []) {0}, //int *keys,
+				NULL,
+				NULL,
+				NULL, //update_text_fn update_text,
+				NULL /*void *data*/);
+		return 0;
+	}
+
+again:
+	item_reset();
+
+	if (camera_query_list(cam_session) != 0) {
+		LOG_E("camera_query_list() failed\n");
+		return KEY_ESC;
+	}
+
+	/* Prepare for checklist nodes */
+	csi_camera_infos_s *cam_infos = &cam_session->camera_infos;
+	for (int i = 0; i < cam_infos->count; i++) {
+		csi_camera_info_s *info = &(cam_infos->info[i]);
+		item_make("%-16s", info->camera_name);
+		item_add_str("%-12s %s",
+			info->device_name,
+			info->bus_info);
+
+		item_set_data(info);	// store cam_info pointer
+		if (i == cam_session->camera_id) {
+			item_set_tag('X');
+			item_set_selected(1);
+		} else {
+			item_set_tag(' ');
+			item_set_selected(0);
+		}
+	}
+
+	ret = dialog_checklist(
+		"Select Camera to open",	/* Title */
+		"Select the camera to open. "
+		"Press 'h' to get capabilities details",
+		CHECKLIST_HEIGTH_MIN + 10,
+		WIN_COLS - CHECKLIST_WIDTH_MIN - 16,
+		8,
+		NULL, 0);
+
+	int cam_id;
+	int selected = item_activate_selected();
+	LOG_D("ret=%d, selected=%s\n", ret, selected ? "true" : "false");
+	char str_buf[256];
+	switch (ret) {
+	case 0:				// item is selected
+		if (!selected)
+			break;
+
+		/* Show operation result */
+		cam_id = item_activate_selected_pos();
+		//char str_buf[256];
+		bool opened = (camera_open(cam_session, cam_id) == 0);
+		snprintf(str_buf, sizeof(str_buf),
+			"Open the below camera %s:\n"
+			"\t id=%d \n\t name='%s' \n\t device='%s' \n\t bus='%s'\n",
+			opened ? "OK" : "Failed",
+			cam_id,
+			cam_session->camera_infos.info[cam_id].camera_name,
+			cam_session->camera_infos.info[cam_id].device_name,
+			cam_session->camera_infos.info[cam_id].bus_info);
+
+		dialog_textbox_simple("Infomation", str_buf, 10, 40);
+		LOG_I("csi_camera_infos_s.info[%d] is opened %s\n",
+			cam_id, opened ? "OK" : "Failed");
+
+		/* Show message bar */
+		snprintf(str_buf, sizeof(str_buf),
+			"The camera open %s: {%d, %s, %s, %s}\n",
+			opened ? "OK" : "Failed",
+			cam_id,
+			cam_session->camera_infos.info[cam_id].camera_name,
+			cam_session->camera_infos.info[cam_id].device_name,
+			cam_session->camera_infos.info[cam_id].bus_info);
+
+		message(str_buf, opened ? 1 : 2);
+
+		break;
+	case 1:				// need help
+		cam_id = item_n();
+		//char str_buf[256];
+		snprintf(str_buf, sizeof(str_buf),
+			"Camera info:\n"
+			"\t id=%d \n\t name='%s' \n\t device='%s' \n\t bus='%s'\n",
+			cam_id,
+			cam_session->camera_infos.info[cam_id].camera_name,
+			cam_session->camera_infos.info[cam_id].device_name,
+			cam_session->camera_infos.info[cam_id].bus_info);
+
+		dialog_textbox_simple("Infomation", str_buf, 10, 40);
+		goto again;
+	case KEY_ESC:			// specific KEY
+		break;
+	case -ERRDISPLAYTOOSMALL:	// error
+	default:
+		LOG_W("Oops? why return ret=%d\n", ret);
+		break;
+	}
+
+	LOG_D("ret=%d\n", ret);
+	return 0;
+}
+

+ 101 - 0
examples/camera/camera_demo3_srcs/dialog_camera_property_bitmask.c

@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <curses.h>
+
+#define LOG_LEVEL 3
+#define LOG_PREFIX "dlg_prop_enum"
+#include <syslog.h>
+#include <camera_manager.h>
+#include <csi_camera_platform_spec.h>
+#include <camera_string.h>
+
+#include "param.h"
+#include "app_dialogs.h"
+
+extern cams_t *cam_session;
+
+int dialog_camera_property_bitmask(csi_camera_property_description_s *property)
+{
+	int ret_key = KEY_ESC;
+
+	if (property == NULL) {
+		LOG_W("property is NULL\n");
+		return KEY_ESC;
+	}
+
+	char *title = property->name;
+	char *prompt = "Please set camera property";
+	int item_pos = 0;
+
+again:
+	item_reset();
+
+	const camera_spec_bitmasks_t *bitmasks_array = camera_spec_get_bitmask_array(property->id);
+	if (bitmasks_array == NULL)
+		return KEY_ESC;
+
+	for (int i = 0; i < bitmasks_array->count; i++) {
+		item_make("bit-%02d: %s", bitmasks_array->bitmask[i],
+			camera_string_bitmask_name(property->id, bitmasks_array->bitmask[i]));
+		item_add_str("%s",
+			(bitmasks_array->bitmask[i] & property->default_value.enum_value) ? " (default)" : "");
+
+		if (bitmasks_array->bitmask[i] & property->value.enum_value)	{
+			item_set_selected(1);
+			item_set_tag('*');
+		}
+		else {
+			item_set_selected(0);
+			item_set_tag(' ');
+		}
+	}
+
+	int list_height = MIN(bitmasks_array->count + 1, 8);
+	ret_key = dialog_checkbox(
+		title, prompt,
+		CHECKLIST_HEIGTH_MIN + list_height + 2,
+		WIN_COLS - CHECKLIST_WIDTH_MIN - 32,
+		list_height, item_pos);
+
+	LOG_D("dialog_checkbox() ret_key=%d\n", ret_key);
+	if (ret_key == KEY_ESC) {
+		return KEY_ESC;
+	} else if (ret_key == 0) {/* select */
+		item_pos = item_n();
+		int bitmask_value = bitmasks_array->bitmask[item_n()];
+		if (item_is_selected()) {
+			property->value.bitmask_value |= bitmask_value;
+		} else {
+			property->value.bitmask_value &= ~bitmask_value;
+		}
+
+		int enum_id = bitmasks_array->bitmask[item_n()];
+		LOG_D("%s item: pos=%d, enum=%d-%s, bitmask_value=%08x\n",
+			item_is_selected() ? "Select" : "Unselect",
+ 			item_n(), enum_id,
+			camera_string_bitmask_name(property->id, enum_id),
+			property->value.bitmask_value);
+		goto again;
+		return ret_key;
+	} else if (ret_key == 1) {/* help */
+		LOG_W("Help does not support yet\n");
+		return ret_key;
+	} else {
+		LOG_E("Unknown return value: %d\n", ret_key);
+		return KEY_ESC;
+	}
+}
+

+ 88 - 0
examples/camera/camera_demo3_srcs/dialog_camera_property_boolean.c

@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <curses.h>
+
+#define LOG_LEVEL 3
+#define LOG_PREFIX "dlg_prop_boolean"
+#include <syslog.h>
+
+#include "param.h"
+#include "app_dialogs.h"
+#include <camera_manager.h>
+
+extern cams_t *cam_session;
+
+int dialog_camera_property_boolean(csi_camera_property_description_s *property)
+{
+	int ret_key = KEY_ESC;
+
+	if (property == NULL) {
+		LOG_W("property is NULL\n");
+		return KEY_ESC;
+	}
+
+	item_reset();
+	char *title = property->name;
+	char *prompt = "Please set camera property";
+
+	item_reset();
+
+	item_make("true");
+	if (property->default_value.bool_value)
+		item_add_str("(default)");
+	if (property->value.bool_value) {
+		item_set_tag('X');
+		item_set_selected(1);
+	} else {
+		item_set_tag(' ');
+		item_set_selected(0);
+	}
+
+	item_make("false");
+	if (!property->default_value.bool_value)
+		item_add_str(" (default)");
+	if (!property->value.bool_value) {
+		item_set_tag('X');
+		item_set_selected(1);
+	} else {
+		item_set_tag(' ');
+		item_set_selected(0);
+	}
+
+	ret_key = dialog_checklist(
+		title, prompt,
+		CHECKLIST_HEIGTH_MIN + 4,
+		WIN_COLS - CHECKLIST_WIDTH_MIN - 32,
+		2,
+		NULL, 0);
+
+	LOG_D("dialog_checklist() ret_key=%d\n", ret_key);
+	if (ret_key == KEY_ESC) {
+		return KEY_ESC;
+	} else if (ret_key == 0) {/* select */
+		LOG_D("select item: %d, means '%s'\n", item_n(),
+			(item_n() == 0) ? "true" : "false");
+		property->value.bool_value = (item_n() == 0) ? true : false;
+		return ret_key;
+	} else if (ret_key == 1) {/* help */
+		LOG_W("Help does not support yet\n");
+		return ret_key;
+	} else {
+		LOG_E("Unknown return value: %d\n", ret_key);
+		return KEY_ESC;
+	}
+}
+

+ 95 - 0
examples/camera/camera_demo3_srcs/dialog_camera_property_enum.c

@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define LOG_LEVEL 3
+#define LOG_PREFIX "dlg_prop_enum"
+#include <syslog.h>
+
+#include <curses.h>
+#include <csi_camera_platform_spec.h>
+#include <camera_manager.h>
+#include <camera_string.h>
+
+#include "param.h"
+#include "app_dialogs.h"
+
+extern cams_t *cam_session;
+
+int dialog_camera_property_enum(csi_camera_property_description_s *property)
+{
+	int ret_key = KEY_ESC;
+
+	if (property == NULL) {
+		LOG_W("property is NULL\n");
+		return KEY_ESC;
+	}
+
+	item_reset();
+	char *title = property->name;
+	char *prompt = "Please set camera property";
+
+	item_reset();
+
+	const camera_spec_enums_s *enums_array = camera_spec_get_enum_array(property->id);
+	if (enums_array == NULL)
+		return KEY_ESC;
+
+	for (int i = 0; i < enums_array->count; i++) {
+		item_make("%d-%s",
+			enums_array->enums[i],
+			camera_string_enum_name(property->id, enums_array->enums[i]));
+		item_add_str("%s",
+			(enums_array->enums[i] == property->default_value.enum_value) ? " (default)" : "");
+
+		if (enums_array->enums[i] == property->value.enum_value)	{
+			item_set_selected(1);
+			item_set_tag('X');
+		}
+		else {
+			item_set_selected(0);
+			item_set_tag(' ');
+		}
+	}
+
+	int list_height = MIN(enums_array->count + 1, 8);
+	ret_key = dialog_checklist(
+		title, prompt,
+		CHECKLIST_HEIGTH_MIN + list_height + 2,
+		WIN_COLS - CHECKLIST_WIDTH_MIN - 32,
+		list_height,
+		NULL, 0);
+
+	LOG_D("dialog_checklist() ret_key=%d\n", ret_key);
+	if (ret_key == KEY_ESC) {
+		return KEY_ESC;
+	} else if (ret_key == 0) {/* select */
+		if (!item_is_selected())
+			return KEY_ESC;
+
+		int enum_id = enums_array->enums[item_n()];
+		LOG_D("select item: pos=%d, enum=%d-%s\n",
+ 			item_n(), enum_id,
+			camera_string_enum_name(property->id, enum_id));
+		property->value.enum_value = enum_id;
+		return ret_key;
+	} else if (ret_key == 1) {/* help */
+		LOG_W("Help does not support yet\n");
+		return ret_key;
+	} else {
+		LOG_E("Unknown return value: %d\n", ret_key);
+		return KEY_ESC;
+	}
+}
+

+ 73 - 0
examples/camera/camera_demo3_srcs/dialog_camera_property_integer.c

@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <curses.h>
+
+#define LOG_LEVEL 3
+#define LOG_PREFIX "dlg_prop_int"
+#include <syslog.h>
+#include <camera_manager.h>
+
+#include "param.h"
+#include "app_dialogs.h"
+
+extern cams_t *cam_session;
+extern char dialog_input_result[MAX_LEN + 1];
+
+int dialog_camera_property_integer(csi_camera_property_description_s *property)
+{
+	int ret_key = KEY_ESC;
+
+	if (property == NULL) {
+		LOG_W("property is NULL\n");
+		return KEY_ESC;
+	}
+
+	char title[64];
+	snprintf(title, sizeof(title), "Camera %s setting", property->name);
+
+	char prompt[64];
+	snprintf(prompt, sizeof(prompt), "value range should be: [%d, %d], step %d",
+		property->minimum, property->maximum, property->step);
+
+	char str_value[32];
+	snprintf(str_value, sizeof(str_value), "%d", property->value.int_value);
+
+again:
+	curs_set(1);
+	ret_key = dialog_inputbox(title, prompt, 10, 50, str_value);
+	curs_set(0);
+
+	if (ret_key == KEY_ESC || ret_key == 1)
+		return KEY_ESC;
+
+	/* can't be empty */
+	if (strlen(dialog_input_result) == 0) {
+		goto again;
+	}
+
+	/* value check, reset if invalid */
+	int value = atoi(dialog_input_result);
+	if (value < property->minimum || value > property->maximum ||
+	    ((value - property->minimum) % property->step != 0)) {
+		LOG_W("%s\n", prompt);
+		goto again;
+	}
+
+	/* accept value, set into property */
+	property->value.int_value = value;
+	return 0;
+}
+

+ 418 - 0
examples/camera/camera_demo3_srcs/dialog_camera_property_list.c

@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define LOG_LEVEL 3
+#define LOG_PREFIX "dlg_prop_list"
+#include <syslog.h>
+
+#include <curses.h>
+#include <camera_manager.h>
+#include <camera_string.h>
+#include "param.h"
+#include "app_dialogs.h"
+
+#include <csi_camera_property.h>
+#include <csi_camera_platform_spec.h>
+
+extern cams_t *cam_session;
+
+//#define USE_DUMMY_DESC
+
+#ifdef USE_DUMMY_DESC
+csi_camera_property_description_s property_hflip = {
+	CSI_CAMERA_PID_HFLIP, CSI_CAMERA_PROPERTY_TYPE_BOOLEAN, "horizon flip",
+	/*min, max , step, def, value, flag, res[2]*/
+	0,     1,    1,   {.bool_value=true},   {.bool_value=false},    0,    {0, 0}
+};
+
+csi_camera_property_description_s property_rotate = {
+	CSI_CAMERA_PID_ROTATE, CSI_CAMERA_PROPERTY_TYPE_INTEGER, "rotate",
+	/*min, max, step, def, value, flag, res[2]*/
+	0,     270,    90,   {.int_value=0},   {.int_value=90},    0,    {0, 0}
+};
+
+csi_camera_property_description_s property_exposure_mode = {
+	CSI_CAMERA_PID_EXPOSURE_MODE, CSI_CAMERA_PROPERTY_TYPE_ENUM, "exposure mode",
+	/*min, max, step, def, value, flag, res[2]*/
+	0,     0,    0,   {.enum_value=CSI_CAMERA_EXPOSURE_MODE_AUTO},   {.enum_value=CSI_CAMERA_EXPOSURE_SHUTTER_PRIORITY},    0,    {0, 0}
+};
+
+csi_camera_property_description_s property_3a_lock = {
+	CSI_CAMERA_PID_3A_LOCK, CSI_CAMERA_PROPERTY_TYPE_BITMASK, "3A LOCK",
+	1, 4, 2, {.bitmask_value = 3}, {.bitmask_value = 2}, 0, {0, 0}
+};
+#endif
+
+struct desc_list {
+	csi_camera_property_description_s desc;
+	struct desc_list *next;
+};
+
+struct desc_list *desc_head = NULL;
+struct desc_list *desc_cur = NULL;
+struct desc_list  desc_nil;
+
+static void desc_list_reset(void)
+{
+	struct desc_list *p, *next;
+
+	for (p = desc_head; p && (p != &desc_nil); p = next) {
+        next = p->next;
+		free(p);
+	}
+	desc_head = NULL;
+	desc_cur = &desc_nil;
+}
+
+static void desc_list_add(csi_camera_property_description_s *desc)
+{
+	struct desc_list *p = malloc(sizeof(*p));
+	memcpy(p, desc, sizeof(*desc));
+
+	if (desc_head)
+		desc_cur->next = p;
+	else
+		desc_head = p;
+	desc_cur = p;
+	p->next = &desc_nil;
+}
+
+static void init_camera_property_items(void)
+{
+#ifdef USE_DUMMY_DESC
+	desc_list_add(&property_hflip);
+	desc_list_add(&property_rotate);
+	desc_list_add(&property_exposure_mode);
+	desc_list_add(&property_3a_lock);
+#else
+	csi_camera_property_description_s desc;
+
+	desc.id = CSI_CAMERA_PID_HFLIP;
+	while (!camera_query_property(cam_session, &desc)) {
+		//LOG_D("Get desc:%s\n", desc.name);
+
+		desc_list_add(&desc);
+
+		desc.id |= CSI_CAMERA_FLAG_NEXT_CTRL;
+	}
+#endif
+}
+
+static void uninit_camera_property_items(void)
+{
+	desc_list_reset();
+}
+
+static int fill_camera_property_items(void)
+{
+	struct desc_list *node;
+	for (node = desc_head; node && (node != &desc_nil); node = node->next) {
+		csi_camera_property_description_s *desc = &(node->desc);
+		char item_name[64];
+		char item_value[64];
+
+		switch (desc->type) {
+		case (CSI_CAMERA_PROPERTY_TYPE_INTEGER):
+			snprintf(item_name, sizeof(item_name), "%-16s:%10s", desc->name, "INTEGER: ");
+			snprintf(item_value, sizeof(item_value), "(%d)", desc->value.int_value);
+			break;
+		case (CSI_CAMERA_PROPERTY_TYPE_BOOLEAN):
+			snprintf(item_name, sizeof(item_name), "%-16s:%10s", desc->name, "BOOLEAN: ");
+			snprintf(item_value, sizeof(item_value), "(%s)", desc->value.bool_value ? "true" : "false");
+			break;
+		case (CSI_CAMERA_PROPERTY_TYPE_ENUM):
+			snprintf(item_name, sizeof(item_name), "%-16s:%10s", desc->name, "ENUM: ");
+			snprintf(item_value, sizeof(item_value), "(%s)",
+				 camera_string_enum_name(desc->id, desc->value.enum_value));
+			break;
+		case (CSI_CAMERA_PROPERTY_TYPE_STRING):
+			snprintf(item_name, sizeof(item_name), "%-16s:%10s", desc->name, "STRING: ");
+			snprintf(item_value, sizeof(item_value), "(%s)", desc->value.str_value);
+			break;
+		case (CSI_CAMERA_PROPERTY_TYPE_BITMASK):
+			snprintf(item_name, sizeof(item_name), "%-16s:%10s", desc->name, "BITMASK: ");
+			snprintf(item_value, sizeof(item_value), "(%08x)", desc->value.bitmask_value);
+			break;
+		default:
+			LOG_E("error type!\n");
+			return -1;
+		}
+
+		item_make("%s", item_name);
+		item_add_str("%s  --->", item_value);
+		item_set_data(&(node->desc));
+		//LOG_D("fill %s\n", desc->name);
+	}
+
+	return 0;
+}
+
+static int get_property_diff_count(void)
+{
+	int diff_count = 0;
+	struct desc_list *node;
+	for (node = desc_head; node && (node != &desc_nil); node = node->next) {
+		//LOG_D("comparing '%s'\n", node->desc.name);
+		csi_camera_property_description_s desc;
+		desc.id = node->desc.id;
+		if (camera_query_property(cam_session, &desc) != 0) {
+			LOG_E("camera_query_property(%d), %s failed\n",
+				node->desc.id, node->desc.name);
+			continue;
+		}
+		if (memcmp(&(node->desc.value), &(desc.value), sizeof(desc.value)) == 0) {
+			//LOG_D("property '%s' is same\n", desc.name);
+			continue;
+		}
+		diff_count ++;
+	}
+	return diff_count;
+}
+
+/* return int: property count(rows) */
+static int get_diff_string(char *text, int length, int rows)
+{
+	int count = 0;
+	int total_len = 0;
+	int add_len;
+	text[0] = '\0';
+	strcat(text,"-------------------------------------------\n");
+
+	for (struct desc_list *node = desc_head;
+	     node && (node != &desc_nil); node = node->next) {
+		//LOG_D("comparing '%s'\n", node->desc.name);
+		csi_camera_property_description_s *desc = &(node->desc);
+
+		csi_camera_property_description_s device_desc;
+		device_desc.id = node->desc.id;
+		if (camera_query_property(cam_session, &device_desc) != 0) {
+			LOG_E("camera_query_property(%d), %s failed\n",
+				node->desc.id, node->desc.name);
+			continue;
+		}
+
+		if (memcmp(&(desc->value), &(device_desc.value), sizeof(desc->value)) == 0) {
+			continue;
+		}
+
+		LOG_D("property '%s' is diff\n", desc->name);
+
+		char item_name[64];
+		char item_value[64];
+
+		switch (desc->type) {
+		case (CSI_CAMERA_PROPERTY_TYPE_INTEGER):
+			snprintf(item_name, sizeof(item_name), "%-16s:%10s", desc->name, "INTEGER: ");
+			snprintf(item_value, sizeof(item_value), "(%d)", desc->value.int_value);
+			break;
+		case (CSI_CAMERA_PROPERTY_TYPE_BOOLEAN):
+			snprintf(item_name, sizeof(item_name), "%-16s:%10s", desc->name, "BOOLEAN: ");
+			snprintf(item_value, sizeof(item_value), "(%s)", desc->value.bool_value ? "true" : "false");
+			break;
+		case (CSI_CAMERA_PROPERTY_TYPE_ENUM):
+			snprintf(item_name, sizeof(item_name), "%-16s:%10s", desc->name, "ENUM: ");
+			snprintf(item_value, sizeof(item_value), "(%s)",
+				 camera_string_enum_name(desc->id, desc->value.enum_value));
+			break;
+		case (CSI_CAMERA_PROPERTY_TYPE_STRING):
+			snprintf(item_name, sizeof(item_name), "%-16s:%10s", desc->name, "STRING: ");
+			snprintf(item_value, sizeof(item_value), "(%s)", desc->value.str_value);
+			break;
+		case (CSI_CAMERA_PROPERTY_TYPE_BITMASK):
+			snprintf(item_name, sizeof(item_name), "%-16s:%10s", desc->name, "BITMASK: ");
+			snprintf(item_value, sizeof(item_value), "(%08x)", desc->value.bitmask_value);
+			break;
+		default:
+			LOG_E("error type!\n");
+			return -1;
+		}
+
+		if (count >= rows)
+			break;
+
+		add_len = strlen(item_name) + strlen(item_value) + 1;
+		if ((total_len + add_len) >= length) {
+			LOG_W("text buffer overflow\n");
+			break;
+		}
+
+		strcat(text, item_name);
+		strcat(text, item_value);
+		strcat(text, "\n");
+
+		total_len += add_len;
+		count++;
+	}
+	return count;
+}
+
+static int apply_property_setting(void)
+{
+	LOG_W("do apply camera property settings\n");
+	int diff_count = get_property_diff_count();
+	int ret;
+
+	// assemble property struct
+	csi_camera_properties_s properties;
+	csi_camera_property_s *property = malloc(diff_count * sizeof(csi_camera_property_s));
+	properties.count = diff_count;
+	properties.property = property;
+	int i = 0;
+
+	for (struct desc_list *node = desc_head;
+	     node && (node != &desc_nil); node = node->next) {
+		//LOG_D("comparing '%s'\n", node->desc.name);
+		csi_camera_property_description_s desc;
+		desc.id = node->desc.id;
+		if (camera_query_property(cam_session, &desc) != 0) {
+			LOG_E("camera_query_property(%d), %s failed\n",
+				node->desc.id, node->desc.name);
+			continue;
+		}
+		if (memcmp(&(node->desc.value), &(desc.value), sizeof(desc.value)) == 0) {
+			//LOG_D("property '%s' is same\n", desc.name);
+			continue;
+		}
+
+		LOG_D("property '%s' is different\n", desc.name);
+		property[i].id = node->desc.id;
+		property[i].type = node->desc.type;
+		memcpy(&(property[i].value), &(node->desc.value), sizeof(node->desc.value));
+
+		i++;
+	}
+
+	ret = camera_set_property(cam_session, &properties);
+	if (ret == 0)
+		LOG_O("camera_set_property() ok!\n");
+	else
+		LOG_E("camera_set_property() failed!\n");
+
+	free(property);
+	return ret;
+}
+
+int dialog_camera_property_list(void)
+{
+	int ret_key = KEY_ESC;
+	int ret = 0;
+
+	csi_camera_property_description_s *init_item = NULL;
+	csi_camera_property_description_s *selected_item;
+	init_camera_property_items();
+
+again:
+	item_reset();
+	if (fill_camera_property_items() != 0) {
+		LOG_E("fill_camera_property_items() failed\n");
+		ret = KEY_ESC;
+		goto exit;
+	}
+
+	int s_scroll = 0;
+	ret_key = dialog_menu("Camera Property Settings",
+		"Select the property, press Enter to change the property setting",
+		WIN_ROWS-2, WIN_COLS, init_item, -1, &s_scroll,	NULL, 0);
+	LOG_D("dialog_menu() ret_key=%d, s_scroll=%d\n", ret_key, s_scroll);
+
+	if (ret_key == KEY_ESC) {
+		ret = KEY_ESC;
+		goto exit;
+	} else if (ret_key == 1) {	/* Apply button */
+		char str_buf[1024];
+		int count = get_diff_string(str_buf, sizeof(str_buf), 32);
+		ret_key = dialog_yesno("Apply camera with new propertis below?", str_buf, 6 + count, 50);
+		if (ret_key != 0) {	// 0 is the button position of 'yes'
+			LOG_D("Apply camera property is canceled\n");
+			goto again;
+		}
+		ret = apply_property_setting();
+		LOG_I("apply_property_setting() %s\n", (ret==0) ? "OK" : "Failed");
+
+		snprintf(str_buf, sizeof(str_buf),
+			"Apply camera properties below %s:\n",
+			(ret == 0) ? "OK" : "Failed");
+
+		dialog_textbox_simple("Infomation", str_buf, 10, 40);
+
+		goto exit;
+	} else if (ret_key == 2) {	/* Cancel button */
+		// do nothing
+		ret = KEY_ESC;
+		goto exit;
+	}
+
+	/* else, Select button */
+	selected_item = (csi_camera_property_description_s *)item_data();
+
+	if (item_tag() == '-') {
+		init_item = NULL;
+		goto again;
+	}
+
+	csi_camera_property_description_s *item_property = item_data();
+	if (item_property == NULL) {
+		LOG_W("No item selected\n");
+		ret = KEY_ESC;
+		goto exit;
+	} else {
+		LOG_D("item '%s' selected\n", item_property->name);
+	}
+
+	switch (item_property->type) {
+	case CSI_CAMERA_PROPERTY_TYPE_INTEGER:
+		ret_key = dialog_camera_property_integer(selected_item);
+		if (ret != KEY_ESC) {
+			LOG_D("set property->value.int_value=%d\n",
+				selected_item->value.int_value);
+		}
+		break;
+	case CSI_CAMERA_PROPERTY_TYPE_BOOLEAN:
+		ret_key = dialog_camera_property_boolean(selected_item);
+		if (ret != KEY_ESC) {
+			LOG_D("set property.value.bool_value='%s'\n",
+				(selected_item->value.bool_value) ? "true" : "false");
+		}
+		break;
+	case CSI_CAMERA_PROPERTY_TYPE_ENUM:
+		ret_key = dialog_camera_property_enum(selected_item);
+		if (ret != KEY_ESC) {
+			LOG_D("set property.value.enum_value='%s'(%d)\n",
+				camera_string_enum_name(selected_item->id,
+						selected_item->value.enum_value),
+				selected_item->value.enum_value);
+		}
+		break;
+	case CSI_CAMERA_PROPERTY_TYPE_STRING:
+		break;
+	case CSI_CAMERA_PROPERTY_TYPE_BITMASK:
+		ret_key = dialog_camera_property_bitmask(selected_item);
+		if (ret != KEY_ESC) {
+			LOG_D("set property.value.enum_value=(%08x)\n",
+				selected_item->value.enum_value);
+		}
+		break;;
+	default:
+		LOG_E("Not supported property_hflip type\n");
+	}
+
+	init_item = item_property;
+	goto again;
+
+exit:
+	uninit_camera_property_items();
+	return ret;
+}
+

+ 151 - 0
examples/camera/camera_demo3_srcs/dialog_camera_set_mode.c

@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <curses.h>
+
+#define LOG_LEVEL 3
+#define LOG_PREFIX "dlg_set_mode"
+#include <syslog.h>
+#include <camera_manager.h>
+
+#include "param.h"
+#include "app_dialogs.h"
+
+extern cams_t *cam_session;
+
+int dialog_camera_set_mode(void)
+{
+	int ret_key = KEY_ESC;
+	int ret;
+
+	LOG_D("Test dialog_checklist\n");
+	if (cam_session == NULL) {
+		LOG_E("cam_session is NULL\n");
+		return KEY_ESC;
+	}
+
+	if (cam_session->camera_handle == NULL) {
+		LOG_I("The camera has not been opened yet\n");
+		dialog_textbox_simple("Infomation", "There's No camera opened yet", 10, 40);
+		return -1;
+	}
+
+again:
+	item_reset();
+
+	if (camera_get_modes(cam_session) != 0) {
+		LOG_E("camera_query_list() failed\n");
+		return KEY_ESC;
+	}
+
+	/* Prepare for checklist nodes */
+	csi_camera_modes_s *modes = &(cam_session->camera_modes);
+	for (int i = 0; i < modes->count; i++) {
+		char mode_desc[256];
+		item_make("mode-%02d: ", modes->modes[i].mode_id);
+		strncpy(mode_desc, modes->modes[i].description, sizeof(mode_desc));
+		mode_desc[60] = '\0';
+		item_add_str(mode_desc);
+		item_set_data(&modes->modes[i]);	// store cam_info pointer
+
+		if (cam_session->camera_mode_id == modes->modes[i].mode_id) {
+			item_set_tag('X');
+			item_set_selected(1);
+		} else {
+			item_set_tag(' ');
+			item_set_selected(0);
+		}
+	}
+
+	ret = dialog_checklist(
+		"Set Camera mode",	/* Title */
+		"Select the camera working mode."
+		"Press 'h' to get details",
+		CHECKLIST_HEIGTH_MIN + 10,
+		WIN_COLS - CHECKLIST_WIDTH_MIN - 16,
+		8,
+		NULL, 0);
+
+	int item_id;
+	int cam_id;
+	int mode_id;
+	int selected = item_activate_selected();
+	LOG_D("ret=%d, selected=%d\n", ret, selected);
+	char str_buf[256];
+	switch (ret) {
+	case 0:				// item is selected
+		if (!selected)
+			break;
+
+		/* Set camera mode */
+		item_id = item_n();	// selected item: modes->modes[item_id]
+		cam_id = cam_session->camera_id;
+		mode_id = modes->modes[item_id].mode_id;
+
+		ret = camera_set_mode(cam_session, mode_id);
+		if (ret != 0) {
+			LOG_E("camera_set_mode() failed\n");
+		}
+
+		//char str_buf[256];
+		snprintf(str_buf, sizeof(str_buf),
+			"Set the below camera:\n"
+			"\t id=%d \n\t name='%s' \n\t device='%s' \n\t bus='%s'\n"
+			"to be working mode:%d %s",
+			cam_id,
+			cam_session->camera_infos.info[cam_id].camera_name,
+			cam_session->camera_infos.info[cam_id].device_name,
+			cam_session->camera_infos.info[cam_id].bus_info,
+			mode_id,
+			(ret == 0) ? "OK" : "Failed");
+
+		dialog_textbox_simple("Infomation", str_buf, 10, 40);
+		LOG_I("csi_camera_infos_s.info[%d] is opened %s\n",
+			cam_id, (ret == 0) ? "OK" : "Failed");
+
+		cam_session->camera_mode_id = mode_id;
+
+		/* Show message bar */
+		snprintf(str_buf, sizeof(str_buf),
+			"Set camera(%d) to be mode: %d %s\n",
+			cam_id,	mode_id, (ret == 0) ? "OK" : "Failed");
+
+		message(str_buf, (ret == 0) ? 1 : 2);
+		break;
+	case 1:				// need help
+		cam_id = item_n();
+		//char str_buf[256];
+		snprintf(str_buf, sizeof(str_buf),
+			"Camera info:\n"
+			"\t id=%d \n\t name='%s' \n\t device='%s' \n\t bus='%s'\n",
+			cam_id,
+			cam_session->camera_infos.info[cam_id].camera_name,
+			cam_session->camera_infos.info[cam_id].device_name,
+			cam_session->camera_infos.info[cam_id].bus_info);
+
+		dialog_textbox_simple("Infomation", str_buf, 10, 40);
+		goto again;
+	case KEY_ESC:			// specific KEY
+		break;
+	case -ERRDISPLAYTOOSMALL:	// error
+	default:
+		LOG_W("Oops? why return ret=%d\n", ret);
+		break;
+	}
+
+	LOG_D("dialog_checklist() ret=%d\n", ret);
+	return 0;
+}
+

+ 90 - 0
examples/camera/camera_demo3_srcs/dialog_channel_list.c

@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define LOG_LEVEL 3
+#define LOG_PREFIX "dlg_chn_list"
+#include <syslog.h>
+
+#include <curses.h>
+
+#include <camera_manager.h>
+#include <camera_string.h>
+#include "app_dialogs.h"
+
+extern cams_t *cam_session;
+
+int dialog_channel_list(void)
+{
+	int ret_key = KEY_ESC;
+	int ret;
+
+	if (cam_session == NULL) {
+		LOG_E("cam_session is NULL\n");
+		return KEY_ESC;
+	}
+
+	/* Get camera list */
+	if (camera_channel_query_list(cam_session) != 0) {
+		LOG_E("camera_get_list() failed\n");
+		return KEY_ESC;
+	}
+
+	char title[64];
+	snprintf(title, sizeof(title), "Camera[%d] Channels List", cam_session->camera_id);
+
+	char text[256*CSI_CAMERA_CHANNEL_MAX_COUNT] = "";
+	char item[256];
+	char temp[128];
+
+	int valid_count = 0;
+	for (int i = CSI_CAMERA_CHANNEL_0; i < CSI_CAMERA_CHANNEL_MAX_COUNT; i++) {
+		csi_camera_channel_cfg_s *chn_cfg = &(cam_session->chn_cfg[i]);
+		if (chn_cfg->status == CSI_CAMERA_CHANNEL_INVALID)
+			continue;
+
+		if (valid_count > 0)
+			strcat(text, "\n");
+
+		snprintf(item, sizeof(item), "Channel[%d] info:\n", chn_cfg->chn_id);
+		strcat(text, item);
+
+		snprintf(item, sizeof(item), "\t Status : %s\n",
+			camera_string_chn_status(chn_cfg->status));
+		strcat(text, item);
+
+		snprintf(item, sizeof(item), "\t Capture: %s\n",
+			camera_string_chn_capture_types(chn_cfg->capture_type, temp));
+		strcat(text, item);
+
+		snprintf(item, sizeof(item), "\t Frame  : count=%d, type=%s\n",
+			chn_cfg->frm_cnt, camera_string_img_type(chn_cfg->img_type));
+		strcat(text, item);
+
+		snprintf(item, sizeof(item), "\t Image  : width=%d, height=%d, pix_fmt=%s\n",
+			chn_cfg->img_fmt.width, chn_cfg->img_fmt.height,
+			camera_string_pixel_format(chn_cfg->img_fmt.pix_fmt));
+		strcat(text, item);
+
+		snprintf(item, sizeof(item), "\t Meta   : %s\n",
+			camera_string_chn_meta_fields(chn_cfg->meta_fields, temp));
+		strcat(text, item);
+
+		valid_count++;
+	}
+
+	int height = MIN((valid_count * 7 + 4),  (WIN_ROWS - 6));
+	return dialog_textbox_simple(title, text, height, 80);
+}
+

+ 573 - 0
examples/camera/camera_demo3_srcs/dialog_channel_open.c

@@ -0,0 +1,573 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <curses.h>
+
+#define LOG_LEVEL 3
+#define LOG_PREFIX "dlg_prop_list"
+#include <syslog.h>
+#include <csi_camera_property.h>
+#include <csi_camera_platform_spec.h>
+#include <camera_manager.h>
+#include <camera_string.h>
+
+#include "param.h"
+#include "app_dialogs.h"
+
+extern cams_t *cam_session;
+
+static int fill_channel_config_items(csi_camera_channel_cfg_s *channel)
+{
+	char str_buf[128];
+	const char item_format[] = "%-14s";
+
+	item_make(item_format, "capture_type");
+	item_add_str(": (%s)  --->", camera_string_chn_capture_types(channel->capture_type, str_buf));
+	item_set_data(channel);
+
+	item_make(item_format, "Capture fields");
+	item_add_str(": (%s)  --->", camera_string_chn_meta_fields(channel->meta_fields, str_buf));
+	item_set_data(channel);
+
+	item_make(item_format, "Buffer count");
+	item_add_str(": (%d)  --->", channel->frm_cnt);
+	item_set_data(channel);
+
+	item_make(item_format, "Image width");
+	item_add_str(": (%d)  --->", channel->img_fmt.width);
+	item_set_data(channel);
+
+	item_make(item_format, "Image height");
+	item_add_str(": (%d)  --->", channel->img_fmt.height);
+	item_set_data(channel);
+
+	item_make(item_format, "Pixel format");
+	item_add_str(": (%s)  --->", camera_string_pixel_format(channel->img_fmt.pix_fmt));
+	item_set_data(channel);
+
+	item_make(item_format, "Buffer type");
+	item_add_str(": (%s)  --->", camera_string_img_type(channel->img_type));
+	item_set_data(channel);
+	return 0;
+}
+
+typedef enum channel_param {
+	CHANNEL_PARAM_CAPTURE_TYPE = 0,
+	CHANNEL_PARAM_META_FIELDS,
+	CHANNEL_PARAM_FRM_CNT,
+	CHANNEL_PARAM_IMG_WIDTH,
+	CHANNEL_PARAM_IMG_HEIGIT,
+	CHANNEL_PARAM_IMG_PIX_FMT,
+	CHANNEL_PARAM_IMG_TYPE,
+} channel_param_e;
+
+extern char dialog_input_result[MAX_LEN + 1];
+static int channel_config_integer(csi_camera_channel_cfg_s *channel, channel_param_e param)
+{
+	int ret_key = KEY_ESC;
+	char title[64];
+	char prompt[64] = "Please enter the appropriate number";
+	char str_value[32];
+
+	if (channel == NULL) {
+		LOG_W("channel is NULL\n");
+		return KEY_ESC;
+	}
+
+again:
+	switch (param) {
+	case CHANNEL_PARAM_FRM_CNT:
+		snprintf(title, sizeof(title), "Config Channel[%d] %s",
+			channel->chn_id, "Buffer Count");
+		snprintf(str_value, sizeof(str_value), "%d", channel->frm_cnt);
+		break;
+	case CHANNEL_PARAM_IMG_WIDTH:
+		snprintf(title, sizeof(title), "Config Channel[%d] %s",
+			channel->chn_id, "Image Width");
+		snprintf(str_value, sizeof(str_value), "%d", channel->img_fmt.width);
+		break;
+	case CHANNEL_PARAM_IMG_HEIGIT:
+		snprintf(title, sizeof(title), "Config Channel[%d] %s",
+			channel->chn_id, "Image Height");
+		snprintf(str_value, sizeof(str_value), "%d", channel->img_fmt.height);
+		break;
+	default:
+		break;
+	}
+
+	curs_set(1);
+	ret_key = dialog_inputbox(title, prompt, 9, 40, str_value);
+	curs_set(0);
+
+	if (ret_key == KEY_ESC || ret_key == 1)
+		return KEY_ESC;
+
+	/* can't be empty */
+	if (strlen(dialog_input_result) == 0) {
+		goto again;
+	}
+
+	/* value check, reset if invalid */
+	int value = atoi(dialog_input_result);
+	if (value <= 0){
+		goto again;
+	}
+
+	/* accept value, set into property */
+	switch (param) {
+	case CHANNEL_PARAM_FRM_CNT:
+		if (value > 100){	// filt unreasonable out
+			goto again;
+		}
+		channel->frm_cnt = value;
+		break;
+	case CHANNEL_PARAM_IMG_WIDTH:
+		if (value > (7680*2)){	// filt unreasonable out
+			goto again;
+		}
+		channel->img_fmt.width = value;
+		break;
+	case CHANNEL_PARAM_IMG_HEIGIT:
+		if (value > (4320*2)){	// filt unreasonable out
+			goto again;
+		}
+		channel->img_fmt.height = value;
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int channel_config_enum(csi_camera_channel_cfg_s *channel, channel_param_e param)
+{
+	int ret_key = KEY_ESC;
+	char title[64];
+	char prompt[64] = "Please select the appropriate enum item";
+	char str_value[32];
+	const camera_spec_enums_s *enums_array;
+
+	if (channel == NULL) {
+		LOG_W("channel is NULL\n");
+		return KEY_ESC;
+	}
+
+	item_reset();
+	switch (param) {
+	case CHANNEL_PARAM_IMG_PIX_FMT:
+		snprintf(title, sizeof(title), "Config Channel[%d] %s",
+			channel->chn_id, "Image Pixel Format");
+
+		enums_array = camera_spec_get_enum_array(CAMERA_SPEC_ENUM_CHANNEL_PIX_FMT);
+		if (enums_array == NULL) {
+			LOG_E("No enum array for CAMERA_SPEC_ENUM_CHN_PIX_FMT(%d)\n",
+				CAMERA_SPEC_ENUM_CHANNEL_PIX_FMT);
+			return KEY_ESC;
+		}
+
+		for (int i = 0; i < enums_array->count; i++) {
+			item_make("%d-%s", enums_array->enums[i],
+				camera_string_pixel_format(enums_array->enums[i]));
+			//item_add_str("");
+			if (channel->img_fmt.pix_fmt == enums_array->enums[i]) {
+				item_set_selected(1);
+				item_set_tag('X');
+			} else {
+				item_set_selected(0);
+				item_set_tag(' ');
+			}
+		}
+
+		break;
+	case CHANNEL_PARAM_IMG_TYPE:
+		snprintf(title, sizeof(title), "Config Channel[%d] %s",
+			channel->chn_id, "Image Buffer Type");
+
+		enums_array = camera_spec_get_enum_array(CAMERA_SPEC_ENUM_CHANNEL_IMG_TYPE);
+		if (enums_array == NULL) {
+			LOG_E("No enum array for CAMERA_SPEC_ENUM_CHN_IMG_TYPE(%08x)\n",
+				CAMERA_SPEC_ENUM_CHANNEL_IMG_TYPE);
+			return KEY_ESC;
+		}
+
+		for (int i = 0; i < enums_array->count; i++) {
+			item_make("%d-%s", i, camera_string_img_type(i));
+			//item_add_str("");
+			if (channel->img_type == enums_array->enums[i]) {
+				item_set_selected(1);
+				item_set_tag('X');
+			} else {
+				item_set_selected(0);
+				item_set_tag(' ');
+			}
+		}
+
+		break;
+	default:
+		return KEY_ESC;
+	}
+
+	int list_height = MIN(enums_array->count + 1, 8);
+	ret_key = dialog_checklist(
+		title, prompt,
+		CHECKLIST_HEIGTH_MIN + list_height + 2,
+		WIN_COLS - CHECKLIST_WIDTH_MIN - 32,
+		list_height,
+		NULL, 0);
+	LOG_D("dialog_checklist() ret_key=%d\n", ret_key);
+
+	if (ret_key == KEY_ESC) {
+		return KEY_ESC;
+	} else if (ret_key == 0) {	/* select */
+		if (!item_is_selected())
+			return KEY_ESC;
+
+		int enum_id = enums_array->enums[item_n()];
+
+		switch(param) {
+		case CHANNEL_PARAM_IMG_PIX_FMT:
+			LOG_D("select item: pos=%d, enum=%d:%s\n",
+				item_n(), enum_id, camera_string_pixel_format(enum_id));
+			channel->img_fmt.pix_fmt = enum_id;
+			break;
+		case CHANNEL_PARAM_IMG_TYPE:
+			LOG_D("select item: pos=%d, enum=%d:%s\n",
+				item_n(), enum_id, camera_string_img_type(enum_id));
+			channel->img_type = enum_id;
+			break;
+		default:
+			return KEY_ESC;
+		}
+		return ret_key;
+	} else if (ret_key == 1) {	/* help */
+		LOG_W("Help does not support yet\n");
+		return ret_key;
+	} else {
+		LOG_E("Unknown return value: %d\n", ret_key);
+		return KEY_ESC;
+	}
+
+	return 0;
+}
+
+static int channel_config_bitmsk_capture_type(csi_camera_channel_cfg_s *channel)
+{
+	int ret_key = KEY_ESC;
+	if (channel == NULL) {
+		LOG_W("channel is NULL\n");
+		return KEY_ESC;
+	}
+
+	char title[64];
+	char prompt[64] = "Please select the appropriate enum item";
+	int item_pos = 0;
+	snprintf(title, sizeof(title), "Config Channel[%d] Capture Types", channel->chn_id);
+	const camera_spec_bitmasks_t *bitmasks_array =
+		camera_spec_get_bitmask_array(CAMERA_SPEC_BITMAKS_CHANNEL_CAPTURE_TYPE);
+	if (bitmasks_array == NULL)
+			return KEY_ESC;
+
+again:
+	item_reset();
+	for (int i = 0; i < bitmasks_array->count; i++) {
+		item_make("bit-%02d: %s", bitmasks_array->bitmask[i],
+			camera_string_capture_type(bitmasks_array->bitmask[i], true));
+		//item_add_str("");
+
+		if (bitmasks_array->bitmask[i] & channel->capture_type)	{
+			item_set_selected(1);
+			item_set_tag('*');
+		}
+		else {
+			item_set_selected(0);
+			item_set_tag(' ');
+		}
+	}
+
+	int list_height = MIN(bitmasks_array->count + 1, 8);
+	ret_key = dialog_checkbox(
+		title, prompt,
+		CHECKLIST_HEIGTH_MIN + list_height + 2,
+		WIN_COLS - CHECKLIST_WIDTH_MIN - 32,
+		list_height, item_pos);
+
+	LOG_D("dialog_checkbox() ret_key=%d\n", ret_key);
+	if (ret_key == KEY_ESC) {
+		return KEY_ESC;
+	} else if (ret_key == 0) {/* select */
+		item_pos = item_n();
+		int bitmask_value = bitmasks_array->bitmask[item_n()];
+		if (item_is_selected()) {
+			channel->capture_type |= bitmask_value;
+		} else {
+			channel->capture_type &= ~bitmask_value;
+		}
+
+		int enum_id = bitmasks_array->bitmask[item_n()];
+		LOG_D("%s item: pos=%d, enum=%d-%s, bitmask_value=%08x\n",
+			item_is_selected() ? "Select" : "Unselect",
+ 			item_n(), enum_id,
+			camera_string_capture_type(enum_id, true),
+			channel->capture_type);
+		goto again;
+		return ret_key;
+	} else if (ret_key == 1) {/* help */
+		LOG_W("Help does not support yet\n");
+		return ret_key;
+	} else {
+		LOG_E("Unknown return value: %d\n", ret_key);
+		return KEY_ESC;
+	}
+}
+
+static int channel_config_bitmsk_meta_type(csi_camera_channel_cfg_s *channel)
+{
+	int ret_key = KEY_ESC;
+	if (channel == NULL) {
+		LOG_W("channel is NULL\n");
+		return KEY_ESC;
+	}
+
+	char title[64];
+	char prompt[64] = "Please select the appropriate enum item";
+	int item_pos = 0;
+	snprintf(title, sizeof(title), "Config Channel[%d] Meta Types", channel->chn_id);
+	const camera_spec_bitmasks_t *bitmasks_array =
+		camera_spec_get_bitmask_array(CAMERA_SPEC_BITMAKS_CHANNEL_META_TYPE);
+	if (bitmasks_array == NULL)
+			return KEY_ESC;
+
+again:
+	item_reset();
+	for (int i = 0; i < bitmasks_array->count; i++) {
+		item_make("bit-%02d: %s", bitmasks_array->bitmask[i],
+			camera_string_meta_field(bitmasks_array->bitmask[i], true));
+		//item_add_str("");
+
+		if (bitmasks_array->bitmask[i] & channel->meta_fields)	{
+			item_set_selected(1);
+			item_set_tag('*');
+		}
+		else {
+			item_set_selected(0);
+			item_set_tag(' ');
+		}
+	}
+
+	int list_height = MIN(bitmasks_array->count + 1, 8);
+	ret_key = dialog_checkbox(
+		title, prompt,
+		CHECKLIST_HEIGTH_MIN + list_height + 2,
+		WIN_COLS - CHECKLIST_WIDTH_MIN - 32,
+		list_height, item_pos);
+
+	LOG_D("dialog_checkbox() ret_key=%d\n", ret_key);
+	if (ret_key == KEY_ESC) {
+		return KEY_ESC;
+	} else if (ret_key == 0) {/* select */
+		item_pos = item_n();
+		int bitmask_value = bitmasks_array->bitmask[item_n()];
+		if (item_is_selected()) {
+			channel->meta_fields |= bitmask_value;
+		} else {
+			channel->meta_fields &= ~bitmask_value;
+		}
+
+		int enum_id = bitmasks_array->bitmask[item_n()];
+		LOG_D("%s item: pos=%d, enum=%d-%s, bitmask_value=%08x\n",
+			item_is_selected() ? "Select" : "Unselect",
+ 			item_n(), enum_id,
+			camera_string_meta_field(enum_id, true),
+			channel->meta_fields);
+		goto again;
+		return ret_key;
+	} else if (ret_key == 1) {/* help */
+		LOG_W("Help does not support yet\n");
+		return ret_key;
+	} else {
+		LOG_E("Unknown return value: %d\n", ret_key);
+		return KEY_ESC;
+	}
+}
+
+/* return int: property rows */
+static int get_diff_string(char *text, csi_camera_channel_cfg_s *channel)
+{
+	int count = 0;
+	int total_len = 0;
+	int add_len;
+	text[0] = '\0';
+
+	strcat(text,"-------------------------------------------\n");
+
+	char item_name[64];
+	char item_value[256];
+	char str_buf1[128];
+	char str_buf2[128];
+
+	if(cam_session->chn_cfg_tmp.capture_type != channel->capture_type) {
+		snprintf(item_name, sizeof(item_name), "%-14s", "capture type");
+		snprintf(item_value, sizeof(item_value), ": (%s) => (%s)\n",
+			camera_string_chn_capture_types(channel->capture_type, str_buf1),
+			camera_string_chn_capture_types(cam_session->chn_cfg_tmp.capture_type, str_buf2));
+		strcat(text, item_name);
+		strcat(text, item_value);
+		count++;
+	}
+
+	if(cam_session->chn_cfg_tmp.meta_fields != channel->meta_fields) {
+		snprintf(item_name, sizeof(item_name), "%-14s", "Meta fields");
+		snprintf(item_value, sizeof(item_value), ": (%s) =>\n\t\t    (%s)\n",
+			camera_string_chn_meta_fields(channel->meta_fields, str_buf1),
+			camera_string_chn_meta_fields(cam_session->chn_cfg_tmp.meta_fields, str_buf2));
+		strcat(text, item_name);
+		strcat(text, item_value);
+		count+=2;
+	}
+
+	if(cam_session->chn_cfg_tmp.frm_cnt != channel->frm_cnt) {
+		snprintf(item_name, sizeof(item_name), "%-14s", "buffer count");
+		snprintf(item_value, sizeof(item_value), ": (%d) => (%d)\n",
+			channel->frm_cnt, cam_session->chn_cfg_tmp.frm_cnt);
+		strcat(text, item_name);
+		strcat(text, item_value);
+		count++;
+	}
+
+	if(cam_session->chn_cfg_tmp.img_fmt.width != channel->img_fmt.width) {
+		snprintf(item_name, sizeof(item_name), "%-14s", "Image width");
+		snprintf(item_value, sizeof(item_value), ": (%d) => (%d)\n",
+			channel->img_fmt.width, cam_session->chn_cfg_tmp.img_fmt.width);
+		strcat(text, item_name);
+		strcat(text, item_value);
+		count++;
+	}
+
+	if(cam_session->chn_cfg_tmp.img_fmt.height != channel->img_fmt.height) {
+		snprintf(item_name, sizeof(item_name), "%-14s", "Image height");
+		snprintf(item_value, sizeof(item_value), ": (%d) => (%d)\n",
+			channel->img_fmt.height, cam_session->chn_cfg_tmp.img_fmt.height);
+		strcat(text, item_name);
+		strcat(text, item_value);
+		count++;
+	}
+
+	if(cam_session->chn_cfg_tmp.img_fmt.pix_fmt != channel->img_fmt.pix_fmt) {
+		snprintf(item_name, sizeof(item_name), "%-14s", "Pixel format");
+		snprintf(item_value, sizeof(item_value), ": (%s) => (%s)\n",
+			camera_string_pixel_format(channel->img_fmt.pix_fmt),
+			camera_string_pixel_format(cam_session->chn_cfg_tmp.img_fmt.pix_fmt));
+		strcat(text, item_name);
+		strcat(text, item_value);
+		count++;
+	}
+
+	if(cam_session->chn_cfg_tmp.img_type != channel->img_type) {
+		snprintf(item_name, sizeof(item_name), "%-14s", "Buffer type");
+		snprintf(item_value, sizeof(item_value), ": (%s) => (%s)\n",
+			camera_string_img_type(channel->img_type),
+			camera_string_img_type(cam_session->chn_cfg_tmp.img_type));
+		strcat(text, item_name);
+		strcat(text, item_value);
+		count++;
+	}
+
+	return count;
+}
+
+static int channel_open_internal(char *feedback)
+{
+	int ret = camera_channel_open(cam_session, &cam_session->chn_cfg_tmp);
+	if (ret != 0) {
+		LOG_E("camera_channel_open() failed, ret=%d\n", ret);
+	}
+
+	if (feedback) {
+		if (ret)
+			sprintf(feedback, "camera_channel_open() failed, ret=%d\n", ret);
+		else
+			sprintf(feedback, "camera_channel_open() OK\n");
+	}
+	return ret;
+}
+
+int dialog_channel_open(csi_camera_channel_cfg_s *channel)
+{
+	int ret_key = KEY_ESC;
+	int ret = 0;
+	char str_buf[1024];
+	int item_pos = 0;
+	csi_camera_channel_cfg_s *chn_tmp = &(cam_session->chn_cfg_tmp);
+	memcpy(chn_tmp, channel, sizeof(*chn_tmp));
+
+again:
+	item_reset();
+	if (fill_channel_config_items(chn_tmp) != 0) {
+		LOG_E("fill_channel_config_items() failed\n");
+		ret = KEY_ESC;
+		goto exit;
+	}
+
+	char *button_names[] = {"Config", " Open ", "Cancel"};
+
+	int s_scroll = 0;
+	snprintf(str_buf, sizeof(str_buf), "Config Camera[%d] - Channel[%d]",
+		cam_session->camera_id, chn_tmp->chn_id);
+	ret_key = dialog_menu(str_buf, "Select item, press Enter to config",
+		WIN_ROWS-2, WIN_COLS, NULL, item_pos, &s_scroll, button_names, 3);
+	item_pos = item_activate_selected_pos();
+	LOG_D("dialog_menu() ret_key=%d, item_pos=%d\n", ret_key, item_pos);
+
+	if (ret_key == 0) {		/* Select button */
+		if (item_pos == CHANNEL_PARAM_FRM_CNT ||
+		    item_pos == CHANNEL_PARAM_IMG_WIDTH ||
+		    item_pos == CHANNEL_PARAM_IMG_HEIGIT) {
+			channel_config_integer(chn_tmp, item_pos);
+		} else if (item_pos == CHANNEL_PARAM_IMG_PIX_FMT ||
+			   item_pos == CHANNEL_PARAM_IMG_TYPE) {
+			channel_config_enum(chn_tmp, item_pos);
+		} else if (item_pos == CHANNEL_PARAM_CAPTURE_TYPE) {
+			channel_config_bitmsk_capture_type(chn_tmp);
+		} else if (item_pos == CHANNEL_PARAM_META_FIELDS){
+			channel_config_bitmsk_meta_type(chn_tmp);
+		}
+		goto again;
+	} else if (ret_key == 1) {	/* Open button */
+		ret = channel_open_internal(str_buf);
+		LOG_I("%s\n", str_buf);
+		dialog_textbox_simple("Infomation", str_buf, 10, 40);
+
+		if (ret != 0) {
+			goto again;
+		}
+
+		goto exit;
+	} else if (ret_key == 2) {	/* Cancel button */
+		// do nothing
+		ret = KEY_ESC;
+		goto exit;
+	} else {
+		ret = KEY_ESC;
+		goto exit;
+	}
+
+	/* else, Select button */
+	goto again;
+
+exit:
+	return ret;
+}
+

+ 339 - 0
examples/camera/camera_demo3_srcs/dialog_channel_run.c

@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <curses.h>
+
+#define LOG_LEVEL 3
+#define LOG_PREFIX "dlg_chn_run"
+#include <syslog.h>
+#include <camera_manager.h>
+#include <camera_string.h>
+
+#include "param.h"
+#include "platform_action.h"
+#include "app_dialogs.h"
+
+extern cams_t *cam_session;
+
+#define _CHECK_SESSION_RETURN()				\
+	do {						\
+		if (session == NULL) {			\
+			LOG_E("session is NULL\n");	\
+			return -EPERM;			\
+		}					\
+	} while (0)
+
+static int do_camera_event_action(cams_t *session, csi_camera_event_s *event)
+{
+	_CHECK_SESSION_RETURN();
+	int ret = 0;
+
+	for (uint32_t i = 0; i < CSI_CAMERA_EVENT_MAX_COUNT; i++) {
+		camera_event_action_t *event_action =
+			&(session->camera_event_action[i].camera);
+		if (event_action->event != event->id)
+			continue;
+
+		LOG_D("Found camera action:%s\n",
+		      camera_string_camera_action(event_action->action));
+
+		if(event_action->action == CAMERA_ACTION_NONE) {
+			LOG_D("CHANNEL CAMERA_ACTION_NONE!\n");
+			continue;
+		}
+		if(event_action->action > (CAMERA_ACTION_LOG_PRINT|CAMERA_ACTION_CAPTURE_FRAME)) {
+			LOG_E("Unkonw camera event action: %d\n", event_action->action);
+			ret = -1;
+		}
+		for(uint32_t j = 0; j < CAMERA_ACTION_MAX_COUNT; j++) {
+			switch (event_action->action & 1 << j) {
+			case CAMERA_ACTION_LOG_PRINT:
+				LOG_D("CAMERA CAMERA_ACTION_LOG_PRINT\n");
+				if((event_action->event & 1 << i) == CSI_CAMERA_EVENT_WARNING) {
+					LOG_D("LOG_PRINT CSI_CAMERA_EVENT_WARNING\n");
+				} else if((event_action->event & 1 << i) == CSI_CAMERA_EVENT_ERROR) {
+					LOG_D("LOG PRINT CSI_CAMERA_EVENT_ERROR\n");
+				} else if((event_action->event & 1 << i) == CSI_CAMERA_EVENT_SENSOR_FIRST_IMAGE_ARRIVE) {
+					LOG_D("LOG PRINT CSI_CAMERA_EVENT_SENSOR_FIRST_IMAGE_ARRIVE\n");
+				} else if((event_action->event & 1 << i) == CSI_CAMERA_EVENT_ISP_3A_ADJUST_READY) {
+					LOG_D("LOG PRINT CSI_CAMERA_EVENT_ISP_3A_ADJUST_READY\n");
+				} else {
+					ret = -1;
+					LOG_E("CAMERA CAMERA_ACTION_LOG_ERROR\n");
+				}
+				break;
+			case CAMERA_ACTION_CAPTURE_FRAME:
+				LOG_D("CAMERA CAMERA_ACTION_CAPTURE_FRAME\n");
+				if((event_action->event & 1 << i) == CSI_CAMERA_EVENT_WARNING) {
+					LOG_D("CAPTURE FRAME CSI_CAMERA_EVENT_WARNING\n");
+				} else if((event_action->event & 1 << i) == CSI_CAMERA_EVENT_ERROR) {
+					LOG_D("CAPTURE FRAME CSI_CAMERA_EVENT_ERROR\n");
+				} else if((event_action->event & 1 << i) == CSI_CAMERA_EVENT_SENSOR_FIRST_IMAGE_ARRIVE) {
+					LOG_D("CAPTURE FRAME CSI_CAMERA_EVENT_SENSOR_FIRST_IMAGE_ARRIVE\n");
+				} else if((event_action->event & 1 << i) == CSI_CAMERA_EVENT_ISP_3A_ADJUST_READY) {
+					LOG_D("CAPTURE FRAME CSI_CAMERA_EVENT_ISP_3A_ADJUST_READY\n");
+				} else {
+					ret = -1;
+					LOG_D("CAMERA CAMERA_ACTION_CAPTURE_FRAME_ERROR\n");
+				}
+				break;
+			default:
+				break;
+
+			}
+		}
+	}
+	return 0;
+}
+
+static int do_channel_event_action(cams_t *session, csi_camera_event_s *event)
+{
+	_CHECK_SESSION_RETURN();
+	csi_frame_s frame;
+	int ret = 0;
+
+	camera_event_action_union_t *event_action_u =
+		session->channel_event_action[event->type - CSI_CAMERA_EVENT_TYPE_CHANNEL0];
+
+	LOG_D("do_channel_event_action()!\n");
+	for (uint32_t i = 0; i < CSI_CAMERA_CHANNEL_EVENT_MAX_COUNT; i++) {
+		camera_channel_event_action_t *event_action = &(event_action_u[i].channel);
+		if (event_action->event != event->id)
+			continue;
+		if (event_action->action == 0) {
+			printf("event_action->action == 0\n");
+			break;
+		}
+
+		LOG_D("Found channel action:%s\n",
+		      camera_string_channel_action(event_action->action));
+
+		if(event_action->action == CAMERA_CHANNEL_ACTION_NONE) {
+			LOG_D("CHANNEL CAMERA_ACTION_NONE!\n");
+			continue;
+		}
+		if(event_action->action > (CAMERA_CHANNEL_ACTION_LOG_PRINT|CAMERA_CHANNEL_ACTION_CAPTURE_FRAME|CAMERA_CHANNEL_ACTION_DISPLAY_FRAME)) {
+			ret = -1;
+			LOG_E("Unkonw channel event action: %d\n", event_action->action);
+		}
+
+		for(uint32_t j = 0; j < CAMERA_CHANNEL_ACTION_MAX_COUNT; j++) {
+			switch (event_action->action & 1 << j) {
+			case CAMERA_CHANNEL_ACTION_LOG_PRINT:
+				LOG_D("CHANNEL CAMERA_ACTION_LOG_PRINT\n");
+				if((event_action->event & 1 << i) == CSI_CAMERA_CHANNEL_EVENT_FRAME_READY) {
+					LOG_D("LOG_PRINT CSI_CAMERA_CHANNEL_EVENT_FRAME_READY\n");
+				} else if((event_action->event & 1 << i) == CSI_CAMERA_CHANNEL_EVENT_FRAME_PUT) {
+					LOG_D("LOG_PRINT CSI_CAMERA_CHANNEL_EVENT_FRAME_PUT\n");
+				} else if((event_action->event & 1 << i) == CSI_CAMERA_CHANNEL_EVENT_OVERFLOW) {
+					LOG_D("LOG_PRINT CSI_CAMERA_CHANNEL_EVENT_OVERFLOW\n");
+				} else {
+					ret = -1;
+					LOG_E("CHANNEL CAMERA_ACTION_LOG_ERROR\n");
+				}
+				break;
+			case CAMERA_CHANNEL_ACTION_CAPTURE_FRAME:
+				LOG_D("CHANNEL CAMERA_ACTION_CAPTURE_FRAME\n");
+
+				/* To show the image can do below steps:
+				 * 1. save capture img to be /tmp/capture.jpg
+				 * 2. img2txt -W 80 -H 60 -f ansi /tmp/capture.jpg > /tmp/capture.txt
+				 * 3. malloc a img_buf and store /tmp/capture.txt into it
+				 * 4. printf(img_buf) to show on log console screen
+				 */
+				if((event_action->event & 1 << i) == CSI_CAMERA_CHANNEL_EVENT_FRAME_READY) {
+					int timeout = -1;
+					int read_frame_count = csi_camera_get_frame_count(NULL, event->type - CSI_CAMERA_EVENT_TYPE_CHANNEL0);
+					LOG_D("read_frame_count = %d\n",read_frame_count);
+					for (int i = 0; i < read_frame_count; i++) {
+						csi_camera_get_frame(NULL,event->type - CSI_CAMERA_EVENT_TYPE_CHANNEL0, &frame, timeout);
+						if(frame.img.usr_addr[0] != NULL) {
+							camera_action_image_save(&frame);
+							csi_camera_put_frame(&frame);
+						}
+					}
+				} else if((event_action->event & 1 << i) == CSI_CAMERA_CHANNEL_EVENT_FRAME_PUT) {
+					LOG_D("CSI_CAMERA_CHANNEL_EVENT_FRAME_PUT\n");
+				} else if((event_action->event & 1 << i) == CSI_CAMERA_CHANNEL_EVENT_OVERFLOW) {
+					LOG_D("CSI_CAMERA_CHANNEL_EVENT_OVERFLOW\n");
+				} else {
+					ret = -1;
+					LOG_E("CHANNEL CAMERA_ACTION_CAPTURE_FRAME_ERROR\n");
+				}
+				break;
+			case CAMERA_CHANNEL_ACTION_DISPLAY_FRAME:
+				LOG_D("CHANNEL CAMERA_ACTION_DISPLAY_FRAME");
+				if((event_action->event & 1 << i) == CSI_CAMERA_CHANNEL_EVENT_FRAME_READY) {
+					int timeout = -1;
+					int read_frame_count = csi_camera_get_frame_count(NULL, event->type - CSI_CAMERA_EVENT_TYPE_CHANNEL0);
+					LOG_D("read_frame_count = %d\n",read_frame_count);
+					//for (int i = 0; i < read_frame_count; i++) {
+						csi_camera_get_frame(NULL,event->type - CSI_CAMERA_EVENT_TYPE_CHANNEL0, &frame, timeout);
+						if(frame.img.usr_addr[0] != NULL) {
+							camera_action_image_display(&frame);
+							LOG_D("frame->usr_addr = %p\n",frame.img.usr_addr[0]);
+							csi_camera_put_frame(&frame);
+						}
+					//}
+				} else if((event_action->event & 1 << i) == CSI_CAMERA_CHANNEL_EVENT_FRAME_PUT) {
+					LOG_D("CSI_CAMERA_CHANNEL_EVENT_FRAME_PUT\n");
+				} else if((event_action->event & 1 << i) == CSI_CAMERA_CHANNEL_EVENT_OVERFLOW) {
+					LOG_D("CSI_CAMERA_CHANNEL_EVENT_OVERFLOW\n");
+				} else {
+					ret = -1;
+					LOG_E("CHANNEL CAMERA_ACTION_DISPLAY_FRAME_ERROR\n");
+				}
+				break;
+			default:
+				break;
+			}
+		}
+	}
+	return ret;
+}
+
+/* action: 0:close, 1:open, 2:start/stop */
+int dialog_channel_run(void)
+{
+	int ret_key = KEY_ESC;
+	int ret;
+	char str_buf[256];
+	csi_camera_channel_cfg_s *selected_chn = NULL;
+
+	if (cam_session == NULL) {
+		LOG_E("cam_session is NULL\n");
+		return KEY_ESC;
+	}
+
+	if (cam_session->camera_handle == NULL) {
+		csi_camera_info_s *info =
+			&(cam_session->camera_infos.info[cam_session->camera_id]);
+		snprintf(str_buf, sizeof(str_buf),
+			"Please open camera first\n");
+		dialog_textbox_simple("Error", str_buf, 6, 30);
+		return KEY_ESC;
+	}
+
+again:
+	item_reset();
+
+	if (camera_channel_query_list(cam_session) != 0) {
+		LOG_E("camera_channel_query_list() failed\n");
+		snprintf(str_buf, sizeof(str_buf),
+			"Failed to query channel list from Camera failed!\n");
+		dialog_textbox_simple("Error", str_buf, 10, 40);
+		return KEY_ESC;
+	}
+
+	/* Prepare for checklist nodes */
+	for (int i = CSI_CAMERA_CHANNEL_0; i < CSI_CAMERA_CHANNEL_MAX_COUNT; i++) {
+		csi_camera_channel_cfg_s *channel = &(cam_session->chn_cfg[i]);
+		if (channel->status == CSI_CAMERA_CHANNEL_INVALID) {
+			continue;
+		}
+
+		item_make("Channel[%d]", channel->chn_id);
+		item_add_str(" (%s)", camera_string_chn_status(channel->status));
+		item_set_data(channel);
+
+		if (channel->status == CSI_CAMERA_CHANNEL_RUNNING || channel->status == CSI_CAMERA_CHANNEL_OPENED) {
+			item_set_tag('X');
+			item_set_selected(1);
+		}
+	}
+
+	char *button_names[] = {"Start", "Stop", "Cancel"};
+	ret = dialog_checklist(
+		"Start/Stop Channel",	/* Title */
+		"Select the channel to start or stop",
+		CHECKLIST_HEIGTH_MIN + 10,
+		WIN_COLS - CHECKLIST_WIDTH_MIN - 16, 8,
+		button_names, ARRAY_SIZE(button_names));
+
+	int selected = item_activate_selected();
+	LOG_D("ret=%d, selected=%s\n", ret, selected ? "true" : "false");
+	switch (ret) {
+	case 0:				// button is: start
+		if (!selected || item_data() == NULL)
+			break;
+
+		/* Show operation result */
+		selected_chn = (csi_camera_channel_cfg_s *)item_data();
+		if (selected_chn->status != CSI_CAMERA_CHANNEL_OPENED) {
+			/* Show message bar */
+			snprintf(str_buf, sizeof(str_buf),
+				"The Camera[%d] channel[%d] can't start, current status is '%s'\n",
+				cam_session->camera_id, selected_chn->chn_id,
+				camera_string_chn_status(selected_chn->status));
+			message(str_buf, 2);
+
+			goto again;
+		}
+		camera_register_event_action(cam_session,
+					do_camera_event_action,
+					do_channel_event_action);
+
+		LOG_D("camera_channel_start selected_chn->chn_id = %x\n",selected_chn->chn_id);
+		ret = camera_channel_start(cam_session, selected_chn->chn_id);
+
+		/* Show message bar */
+		snprintf(str_buf, sizeof(str_buf),
+			"Start Camera[%d] channel[%d] %s\n",
+			cam_session->camera_id, selected_chn->chn_id,
+			(ret == 0) ? "OK" : "failed");
+		message(str_buf, (ret == 0) ? 1 : 2);
+		goto again;
+		break;
+	case 1:				// button is: stop
+		if (!selected || item_data() == NULL)
+			break;
+
+		/* Show operation result */
+		selected_chn = (csi_camera_channel_cfg_s *)item_data();
+		if (selected_chn->status != CSI_CAMERA_CHANNEL_RUNNING) {
+			/* Show message bar */
+			snprintf(str_buf, sizeof(str_buf),
+				"The Camera[%d] channel[%d] can't stop, current status is '%s'\n",
+				cam_session->camera_id, selected_chn->chn_id,
+				camera_string_chn_status(selected_chn->status));
+			message(str_buf, 2);
+
+			goto again;
+		}
+
+		ret = camera_channel_stop(cam_session, selected_chn->chn_id);
+		/* Show message bar */
+		snprintf(str_buf, sizeof(str_buf),
+			"Stop Camera[%d] channel[%d] %s\n",
+			cam_session->camera_id, selected_chn->chn_id,
+			(ret == 0) ? "OK" : "failed");
+		message(str_buf, (ret == 0) ? 1 : 2);
+		goto again;
+		break;
+	case 2: 			// button is: cancel
+	case KEY_ESC:			// specific KEY
+		ret = KEY_ESC;
+		break;
+	default:
+		LOG_W("Oops? why return ret=%d\n", ret);
+		ret = KEY_ESC;
+		break;
+	}
+
+	LOG_D("ret=%d\n", ret);
+	return ret;
+}
+

+ 150 - 0
examples/camera/camera_demo3_srcs/dialog_channel_select.c

@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <curses.h>
+
+#define LOG_LEVEL 3
+#define LOG_PREFIX "dlg_chn_select"
+#include <syslog.h>
+#include <camera_manager.h>
+#include <camera_string.h>
+
+#include "param.h"
+#include "app_dialogs.h"
+
+extern cams_t *cam_session;
+
+/* action: 0:close, 1:open, 2:start/stop */
+int dialog_channel_select(csi_camera_channel_cfg_s **selected_chn, int action)
+{
+	int ret_key = KEY_ESC;
+	int ret;
+	char str_buf[256];
+	*selected_chn = NULL;
+
+	if (cam_session == NULL) {
+		LOG_E("cam_session is NULL\n");
+		return KEY_ESC;
+	}
+
+	if (cam_session->camera_handle == NULL) {
+		csi_camera_info_s *info =
+			&(cam_session->camera_infos.info[cam_session->camera_id]);
+		snprintf(str_buf, sizeof(str_buf),
+			"Please open camera first\n");
+		dialog_textbox_simple("Error", str_buf, 6, 30);
+		return KEY_ESC;
+	}
+
+again:
+	item_reset();
+
+	if (camera_channel_query_list(cam_session) != 0) {
+		LOG_E("camera_channel_query_list() failed\n");
+		snprintf(str_buf, sizeof(str_buf),
+			"Failed to query channel list from Camera failed!\n");
+		dialog_textbox_simple("Error", str_buf, 10, 40);
+		return KEY_ESC;
+	}
+	/* Prepare for checklist nodes */
+	for (int i = CSI_CAMERA_CHANNEL_0; i < CSI_CAMERA_CHANNEL_MAX_COUNT; i++) {
+		csi_camera_channel_cfg_s *chn_cfg = &(cam_session->chn_cfg[i]);
+		if (chn_cfg->status == CSI_CAMERA_CHANNEL_INVALID) {
+			continue;
+		}
+
+		item_make("Channel[%d]", chn_cfg->chn_id);
+		item_add_str(" (%s)  --->", camera_string_chn_status(chn_cfg->status));
+		item_set_data(chn_cfg);
+
+		if (chn_cfg->status == CSI_CAMERA_CHANNEL_OPENED || chn_cfg->status == CSI_CAMERA_CHANNEL_RUNNING) {
+			item_set_tag('X');
+			item_set_selected(1);
+		}
+	}
+
+	if (action == 0) {	// action is close
+		char *button_names[] = {" Close ", " Help "};
+		ret = dialog_checklist(
+			"Select Channel",	/* Title */
+			"Select the channel to close",
+			CHECKLIST_HEIGTH_MIN + 10,
+			WIN_COLS - CHECKLIST_WIDTH_MIN - 16, 8,
+			button_names, sizeof(button_names) / sizeof(button_names[0]));
+	} else if (action == 1) {		// action is open
+		ret = dialog_checklist(
+			"Select Channel",	/* Title */
+			"Select the channel to config and open",
+			CHECKLIST_HEIGTH_MIN + 10,
+			WIN_COLS - CHECKLIST_WIDTH_MIN - 16, 8,
+			NULL, 0);
+	} else {		// action is start/stop
+		ret = dialog_checklist(
+			"Select Channel",	/* Title */
+			"Select the channel to Start or Stop",
+			CHECKLIST_HEIGTH_MIN + 10,
+			WIN_COLS - CHECKLIST_WIDTH_MIN - 16, 8,
+			NULL, 0);
+	}
+
+	int selected = item_activate_selected();
+	LOG_D("ret=%d, selected=%s\n", ret, selected ? "true" : "false");
+	switch (ret) {
+	case 0:				// item is selected/close
+		if (!selected)
+			break;
+
+		/* Show operation result */
+		*selected_chn = (csi_camera_channel_cfg_s *)item_data();
+
+		if (action == 0) {	// to close
+			if ((*selected_chn)->status == CSI_CAMERA_CHANNEL_RUNNING) {
+				dialog_textbox_simple("Infomation",
+					"The channel is Running, \nplease stop first", 6, 40);
+				goto again;
+			}
+		} else if (action == 1) {	// to open
+			if ((*selected_chn)->status == CSI_CAMERA_CHANNEL_OPENED ||
+			    (*selected_chn)->status == CSI_CAMERA_CHANNEL_RUNNING) {
+				dialog_textbox_simple("Infomation",
+				"The channel is Opened or Running, \nplease close first", 6, 40);
+				goto again;
+			}
+		}
+		/* Show message bar */
+		snprintf(str_buf, sizeof(str_buf),
+			"The Camera[%d] channel[%d] is selected\n",
+			cam_session->camera_id,
+			(*selected_chn)->chn_id);
+		message(str_buf, 0);
+		ret = 0;
+		break;
+	case 1:				// need help
+		LOG_W("Help is not supported yet\n");
+		goto again;
+	case KEY_ESC:			// specific KEY
+		ret = KEY_ESC;
+		break;
+	case -ERRDISPLAYTOOSMALL:	// error
+	default:
+		LOG_W("Oops? why return ret=%d\n", ret);
+		ret = KEY_ESC;
+		break;
+	}
+
+	LOG_D("ret=%d\n", ret);
+	return ret;
+}
+

+ 135 - 0
examples/camera/camera_demo3_srcs/dialog_event_subscribe_action_camera.c

@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <curses.h>
+
+#define LOG_LEVEL 3
+#define LOG_PREFIX "dlg_prop_enum"
+#include <syslog.h>
+#include <camera_manager.h>
+#include <camera_app_spec.h>
+#include <csi_camera_platform_spec.h>
+#include <camera_string.h>
+
+#include "param.h"
+#include "app_dialogs.h"
+
+extern cams_t *cam_session;
+
+static int add_event_actions(camera_event_action_union_t *event_action)
+{
+	int count = 0;
+	const camera_app_bitmasks_t *bitmasks =
+		camera_app_get_bitmask_array(CAMERA_APP_BITMAKS_CAMERA_EVENT_ACTION);
+	LOG_D("bitmasks->count=%d\n", bitmasks->count);
+
+	if (bitmasks == NULL) {
+		LOG_E("Can't get camera's action support list\n");
+		return count;
+	}
+	LOG_D("camera.action=0x%08x\n", event_action->camera.action);
+
+	switch (event_action->camera.event) {
+	case CSI_CAMERA_EVENT_WARNING:
+	case CSI_CAMERA_EVENT_ERROR:
+	case CSI_CAMERA_EVENT_SENSOR_FIRST_IMAGE_ARRIVE:
+	case CSI_CAMERA_EVENT_ISP_3A_ADJUST_READY:
+		for (int i = 0; i < bitmasks->count; i++) {
+			csi_camera_event_id_e loop_action = bitmasks->bitmask[i];
+			bool action_set = (event_action->camera.action & loop_action) != 0;
+			const char *item_name = camera_string_camera_action(loop_action);
+
+			item_make("\t%-16s(0x%08x)", item_name, loop_action);
+			LOG_D("\t%-16s(0x%08x)\n", item_name, loop_action);
+			item_set_tag(action_set ? '*' : ' ');
+			item_set_int(loop_action);
+		}
+		break;
+	}
+}
+
+
+int dialog_event_subscribe_action_camera(camera_event_action_union_t *event_action)
+{
+	int ret_key = KEY_ESC;
+
+	if (event_action == NULL) {
+		LOG_W("event_action is NULL\n");
+		return KEY_ESC;
+	}
+
+	char *title = "Set Camera Event Action(s)";
+	char *prompt = "Select the Camera event then config the action(s)";
+	int item_pos = 0;
+	int list_count = 0;
+
+again:
+	item_reset();
+
+	item_make("%-32s","Subscribe");
+	if (event_action->camera.subscribed == false) {
+		item_set_tag(' ');
+	} else {
+		item_set_tag('*');
+		list_count = add_event_actions(event_action);
+	}
+
+	int list_height = MIN(list_count + 8, 24);
+	ret_key = dialog_checkbox(
+			  title, prompt,
+			  CHECKLIST_HEIGTH_MIN + list_height + 2,
+			  WIN_COLS - CHECKLIST_WIDTH_MIN - 32,
+			  list_height, item_pos);
+
+	LOG_D("dialog_checkbox() ret_key=%d\n", ret_key);
+	if (ret_key == KEY_ESC) {
+		return KEY_ESC;
+	} else if (ret_key == 0) {/* select */
+		item_pos = item_n();
+		LOG_D("item_pos=%d\n", item_pos);
+
+		if (item_pos == 0) {	// 1st item, which indicate whether register actions
+			if (item_tag() == ' ') {
+				event_action->camera.subscribed = true;
+				goto again;
+			} else {
+				event_action->camera.subscribed = false;
+				goto again;
+			}
+		} else {		// other item, which indicate whether register actions
+			camera_action_e cur_action = item_int();
+			if (item_tag() == ' ') {
+				event_action->camera.action |= cur_action;
+				item_set_tag('*');
+			} else {
+				event_action->camera.action &= ~cur_action;
+				item_set_tag(' ');
+			}
+			LOG_D("camera.action=0x%08x\n", event_action->camera.action);
+		}
+
+		goto again;
+		return ret_key;
+	} else if (ret_key == 1) {/* Return */
+		return ret_key;
+	} else if (ret_key == 2) {/* Help */
+		LOG_W("Help does not support yet\n");
+		return ret_key;
+	} else {
+		LOG_E("Unknown return value: %d\n", ret_key);
+		return KEY_ESC;
+	}
+}
+

+ 132 - 0
examples/camera/camera_demo3_srcs/dialog_event_subscribe_action_channel.c

@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <curses.h>
+
+#define LOG_LEVEL 3
+#define LOG_PREFIX "dlg_prop_enum"
+#include <syslog.h>
+#include <camera_manager.h>
+#include <camera_app_spec.h>
+#include <csi_camera_platform_spec.h>
+#include <camera_string.h>
+
+#include "param.h"
+#include "app_dialogs.h"
+
+extern cams_t *cam_session;
+
+static int add_event_actions(camera_event_action_union_t *event_action)
+{
+	int count = 0;
+	const camera_app_bitmasks_t *bitmasks =
+		camera_app_get_bitmask_array(CAMERA_APP_BITMAKS_CHANNEL_EVENT_ACTION);
+
+	if (bitmasks == NULL) {
+		LOG_E("Can't get channel's action support list\n");
+		return count;
+	}
+	LOG_D("camera.action=0x%08x\n", event_action->channel.action);
+
+	switch (event_action->channel.event) {
+	case CSI_CAMERA_CHANNEL_EVENT_FRAME_READY:
+	case CSI_CAMERA_CHANNEL_EVENT_FRAME_PUT:
+	case CSI_CAMERA_CHANNEL_EVENT_OVERFLOW:
+		for (int i = 0; i < bitmasks->count; i++) {
+			csi_camera_event_id_e loop_action = bitmasks->bitmask[i];
+			bool action_set = (event_action->channel.action & loop_action) != 0;
+			const char *item_name = camera_string_channel_action(loop_action);
+
+			item_make("\t%-16s(0x%08x)", item_name, loop_action);
+			item_set_tag(action_set ? '*' : ' ');
+			item_set_int(loop_action);
+		}
+		break;
+	}
+}
+
+
+int dialog_event_subscribe_action_channel(camera_event_action_union_t *event_action)
+{
+	int ret_key = KEY_ESC;
+
+	if (event_action == NULL) {
+		LOG_W("event_action is NULL\n");
+		return KEY_ESC;
+	}
+
+	char *title = "Set Channel Event Action(s)";
+	char *prompt = "Select the channel event then config the action(s)";
+	int item_pos = 0;
+	int list_count = 0;
+
+again:
+	item_reset();
+
+	item_make("%-32s","Subscribe");
+	if (event_action->channel.subscribed == false) {
+		item_set_tag(' ');
+	} else {
+		item_set_tag('*');
+		list_count = add_event_actions(event_action);
+	}
+
+	int list_height = MIN(list_count + 8, 24);
+	ret_key = dialog_checkbox(
+		title, prompt,
+		CHECKLIST_HEIGTH_MIN + list_height + 2,
+		WIN_COLS - CHECKLIST_WIDTH_MIN - 32,
+		list_height, item_pos);
+
+	//LOG_D("dialog_checkbox() ret_key=%d\n", ret_key);
+	if (ret_key == KEY_ESC) {
+		return KEY_ESC;
+	} else if (ret_key == 0) {/* select */
+		item_pos = item_n();
+		LOG_D("item_pos=%d\n", item_pos);
+
+		if (item_pos == 0) {	// 1st item, which indicate whether register actions
+			if (item_tag() == ' ') {
+				event_action->channel.subscribed = true;
+				goto again;
+			} else {
+				event_action->channel.subscribed = false;
+				goto again;
+			}
+		} else {		// other item, which indicate whether register actions
+			camera_action_e cur_action = item_int();
+			if (item_tag() == ' ') {
+				event_action->channel.action |= cur_action;
+				item_set_tag('*');
+			} else {
+				event_action->channel.action &= ~cur_action;
+				item_set_tag(' ');
+			}
+			LOG_D("camera.action=0x%08x\n", event_action->channel.action);
+		}
+
+		goto again;
+		return ret_key;
+	} else if (ret_key == 1) {/* Return */
+		return ret_key;
+	} else if (ret_key == 2) {/* Help */
+		LOG_W("Help does not support yet\n");
+		return ret_key;
+	} else {
+		LOG_E("Unknown return value: %d\n", ret_key);
+		return KEY_ESC;
+	}
+}
+

+ 135 - 0
examples/camera/camera_demo3_srcs/dialog_event_subscribe_action_list.c

@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define LOG_LEVEL 3
+#define LOG_PREFIX "dlg_prop_list"
+#include <syslog.h>
+
+#include <curses.h>
+#include <camera_manager.h>
+#include <camera_manager_utils.h>
+#include <camera_string.h>
+
+#include "param.h"
+#include "app_dialogs.h"
+
+#include <csi_camera_property.h>
+#include <csi_camera_platform_spec.h>
+
+extern cams_t *cam_session;
+
+static int fill_items(void)
+{
+	char item_name[64];
+	char item_value[64];
+	camera_event_action_union_t *event_action;
+
+	/* Fill camera event and action */
+	item_make("*** Camera[%d] Event/Action ***", cam_session->camera_id);
+	item_set_tag(' ');
+	item_set_data(NULL);
+
+	for (int i = 0; i < CSI_CAMERA_EVENT_MAX_COUNT; i++) {
+		event_action = &(cam_session->camera_event_action[i]);
+		if (!event_action->camera.supported)
+			continue;
+
+		item_make("    %-18s", camera_string_camera_event_type(event_action->camera.event));
+		item_add_str("(%s)  --->", event_action->camera.subscribed
+					   ? "Subscribed" : "Un-subscribed");
+		item_set_tag('M');
+		item_set_data(event_action);
+		//cam_mng_dump_event_action_union(event_action);
+	}
+	for(int i = 0;i < CSI_CAMERA_CHANNEL_MAX_COUNT;i++){
+		if((cam_session->chn_cfg[i].status == CSI_CAMERA_CHANNEL_OPENED) || 
+				(cam_session->chn_cfg[i].status == CSI_CAMERA_CHANNEL_RUNNING)){
+			item_make("    *** Channel[%d] Event/Action ***",
+					cam_session->chn_cfg[i].chn_id);
+			item_set_tag(' ');
+			item_set_data(NULL);
+
+			for (int j = 0; j < CSI_CAMERA_CHANNEL_EVENT_MAX_COUNT; j++) {
+				event_action = &(cam_session->channel_event_action[i][j]);
+				if (!event_action->channel.supported)
+					continue;
+
+				item_make("        %-18s", camera_string_channel_event_type(event_action->channel.event));
+				item_add_str("(%s)  --->", event_action->channel.subscribed
+						? "Subscribed" : "Un-subscribed");
+				item_set_tag('N');			// Type: Channel
+				item_set_data(event_action);
+				//cam_mng_dump_event_action_union(event_action); 
+
+			}
+		}
+	}
+	return 0;
+}
+
+int dialog_event_subscribe_action_list(camera_event_action_union_t **event_action)
+{
+	int ret_key = KEY_ESC;
+	int ret = 0;
+
+	char selected_tag;
+	camera_event_action_union_t *selected_data;
+	*event_action = NULL;
+	char str_buf[128];
+
+again:
+	item_reset();
+	if (fill_items() != 0) {
+		LOG_E("fill_items() failed\n");
+		ret = KEY_ESC;
+		goto exit;
+	}
+
+	int s_scroll = 0;
+	ret_key = dialog_menu("Camera Event Subscribe & Action Setting",
+		"Select the Camera/Channel, press Enter to set the event subscribe and event action",
+		WIN_ROWS-2, WIN_COLS, NULL, -1, &s_scroll, NULL, 0);
+	//LOG_D("dialog_menu() ret_key=%d, s_scroll=%d\n", ret_key, s_scroll);
+
+	switch (ret_key) {
+	case 0:		/* Select button */
+		selected_tag = item_tag();
+		selected_data = (camera_event_action_union_t *)item_data();
+		if (selected_data != NULL) {
+			*event_action = selected_data;
+			ret = 0;
+			break;
+		} else {
+			goto again;
+		}
+		break;
+	case 1:		/* Apply button */
+		ret = camera_subscribe_event(cam_session);
+		snprintf(str_buf, sizeof(str_buf),
+			"Apply Camera[%d] and Channels event register %s.",
+			cam_session->camera_id, (ret == 0) ? "OK" : "failed");
+		dialog_textbox_simple("Infomation", str_buf, 6, 56);
+		goto again;
+	case 2:		/* Cancel button */
+	case KEY_ESC:	/* Escape */
+	default:
+		ret = KEY_ESC;
+		goto exit;
+	}
+
+exit:
+	return ret;
+}
+

+ 302 - 0
examples/camera/camera_demo3_srcs/inputbox.c

@@ -0,0 +1,302 @@
+/*
+ *  inputbox.c -- implements the input box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+#include "app_dialogs.h"
+
+char dialog_input_result[MAX_LEN + 1];
+
+/*
+ *  Print the termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected)
+{
+	int x = width / 2 - 11;
+	int y = height - 2;
+
+	print_button(dialog, gettext("  Ok  "), y, x, selected == 0);
+	print_button(dialog, gettext(" Help "), y, x + 14, selected == 1);
+
+	wmove(dialog, y, x + 1 + 14 * selected);
+	wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box for inputing a string
+ */
+int dialog_inputbox(const char *title, const char *prompt, int height, int width,
+		    const char *init)
+{
+	int i, x, y, box_y, box_x, box_width;
+	int input_x = 0, key = 0, button = -1;
+	int show_x, len, pos;
+	char *instr = dialog_input_result;
+	WINDOW *dialog;
+
+	if (!init)
+		instr[0] = '\0';
+	else
+		strcpy(instr, init);
+
+do_resize:
+	if (WIN_ROWS <= (height - INPUTBOX_HEIGTH_MIN))
+		return -ERRDISPLAYTOOSMALL;
+	if (WIN_COLS <= (width - INPUTBOX_WIDTH_MIN))
+		return -ERRDISPLAYTOOSMALL;
+
+	/* center dialog box on screen */
+	x = (WIN_COLS - width) / 2;
+	y = (WIN_ROWS - height) / 2;
+
+	draw_shadow(stdscr, y, x, height, width);
+
+	dialog = newwin(height, width, y, x);
+	keypad(dialog, TRUE);
+
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
+	wattrset(dialog, dlg.border.atr);
+	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+	for (i = 0; i < width - 2; i++)
+		waddch(dialog, ACS_HLINE);
+	wattrset(dialog, dlg.dialog.atr);
+	waddch(dialog, ACS_RTEE);
+
+	print_title(dialog, title, width);
+
+	wattrset(dialog, dlg.dialog.atr);
+	print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+	/* Draw the input field box */
+	box_width = width - 6;
+	getyx(dialog, y, x);
+	box_y = y + 2;
+	box_x = (width - box_width) / 2;
+	draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2,
+		 dlg.dialog.atr, dlg.border.atr);
+
+	print_buttons(dialog, height, width, 0);
+
+	/* Set up the initial value */
+	wmove(dialog, box_y, box_x);
+	wattrset(dialog, dlg.inputbox.atr);
+
+	len = strlen(instr);
+	pos = len;
+
+	if (len >= box_width) {
+		show_x = len - box_width + 1;
+		input_x = box_width - 1;
+		for (i = 0; i < box_width - 1; i++)
+			waddch(dialog, instr[show_x + i]);
+	} else {
+		show_x = 0;
+		input_x = len;
+		waddstr(dialog, instr);
+	}
+
+	wmove(dialog, box_y, box_x + input_x);
+
+	wrefresh(dialog);
+
+	while (key != KEY_ESC) {
+		key = wgetch(dialog);
+
+		if (button == -1) {	/* Input box selected */
+			switch (key) {
+			case TAB:
+			case KEY_UP:
+			case KEY_DOWN:
+				break;
+			case KEY_BACKSPACE:
+			case 127:
+				if (pos) {
+					wattrset(dialog, dlg.inputbox.atr);
+					if (input_x == 0) {
+						show_x--;
+					} else
+						input_x--;
+
+					if (pos < len) {
+						for (i = pos - 1; i < len; i++) {
+							instr[i] = instr[i+1];
+						}
+					}
+
+					pos--;
+					len--;
+					instr[len] = '\0';
+					wmove(dialog, box_y, box_x);
+					for (i = 0; i < box_width; i++) {
+						if (!instr[show_x + i]) {
+							waddch(dialog, ' ');
+							break;
+						}
+						waddch(dialog, instr[show_x + i]);
+					}
+					wmove(dialog, box_y, input_x + box_x);
+					wrefresh(dialog);
+				}
+				continue;
+			case KEY_LEFT:
+				if (pos > 0) {
+					if (input_x > 0) {
+						wmove(dialog, box_y, --input_x + box_x);
+					} else if (input_x == 0) {
+						show_x--;
+						wmove(dialog, box_y, box_x);
+						for (i = 0; i < box_width; i++) {
+							if (!instr[show_x + i]) {
+								waddch(dialog, ' ');
+								break;
+							}
+							waddch(dialog, instr[show_x + i]);
+						}
+						wmove(dialog, box_y, box_x);
+					}
+					pos--;
+				}
+				continue;
+			case KEY_RIGHT:
+				if (pos < len) {
+					if (input_x < box_width - 1) {
+						wmove(dialog, box_y, ++input_x + box_x);
+					} else if (input_x == box_width - 1) {
+						show_x++;
+						wmove(dialog, box_y, box_x);
+						for (i = 0; i < box_width; i++) {
+							if (!instr[show_x + i]) {
+								waddch(dialog, ' ');
+								break;
+							}
+							waddch(dialog, instr[show_x + i]);
+						}
+						wmove(dialog, box_y, input_x + box_x);
+					}
+					pos++;
+				}
+				continue;
+			default:
+				if (key < 0x100 && isprint(key)) {
+					if (len < MAX_LEN) {
+						wattrset(dialog, dlg.inputbox.atr);
+						if (pos < len) {
+							for (i = len; i > pos; i--)
+								instr[i] = instr[i-1];
+							instr[pos] = key;
+						} else {
+							instr[len] = key;
+						}
+						pos++;
+						len++;
+						instr[len] = '\0';
+
+						if (input_x == box_width - 1) {
+							show_x++;
+						} else {
+							input_x++;
+						}
+
+						wmove(dialog, box_y, box_x);
+						for (i = 0; i < box_width; i++) {
+							if (!instr[show_x + i]) {
+								waddch(dialog, ' ');
+								break;
+							}
+							waddch(dialog, instr[show_x + i]);
+						}
+						wmove(dialog, box_y, input_x + box_x);
+						wrefresh(dialog);
+					} else
+						flash();	/* Alarm user about overflow */
+					continue;
+				}
+			}
+		}
+		switch (key) {
+		case 'O':
+		case 'o':
+			delwin(dialog);
+			return 0;
+		case 'H':
+		case 'h':
+			delwin(dialog);
+			return 1;
+		case KEY_UP:
+		case KEY_LEFT:
+			switch (button) {
+			case -1:
+				button = 1;	/* Indicates "Help" button is selected */
+				print_buttons(dialog, height, width, 1);
+				break;
+			case 0:
+				button = -1;	/* Indicates input box is selected */
+				print_buttons(dialog, height, width, 0);
+				wmove(dialog, box_y, box_x + input_x);
+				wrefresh(dialog);
+				break;
+			case 1:
+				button = 0;	/* Indicates "OK" button is selected */
+				print_buttons(dialog, height, width, 0);
+				break;
+			}
+			break;
+		case TAB:
+		case KEY_DOWN:
+		case KEY_RIGHT:
+			switch (button) {
+			case -1:
+				button = 0;	/* Indicates "OK" button is selected */
+				print_buttons(dialog, height, width, 0);
+				break;
+			case 0:
+				button = 1;	/* Indicates "Help" button is selected */
+				print_buttons(dialog, height, width, 1);
+				break;
+			case 1:
+				button = -1;	/* Indicates input box is selected */
+				print_buttons(dialog, height, width, 0);
+				wmove(dialog, box_y, box_x + input_x);
+				wrefresh(dialog);
+				break;
+			}
+			break;
+		case ' ':
+		case '\n':
+			delwin(dialog);
+			return (button == -1 ? 0 : button);
+		case 'X':
+		case 'x':
+			key = KEY_ESC;
+			break;
+		case KEY_ESC:
+			key = on_key_esc(dialog);
+			break;
+		case KEY_RESIZE:
+			delwin(dialog);
+			on_key_resize();
+			goto do_resize;
+		}
+	}
+
+	delwin(dialog);
+	return KEY_ESC;		/* ESC pressed */
+}

+ 153 - 0
examples/camera/camera_demo3_srcs/menu_process.c

@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <curses.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define LOG_LEVEL 3
+#define LOG_PREFIX "camera_demo3"
+#include <syslog.h>
+
+#include <camera_manager.h>
+#include <camera_manager_utils.h>
+#include <camera_string.h>
+
+#include "param.h"
+#include "app_dialogs.h"
+#include "menu_process.h"
+
+void menu_camera_process(menu_camera_item_e item)
+{
+	int ret;
+	switch (item) {
+	case MENU_CAMERA_LIST:
+		LOG_D("dialog_camera_list()\n");
+		ret = dialog_camera_list();
+		break;
+	case MENU_CAMERA_OPEN:
+		LOG_D("dialog_camera_open()\n");
+		ret = dialog_camera_open();
+		break;
+	case MENU_CAMERA_SET_MODE:
+		LOG_D("dialog_camera_set_mode()\n");
+		ret = dialog_camera_set_mode();
+		break;
+	case MENU_CAMERA_SET_PROPERTY:
+		LOG_D("dialog_camera_property_list()\n");
+		ret = dialog_camera_property_list();
+		break;
+	case MENU_CAMERA_CLOSE:
+		LOG_D("dialog_camera_close()\n");
+		ret = dialog_camera_close();
+		break;
+	case -1:
+		ret = -1;
+		break;
+	default:
+		LOG_E("Unknown menu item:%d\n", item);
+		ret = -1;
+	}
+	return;
+}
+
+void menu_channel_process(menu_camera_item_e item)
+{
+	int ret;
+	csi_camera_channel_cfg_s *selected_chn;
+	char str_buf[128];
+
+	switch (item) {
+	case MENU_CHANNEL_LIST:
+		LOG_D("channel_list()\n");
+		dialog_channel_list();
+		break;
+	case MENU_CHANNEL_OPEN:
+again_channel_open:
+		LOG_D("channel_open()\n");
+		ret = dialog_channel_select(&selected_chn, 1);
+		if (ret == KEY_ESC || ret != 0 ||	/* Not "Select" button */
+		    selected_chn == NULL) {		/* No Channel be selected */
+			return;
+		}
+		ret = dialog_channel_open(selected_chn);
+		touchwin(stdscr);
+		refresh();
+		goto again_channel_open;
+		break;
+	case MENU_CHANNEL_CLOSE:
+again_channel_close:
+		LOG_D("channel_close()\n");
+		ret = dialog_channel_select(&selected_chn, 0);
+		if (ret == KEY_ESC || ret != 0 ||	/* Not "Select" button */
+		    selected_chn == NULL) {		/* No Channel be selected */
+			return;
+		}
+		ret = camera_channel_close(cam_session, selected_chn->chn_id);
+		snprintf(str_buf, sizeof(str_buf),
+			"Close Camera[%d]:Channel[%d] %s",
+			cam_session->camera_id, selected_chn->chn_id,
+			(ret == 0) ? "OK" : "failed");
+		dialog_textbox_simple("Infomation", str_buf, 10, 40);
+		touchwin(stdscr);
+		refresh();
+		goto again_channel_close;
+		break;
+	case -1:
+		break;
+	default:
+		LOG_E("Unknown menu item:%d\n", item);
+		break;
+	}
+
+	return;
+}
+
+void menu_event_run_process(menu_camera_item_e item)
+{
+	int ret;
+	char str_buf[128];
+	camera_event_action_union_t *event_action = NULL;
+	csi_camera_channel_cfg_s *selected_chn;
+
+	switch (item) {
+	case MENU_EVENT_SUBSCRIBE_ACTION:
+again_subscribe_action:
+		LOG_D("dialog_event_subscribe_action_list()\n");
+		ret = dialog_event_subscribe_action_list(&event_action);
+		if (ret == KEY_ESC || ret != 0 || event_action == NULL)
+			return;
+
+		cam_mng_dump_event_action_union(event_action);
+		if (event_action->target == MANAGE_TARGET_CAMERA) {
+			ret = dialog_event_subscribe_action_camera(event_action);
+			LOG_D("dialog_event_subscribe_action_camera() ret=%d\n", ret);
+			goto again_subscribe_action;
+		} else if (event_action->target == MANAGE_TARGET_CHANNEL) {
+			ret = dialog_event_subscribe_action_channel(event_action);
+			LOG_D("dialog_event_subscribe_action_channel() ret=%d\n", ret);
+			goto again_subscribe_action;
+		}
+		break;
+	case MENU_EVENT_START_STOP:
+		ret = dialog_channel_run();
+		break;
+	case -1:
+		break;
+	default:
+		LOG_E("Unknown menu item:%d\n", item);
+		break;
+	}
+
+	return;
+}
+

+ 30 - 0
examples/camera/camera_demo3_srcs/menu_process.h

@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <curses.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define LOG_LEVEL 3
+#define LOG_PREFIX "camera_demo3"
+#include <syslog.h>
+
+#include "camera_manager.h"
+#include "param.h"
+#include "app_dialogs.h"
+
+extern cams_t *cam_session;
+
+void menu_camera_process(menu_camera_item_e item);
+void menu_channel_process(menu_camera_item_e item);
+void menu_event_run_process(menu_camera_item_e item);
+

+ 442 - 0
examples/camera/camera_demo3_srcs/menubox.c

@@ -0,0 +1,442 @@
+/*
+ *  menubox.c -- implements the menu box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ *  Changes by Clifford Wolf (god@clifford.at)
+ *
+ *  [ 1998-06-13 ]
+ *
+ *    *)  A bugfix for the Page-Down problem
+ *
+ *    *)  Formerly when I used Page Down and Page Up, the cursor would be set
+ *        to the first position in the menu box.  Now lxdialog is a bit
+ *        smarter and works more like other menu systems (just have a look at
+ *        it).
+ *
+ *    *)  Formerly if I selected something my scrolling would be broken because
+ *        lxdialog is re-invoked by the Menuconfig shell script, can't
+ *        remember the last scrolling position, and just sets it so that the
+ *        cursor is at the bottom of the box.  Now it writes the temporary file
+ *        lxdialog.scrltmp which contains this information. The file is
+ *        deleted by lxdialog if the user leaves a submenu or enters a new
+ *        one, but it would be nice if Menuconfig could make another "rm -f"
+ *        just to be sure.  Just try it out - you will recognise a difference!
+ *
+ *  [ 1998-06-14 ]
+ *
+ *    *)  Now lxdialog is crash-safe against broken "lxdialog.scrltmp" files
+ *        and menus change their size on the fly.
+ *
+ *    *)  If for some reason the last scrolling position is not saved by
+ *        lxdialog, it sets the scrolling so that the selected item is in the
+ *        middle of the menu box, not at the bottom.
+ *
+ * 02 January 1999, Michael Elizabeth Chastain (mec@shout.net)
+ * Reset 'scroll' to 0 if the value from lxdialog.scrltmp is bogus.
+ * This fixes a bug in Menuconfig where using ' ' to descend into menus
+ * would leave mis-synchronized lxdialog.scrltmp files lying around,
+ * fscanf would read in 'scroll', and eventually that value would get used.
+ */
+
+#include "dialog.h"
+#include "app_dialogs.h"
+
+static int menu_width, item_x;
+
+/*
+ * Print menu item
+ */
+static void do_print_item(WINDOW * win, const char *item, int line_y,
+			  int selected, int hotkey)
+{
+	int j;
+	char *menu_item = malloc(menu_width + 1);
+
+	strncpy(menu_item, item, menu_width - item_x);
+	menu_item[menu_width - item_x] = '\0';
+	j = first_alpha(menu_item, "YyNnMmHh");
+
+	/* Clear 'residue' of last item */
+	wattrset(win, dlg.menubox.atr);
+	wmove(win, line_y, 0);
+#if OLD_NCURSES
+	{
+		int i;
+		for (i = 0; i < menu_width; i++)
+			waddch(win, ' ');
+	}
+#else
+	wclrtoeol(win);
+#endif
+	wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
+	mvwaddstr(win, line_y, item_x, menu_item);
+	if (hotkey) {
+		wattrset(win, selected ? dlg.tag_key_selected.atr
+			 : dlg.tag_key.atr);
+		mvwaddch(win, line_y, item_x + j, menu_item[j]);
+	}
+	if (selected) {
+		wmove(win, line_y, item_x + 1);
+	}
+	free(menu_item);
+	wrefresh(win);
+}
+
+#define print_item(index, choice, selected)				\
+do {									\
+	item_set(index);						\
+	do_print_item(menu, item_str(), choice, selected, !item_is_tag(':')); \
+} while (0)
+
+/*
+ * Print the scroll indicators.
+ */
+static void print_arrows(WINDOW * win, int item_no, int scroll, int y, int x,
+			 int height)
+{
+	int cur_y, cur_x;
+
+	getyx(win, cur_y, cur_x);
+
+	wmove(win, y, x);
+
+	if (scroll > 0) {
+		wattrset(win, dlg.uarrow.atr);
+		waddch(win, ACS_UARROW);
+		waddstr(win, "(-)");
+	} else {
+		wattrset(win, dlg.menubox.atr);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+	}
+
+	y = y + height + 1;
+	wmove(win, y, x);
+	wrefresh(win);
+
+	if ((height < item_no) && (scroll + height < item_no)) {
+		wattrset(win, dlg.darrow.atr);
+		waddch(win, ACS_DARROW);
+		waddstr(win, "(+)");
+	} else {
+		wattrset(win, dlg.menubox_border.atr);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+		waddch(win, ACS_HLINE);
+	}
+
+	wmove(win, cur_y, cur_x);
+	wrefresh(win);
+}
+
+/*
+ * Display the termination buttons.
+ */
+static void print_buttons(WINDOW * win, int height, int width, int selected,
+			  char *button_names[], int button_count)
+{
+	int x = width / 2 - 28;
+	int y = height - 2;
+
+	if (button_names == NULL) {
+		print_button(win, gettext("Select"), y, x + 12, selected == 0);
+		print_button(win, gettext("Apply"), y, x + 24, selected == 1);
+		print_button(win, gettext("Cancel"), y, x + 36, selected == 2);
+	} else {
+		for (int i = 0; i < button_count; i++) {
+			print_button(win, gettext(button_names[i]), y, x + 12 * (i + 1), selected == i);
+		}
+	}
+
+	wmove(win, y, x + 1 + 12 + 12 * selected);
+	wrefresh(win);
+}
+
+/* scroll up n lines (n may be negative) */
+static void do_scroll(WINDOW *win, int *scroll, int n)
+{
+	/* Scroll menu up */
+	scrollok(win, TRUE);
+	wscrl(win, n);
+	scrollok(win, FALSE);
+	*scroll = *scroll + n;
+	wrefresh(win);
+}
+
+/*
+ * Display a menu for choosing among a number of options
+   Indicate selected item: set 'selected' or 'selected_pos'
+   Indicate buttons: char *button_name[], int button_count
+ */
+int dialog_menu(const char *title, const char *prompt,
+		int height, int width,
+		const void *selected, int selected_pos, int *s_scroll,
+		char *button_names[], int button_count)
+{
+	int i, j, x, y, box_x, box_y;
+	int menu_height;
+	int key = 0, button = 0, scroll = 0, choice = 0;
+	int first_item =  0, max_choice;
+	WINDOW *dialog, *menu;
+
+do_resize:
+	//height = getmaxy(stdscr);
+	//width = getmaxx(stdscr);
+	if (height < MENUBOX_HEIGTH_MIN || width < MENUBOX_WIDTH_MIN)
+		return -ERRDISPLAYTOOSMALL;
+
+	height -= 4;
+	width  -= 5;
+	menu_height = height - 8;
+
+	max_choice = MIN(menu_height, item_count());
+
+	/* center dialog box on screen */
+	x = (WIN_COLS - width) / 2;
+	y = (WIN_ROWS - height) / 2;
+
+	draw_shadow(stdscr, y, x, height, width);
+
+	dialog = newwin(height, width, y, x);
+	keypad(dialog, TRUE);
+
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
+	wattrset(dialog, dlg.border.atr);
+	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+	for (i = 0; i < width - 2; i++)
+		waddch(dialog, ACS_HLINE);
+	wattrset(dialog, dlg.dialog.atr);
+	wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
+	waddch(dialog, ACS_RTEE);
+
+	print_title(dialog, title, width);
+
+	wattrset(dialog, dlg.dialog.atr);
+	print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+	menu_width = width - 6;
+	box_y = height - menu_height - 5;
+	box_x = (width - menu_width) / 2 - 1;
+
+	/* create new window for the menu */
+	menu = subwin(dialog, menu_height, menu_width,
+		      y + box_y + 1, x + box_x + 1);
+	keypad(menu, TRUE);
+
+	/* draw a box around the menu items */
+	draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2,
+		 dlg.menubox_border.atr, dlg.menubox.atr);
+
+	if (menu_width >= 60)
+		item_x = (menu_width - 50) / 3;
+	else
+		item_x = 4;
+
+	/* Set choice to default item */
+	item_foreach() {
+		if (selected && (selected == item_data()))
+			choice = item_n();
+	}
+	if (selected_pos >= 0)
+		choice = selected_pos;
+
+	/* get the saved scroll info */
+	scroll = *s_scroll;
+	if ((scroll <= choice) && (scroll + max_choice > choice) &&
+	   (scroll >= 0) && (scroll + max_choice <= item_count())) {
+		first_item = scroll;
+		choice = choice - scroll;
+	} else {
+		scroll = 0;
+	}
+	if ((choice >= max_choice)) {
+		if (choice >= item_count() - max_choice / 2)
+			scroll = first_item = item_count() - max_choice;
+		else
+			scroll = first_item = choice - max_choice / 2;
+		choice = choice - scroll;
+	}
+
+	/* Print the menu */
+	for (i = 0; i < max_choice; i++) {
+		print_item(first_item + i, i, i == choice);
+	}
+
+	wnoutrefresh(menu);
+
+	print_arrows(dialog, item_count(), scroll,
+		     box_y, box_x + item_x + 1, menu_height);
+
+	print_buttons(dialog, height, width, 0, button_names, button_count);
+	wmove(menu, choice, item_x + 1);
+	wrefresh(menu);
+
+	while (key != KEY_ESC) {
+		key = wgetch(menu);
+
+		if (key < 256 && isalpha(key))
+			key = tolower(key);
+
+		if (strchr("ynmh ", key))
+			i = max_choice;
+		else {
+			for (i = choice + 1; i < max_choice; i++) {
+				item_set(scroll + i);
+				j = first_alpha(item_str(), "YyNnMmHh");
+				if (key == tolower(item_str()[j]))
+					break;
+			}
+			if (i == max_choice)
+				for (i = 0; i < max_choice; i++) {
+					item_set(scroll + i);
+					j = first_alpha(item_str(), "YyNnMmHh");
+					if (key == tolower(item_str()[j]))
+						break;
+				}
+		}
+
+		if (item_count() != 0 &&
+		    (i < max_choice ||
+		     key == KEY_UP || key == KEY_DOWN ||
+		     key == '-' || key == '+' ||
+		     key == KEY_PPAGE || key == KEY_NPAGE)) {
+			/* Remove highligt of current item */
+			print_item(scroll + choice, choice, FALSE);
+
+			if (key == KEY_UP || key == '-') {
+				if (choice < 2 && scroll) {
+					/* Scroll menu down */
+					do_scroll(menu, &scroll, -1);
+
+					print_item(scroll, 0, FALSE);
+				} else
+					choice = MAX(choice - 1, 0);
+
+			} else if (key == KEY_DOWN || key == '+') {
+				print_item(scroll+choice, choice, FALSE);
+
+				if ((choice > max_choice - 3) &&
+				    (scroll + max_choice < item_count())) {
+					/* Scroll menu up */
+					do_scroll(menu, &scroll, 1);
+
+					print_item(scroll+max_choice - 1,
+						   max_choice - 1, FALSE);
+				} else
+					choice = MIN(choice + 1, max_choice - 1);
+
+			} else if (key == KEY_PPAGE) {
+				scrollok(menu, TRUE);
+				for (i = 0; (i < max_choice); i++) {
+					if (scroll > 0) {
+						do_scroll(menu, &scroll, -1);
+						print_item(scroll, 0, FALSE);
+					} else {
+						if (choice > 0)
+							choice--;
+					}
+				}
+
+			} else if (key == KEY_NPAGE) {
+				for (i = 0; (i < max_choice); i++) {
+					if (scroll + max_choice < item_count()) {
+						do_scroll(menu, &scroll, 1);
+						print_item(scroll+max_choice-1,
+							   max_choice - 1, FALSE);
+					} else {
+						if (choice + 1 < max_choice)
+							choice++;
+					}
+				}
+			} else
+				choice = i;
+
+			print_item(scroll + choice, choice, TRUE);
+
+			print_arrows(dialog, item_count(), scroll,
+				     box_y, box_x + item_x + 1, menu_height);
+
+			wnoutrefresh(dialog);
+			wrefresh(menu);
+
+			continue;	/* wait for another key press */
+		}
+
+		switch (key) {
+		case KEY_LEFT:
+		case TAB:
+		case KEY_RIGHT:
+			button = ((key == KEY_LEFT ? --button : ++button) < 0) ?
+				2 : (button > 2 ? 0 : button);
+
+			print_buttons(dialog, height, width, button, button_names, button_count);
+			wrefresh(menu);
+			break;
+		case ' ':
+		case 'S':
+		case 's':
+		case 'A':
+		case 'a':
+		case 'C':
+		case 'c':
+		case '\n':
+			/* save scroll info */
+			*s_scroll = scroll;
+			delwin(menu);
+			delwin(dialog);
+			item_set(scroll + choice);
+			item_set_selected(1);
+			switch (key) {
+			case 'S':
+			case 's':
+				return 0;
+			case 'A':
+			case 'a':
+				return 1;
+			case 'C':
+			case 'c':
+				return 2;
+			case '\n':
+				return button;
+			}
+			return 0;
+		case 'e':
+		case 'x':
+			key = KEY_ESC;
+			break;
+		case KEY_ESC:
+			key = on_key_esc(menu);
+			break;
+		case KEY_RESIZE:
+			on_key_resize();
+			delwin(menu);
+			delwin(dialog);
+			goto do_resize;
+		}
+	}
+	delwin(menu);
+	delwin(dialog);
+	return key;		/* ESC pressed */
+}

+ 66 - 0
examples/camera/camera_demo3_srcs/param.c

@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "param.h"
+
+char param[10][10][MENU_ITEM_MAX_LEN+1];
+
+static void GetSubStr(char *des, char *src, char ch, int n)
+{
+	int i, len;
+	char *p1, *p, tmp[300];
+	strcpy(tmp, src);
+	*des = 0;
+	p1 = tmp;
+
+	for (int i = 0; i < n; i++) {
+		p = (char *)strchr(p1, ch);
+		if (p != NULL) {
+			*p++ = 0;
+			p1 = p;
+		}
+	}
+
+	p = (char *)strchr(p1, ch);
+	if (p != NULL) {
+		*p = 0;
+		strcpy(des, p1);
+	}
+}
+
+int get_param(char *name)
+{
+	FILE *fp;
+	char ss[201], xm[3], gs[3];
+	int i, j;
+	sprintf(ss, "%s.conf", name);
+	if ((fp = fopen(ss, "r")) == NULL) return (-1);
+	for (j = 0; j < 10; j++)
+		for (i = 0; i < 10; i++)
+			memset(param[j][i], 0, 13);
+	while (1) {
+		memset(ss, 0, 201);
+		fgets(ss, 200, fp);
+		if (feof(fp)) break;
+		if (ss[0] == '#') continue;
+		GetSubStr(xm, ss, '|', 0);
+		GetSubStr(gs, ss, '|', 1);
+		j = atoi(xm);
+		for (i = 1; i <= atoi(gs); i++) {
+			sprintf(param[j][0], "%s", gs);
+			GetSubStr(param[j][i], ss, '|', i + 1);
+		}
+	}
+	fclose(fp);
+	return (0);
+}
+

+ 42 - 0
examples/camera/camera_demo3_srcs/param.h

@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __PARAM_H__
+#define __PARAM_H__
+
+#include <curses.h>
+
+#define MENU_ITEM_MAX_LEN 16
+extern char param[10][10][MENU_ITEM_MAX_LEN+1];
+int get_param(char *name);
+
+#define MENU_CAMERA 1
+typedef enum {
+	MENU_CAMERA_LIST = 0,
+	MENU_CAMERA_OPEN,
+	MENU_CAMERA_SET_MODE,
+	MENU_CAMERA_SET_PROPERTY,
+	MENU_CAMERA_CLOSE,
+} menu_camera_item_e;
+
+#define MENU_CHANNEL 2
+typedef enum {
+	MENU_CHANNEL_LIST = 0,
+	MENU_CHANNEL_OPEN,
+	MENU_CHANNEL_CLOSE,
+} menu_channel_item_e;
+
+#define MENU_EVENT_RUN 3
+typedef enum {
+	MENU_EVENT_SUBSCRIBE_ACTION = 0,
+	MENU_EVENT_START_STOP,
+} menu_event_run_item_e;
+
+
+#endif /* __PARAM_H__ */

+ 414 - 0
examples/camera/camera_demo3_srcs/textbox.c

@@ -0,0 +1,414 @@
+/*
+ *  textbox.c -- implements the text box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "dialog.h"
+#include "app_dialogs.h"
+
+static void back_lines(int n);
+static void print_page(WINDOW *win, int height, int width, update_text_fn
+		       update_text, void *data);
+static void print_line(WINDOW *win, int row, int width);
+static char *get_line(void);
+static void print_position(WINDOW * win);
+
+static int hscroll;
+static int begin_reached, end_reached, page_length;
+static char *buf;
+static char *page;
+
+/*
+ * refresh window content
+ */
+static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
+			     int cur_y, int cur_x, update_text_fn update_text,
+			     void *data)
+{
+	print_page(box, boxh, boxw, update_text, data);
+	print_position(dialog);
+	wmove(dialog, cur_y, cur_x);	/* Restore cursor position */
+	wrefresh(dialog);
+}
+
+/*
+ * Display text from a file in a dialog box.
+ *
+ * keys is a null-terminated array
+ * update_text() may not add or remove any '\n' or '\0' in tbuf
+ */
+int dialog_textbox(const char *title, char *tbuf, int initial_height,
+		   int initial_width, int *keys, int *_vscroll, int *_hscroll,
+		   update_text_fn update_text, void *data)
+{
+	int i, x, y, cur_x, cur_y, key = 0;
+	int height, width, boxh, boxw;
+	WINDOW *dialog, *box;
+	bool done = false;
+
+	begin_reached = 1;
+	end_reached = 0;
+	page_length = 0;
+	hscroll = 0;
+	buf = tbuf;
+	page = buf;	/* page is pointer to start of page to be displayed */
+
+	if (_vscroll && *_vscroll) {
+		begin_reached = 0;
+
+		for (i = 0; i < *_vscroll; i++)
+			get_line();
+	}
+	if (_hscroll)
+		hscroll = *_hscroll;
+
+do_resize:
+	getmaxyx(stdscr, height, width);
+	if (height < TEXTBOX_HEIGTH_MIN || width < TEXTBOX_WIDTH_MIN)
+		return -ERRDISPLAYTOOSMALL;
+	if (initial_height != 0)
+		height = initial_height;
+	else
+		if (height > 4)
+			height -= 4;
+		else
+			height = 0;
+	if (initial_width != 0)
+		width = initial_width;
+	else
+		if (width > 5)
+			width -= 5;
+		else
+			width = 0;
+
+	/* center dialog box on screen */
+	x = (WIN_COLS - width) / 2;
+	y = (WIN_ROWS - height) / 2;
+
+	draw_shadow(stdscr, y, x, height, width);
+
+	dialog = newwin(height, width, y, x);
+	keypad(dialog, TRUE);
+
+	/* Create window for box region, used for scrolling text */
+	boxh = height - 4;
+	boxw = width - 2;
+	box = subwin(dialog, boxh, boxw, y + 1, x + 1);
+	wattrset(box, dlg.dialog.atr);
+	wbkgdset(box, dlg.dialog.atr & A_COLOR);
+
+	keypad(box, TRUE);
+
+	/* register the new window, along with its borders */
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
+
+	wattrset(dialog, dlg.border.atr);
+	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+	for (i = 0; i < width - 2; i++)
+		waddch(dialog, ACS_HLINE);
+	wattrset(dialog, dlg.dialog.atr);
+	wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
+	waddch(dialog, ACS_RTEE);
+
+	print_title(dialog, title, width);
+
+	print_button(dialog, gettext(" Exit "), height - 2, width / 2 - 4, TRUE);
+	wnoutrefresh(dialog);
+	getyx(dialog, cur_y, cur_x);	/* Save cursor position */
+
+	/* Print first page of text */
+	attr_clear(box, boxh, boxw, dlg.dialog.atr);
+	refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x, update_text,
+			 data);
+
+	while (!done) {
+		key = wgetch(dialog);
+		switch (key) {
+		case 'E':	/* Exit */
+		case 'e':
+		case 'X':
+		case 'x':
+		case 'q':
+		case '\n':
+			done = true;
+			break;
+		case 'g':	/* First page */
+		case KEY_HOME:
+			if (!begin_reached) {
+				begin_reached = 1;
+				page = buf;
+				refresh_text_box(dialog, box, boxh, boxw,
+						 cur_y, cur_x, update_text,
+						 data);
+			}
+			break;
+		case 'G':	/* Last page */
+		case KEY_END:
+
+			end_reached = 1;
+			/* point to last char in buf */
+			page = buf + strlen(buf);
+			back_lines(boxh);
+			refresh_text_box(dialog, box, boxh, boxw, cur_y,
+					 cur_x, update_text, data);
+			break;
+		case 'K':	/* Previous line */
+		case 'k':
+		case KEY_UP:
+			if (begin_reached)
+				break;
+
+			back_lines(page_length + 1);
+			refresh_text_box(dialog, box, boxh, boxw, cur_y,
+					 cur_x, update_text, data);
+			break;
+		case 'B':	/* Previous page */
+		case 'b':
+		case 'u':
+		case KEY_PPAGE:
+			if (begin_reached)
+				break;
+			back_lines(page_length + boxh);
+			refresh_text_box(dialog, box, boxh, boxw, cur_y,
+					 cur_x, update_text, data);
+			break;
+		case 'J':	/* Next line */
+		case 'j':
+		case KEY_DOWN:
+			if (end_reached)
+				break;
+
+			back_lines(page_length - 1);
+			refresh_text_box(dialog, box, boxh, boxw, cur_y,
+					 cur_x, update_text, data);
+			break;
+		case KEY_NPAGE:	/* Next page */
+		case ' ':
+		case 'd':
+			if (end_reached)
+				break;
+
+			begin_reached = 0;
+			refresh_text_box(dialog, box, boxh, boxw, cur_y,
+					 cur_x, update_text, data);
+			break;
+		case '0':	/* Beginning of line */
+		case 'H':	/* Scroll left */
+		case 'h':
+		case KEY_LEFT:
+			if (hscroll <= 0)
+				break;
+
+			if (key == '0')
+				hscroll = 0;
+			else
+				hscroll--;
+			/* Reprint current page to scroll horizontally */
+			back_lines(page_length);
+			refresh_text_box(dialog, box, boxh, boxw, cur_y,
+					 cur_x, update_text, data);
+			break;
+		case 'L':	/* Scroll right */
+		case 'l':
+		case KEY_RIGHT:
+			if (hscroll >= MAX_LEN)
+				break;
+			hscroll++;
+			/* Reprint current page to scroll horizontally */
+			back_lines(page_length);
+			refresh_text_box(dialog, box, boxh, boxw, cur_y,
+					 cur_x, update_text, data);
+			break;
+		case KEY_ESC:
+			if (on_key_esc(dialog) == KEY_ESC)
+				done = true;
+			break;
+		case KEY_RESIZE:
+			back_lines(height);
+			delwin(box);
+			delwin(dialog);
+			on_key_resize();
+			goto do_resize;
+		default:
+			for (i = 0; keys[i]; i++) {
+				if (key == keys[i]) {
+					done = true;
+					break;
+				}
+			}
+		}
+	}
+	delwin(box);
+	delwin(dialog);
+	if (_vscroll) {
+		const char *s;
+
+		s = buf;
+		*_vscroll = 0;
+		back_lines(page_length);
+		while (s < page && (s = strchr(s, '\n'))) {
+			(*_vscroll)++;
+			s++;
+		}
+	}
+	if (_hscroll)
+		*_hscroll = hscroll;
+	return key;
+}
+
+int dialog_textbox_simple(const char *title, char *tbuf, int initial_height, int initial_width)
+{
+	return dialog_textbox(title, tbuf,initial_height, initial_width,
+			      (int []) {0}, NULL, NULL, NULL, NULL);
+}
+
+/*
+ * Go back 'n' lines in text. Called by dialog_textbox().
+ * 'page' will be updated to point to the desired line in 'buf'.
+ */
+static void back_lines(int n)
+{
+	int i;
+
+	begin_reached = 0;
+	/* Go back 'n' lines */
+	for (i = 0; i < n; i++) {
+		if (*page == '\0') {
+			if (end_reached) {
+				end_reached = 0;
+				continue;
+			}
+		}
+		if (page == buf) {
+			begin_reached = 1;
+			return;
+		}
+		page--;
+		do {
+			if (page == buf) {
+				begin_reached = 1;
+				return;
+			}
+			page--;
+		} while (*page != '\n');
+		page++;
+	}
+}
+
+/*
+ * Print a new page of text.
+ */
+static void print_page(WINDOW *win, int height, int width, update_text_fn
+		       update_text, void *data)
+{
+	int i, passed_end = 0;
+
+	if (update_text) {
+		char *end;
+
+		for (i = 0; i < height; i++)
+			get_line();
+		end = page;
+		back_lines(height);
+		update_text(buf, page - buf, end - buf, data);
+	}
+
+	page_length = 0;
+	for (i = 0; i < height; i++) {
+		print_line(win, i, width);
+		if (!passed_end)
+			page_length++;
+		if (end_reached && !passed_end)
+			passed_end = 1;
+	}
+	wnoutrefresh(win);
+}
+
+/*
+ * Print a new line of text.
+ */
+static void print_line(WINDOW * win, int row, int width)
+{
+	char *line;
+
+	line = get_line();
+	line += MIN(strlen(line), hscroll);	/* Scroll horizontally */
+	wmove(win, row, 0);	/* move cursor to correct line */
+	waddch(win, ' ');
+	waddnstr(win, line, MIN(strlen(line), width - 2));
+
+	/* Clear 'residue' of previous line */
+#if OLD_NCURSES
+	{
+		int x = getcurx(win);
+		int i;
+		for (i = 0; i < width - x; i++)
+			waddch(win, ' ');
+	}
+#else
+	wclrtoeol(win);
+#endif
+}
+
+/*
+ * Return current line of text. Called by dialog_textbox() and print_line().
+ * 'page' should point to start of current line before calling, and will be
+ * updated to point to start of next line.
+ */
+static char *get_line(void)
+{
+	int i = 0;
+	static char line[MAX_LEN + 1];
+
+	end_reached = 0;
+	while (*page != '\n') {
+		if (*page == '\0') {
+			end_reached = 1;
+			break;
+		} else if (i < MAX_LEN)
+			line[i++] = *(page++);
+		else {
+			/* Truncate lines longer than MAX_LEN characters */
+			if (i == MAX_LEN)
+				line[i++] = '\0';
+			page++;
+		}
+	}
+	if (i <= MAX_LEN)
+		line[i] = '\0';
+	if (!end_reached)
+		page++;		/* move past '\n' */
+
+	return line;
+}
+
+/*
+ * Print current position
+ */
+static void print_position(WINDOW * win)
+{
+	int percent;
+
+	wattrset(win, dlg.position_indicator.atr);
+	wbkgdset(win, dlg.position_indicator.atr & A_COLOR);
+	percent = (page - buf) * 100 / strlen(buf);
+	wmove(win, getmaxy(win) - 3, getmaxx(win) - 9);
+	wprintw(win, "(%3d%%)", percent);
+}

+ 735 - 0
examples/camera/camera_demo3_srcs/util.c

@@ -0,0 +1,735 @@
+/*
+ *  util.c
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdarg.h>
+
+#include "dialog.h"
+
+/* Needed in signal handler in mconf.c */
+int saved_x, saved_y;
+
+struct dialog_info dlg;
+
+static void set_mono_theme(void)
+{
+	dlg.screen.atr = A_NORMAL;
+	dlg.shadow.atr = A_NORMAL;
+	dlg.dialog.atr = A_NORMAL;
+	dlg.title.atr = A_BOLD;
+	dlg.border.atr = A_NORMAL;
+	dlg.button_active.atr = A_REVERSE;
+	dlg.button_inactive.atr = A_DIM;
+	dlg.button_key_active.atr = A_REVERSE;
+	dlg.button_key_inactive.atr = A_BOLD;
+	dlg.button_label_active.atr = A_REVERSE;
+	dlg.button_label_inactive.atr = A_NORMAL;
+	dlg.inputbox.atr = A_NORMAL;
+	dlg.inputbox_border.atr = A_NORMAL;
+	dlg.searchbox.atr = A_NORMAL;
+	dlg.searchbox_title.atr = A_BOLD;
+	dlg.searchbox_border.atr = A_NORMAL;
+	dlg.position_indicator.atr = A_BOLD;
+	dlg.menubox.atr = A_NORMAL;
+	dlg.menubox_border.atr = A_NORMAL;
+	dlg.item.atr = A_NORMAL;
+	dlg.item_selected.atr = A_REVERSE;
+	dlg.tag.atr = A_BOLD;
+	dlg.tag_selected.atr = A_REVERSE;
+	dlg.tag_key.atr = A_BOLD;
+	dlg.tag_key_selected.atr = A_REVERSE;
+	dlg.check.atr = A_BOLD;
+	dlg.check_selected.atr = A_REVERSE;
+	dlg.uarrow.atr = A_BOLD;
+	dlg.darrow.atr = A_BOLD;
+}
+
+#define DLG_COLOR(dialog, f, b, h) \
+do {                               \
+	dlg.dialog.fg = (f);       \
+	dlg.dialog.bg = (b);       \
+	dlg.dialog.hl = (h);       \
+} while (0)
+
+static void set_classic_theme(void)
+{
+	DLG_COLOR(screen,                COLOR_CYAN,   COLOR_BLUE,   true);
+	DLG_COLOR(shadow,                COLOR_BLACK,  COLOR_BLACK,  true);
+	DLG_COLOR(dialog,                COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(title,                 COLOR_YELLOW, COLOR_WHITE,  true);
+	DLG_COLOR(border,                COLOR_WHITE,  COLOR_WHITE,  true);
+	DLG_COLOR(button_active,         COLOR_WHITE,  COLOR_BLUE,   true);
+	DLG_COLOR(button_inactive,       COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(button_key_active,     COLOR_WHITE,  COLOR_BLUE,   true);
+	DLG_COLOR(button_key_inactive,   COLOR_RED,    COLOR_WHITE,  false);
+	DLG_COLOR(button_label_active,   COLOR_YELLOW, COLOR_BLUE,   true);
+	DLG_COLOR(button_label_inactive, COLOR_BLACK,  COLOR_WHITE,  true);
+	DLG_COLOR(inputbox,              COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(inputbox_border,       COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(searchbox,             COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(searchbox_title,       COLOR_YELLOW, COLOR_WHITE,  true);
+	DLG_COLOR(searchbox_border,      COLOR_WHITE,  COLOR_WHITE,  true);
+	DLG_COLOR(position_indicator,    COLOR_YELLOW, COLOR_WHITE,  true);
+	DLG_COLOR(menubox,               COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(menubox_border,        COLOR_WHITE,  COLOR_WHITE,  true);
+	DLG_COLOR(item,                  COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(item_selected,         COLOR_WHITE,  COLOR_BLUE,   true);
+	DLG_COLOR(tag,                   COLOR_YELLOW, COLOR_WHITE,  true);
+	DLG_COLOR(tag_selected,          COLOR_YELLOW, COLOR_BLUE,   true);
+	DLG_COLOR(tag_key,               COLOR_YELLOW, COLOR_WHITE,  true);
+	DLG_COLOR(tag_key_selected,      COLOR_YELLOW, COLOR_BLUE,   true);
+	DLG_COLOR(check,                 COLOR_BLACK,  COLOR_WHITE,  false);
+	DLG_COLOR(check_selected,        COLOR_WHITE,  COLOR_BLUE,   true);
+	DLG_COLOR(uarrow,                COLOR_GREEN,  COLOR_WHITE,  true);
+	DLG_COLOR(darrow,                COLOR_GREEN,  COLOR_WHITE,  true);
+}
+
+static void set_blackbg_theme(void)
+{
+	DLG_COLOR(screen, COLOR_RED,   COLOR_BLACK, true);
+	DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, false);
+	DLG_COLOR(dialog, COLOR_WHITE, COLOR_BLACK, false);
+	DLG_COLOR(title,  COLOR_RED,   COLOR_BLACK, false);
+	DLG_COLOR(border, COLOR_BLACK, COLOR_BLACK, true);
+
+	DLG_COLOR(button_active,         COLOR_YELLOW, COLOR_RED,   false);
+	DLG_COLOR(button_inactive,       COLOR_YELLOW, COLOR_BLACK, false);
+	DLG_COLOR(button_key_active,     COLOR_YELLOW, COLOR_RED,   true);
+	DLG_COLOR(button_key_inactive,   COLOR_RED,    COLOR_BLACK, false);
+	DLG_COLOR(button_label_active,   COLOR_WHITE,  COLOR_RED,   false);
+	DLG_COLOR(button_label_inactive, COLOR_BLACK,  COLOR_BLACK, true);
+
+	DLG_COLOR(inputbox,         COLOR_YELLOW, COLOR_BLACK, false);
+	DLG_COLOR(inputbox_border,  COLOR_YELLOW, COLOR_BLACK, false);
+
+	DLG_COLOR(searchbox,        COLOR_YELLOW, COLOR_BLACK, false);
+	DLG_COLOR(searchbox_title,  COLOR_YELLOW, COLOR_BLACK, true);
+	DLG_COLOR(searchbox_border, COLOR_BLACK,  COLOR_BLACK, true);
+
+	DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK,  false);
+
+	DLG_COLOR(menubox,          COLOR_YELLOW, COLOR_BLACK, false);
+	DLG_COLOR(menubox_border,   COLOR_BLACK,  COLOR_BLACK, true);
+
+	DLG_COLOR(item,             COLOR_WHITE, COLOR_BLACK, false);
+	DLG_COLOR(item_selected,    COLOR_WHITE, COLOR_RED,   false);
+
+	DLG_COLOR(tag,              COLOR_RED,    COLOR_BLACK, false);
+	DLG_COLOR(tag_selected,     COLOR_YELLOW, COLOR_RED,   true);
+	DLG_COLOR(tag_key,          COLOR_RED,    COLOR_BLACK, false);
+	DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_RED,   true);
+
+	DLG_COLOR(check,            COLOR_YELLOW, COLOR_BLACK, false);
+	DLG_COLOR(check_selected,   COLOR_YELLOW, COLOR_RED,   true);
+
+	DLG_COLOR(uarrow, COLOR_RED, COLOR_BLACK, false);
+	DLG_COLOR(darrow, COLOR_RED, COLOR_BLACK, false);
+}
+
+static void set_bluetitle_theme(void)
+{
+	set_classic_theme();
+	DLG_COLOR(title,               COLOR_BLUE,   COLOR_WHITE, true);
+	DLG_COLOR(button_key_active,   COLOR_YELLOW, COLOR_BLUE,  true);
+	DLG_COLOR(button_label_active, COLOR_WHITE,  COLOR_BLUE,  true);
+	DLG_COLOR(searchbox_title,     COLOR_BLUE,   COLOR_WHITE, true);
+	DLG_COLOR(position_indicator,  COLOR_BLUE,   COLOR_WHITE, true);
+	DLG_COLOR(tag,                 COLOR_BLUE,   COLOR_WHITE, true);
+	DLG_COLOR(tag_key,             COLOR_BLUE,   COLOR_WHITE, true);
+
+}
+
+/*
+ * Select color theme
+ */
+static int set_theme(const char *theme)
+{
+	int use_color = 1;
+	if (!theme)
+		set_bluetitle_theme();
+	else if (strcmp(theme, "classic") == 0)
+		set_classic_theme();
+	else if (strcmp(theme, "bluetitle") == 0)
+		set_bluetitle_theme();
+	else if (strcmp(theme, "blackbg") == 0)
+		set_blackbg_theme();
+	else if (strcmp(theme, "mono") == 0)
+		use_color = 0;
+
+	return use_color;
+}
+
+static void init_one_color(struct dialog_color *color)
+{
+	static int pair = 10;
+
+	pair++;
+	init_pair(pair, color->fg, color->bg);
+	if (color->hl)
+		color->atr = A_BOLD | COLOR_PAIR(pair);
+	else
+		color->atr = COLOR_PAIR(pair);
+}
+
+static void init_dialog_colors(void)
+{
+	init_one_color(&dlg.screen);
+	init_one_color(&dlg.shadow);
+	init_one_color(&dlg.dialog);
+	init_one_color(&dlg.title);
+	init_one_color(&dlg.border);
+	init_one_color(&dlg.button_active);
+	init_one_color(&dlg.button_inactive);
+	init_one_color(&dlg.button_key_active);
+	init_one_color(&dlg.button_key_inactive);
+	init_one_color(&dlg.button_label_active);
+	init_one_color(&dlg.button_label_inactive);
+	init_one_color(&dlg.inputbox);
+	init_one_color(&dlg.inputbox_border);
+	init_one_color(&dlg.searchbox);
+	init_one_color(&dlg.searchbox_title);
+	init_one_color(&dlg.searchbox_border);
+	init_one_color(&dlg.position_indicator);
+	init_one_color(&dlg.menubox);
+	init_one_color(&dlg.menubox_border);
+	init_one_color(&dlg.item);
+	init_one_color(&dlg.item_selected);
+	init_one_color(&dlg.tag);
+	init_one_color(&dlg.tag_selected);
+	init_one_color(&dlg.tag_key);
+	init_one_color(&dlg.tag_key_selected);
+	init_one_color(&dlg.check);
+	init_one_color(&dlg.check_selected);
+	init_one_color(&dlg.uarrow);
+	init_one_color(&dlg.darrow);
+}
+
+/*
+ * Setup for color display
+ */
+static void color_setup(const char *theme)
+{
+	int use_color;
+
+	use_color = set_theme(theme);
+	if (use_color && has_colors()) {
+		start_color();
+		init_dialog_colors();
+	} else
+		set_mono_theme();
+}
+
+/*
+ * Set window to attribute 'attr'
+ */
+void attr_clear(WINDOW * win, int height, int width, chtype attr)
+{
+	int i, j;
+
+	wattrset(win, attr);
+	for (i = 0; i < height; i++) {
+		wmove(win, i, 0);
+		for (j = 0; j < width; j++)
+			waddch(win, ' ');
+	}
+	touchwin(win);
+}
+
+void dialog_clear(void)
+{
+	int lines, columns;
+
+	lines = getmaxy(stdscr);
+	columns = getmaxx(stdscr);
+
+	attr_clear(stdscr, lines, columns, dlg.screen.atr);
+	/* Display background title if it exists ... - SLH */
+	if (dlg.backtitle != NULL) {
+		int i, len = 0, skip = 0;
+		struct subtitle_list *pos;
+
+		wattrset(stdscr, dlg.screen.atr);
+		mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle);
+
+		for (pos = dlg.subtitles; pos != NULL; pos = pos->next) {
+			/* 3 is for the arrow and spaces */
+			len += strlen(pos->text) + 3;
+		}
+
+		wmove(stdscr, 1, 1);
+		if (len > columns - 2) {
+			const char *ellipsis = "[...] ";
+			waddstr(stdscr, ellipsis);
+			skip = len - (columns - 2 - strlen(ellipsis));
+		}
+
+		for (pos = dlg.subtitles; pos != NULL; pos = pos->next) {
+			if (skip == 0)
+				waddch(stdscr, ACS_RARROW);
+			else
+				skip--;
+
+			if (skip == 0)
+				waddch(stdscr, ' ');
+			else
+				skip--;
+
+			if (skip < strlen(pos->text)) {
+				waddstr(stdscr, pos->text + skip);
+				skip = 0;
+			} else
+				skip -= strlen(pos->text);
+
+			if (skip == 0)
+				waddch(stdscr, ' ');
+			else
+				skip--;
+		}
+
+		for (i = len + 1; i < columns - 1; i++)
+			waddch(stdscr, ACS_HLINE);
+	}
+	wnoutrefresh(stdscr);
+}
+
+/*
+ * Do some initialization for dialog
+ */
+int init_dialog(const char *backtitle)
+{
+	int height, width;
+
+	//initscr();		/* Init curses */
+
+	/* Get current cursor position for signal handler in mconf.c */
+	getyx(stdscr, saved_y, saved_x);
+
+	getmaxyx(stdscr, height, width);
+	if (height < WINDOW_HEIGTH_MIN || width < WINDOW_WIDTH_MIN) {
+		endwin();
+		return -ERRDISPLAYTOOSMALL;
+	}
+
+	dlg.backtitle = backtitle;
+	color_setup("classic");
+
+	keypad(stdscr, TRUE);
+	cbreak();
+	noecho();
+	dialog_clear();
+
+	return 0;
+}
+
+void set_dialog_backtitle(const char *backtitle)
+{
+	dlg.backtitle = backtitle;
+}
+
+void set_dialog_subtitles(struct subtitle_list *subtitles)
+{
+	dlg.subtitles = subtitles;
+}
+
+/*
+ * End using dialog functions.
+ */
+void end_dialog(int x, int y)
+{
+	/* move cursor back to original position */
+	move(y, x);
+	refresh();
+	endwin();
+}
+
+/* Print the title of the dialog. Center the title and truncate
+ * tile if wider than dialog (- 2 chars).
+ **/
+void print_title(WINDOW *dialog, const char *title, int width)
+{
+	if (title) {
+		int tlen = MIN(width - 2, strlen(title));
+		wattrset(dialog, dlg.title.atr);
+		mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
+		mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen);
+		waddch(dialog, ' ');
+	}
+}
+
+/*
+ * Print a string of text in a window, automatically wrap around to the
+ * next line if the string is too long to fit on one line. Newline
+ * characters '\n' are propperly processed.  We start on a new line
+ * if there is no room for at least 4 nonblanks following a double-space.
+ */
+void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x)
+{
+	int newl, cur_x, cur_y;
+	int prompt_len, room, wlen;
+	char tempstr[MAX_LEN + 1], *word, *sp, *sp2, *newline_separator = 0;
+
+	strcpy(tempstr, prompt);
+
+	prompt_len = strlen(tempstr);
+
+	if (prompt_len <= width - x * 2) {	/* If prompt is short */
+		wmove(win, y, (width - prompt_len) / 2);
+		waddstr(win, tempstr);
+	} else {
+		cur_x = x;
+		cur_y = y;
+		newl = 1;
+		word = tempstr;
+		while (word && *word) {
+			sp = strpbrk(word, "\n ");
+			if (sp && *sp == '\n')
+				newline_separator = sp;
+
+			if (sp)
+				*sp++ = 0;
+
+			/* Wrap to next line if either the word does not fit,
+			   or it is the first word of a new sentence, and it is
+			   short, and the next word does not fit. */
+			room = width - cur_x;
+			wlen = strlen(word);
+			if (wlen > room ||
+			    (newl && wlen < 4 && sp
+			     && wlen + 1 + strlen(sp) > room
+			     && (!(sp2 = strpbrk(sp, "\n "))
+				 || wlen + 1 + (sp2 - sp) > room))) {
+				cur_y++;
+				cur_x = x;
+			}
+			wmove(win, cur_y, cur_x);
+			waddstr(win, word);
+			getyx(win, cur_y, cur_x);
+
+			/* Move to the next line if the word separator was a newline */
+			if (newline_separator) {
+				cur_y++;
+				cur_x = x;
+				newline_separator = 0;
+			} else
+				cur_x++;
+
+			if (sp && *sp == ' ') {
+				cur_x++;	/* double space */
+				while (*++sp == ' ') ;
+				newl = 1;
+			} else
+				newl = 0;
+			word = sp;
+		}
+	}
+}
+
+/*
+ * Print a button
+ */
+void print_button(WINDOW * win, const char *label, int y, int x, int selected)
+{
+	int i, temp;
+
+	wmove(win, y, x);
+	wattrset(win, selected ? dlg.button_active.atr
+		 : dlg.button_inactive.atr);
+	waddstr(win, "<");
+	temp = strspn(label, " ");
+	label += temp;
+	wattrset(win, selected ? dlg.button_label_active.atr
+		 : dlg.button_label_inactive.atr);
+	for (i = 0; i < temp; i++)
+		waddch(win, ' ');
+	wattrset(win, selected ? dlg.button_key_active.atr
+		 : dlg.button_key_inactive.atr);
+	waddch(win, label[0]);
+	wattrset(win, selected ? dlg.button_label_active.atr
+		 : dlg.button_label_inactive.atr);
+	waddstr(win, (char *)label + 1);
+	wattrset(win, selected ? dlg.button_active.atr
+		 : dlg.button_inactive.atr);
+	waddstr(win, ">");
+	wmove(win, y, x + temp + 1);
+}
+
+/*
+ * Draw a rectangular box with line drawing characters
+ */
+void
+draw_box(WINDOW * win, int y, int x, int height, int width,
+	 chtype box, chtype border)
+{
+	int i, j;
+
+	wattrset(win, 0);
+	for (i = 0; i < height; i++) {
+		wmove(win, y + i, x);
+		for (j = 0; j < width; j++)
+			if (!i && !j)
+				waddch(win, border | ACS_ULCORNER);
+			else if (i == height - 1 && !j)
+				waddch(win, border | ACS_LLCORNER);
+			else if (!i && j == width - 1)
+				waddch(win, box | ACS_URCORNER);
+			else if (i == height - 1 && j == width - 1)
+				waddch(win, box | ACS_LRCORNER);
+			else if (!i)
+				waddch(win, border | ACS_HLINE);
+			else if (i == height - 1)
+				waddch(win, box | ACS_HLINE);
+			else if (!j)
+				waddch(win, border | ACS_VLINE);
+			else if (j == width - 1)
+				waddch(win, box | ACS_VLINE);
+			else
+				waddch(win, box | ' ');
+	}
+}
+
+/*
+ * Draw shadows along the right and bottom edge to give a more 3D look
+ * to the boxes
+ */
+void draw_shadow(WINDOW * win, int y, int x, int height, int width)
+{
+	int i;
+
+	if (has_colors()) {	/* Whether terminal supports color? */
+		wattrset(win, dlg.shadow.atr);
+		wmove(win, y + height, x + 2);
+		for (i = 0; i < width; i++)
+			waddch(win, winch(win) & A_CHARTEXT);
+		for (i = y + 1; i < y + height + 1; i++) {
+			wmove(win, i, x + width);
+			waddch(win, winch(win) & A_CHARTEXT);
+			waddch(win, winch(win) & A_CHARTEXT);
+		}
+		wnoutrefresh(win);
+	}
+}
+
+/*
+ *  Return the position of the first alphabetic character in a string.
+ */
+int first_alpha(const char *string, const char *exempt)
+{
+	int i, in_paren = 0, c;
+
+	for (i = 0; i < strlen(string); i++) {
+		c = tolower(string[i]);
+
+		if (strchr("<[(", c))
+			++in_paren;
+		if (strchr(">])", c) && in_paren > 0)
+			--in_paren;
+
+		if ((!in_paren) && isalpha(c) && strchr(exempt, c) == 0)
+			return i;
+	}
+
+	return 0;
+}
+
+/*
+ * ncurses uses ESC to detect escaped char sequences. This resutl in
+ * a small timeout before ESC is actually delivered to the application.
+ * lxdialog suggest <ESC> <ESC> which is correctly translated to two
+ * times esc. But then we need to ignore the second esc to avoid stepping
+ * out one menu too much. Filter away all escaped key sequences since
+ * keypad(FALSE) turn off ncurses support for escape sequences - and thats
+ * needed to make notimeout() do as expected.
+ */
+int on_key_esc(WINDOW *win)
+{
+	int key;
+	int key2;
+	int key3;
+
+	nodelay(win, TRUE);
+	keypad(win, FALSE);
+	key = wgetch(win);
+	key2 = wgetch(win);
+	do {
+		key3 = wgetch(win);
+	} while (key3 != ERR);
+	nodelay(win, FALSE);
+	keypad(win, TRUE);
+	if (key == KEY_ESC && key2 == ERR)
+		return KEY_ESC;
+	else if (key != ERR && key != KEY_ESC && key2 == ERR)
+		ungetch(key);
+
+	return -1;
+}
+
+/* redraw screen in new size */
+int on_key_resize(void)
+{
+	dialog_clear();
+	return KEY_RESIZE;
+}
+
+struct dialog_list *item_cur;
+struct dialog_list item_nil;
+struct dialog_list *item_head;
+
+void item_reset(void)
+{
+	struct dialog_list *p, *next;
+
+	for (p = item_head; p; p = next) {
+		next = p->next;
+		free(p);
+	}
+	item_head = NULL;
+	item_cur = &item_nil;
+}
+
+void item_make(const char *fmt, ...)
+{
+	va_list ap;
+	struct dialog_list *p = malloc(sizeof(*p));
+
+	if (item_head)
+		item_cur->next = p;
+	else
+		item_head = p;
+	item_cur = p;
+	memset(p, 0, sizeof(*p));
+
+	va_start(ap, fmt);
+	vsnprintf(item_cur->node.str, sizeof(item_cur->node.str), fmt, ap);
+	va_end(ap);
+}
+
+void item_add_str(const char *fmt, ...)
+{
+	va_list ap;
+	size_t avail;
+
+	avail = sizeof(item_cur->node.str) - strlen(item_cur->node.str);
+
+	va_start(ap, fmt);
+	vsnprintf(item_cur->node.str + strlen(item_cur->node.str),
+		  avail, fmt, ap);
+	item_cur->node.str[sizeof(item_cur->node.str) - 1] = '\0';
+	va_end(ap);
+}
+
+void item_set_tag(char tag)
+{
+	item_cur->node.tag = tag;
+}
+
+void item_set_int(int int_value)
+{
+	item_cur->node.int_value = int_value;
+}
+
+void item_set_data(void *ptr)
+{
+	item_cur->node.data = ptr;
+}
+
+void item_set_selected(int val)
+{
+	item_cur->node.selected = val;
+}
+
+int item_activate_selected(void)
+{
+	item_foreach()
+		if (item_is_selected())
+			return 1;
+	return 0;
+}
+
+int item_activate_selected_pos(void)
+{
+	int i = 0;
+	item_foreach() {
+		if (item_is_selected())
+			return i;
+		i++;
+	}
+	return -1;
+}
+
+void *item_data(void)
+{
+	return item_cur->node.data;
+}
+
+char item_tag(void)
+{
+	return item_cur->node.tag;
+}
+
+int item_int(void)
+{
+	return item_cur->node.int_value;
+}
+
+int item_count(void)
+{
+	int n = 0;
+	struct dialog_list *p;
+
+	for (p = item_head; p; p = p->next)
+		n++;
+	return n;
+}
+
+void item_set(int n)
+{
+	int i = 0;
+	item_foreach()
+		if (i++ == n)
+			return;
+}
+
+int item_n(void)
+{
+	int n = 0;
+	struct dialog_list *p;
+
+	for (p = item_head; p; p = p->next) {
+		if (p == item_cur)
+			return n;
+		n++;
+	}
+	return 0;
+}
+
+const char *item_str(void)
+{
+	return item_cur->node.str;
+}
+
+int item_is_selected(void)
+{
+	return (item_cur->node.selected != 0);
+}
+
+int item_is_tag(char tag)
+{
+	return (item_cur->node.tag == tag);
+}

+ 123 - 0
examples/camera/camera_demo3_srcs/yesno.c

@@ -0,0 +1,123 @@
+/*
+ *  yesno.c -- implements the yes/no box
+ *
+ *  ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
+ *  MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.com)
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version 2
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define LOG_LEVEL 2
+//#define LOG_PREFIX ""
+#include <syslog.h>
+
+#include "dialog.h"
+#include "app_dialogs.h"
+
+/*
+ * Display termination buttons
+ */
+static void print_buttons(WINDOW * dialog, int height, int width, int selected)
+{
+	int x = width / 2 - 10;
+	int y = height - 2;
+
+	print_button(dialog, gettext(" Yes "), y, x, selected == 0);
+	print_button(dialog, gettext("  No  "), y, x + 13, selected == 1);
+
+	wmove(dialog, y, x + 1 + 13 * selected);
+	wrefresh(dialog);
+}
+
+/*
+ * Display a dialog box with two buttons - Yes and No
+ */
+int dialog_yesno(const char *title, const char *prompt, int height, int width)
+{
+	int i, x, y, key = 0, button = 0;
+	WINDOW *dialog;
+
+do_resize:
+	if (WIN_ROWS < (height + YESNO_HEIGTH_MIN))
+		return -ERRDISPLAYTOOSMALL;
+	if (WIN_COLS < (width + YESNO_WIDTH_MIN))
+		return -ERRDISPLAYTOOSMALL;
+
+	/* center dialog box on screen */
+	x = (WIN_COLS - width) / 2;
+	y = (WIN_ROWS - height) / 2;
+
+	draw_shadow(stdscr, y, x, height, width);
+
+	dialog = newwin(height, width, y, x);
+	keypad(dialog, TRUE);
+
+	//wbkgd(dialog, COLOR_PAIR(0));
+	draw_box(dialog, 0, 0, height, width,
+		 dlg.dialog.atr, dlg.border.atr);
+
+	wattrset(dialog, dlg.border.atr);
+	mvwaddch(dialog, height - 3, 0, ACS_LTEE);
+
+	for (i = 0; i < width - 2; i++)
+		waddch(dialog, ACS_HLINE);
+	wattrset(dialog, dlg.dialog.atr);
+	waddch(dialog, ACS_RTEE);
+
+	print_title(dialog, title, width);
+
+	wattrset(dialog, dlg.dialog.atr);
+	print_autowrap(dialog, prompt, width - 2, 1, 3);
+
+	print_buttons(dialog, height, width, 0);
+
+	while (key != KEY_ESC) {
+		key = wgetch(dialog);
+		switch (key) {
+		case 'Y':
+		case 'y':
+			delwin(dialog);
+			return 0;
+		case 'N':
+		case 'n':
+			delwin(dialog);
+			return 1;
+
+		case TAB:
+		case KEY_LEFT:
+		case KEY_RIGHT:
+			button = ((key == KEY_LEFT ? --button : ++button) < 0) ? 1 : (button > 1 ? 0 : button);
+
+			print_buttons(dialog, height, width, button);
+			wrefresh(dialog);
+			break;
+		case ' ':
+		case '\n':
+			delwin(dialog);
+			return button;
+		case KEY_ESC:
+			key = on_key_esc(dialog);
+			break;
+		case KEY_RESIZE:
+			//delwin(dialog);
+			//on_key_resize();
+			//goto do_resize;
+			;
+		}
+	}
+
+	delwin(dialog);
+	return key;		/* ESC pressed */
+}

+ 297 - 0
examples/camera/camera_demo4.c

@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <pthread.h>
+
+#define LOG_LEVEL 3
+#define LOG_PREFIX "camera_demo4"
+#include <syslog.h>
+
+#include <csi_frame.h>
+#include <csi_camera.h>
+
+#define TEST_DEVICE_NAME "/dev/video0"
+
+typedef struct cam_channel_control {
+	pthread_t thread_id;
+	bool run;
+	csi_cam_handle_t cam_handle;
+	csi_camera_channel_cfg_s chn_cfg;
+} cam_channel_control_t;
+
+static void dump_camera_meta(csi_frame_s *frame);
+static void *channel_thread(void *arg);
+
+int main(int argc, char *argv[])
+{
+	bool running = true;
+	csi_camera_info_s camera_info;
+
+	// 获取设备中,所有的Camera
+	struct csi_camera_infos camera_infos;
+	csi_camera_query_list(&camera_infos);
+	LOG_O("csi_camera_query_list() OK\n");
+
+	// 打印所有设备所支持的Camera
+	for (uint32_t i = 0; i < camera_infos.count; i++) {
+		printf("Camera[%d]: camera_name='%s', device_name='%s', bus_info='%s', capabilities=0x%08x\n",
+		       i, camera_infos.info[i].camera_name, camera_infos.info[i].device_name,
+		       camera_infos.info[i].bus_info, camera_infos.info[i].capabilities);
+	}
+	/*  Camera[0]: camera_name='RGB_Camera', device_name='/dev/video0', bus_info='CSI-MIPI', capabilities=0x00800001
+	 *  Camera[1]: camera_name:'Mono_Camera', device_name:'/dev/video8', bus_info='USB', capabilities=0x00000001
+	 */
+
+	bool found_camera = false;
+	for (uint32_t i = 0; i < camera_infos.count; i++) {
+		if (strcmp(camera_infos.info[i].device_name, TEST_DEVICE_NAME) == 0) {
+			camera_info = camera_infos.info[i];
+			printf("found device_name:'%s'\n", camera_info.device_name);
+			found_camera = true;
+			break;
+		}
+	}
+	if (!found_camera) {
+		LOG_E("Can't find camera_name:'%s'\n", TEST_DEVICE_NAME);
+		exit(-1);
+	}
+
+	printf("The caps are:\n");
+	for (uint32_t i = 1; i < 0x80000000; i = i << 1) {
+		switch (camera_info.capabilities & i) {
+		case CSI_CAMERA_CAP_VIDEO_CAPTURE:
+			printf("\t Video capture\n");
+			break;
+		case CSI_CAMERA_CAP_META_CAPTURE:
+			printf("\t metadata capture\n");
+			break;
+		default:
+			if (camera_info.capabilities & i) {
+				printf("\t unknown capabilities(0x%08x)\n", camera_info.capabilities & i);
+			}
+			break;
+		}
+	}
+	/*  The caps are: Video capture, metadata capture */
+
+	// 打开Camera设备获取句柄,作为后续操对象
+	csi_cam_handle_t cam_handle;
+	csi_camera_open(&cam_handle, camera_info.device_name);
+	LOG_O("csi_camera_open() OK\n");
+
+	// 获取Camera支持的工作模式
+	struct csi_camera_modes camera_modes;
+	camera_modes.count = 0;
+	csi_camera_get_modes(cam_handle, &camera_modes);
+	LOG_O("csi_camera_get_modes() OK\n");
+
+	// 打印camera所支持的所有工作模式
+	printf(" Camera:'%s' modes are:{\n", TEST_DEVICE_NAME);
+	for (uint32_t i = 0; i < camera_modes.count; i++) {
+		printf("\t mode_id=%d: description:'%s'\n",
+		       camera_modes.modes[i].mode_id, camera_modes.modes[i].description);
+	}
+	printf("}\n");
+
+	// 设置camera的工作模式及其配置
+	csi_camera_mode_cfg_s camera_cfg;
+	camera_cfg.mode_id = 1;
+	camera_cfg.calibriation = NULL; // 采用系统默认配置
+	camera_cfg.lib3a = NULL;	// 采用系统默认配置
+	csi_camera_set_mode(cam_handle, &camera_cfg);
+
+	// 获取单个可控单元的属性
+	csi_camera_property_description_s description;
+	description.id = CSI_CAMERA_PID_HFLIP;
+	csi_camera_query_property(cam_handle, &description);
+	printf("properity id=0x%08x type=%d default=%d value=%d\n",
+	       description.id, description.type,
+	       description.default_value.bool_value, description.value.bool_value);
+	/* id=0x0098090x, type=2 default=0 value=1 */
+	/* Other example:
+	 * id=0x0098090y, type=3 min=0 max=255 step=1 default=127 value=116
+	 * id=0x0098090z, type=4 min=0 max=3 default=0 value=2
+	 *                                0: IDLE
+	 *                                1: BUSY
+	 *                                2: REACHED
+	 *                                3: FAILED
+	 */
+
+	// 轮询获取所有可控制的单元
+	description.id = CSI_CAMERA_PID_HFLIP;
+	while (!csi_camera_query_property(cam_handle, &description)) {
+		//printf(...); // 打印属性
+		description.id |= CSI_CAMERA_FLAG_NEXT_CTRL;
+	}
+	LOG_O("csi_camera_query_property() OK\n");
+
+	// 同时配置多个参数
+	csi_camera_properties_s properties;
+	csi_camera_property_s property[2];
+	property[0].id = CSI_CAMERA_PID_HFLIP;
+	property[0].type = CSI_CAMERA_PROPERTY_TYPE_BOOLEAN;
+	property[0].value.bool_value = true;
+	property[0].id = CSI_CAMERA_PID_VFLIP;
+	property[0].type = CSI_CAMERA_PROPERTY_TYPE_BOOLEAN;
+	property[0].value.bool_value = true;
+	properties.count = 2;
+	properties.property = property;
+	csi_camera_get_property(cam_handle, &properties);
+	LOG_O("csi_camera_get_property() OK\n");
+
+	cam_channel_control_t channel_control[2];
+
+	for (int i = 0; i < 2; i++) {
+		cam_channel_control_t *chn_ctrl = &channel_control[i];
+		pthread_t *thread_id = &(chn_ctrl->thread_id);
+		csi_camera_channel_cfg_s *chn_cfg = &(chn_ctrl->chn_cfg);
+		chn_ctrl->run = true;
+		chn_ctrl->cam_handle = cam_handle;
+
+		chn_cfg->frm_cnt = 4;
+		if (i = 0) {
+			chn_cfg->chn_id = CSI_CAMERA_CHANNEL_0;
+			chn_cfg->img_fmt.width = 640;
+			chn_cfg->img_fmt.height = 480;
+			chn_cfg->img_fmt.pix_fmt = CSI_PIX_FMT_NV12;
+		} else {
+			chn_cfg->chn_id = CSI_CAMERA_CHANNEL_1;
+			chn_cfg->img_fmt.width = 1280;
+			chn_cfg->img_fmt.height = 720;
+			chn_cfg->img_fmt.pix_fmt = CSI_PIX_FMT_I420;
+		}
+		chn_cfg->meta_fields = CSI_CAMERA_META_DEFAULT_FIELDS;
+		chn_cfg->capture_type = CSI_CAMERA_CHANNEL_CAPTURE_VIDEO |
+					CSI_CAMERA_CHANNEL_CAPTURE_META;
+
+		pthread_create(thread_id, NULL, channel_thread, chn_ctrl);
+		sleep(1);	// channel[1] start after 1 second
+	}
+	sleep(3);
+	channel_control[0].run = false;
+	sleep(2);
+	channel_control[1].run = false;
+
+	for (int i = 0; i < 2; i++) {
+		cam_channel_control_t *chn_ctrl = &channel_control[i];
+		int chn_id = chn_ctrl->chn_cfg.chn_id;
+		if (pthread_join(chn_ctrl->thread_id, NULL)) {
+			LOG_E("[chn-%d] pthread_join() failed, %s\n", chn_id, strerror(errno));
+		}
+	}
+
+	csi_camera_close(cam_handle);
+	return 0;
+}
+
+static void *channel_thread(void *arg)
+{
+	int ret;
+	cam_channel_control_t *chn_ctrl = (cam_channel_control_t *)arg;
+	csi_cam_handle_t cam_handle = chn_ctrl->cam_handle;
+	int chn_id = chn_ctrl->chn_cfg.chn_id;
+
+	ret = csi_camera_channel_open(cam_handle, &(chn_ctrl->chn_cfg));
+	if (ret != 0) {
+		LOG_E("[chn_%d] csi_camera_channel_open() failed, ret=%d\n", chn_id, ret);
+		return NULL;
+	}
+	LOG_O("[chn_%d] csi_camera_channel_open() OK\n", chn_id);
+
+	// 订阅Event
+	csi_cam_event_handle_t event_handle;
+	csi_camera_create_event(&event_handle, cam_handle);
+	struct csi_camera_event_subscription subscribe_cam;
+	struct csi_camera_event_subscription subscribe_chn;
+	subscribe_cam.type = CSI_CAMERA_EVENT_TYPE_CAMERA; // 订阅Camera的ERROR事件
+	subscribe_cam.id = CSI_CAMERA_EVENT_WARNING | CSI_CAMERA_EVENT_ERROR;
+	csi_camera_subscribe_event(event_handle, &subscribe_cam);
+
+	subscribe_chn.type = chn_id;    // 订阅Channel0的FRAME_READY事件
+	subscribe_chn.id = CSI_CAMERA_CHANNEL_EVENT_FRAME_READY |
+		           CSI_CAMERA_CHANNEL_EVENT_OVERFLOW;
+	csi_camera_subscribe_event(event_handle, &subscribe_chn);
+	LOG_O("Event subscript OK\n");
+
+	// 处理订阅的Event
+	LOG_O("[chn_%d] Starting get events...\n", chn_id);
+	csi_frame_s frame;
+	struct csi_camera_event event;
+
+	while (chn_ctrl->run) {
+		int timeout = 100; // unit: ms, -1 means wait forever, or until error occurs
+		LOG_D("[chn_%d] before csi_camera_get_event\n", chn_id);
+		csi_camera_get_event(event_handle, &event, timeout);
+		LOG_D("[chn_%d] after csi_camera_get_event\n", chn_id);
+
+		switch (event.type) {
+		case CSI_CAMERA_EVENT_TYPE_CAMERA:
+			switch (event.id) {
+			case CSI_CAMERA_EVENT_ERROR:
+				// do sth.
+				break;
+			default:
+				break;
+			}
+		case CSI_CAMERA_EVENT_TYPE_CHANNEL0:
+		case CSI_CAMERA_EVENT_TYPE_CHANNEL1:
+			if (event.type != chn_id) {
+				LOG_E("[chn_%d] Recv type(%d) is not expected\n",
+					chn_id, event.type);
+				break;
+			}
+			switch (event.id) {
+			case CSI_CAMERA_CHANNEL_EVENT_FRAME_READY: {
+				LOG_O("[chn_%d] Get ready frame\n", chn_id);
+				int read_frame_count = csi_camera_get_frame_count(cam_handle, chn_id);
+				for (int i = 0; i < read_frame_count; i++) {
+					csi_camera_get_frame(cam_handle, chn_id, &frame, timeout);
+					dump_camera_meta(&frame);
+					csi_camera_put_frame(&frame);
+				}
+				break;
+			}
+			default:
+				LOG_W("[chn_%d] Get unknown event type\n", event.type);
+				break;
+			}
+		default:
+			break;
+		}
+	}
+
+	csi_camera_unsubscribe_event(event_handle, &subscribe_cam);
+	csi_camera_unsubscribe_event(event_handle, &subscribe_chn);
+	csi_camera_destory_event(event_handle);
+	csi_camera_channel_stop(cam_handle, chn_id);
+	pthread_exit(NULL);
+}
+
+static void dump_camera_meta(csi_frame_s *frame)
+{
+	int i;
+	if (frame->meta.type != CSI_META_TYPE_CAMERA)
+		return;
+
+	csi_camera_meta_s *meta_data = (csi_camera_meta_s *)frame->meta.data;
+	int meta_count = meta_data->count;
+	csi_camrea_meta_unit_s meta_unit;
+
+	for (i = 0; i < meta_count; i++) {
+		csi_camera_frame_get_meta_unit(
+			&meta_unit, meta_data, CSI_CAMERA_META_ID_FRAME_ID);
+		printf("meta_id=%d, meta_type=%d, meta_value=%d",
+		       meta_unit.id, meta_unit.type, meta_unit.int_value);
+	}
+}
+

+ 438 - 0
examples/camera/camera_frame_display.c

@@ -0,0 +1,438 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: ShenWuYi <shenwuyi.swy@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <syslog.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+
+#include <fcntl.h>
+
+#include <csi_camera.h>
+#include <stdlib.h>
+#include "process_linker_types.h"
+#include "process_linker.h"
+#include "video_mem.h"
+
+
+#define NUM_OF_BUFFERS  5
+
+typedef struct _CsiPictureBuffer
+{
+  unsigned int bus_address;
+  void *virtual_address;
+  unsigned int size;
+  int fd;
+} CsiPictureBuffer;
+typedef struct _CsiPlinkContext
+{
+    int useplink;
+    int exitplink;
+    CsiPictureBuffer sendbuffer[NUM_OF_BUFFERS];
+    int sendid;
+    int available_bufs;
+    void *vmem;
+    PlinkHandle plink;
+    PlinkChannelID chnid;
+} CsiPlinkContext;
+static int get_buffer_count(PlinkPacket *pkt)
+{
+    int ret = 0;
+    for (int i = 0; i < pkt->num; i++)
+    {
+        PlinkDescHdr *hdr = (PlinkDescHdr *)(pkt->list[i]);
+        if (hdr->type == PLINK_TYPE_MESSAGE)
+        {
+            int *data = (int *)(pkt->list[i] + DATA_HEADER_SIZE);
+            if (*data == PLINK_EXIT_CODE)
+            {
+                ret |= 0x80000000; // set bit 31 to 1 to indicate 'exit'
+            }
+            else if (*data >= 0)
+                ret++;
+        }
+    }
+
+    return ret;
+}
+
+static void allocate_sendbuffers(CsiPictureBuffer picbuffers[NUM_OF_BUFFERS], unsigned int size, void *vmem)
+{
+    unsigned int buffer_size = (size + 0xFFF) & ~0xFFF;
+    VmemParams params;
+    params.size = buffer_size;
+    params.flags = VMEM_FLAG_CONTIGUOUS | VMEM_FLAG_4GB_ADDR;
+    for (int i = 0; i < NUM_OF_BUFFERS; i++)
+    {
+        VMEM_allocate(vmem, &params);
+        VMEM_mmap(vmem, &params);
+        VMEM_export(vmem, &params);
+        LOG_O("[SERVER] mmap %p from %x with size %d, dma-buf fd %d\n",
+                params.vir_address, params.phy_address, params.size, params.fd);
+        picbuffers[i].virtual_address = params.vir_address;
+        picbuffers[i].bus_address = params.phy_address;
+        picbuffers[i].size = buffer_size;
+        picbuffers[i].fd = params.fd;
+    }
+}
+
+void *vi_plink_create(csi_camera_channel_cfg_s *chn_cfg)
+{
+	int ret = 0;
+    CsiPlinkContext *plink_ctx = NULL;
+    char *env=NULL;
+	if (chn_cfg == NULL) {
+		LOG_E("%s failt to  get chn_cfg\n", __func__);
+		return NULL;
+	}
+
+	plink_ctx = malloc(sizeof(CsiPlinkContext));
+    if(!plink_ctx)
+    {
+        LOG_E("malloc faile\n");
+        return NULL;
+    }
+
+	char *plinknamebase0 = "/tmp/plink.test";
+	char *plinknamebase1 = "/tmp/plink_npu_rgb.test";
+	char *plinknamebase2 = "/tmp/plink.test2";
+	env = getenv("ISP_PLINK_NAME0");
+
+	if (env != NULL) {
+		plinknamebase0  = env;
+	}
+
+	env = getenv("ISP_PLINK_NAME1");
+	if (env != NULL) {
+		plinknamebase1  = env;
+	}
+
+	env = getenv("ISP_PLINK_NAME2");
+	if (env != NULL) {
+		plinknamebase2  = env;
+	}
+	char plinkname[32];
+	if (chn_cfg->chn_id == CSI_CAMERA_CHANNEL_0) {
+		sprintf(plinkname, "%s", plinknamebase0);
+	} else if (chn_cfg->chn_id == CSI_CAMERA_CHANNEL_1) {
+		sprintf(plinkname, "%s",  plinknamebase1);
+	} else {
+		sprintf(plinkname, "%s",  plinknamebase2);
+	}
+	fprintf(stderr, "%s, %d: ISP_PLINK_NAME = %s\n", __func__, __LINE__, plinkname);
+
+
+    plink_ctx->exitplink = 0;
+    fprintf(stderr, "%s, %d: Launching plink server...\n", __func__, __LINE__);
+    memset(&plink_ctx->sendbuffer[0], 0, sizeof(plink_ctx->sendbuffer));
+    if (VMEM_create(&plink_ctx->vmem) != VMEM_STATUS_OK)
+    {
+        fprintf(stderr, "Failed to create VMEM.");
+        return NULL;
+    }
+    else {
+        int framesize = 0;
+        int stride = (chn_cfg->img_fmt.width + 127) & (~127); // align stride to 128
+        switch (chn_cfg->img_fmt.pix_fmt) {
+            case CSI_PIX_FMT_BGR:
+            {
+                framesize = stride * 304 * 3; //stride * chn_cfg->img_fmt.height * 3;
+                allocate_sendbuffers(plink_ctx->sendbuffer, framesize, plink_ctx->vmem);
+                // reset to black picture
+                uint32_t lumasize = stride * chn_cfg->img_fmt.height;
+                for (int i = 0; i < NUM_OF_BUFFERS; i++)
+                    memset(plink_ctx->sendbuffer[i].virtual_address, 0, framesize);
+                break;
+            }
+
+            case CSI_PIX_FMT_NV12:
+            default:
+            {
+                framesize = stride * chn_cfg->img_fmt.height * 3 / 2;
+                allocate_sendbuffers(plink_ctx->sendbuffer, framesize, plink_ctx->vmem);
+                // reset to black picture
+                uint32_t lumasize = stride * chn_cfg->img_fmt.height;
+                for (int i = 0; i < NUM_OF_BUFFERS; i++) {
+                    CsiPictureBuffer *buf = &plink_ctx->sendbuffer[i];
+                    memset(buf->virtual_address, 0, lumasize);
+                    memset(buf->virtual_address + lumasize, 0x80, lumasize/2);
+                }
+                break;
+            }
+        }
+    }
+
+    PLINK_create(&plink_ctx->plink, plinkname, PLINK_MODE_SERVER);
+    if (plink_ctx->plink) {
+        PLINK_connect(plink_ctx->plink, &plink_ctx->chnid);
+    }
+
+    plink_ctx->sendid = 0;
+    plink_ctx->available_bufs = NUM_OF_BUFFERS;
+
+	return plink_ctx;
+}
+
+void vi_plink_release(void * plink)
+{
+    CsiPlinkContext * plink_ctx = (CsiPlinkContext *)plink;
+    if(plink_ctx)
+    {
+        PLINK_close(plink_ctx->plink,plink_ctx->chnid);
+        VMEM_destroy(plink_ctx->vmem);
+    }
+}
+
+
+void display_camera_frame(void *plink, csi_frame_s *frame)
+{
+	
+    CsiPlinkContext * plink_ctx = (CsiPlinkContext *)plink;
+	if ((plink_ctx == NULL) ||  (frame == NULL)) {
+		LOG_E("%s  check param fail\n", __func__);
+        return;
+	}
+
+
+	LOG_O("%sfmt=%d img.strides[0] = %d\n", __func__,frame->img.pix_format, frame->img.strides[0]);
+
+	if (!plink_ctx->exitplink) {
+		struct timeval tv_start, tv_end, tv_duration;
+		gettimeofday(&tv_start, 0);
+		// retrieve buffers
+		PlinkPacket pkt = {0};
+		if (plink_ctx->plink != NULL) {
+			while (PLINK_wait(plink_ctx->plink, plink_ctx->chnid, 0) == PLINK_STATUS_OK)
+			{
+				if (PLINK_recv(plink_ctx->plink, plink_ctx->chnid, &pkt) != PLINK_STATUS_OK) {
+					plink_ctx->exitplink = 1;
+					break;
+				}
+				int count = get_buffer_count(&pkt);
+				if (count >= 0)
+					plink_ctx->available_bufs += count;
+				else {
+					fprintf(stderr, "[SERVER] Exit!\n");
+					plink_ctx->exitplink = 1;
+					break;
+				}
+			}
+		}
+
+        /*
+        void *phy_address = NULL;
+        int dmabuf_fd = -1;
+        if (vi_mem_dmabuf_isenable()) {
+            phy_address = vi_mem_unmap(frame->img.usr_addr[0]);
+            dmabuf_fd = vi_mem_export(phy_address);
+        }
+        */
+
+		// send one buffer if there is available slot
+        if (frame->img.type == CSI_IMG_TYPE_DMA_BUF && !plink_ctx->exitplink
+            && plink_ctx->available_bufs > 0 && plink_ctx->plink != NULL && ((frame->img.pix_format == CSI_PIX_FMT_RAW_8BIT)|| (frame->img.pix_format == CSI_PIX_FMT_RAW_12BIT))) {
+            char str[200];
+            static int i = 0;
+			uint32_t dstw = frame->img.width;//800;
+			uint32_t dsth = frame->img.height;//1280;
+			uint32_t dsts = frame->img.strides[0];//896;
+            i++;
+            sprintf(str, "echo frame is %d > ~/frame", i);
+            system(str);
+
+			PlinkRawInfo info = {0};
+
+			info.header.type = PLINK_TYPE_2D_RAW;
+			info.header.size = DATA_SIZE(info);
+			info.header.id = plink_ctx->sendid + 1;
+
+			info.format = PLINK_COLOR_FormatRawBayer10bit;
+			// info.bus_address = vi_mem_import(frame->img.dmabuf[0].fds) + frame->img.dmabuf[0].offset;
+            // vi_mem_release(info.bus_address);
+
+			info.img_width = dstw;
+			info.img_height = dsth;
+			info.stride = frame->img.strides[0];
+			info.offset = 0;
+			pkt.list[0] = &info;
+			pkt.num = 1;
+			pkt.fd = frame->img.dmabuf[0].fds;
+			if (PLINK_send(plink_ctx->plink, plink_ctx->chnid, &pkt) != PLINK_STATUS_OK)
+				plink_ctx->exitplink = 1;
+			gettimeofday(&tv_end, 0);
+			timersub(&tv_end, &tv_start, &tv_duration);
+			plink_ctx->sendid = (plink_ctx->sendid + 1) % NUM_OF_BUFFERS;
+			plink_ctx->available_bufs -= 1;
+		}
+        else if (frame->img.type == CSI_IMG_TYPE_DMA_BUF && !plink_ctx->exitplink
+            && plink_ctx->available_bufs > 0 && plink_ctx->plink != NULL && ((frame->img.pix_format == CSI_PIX_FMT_YUV_SEMIPLANAR_420)|| (frame->img.pix_format == CSI_PIX_FMT_NV12))) {
+            char str[200];
+            static int i = 0;
+			uint32_t dstw = frame->img.width;//800;
+			uint32_t dsth = frame->img.height;//1280;
+			uint32_t dsts = frame->img.strides[0];//896;
+            i++;
+            sprintf(str, "echo frame is %d > ~/frame", i);
+            system(str);
+
+			PlinkYuvInfo info = {0};
+
+			info.header.type = PLINK_TYPE_2D_YUV;
+			info.header.size = DATA_SIZE(info);
+			info.header.id = plink_ctx->sendid + 1;
+
+			info.format = PLINK_COLOR_FormatYUV420SemiPlanar;
+			// info.bus_address_y = vi_mem_import(frame->img.dmabuf[0].fds) + frame->img.dmabuf[0].offset;
+			// info.bus_address_u = info.bus_address_y + frame->img.dmabuf[1].offset;
+            // vi_mem_release(info.bus_address_y);
+
+			info.pic_width = dstw;
+			info.pic_height = dsth;
+			info.stride_y = dsts;
+			info.stride_u = dsts;
+			info.stride_v = dsts;
+			info.offset_y = 0;
+			info.offset_u = frame->img.dmabuf[1].offset;
+			info.offset_v = frame->img.dmabuf[2].offset;
+			pkt.list[0] = &info;
+			pkt.num = 1;
+			pkt.fd = frame->img.dmabuf[0].fds;
+			if (PLINK_send(plink_ctx->plink, plink_ctx->chnid, &pkt) != PLINK_STATUS_OK)
+				plink_ctx->exitplink = 1;
+			gettimeofday(&tv_end, 0);
+			timersub(&tv_end, &tv_start, &tv_duration);
+			plink_ctx->sendid = (plink_ctx->sendid + 1) % NUM_OF_BUFFERS;
+			plink_ctx->available_bufs -= 1;
+		} else if (!plink_ctx->exitplink && plink_ctx->available_bufs > 0 && plink_ctx->plink != NULL && (frame->img.pix_format == CSI_PIX_FMT_BGR)) {
+			CsiPictureBuffer *buf = &plink_ctx->sendbuffer[plink_ctx->sendid];
+			int y = 0;
+
+			uint8_t *src = frame->img.usr_addr[0];
+			uint8_t *dst = buf->virtual_address;
+			uint32_t srcw = frame->img.width;
+			uint32_t srch = frame->img.height;
+			uint32_t dstw = frame->img.width;
+			uint32_t dsth = frame->img.height;
+			uint32_t dsts = frame->img.width;
+			switch (frame->img.pix_format ) {
+				case CSI_PIX_FMT_BGR:
+				{
+					dstw = 300;
+					dsth = 304;
+					uint32_t w = dstw > srcw ? srcw : dstw;
+					uint32_t h = dsth > srch ? srch : dsth;
+					if (w != 300 || h != 176 || dsts != 304) {
+						fprintf(stderr, "ERROR: expect 300x300 (stride 304) image while recieved %dx%d (stride %d) image\n", w, h, dsts);
+						break;
+					}
+					for (y = 0; y < h; y++)
+					{
+						memcpy(dst, src, w);
+						src += srcw;
+						dst += dsts;
+					}
+					src = frame->img.usr_addr[0] + srcw*srch;
+					dst = buf->virtual_address + dsts*dsth;
+					for (y = 0; y < h; y++)
+					{
+						memcpy(dst, src, w);
+						src += srcw;
+						dst += dsts;
+					}
+					src = frame->img.usr_addr[0] + srcw*srch*2;
+					dst = buf->virtual_address + dsts*dsth*2;
+					for (y = 0; y < h; y++)
+					{
+						memcpy(dst, src, w);
+						src += srcw;
+						dst += dsts;
+					}
+
+					PlinkRGBInfo info = {0};
+
+					info.header.type = PLINK_TYPE_2D_RGB;
+					info.header.size = DATA_SIZE(info);
+					info.header.id = plink_ctx->sendid + 1;
+
+					info.format = PLINK_COLOR_Format24BitBGR888Planar;
+					info.bus_address_b = buf->bus_address;
+					info.bus_address_g = info.bus_address_b + dsts*dsth;
+					info.bus_address_r = info.bus_address_g + dsts*dsth;
+					info.img_width = dstw;
+					info.img_height = dsth;
+					info.stride_b = dsts;
+					info.stride_g = dsts;
+					info.stride_r = dsts;
+
+					pkt.list[0] = &info;
+					pkt.num = 1;
+					pkt.fd = buf->fd;
+
+					if (PLINK_send(plink_ctx->plink, plink_ctx->chnid, &pkt) != PLINK_STATUS_OK)
+						plink_ctx->exitplink = 1;
+					break;
+				}
+
+				case CSI_PIX_FMT_NV12:
+				default:
+				{
+					uint32_t w = dstw > srcw ? srcw : dstw;
+					uint32_t h = dsth > srch ? srch : dsth;
+					for (y = 0; y < h; y++)
+					{
+						memcpy(dst, src, w);
+						src += srcw;
+						dst += dsts;
+					}
+					src = frame->img.usr_addr[0] + frame->img.strides[0] * frame->img.height;
+					dst = buf->virtual_address + (dsts * dsth);
+					for (y = 0; y < h/2; y++)
+					{
+						memcpy(dst, src, w);
+						src += srcw;
+						dst += dsts;
+					}
+
+					PlinkYuvInfo info = {0};
+
+					info.header.type = PLINK_TYPE_2D_YUV;
+					info.header.size = DATA_SIZE(info);
+					info.header.id = plink_ctx->sendid + 1;
+
+					info.format = PLINK_COLOR_FormatYUV420SemiPlanar;
+					info.bus_address_y = buf->bus_address;
+					info.bus_address_u = buf->bus_address + dsts*dsth;
+					info.bus_address_v = info.bus_address_u;
+					info.pic_width = dstw;
+					info.pic_height = dsth;
+					info.stride_y = dsts;
+					info.stride_u = dsts;
+					info.stride_v = dsts;
+
+					pkt.list[0] = &info;
+					pkt.num = 1;
+					pkt.fd = buf->fd;
+					if (PLINK_send(plink_ctx->plink, plink_ctx->chnid, &pkt) != PLINK_STATUS_OK)
+						plink_ctx->exitplink = 1;
+					break;
+				}
+			}
+
+			gettimeofday(&tv_end, 0);
+			timersub(&tv_end, &tv_start, &tv_duration);
+
+			plink_ctx->sendid = (plink_ctx->sendid + 1) % NUM_OF_BUFFERS;
+			plink_ctx->available_bufs -= 1;
+		}
+	}
+	LOG_O("%s exit \n", __func__);
+}

+ 391 - 0
examples/camera/camera_test1.c

@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LOG_LEVEL 2
+#define LOG_PREFIX "camera_demo1"
+#include <syslog.h>
+
+#include <csi_frame.h>
+#include <csi_camera.h>
+
+#ifdef PLATFORM_SIMULATOR
+#include "apputilities.h"
+#endif
+
+static void dump_camera_meta(csi_frame_s *frame);
+static int save_camera_img(csi_frame_s *frame);
+static int save_camera_stream(csi_frame_s *frame);
+
+#define TEST_DEVICE_NAME "/dev/video0"
+#define CSI_CAMERA_TRUE  1
+#define CSI_CAMERA_FALSE 0
+
+char *prog_name; 
+
+void usage()
+{
+	fprintf (stderr,
+			"usage: %s [options]\n"
+			"Options:\n"
+			"\t-D dev		target video device like /dev/video0\n"
+			"\t-R resolution        format is like 640x480\n"
+			"\t-F format		like NV12\n"
+			"\t-C channel_index		channel index defined in dts, index from 0\n"
+			"\t-M output mode		0: save as image; 1: save as stream file\n"
+			"\t-N number for frames		0: record forever; others: the recorded frame numbers"
+			, prog_name
+		);
+}
+
+int main(int argc, char *argv[])
+{
+	bool running = false;
+	csi_camera_info_s camera_info;
+
+	int opt;
+	char device[CSI_CAMERA_NAME_MAX_LEN];    /* target video device like /dev/video0 */
+	char *resolution;    /* resolution information like 640x480 */
+	int hres, vres;    /* resolution information like 640x480 */
+	char *resDelim = "xX";
+	char *format;    /* format information like NV12 */
+	enum csi_pixel_fmt fenum;
+	int channelIdx;    /* channel information like 8 */
+	int outMode = 0;
+	int fNum = 0;
+
+	prog_name = argv[0];
+
+	while ((opt = getopt(argc, argv, "D:R:F:C:M:hN:")) != EOF) {
+		switch(opt) {
+			case 'D':
+				//device = optarg;
+				strcpy(device, optarg);
+				continue;
+			case 'R':
+				resolution = optarg;
+				hres = atoi(strtok(resolution, resDelim));
+				vres = atoi(strtok(NULL, resDelim));
+				continue;
+			case 'M':
+				outMode = atoi(optarg);
+				continue;
+			case 'N':
+				fNum = atoi(optarg);
+				continue;
+			case 'F':
+				format = optarg;
+				if(strstr(format, "NV12")){
+					fenum = CSI_PIX_FMT_NV12;
+				}
+				else if(strstr(format, "I420")){
+					fenum = CSI_PIX_FMT_I420;
+				}
+				else{
+					fenum = CSI_PIX_FMT_I420;
+				}
+				continue;
+			case 'C':
+				channelIdx = atoi(optarg);
+				continue;
+			case '?':
+			case 'h':
+			default:
+				usage();
+				return 1;
+		}
+	}
+
+	const csi_camera_channel_id_e CAMERA_CHANNEL_ID = CSI_CAMERA_CHANNEL_0 + channelIdx;
+	const csi_camera_event_type_e CAMERA_CHANNEL_EVENT_TYPE = CSI_CAMERA_EVENT_TYPE_CHANNEL0 + channelIdx;
+	if (fNum == 0)
+		running == true;
+
+
+	// 打印HAL接口版本号
+	csi_api_version_u version;
+	csi_camera_get_version(&version);
+	printf("Camera HAL version: %d.%d\n", version.major, version.minor);
+
+	// 获取设备中,所有的Camera
+	struct csi_camera_infos camera_infos;
+	memset(&camera_infos, 0, sizeof(camera_infos));
+	csi_camera_query_list(&camera_infos);
+
+	// 打印所有设备所支持的Camera
+	for (int i = 0; i < camera_infos.count; i++) {
+		camera_info = camera_infos.info[i];
+		printf("Camera[%d]: camera_name='%s', device_name='%s', bus_info='%s', capabilities=0x%08x\n",
+				i,
+				camera_info.camera_name, camera_info.device_name, camera_info.bus_info,
+				camera_info.capabilities);
+		printf("Camera[%d] caps are:\n",
+				i); /*  The caps are: Video capture, metadata capture */
+		for (int j = 1; j <= 0x08000000; j = j << 1) {
+			switch (camera_info.capabilities & j) {
+				case CSI_CAMERA_CAP_VIDEO_CAPTURE:
+					printf("\t camera_infos.info[%d]:Video capture,\n", i);
+					break;
+				case CSI_CAMERA_CAP_META_CAPTURE:
+					printf("\t camera_infos.info[%d] metadata capture,\n", i);
+					break;
+				default:
+					if (camera_info.capabilities & j) {
+						printf("\t camera_infos.info[%d] unknown capabilities(0x%08x)\n", i,
+								camera_info.capabilities & j);
+					}
+					break;
+			}
+		}
+	}
+
+
+	// 打开Camera设备获取句柄,作为后续操对象
+	csi_cam_handle_t cam_handle;
+	//csi_camera_open(&cam_handle, camera_info.device_name);
+	strcpy(camera_info.device_name, device);
+	//camera_info.device_name = device;
+	csi_camera_open(&cam_handle, camera_info.device_name);
+	//csi_camera_open(&cam_handle, device);
+	// 获取Camera支持的工作模式
+	struct csi_camera_modes camera_modes;
+	csi_camera_get_modes(cam_handle, &camera_modes);
+
+	// 打印camera所支持的所有工作模式
+	printf("Camera:'%s' modes are:\n", device);
+	printf("{\n");
+	for (int i = 0; i < camera_modes.count; i++) {
+		printf("\t mode_id=%d: description:'%s'\n",
+				camera_modes.modes[i].mode_id, camera_modes.modes[i].description);
+	}
+	printf("}\n");
+
+	// 设置camera的工作模式及其配置
+	csi_camera_mode_cfg_s camera_cfg;
+	camera_cfg.mode_id = 1;
+	camera_cfg.calibriation = NULL; // 采用系统默认配置
+	camera_cfg.lib3a = NULL;	// 采用系统默认配置
+	csi_camera_set_mode(cam_handle, &camera_cfg);
+
+	// 获取单个可控单元的属性
+	csi_camera_property_description_s description;
+	/* id=0x0098090x, type=2 default=0 value=1 */
+	/* Other example:
+	 * id=0x0098090y, type=3 min=0 max=255 step=1 default=127 value=116
+	 * id=0x0098090z, type=4 min=0 max=3 default=0 value=2
+	 *                                0: IDLE
+	 *                                1: BUSY
+	 *                                2: REACHED
+	 *                                3: FAILED
+	 */
+
+	// 轮询获取所有可控制的单元
+	printf("all properties are:\n");
+	description.id = CSI_CAMERA_PID_HFLIP;
+	while (!csi_camera_query_property(cam_handle, &description)) {
+		switch (description.type) {
+			case (CSI_CAMERA_PROPERTY_TYPE_INTEGER):
+				printf("id=0x%08x type=%d default=%d value=%d\n",
+						description.id, description.type,
+						description.default_value.int_value, description.value.int_value);
+				break;
+			case (CSI_CAMERA_PROPERTY_TYPE_BOOLEAN):
+				printf("id=0x%08x type=%d default=%d value=%d\n",
+						description.id, description.type,
+						description.default_value.bool_value, description.value.bool_value);
+				break;
+			case (CSI_CAMERA_PROPERTY_TYPE_ENUM):
+				printf("id=0x%08x type=%d default=%d value=%d\n",
+						description.id, description.type,
+						description.default_value.enum_value, description.value.enum_value);
+				break;
+			case (CSI_CAMERA_PROPERTY_TYPE_STRING):
+				printf("id=0x%08x type=%d default=%s value=%s\n",
+						description.id, description.type,
+						description.default_value.str_value, description.value.str_value);
+				break;
+			case (CSI_CAMERA_PROPERTY_TYPE_BITMASK):
+				printf("id=0x%08x type=%d default=%x value=%x\n",
+						description.id, description.type,
+						description.default_value.bitmask_value, description.value.bitmask_value);
+				break;
+			default:
+				LOG_E("error type!\n");
+				break;
+		}
+		description.id |= CSI_CAMERA_FLAG_NEXT_CTRL;
+	}
+
+	// 同时配置多个参数
+	csi_camera_properties_s properties;
+	csi_camera_property_s property[3];
+	property[0].id = CSI_CAMERA_PID_HFLIP;
+	property[0].type = CSI_CAMERA_PROPERTY_TYPE_BOOLEAN;
+	property[0].value.bool_value = false;
+	property[1].id = CSI_CAMERA_PID_VFLIP;
+	property[1].type = CSI_CAMERA_PROPERTY_TYPE_BOOLEAN;
+	property[1].value.bool_value = false;
+	property[2].id = CSI_CAMERA_PID_ROTATE;
+	property[2].type = CSI_CAMERA_PROPERTY_TYPE_INTEGER;
+	property[2].value.int_value = 0;
+	properties.count = 3;
+	properties.property = property;
+	if (csi_camera_set_property(cam_handle, &properties) < 0) {
+		LOG_O("set_property fail!\n");
+	}
+	LOG_O("set_property ok!\n");
+
+	// 查询输出channel
+	csi_camera_channel_cfg_s chn_cfg;
+	chn_cfg.chn_id = CAMERA_CHANNEL_ID;
+	csi_camera_channel_query(cam_handle, &chn_cfg);
+	if (chn_cfg.status != CSI_CAMERA_CHANNEL_CLOSED) {
+		printf("Can't open CSI_CAMERA_CHANNEL_0\n");
+		exit(-1);
+	}
+
+	// 打开输出channel
+	chn_cfg.chn_id = channelIdx;
+	chn_cfg.frm_cnt = 4;
+	chn_cfg.img_fmt.width = hres;
+	chn_cfg.img_fmt.height = vres;
+	chn_cfg.img_fmt.pix_fmt = fenum;
+	chn_cfg.img_type = CSI_IMG_TYPE_DMA_BUF;
+	chn_cfg.meta_fields = CSI_CAMERA_META_DEFAULT_FIELDS;
+	chn_cfg.capture_type = CSI_CAMERA_CHANNEL_CAPTURE_VIDEO |
+		CSI_CAMERA_CHANNEL_CAPTURE_META;
+	csi_camera_channel_open(cam_handle, &chn_cfg);
+
+	// 订阅Event
+	csi_cam_event_handle_t event_handle;
+	csi_camera_create_event(&event_handle, cam_handle);
+	csi_camera_event_subscription_s subscribe;
+	subscribe.type =
+		CSI_CAMERA_EVENT_TYPE_CAMERA;      // 订阅Camera的ERROR事件
+	subscribe.id = CSI_CAMERA_EVENT_WARNING | CSI_CAMERA_EVENT_ERROR;
+	csi_camera_subscribe_event(event_handle, &subscribe);
+	subscribe.type =
+		CAMERA_CHANNEL_EVENT_TYPE;    // 订阅Channel0的FRAME_READY事件
+	subscribe.id = CSI_CAMERA_CHANNEL_EVENT_FRAME_READY |
+		CSI_CAMERA_CHANNEL_EVENT_OVERFLOW;
+	csi_camera_subscribe_event(event_handle, &subscribe);
+
+	// 开始从channel中取出准备好的frame
+	csi_camera_channel_start(cam_handle, CAMERA_CHANNEL_ID);
+
+	// 处理订阅的Event
+	csi_frame_s frame;
+	struct csi_camera_event event;
+
+	while (running || fNum >= 0 ) {
+		int timeout = -1; // unit: ms, -1 means wait forever, or until error occurs
+		csi_camera_get_event(event_handle, &event, timeout);
+		if(event.type == CSI_CAMERA_EVENT_TYPE_CAMERA){
+			switch (event.id) {
+				case CSI_CAMERA_EVENT_ERROR:
+					// do sth.
+					LOG_D("get CAMERA EVENT CSI_CAMERA_EVENT_ERROR!\n");
+					break;
+				default:
+					break;
+			}
+		}
+		if(event.type == CAMERA_CHANNEL_EVENT_TYPE){
+			switch (event.id) {
+				case CSI_CAMERA_CHANNEL_EVENT_FRAME_READY: {
+					   int read_frame_count = csi_camera_get_frame_count(cam_handle,
+							   CAMERA_CHANNEL_ID);
+					   for (int i = 0; i < read_frame_count; i++) {
+						   csi_camera_get_frame(cam_handle, CAMERA_CHANNEL_ID, &frame, timeout);
+						   fNum--;
+
+#ifdef PLATFORM_SIMULATOR
+						   show_frame_image(frame.img.usr_addr[0], frame.img.height, frame.img.width);
+#endif
+
+						   if (outMode == 0)
+							   save_camera_img(&frame);
+						   else
+							   save_camera_stream(&frame);
+
+						   csi_frame_release(&frame);
+					   }
+					   break;
+				   }
+				default:
+					   break;
+			}
+		}
+	}
+	csi_camera_channel_stop(cam_handle, CAMERA_CHANNEL_ID);
+	usleep (1000000);
+	// 取消订阅某一个event, 也可以直接调用csi_camera_destory_event,结束所有的订阅
+	subscribe.type = CAMERA_CHANNEL_EVENT_TYPE;
+	subscribe.id = CSI_CAMERA_CHANNEL_EVENT_FRAME_READY;
+	csi_camera_unsubscribe_event(event_handle, &subscribe);
+
+	csi_camera_destory_event(event_handle);
+
+	csi_camera_channel_close(cam_handle, CAMERA_CHANNEL_ID);
+	csi_camera_close(cam_handle);
+}
+
+static void dump_camera_meta(csi_frame_s *frame)
+{
+	int i;
+	//printf("%s\n", __func__);
+	if (frame->meta.type != CSI_META_TYPE_CAMERA)
+		return;
+
+	csi_camera_meta_s *meta_data = (csi_camera_meta_s *)frame->meta.data;
+	int meta_count = meta_data->count;
+	csi_camrea_meta_unit_s meta_unit;
+
+	for (i = 0; i < meta_count; i++) {
+		csi_camera_frame_get_meta_unit(
+				&meta_unit, meta_data, CSI_CAMERA_META_ID_FRAME_ID);
+		//printf("meta_id=%d, meta_type=%d, meta_value=%d",
+		//       meta_unit.id, meta_unit.type, meta_unit.int_value);
+	}
+}
+
+static int save_camera_img(csi_frame_s *frame)
+{
+	static int fcount = 0;
+	char fname[20]; 
+	FILE *fp;
+	fcount = fcount%4;
+	sprintf(fname, "%s%d%s", "hal_image", fcount, ".yuv");
+	fcount++;
+
+	if((fp = fopen(fname, "wb")) == NULL){
+		printf("Error: Can't open file\n");
+		return -1;
+	}
+	fwrite(frame->img.usr_addr[0], sizeof(char), frame->img.size, fp);
+	fclose(fp);
+	return 0;
+}
+
+static int save_camera_stream(csi_frame_s *frame)
+{
+	FILE *fp;
+	char *fname = "hal_stream.yuv";
+	if((fp = fopen(fname, "ab+")) == NULL){
+		printf("Error: Can't open file\n");
+		return -1;
+	}
+	fwrite(frame->img.usr_addr[0], sizeof(char), frame->img.size, fp);
+	fclose(fp);
+	return 0;
+}
+

+ 41 - 0
examples/camera/opencv/Makefile

@@ -0,0 +1,41 @@
+##
+ # Copyright (C) 2021 Alibaba Group Holding Limited
+ # Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ #
+ # This program is free software; you can redistribute it and/or modify
+ # it under the terms of the GNU General Public License version 2 as
+ # published by the Free Software Foundation.
+##
+DIR_TO_ROOT=../../..
+
+include $(DIR_TO_ROOT)/build.param
+LIBOPENCV_INC  = $(shell pkg-config --cflags opencv) -I./
+LIBOPENCV_LIBS = $(shell pkg-config --libs opencv) 
+
+TARGET := libapp_utilities.a
+OUTPUT_DIR := $(DIR_TO_ROOT)/output/hal/
+
+#CFLAGS  = -Wall -g -O0
+
+SRCS = $(wildcard *.cpp)
+OBJS = $(SRCS:.cpp=.o)
+
+all: $(TARGET) 
+
+$(TARGET): $(OBJS)
+	@mkdir -p $(OUTPUT_DIR)
+	@echo "Linking" $@ "..."
+	$(AR) -r -o $(OUTPUT_DIR)/$@ .obj/*.o
+
+$(OBJS): %.o:%.cpp
+	@echo $(BUILD_LOG_START)
+	@mkdir -p .obj
+	@echo "Compiling" $< "..."
+	$(CXX) $(CFLAGS) $(INCLUDE) $(LIBOPENCV_INC) $(LIBOPENCV_LIBS) -c -o .obj/$(notdir $@) $<  
+	@echo $(BUILD_LOG_END)
+
+clean:
+	rm -rf .obj
+	rm -f $(OUTPUT_DIR)/$(TARGET)
+
+.PHONY: clean all 

+ 24 - 0
examples/camera/opencv/apputilities.cpp

@@ -0,0 +1,24 @@
+#include <opencv2/opencv.hpp>
+#include <opencv2/core/core.hpp>
+#include <opencv2/highgui/highgui.hpp>
+#include <opencv2/imgproc/imgproc.hpp>
+#include <iostream>
+#include <fstream>
+using namespace cv;
+using namespace std;
+
+#include "apputilities.h"
+
+int show_frame_image(void *mat, int height, int width)
+{
+	Mat dis_mat;
+	dis_mat.create(height * 3 / 2, width, CV_8UC1);
+	dis_mat.data = (uchar *)mat;
+	cvtColor(dis_mat, dis_mat, CV_YUV2BGRA_I420);
+	namedWindow("camera local i420");
+	imshow("camera local i420", dis_mat);
+	waitKey(1);
+	dis_mat.release();
+	return 0;
+}
+

+ 16 - 0
examples/camera/opencv/apputilities.h

@@ -0,0 +1,16 @@
+#ifndef __APPUTILITIES_H__
+#define __APPUTILITIES_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//wait for complete
+int show_frame_image(void *mat, int height, int width);
+
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif

+ 3 - 0
examples/camera/run_camera_demo3.sh

@@ -0,0 +1,3 @@
+#!/bin/bash
+# To watch log output, use: tail -f /tmp/debug_camera_demo3.log
+stdbuf -oL ./camera_demo3 >> /tmp/debug_camera_demo3.log 2>&1

+ 1 - 0
examples/common/.gitignore

@@ -0,0 +1 @@
+mtrace_demo

+ 27 - 0
examples/common/Makefile

@@ -0,0 +1,27 @@
+##
+ # Copyright (C) 2021 Alibaba Group Holding Limited
+ # Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ #
+ # This program is free software; you can redistribute it and/or modify
+ # it under the terms of the GNU General Public License version 2 as
+ # published by the Free Software Foundation.
+##
+DIR_TO_ROOT=../..
+include $(DIR_TO_ROOT)/build.param
+
+#CFLAGS  +=
+LIBS	+= -lhal_common
+OUTPUT_DIR := $(DIR_TO_ROOT)/output/examples/common
+
+TARGET_1 := mtrace_demo
+SRCS_1 = mtrace_demo.c
+
+all:  $(TARGET_1)
+
+clean:
+	rm -rf .obj
+	rm -f $(TARGET_1) $(OUTPUT_DIR)/$(TARGET_1)
+
+include $(DIR_TO_ROOT)/common_target.mk
+
+.PHONY: clean all

+ 25 - 0
examples/common/mtrace_demo.c

@@ -0,0 +1,25 @@
+#define DEBUG_MTRACE
+#include <stdlib.h>	// for malloc
+#include <mcheck.h>	// for mtrace() / muntrace();
+
+#define LOG_LEVEL 2
+#include <syslog.h>
+
+int main(int argc, char **argv)
+{
+	LOG_I("Enter\n");
+	int ret;
+
+#ifdef DEBUG_MTRACE
+	mtrace();
+#endif
+
+	int *tmp = malloc(0x1234);
+	LOG_I("malloc 0x1234 bytes(%p) without free.\n", tmp);
+
+#ifdef DEBUG_MTRACE
+	muntrace();
+#endif
+	LOG_I("Exit\n");
+}
+

+ 13 - 0
examples/common/run_mtrace_demo.sh

@@ -0,0 +1,13 @@
+#!/bin/sh
+
+export MALLOC_TRACE=/tmp/mtrace_demo_mtrace.log
+rm -f $MALLOC_TRACE
+# set '/proc/sys/kernel/randomize_va_space' to be 0
+# to disable Address Space Layout Randomization(ASLR)
+#sudo sysctl -w kernel.randomize_va_space=0
+
+echo  "\n**** Run mtrace demo ****"
+./mtrace_demo
+
+echo  "\n**** mtrace analysis result ****"
+mtrace ./mtrace_demo $MALLOC_TRACE | grep -E "\.c|\.cpp"

+ 3 - 0
examples/frame/.gitignore

@@ -0,0 +1,3 @@
+frame_demo1
+frame_demo2
+consumer_dump_file.yuv

+ 33 - 0
examples/frame/Makefile

@@ -0,0 +1,33 @@
+##
+ # Copyright (C) 2021 Alibaba Group Holding Limited
+ # Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ #
+ # This program is free software; you can redistribute it and/or modify
+ # it under the terms of the GNU General Public License version 2 as
+ # published by the Free Software Foundation.
+##
+DIR_TO_ROOT=../..
+include $(DIR_TO_ROOT)/build.param
+
+CFLAGS  += -I$(DIR_TO_ROOT)/src/platform/simulator/drivers/ion/
+LIBS	+= -lhal_common -lhal_platform
+OUTPUT_DIR := $(DIR_TO_ROOT)/output/examples/frame
+
+TARGET_1 := frame_demo1
+SRCS_1 = frame_demo1.c frame_demo_common.c
+
+TARGET_2 := frame_demo2
+SRCS_2 = frame_demo2.c frame_demo2_producer.c frame_demo2_consumer.c frame_demo_common.c
+
+all:  $(TARGET_1) $(TARGET_2)
+	@mkdir -p $(OUTPUT_DIR)/../resource
+	cp -f $(DIR_TO_ROOT)/examples/resource/yuv420_1280x720_csky2016.yuv $(OUTPUT_DIR)/../resource
+
+clean:
+	rm -rf .obj
+	rm -f $(TARGET_1) $(OUTPUT_DIR)/$(TARGET_1)
+	rm -f $(TARGET_2) $(OUTPUT_DIR)/$(TARGET_2)
+
+include $(DIR_TO_ROOT)/common_target.mk
+
+.PHONY: clean all

+ 109 - 0
examples/frame/frame_demo1.c

@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+
+#define LOG_LEVEL 2
+#define LOG_PREFIX "camera_demo1"
+#include <syslog.h>
+
+#include <ion.h>
+#include <csi_frame.h>
+#include <csi_camera_frame.h>
+#include "frame_demo_common.h"
+
+static const char *img_name = "../resource/yuv420_1280x720_csky2016.yuv";
+static csi_img_format_t img_format = {
+	.width = 1280,
+	.height = 720,
+	.pix_fmt = CSI_PIX_FMT_I420,
+};
+
+int main(int argc, char *argv[])
+{
+	int ret = -1;
+	int i;
+
+	int img_fd;
+	long img_size;
+	int ion_fd;
+	int dmabuf_fd;
+	void *dmabuf_addr;
+	csi_frame_s camera_frame;
+	csi_camera_meta_s *camera_meta;
+
+	// get image file size
+	if (fdc_get_img_file_size(&img_size, img_name) != 0)
+		goto LAB_ERR;
+
+	// open ion device
+	if (fdc_get_ion_device_fd(&ion_fd) != 0)
+		goto LAB_ERR;
+
+
+	// alloc dma-buf from ion device
+	struct ion_allocation_data alloc_data;
+	if (fdc_alloc_ion_buf(&alloc_data, ion_fd, img_size) != 0)
+		goto LAB_ERR_ION_OPENED;
+	dmabuf_fd = alloc_data.fd;
+
+	// map dma-buf to user addr
+	if (fdc_mmap_dmabuf_addr(&dmabuf_addr, img_size, dmabuf_fd) != 0)
+		goto LAB_ERR_BUF_ALLOCED;
+
+	// open image file
+	img_fd = open(img_name, O_RDONLY);
+	if (img_fd < 0) {
+		LOG_E("Open image file '%s' failed, %s\n",
+		      img_name, strerror(errno));
+		goto LAB_ERR_MMAPPED;
+	}
+
+	// store image into dma-buf
+	if (fdc_store_img_to_dmabuf(dmabuf_addr, img_fd, img_size) != 0)
+		goto LAB_ERR_IMG_OPENED;
+
+	// create csi_frame
+	if (fdc_create_csi_frame(&camera_frame, &img_format, &camera_meta, img_size, dmabuf_fd,
+				 dmabuf_addr) != 0)
+		goto LAB_ERR_IMG_OPENED;
+
+	// dump camera meta from csi frame
+	fdc_dump_camera_meta((csi_camera_meta_s *)camera_frame.meta.data);
+
+	// destory csi_frame
+	fdc_destory_csi_frame(&camera_frame);
+	ret = 0;
+
+LAB_ERR_IMG_OPENED:
+	close(img_fd);
+
+LAB_ERR_MMAPPED:
+	munmap(dmabuf_addr, img_size);
+
+LAB_ERR_BUF_ALLOCED:
+	close(dmabuf_fd);
+
+LAB_ERR_ION_OPENED:
+	close(ion_fd);
+
+LAB_ERR:
+	return ret;
+}
+

+ 104 - 0
examples/frame/frame_demo2.c

@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+#include <sys/wait.h>
+#include <sys/socket.h>
+
+#define LOG_LEVEL 2
+#define LOG_PREFIX "master"
+#include <syslog.h>
+
+#include <ion.h>
+#include <csi_frame.h>
+#include <csi_camera_frame.h>
+#include "frame_demo_common.h"
+
+const char *img_name = "../resource/yuv420_1280x720_csky2016.yuv";
+csi_img_format_t img_format = {
+	.width = 1280,
+	.height = 720,
+	.pix_fmt = CSI_PIX_FMT_I420,
+};
+
+extern int producer_process(int socket_fd);
+extern int consumer_process(int socket_fd);
+
+int main(int argc, char *argv[])
+{
+	int ret;
+	int socket_pair[2]; 	/* sockpair() */
+	pid_t producer_pid;
+	pid_t consumer_pid;
+	int process_status;	/* the status of child process */
+
+	char str_sockfd[10];	/* store the string format */
+
+	/* Create socket pare */
+	if (socketpair(AF_LOCAL, SOCK_STREAM, 0,
+		       socket_pair) == -1) {	/* must be AF_LOCAL or AF_UNIX !!!!*/
+		LOG_E("create socketpair error(%d), %s\n", errno, strerror(errno));
+		exit(1);
+	}
+	LOG_I("Create socketpair OK:{%d, %d}\n", socket_pair[0], socket_pair[1]);
+
+	/* run producer process, using socket_pair[0] */
+	if ((producer_pid = fork()) == 0) {
+		/* child process2: producer_process */
+		LOG_D("producer process starting ...\n");
+		close(socket_pair[1]); // producer only use socket_pair[0]
+
+		producer_process(socket_pair[0]);
+		LOG_D("producer process exiting ...\n");
+		exit(0);
+	}
+
+	/* run consumer process, using socket_pair[1] */
+	if ((consumer_pid = fork()) == 0) {
+		/* child process1: consumer_process */
+		LOG_D("consumer process starting...\n");
+		close(socket_pair[0]); // producer only use socket_pair[1]
+
+		consumer_process(socket_pair[1]);
+		LOG_D("consumer process exiting...\n");
+		exit(0);
+	}
+
+	/* wait the children process end */
+	waitpid(producer_pid, &process_status, 0);
+	if (WIFEXITED(process_status) == 0) {
+		LOG_E("producer exit abnormal\n");
+	}
+
+	waitpid(consumer_pid, &process_status, 0);
+	if (WIFEXITED(process_status) == 0) {
+		LOG_E("consumer eixt abnormal\n");
+	}
+
+	/* close the socket_pair */
+	ret = close(socket_pair[0]);
+	LOG_D("close(socket_pair[0]) ret=%d, %s\n", errno, strerror(errno));
+
+	ret = close(socket_pair[1]);
+	LOG_D("close(socket_pair[1]) ret=%d, %s\n", errno, strerror(errno));
+
+	LOG_D("Exit master\n");
+	return 0;
+}
+

+ 187 - 0
examples/frame/frame_demo2_consumer.c

@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+#include <sys/wait.h>
+#include <sys/socket.h>
+
+#define LOG_LEVEL 3
+#define LOG_PREFIX "consumer"
+#include <syslog.h>
+#include <dump_utils.h>
+
+#include <ion.h>
+#include <csi_frame.h>
+#include <csi_camera_frame.h>
+#include "frame_demo_common.h"
+
+extern const char *img_name;
+extern csi_img_format_t img_format;
+
+int consumer_process(int socket_fd)
+{
+	int ret = -1;
+
+	LOG_D("Starting consumer\n");
+	sleep(1); 	// waiting for producer exit to watch log easily
+	if (socket_fd <= 0)  {
+		LOG_E("socket_fd(%d) is invalid\n", socket_fd);
+		goto LAB_ERR;
+	}
+	LOG_D("The input socket_fd=%d\n", socket_fd);
+
+	struct msghdr msghdr_recv = { 		// init data
+		.msg_name = NULL,			// the socket address
+		.msg_namelen = 0,			// len of socket name
+	};
+
+	char ctrls[CMSG_SPACE(sizeof(int)*3)] = {};
+	memset(ctrls, 0, sizeof(ctrls));
+	msghdr_recv.msg_control = ctrls;
+	msghdr_recv.msg_controllen = sizeof(ctrls);
+
+	csi_frame_s camera_frame;
+	csi_camera_meta_s camera_meta;
+	char meta_data[CSI_CAMERA_META_MAX_LEN];	//CSI_CAMERA_META_MAX_LEN
+
+	struct iovec iov[3];
+	iov[0].iov_base = &camera_frame.img;		// iov[0] stores csi_frame.img info
+	iov[0].iov_len = sizeof(camera_frame.img);
+	iov[1].iov_base = &camera_frame.meta;		// iov[1] stores csi_frame.meta info
+	iov[1].iov_len = sizeof(camera_frame.meta);
+	iov[2].iov_base = meta_data;			// iov[2] stores csi_frame.meta data
+	iov[2].iov_len = sizeof(meta_data);
+
+	msghdr_recv.msg_iov = iov;			// the io/vector info
+	msghdr_recv.msg_iovlen = CSI_IMAGE_MAX_PLANES;	// the num of iov
+
+	ssize_t	recv_len;
+	if ((recv_len = recvmsg(socket_fd, &msghdr_recv, 0)) < 0) {
+		// the msg is recv by msghdr_recv
+		LOG_E("recv error:%d, %s\n", errno, strerror(errno));
+		goto LAB_ERR;
+	}
+	LOG_D("recvmsg() length=%zd\n", recv_len);
+	fdc_dump_msghdr(&msghdr_recv);
+
+	int msghdr_count = 0;
+	struct cmsghdr *pCmsghdr = NULL;		// the pointer of control
+	for (pCmsghdr = CMSG_FIRSTHDR(&msghdr_recv); pCmsghdr != NULL;
+	     pCmsghdr = CMSG_NXTHDR(&msghdr_recv,pCmsghdr)) {
+		msghdr_count++;
+	}
+	LOG_D("msghdr_count=%d\n", msghdr_count);
+
+	// now, only 1 plane even in I420 format (CSI_IMAGE_I420_PLANES)
+	if ((pCmsghdr = CMSG_FIRSTHDR(&msghdr_recv)) != NULL &&
+	    pCmsghdr->cmsg_len == CMSG_LEN(sizeof(int) * 1)) {
+		if (pCmsghdr->cmsg_level != SOL_SOCKET) {
+			LOG_E("Ctl level should be SOL_SOCKET\n");
+			goto LAB_ERR;
+		}
+
+		if (pCmsghdr->cmsg_type != SCM_RIGHTS) {
+			LOG_E("Ctl type should be SCM_RIGHTS\n");
+			goto LAB_ERR;
+		}
+
+		int fd_count = (pCmsghdr->cmsg_len - CMSG_SPACE(0)) / sizeof(int);
+		LOG_D("pCmsghdr->cmsg_len=%zd, fd_count=%d\n", pCmsghdr->cmsg_len, fd_count);
+		int *fdptr = (int *) CMSG_DATA(pCmsghdr);
+
+		for (int i = 0; i < CSI_IMAGE_MAX_PLANES; i ++) {
+			if (i < fd_count)
+				camera_frame.img.fds[i] = fdptr[i];
+			else
+				camera_frame.img.fds[i] = -1;
+		}
+	} else {
+		if (pCmsghdr == NULL)
+			LOG_E("pCmsghdr=%p\n", pCmsghdr);
+		else
+			LOG_E("pCmsghdr->cmsg_len=%zu, should=%zu\n",
+				pCmsghdr->cmsg_len,
+				CMSG_LEN(sizeof(int) * CSI_IMAGE_MAX_PLANES));
+
+		goto LAB_ERR;
+	}
+	int dma_buf_fd = camera_frame.img.fds[0];
+	LOG_D("recvmsg() with dmabuf_fds={%d, %d, %d}\n",
+	      camera_frame.img.fds[0], camera_frame.img.fds[1], camera_frame.img.fds[2]);
+
+	// fill camera frame img fds
+	camera_frame.meta.data = meta_data;
+	csi_dump_hex((char *)(&camera_frame.meta), sizeof(camera_frame.meta), "meta");
+	csi_dump_hex(camera_frame.meta.data, camera_frame.meta.size, "consumer: meta.data");
+	csi_dump_img_info(&camera_frame.img);
+
+	csi_camera_meta_s *camera_meta_data = (csi_camera_meta_s *)camera_frame.meta.data;
+	camera_meta_data->units = (csi_camrea_meta_unit_s *)((char *)camera_meta_data + sizeof(csi_camera_meta_s));
+	fdc_dump_camera_meta(camera_meta_data);
+
+	LOG_D("csi frame meta = {type=%d, size=%zd, data=%p}\n",
+		camera_frame.meta.type, camera_frame.meta.size, camera_frame.meta.data);
+	LOG_D("csi camera meta = {.count=%d, .size=%zd, .units=%p}\n",
+		camera_meta_data->count, camera_meta_data->size, camera_meta_data->units);
+
+	// save image file
+	const char *save_file_name = "consumer_dump_file.yuv";
+	remove(save_file_name);
+	FILE *dump_file = fopen(save_file_name, "wb");
+	if (dump_file) {
+		void *addr = NULL;
+		int length = 0;
+
+		length = camera_frame.img.size; //(img_format.height * img_format.width);
+
+		ret = fdc_mmap_dmabuf_addr(&addr, length, camera_frame.img.fds[0]);
+		LOG_D("ret=%d, addr=%p, lenght=%d\n", ret, addr, length);
+		if (ret == 0 || addr != NULL) {
+			size_t write_len = fwrite(addr, length, 1, dump_file);
+			LOG_O("dump dma-buf into '%s', write_len=%zd\n",
+				save_file_name, write_len);
+		}
+
+		fclose(dump_file);
+	} else {
+		LOG_E("fopen failed, %s\n", strerror(errno));
+	}
+	//fclose(dump_file);
+
+
+	for (int i = 0; i < CSI_IMAGE_MAX_PLANES; i++) {
+		if (camera_frame.img.fds[i] > 0) {
+			ret = close(camera_frame.img.fds[i]);
+			LOG_D("close(camera_frame.img.fds[%d]) ret=%d, %s\n",
+				i, errno, strerror(errno));
+		}
+	}
+
+	ret = close(socket_fd);
+	LOG_D("close(socket_fd) ret=%d, %s\n", errno, strerror(errno));
+	ret = 0;
+
+LAB_ERR:
+	if (ret)
+		LOG_E("Exiting consumer\n");
+	else
+		LOG_D("Exiting consumer\n");
+	return ret;
+}
+

+ 171 - 0
examples/frame/frame_demo2_producer.c

@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+#include <sys/wait.h>
+#include <sys/socket.h>
+
+#define LOG_LEVEL 3
+#define LOG_PREFIX "producer"
+#include <syslog.h>
+#include <dump_utils.h>
+
+#include <ion.h>
+#include <csi_frame.h>
+#include <csi_camera_frame.h>
+#include "frame_demo_common.h"
+
+extern const char *img_name;
+extern csi_img_format_t img_format;
+
+int producer_process(int socket_fd)
+{
+	int ret = -1;
+
+	int img_fd;
+	long img_size;
+	int ion_fd;
+	int dmabuf_fd;
+	void *dmabuf_addr;
+	csi_frame_s camera_frame;
+	csi_camera_meta_s *camera_meta;
+
+	LOG_D("Starting producer\n");
+	if (socket_fd <= 0)  {
+		LOG_E("socket_fd(%d) is invalid\n", socket_fd);
+		goto LAB_EXIT;
+	}
+	LOG_D("The input socket_fd=%d\n", socket_fd);
+
+	// get image file size
+	if (fdc_get_img_file_size(&img_size, img_name) != 0)
+		goto LAB_EXIT;
+
+	// open ion device
+	if (fdc_get_ion_device_fd(&ion_fd) != 0)
+		goto LAB_EXIT;
+
+	// alloc dma-buf from ion device
+	struct ion_allocation_data alloc_data;
+	if (fdc_alloc_ion_buf(&alloc_data, ion_fd, img_size) != 0)
+		goto LAB_ERR_ION_OPENED;
+	dmabuf_fd = alloc_data.fd;
+
+	// map dma-buf to user addr
+	if (fdc_mmap_dmabuf_addr(&dmabuf_addr, img_size, dmabuf_fd) != 0)	// should do unmap!!!!!!!!!!!!!!!!!
+		goto LAB_ERR_BUF_ALLOCED;
+
+	// open image file
+	img_fd = open(img_name, O_RDONLY);
+	if (img_fd < 0) {
+		LOG_E("Open image file '%s' failed, %s\n",
+		      img_name, strerror(errno));
+		goto LAB_ERR_MMAPPED;
+	}
+
+	// store image into dma-buf
+	if (fdc_store_img_to_dmabuf(dmabuf_addr, img_fd, img_size) != 0)
+		goto LAB_ERR_IMG_OPENED;
+
+	// create csi_frame
+	if (fdc_create_csi_frame(&camera_frame, &img_format, &camera_meta,
+				 img_size, dmabuf_fd, dmabuf_addr) != 0)
+		goto LAB_ERR_IMG_OPENED;
+
+	// dump camera meta from csi frame
+
+	fdc_dump_camera_meta((csi_camera_meta_s *)camera_frame.meta.data);
+	csi_dump_hex((char*)camera_meta, camera_frame.meta.size, "producer: meta.data");
+	csi_dump_img_info(&camera_frame.img);
+
+	////////////////////////////////////////////////////////////////////////
+	// store csi_frame into socket msg and send begin
+	struct msghdr msghdr_send = { 			// init data
+		.msg_name = NULL,			// the socket address
+		.msg_namelen = 0,			// len of socket name
+	};
+
+	int transfer_fd_count = 1;			// it's YUV420P, has only 2 planes
+	char ctrls[CMSG_SPACE(sizeof(int)) * CSI_IMAGE_MAX_PLANES] = {}; // store dma-buf fd
+	msghdr_send.msg_control = ctrls;
+	msghdr_send.msg_controllen = CMSG_SPACE(sizeof(int)) * transfer_fd_count;
+	LOG_D("msg_controllen = %zd\n", msghdr_send.msg_controllen);
+
+	struct cmsghdr *pCmsghdr;			// the pointer of control
+	int *fdptr = (int *) CMSG_DATA(pCmsghdr);
+
+	// the 1st info stores dma-buf fd[0]
+	pCmsghdr = CMSG_FIRSTHDR(&msghdr_send);		// the info of head
+	pCmsghdr->cmsg_len = CMSG_LEN(sizeof(int));     // the msg len
+	pCmsghdr->cmsg_level = SOL_SOCKET; 		// stream mode
+	pCmsghdr->cmsg_type = SCM_RIGHTS;  		// file descriptor
+	fdptr = (int *) CMSG_DATA(pCmsghdr);
+	*fdptr = camera_frame.img.fds[0];
+
+	struct iovec iov[3];				// io vector strores csi_frame
+	iov[0].iov_base = &camera_frame.img;		// iov[0] stores csi_frame.img
+	iov[0].iov_len = sizeof(camera_frame.img);
+	iov[1].iov_base = &camera_frame.meta;		// iov[1] stores csi_frame.meta info
+	iov[1].iov_len = sizeof(camera_frame.meta);
+	iov[2].iov_base = camera_frame.meta.data;	// iov[2] stores csi_frame.meta data
+	iov[2].iov_len = sizeof(camera_frame.meta) + camera_frame.meta.size;
+
+	msghdr_send.msg_iov = iov;			// the io/vector info
+	msghdr_send.msg_iovlen = 3;			// the num of iov
+
+	ssize_t size = sendmsg(socket_fd, &msghdr_send, 0);// send msg now
+	if (size < 0) {
+		LOG_E("sendmsg() failed, errno=%d, %s\n", errno, strerror(errno));
+	} else if (size == 0) {
+		LOG_W("sendmsg() failed, %zd bytes\n", size);
+	} else {
+		LOG_O("sendmsg() OK, %zd bytes\n", size);
+	}
+
+	// destory csi_frame
+	fdc_destory_csi_frame(&camera_frame);
+	ret = 0;
+
+LAB_ERR_IMG_OPENED:
+	ret = close(img_fd);
+	LOG_D("close(img_fd) ret=%d, %s\n", ret, strerror(errno));
+
+LAB_ERR_MMAPPED:
+	ret = munmap(dmabuf_addr, img_size);
+	LOG_D("munmap() ret=%d, %s\n", ret, strerror(errno));
+
+LAB_ERR_BUF_ALLOCED:
+	ret = close(dmabuf_fd);
+	LOG_D("close(dmabuf_fd) ret=%d, %s\n", ret, strerror(errno));
+
+LAB_ERR_ION_OPENED:
+	close(ion_fd);
+	LOG_D("close(ion_fd) ret=%d, %s\n", ret, strerror(errno));
+
+LAB_EXIT:
+	ret = close(socket_fd);
+	LOG_D("close(socket_fd) ret=%d, %s\n", ret, strerror(errno));
+
+	if (ret)
+		LOG_E("Exiting producer\n");
+	else
+		LOG_D("Exiting producer\n");
+	return ret;
+}
+

+ 214 - 0
examples/frame/frame_demo_common.c

@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+#define LOG_LEVEL 2
+//#define LOG_PREFIX "demo_common"
+#include <syslog.h>
+
+#include <ion.h>
+#include <csi_frame.h>
+#include <csi_camera_frame.h>
+#include "frame_demo_common.h"
+
+#define PAGE_SIZE 4096
+//#define IMG_YUV420_FILENAME "../resource/yuv420_1280x720_csky2016.yuv"
+#define IMG_RESOLUTION_WIDTH  1280
+#define IMG_RESOLUTION_HEIGHT 720
+
+/* fdc = frame demo common */
+int fdc_get_img_file_size(long *img_size, const char *filename)
+{
+	struct stat img_stat;
+	if (stat(filename, &img_stat) != 0) {
+		LOG_E("stat file '%s' failed, %s\n", filename, strerror(errno));
+		return -1;
+	}
+	*img_size = img_stat.st_size;
+	LOG_O("Get image '%s' size=%ld\n", filename, *img_size);
+	return 0;
+}
+
+int fdc_get_ion_device_fd(int *ion_fd)
+{
+	*ion_fd = open(ION_DEVICE_NAME, O_RDWR);
+	if (*ion_fd < 0) {
+		LOG_E("Open ion device:'%s' failed, %s\n", ION_DEVICE_NAME, strerror(errno));
+		return -1;
+	}
+	LOG_O("Open ion device OK, ion_fd=%d\n", *ion_fd);
+	return 0;
+}
+
+int fdc_alloc_ion_buf(struct ion_allocation_data *alloc_data,
+		  int ion_fd, unsigned long img_size)
+{
+	alloc_data->len = img_size;
+	if (ioctl(ion_fd, ION_IOC_ALLOC, alloc_data) ||
+	    alloc_data->fd < 0) {
+		LOG_E("ion ioctl failed, %s\n", strerror(errno));
+		return -1;
+	}
+	int dmabuf_fd = alloc_data->fd;
+	LOG_O("Alloc %ld from ion device OK, dmabuf_fd=%d\n", img_size, dmabuf_fd);
+	return 0;
+}
+
+int fdc_mmap_dmabuf_addr(void **addr, unsigned long length, int dmabuf_fd)
+{
+	LOG_D("Enter, length=%zd, dmabuf_fd=%d\n", length, dmabuf_fd);
+	*addr = mmap(NULL, length, PROT_READ | PROT_WRITE,
+			 MAP_SHARED, dmabuf_fd, 0);
+	if (*addr == NULL || *addr == MAP_FAILED) {
+		LOG_E("Map dmabuf failed\n");
+		return -1;
+	}
+	LOG_O("mmap dmabuf to user addr: %p OK\n", *addr);
+	return 0;
+}
+
+int fdc_store_img_to_dmabuf(void *dmabuf_addr, int img_fd, long img_size)
+{
+	long totle_len=0, read_len = 0;
+	char *img_ptr = (char*)dmabuf_addr;
+	while ((read_len = read(img_fd, (img_ptr + totle_len), PAGE_SIZE)) > 0) {
+		totle_len += read_len;
+	}
+	if (read_len < 0) {
+		LOG_E("Read from image file failed, %s\n", strerror(errno));
+		return -1;
+	}
+	if (totle_len != img_size) {
+		LOG_E("Read total len(%ld) != stat size(%ld)\n", totle_len, img_size);
+		return -1;
+	}
+	LOG_O("Store image into dma-buf OK\n");
+	return 0;
+}
+
+int fdc_create_csi_frame(csi_frame_s *camera_frame,
+	csi_img_format_t *img_format, csi_camera_meta_s **camera_meta,
+	long img_size, int dmabuf_fd, void *dmabuf_addr)
+{
+	// fill csi_frame's img info
+	camera_frame->img.type = CSI_IMG_TYPE_DMA_BUF;
+	camera_frame->img.size = img_size;
+	camera_frame->img.width = img_format->width;
+	camera_frame->img.height = img_format->height;
+	camera_frame->img.pix_format = img_format->pix_fmt;
+	camera_frame->img.num_planes = 1;	// Now use only 1 plane data
+	camera_frame->img.fds[0] = dmabuf_fd;
+	camera_frame->img.strides[0] = img_format->width;
+	camera_frame->img.offsets[0] = 0;
+
+	camera_frame->img.fds[1] = -1;
+	camera_frame->img.strides[1] = 0;
+	camera_frame->img.offsets[1] = 0;
+
+	camera_frame->img.fds[2] = -1;
+	camera_frame->img.strides[2] = 0;
+	camera_frame->img.offsets[2] = 0;
+	camera_frame->img.modifier = 0;
+
+	// prepare csi_camera_frame meta info
+	int meta_unit_count = 5;
+	size_t meta_data_size;
+	csi_camera_frame_alloc_meta(camera_meta, meta_unit_count, &meta_data_size);
+
+	(*camera_meta)->units[0].id = CSI_CAMERA_META_ID_CAMERA_NAME;
+	(*camera_meta)->units[0].type = CSI_META_VALUE_TYPE_STR;
+	strncpy((*camera_meta)->units[0].str_value, "/dev/video0",
+		sizeof((*camera_meta)->units[0].str_value));
+
+	(*camera_meta)->units[1].id = CSI_CAMERA_META_ID_CHANNEL_ID;
+	(*camera_meta)->units[1].type = CSI_META_VALUE_TYPE_UINT;
+	(*camera_meta)->units[1].uint_value = 1;
+
+	(*camera_meta)->units[2].id = CSI_CAMERA_META_ID_FRAME_ID;
+	(*camera_meta)->units[2].type = CSI_META_VALUE_TYPE_INT;
+	(*camera_meta)->units[2].uint_value = 2;
+
+	(*camera_meta)->units[3].id = CSI_CAMERA_META_ID_TIMESTAMP;
+	(*camera_meta)->units[3].type = CSI_META_VALUE_TYPE_TIMEVAL;
+	gettimeofday(&(*camera_meta)->units[3].time_value, NULL);
+
+	(*camera_meta)->units[4].id = CSI_CAMERA_META_ID_HDR;
+	(*camera_meta)->units[4].type = CSI_META_VALUE_TYPE_TIMEVAL;
+	(*camera_meta)->units[4].bool_value = false;
+
+	camera_frame->meta.type = CSI_META_TYPE_CAMERA;
+	camera_frame->meta.size = meta_data_size;
+	camera_frame->meta.data = *camera_meta;
+
+	LOG_D("*camera_meta=camera_frame->meta.data=%p\n", camera_frame->meta.data);
+
+	return 0;
+}
+
+void fdc_dump_camera_meta(csi_camera_meta_s *camera_meta)
+{
+	int ret;
+	csi_camrea_meta_unit_s meta_unit;
+	ret = csi_camera_frame_get_meta_unit(&meta_unit, camera_meta, CSI_CAMERA_META_ID_TIMESTAMP);
+	if (ret == 0) {
+		struct timeval tv = meta_unit.time_value;
+		struct tm *t = localtime(&tv.tv_sec);
+		if (t != NULL) {
+			LOG_O("Get timestamp from csi frame:%d-%d-%d %d:%d:%d.%ld\n",
+				1900+t->tm_year, 1+t->tm_mon, t->tm_mday,
+				t->tm_hour, t->tm_min, t->tm_sec, tv.tv_usec);
+			return;
+		} else {
+			LOG_E("timestamp is invalid\n");
+			return;
+		}
+	}
+	return;
+}
+
+void fdc_destory_csi_frame(csi_frame_s *camera_frame)
+{
+	if (camera_frame->meta.data != NULL)
+		csi_camera_frame_free_meta((csi_camera_meta_s*)camera_frame->meta.data);
+}
+
+void fdc_dump_msghdr(struct msghdr *msg)
+{
+	int i;
+	if (msg == NULL) {
+		LOG_E("mgs = NULL\n");
+		return;
+	}
+
+	LOG_D("struct msghdr *msg(%p) = {\n", msg);
+	LOG_D("\t .msg_iov=%p\n", msg->msg_iov);
+	LOG_D("\t .msg_iovlen=%zd\n", msg->msg_iovlen);
+	for(i = 0; i < msg->msg_iovlen; i++) {
+		struct iovec *iovc = &(msg->msg_iov[i]);
+		LOG_D("\t   .msg_iov[%d]={.iov_base=%p, .iov_len=%zd}\n",
+			i, msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len);
+	}
+	LOG_D("\t .msg_control=%p\n", msg->msg_control);
+	LOG_D("\t .msg_control=%zd\n", msg->msg_controllen);
+	LOG_D("\t .name=%p\n", msg->msg_name);
+	LOG_D("\t .msg_namelen=%d\n", msg->msg_namelen);
+	LOG_D("\t .msg_flags=%d\n", msg->msg_flags);
+	LOG_D("}\n");
+}
+

+ 50 - 0
examples/frame/frame_demo_common.h

@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __FRAME_DEMO_COMMON_H__
+#define __FRAME_DEMO_COMMON_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <ion.h>
+#include <csi_frame.h>
+#include <csi_camera_frame.h>
+
+#define ION_DEVICE_NAME "/dev/ion"
+
+extern const int PAGE_SIZE;
+extern const char *IMG_YUV420_FILENAME;
+extern const int IMG_RESOLUTION_WIDTH;
+extern const int IMG_RESOLUTION_HEIGHT;;
+
+int fdc_get_img_file_size(long *img_size, const char *filename);
+int fdc_get_ion_device_fd(int *ion_fd);
+int fdc_alloc_ion_buf(struct ion_allocation_data *alloc_data,
+		      int ion_fd, unsigned long img_size);
+int fdc_mmap_dmabuf_addr(void **addr, unsigned long length, int dmabuf_fd);
+int fdc_store_img_to_dmabuf(void *dmabuf_addr, int img_fd, long img_size);
+int fdc_create_csi_frame(csi_frame_s *camera_frame,
+			 csi_img_format_t *img_format, csi_camera_meta_s **camera_meta,
+			 long img_size, int dmabuf_fd, void *dmabuf_addr);
+void fdc_dump_camera_meta(csi_camera_meta_s *camera_meta);
+void fdc_destory_csi_frame(csi_frame_s *camera_frame);
+void fdc_dump_msghdr(struct msghdr *msg);
+
+#endif /* __FRAME_DEMO_COMMON_H__ */

+ 1070 - 0
examples/g2d/g2d_demo.c

@@ -0,0 +1,1070 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <csi_g2d.h>
+#include <csi_g2d_types.h>
+
+typedef struct _bitmap_file {
+    const char *name;
+    unsigned int width;
+    unsigned int height;
+    unsigned int format;
+} bitmap_file;
+
+const static bitmap_file sbitmaps[] = {
+    {
+	.name	= "resource/image1_640x480_nv12.yuv",
+	.width	= 640,
+	.height	= 480,
+	.format	= CSI_G2D_FMT_NV12,
+    },
+    {
+	.name	= "resource/image2_640x480_argb.rgb",
+	.width	= 640,
+	.height	= 480,
+	.format	= CSI_G2D_FMT_BGRA8888,
+    },
+    {
+	.name	= "resource/image3_640x480_nv12.yuv",
+	.width	= 640,
+	.height	= 480,
+	.format	= CSI_G2D_FMT_NV12,
+    },
+    {
+	.name	= "resource/horse_640x480_nv12.yuv",
+	.width	= 640,
+	.height	= 480,
+	.format	= CSI_G2D_FMT_NV12,
+    },
+};
+
+static int g2d_load_bitmap(csi_g2d_surface *surface, const char *path)
+{
+    int i, j, bytes, lsize;
+    int width[3], height[3];
+    FILE *file;
+    void *ptr;
+
+    if (!surface || !surface->nplanes || surface->nplanes > 3)
+	return -1;
+
+    file = fopen(path, "r");
+    if (!file)
+	return -1;
+
+    width[0]  = surface->width;
+    height[0] = surface->height;
+    switch (surface->format) {
+    case CSI_G2D_FMT_NV12:
+    case CSI_G2D_FMT_NV21:
+	width[1]  = surface->width / 2;
+	height[1] = surface->height / 2;
+	break;
+    case CSI_G2D_FMT_ARGB8888:
+    case CSI_G2D_FMT_BGRA8888:
+	break;
+    /* TODO: add more formats support here */
+    default:
+	return -1;
+    }
+
+    for (i = 0; i < surface->nplanes; i++) {
+	for (j = 0; j < height[i]; j++) {
+	    ptr = surface->lgcaddr[i] + j * surface->stride[i];
+	    lsize = width[i] * surface->cpp[i];
+
+	    bytes = fread(ptr, 1, lsize, file);
+	    if (bytes != lsize)
+		return -1;
+	}
+    }
+
+    return 0;
+}
+
+static int g2d_save_bitmap(csi_g2d_surface *surface, const char *path)
+{
+    int i, j, bytes, lsize;
+    int width[3], height[3];
+    FILE *file;
+    void *ptr;
+
+    if (!surface || !surface->nplanes || surface->nplanes > 3)
+	return -1;
+
+    file = fopen(path, "w");
+    if (!file)
+	return -1;
+
+    width[0]  = surface->width;
+    height[0] = surface->height;
+    switch (surface->format) {
+    case CSI_G2D_FMT_NV12:
+    case CSI_G2D_FMT_NV21:
+	width[1]  = surface->width / 2;
+	height[1] = surface->height / 2;
+	break;
+    /* TODO: add more formats support here */
+    case CSI_G2D_FMT_ARGB8888:
+	break;
+    default:
+	return -1;
+    }
+
+    for (i = 0; i < surface->nplanes; i++) {
+	for (j = 0; j < height[i]; j++) {
+	    ptr = surface->lgcaddr[i] + j * surface->stride[i];
+	    lsize = width[i] * surface->cpp[i];
+
+	    bytes = fwrite(ptr, 1, lsize, file);
+	    if (bytes != lsize)
+		return -1;
+	}
+    }
+
+    return 0;
+}
+
+static int g2d_test_filterblit_with_rotation(void)
+{
+    int ret;
+    const bitmap_file *bitmap = &sbitmaps[0];
+    csi_g2d_surface *source, *target;
+    csi_g2d_region dstRect;
+
+    printf("start to do filterblit operation with 90 rotation: ");
+
+    source = calloc(1, sizeof(*source));
+    if (!source) {
+	printf("allocate source surface failed\n");
+	exit(-1);
+    }
+
+    target = calloc(1, sizeof(*target));
+    if (!target) {
+	printf("allocate target surface failed\n");
+	exit(-1);
+    }
+
+    source->width	= bitmap->width;
+    source->height	= bitmap->height;
+    source->format	= bitmap->format;
+    ret = csi_g2d_surface_create(source);
+    if (ret) {
+	printf("create source surface failed\n");
+	exit(-1);
+    }
+
+    target->width	= bitmap->width * 2;
+    target->height	= bitmap->height * 2;
+    target->format	= CSI_G2D_FMT_ARGB8888;
+    ret = csi_g2d_surface_create(target);
+    if (ret) {
+	printf("create target surface failed\n");
+	exit(-1);
+    }
+
+    printf("%ux%u NV12 -> %ux%u ARGB8888\n", source->width, source->height, target->width, target->height);
+
+    ret = g2d_load_bitmap(source, bitmap->name);
+    if (ret) {
+	printf("load bitmap to source failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_surface_set_source(source);
+    if (ret) {
+	printf("set source surface failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_surface_set_target(target);
+    if (ret) {
+	printf("set target surface failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_blit_set_rotation(CSI_G2D_ROTATION_0_DEGREE);
+    if (ret) {
+	printf("set rotation to 0 failed\n");
+	exit(-1);
+    }
+
+    dstRect.left   = dstRect.top = 0;
+    dstRect.right  = target->width;
+    dstRect.bottom = target->height;
+
+    ret = csi_g2d_blit_set_filter_tap(CSI_G2D_FILTER_TAP_5,
+			CSI_G2D_FILTER_TAP_5);
+    if (ret) {
+	printf("set filter tap failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_blit_filterblit(&dstRect, 1);
+    if (ret) {
+	printf("filterblit nv12 to argb8888 failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_flush();
+    if (ret) {
+	printf("flush g2d failed\n");
+	exit(-1);
+    }
+
+    ret = g2d_save_bitmap(target, "result/image1_result_1280x960_argb8888.rgb");
+    if (ret) {
+	printf("save result failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_surface_destroy(source);
+    if (ret) {
+	printf("destroy source surface failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_surface_destroy(target);
+    if (ret) {
+	printf("destroy target surface failed\n");
+	exit(-1);
+    }
+
+    printf("filterblit operation finished\n");
+    return 0;
+
+}
+
+static int g2d_test_stretchblit_with_rotation(void)
+{
+    int ret;
+    const bitmap_file *bitmap = &sbitmaps[0];
+    csi_g2d_surface *source, *target;
+    csi_g2d_region dstRect;
+
+    printf("start to do stretchblit operation with 90 rotation: ");
+
+    source = calloc(1, sizeof(*source));
+    if (!source) {
+	printf("allocate source surface failed\n");
+	exit(-1);
+    }
+
+    target = calloc(1, sizeof(*target));
+    if (!target) {
+	printf("allocate target surface failed\n");
+	exit(-1);
+    }
+
+    source->width	= bitmap->width;
+    source->height	= bitmap->height;
+    source->format	= bitmap->format;
+    ret = csi_g2d_surface_create(source);
+    if (ret) {
+	printf("create source surface failed\n");
+	exit(-1);
+    }
+
+    target->width	= bitmap->height * 2;
+    target->height	= bitmap->width * 2;
+    target->format	= CSI_G2D_FMT_ARGB8888;
+    ret = csi_g2d_surface_create(target);
+    if (ret) {
+	printf("create target surface failed\n");
+	exit(-1);
+    }
+
+    printf("%ux%u NV12 -> %ux%u ARGB8888\n", source->width, source->height, target->width, target->height);
+
+    ret = g2d_load_bitmap(source, bitmap->name);
+    if (ret) {
+	printf("load bitmap to source failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_surface_set_source(source);
+    if (ret) {
+	printf("set source surface failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_surface_set_target(target);
+    if (ret) {
+	printf("set target surface failed\n");
+	exit(-1);
+    }
+
+    dstRect.left   = dstRect.top = 0;
+    dstRect.right  = target->width;
+    dstRect.bottom = target->height;
+
+    ret = csi_g2d_blit_set_rotation(CSI_G2D_ROTATION_90_DEGREE);
+    if (ret) {
+	printf("set rotation to 90 failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_blit_stretchblit(&dstRect, 1);
+    if (ret) {
+	printf("stretchblit nv12 to argb8888 failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_flush();
+    if (ret) {
+	printf("flush g2d failed\n");
+	exit(-1);
+    }
+
+    ret = g2d_save_bitmap(target, "result/image1_result_960x1280_argb8888.rgb");
+    if (ret) {
+	printf("save result failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_surface_destroy(source);
+    if (ret) {
+	printf("destroy source surface failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_surface_destroy(target);
+    if (ret) {
+	printf("destroy target surface failed\n");
+	exit(-1);
+    }
+
+    printf("stretchblit operation with 90 rotation finished\n");
+    return 0;
+}
+
+static int g2d_test_bitblit_with_alpha_blending(void)
+{
+    int ret;
+    const bitmap_file *bitmap = &sbitmaps[0];
+    csi_g2d_surface *source, *target;
+    csi_g2d_region srcRect, dstRect;
+    csi_g2d_blend_mode blend_mode;
+
+    printf("start to do bitblit operation with alpha blending\n");
+
+    source = calloc(1, sizeof(*source));
+    if (!source) {
+	printf("allocate source surface failed\n");
+	exit(-1);
+    }
+
+    target = calloc(1, sizeof(*target));
+    if (!target) {
+	printf("allocate target surface failed\n");
+	exit(-1);
+    }
+
+    source->width	= bitmap->width;
+    source->height	= bitmap->height;
+    source->format	= CSI_G2D_FMT_ARGB8888;
+
+    ret = csi_g2d_surface_create(source);
+    if (ret) {
+	printf("create source surface failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_surface_set_target(source);
+    if (ret) {
+        printf("set source surface failed\n");
+        exit(-1);
+    }
+
+    srcRect.left   = srcRect.top = 0;
+    srcRect.right  = source->width;
+    srcRect.bottom = source->height;
+
+    ret = csi_g2d_fill(&srcRect, 1, 0x0);
+    if (ret) {
+	printf("fill source surface failed\n");
+	exit(-1);
+    }
+
+    srcRect.left  = 50;
+    srcRect.top   = 60;
+    srcRect.right = 250;
+    srcRect.bottom = 260;
+
+    ret = csi_g2d_fill(&srcRect, 1, 0xFF0000FF);
+    if (ret) {
+	printf("fill source surface failed\n");
+	exit(-1);
+    }
+
+    srcRect.left   = srcRect.top = 0;
+    srcRect.right  = source->width;
+    srcRect.bottom = source->height;
+
+    target->width	= bitmap->width;
+    target->height	= bitmap->height;
+    target->format	= CSI_G2D_FMT_ARGB8888;
+    ret = csi_g2d_surface_create(target);
+    if (ret) {
+	printf("create target surface failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_surface_set_target(target);
+    if (ret) {
+	printf("set target surface failed\n");
+	exit(-1);
+    }
+
+    dstRect.left   = dstRect.top = 0;
+    dstRect.right  = target->width;
+    dstRect.bottom = target->height;
+
+    ret = csi_g2d_fill(&dstRect, 1, 0x0);
+    if (ret) {
+	printf("fill source surface failed\n");
+	exit(-1);
+    }
+
+    dstRect.left = 20;
+    dstRect.top  = 30;
+    dstRect.right  = 120;
+    dstRect.bottom = 130;
+
+    ret = csi_g2d_fill(&dstRect, 1, 0xFFFF0000);
+    if (ret) {
+	printf("fill source surface failed\n");
+	exit(-1);
+     }
+
+    ret = csi_g2d_surface_set_source(source);
+    if (ret) {
+        printf("set source surface failed\n");
+        exit(-1);
+    }
+
+    /* set alpha modes */
+    blend_mode = CSI_G2D_BLEND_MODE_XOR;
+
+    ret = csi_g2d_surface_set_source_alpha_mode(
+	CSI_G2D_ALPHA_MODE_STRAIGHT,
+	blend_mode
+    );
+    if (ret) {
+	printf("set source alpha mode failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_surface_set_source_global_alpha_mode(
+	CSI_G2D_GLOBAL_ALPHA_MODE_OFF,
+	0xFFFFFFFF
+    );
+    if (ret) {
+	printf("set source global alpha mode failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_surface_set_target_alpha_mode(
+	CSI_G2D_ALPHA_MODE_STRAIGHT,
+	blend_mode
+    );
+    if (ret) {
+	printf("set target alpha mode failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_surface_set_target_global_alpha_mode(
+	CSI_G2D_GLOBAL_ALPHA_MODE_OFF,
+	0xFFFFFFFF
+    );
+    if (ret) {
+	printf("set target global alpha mode failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_surface_enable_disable_alpha_blend(true);
+    if (ret) {
+	printf("enable alpha blend failed\n");
+	exit(-1);
+    }
+
+    dstRect.left   = dstRect.top = 0;
+    dstRect.right  = target->width;
+    dstRect.bottom = target->height;
+
+    ret = csi_g2d_blit_bitblit(&dstRect, 1);
+    if (ret) {
+        printf("bitblit argb8888 to argb8888 with alpha blend failed\n");
+        exit(-1);
+    }
+
+    ret = csi_g2d_flush();
+    if (ret) {
+        printf("flush g2d failed\n");
+        exit(-1);
+    }
+
+    ret = g2d_save_bitmap(target, "result/alpha_blend_result_640x480_argb8888.rgb");
+    if (ret) {
+	printf("save result failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_surface_destroy(source);
+    if (ret) {
+	printf("destroy source surface failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_surface_destroy(target);
+    if (ret) {
+	printf("destroy target surface failed\n");
+	exit(-1);
+    }
+
+    printf("bitblit operation with alpha blending finished\n");
+    return 0;
+}
+
+static int g2d_test_bitblit_with_rotation(void)
+{
+    int ret;
+    const bitmap_file *bitmap = &sbitmaps[0];
+    csi_g2d_surface *source, *target;
+    csi_g2d_region dstRect;
+
+    printf("start to do bitblit operation with 90 rotation: ");
+
+    source = calloc(1, sizeof(*source));
+    if (!source) {
+	printf("allocate source surface failed\n");
+	exit(-1);
+    }
+
+    target = calloc(1, sizeof(*target));
+    if (!target) {
+	printf("allocate target surface failed\n");
+	exit(-1);
+    }
+
+    source->width	= bitmap->width;
+    source->height	= bitmap->height;
+    source->format	= bitmap->format;
+    ret = csi_g2d_surface_create(source);
+    if (ret) {
+	printf("create source surface failed\n");
+	exit(-1);
+    }
+
+    target->width	= bitmap->height;
+    target->height	= bitmap->width;
+    target->format	= CSI_G2D_FMT_ARGB8888;
+    ret = csi_g2d_surface_create(target);
+    if (ret) {
+	printf("create target surface failed\n");
+	exit(-1);
+    }
+
+    printf("%ux%u NV12 -> %ux%u ARGB8888\n", source->width, source->height, target->width, target->height);
+
+    ret = g2d_load_bitmap(source, bitmap->name);
+    if (ret) {
+	printf("load bitmap to source failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_surface_set_source(source);
+    if (ret) {
+	printf("set source surface failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_surface_set_target(target);
+    if (ret) {
+	printf("set target surface failed\n");
+	exit(-1);
+    }
+
+    dstRect.left   = dstRect.top = 0;
+    dstRect.right  = target->width;
+    dstRect.bottom = target->height;
+
+    ret = csi_g2d_blit_set_rotation(CSI_G2D_ROTATION_90_DEGREE);
+    if (ret) {
+	printf("set rotation to 90 failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_blit_bitblit(&dstRect, 1);
+    if (ret) {
+	printf("bitblit nv12 to nv12 failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_flush();
+    if (ret) {
+	printf("flush g2d failed\n");
+	exit(-1);
+    }
+
+    ret = g2d_save_bitmap(target, "result/image1_result_480x640_argb8888.rgb");
+    if (ret) {
+	printf("save result failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_surface_destroy(source);
+    if (ret) {
+	printf("destroy source surface failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_surface_destroy(target);
+    if (ret) {
+	printf("destroy target surface failed\n");
+	exit(-1);
+    }
+
+    printf("bitblit operation with 90 rotation finished\n");
+    return 0;
+
+}
+
+static int g2d_test_fill_rectangle(void)
+{
+    int ret;
+    csi_g2d_surface *target;
+    csi_g2d_region dstRect;
+
+    printf("start to do rectangle fill operation: ");
+
+    target = calloc(1, sizeof(*target));
+    if (!target) {
+	printf("allocate target surface failed\n");
+	exit(-1);
+    }
+
+    target->width	= 640;
+    target->height	= 480;
+    target->format	= CSI_G2D_FMT_ARGB8888;
+
+    ret = csi_g2d_surface_create(target);
+    if (ret) {
+	printf("create target surface failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_surface_set_target(target);
+    if (ret) {
+	printf("set target surface failed\n");
+	exit(-1);
+    }
+
+    printf("fill red to %ux%u rectangle\n", target->width, target->height);
+
+    dstRect.left   = dstRect.top = 0;
+    dstRect.right  = target->width;
+    dstRect.bottom = target->height;
+
+    ret = csi_g2d_fill(&dstRect, 1, 0xffff0000);
+    if (ret) {
+	printf("g2d fill operation failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_flush();
+    if (ret) {
+	printf("flush g2d failed\n");
+	exit(-1);
+    }
+
+    ret = g2d_save_bitmap(target, "result/image1_result_640x480_argb8888_fill.rgb");
+    if (ret) {
+	printf("save result failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_surface_destroy(target);
+    if (ret) {
+	printf("destroy target surface failed\n");
+	exit(-1);
+    }
+
+    printf("fill rectangle operation finished\n");
+    return 0;
+}
+
+static int g2d_test_draw_rectangle(void)
+{
+    int ret;
+    const bitmap_file *bitmap = &sbitmaps[1];
+    csi_g2d_surface *target;
+    csi_g2d_region dstRect;
+    csi_g2d_rectangle rectangle;
+
+    printf("start to do rectangle draw operation\n");
+
+    target = calloc(1, sizeof(*target));
+    if (!target) {
+	printf("allocate target surface failed\n");
+	exit(-1);
+    }
+
+    target->width	= bitmap->width;
+    target->height	= bitmap->height;
+    target->format	= CSI_G2D_FMT_ARGB8888;
+    ret = csi_g2d_surface_create(target);
+    if (ret) {
+	printf("create target surface failed\n");
+	exit(-1);
+    }
+
+    ret = g2d_load_bitmap(target, bitmap->name);
+    if (ret) {
+	printf("load bitmap to target failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_surface_set_target(target);
+    if (ret) {
+	printf("set target surface failed\n");
+	exit(-1);
+    }
+
+    dstRect.left   = dstRect.top = 0;
+    dstRect.right  = target->width;
+    dstRect.bottom = target->height;
+
+    ret = csi_g2d_brush_create(0xffff0000, false);
+    if (ret) {
+	printf("create brush failed\n");
+	exit(-1);
+    }
+
+    rectangle.line[0].start.x = dstRect.left + 30;
+    rectangle.line[0].start.y = dstRect.top  + 30;
+    rectangle.line[0].end.x   = dstRect.right  - 30;
+    rectangle.line[0].end.y   = dstRect.top  + 30;
+
+    rectangle.line[1].start.x = dstRect.left + 30;
+    rectangle.line[1].start.y = dstRect.top  + 30;
+    rectangle.line[1].end.x   = dstRect.left + 30;
+    rectangle.line[1].end.y   = dstRect.bottom - 30;
+
+    rectangle.line[2].start.x = dstRect.left + 30;
+    rectangle.line[2].start.y = dstRect.bottom - 30;
+    rectangle.line[2].end.x   = dstRect.right  - 30;
+    rectangle.line[2].end.y   = dstRect.bottom - 30;
+
+    rectangle.line[3].start.x = dstRect.right  - 30;
+    rectangle.line[3].start.y = dstRect.top + 30;
+    rectangle.line[3].end.x   = dstRect.right  - 30;
+    rectangle.line[3].end.y   = dstRect.bottom - 30;
+
+    ret = csi_g2d_line_draw_rectangle(&rectangle, 1);
+    if (ret) {
+	printf("draw one rectangle failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_flush();
+    if (ret) {
+	printf("flush g2d failed\n");
+	exit(-1);
+    }
+
+    ret = g2d_save_bitmap(target, "result/image1_result_640x480_argb8888_rectangle.rgb");
+    if (ret) {
+	printf("save result failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_surface_destroy(target);
+    if (ret) {
+	printf("destroy target surface failed\n");
+	exit(-1);
+    }
+
+    printf("draw rectangle operation finished\n");
+    return 0;
+}
+
+static int g2d_test_multisrc_blit(void)
+{
+    int i, ret;
+    csi_g2d_surface *source[4], *target;
+    csi_g2d_region srcRect, dstRect;
+
+    printf("start to do multisrc blit operation\n");
+
+    for (i = 0; i < 4; i++) {
+	source[i] = calloc(1, sizeof(csi_g2d_surface));
+	if (!source[i]) {
+	    printf("allocate source surface %d failed\n", i);
+	    exit(-1);
+	}
+    }
+
+    target = calloc(1, sizeof(*target));
+    if (!target) {
+        printf("allocate target surface failed\n");
+        exit(-1);
+    }
+
+    for (i = 0; i < 4; i++) {
+        source[i]->width  = sbitmaps[i].width;
+        source[i]->height = sbitmaps[i].height;
+        source[i]->format = sbitmaps[i].format;
+        ret = csi_g2d_surface_create(source[i]);
+        if (ret) {
+            printf("create source surface failed\n");
+            exit(-1);
+        }
+
+        ret = g2d_load_bitmap(source[i], sbitmaps[i].name);
+        if (ret) {
+            printf("load bitmap %d to source failed\n", i);
+            exit(-1);
+        }
+    }
+
+    target->width       = 640;
+    target->height      = 480;
+    target->format      = CSI_G2D_FMT_ARGB8888;
+    ret = csi_g2d_surface_create(target);
+    if (ret) {
+        printf("create target surface failed\n");
+        exit(-1);
+    }
+
+    ret = csi_g2d_surface_set_target(target);
+    if (ret) {
+        printf("set target surface failed\n");
+        exit(-1);
+    }
+
+    dstRect.left   = dstRect.top = 0;
+    dstRect.right  = target->width;
+    dstRect.bottom = target->height;
+
+    ret = csi_g2d_fill(&dstRect, 1, 0x0);
+    if (ret) {
+        printf("fill target surface to 0x0 failed\n");
+        exit(-1);
+    }
+
+    for (i = 0; i < 4; i++) {
+        ret = csi_g2d_surface_select_source(i);
+        if (ret) {
+            printf("select source %d\n", i);
+            exit(-1);
+        }
+
+        ret = csi_g2d_surface_set_source(source[i]);
+        if (ret) {
+            printf("set source %d surface failed\n", i);
+            exit(-1);
+        }
+
+        switch (i % 4) {
+        case 0:
+            srcRect.left = 320;
+            srcRect.top  = 240;
+            srcRect.right = srcRect.left + 320;
+            srcRect.bottom = srcRect.top + 240;
+            break;
+        case 1:
+            srcRect.left = 0;
+            srcRect.top  = 240;
+            srcRect.right = srcRect.left + 320;
+            srcRect.bottom = srcRect.top + 240;
+            break;
+        case 2:
+            srcRect.left = 0;
+            srcRect.top  = 0;
+            srcRect.right = srcRect.left + 320;
+            srcRect.bottom = srcRect.top + 240;
+            break;
+        case 3:
+            srcRect.left = 320;
+            srcRect.top  = 0;
+            srcRect.right = srcRect.left + 320;
+            srcRect.bottom = srcRect.top + 240;
+            break;
+        }
+
+        ret = csi_g2d_surface_set_source_clipping(&srcRect);
+        if (ret) {
+            printf("set source %d clipping failed\n", i);
+            return ret;
+        }
+    }
+
+    ret = csi_g2d_blit_multisrc_blit(0xF, &dstRect, 1);
+    if (ret) {
+        printf("multisrc blit failed\n");
+        exit(-1);
+    }
+
+    ret = csi_g2d_flush();
+    if (ret) {
+        printf("flush g2d failed\n");
+        exit(-1);
+    }
+
+    ret = g2d_save_bitmap(target, "result/multisrc_result_640x480_argb.rgb");
+    if (ret) {
+        printf("save result failed\n");
+        exit(-1);
+    }
+
+    for (i = 0; i < 4; i++) {
+	ret = csi_g2d_surface_destroy(source[i]);
+	if (ret) {
+	    printf("destroy source surface failed\n");
+	    exit(-1);
+	}
+    }
+
+    ret = csi_g2d_surface_destroy(target);
+    if (ret) {
+	printf("destroy target surface failed\n");
+	exit(-1);
+    }
+
+    printf("multisrc blit operation with 4 sources finished\n");
+    return 0;
+}
+
+static int g2d_test_bitblit(void)
+{
+    int ret;
+    const bitmap_file *bitmap = &sbitmaps[0];
+    csi_g2d_surface *source, *target;
+    csi_g2d_region dstRect;
+
+    printf("start to do bitblit operation: ");
+
+    source = calloc(1, sizeof(*source));
+    if (!source) {
+	printf("allocate source surface failed\n");
+	exit(-1);
+    }
+
+    target = calloc(1, sizeof(*target));
+    if (!target) {
+	printf("allocate target surface failed\n");
+	exit(-1);
+    }
+
+    source->width	= bitmap->width;
+    source->height	= bitmap->height;
+    source->format	= bitmap->format;
+    ret = csi_g2d_surface_create(source);
+    if (ret) {
+	printf("create source surface failed\n");
+	exit(-1);
+    }
+
+    target->width	= bitmap->width;
+    target->height	= bitmap->height;
+    target->format	= CSI_G2D_FMT_ARGB8888;
+    ret = csi_g2d_surface_create(target);
+    if (ret) {
+	printf("create target surface failed\n");
+	exit(-1);
+    }
+
+    printf("%ux%u NV12 -> %ux%u ARGB8888\n", source->width, source->height, target->width, target->height);
+
+    ret = g2d_load_bitmap(source, bitmap->name);
+    if (ret) {
+	printf("load bitmap to source failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_surface_set_source(source);
+    if (ret) {
+	printf("set source surface failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_surface_set_target(target);
+    if (ret) {
+	printf("set target surface failed\n");
+	exit(-1);
+    }
+
+    dstRect.left   = dstRect.top = 0;
+    dstRect.right  = target->width;
+    dstRect.bottom = target->height;
+
+    ret = csi_g2d_blit_bitblit(&dstRect, 1);
+    if (ret) {
+	printf("bitblit nv12 to nv12 failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_flush();
+    if (ret) {
+	printf("flush g2d failed\n");
+	exit(-1);
+    }
+
+    ret = g2d_save_bitmap(target, "result/image1_result_640x480_argb8888.rgb");
+    if (ret) {
+	printf("save result failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_surface_destroy(source);
+    if (ret) {
+	printf("destroy source surface failed\n");
+	exit(-1);
+    }
+
+    ret = csi_g2d_surface_destroy(target);
+    if (ret) {
+	printf("destroy target surface failed\n");
+	exit(-1);
+    }
+
+    printf("bitblit operation with 90 rotation finished\n");
+    return 0;
+}
+
+int main(void)
+{
+    int ret;
+
+    ret = csi_g2d_open();
+    if (ret) {
+	printf("open csi g2d failed\n");
+	exit(-1);
+    }
+
+    g2d_test_bitblit();
+
+    g2d_test_draw_rectangle();
+
+    g2d_test_fill_rectangle();
+
+    g2d_test_bitblit_with_rotation();
+
+    g2d_test_stretchblit_with_rotation();
+
+    g2d_test_filterblit_with_rotation();
+
+    g2d_test_bitblit_with_alpha_blending();
+
+    g2d_test_multisrc_blit();
+
+    ret = csi_g2d_close();
+    if (ret) {
+	printf("close g2d failed\n");
+	exit(-1);
+    }
+
+    exit(0);
+}

File diff suppressed because it is too large
+ 0 - 0
examples/resource/yuv420_1280x720_csky2016.yuv


+ 3 - 0
examples/vdec/.gitignore

@@ -0,0 +1,3 @@
+vdec_demo1
+vdec_demo2
+vdec_demo3

+ 30 - 0
examples/vdec/Makefile

@@ -0,0 +1,30 @@
+##
+ # Copyright (C) 2021 Alibaba Group Holding Limited
+ # Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ #
+ # This program is free software; you can redistribute it and/or modify
+ # it under the terms of the GNU General Public License version 2 as
+ # published by the Free Software Foundation.
+##
+DIR_TO_ROOT=../..
+include $(DIR_TO_ROOT)/build.param
+
+#CFLAGS +=
+LIBS	+= -lhal_common -lhal_platform
+OUTPUT_DIR := $(DIR_TO_ROOT)/output/examples/vdec
+#PREPARE := lib_camera
+
+TARGET_1 := vdec_demo1
+SRCS_1 = vdec_demo1.c
+
+TARGET_ALL := $(TARGET_1)
+
+all: $(TARGET_ALL)
+
+clean:
+	rm -rf .obj
+	rm -f $(TARGET_1) $(OUTPUT_DIR)/$(TARGET_1)
+
+include $(DIR_TO_ROOT)/common_target.mk
+
+.PHONY: clean all

+ 172 - 0
examples/vdec/vdec_demo1.c

@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LOG_LEVEL 3
+#define LOG_PREFIX "vdec_demo1"
+#include <syslog.h>
+
+#include <csi_vdec.h>
+#include <csi_allocator.h>
+
+#define TEST_MODULE_NAME "simulator_vdec0"
+
+int main(int argc, char *argv[])
+{
+	int ret;
+	csi_vdec_info_t vdec_info;
+	csi_vdec_dev_t decoder;
+	csi_vdec_chn_t channel;
+
+	// 打印HAL接口版本号
+	csi_api_version_u version;
+	csi_vdec_get_version(&version);
+	printf("Video Decoder HAL version: %d.%d\n", version.major, version.minor);
+
+	// 获取设备中,所有的Video Decoder
+	struct csi_vdec_infos vdec_infos;
+	csi_vdec_query_list(&vdec_infos);
+
+	// 打印所有设备所支持的Video Decoder
+	bool found_module = false;
+	for (int i = 0; i < vdec_infos.count; i++) {
+		csi_vdec_info_t *info;
+		info = &(vdec_infos.info[i]);
+		printf("decoder[%d]: module_name='%s', device_name='%s', capabilities=0x%lx\n",
+		       i, info->module_name, info->device_name, info->capabilities);
+
+		if (strcmp(info->module_name, TEST_MODULE_NAME) == 0) {
+			vdec_info = *info;
+			found_module = true;
+		}
+	}
+
+	if (!found_module) {
+		LOG_E("Can't find module_name:'%s'\n", TEST_MODULE_NAME);
+		exit(-1);
+	}
+
+	// 打开设备获取句柄,作为后续操对象
+	csi_vdec_open(&decoder, vdec_info.device_name);
+
+	// 创建视频解码通道
+	csi_vdec_config_s dec_cfg;
+	dec_cfg.input_mode = CSI_VDEC_INPUT_MODE_FRAME;
+	dec_cfg.input_stream_buf_size = 1*1024*1024;
+	dec_cfg.output_format = CSI_PIX_FMT_I420;
+	dec_cfg.output_width = 1920;
+	dec_cfg.output_height = 1080;
+	dec_cfg.output_order = CSI_VDEC_OUTPUT_ORDER_DISP;
+	dec_cfg.dec_vcodec_id = CSI_VCODEC_ID_H264;
+	dec_cfg.output_img_type = CSI_VDEC_MODE_IPB;
+	dec_cfg.dec_frame_buf_cnt = 8;
+	csi_vdec_create_channel(&channel, decoder, &dec_cfg);
+
+	// 配置内存分配器
+	if (1) {
+	    //csi_allocator_s *allocator = csi_allocator_get(CSI_ALLOCATOR_TYPE_DMA);
+	    //csi_vdec_set_memory_allocator(channel, allocator);
+	} else {
+	    csi_frame_s *allocated_frames[8];   // TODO: allocate frames first
+	    csi_vdec_register_frames(channel, allocated_frames, 8);
+	}
+
+	// 配置解码通道模式
+	csi_vdec_mode_s vdec_mode;
+	vdec_mode.fb_source = CSI_FB_SOURCE_DMABUF;
+	vdec_mode.low_latency_mode = false;
+	vdec_mode.mini_buf_mode = false;
+	csi_vdec_set_mode(channel, &vdec_mode);
+
+	// 获取和重新配置解码通道属性
+	csi_vdec_get_chn_config(channel, &dec_cfg);
+	dec_cfg.dec_frame_buf_cnt = 16;
+	csi_vdec_set_chn_config(channel, &dec_cfg);
+
+	// 订阅事件
+	csi_vdec_event_handle_t event_handle;
+	csi_vdec_create_event_handle(&event_handle, decoder);
+	csi_vdec_event_subscription_t subscribe_dec, subscribe_chn;
+
+	subscribe_dec.type = CSI_VDEC_EVENT_TYPE_DECODER;    // 订阅Decoder事件
+	subscribe_dec.id = CSI_VDEC_EVENT_ID_ERROR;
+	csi_vdec_subscribe_event(event_handle, &subscribe_dec);
+
+	subscribe_chn.type = CSI_VDEC_EVENT_TYPE_CHANNEL;    // 订阅Channel事件
+	subscribe_chn.id = CSI_VDEC_CHANNEL_EVENT_ID_FRAME_READY;
+	csi_vdec_subscribe_event(event_handle, &subscribe_chn);
+
+	// 传送视频码流
+	csi_vdec_start(channel);
+
+	const int send_count = 25;
+	const int stream_packet_len = 1024;
+
+	csi_vdec_stream_s stream;
+	stream.data = malloc(stream_packet_len);
+
+	for (int i = 0; i < send_count; i++) {
+		stream.length = stream_packet_len;
+		stream.pts = 40 * i;
+		stream.eos = (i < (send_count - 1)) ? false : true;
+
+		if (i == 10) {
+			// Just for testing
+			csi_vdec_reset(channel);
+		}
+		csi_vdec_send_stream_buf(channel, &stream, 1000);
+	}
+	free(stream.data);
+	stream.data = NULL;
+
+	// 收取解码结果
+	csi_frame_s *frame;
+	struct csi_vdec_event event;
+
+	int get_count = 0;
+	csi_vdec_chn_status_s status;
+
+	while (get_count < send_count) {
+		// timeout unit: ms, -1 means wait forever, or until error occurs
+		csi_vdec_get_event(event_handle, &event, -1);
+
+		switch (event.type) {
+		case CSI_VDEC_EVENT_TYPE_DECODER:
+			csi_vdec_query_status(channel, &status);
+			// Dump Status
+			break;
+		case CSI_VDEC_EVENT_TYPE_CHANNEL:
+			switch (event.id) {
+			case CSI_VDEC_CHANNEL_EVENT_ID_FRAME_READY:
+				csi_vdec_get_frame(channel, &frame, 1000);
+				get_count++;
+				// display frame
+				// release frame: frame.release();
+			}
+			break;
+		default:
+			break;
+		}
+
+
+	}
+
+	// 关闭与回收资源
+	csi_vdec_stop(channel);
+	csi_vdec_unsubscribe_event(event_handle, &subscribe_dec);
+	csi_vdec_unsubscribe_event(event_handle, &subscribe_chn);
+	csi_vdec_destory_channel(channel);
+	csi_vdec_close(decoder);
+
+	return 0;
+}
+

+ 1 - 0
examples/venc/.gitignore

@@ -0,0 +1 @@
+venc_demo1

+ 30 - 0
examples/venc/Makefile

@@ -0,0 +1,30 @@
+##
+ # Copyright (C) 2021 Alibaba Group Holding Limited
+ # Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ #
+ # This program is free software; you can redistribute it and/or modify
+ # it under the terms of the GNU General Public License version 2 as
+ # published by the Free Software Foundation.
+##
+DIR_TO_ROOT=../..
+include $(DIR_TO_ROOT)/build.param
+
+#CFLAGS +=
+LIBS	+= -lhal_common -lhal_platform
+OUTPUT_DIR := $(DIR_TO_ROOT)/output/examples/venc
+#PREPARE := lib_camera
+
+TARGET_1 := venc_demo1
+SRCS_1 = venc_demo1.c
+
+TARGET_ALL := $(TARGET_1)
+
+all: $(TARGET_ALL)
+
+clean:
+	rm -rf .obj
+	rm -f $(TARGET_1) $(OUTPUT_DIR)/$(TARGET_1)
+
+include $(DIR_TO_ROOT)/common_target.mk
+
+.PHONY: clean all

+ 179 - 0
examples/venc/venc_demo1.c

@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LOG_LEVEL 3
+#define LOG_PREFIX "venc_demo1"
+#include <syslog.h>
+
+#include <csi_venc.h>
+
+#define TEST_MODULE_NAME "simulator_venc0"
+
+int main(int argc, char *argv[])
+{
+	int ret;
+	csi_venc_info_s venc_info;
+	csi_venc_dev_t encoder;
+	csi_venc_chn_t channel;
+
+	// 打印HAL接口版本号
+	csi_api_version_u version;
+	csi_venc_get_version(&version);
+	printf("Video Encoder HAL version: %d.%d\n", version.major, version.minor);
+
+	// 获取设备中,所有的Video Encoder
+	struct csi_venc_infos venc_infos;
+	csi_venc_query_list(&venc_infos);
+
+	// 打印所有设备所支持的Video Encoder
+	bool found_module = false;
+	for (int i = 0; i < venc_infos.count; i++) {
+		csi_venc_info_s *info;
+		info = &(venc_infos.info[i]);
+		printf("decoder[%d]: module_name='%s', device_name='%s', capabilities=0x%lx\n",
+		       i, info->module_name, info->device_name, info->capabilities);
+
+		if (strcmp(info->module_name, TEST_MODULE_NAME) == 0) {
+			venc_info = *info;
+			found_module = true;
+		}
+	}
+
+	if (!found_module) {
+		LOG_E("Can't find module_name:'%s'\n", TEST_MODULE_NAME);
+		exit(-1);
+	}
+
+	// 打开设备获取句柄,作为后续操对象
+	csi_venc_open(&encoder, venc_info.device_name);
+
+	// 创建视频解码通道
+	csi_venc_chn_cfg_s chn_cfg;
+	chn_cfg.attr.enc_vcodec_id = CSI_VCODEC_ID_H264;
+	chn_cfg.attr.max_pic_width = 3840;
+	chn_cfg.attr.max_pic_height = 2160;
+	chn_cfg.attr.input_format = CSI_PIX_FMT_I420;
+	chn_cfg.attr.pic_width = 1920;
+	chn_cfg.attr.pic_height = 1080;
+	chn_cfg.attr.buf_size = 1*1024*1024;
+
+	chn_cfg.attr.h264_attr.profile = CSI_VENC_H264_PROFILE_HIGH;
+	chn_cfg.attr.h264_attr.level = CSI_VENC_H264_LEVEL_4;
+	chn_cfg.attr.h264_attr.frame_type = CSI_VCODEC_I_FRAME |
+					    CSI_VCODEC_P_FRAME |
+					    CSI_VCODEC_B_FRAME;
+	chn_cfg.attr.h264_attr.share_buf = true;
+
+	chn_cfg.gop.gop_num = 5;
+	chn_cfg.gop.gop_mode = CSI_VENC_GOPMODE_NORMALP;
+	chn_cfg.gop.normalp.ip_qp_delta = 10;
+
+	chn_cfg.rc.rc_mode = CSI_VENC_RC_MODE_H264CBR;
+	chn_cfg.rc.h264_vbr.stat_time = 10;
+	chn_cfg.rc.h264_vbr.framerate_numer = 25;
+	chn_cfg.rc.h264_vbr.framerate_denom = 1;
+	chn_cfg.rc.h264_vbr.max_bit_rate = 16 * 1024; // kbps
+	csi_venc_create_channel(&channel, encoder, &chn_cfg);
+
+	// 配置内存分配器
+	//csi_allocator_s *allocator = csi_allocator_get(CSI_ALLOCATOR_TYPE_DMA);
+	//csi_venc_set_memory_allocator(channel, allocator);
+
+	// 设置解码通道扩展属性
+	csi_venc_chn_ext_property_s ext_property;
+	ext_property.prop_id = CSI_VENC_EXT_PROPERTY_ROI;
+	ext_property.roi_prop.index = 0;
+	ext_property.roi_prop.enable = true;
+	ext_property.roi_prop.abs_qp = 1;
+	ext_property.roi_prop.qp = 51;
+	csi_venc_set_ext_property(channel, &ext_property);
+
+	// 订阅事件
+	csi_venc_event_handle_t event_handle;
+	csi_venc_create_event_handle(&event_handle, encoder);
+	csi_venc_event_subscription_s subscribe_dec, subscribe_chn;
+
+	subscribe_dec.type = CSI_VENC_EVENT_TYPE_DECODER;    // 订阅Encoder事件
+	subscribe_dec.id = CSI_VENC_EVENT_ID_ERROR;
+	csi_venc_subscribe_event(event_handle, &subscribe_dec);
+
+	subscribe_chn.type = CSI_VENC_EVENT_TYPE_CHANNEL;    // 订阅Channel事件
+	subscribe_chn.id = CSI_VENC_CHANNEL_EVENT_ID_FRAME_READY;
+	csi_venc_subscribe_event(event_handle, &subscribe_chn);
+
+	// 传送视频码流
+	csi_venc_start(channel);
+
+	csi_frame_s frame;
+	int send_count = 25;
+	for (int i = 0; i < send_count; i++) {
+		if (i == 10) {
+			// Just for testing
+			csi_venc_reset(channel);
+		}
+
+		if (i %5 != 0) {
+			// Send normal frame
+			csi_venc_send_frame(channel, &frame, 1000);
+		}
+		else {
+			// Send frame with extended properties
+			csi_venc_frame_prop_s frame_prop[2];
+			frame_prop[0].type = CSI_VENC_FRAME_PROP_FORCE_IDR;
+			frame_prop[0].force_idr = true;
+			frame_prop[1].type = CSI_VENC_FRAME_PROP_FORCE_SKIP;
+			frame_prop[1].force_skip = false;
+			csi_venc_send_frame_ex(channel, &frame, 1000,
+					       frame_prop, ARRAY_SIZE(frame_prop));
+		}
+	}
+
+	// 收取解码结果
+	csi_stream_s stream;
+	struct csi_venc_event event;
+
+	int get_count = 0;
+	csi_venc_chn_status_s status;
+
+	while (get_count < send_count) {
+		int timeout = -1; // unit: ms, -1 means wait forever, or until error occurs
+		csi_venc_get_event(event_handle, &event, timeout);
+
+		switch (event.type) {
+		case CSI_VENC_EVENT_TYPE_DECODER:
+			csi_venc_query_status(channel, &status);
+			// Dump Status
+			break;
+		case CSI_VENC_EVENT_TYPE_CHANNEL:
+			switch (event.id) {
+			case CSI_VENC_CHANNEL_EVENT_ID_FRAME_READY:
+				csi_venc_get_stream(channel, &stream, 1000);
+				// save stream ...
+				// release stream:  stream.release();
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	// 关闭与回收资源
+	csi_venc_stop(channel);
+	csi_venc_unsubscribe_event(event_handle, &subscribe_dec);
+	csi_venc_unsubscribe_event(event_handle, &subscribe_chn);
+	csi_venc_destory_channel(channel);
+	csi_venc_close(encoder);
+
+	return 0;
+}
+

+ 42 - 0
include/common/camera_string.h

@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __CAMERA_STRING_H__
+#define __CAMERA_STRING_H__
+
+#include <stdio.h>
+
+#include <string.h>
+#include <csi_camera.h>
+#include <camera_manager.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+const char *camera_string_enum_name(int property_id, int enum_id);
+const char *camera_string_bitmask_name(int property_id, int enum_id);
+const char *camera_string_capture_type(csi_camera_channel_capture_type_e type, bool accept_unknown);
+const char *camera_string_chn_capture_types(int fields, char *fields_string);
+const char *camera_string_pixel_format(csi_pixel_fmt_e pix_fmt);
+const char *camera_string_img_type(csi_img_type_e img_type);
+const char *camera_string_meta_field(csi_camera_meta_id_e type, bool accept_unknown);
+const char *camera_string_chn_meta_fields(int fields, char *fields_string);
+const char *camera_string_chn_status(csi_img_type_e img_type);
+
+const char *camera_string_camera_event_type(csi_camera_event_id_e event_id);
+const char *camera_string_channel_event_type(csi_camera_channel_event_id_e event_id);
+const char *camera_string_channel_action(camera_channel_action_e action);
+const char *camera_string_camera_action(camera_action_e action);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif  /* __CAMERA_STRING_H__ */

+ 65 - 0
include/common/common.h

@@ -0,0 +1,65 @@
+/*
+ * Copyright 2018 C-SKY Microsystems Co., Ltd.
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * 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 __COMMON_H__
+#define __COMMON_H__
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <mcheck.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "common_errno.h"
+#include "common_datatype.h"
+#include "syslog.h"
+#include "list.h"
+
+
+#define CHECK_RET_RETURN(ret) \
+	if (ret != 0) { \
+		LOG_E("failed, ret=%d\n", ret); \
+		return ret; \
+	}
+
+#define CHECK_RET_EXIT(ret) \
+	if (ret != 0) { \
+		LOG_E("failed, ret=%d\n", ret); \
+		exit(ret); \
+	}
+
+#define CHECK_RET_WARNING(ret) \
+		if (ret != 0) { \
+			LOG_W("Warning, ret=%d\n", ret); \
+		}
+
+#define CHECK_POINTER_RETURN(pointer) \
+	if (pointer == NULL) { \
+		LOG_E("pointer is NULL\n"); \
+		return ERRNO_INVALID_PARAMETER; \
+	}
+
+#endif /* __COMMON_H__ */
+

+ 58 - 0
include/common/common_datatype.h

@@ -0,0 +1,58 @@
+/*
+ * Copyright 2018 C-SKY Microsystems Co., Ltd.
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * 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 __COMMON_DATATYPE_H__
+#define __COMMON_DATATYPE_H__
+
+#ifndef NULL
+#define	NULL  0x00
+#endif
+
+#ifndef TRUE
+#define TRUE  0x01
+#endif
+#ifndef FALSE
+#define FALSE 0x00
+#endif
+
+#ifndef true
+#define true  0x01
+#endif
+#ifndef false
+#define false 0x00
+#endif
+
+
+#ifndef bool
+typedef unsigned char       bool;
+#endif
+
+#if 0	/* below types are defined in /usr/include/stdint.h */
+typedef unsigned char       uint8_t;
+typedef unsigned short      uint16_t;
+typedef unsigned int        uint32_t;
+
+typedef signed char         int8_t;
+typedef signed short        int16_t;
+typedef signed int          int32_t;
+
+typedef unsigned long long  uint64_t;
+#endif
+
+#endif /* __COMMON_DATATYPE_H__ */
+

+ 34 - 0
include/common/common_errno.h

@@ -0,0 +1,34 @@
+/*
+ * Copyright 2018 C-SKY Microsystems Co., Ltd.
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * 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 __COMMON_ERRNO_H__
+#define __COMMON_ERRNO_H__
+#include <errno.h>
+
+typedef enum {
+	FAILURE = -1,
+	SUCCESS = 0,
+
+	ERRNO_INVALID_PARAMETER,
+	ERRNO_INVALID_STATE,
+
+	ERRNO_INVALID_CLIENT_PACKAGE,
+} common_errno_e;
+
+#endif /* __COMMON_ERRNO_H__ */
+

+ 20 - 0
include/common/dump_utils.h

@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __DUMP_UTILS_H__
+#define __DUMP_UTILS_H__
+
+#include <stdio.h>
+#include <string.h>
+
+#include <csi_frame.h>
+
+void csi_dump_hex(char *data, int length, char *name);
+void csi_dump_img_info(csi_img_s *img);
+
+#endif  // __DUMP_UTILS_H__

+ 19 - 0
include/common/ipc_fd_transfer.h

@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+union {
+	struct cmsghdr	cm;			// control msg
+	char   ctl[CMSG_SPACE(sizeof(int))];	// the pointer of char
+} ctl_un;
+

+ 154 - 0
include/common/list.h

@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) HighPoint Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/dev/hptrr/list.h,v 1.2.2.1.4.1 2010/06/14 02:09:06 kensmith Exp $
+ */
+/*
+ * $Id: list.h,v 1.6 2006/10/31 06:25:28 gmm Exp $
+ * Copyright (C) 2004-2005 HighPoint Technologies, Inc. All rights reserved.
+ */
+#ifndef _HPT_LIST_H_
+#define _HPT_LIST_H_
+
+#ifndef _LINUX_LIST_H
+
+#ifndef _LINUX_TYPES_H
+
+#ifndef HPT_INLINE
+#define HPT_INLINE __inline
+#endif
+
+typedef unsigned long HPT_UPTR;
+
+struct list_head {
+	struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define INIT_LIST_HEAD(ptr) do { (ptr)->next = (ptr); (ptr)->prev = (ptr); } while (0)
+
+static HPT_INLINE void __list_add(struct list_head * _new, struct list_head * prev, struct list_head * next)
+{
+	next->prev = _new;
+	_new->next = next;
+	_new->prev = prev;
+	prev->next = _new;
+}
+
+static HPT_INLINE void list_add(struct list_head *_new, struct list_head *head)
+{
+	__list_add(_new, head, head->next);
+}
+
+static HPT_INLINE void list_add_tail(struct list_head *_new, struct list_head *head)
+{
+	__list_add(_new, head->prev, head);
+}
+
+static HPT_INLINE void __list_del(struct list_head * prev, struct list_head * next)
+{
+	next->prev = prev;
+	prev->next = next;
+}
+
+static HPT_INLINE void list_del(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+}
+
+static HPT_INLINE void list_del_init(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+	INIT_LIST_HEAD(entry); 
+}
+
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+        __list_del(list->prev, list->next);
+        list_add(list, head);
+}
+
+static inline void list_move_tail(struct list_head *list,
+				  struct list_head *head)
+{
+        __list_del(list->prev, list->next);
+        list_add_tail(list, head);
+}
+
+static HPT_INLINE int list_empty(struct list_head *head)
+{
+	return head->next == head;
+}
+
+static HPT_INLINE void __list_splice(struct list_head *list,
+				 struct list_head *head)
+{
+	struct list_head *first = list->next;
+	struct list_head *last = list->prev;
+	struct list_head *at = head->next;
+
+	first->prev = head;
+	head->next = first;
+
+	last->next = at;
+	at->prev = last;
+}
+
+static HPT_INLINE void list_splice(struct list_head *list, struct list_head *head)
+{
+	if (!list_empty(list))
+		__list_splice(list, head);
+}
+
+static HPT_INLINE void list_splice_init(struct list_head *list, struct list_head *head)
+{
+	if (!list_empty(list)) {
+		__list_splice(list, head);
+		INIT_LIST_HEAD(list);
+	}
+}
+
+/*#define list_entry(ptr, type, member) \
+ ((type *)((char *)(ptr)-(HPT_UPTR)(&((type *)0)->member))) */
+#define list_entry(ptr, type, member) \
+	((type *)((unsigned long)(ptr)-((unsigned long)(&((type *)1)->member) - 1)))
+
+#define list_for_each(pos, head) \
+	for (pos = (head)->next; pos != (head); pos = pos->next)
+
+#define list_for_each_safe(pos, n, head) \
+	for (pos = (head)->next, n = pos->next; pos != (head); \
+		pos = n, n = pos->next)
+
+#define get_first_item(attached, type, member) \
+	((type *)((char *)((attached)->next)-(HPT_UPTR)(&((type *)0)->member)))
+
+#endif
+
+#endif
+
+#endif
+

+ 50 - 0
include/common/llist.h

@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: zhuxinran <fuqian.zxr@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LLIST_H__
+#define __LLIST_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LLIST_FORWARD		1
+#define LLIST_BACKWARD		2
+
+typedef void llist_op(const void *);
+typedef int llist_cmp(const void *, const void *);
+
+struct llist_node_st {
+	struct llist_node_st *prev;
+	struct llist_node_st *next;
+	char data[1];
+};
+
+typedef struct llist_head_st {
+	int size;
+	struct llist_node_st head;
+	int (*insert)(struct llist_head_st *, const void *data, int mode);
+	void *(*find)(struct llist_head_st *, const void *data, llist_cmp *cmp);
+	int (*delete)(struct llist_head_st *, const void *data, llist_cmp *cmp);
+	int (*fetch)(struct llist_head_st *, const void *data, llist_cmp *cmp,
+		     void *rdata);
+	void (*travel)(struct llist_head_st *, llist_op *op);
+} LLIST;
+
+LLIST *llist_create(int size);
+
+void llist_destroy(LLIST *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+

+ 104 - 0
include/common/producer_consumer_async.h

@@ -0,0 +1,104 @@
+/*
+ * Copyright 2018-2019 C-SKY Microsystems Co., Ltd.
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * 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 __PRODUCER_CONSUMER_ASYNC_H__
+#define __PRODUCER_CONSUMER_ASYNC_H__
+
+#include "common.h"
+
+struct pca_data_info;
+typedef int32_t (*pca_consumed_callback)(struct pca_data_info* data_info);
+
+typedef struct pca_data_info {
+	void* data;				/* data pointer */
+	uint32_t length;			/* data length */
+	uint32_t type;				/* data type */
+	pca_consumed_callback consumed_callback;/* data need free by dispatcher */
+} pca_data_info_t;
+
+typedef struct pca_data_statistics {
+	uint32_t total_delivered;	/* Data feeded in */
+	uint32_t total_discarded;	/* Data discarded because busy */
+	uint32_t total_updated;		/* New data updated in before consume */
+	uint32_t total_consumed;	/* Data consumed */
+} pca_data_statistics_t;
+
+typedef int32_t (*pca_consumer_process)(pca_data_info_t* data_info);
+
+typedef struct pca_thread_info {
+	pthread_t tid;			/* thread ID */
+	char name[32];			/* thread name */
+	sem_t sem_wakeup;		/* semphore to wakeup thread */
+	bool  is_running;
+
+	pca_data_info_t data_info;	/* the data delivered from parent */
+	bool has_new_data;		/* indicate there is new data to handle */
+	bool need_unlock_data_mutex;	/* Just for mark flag when need unlock */
+	pthread_mutex_t mutex_data;	/* mutex to protect handling data */
+	pca_data_statistics_t stats;	/* the statistics of data */
+} pca_thread_info_t;
+
+typedef struct pca_consumer_processor_info {
+	pca_consumer_process process;	/* consumer processor function */
+	int data_type;			/* the data type to be consume */
+	char name[16];			/* consumer name for debug */
+} pca_consumer_processor_info_t;
+
+struct pca_dispatcher_info;		/* Declare here but defined below */
+
+typedef struct pca_consumer_list_info {
+	pca_thread_info_t thread_info;		/* thread info */
+	pca_consumer_processor_info_t processor;/* post processor info */
+	struct list_head list;			/* to build list */
+	struct pca_dispatcher_info* dispatcher;	/* dispatcher's pointer */
+} pca_consumer_list_info_t;
+
+typedef struct {
+	pca_data_info_t data_info;		/* data_info */
+	unsigned int reference_count;		/* data using count */
+	struct list_head list;			/* to build list */
+} pca_data_free_list_info_t;
+
+typedef struct pca_dispatcher_info {
+	pca_thread_info_t thread_info;		/* thread info */
+
+	pthread_mutex_t consumer_mutex;		/* mutex to protect consumer_list */
+	pca_consumer_list_info_t consumer_list;	/* consumers list */
+
+	pthread_mutex_t data_free_mutex;	/* mutex to protect data_free_list */
+	pca_data_free_list_info_t data_free_list;/* data list need to free */
+} pca_dispatcher_info_t;
+
+int32_t pca_dispatcher_create(pca_dispatcher_info_t** dispatcher, char* name);
+int32_t pca_dispatcher_run(pca_dispatcher_info_t* dispatcher);
+int32_t pca_dispatcher_feed(pca_dispatcher_info_t* dispatcher,
+			    void *data, int32_t data_type);
+int32_t pca_dispatcher_stop(pca_dispatcher_info_t* dispatcher);
+int32_t pca_dispatcher_destory(pca_dispatcher_info_t* dispatcher);
+
+int32_t pca_add_consumer_processor(pca_dispatcher_info_t* dispatcher,
+				   pca_consumer_processor_info_t *processor);
+int32_t pca_remove_consumer_processor(pca_dispatcher_info_t* dispatcher,
+				      pca_consumer_processor_info_t *processor);
+int32_t pca_feed_consumers(pca_dispatcher_info_t* dispatcher,
+			   pca_data_info_t* data_info);
+int32_t pca_feed_dispatcher(pca_dispatcher_info_t* dispatcher,
+			    pca_data_info_t* data_info);
+
+#endif /* __PRODUCER_CONSUMER_ASYNC_H__ */
+

+ 47 - 0
include/common/ringbuffer.h

@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: zhuxinran <fuqian.zxr@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+/*
+ * Copyright (C) 2017-2020 Alibaba Group Holding Limited
+ */
+
+#ifndef _DRV_RINGBUFFER_H_
+#define _DRV_RINGBUFFER_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "stdint.h"
+#include <stdbool.h>
+
+typedef struct ringbuffer {
+	uint8_t *buffer;
+	uint32_t size;
+	uint32_t write;
+	uint32_t read;
+	uint32_t data_len;
+} ringbuffer_t;
+
+void ringbuffer_reset(ringbuffer_t *fifo);
+uint32_t ringbuffer_len(ringbuffer_t *fifo);
+uint32_t ringbuffer_avail(ringbuffer_t *fifo);
+bool ringbuffer_is_empty(ringbuffer_t *fifo);
+bool ringbuffer_is_full(ringbuffer_t *fifo);
+
+/*write to ringbuffer*/
+uint32_t ringbuffer_in(ringbuffer_t *fifo, const void *in, uint32_t len);
+
+/*read to ringbuffer*/
+uint32_t ringbuffer_out(ringbuffer_t *fifo, void *out, uint32_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DRV_RINGBUFFER_H_ */

+ 111 - 0
include/common/syslog.h

@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#ifndef SYSLOG_H
+#define SYSLOG_H
+
+#define LOG_ENABLE
+
+#ifdef LOG_LEVEL
+#if (LOG_LEVEL >= 3)
+#define LOG_ENABLE_D
+#endif
+
+#if (LOG_LEVEL >= 2)
+#define LOG_ENABLE_I
+#endif
+
+#if (LOG_LEVEL >= 1)
+#define LOG_ENABLE_W
+#endif
+
+#if (LOG_LEVEL >= 0)
+#define LOG_ENABLE_E
+#endif
+#else   /* #ifdef LOG_LEVEL */
+#define LOG_ENABLE_E    /* Default level if LOG_LEVEL not defiend */
+#endif  /* #ifdef LOG_LEVEL */
+
+/* [LogLevel:FileName:Function:Line] */
+extern const char *PFORMAT_D;
+extern const char *PFORMAT_I;
+extern const char *PFORMAT_W;
+extern const char *PFORMAT_E;
+extern const char *PFORMAT_O;
+
+#ifdef LOG_PREFIX
+#define LOG_PREF LOG_PREFIX"-"
+#else
+#define LOG_PREF ""
+#endif
+
+#define LOG_E_BASE_ARGS LOG_PREF, __FUNCTION__, __LINE__
+#define LOG_W_BASE_ARGS LOG_PREF, __FUNCTION__, __LINE__
+#define LOG_I_BASE_ARGS LOG_PREF, __FUNCTION__, __LINE__
+#define LOG_D_BASE_ARGS LOG_PREF, __FUNCTION__, __LINE__
+#define LOG_O_BASE_ARGS LOG_PREF, __FUNCTION__, __LINE__
+
+/* Log in freely format without prefix */
+#ifdef LOG_ENABLE
+#define LOG_F(fmt, args...) printf(fmt,##args)
+#else
+#define LOG_F(fmt, args...)
+#endif
+
+// OK, Green color
+#define LOG_O(fmt, args...)	\
+	do {printf(PFORMAT_O,LOG_O_BASE_ARGS); printf(fmt,##args);} while(0)
+
+#define LOGPRINT_E printf
+#define LOGPRINT_W printf
+#define LOGPRINT_I printf
+#define LOGPRINT_D printf
+
+/* Log debug */
+#if defined(LOG_ENABLE_D) && defined(LOG_ENABLE)
+#define LOG_D(fmt, args...) \
+    do {LOGPRINT_D(PFORMAT_D,LOG_D_BASE_ARGS); LOGPRINT_D(fmt,##args);} while(0)
+#else
+#define LOG_D(fmt, args...)
+#endif
+
+/* Log information */
+#if defined(LOG_ENABLE_I) && defined(LOG_ENABLE)
+#define LOG_I(fmt, args...) \
+    do {LOGPRINT_I(PFORMAT_I ,LOG_I_BASE_ARGS); LOGPRINT_I(fmt,##args);} while(0)
+#else
+#define LOG_I(fmt, args...)
+#endif
+
+/* Log warning */
+#if defined(LOG_ENABLE_W) && defined(LOG_ENABLE)
+#define LOG_W(fmt, args...) \
+    do {LOGPRINT_W(PFORMAT_W,LOG_W_BASE_ARGS); LOGPRINT_W(fmt,##args);} while(0)
+#else
+#define LOG_W(fmt, args...)
+#endif
+
+/* Log error */
+#if defined(LOG_ENABLE_E) && defined(LOG_ENABLE)
+#define LOG_E(fmt, args...) \
+    do{LOGPRINT_E(PFORMAT_E,LOG_E_BASE_ARGS); LOGPRINT_E(fmt,##args);} while(0)
+#else
+#define LOG_E(fmt, args...)
+#endif
+
+#define ENTER_VOID()    LOG_D("Enter\n")
+#define EXIT_VOID()     do { LOG_D("Exit\n"); return;} while(0)
+#define EXIT_INT(val)   do { LOG_D("Exit, return val=%d\n", (int)val); return val;} while(0)
+#define EXIT_PTR(ptr)   do { LOG_D("Exit, return ptr=%p\n", (void*)ptr); return ptr;} while(0)
+
+#endif  // SYSLOG_H

+ 50 - 0
include/hal/csi_allocator.h

@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __CSI_ALLOCATOR_H__
+#define __CSI_ALLOCATOR_H__
+
+#include <stddef.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+typedef enum csi_allocator_type {
+	CSI_ALLOCATOR_TYPE_SYSTEM,
+	CSI_ALLOCATOR_TYPE_SYSTEM_CONTIG,
+	CSI_ALLOCATOR_TYPE_CARVEOUT,
+	CSI_ALLOCATOR_TYPE_DMA,
+	CSI_ALLOCATOR_TYPE_CUSTOM,
+} csi_allocator_type_e;	// refer from ion_heap_type
+
+typedef struct csi_mem {
+	void *usr_addr;
+	union {
+		int64_t phy_addr; /* 0 means invalid */
+		int fd; /* -1 means invalid */
+	};
+
+	size_t size;
+	void *opaque; /* not for user, DO NOT use or modify it */
+} csi_mem_s;
+
+
+typedef struct csi_allocator {
+	//int (*init)(char *args);
+	csi_mem_s *(*alloc)(csi_allocator_type_e type, size_t size, uint32_t align);
+	void (*free)(csi_mem_s *mem);
+	void *(*map)(csi_mem_s *mem);
+	void (*unmap)(csi_mem_s *mem);
+} csi_allocator_s;
+
+//csi_allocator_s *csi_allocator_get(csi_allocator_type_e type);
+int32_t csi_hal_set_allocator(csi_allocator_s allocator);
+int32_t csi_hal_get_allocator(csi_allocator_s *allocator);
+
+#endif /* __CSI_ALLOCATOR_H__ */

+ 135 - 0
include/hal/csi_audio_ai.h

@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: fuqian.zxr <fuqian.zxr@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __CSI_AUDIO_AI_H__
+#define __CSI_AUDIO_AI_H__
+
+#include "csi_audio_common.h"
+
+#define CSI_AUDIO_AI_VERSION_MAJOR	0
+#define CSI_AUDIO_AI_VERSION_MINOR	1
+
+#define VQE_DRC_SECNUM 5
+
+#define CSI_AI_MAX_COUNT 16
+#define CSI_AI_NAME_MAX_LEN 32
+
+#define CSI_AI_CAP_SPDIF  0x00000001 /*Is a spdif device*/
+#define CSI_AI_CAP_HDMI   0x00000002 /*IS a hdmi audio*/
+#define CSI_AI_CAP_CODEC  0x00000003 /*Is a codec audio*/
+
+typedef struct csi_ai_info {
+    char ai_name[CSI_AI_NAME_MAX_LEN];
+    unsigned int capbilities;
+}csi_ai_info_s;
+
+typedef struct csi_ai_infos {
+    unsigned int count;
+    csi_ai_info_s info[CSI_AI_MAX_COUNT];
+}csi_ai_infos_s;
+
+typedef struct csi_aec_frame {
+    csi_audio_frame_s refframe;
+    bool bvalid;
+    bool bsysbind;
+}csi_aec_frame_s;
+
+typedef struct csi_aichn_frame{
+    uint32_t usr_frm_depth;
+}csi_aichn_frame_s;
+
+typedef struct csi_ai_aec_config {
+    bool    usrmode;
+    int8_t  cngmode;
+    int8_t  nearallpassenergy;
+    int8_t  nearcleansupenergy;
+    int16_t dthnl_sort_qth;
+    int16_t echobandlow;
+    int16_t echobandhigh;
+    int16_t echobandlow2;
+    int16_t echobandhigh2;
+    int16_t erl_band[6];
+    int16_t erl[7];
+    int16_t voice_protect_freql;
+    int16_t voice_protect_freql1;
+    int32_t reserved;
+}csi_ai_aec_config_s;
+
+typedef struct csi_ai_rnr_config {
+    bool    usrmode;
+    int32_t nrmode;
+    int32_t maxnrlevel;
+    int32_t noisethresh;
+}csi_ai_rnr_config_s;
+
+typedef struct csi_ai_hdr_config {
+    bool usrmode;
+    int32_t mingaindb;
+    int32_t maxgaindb;
+    int32_t micgaindb;
+    int32_t micgainstepdb;
+    void *callback;
+}csi_ai_hdr_config_s;
+
+typedef struct csi_ai_drc_config {
+    bool usrmode;
+    int16_t attacktime;
+    int16_t releasetime;
+    int16_t oldlevdb[VQE_DRC_SECNUM];
+    int16_t newlevdb[VQE_DRC_SECNUM];
+}csi_ai_drc_config_s;
+
+
+int32_t csi_ai_get_version(csi_api_version_u *version);
+
+int32_t csi_ai_query_list(csi_ai_infos_s *infos);
+
+int32_t csi_ai_setpubattr(int32_t aidevid,csi_aio_attr_s *aiattr);
+int32_t csi_ai_getpubattr(int32_t aidevid,csi_aio_attr_s *aiattr);
+
+int32_t csi_ai_enable(int32_t aidevid);
+int32_t csi_ai_disable(int32_t aidevid);
+
+int32_t csi_ai_enablechn(int32_t aidevid,int32_t aichn);
+int32_t csi_ai_disablechn(int32_t aidevid,int32_t aichn);
+
+int32_t csi_ai_getframe(int32_t aidev,int32_t aichn,csi_audio_frame_s *frm,csi_aec_frame_s *aecfrm,int32_t timeout);
+int32_t csi_ai_releaseframe(int32_t aidev,int32_t aichn,csi_audio_frame_s *frm,csi_aec_frame_s *aecfrm);
+
+int32_t csi_ai_setchnparam(int32_t aidev,int32_t aichn,csi_aichn_frame_s *chnparam);
+int32_t csi_ai_getchnparam(int32_t aidev,int32_t aichn,csi_aichn_frame_s *chnparam);
+
+int32_t csi_ai_enableresmp(int32_t aidev,int32_t aichn,csi_audio_sample_rate_e out_sample_rate);
+int32_t csi_ai_disableresmp(int32_t aidev,int32_t aichn);
+
+int32_t csi_ai_setvqeattr(int32_t aidev,int32_t aichn,int32_t aochn,int *level);
+int32_t csi_ai_getvqeattr(int32_t aidev,int32_t aichn,int *level);
+
+int32_t csi_ai_settalkvqeattr(int32_t aidev,int32_t aichn,int32_t aodev,int32_t aochn,int *level);
+int32_t csi_ai_gettalkvqeattr(int32_t aidev,int32_t aichn,int *level);
+
+int32_t csi_ai_setrecordvqeattr(int32_t aidev,int32_t aichn,int *level);
+int32_t csi_ai_getrecordvqeattr(int32_t aidev,int32_t aichn,int *level);
+
+int32_t csi_ai_enablevqe(int32_t aidev,int32_t aichn);
+int32_t csi_ai_disablevqe(int32_t aidev,int32_t aichn);
+
+int32_t csi_ai_settrackmode(int32_t aidev,csi_audio_track_mode_e trackmode);
+int32_t csi_ai_gettrackmode(int32_t aidev,csi_audio_track_mode_e *trackmode);
+
+int32_t csi_ai_reset(int32_t aidevid);
+
+int32_t csi_ai_queryfilestatus(int32_t aidev,int32_t aichn,csi_audio_file_status_s *filestatus);
+
+int32_t csi_ai_setvqevolume(int32_t aidev,int32_t aichn,int32_t volumedb);
+int32_t csi_ai_getvqevolume(int32_t aidev,int32_t aichn,int32_t *volumedb);
+
+int32_t csi_ai_enableaecrefframe(int32_t aidev,int32_t aichn,int32_t aodev,int32_t aochn);
+int32_t csi_ai_disableaecrefframe(int32_t aidev,int32_t aichn);
+
+#endif

+ 113 - 0
include/hal/csi_audio_ao.h

@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: fuqian.zxr <fuqian.zxr@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __CSI_AUDIO_AO_H__
+#define __CSI_AUDIO_AO_H__
+
+#include "csi_audio_common.h"
+
+#define CSI_AO_MAX_COUNT 16
+#define CSI_AO_NAME_MAX_LEN 32
+
+#define CSI_AO_CAP_SPDIF  0x00000001 /*Is a spdif device*/
+#define CSI_AO_CAP_HDMI   0x00000002 /*IS a hdmi audio*/
+#define CSI_AO_CAP_CODEC  0x00000003 /*Is a codec audio*/
+
+typedef struct csi_ao_info {
+    char ai_name[CSI_AO_NAME_MAX_LEN];
+    unsigned int capbilities;
+}csi_ao_info_s;
+
+typedef struct csi_ao_infos {
+    unsigned int count;
+    csi_ao_info_s info[CSI_AO_MAX_COUNT];
+}csi_ao_infos_s;
+
+#define CSI_AUDIO_AO_VERSION_MAJOR	0
+#define CSI_AUDIO_AO_VERSION_MINOR	1
+
+typedef struct csi_ao_chn_state {
+    uint32_t chntotalnum;
+    uint32_t chnfreenum;
+    uint32_t chnbusynum;
+}csi_ao_chn_state_s;
+
+typedef enum csi_audio_fade_rate {
+    AUIDO_FADE_RATE_1 = 0,
+    AUIDO_FADE_RATE_2 = 1,
+    AUIDO_FADE_RATE_4 = 2,
+    AUIDO_FADE_RATE_8 = 3,
+    AUIDO_FADE_RATE_16 = 4,
+    AUIDO_FADE_RATE_32 = 5,
+    AUIDO_FADE_RATE_64 = 6,
+    AUIDO_FADE_RATE_128 = 7,
+    AUIDO_FADE_RATE_BUTT
+}csi_audio_fade_rate_e;
+
+typedef struct csi_audio_fade {
+    bool fade;
+    csi_audio_fade_rate_e fadeinrate;
+    csi_audio_fade_rate_e fadeoutrate;
+}csi_audio_fade_s;
+
+typedef struct csi_ao_vqe_config {
+    int32_t hpfopen;
+    int32_t anropen;
+    int32_t agcopen;
+    int32_t eqopen;
+    int32_t worksamplerate;
+    int32_t framesample;
+    csi_vqe_workstate_e workstate;
+    csi_audio_hpf_config_s hpfcfg;
+    csi_audio_anr_config_s anrcfg;
+    csi_audio_agc_config_s agccfg;
+    csi_audio_eq_config_s eqcfg;
+}csi_ao_vqe_config_s;
+
+int32_t csi_ao_get_version(csi_api_version_u *version);
+
+int32_t csi_ao_query_list(csi_ao_infos_s *infos);
+int32_t csi_ao_setpubattr(int32_t aodev,csi_aio_attr_s *attr);
+int32_t csi_ao_getpubattr(int32_t aodev,csi_aio_attr_s *attr);
+
+int32_t csi_ao_enable(int32_t aodev);
+int32_t csi_ao_disable(int32_t aodev);
+
+int32_t csi_ao_enablechn(int32_t aodev,int32_t aochn);
+int32_t csi_ao_disablechn(int32_t aodev,int32_t aochn);
+
+
+int32_t csi_ao_sendframe(int32_t aodev,int32_t aochn,const csi_audio_frame_s *data,int32_t timeout);
+int32_t csi_ao_enableresmp(int32_t aodev,int32_t aochn,csi_audio_sample_rate_e insamplerate);
+
+int32_t csi_ao_disableresmp(int32_t aodev,int32_t aochn);
+int32_t csi_ao_pausechn(int32_t aodev,int32_t aochn);
+
+int32_t csi_ao_resumechn(int32_t aodev,int32_t aochn);
+int32_t csi_ao_clearchnbuf(int32_t aodev,int32_t aochn);
+
+int32_t csi_ao_querychnstat(int32_t aodev,int32_t aochn,csi_ao_chn_state_s *status);
+
+int32_t csi_ao_settrackmode(int32_t aodev,csi_audio_track_mode_e trackmode);
+int32_t csi_ao_gettrackmode(int32_t aodev,csi_audio_track_mode_e *trackmode);
+
+int32_t csi_ao_setvolume(int32_t aodev,int32_t volume);
+int32_t csi_ao_getvolume(int32_t aodev,int32_t *volume);
+
+int32_t csi_ao_setmute(int32_t aodev,bool enable,csi_audio_fade_s *fade);
+int32_t csi_ao_getmute(int32_t aodev,bool enable,csi_audio_fade_s *fade);
+
+int32_t csi_ao_reset(int32_t aodev);
+
+int32_t csi_ao_setvqeattr(int32_t aodev,int32_t aochn,csi_ao_vqe_config_s *vqeconfig);
+int32_t csi_ao_getvqeattr(int32_t aodev,int32_t aochn,csi_ao_vqe_config_s *vqeconfig);
+
+int32_t csi_ao_enablevqe(int32_t aodev,int32_t aochn);
+int32_t csi_ao_disablevqe(int32_t aodev,int32_t aochn);
+
+#endif

+ 168 - 0
include/hal/csi_audio_common.h

@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: fuqian.zxr <fuqian.zxr@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __CSI_AUDIO_COMMON_H__
+#define __CSI_AUDIO_COMMON_H__
+
+#include <unistd.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include "csi_common.h"
+
+#define MAX_AUDIO_FILE_PATH_LEN 256
+#define VQE_EQ_BAND_NUM 10
+
+typedef enum csi_audio_sample_rate {
+    AUDIO_SAMPLE_RATE_8000  = 8000,  /*8K samplerate*/
+    AUDIO_SAMPLE_RATE_12000 = 12000, /*12K samplerate*/
+    AUDIO_SAMPLE_RATE_11025 = 11025, /*11.025K samplerate*/
+    AUDIO_SAMPLE_RATE_16000 = 16000, /*16K samplerate*/
+    AUDIO_SAMPLE_RATE_22050 = 22050, /*22.05k samplerate*/
+    AUDIO_SAMPLE_RATE_24000 = 24000, /*24K samplerate*/
+    AUDIO_SAMPLE_RATE_32000 = 32000, /*32K samplerate*/
+    AUDIO_SAMPLE_RATE_44100 = 44100, /*44.1K samplerate*/
+    AUDIO_SAMPLE_RATE_48000 = 48000, /*48K samplerate*/
+    AUDIO_SAMPLE_RATE_64000 = 64000, /*64K samplerate*/
+    AUDIO_SAMPLE_RATE_96000 = 96000, /*96K samplerate*/
+    AUDIO_SAMPLE_RATE_BUTT,
+}csi_audio_sample_rate_e;
+
+typedef enum csi_audio_bit_width {
+    AUDIO_BIT_WIDTH_8  = 0,  /*8bit width*/
+    AUDIO_BIT_WIDTH_16 = 1,  /*16bit width*/
+    AUDIO_BIT_WIDTH_24 = 2,  /*24bit width*/
+    AUDIO_BIT_WIDTH_BUTT,
+}csi_audio_bit_width_e;
+
+typedef enum csi_audio_mode {
+    AIO_MODE_I2S_MASTER = 0,  /* AIO I2S master mode */
+    AIO_MODE_I2S_SLAVE,       /* AIO I2S slave mode */
+    AIO_MODE_PCM_SLAVE_STD,   /* AIO PCM slave standard mode */
+    AIO_MODE_PCM_SLAVE_NSTD,  /* AIO PCM slave non-standard mode */
+    AIO_MODE_PCM_MASTER_STD,  /* AIO PCM master standard mode */
+    AIO_MODE_PCM_MASTER_NSTD, /* AIO PCM master non-standard mode */
+    AIO_MODE_BUTT,
+}csi_audio_mode_e;
+
+typedef enum csi_audio_sound_mode {
+    AUDIO_SOUND_MODE_MONO   = 0, /*mono*/
+    AUDIO_SOUND_MODE_STEREO = 1, /*stereo*/
+    AUDIO_SOUND_MODE_BUTT
+}csi_audio_sound_mode_e;
+
+typedef enum csi_auido_i2stype {
+    AIO_I2STYPE_INNERCODEC = 0, /*AIO I2S connect inner audio CODEC*/
+    AIO_I2STYPE_INNERHDMI,      /*AIO I2S connect inner HDMI*/
+    AIO_I2STYPE_EXTERN,         /*AIO I2S connect extern hardware*/
+}csi_auido_i2stype_e;
+
+typedef struct csi_aio_attr {
+    csi_audio_sample_rate_e samplerate;  /*sample rate*/
+    csi_audio_bit_width_e bitwidth; /*bitwidth*/
+    csi_audio_mode_e workmode;    /*master or slave mode*/
+    csi_audio_sound_mode_e soundmode; /*mono or steror*/
+    uint32_t exflag;
+    uint32_t frmnum;
+    uint32_t pt_num_per_frm;
+    uint32_t chncnt;
+    csi_auido_i2stype_e i2stype;
+}csi_aio_attr_s;
+
+typedef struct csi_audio_frame {
+    csi_audio_bit_width_e bitwidth;
+    csi_audio_sound_mode_e soundmode;
+    void *viraddr[2];
+    uint32_t  phyaddr[2];
+    uint64_t  timestamp; /*audio frame timestamp*/
+    uint32_t  seq; /*audio frame seq*/
+    uint32_t  len; /*data length per channel in frame*/
+    uint32_t  poolid[2];
+}csi_audio_frame_s;
+
+typedef enum csi_audio_track_mode {
+    AUDIO_TRACK_NORMAL = 0,
+    AUDIO_TRACK_BOTH_LEFT = 1,
+    AUDIO_TRACK_BOTH_RIGHT = 2,
+    AUDIO_TRACK_EXCHANGE = 3,
+    AUDIO_TRACK_MIX = 4,
+    AUDIO_TRACK_LEFT_MUTE = 5,
+    AUDIO_TRACK_RIGHT_MUTE = 6,
+    AUDIO_TRACK_BOTH_MUTE = 7,
+    AUDIO_TRACK_BUTT,
+}csi_audio_track_mode_e;
+
+typedef struct csi_audio_save_file_info {
+    bool cfg;
+    char filepath[MAX_AUDIO_FILE_PATH_LEN];
+    char filename[MAX_AUDIO_FILE_PATH_LEN];
+    uint32_t filesize;
+}csi_audio_save_file_info_s;
+
+typedef struct csi_audio_file_status {
+    bool saving;
+}csi_audio_file_status_s;
+
+typedef enum csi_vqe_workstate {
+    VQE_WORKSTATE_COMMON  = 0,
+    VQE_WORKSTATE_MUSIC  = 1,
+    VQE_WORKSTATE_NOISY  = 2
+}csi_vqe_workstate_e;
+
+typedef enum csi_audio_hpf_freq {
+    AUDIO_HPF_FREQ_80 = 80,   /*80HZ*/
+    AUDIO_HPF_FREQ_120 = 120, /*120Hz*/
+    AUDIO_HPF_FREQ_150 = 150, /*150Hz*/
+    AUDIO_HPF_FREQ_BUTT,
+}csi_audio_hpf_freq_e;
+
+typedef struct csi_audio_hpf_config {
+    bool usrmode;
+    csi_audio_hpf_freq_e hpffreq;
+}csi_audio_hpf_config_s;
+
+typedef struct csi_audio_anr_config {
+    bool usrmode;
+    int16_t nrintensity;
+    int16_t noisedbthr;
+    int8_t sp_pro_switch;
+    int32_t reserved;
+}csi_audio_anr_config_s;
+
+typedef struct csi_audio_agc_config {
+    bool usrmode;
+    int8_t target_level;
+    int8_t noise_floor;
+    int8_t maxgain;
+    int8_t adjustspeed;
+    int8_t improvesnr;
+    int8_t usehighpassfilt;
+    int8_t outputmode;
+    int16_t noisesupswitch;
+    int32_t reserved;
+}csi_audio_agc_config_s;
+
+typedef struct csi_audio_eq_config {
+    int8_t gaindb[VQE_EQ_BAND_NUM];
+    int32_t reserved;
+}csi_audio_eq_config_s;
+
+typedef enum {
+    PT_PCMU  = 0,
+    PT_1016  = 1,
+    PT_BUTT
+}PAYLOAD_TYPE_E;
+
+typedef struct csi_audio_stream {
+    uint8_t *stream; /*the virtual address of stream*/
+    uint32_t phyaddr; /*the physics address of stream*/
+    uint32_t len;   /*stream length,by bytes*/
+    uint64_t timestamp; /*frame time stamp*/
+    uint32_t seq; /*frame seq,if stream is not a valid frame 0*/
+}csi_audio_stream_s;
+
+#endif

+ 61 - 0
include/hal/csi_audio_dec.h

@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: fuqian.zxr <fuqian.zxr@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __CSI_AUDIO_DEC_H__
+#define __CSI_AUDIO_DEC_H__
+
+#include "csi_audio_common.h"
+
+#define CSI_AUDIO_DEC_VERSION_MAJOR	0
+#define CSI_AUDIO_DEC_VERSION_MINOR	1
+
+typedef enum csi_adec_mode {
+    ADEC_MODE_PACK = 0,
+    ADEC_MODE_STREAM,
+    ADEC_MODE_BUTT
+}csi_adec_mode_e;
+
+typedef struct csi_adec_ch_attr {
+    PAYLOAD_TYPE_E type;
+    uint32_t bufsize;
+    csi_adec_mode_e mode;
+    void *value;
+}csi_adec_ch_attr_s;
+
+typedef struct csi_adec_decoder {
+    PAYLOAD_TYPE_E type;
+    char name[16];
+    int32_t (*openendecoder)(void *decoderattr,void **decoder);
+    int32_t (*decoderfrm)(void *decoder,uint8_t **inbuf,int32_t leftbyte,uint16_t *outbuf,uint32_t *outlen,uint32_t *chns);
+    int32_t (*getfrminfo)(void *decoder,void *info);
+    int32_t (*closedecoder)(void *decoder);
+    int32_t (*resetdecoder)(void *decoder);
+}csi_adec_decoder_s;
+
+typedef struct csi_audio_frame_info {
+    csi_audio_frame_s *frame;
+    uint32_t id;
+}csi_audio_frame_info_s;
+
+int32_t csi_adec_get_version(csi_api_version_u *version);
+
+int32_t csi_adec_create(int32_t adchn,csi_adec_ch_attr_s);
+int32_t csi_adec_destroy(int32_t adchn);
+
+int32_t csi_adec_sendstream(int32_t adchn,const csi_audio_stream_s *stream, bool block);
+int32_t csi_adec_clearchnbuf(int32_t adchn);
+
+int32_t csi_adec_registerdecoder(int32_t handle,csi_adec_decoder_s *decoder);
+int32_t csi_adec_unregisterdecoder(int32_t hanbdle);
+
+int32_t csi_adec_getframe(int32_t adchn,csi_audio_frame_info_s *frameinfo,bool block);
+int32_t csi_adec_releaseframe(int32_t adchn,csi_audio_frame_info_s *frameinfo);
+
+int32_t csi_adec_sendendofstream(int adchn,bool instant);
+
+#endif

+ 63 - 0
include/hal/csi_audio_enc.h

@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: fuqian.zxr <fuqian.zxr@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __CSI_AUDIO_ENC_H__
+#define __CSI_AUDIO_ENC_H__
+
+#include <unistd.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "csi_audio_common.h"
+
+#define CSI_AUDIO_ENC_VERSION_MAJOR	0
+#define CSI_AUDIO_ENC_VERSION_MINOR	1
+
+typedef struct csi_aenc_chn_attr
+{
+    PAYLOAD_TYPE_E type;
+    uint32_t  numperfrm;
+    uint32_t  buffersize;
+}csi_aenc_chn_attr_s;
+
+typedef struct csi_aec_frame {
+    csi_audio_frame_s refframe;
+    bool valid;
+    bool sysbind;
+}csi_aec_frame_s;
+
+typedef struct csi_aenc_encode {
+    PAYLOAD_TYPE_E type;
+    uint32_t maxfrmlen;
+    char name[16];
+    int32_t (*openencoder)(void *encoderattr,void **encoder);
+    int32_t (*encoderfrm)(void *encoder,const csi_audio_frame_s *data,uint8_t *outbuf,uint32_t *outlen);
+    int32_t (*closeencoder)(void *encoder);
+}csi_aenc_encode_s;
+
+int32_t csi_adec_get_version(csi_api_version_u *version);
+
+int32_t csi_aenc_createchn(int32_t aechn,const csi_aenc_chn_attr_s attr);
+int32_t csi_aenc_destroychn(int32_t aechn);
+
+int32_t csi_aenc_sendframe(int32_t aechn,const csi_audio_frame_s *frm,const csi_aec_frame_s *aecfrm);
+int32_t csi_aenc_getstream(int32_t aechn,csi_audio_stream_s *stream,int32_t timeout);
+
+int32_t csi_aenc_releasestream(int32_t aechn,const csi_audio_stream_s *stream);
+
+int32_t csi_aenc_getfd(int32_t aechn);
+int32_t csi_aenc_registerencoder(int32_t handle,csi_aenc_encode_s *encoder);
+int32_t csi_aenc_unregisterencoder(int32_t handle);
+
+int32_t csi_aenc_savefile(int32_t aechn,csi_audio_save_file_info_s *savefileinfo);
+int32_t csi_aenc_queryfilestatus(int32_t aechn,csi_audio_file_status_s *filestatus);
+
+int32_t csi_aec_getstreambufinfo(int32_t aechn,uint32_t *physaddr,uint32_t *size);
+
+#endif

+ 297 - 0
include/hal/csi_camera.h

@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __CSI_CAMERA_H__
+#define __CSI_CAMERA_H__
+
+#include <time.h>
+
+#include <csi_common.h>
+#include <csi_camera_property.h>
+#include <csi_camera_frame.h>
+#include <csi_frame_ex.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Camera logical parts are below, including: input sensor and output channel
+ *  @------------------------------@
+ *  |    Camera Settings      _____|______   Channel Settings
+ *  |  ===================   |            | =====================
+ *  |      Exposure          | channel[0] | configuration: width/height, pix_fmt
+ *  |      R/G/B Gain        |_____ ______| ---> Channel Events
+ *  |      HDR mode           _____|______
+ *  |        ......          |            |
+ *  |                        | channel[1] | configuration: width/height, pix_fmt
+ *  |                        |_____ ______| ---> Channel Events
+ *  |                         _____|______
+ *  |                        |            |
+ *  |                        | channel[n] | configuration: width/height, pix_fmt
+ *  |                        |_____ ______| ---> Channel Events
+ *  |        CAMERA                |
+ *  @------------------------------@        ===> Camera Events (sensor, error, warning...)
+ */
+
+#define CSI_CAMERA_VERSION_MAJOR	0
+#define CSI_CAMERA_VERSION_MINOR	2
+
+#define CSI_CAMERA_NAME_MAX_LEN 32
+typedef void *csi_cam_handle_t;
+typedef void *csi_cam_event_handle_t;
+typedef struct csi_cam_handle_info {
+	int idx;
+} csi_cam_handle_info_t;
+
+#define MAX_FRAME_COUNT 1024
+typedef enum csi_frame_status_type {
+	CSI_FRAME_IDLE = 1,
+	CSI_FRAME_WORKING = 2,
+	CSI_FRAME_READY = 3,
+	CSI_FRAME_DISPATCHED = 4,
+} csi_frame_status_type_e;
+
+typedef struct frame_channel_info {
+
+	unsigned char *frame_bufs[MAX_FRAME_COUNT];
+	int frame_status[MAX_FRAME_COUNT];
+	int refcount[MAX_FRAME_COUNT];
+
+	int frame_cnt;
+	csi_frame_s frame[MAX_FRAME_COUNT];
+} frame_channel_info_s;
+
+typedef struct camera_frame_info {
+	unsigned char *frame_bufs;
+	int frame_status;
+} camera_frame_info_s;
+
+#define CSI_CAMERA_CAP_VIDEO_CAPTURE	0x00000001  /* Is a video capture device */
+#define CSI_CAMERA_CAP_META_CAPTURE	0x00800000  /* Is a metadata capture device */
+
+typedef struct csi_camera_info {
+	char camera_name[CSI_CAMERA_NAME_MAX_LEN];
+	char device_name[CSI_CAMERA_NAME_MAX_LEN];
+	char		bus_info[32];	 /* e.g. "MIPI-CSI" */
+	unsigned int	capabilities;	 /* bit mask of CSI_CAMERA_CAP_xx */
+} csi_camera_info_s;
+
+#define CSI_CAMERA_MAX_COUNT 16
+typedef struct csi_camera_infos {
+	unsigned int count;
+	csi_camera_info_s info[CSI_CAMERA_MAX_COUNT];
+} csi_camera_infos_s;
+
+#define CSI_CAMERA_MODE_MAX_COUNT 16
+typedef struct csi_camera_modes {
+	int count;
+	struct {
+		int mode_id;
+		char description[128];
+	} modes[CSI_CAMERA_MODE_MAX_COUNT];
+} csi_camera_modes_s;
+
+typedef struct csi_camera_mode_cfg {
+	int mode_id;
+	char *calibriation;	/* set NULL to use default in system  */
+	char *lib3a;		/* set NULL to use default in system  */
+} csi_camera_mode_cfg_s;
+
+typedef enum csi_camera_property_type {
+	CSI_CAMERA_PROPERTY_TYPE_INTEGER	= 1,
+	CSI_CAMERA_PROPERTY_TYPE_BOOLEAN	= 2,
+	CSI_CAMERA_PROPERTY_TYPE_ENUM		= 3,
+	CSI_CAMERA_PROPERTY_TYPE_STRING		= 7,
+	CSI_CAMERA_PROPERTY_TYPE_BITMASK	= 8,
+} csi_camera_property_type_e;
+
+typedef union csi_camera_property_data {
+	bool     bool_value;
+	int      int_value;
+	int      enum_value;
+	uint32_t bitmask_value;
+	char     str_value[32];
+} csi_camera_property_data_u;
+
+typedef struct csi_camera_property_description {
+	unsigned int 			id;		/* CSI_CAMERA_PID_xx */
+	csi_camera_property_type_e	type;		/* data type */
+	char				name[32];	/* Whatever */
+	int				minimum;	/* Note signedness */
+	int				maximum;
+	int				step;
+	csi_camera_property_data_u default_value;
+	csi_camera_property_data_u value; /*current value*/
+	unsigned int			flags;
+	unsigned int			reserved[2];
+} csi_camera_property_description_s;
+
+typedef struct csi_camera_property {
+	unsigned int	id;
+	csi_camera_property_type_e	type;		/* data type */
+	csi_camera_property_data_u value;
+} csi_camera_property_s;
+
+typedef struct csi_camera_properties {
+	unsigned int count;
+	csi_camera_property_s *property;
+} csi_camera_properties_s;
+
+typedef enum csi_camera_channel_id {
+	CSI_CAMERA_CHANNEL_0 = 0,
+	CSI_CAMERA_CHANNEL_1,
+	CSI_CAMERA_CHANNEL_2,
+	CSI_CAMERA_CHANNEL_3,
+	CSI_CAMERA_CHANNEL_4,
+	CSI_CAMERA_CHANNEL_5,
+	CSI_CAMERA_CHANNEL_6,
+	CSI_CAMERA_CHANNEL_7,
+	CSI_CAMERA_CHANNEL_MAX_COUNT
+} csi_camera_channel_id_e;
+
+typedef enum csi_camera_channel_status {
+	CSI_CAMERA_CHANNEL_INVALID = -1,	/* channel can't be openned */
+    CSI_CAMERA_CHANNEL_CLOSED,
+    CSI_CAMERA_CHANNEL_OPENED,
+	CSI_CAMERA_CHANNEL_RUNNING,
+    CSI_CAMERA_CHANNEL_EXCEPTION,
+} csi_camera_channel_status_e;
+
+typedef enum csi_camera_channel_capture_type {
+	CSI_CAMERA_CHANNEL_CAPTURE_VIDEO = (1 << 0),
+	CSI_CAMERA_CHANNEL_CAPTURE_META  = (1 << 1),
+} csi_camera_channel_capture_type_e;
+
+typedef struct csi_camera_channel_cfg {
+	csi_camera_channel_id_e 	chn_id;
+	unsigned int			capture_type;	/* bitmask of: csi_camera_channel_capture_type_e */
+	unsigned int			frm_cnt;
+	csi_img_format_t		img_fmt;
+	csi_img_type_e			img_type;
+	unsigned int			meta_fields;	/* bitmask of: csi_camera_meta_id_e */
+	csi_camera_channel_status_e	status;
+} csi_camera_channel_cfg_s;
+
+typedef enum csi_camera_event_type {
+	CSI_CAMERA_EVENT_TYPE_INVALID = -1,
+	CSI_CAMERA_EVENT_TYPE_CAMERA,
+	CSI_CAMERA_EVENT_TYPE_CHANNEL0,
+	CSI_CAMERA_EVENT_TYPE_CHANNEL1,
+	CSI_CAMERA_EVENT_TYPE_CHANNEL2,
+	CSI_CAMERA_EVENT_TYPE_CHANNEL3,
+	CSI_CAMERA_EVENT_TYPE_CHANNEL4,
+	CSI_CAMERA_EVENT_TYPE_CHANNEL5,
+	CSI_CAMERA_EVENT_TYPE_CHANNEL6,
+	CSI_CAMERA_EVENT_TYPE_CHANNEL7,
+} csi_camera_event_type_e;
+
+typedef enum csi_camera_event_id {
+	CSI_CAMERA_EVENT_WARNING                   = 1 << 0,
+	CSI_CAMERA_EVENT_ERROR                     = 1 << 1,
+	CSI_CAMERA_EVENT_SENSOR_FIRST_IMAGE_ARRIVE = 1 << 2,
+	CSI_CAMERA_EVENT_ISP_3A_ADJUST_READY       = 1 << 3,
+
+	CSI_CAMERA_EVENT_MAX_COUNT = 32
+} csi_camera_event_id_e;
+
+typedef enum csi_camera_channel_event_id {
+	CSI_CAMERA_CHANNEL_EVENT_FRAME_READY = 1 << 0,
+	CSI_CAMERA_CHANNEL_EVENT_FRAME_PUT   = 1 << 1,
+	CSI_CAMERA_CHANNEL_EVENT_OVERFLOW    = 1 << 2,
+
+	CSI_CAMERA_CHANNEL_EVENT_MAX_COUNT = 32
+} csi_camera_channel_event_id_e;
+
+typedef struct csi_camera_event_subscription {
+	csi_camera_event_type_e type;
+	unsigned int id;	/* bitmasks */
+} csi_camera_event_subscription_s;
+
+typedef struct csi_camera_event {
+	csi_camera_event_type_e	type;
+	unsigned int		id;
+	struct timespec		timestamp;
+	union {
+		char bin[128];
+	};
+} csi_camera_event_s;
+
+int csi_camera_get_version(csi_api_version_u *version);
+
+int csi_camera_query_list(csi_camera_infos_s *infos);
+int csi_camera_open(csi_cam_handle_t *cam_handle, const char *device_name);
+int csi_camera_close(csi_cam_handle_t cam_handle);
+
+int csi_camera_get_modes(csi_cam_handle_t cam_handle,
+			 csi_camera_modes_s *modes);
+
+int csi_camera_set_mode(csi_cam_handle_t cam_handle,
+			csi_camera_mode_cfg_s *cfg);
+
+int csi_camera_get_io_pattern(csi_cam_handle_t cam_handle, int *pattern);
+int csi_camera_get_frame_config(csi_cam_handle_t cam_handle, csi_img_format_t *img_fmt, csi_frame_config_s *frm_cfg);
+int csi_camera_set_frame_config(csi_cam_handle_t cam_handle, csi_img_format_t *img_fmt, csi_frame_config_s *frm_cfg);
+
+int csi_sensor_enable_colobar(csi_cam_handle_t cam_handle, int en);
+int csi_camera_query_property(csi_cam_handle_t cam_handle,
+			      csi_camera_property_description_s *desc);
+int csi_camera_get_property(csi_cam_handle_t cam_handle,
+			    csi_camera_properties_s *properties);
+int csi_camera_set_property(csi_cam_handle_t cam_handle,
+			    csi_camera_properties_s *properties);
+
+int csi_camera_channel_open(csi_cam_handle_t cam_handle,
+			    csi_camera_channel_cfg_s *cfg);
+int csi_camera_channel_close(csi_cam_handle_t cam_handle,
+			     csi_camera_channel_id_e chn_id);
+int csi_camera_channel_query(csi_cam_handle_t cam_handle,
+			     csi_camera_channel_cfg_s *cfg);
+
+int csi_camera_get_frame_count(csi_cam_handle_t cam_handle,
+			       csi_camera_channel_id_e chn_id);
+int csi_camera_get_frame(csi_cam_handle_t cam_handle,
+			 csi_camera_channel_id_e chn_id,
+			 csi_frame_s *frame, int timeout);
+
+int csi_camera_put_frame(csi_frame_s *frame);
+
+
+int csi_camera_dequeue_frame(csi_cam_handle_t cam_handle,
+			     csi_camera_channel_id_e chn_id,
+			     csi_frame_ex_s **frame,
+			     int timeout);
+
+int csi_camera_enqueue_frame(csi_cam_handle_t cam_handle,
+			     csi_camera_channel_id_e chn_id,
+			     csi_frame_ex_s *frame);
+
+
+int csi_camera_create_event(csi_cam_event_handle_t *event_handle,
+			    csi_cam_handle_t cam_handle);
+int csi_camera_destory_event(csi_cam_event_handle_t event_handle);
+
+int csi_camera_subscribe_event(csi_cam_event_handle_t event_handle,
+			       csi_camera_event_subscription_s *subscribe);
+int csi_camera_unsubscribe_event(csi_cam_event_handle_t event_handle,
+				 csi_camera_event_subscription_s *subscribe);
+int csi_camera_get_event(csi_cam_event_handle_t event_handle,
+			 csi_camera_event_s *event,
+			 int timeout);
+
+int csi_camera_channel_start(csi_cam_handle_t cam_handle,
+			     csi_camera_channel_id_e chn_id);
+int csi_camera_channel_stop(csi_cam_handle_t cam_handle,
+			    csi_camera_channel_id_e chn_id);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* __CSI_CAMERA_H__ */

+ 62 - 0
include/hal/csi_camera_frame.h

@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __CSI_CAMERA_FRAME_H__
+#define __CSI_CAMERA_FRAME_H__
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <sys/time.h>
+
+#include <csi_frame.h>
+
+#define CSI_CAMERA_META_MAX_LEN 1024
+
+typedef enum csi_camera_meta_id {
+	CSI_CAMERA_META_ID_CAMERA_NAME = (1<<0), /* str_value */
+	CSI_CAMERA_META_ID_CHANNEL_ID  = (1<<1), /* uint_value */
+	CSI_CAMERA_META_ID_FRAME_ID    = (1<<2), /* uint_value: Re-Count from zero when start() */
+	CSI_CAMERA_META_ID_TIMESTAMP   = (1<<3), /* time_value: Get from gettimeofday()  */
+	CSI_CAMERA_META_ID_HDR         = (1<<4), /* bool_value */
+} csi_camera_meta_id_e;
+
+#define CSI_CAMERA_META_NO_FIELD 0
+#define CSI_CAMERA_META_DEFAULT_FIELDS (CSI_CAMERA_META_ID_CAMERA_NAME       | \
+					CSI_CAMERA_META_ID_CHANNEL_ID        | \
+					CSI_CAMERA_META_ID_FRAME_ID          | \
+					CSI_CAMERA_META_ID_TIMESTAMP)
+
+typedef struct csi_camrea_meta_unit {
+	csi_camera_meta_id_e  id;
+	csi_meta_value_type_e type;
+	union {
+		bool		bool_value;
+		int		int_value;
+		unsigned int	uint_value;
+		char		str_value[32];
+		struct timeval  time_value;
+	};
+} csi_camrea_meta_unit_s;
+
+typedef struct csi_camera_meta {
+	unsigned int            count;
+	size_t                  size;
+	csi_camrea_meta_unit_s *units;	// Is meta_unit array head
+} csi_camera_meta_s;
+
+int csi_camera_frame_alloc_meta(csi_camera_meta_s **meta, int meta_count, size_t *meta_data_size);
+int csi_camera_frame_free_meta(csi_camera_meta_s *meta);
+
+int csi_camera_frame_get_meta_unit(csi_camrea_meta_unit_s *meta_unit,
+				   csi_camera_meta_s      *meta_data,
+				   csi_camera_meta_id_e    meta_field);
+
+
+#endif /* __CSI_CAMERA_FRAME_H__ */
+

+ 62 - 0
include/hal/csi_camera_platform_spec.h

@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __CSI_CAMERA_PLATFORM_SPEC_H__
+#define __CSI_CAMERA_PLATFORM_SPEC_H__
+#include <stdio.h>
+#include <csi_camera.h>
+
+/******************************************************************************/
+/*********** Platform Spec in Enum ********************************************/
+/******************************************************************************/
+
+#define CAMERA_PROPERTY_MAX_ENUM_COUNT 16
+
+typedef struct camera_support_enums {
+	int count;
+	int enums[CAMERA_PROPERTY_MAX_ENUM_COUNT];
+} camera_spec_enums_s;
+
+typedef enum camera_sepc_enums {
+	CAMERA_SPEC_ENUM_CHANNEL_PIX_FMT,
+	CAMERA_SPEC_ENUM_CHANNEL_IMG_TYPE,
+	CAMERA_SPEC_ENUM_CAMERA_EVENT_TYPES,
+	CAMERA_SPEC_ENUM_CHANNEL_EVENT_TYPES,
+
+	/* Camera Properties below */
+	CAMERA_SPEC_ENUM_CAMERA_EXPOSURE_MODES = CSI_CAMERA_PID_EXPOSURE_MODE,
+} camera_sepc_enums_e;
+
+const camera_spec_enums_s *camera_spec_get_enum_array(int property_id);
+
+
+/******************************************************************************/
+/*********** Platform Spec in Bitmask *****************************************/
+/******************************************************************************/
+
+#define CAMERA_PROPERTY_MAX_BITMASK_COUNT 32
+
+typedef struct camera_support_bitmasks {
+	int count;
+	int bitmask[CAMERA_PROPERTY_MAX_BITMASK_COUNT];
+} camera_spec_bitmasks_t;
+
+
+typedef enum camera_sepc_bitmasks {
+	CAMERA_SPEC_BITMAKS_CHANNEL_CAPTURE_TYPE,
+	CAMERA_SPEC_BITMAKS_CHANNEL_META_TYPE,
+
+	/* Camera Properties below */
+	CAMERA_SPEC_BITMAKS_CAMERA_3A_LOCK = CSI_CAMERA_PID_3A_LOCK,
+} camera_sepc_bitmasks_e;
+
+const camera_spec_bitmasks_t *camera_spec_get_bitmask_array(int property_id);
+
+#endif /* __CSI_CAMERA_PLATFORM_SPEC_H__ */
+

+ 93 - 0
include/hal/csi_camera_property.h

@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __CSI_CAMERA_PROPERTY_H__
+#define __CSI_CAMERA_PROPERTY_H__
+
+/* Camera Property ID */
+#define CSI_CAMERA_PID_BASE		(0x009a0000 | 0x900)
+
+#define CSI_CAMERA_FLAG_NEXT_CTRL	0x80000000
+
+/* image processing releated */
+#define CSI_CAMERA_PID_HFLIP                  (CSI_CAMERA_PID_BASE + 0x1)
+#define CSI_CAMERA_PID_VFLIP                  (CSI_CAMERA_PID_BASE + 0x2)
+#define CSI_CAMERA_PID_ROTATE                 (CSI_CAMERA_PID_BASE + 0x3)
+
+/* exposure related */
+#define CSI_CAMERA_PID_EXPOSURE_MODE          (CSI_CAMERA_PID_BASE + 0x11)
+enum CSI_CAMERA_EXPOSURE_MODE {
+	CSI_CAMERA_EXPOSURE_MODE_AUTO = 0,
+	CSI_CAMERA_EXPOSURE_MANUAL = 1,
+	CSI_CAMERA_EXPOSURE_SHUTTER_PRIORITY = 2,
+	CSI_CAMERA_EXPOSURE_APERTURE_PRIORITY = 3,
+};
+#define CSI_CAMERA_PID_EXPOSURE_ABSOLUTE      (CSI_CAMERA_PID_BASE + 0x12)
+#define CSI_CAMERA_PID_EXPOSURE_AUTO_PRIORITY (CSI_CAMERA_PID_BASE + 0x13)
+#define CSI_CAMERA_PID_EXPOSURE_BIAS          (CSI_CAMERA_PID_BASE + 0x14)
+#define CSI_CAMERA_PID_EXPOSURE_METERING      (CSI_CAMERA_PID_BASE + 0x15)
+enum CSI_CAMERA_PID_EXPOSURE_METERING_MODE {
+	CSI_CAMERA_EXPOSURE_METERING_AVERAGE = 0,
+	CSI_CAMERA_EXPOSURE_METERING_CENTER_WEIGHTED = 1,
+	CSI_CAMERA_EXPOSURE_METERING_SPOT = 2,
+	CSI_CAMERA_EXPOSURE_METERING_MATRIX = 3,
+};
+
+/* Focus related */
+#define CSI_CAMERA_PID_FOCUS_ABSOLUTE         (CSI_CAMERA_PID_BASE + 0x21)
+#define CSI_CAMERA_PID_FOCUS_RELATIVE         (CSI_CAMERA_PID_BASE + 0x22)
+#define CSI_CAMERA_PID_FOCUS_AUTO             (CSI_CAMERA_PID_BASE + 0x23)
+
+#define CSI_CAMERA_PID_AUTO_FOCUS_START       (CSI_CAMERA_PID_BASE + 0x24)
+#define CSI_CAMERA_PID_AUTO_FOCUS_STOP        (CSI_CAMERA_PID_BASE + 0x25)
+
+#define CSI_CAMERA_PID_AUTO_FOCUS_STATUS      (CSI_CAMERA_PID_BASE + 0x26)
+#define CSI_CAMERA_AUTO_FOCUS_STATUS_IDLE     (1<<0)
+#define CSI_CAMERA_AUTO_FOCUS_STATUS_BUSY     (1<<1)
+#define CSI_CAMERA_AUTO_FOCUS_STATUS_REACHED  (1<<2)
+#define CSI_CAMERA_AUTO_FOCUS_STATUS_FAILED   (1<<3)
+
+/* 3A misc */
+#define CSI_CAMERA_PID_AUTO_PRESET_WHITE_BALANCE (CSI_CAMERA_PID_BASE + 0x31)
+enum CSI_CAMERA_AUTO_PRESET_WHITE_BALANCE_MODE {
+	CSI_CAMERA_WHITE_BALANCE_MANUAL  = 0,
+	CSI_CAMERA_WHITE_BALANCE_AUTO    = 1,
+	CSI_CAMERA_WHITE_BALANCE_CUSTOM1 = 2,
+	CSI_CAMERA_WHITE_BALANCE_CUSTOM2 = 3,
+};
+
+#define CSI_CAMERA_PID_3A_LOCK             (CSI_CAMERA_PID_BASE + 0x32)
+#define CSI_CAMERA_LOCK_EXPOSURE           (1 << 0)
+#define CSI_CAMERA_LOCK_WHITE_BALANCE      (1 << 1)
+#define CSI_CAMERA_LOCK_FOCUS              (1 << 2)
+
+/* Gain */
+#define CSI_CAMERA_PID_RED_GAIN            (CSI_CAMERA_PID_BASE + 0x41)
+#define CSI_CAMERA_PID_GREEN_GAIN          (CSI_CAMERA_PID_BASE + 0x42)
+#define CSI_CAMERA_PID_BLUE_GAIN           (CSI_CAMERA_PID_BASE + 0x43)
+#define CSI_CAMERA_PID_WIDE_DYNAMIC_RANGE  (CSI_CAMERA_PID_BASE + 0x44)
+#define CSI_CAMERA_PID_ZOOM_ABSOLUTE       (CSI_CAMERA_PID_BASE + 0x45)
+#define CSI_CAMERA_PID_ZOOM_RELATIVE       (CSI_CAMERA_PID_BASE + 0x46)
+#define CSI_CAMERA_PID_ZOOM_CONTINOUS      (CSI_CAMERA_PID_BASE + 0x47)
+
+/* PAN & TILT */
+#define CSI_CAMERA_PID_PAN_RELATIVE        (CSI_CAMERA_PID_BASE + 0x51)
+#define CSI_CAMERA_PID_TILT_RELATIVE       (CSI_CAMERA_PID_BASE + 0x52)
+#define CSI_CAMERA_PID_PAN_ABSOLUTE        (CSI_CAMERA_PID_BASE + 0x53)
+#define CSI_CAMERA_PID_TILT_ABSOLUTE       (CSI_CAMERA_PID_BASE + 0x54)
+#define CSI_CAMERA_PID_PAN_RESET           (CSI_CAMERA_PID_BASE + 0x55)
+#define CSI_CAMERA_PID_TILT_RESET          (CSI_CAMERA_PID_BASE + 0x56)
+
+/* misc enhance */
+#define CSI_CAMERA_PID_HDR_MODE	           (CSI_CAMERA_PID_BASE + 0x61)
+#define CSI_CAMERA_PID_BAND_STOP_FILTER    (CSI_CAMERA_PID_BASE + 0x62)
+#define CSI_CAMERA_PID_IMAGE_STABILIZATION (CSI_CAMERA_PID_BASE + 0x63)
+
+#endif /* __CSI_CAMERA_PROPERTY_H__ */
+

+ 68 - 0
include/hal/csi_common.h

@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __CSI_COMMON_H__
+#define __CSI_COMMON_H__
+
+#include <stdint.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+
+typedef union csi_api_version {
+	struct {
+		uint16_t minor;
+		uint16_t major;
+	};
+	uint32_t version;
+} csi_api_version_u;
+
+typedef struct csi_size {
+	uint32_t	width;
+	uint32_t	height;
+} csi_size_s;
+
+typedef struct csi_rect {
+	uint32_t	pos_x;
+	uint32_t	pos_y;
+	uint32_t	width;
+	uint32_t	height;
+} csi_rect_s;
+
+
+enum {
+	CSI_IO_PATTERN_INTERNAL_MEMORY =  0x01, /* Internal preparation IO memory mode */
+	CSI_IO_PATTERN_EXTERNAL_MEMORY =  0x02  /* External preparation IO memory mode */
+};
+
+typedef enum csi_common_err_code {
+	CSI_SUCCESS,
+	CSI_ERR_BAD_PARAM,
+	CSI_ERR_NOT_SUPPORT,
+	CSI_ERR_BUSY,
+	CSI_ERR_OUT_OF_MEMORY,
+	CSI_ERR_NEED_MORE_DATA,
+	CSI_ERR_NEED_MORE_IO_FRAME,
+	CSI_ERR_TIMEOUT,
+	CSI_ERR_WAIT
+} csi_common_err_code_e;
+
+
+int32_t csi_hal_init();
+int32_t csi_hal_deinit();
+
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* __CSI_COMMON_H__ */

+ 54 - 0
include/hal/csi_fce.h

@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright(C) 2021 Alibaba Communications Inc.
+ * Author: David Li <liyong.li@alibaba-inc.com>
+ */
+
+#ifndef _FCE_HAL_H_
+#define _FCE_HAL_H_
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#include "fce_cfg.h"
+
+enum FCE_EVENT {
+    FCE_EVENT_COMPLETE = 0,
+    FCE_EVENT_PAUSE,
+    FCE_EVENT_BUSERR,
+    FCE_EVENT_TIMEOUT,
+    FCE_EVENT_UNDEFMSG,
+    FCE_EVENT_SOCKERR,
+    FCE_EVENT_OTHER
+};
+
+typedef void *csi_fce_handle_t;
+typedef void *csi_fce_sock_handle_t;
+
+int csi_fce_open(csi_fce_handle_t *fce_handle, char *name);
+int csi_fce_close(csi_fce_handle_t fce_handle);
+int csi_fce_query_result_cnt(csi_fce_handle_t fce_handle, unsigned int *cnt);
+int csi_fce_set_result_cnt(csi_fce_handle_t fce_handle, unsigned int *cnt);
+int csi_fce_set_attr(csi_fce_handle_t fce_handle, struct fce_cfg *cfg);
+int csi_fce_get_attr(csi_fce_handle_t fce_handle, struct fce_cfg *cfg);
+int csi_fce_do_compare(csi_fce_handle_t fce_handle, struct target_vector *target_vect);
+int csi_fce_get_result(csi_fce_handle_t fce_handle, struct top_result *top_buf);
+int csi_fce_suspend(csi_fce_handle_t fce_handle);
+int csi_fce_resume(csi_fce_handle_t fce_handle);
+
+unsigned long csi_fce_create_featurelib(csi_fce_handle_t fce_handle, unsigned int size);
+int csi_fce_release_featurelib(csi_fce_handle_t fce_handle, unsigned long offset);
+
+int csi_fce_config_init(struct fce_cfg *cfg);
+int csi_fce_check_result(struct top_result *res1, struct top_result *res2);
+
+int csi_fce_init_sock(csi_fce_sock_handle_t *sock_handle, unsigned long timeout_ms);
+int csi_fce_release_sock(csi_fce_sock_handle_t sock_handle);
+enum FCE_EVENT csi_fce_waitevent(csi_fce_sock_handle_t sock_handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // #ifndef _FCE_HAL_H_

+ 94 - 0
include/hal/csi_fce_cfg.h

@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright(C) 2021 Alibaba Communications Inc.
+ * Author: David Li <liyong.li@alibaba-inc.com>
+ */
+
+#ifndef FCE_CFG_H
+#define FCE_CFG_H
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+#define MAX_BASE_NUM 1000000
+#define TOPREG_CNT 8
+#define TARGET_VECTOR_CNT 64
+#define PREPRO_VECTOR_CNT 64
+#define BITS_PER_BYTE 8
+
+enum FCE_BASE_NUM {
+	BASENUM_1 = 0,
+	BASENUM_10,
+	BASENUM_1w,
+	BASENUM_5w,
+	BASENUM_10w,
+	BASENUM_20w,
+	BASENUM_50w,
+	BASENUM_100w,
+	BASENUM_MAX = BASENUM_100w,
+};
+
+enum FCE_DIMENSION {
+	DIM_128 = 0,
+	DIM_160,
+	DIM_192,
+	DIM_224,
+	DIM_256,
+	DIM_MAX = DIM_256,
+};
+
+enum FCE_INT_WIDTH {
+	INT_WIDTH_8 = 0,
+	INT_WIDTH_4,
+	INT_WIDTH_MAX = INT_WIDTH_4,
+};
+
+enum FCE_SIGN_SEL {
+	UNSIGN = 0,
+	SIGN,
+	SIGSEL_MAX = SIGN,
+};
+
+struct target_vector {
+	int value;
+};
+
+struct prepro_vector {
+	int value;
+};
+
+enum FCE_ENDIAN_SEL {
+	FCE_LIT_ENDIAN = 0,
+	FCE_BIG_ENDIAN,
+	FCE_ENDIAN_MAX = FCE_BIG_ENDIAN,
+};
+
+struct fce_cfg {
+	unsigned int base_num;	// feature num in library, < MAX_BASE_NUM
+	// comparasion start address in feature library buffer, default is 0
+	unsigned long offset_base;
+	unsigned long saddr;	// fill in kernel driver
+	enum FCE_DIMENSION dim;	// dimension
+	enum FCE_INT_WIDTH width;
+	enum FCE_SIGN_SEL sigsel;	// sign or unsign
+	unsigned int readnum;	// number of target vector, unit byte
+	// data endian format of feature library
+	enum FCE_ENDIAN_SEL base_endian;
+	// data endian format of target feature vector for comparasion
+	enum FCE_ENDIAN_SEL target_endian;
+	// data endian format of xor operation on the feature library
+	enum FCE_ENDIAN_SEL prepro_endian;
+	struct prepro_vector prepro_vect[PREPRO_VECTOR_CNT]; // xor vector
+};
+
+struct top_result {
+	int match_value;
+	unsigned int match_index;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // #ifndef FCE_CFG_H

+ 156 - 0
include/hal/csi_frame.h

@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2021 Alibaba Group Holding Limited
+ * Author: LuChongzhi <chongzhi.lcz@alibaba-inc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __CSI_FRAME_H__
+#define __CSI_FRAME_H__
+
+#include <stddef.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+/*
+ * CSI frame defination is below, including
+ *
+ *  @-- [frm_id] ----------------@
+ *  |  __________   ___________  |
+ *  | |          | |           | |
+ *  | | img_info | | meta_info | |
+ *  | |__________| |___________| |
+ *  |                            |
+ *  @------- csi_frame_s --------@
+ */
+
+#define CSI_IMAGE_MAX_PLANES	3
+#define CSI_IMAGE_I420_PLANES	2
+
+typedef enum csi_pixel_fmt {
+	CSI_PIX_FMT_I420,	// YYYYYYYY UU VV, alias: YUV420P/YU12/IYUV
+	CSI_PIX_FMT_NV12,	// YYYYYYYY UV UV, alias: YUV420SP
+	CSI_PIX_FMT_BGR,
+	CSI_PIX_FMT_RAW_8BIT,/*default no align*/
+	CSI_PIX_FMT_RAW_10BIT,
+	CSI_PIX_FMT_RAW_12BIT,
+	CSI_PIX_FMT_RAW_14BIT,
+	CSI_PIX_FMT_RAW_16BIT,
+	CSI_PIX_FMT_RGB_PLANAR_888,
+	CSI_PIX_FMT_RGB_INTEVLEAVED_888,
+	CSI_PIX_FMT_YUV_PLANAR_422,
+	CSI_PIX_FMT_YUV_PLANAR_420,
+	CSI_PIX_FMT_YUV_PLANAR_444,
+	CSI_PIX_FMT_YUV_SEMIPLANAR_422,
+	CSI_PIX_FMT_YUV_SEMIPLANAR_420,
+	CSI_PIX_FMT_YUV_SEMIPLANAR_444,
+	CSI_PIX_FMT_YUV_TEVLEAVED_422,
+	CSI_PIX_FMT_YUV_TEVLEAVED_420,
+	CSI_PIX_FMT_YUV_TEVLEAVED_444,
+} csi_pixel_fmt_e;
+
+typedef enum csi_color_gamut {
+	CSI_COLOR_GAMUT_DEFAULT = 0,
+	CSI_COLOR_GAMUT_BT601,
+	CSI_COLOR_GAMUT_BT709,
+	CSI_COLOR_GAMUT_BT2020,
+} csi_color_gamut_e;
+
+typedef enum csi_meta_type {
+	CSI_META_TYPE_SYSTEM,
+	CSI_META_TYPE_CAMERA,
+	CSI_META_TYPE_VDEC,
+	CSI_META_TYPE_GPU,
+	CSI_META_TYPE_G2D,
+} csi_meta_type_e;
+
+typedef enum csi_img_type {
+	CSI_IMG_TYPE_DMA_BUF,		// memory allocated via dma-buf
+	CSI_IMG_TYPE_SYSTEM_CONTIG,	// memory allocated via kmalloc
+	CSI_IMG_TYPE_CARVEOUT,		// memory allocated from reserved memory
+	CSI_IMG_TYPE_UMALLOC,		// memory allocated from user mode malloc
+	CSI_IMG_TYPE_SHM,		// memory allocated from share memory(<sys/shm.h>)
+} csi_img_type_e;
+
+typedef enum csi_meta_value_type {
+	CSI_META_VALUE_TYPE_BOOL,
+	CSI_META_VALUE_TYPE_INT,
+	CSI_META_VALUE_TYPE_UINT,
+	CSI_META_VALUE_TYPE_STR,
+	CSI_META_VALUE_TYPE_TIMEVAL,
+} csi_meta_value_type_e;
+
+
+/*
+ * CSI frame config design
+ *
+ *     line_stride -->|
+ *   img_width -->|   |
+ *   _____________|___| __ start addr of frame/image, alignment (such as 4096)
+ *  |             |   |
+ *  | img_content |   |
+ *  |_____________|___| __ end addr of image, No alignment requirement
+ *  | extra_data      |
+ *  |_________________| __ end addr of frame, No alignment requirement
+ */
+
+typedef struct csi_img_format {
+	uint32_t	width;
+	uint32_t	height;
+	csi_pixel_fmt_e	pix_fmt;
+} csi_img_format_t;
+
+
+typedef struct {
+    int32_t stride_alignment;	// should >= to the width of the image according to IP design
+    int32_t addr_alignment;	// physical begin address alignment according to IP design
+    int32_t extra_size;	    // storaging platform private data according to IP design (meta data storage is suggested)
+    int32_t min_buffers_count;  // minimum number of buffers required
+} csi_frame_config_s;       // New defined structure
+
+typedef struct {
+    int fds;  	// stores in dma_buf memory(s)
+    unsigned long offset;
+} cam_frame_dmabuf_t;
+
+typedef struct csi_img {
+	csi_img_type_e	type;
+	size_t		size;
+	uint32_t	width;
+	uint32_t	height;
+	csi_pixel_fmt_e	pix_format;
+	csi_color_gamut_e color_gamut;
+	uint32_t	num_planes;
+	union {
+        cam_frame_dmabuf_t dmabuf[CSI_IMAGE_MAX_PLANES];		// stores in dma_buf memory(s)
+        int fds[CSI_IMAGE_MAX_PLANES];		// stores in dma_buf memory(s)
+		void  *phy_addr[CSI_IMAGE_MAX_PLANES];	// stores in phy contigous memory(s)
+		void  *usr_addr[CSI_IMAGE_MAX_PLANES];	// stores in usr contigous memory(s)
+	};
+	uint32_t strides[CSI_IMAGE_MAX_PLANES];
+	uint32_t offsets[CSI_IMAGE_MAX_PLANES];
+	uint64_t modifier;
+    void *priv;
+} csi_img_s;
+
+typedef struct csi_meta {
+	csi_meta_type_e  type;
+	size_t           size;
+	void            *data;
+} csi_meta_s;
+
+typedef struct csi_frame {
+	csi_img_s  img;
+	csi_meta_s meta;
+} csi_frame_s;
+
+
+int   csi_frame_reference(csi_frame_s *frame_dest, csi_frame_s *frame_src);
+int   csi_frame_release(csi_frame_s *frame);
+void *csi_frame_mmap(csi_frame_s *frame);
+int   csi_frame_munmap(csi_frame_s *frame);
+
+#endif /* __CSI_FRAME_H__ */

+ 176 - 0
include/hal/csi_frame_ex.h

@@ -0,0 +1,176 @@
+/**
+* Copyright (C) 2021 Alibaba Group Holding Limited
+**/
+#ifndef _CSI_FRAME_EX_H
+#define _CSI_FRAME_EX_H
+
+#include <csi_common.h>
+
+#define MAX_PLANE_COUNT  3
+
+typedef enum {
+	CSI_PIXEL_FORMAT_RGB_444 = 0,
+	CSI_PIXEL_FORMAT_RGB_555,
+	CSI_PIXEL_FORMAT_RGB_565,
+	CSI_PIXEL_FORMAT_RGB_888,
+
+	CSI_PIXEL_FORMAT_BGR_444,
+	CSI_PIXEL_FORMAT_BGR_555,
+	CSI_PIXEL_FORMAT_BGR_565,
+	CSI_PIXEL_FORMAT_BGR_888,
+
+	CSI_PIXEL_FORMAT_ARGB_1555,
+	CSI_PIXEL_FORMAT_ARGB_4444,
+	CSI_PIXEL_FORMAT_ARGB_8565,
+	CSI_PIXEL_FORMAT_ARGB_8888,
+	CSI_PIXEL_FORMAT_ARGB_2BPP,
+
+	CSI_PIXEL_FORMAT_ABGR_1555,
+	CSI_PIXEL_FORMAT_ABGR_4444,
+	CSI_PIXEL_FORMAT_ABGR_8565,
+	CSI_PIXEL_FORMAT_ABGR_8888,
+
+	CSI_PIXEL_FORMAT_RGB_BAYER_8BPP,
+	CSI_PIXEL_FORMAT_RGB_BAYER_10BPP,
+	CSI_PIXEL_FORMAT_RGB_BAYER_12BPP,
+	CSI_PIXEL_FORMAT_RGB_BAYER_14BPP,
+	CSI_PIXEL_FORMAT_RGB_BAYER_16BPP,
+
+	CSI_PIXEL_FORMAT_YVU_PLANAR_422,
+	CSI_PIXEL_FORMAT_YVU_PLANAR_420,
+	CSI_PIXEL_FORMAT_YVU_PLANAR_444,
+
+	CSI_PIXEL_FORMAT_YVU_SEMIPLANAR_422,
+	CSI_PIXEL_FORMAT_YVU_SEMIPLANAR_420,
+	CSI_PIXEL_FORMAT_YVU_SEMIPLANAR_444,
+
+	CSI_PIXEL_FORMAT_YUV_SEMIPLANAR_422,
+	CSI_PIXEL_FORMAT_YUV_SEMIPLANAR_420,
+	CSI_PIXEL_FORMAT_YUV_SEMIPLANAR_444,
+
+	CSI_PIXEL_FORMAT_YUYV_PACKAGE_422,
+	CSI_PIXEL_FORMAT_YVYU_PACKAGE_422,
+	CSI_PIXEL_FORMAT_UYVY_PACKAGE_422,
+	CSI_PIXEL_FORMAT_VYUY_PACKAGE_422,
+	CSI_PIXEL_FORMAT_YYUV_PACKAGE_422,
+	CSI_PIXEL_FORMAT_YYVU_PACKAGE_422,
+	CSI_PIXEL_FORMAT_UVYY_PACKAGE_422,
+	CSI_PIXEL_FORMAT_VUYY_PACKAGE_422,
+	CSI_PIXEL_FORMAT_VY1UY0_PACKAGE_422,
+
+	CSI_PIXEL_FORMAT_YUV_400,
+	CSI_PIXEL_FORMAT_UV_420,
+
+	CSI_PIXEL_FORMAT_MAX
+} csi_pixel_format_e;
+
+#if 0
+typedef enum {
+	CSI_PICTURE_TYPE_NONE = 0, /* undefined */
+	CSI_PICTURE_TYPE_I,        /* intra */
+	CSI_PICTURE_TYPE_P,        /* predicted */
+	CSI_PICTURE_TYPE_B,        /* BI-dir predictd */
+	CSI_PICTURE_TYPE_S,        /* S(GMC)-VOP MPEG-4 */
+	CSI_PICTURE_TYPE_SI,       /* Switching intra */
+	CSI_PICTURE_TYPE_SP,       /* Switching Predicted */
+	CSI_PICTURE_TYPE_BI,       /* BI Type */
+} csi_picture_type_e;
+#endif
+
+
+typedef enum {
+	CSI_CHROMA_LOCATION_LEFT,
+	CSI_CHROMA_LOCATION_CENTER,
+	CSI_CHROMA_LOCATION_TOPLEFT,
+	CSI_CHROMA_LOCATION_TOP,
+	CSI_CHROMA_LOCATION_BOTTOMLEFT,
+	CSI_CHROMA_LOCATION_BOTTOM,
+	CSI_CHROMA_LOCATION_DV420
+} csi_chroma_location_e;
+
+#if 0
+typedef enum {
+	CSI_FRAME_COMPRESS_MODE_NONE = 0, /* no compress */
+	CSI_FRAME_COMPRESS_MODE_SEQ,      /* compress unit is 256x1 bytes as a segment. */
+	CSI_FRAME_COMPRESS_MODE_TILE,     /* compress unit is a tile. */
+	CSI_FRAME_COMPRESS_MODE_LINE,     /* compress unit is the whole line.  raw for VI */
+	CSI_FRAME_COMPRESS_MODE_FRAME,    /* compress unit is the whole frame. YUV for VI(3DNR), RGB for TDE(write)/VO(read) */
+	CSI_FRAME_COMPRESS_MAX
+} csi_frame_compress_mode;
+#endif
+
+typedef enum {
+	CSI_COLORSPACE_ACES,   /* RGB color space ACES standardized as SMPTE ST 2065-1:2012. */
+	CSI_COLORSPACE_ACESCG, /* RGB color space ACEScg standardized as Academy S-2014-004. */
+	CSI_COLORSPACE_RGB,    /* RGB color space Adobe RGB (1998). */
+	CSI_COLORSPACE_BT2020, /* RGB color space BT.2020 standardized as Rec. */
+	CSI_COLORSPACE_BT709,   /* RGB color space BT.709 standardized as Rec. */
+	CSI_COLORSPACE_CIE_LAB, /* Lab color space CIE L*a*b*. */
+	CSI_COLORSPACE_CIE_XYZ, /* XYZ color space CIE XYZ.  */
+	CSI_COLORSPACE_DCI_P3,  /* RGB color space DCI-P3 standardized as SMPTE RP 431-2-2007. */
+	CSI_COLORSPACE_DISPLAY_p3, /* RGB color space Display P3 based on SMPTE RP 431-2-2007 and IEC 61966-2.1:1999.  */
+	CSI_COLORSPACE_EXTENDED_SRGB, /* RGB color space scRGB-nl standardized as IEC 61966-2-2:2003. */
+	CSI_COLORSPACE_LINEAR_EXTENDED_SRGB, /* RGB color space scRGB standardized as IEC 61966-2-2:2003.  */
+	CSI_COLORSPACE_LINEAR_SRGB, /* RGB color space sRGB standardized as IEC 61966-2.1:1999.  */
+	CSI_COLORSPACE_NTSC_1953, /* RGB color space NTSC, 1953 standard.  */
+	CSI_COLORSPACE_PRO_PHOTO_RGB, /* RGB color space NTSC, 1953 standard. */
+	CSI_COLORSPACE_SMPTE_C, /* RGB color space SMPTE C.  */
+	CSI_COLORSPACE_SRGB  /* RGB color space sRGB standardized as IEC 61966-2.1:1999.  */
+} csi_color_space_e;
+
+typedef enum {
+	CSI_VIDEO_FORMAT_UNDEFINED,
+	CSI_VIDEO_FORMAT_COMPONENT,
+	CSI_VIDEO_FORMAT_PAL,
+	CSI_VIDEO_FORMAT_NTSC,
+	CSI_VIDEO_FORMAT_SECAM,
+	CSI_VIDEO_FORMAT_MAC
+} csi_video_format_e;
+
+
+typedef struct csi_frame_info {
+	int32_t width;
+	int32_t height;
+	/* the region of interest of the frame */
+	//csi_rect_s roi;
+	csi_pixel_format_e pixel_format;
+	//csi_frame_compress_mode compress_mode;
+	csi_color_space_e  color_space;
+	csi_chroma_location_e chroma_location;
+} csi_frame_info_s;
+
+typedef struct csi_frame_data {
+	int64_t pts;
+	int64_t dts;
+	int64_t frame_num;
+	int8_t is_key_frame;
+	int8_t is_eos; /* last frame */
+
+	int32_t offset[MAX_PLANE_COUNT];
+	int32_t stride[MAX_PLANE_COUNT];
+	int32_t num_plane;
+
+	void *vir_addr[MAX_PLANE_COUNT];
+	union {
+		int fd[MAX_PLANE_COUNT];  /* -1 means invalid */
+		int64_t phy_addr[MAX_PLANE_COUNT]; /* 0 means invalid */
+	};
+} csi_frame_data_s;
+
+
+typedef struct csi_frame_ex {
+	csi_frame_info_s frame_info;
+	csi_frame_data_s frame_data;
+	void *opaque; /* not for user, DO NOT use or modify it */
+} csi_frame_ex_s;
+
+#if 0
+typedef struct csi_bitstream {
+	void *buf;
+	uint32_t len;
+	uint8_t is_eos;   //is the end of stream
+	uint8_t is_frame; //is whole compress frame data
+} csi_bitstream_s;
+#endif
+
+#endif

+ 204 - 0
include/hal/csi_g2d.h

@@ -0,0 +1,204 @@
+#ifndef __CSI_G2D_H__
+#define __CSI_G2D_H__
+
+#include <csi_g2d_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _g2d_surface;
+typedef struct _g2d_surface g2d_surface;
+
+struct _g2d_context;
+typedef struct _g2d_context g2d_context;
+
+typedef enum _csi_g2d_tiling {
+    CSI_G2D_LINEAR,
+} csi_g2d_tiling;
+
+typedef enum _csi_g2d_rotation {
+    CSI_G2D_ROTATION_0_DEGREE,
+    CSI_G2D_ROTATION_90_DEGREE,
+    CSI_G2D_ROTATION_180_DEGREE,
+    CSI_G2D_ROTATION_270_DEGREE,
+    CSI_G2D_ROTATION_FLIP_X = 0x10000000,
+    CSI_G2D_ROTATION_FLIP_Y = 0x20000000,
+} csi_g2d_rotation;
+
+/* TODO: maximum 16 different modes */
+typedef enum _csi_g2d_blend_mode {
+    CSI_G2D_BLEND_MODE_CLEAR,
+    CSI_G2D_BLEND_MODE_SRC,
+    CSI_G2D_BLEND_MODE_DST,
+    CSI_G2D_BLEND_MODE_SRC_OVER,
+    CSI_G2D_BLEND_MODE_DST_OVER,
+    CSI_G2D_BLEND_MODE_SRC_IN,
+    CSI_G2D_BLEND_MODE_DST_IN,
+    CSI_G2D_BLEND_MODE_SRC_OUT,
+    CSI_G2D_BLEND_MODE_DST_OUT,
+    CSI_G2D_BLEND_MODE_SRC_ATOP,
+    CSI_G2D_BLEND_MODE_DST_ATOP,
+    CSI_G2D_BLEND_MODE_ADD,
+    CSI_G2D_BLEND_MODE_XOR,
+} csi_g2d_blend_mode;
+
+typedef enum _csi_g2d_alpha_mode {
+    CSI_G2D_ALPHA_MODE_STRAIGHT,
+    CSI_G2D_ALPHA_MODE_INVERSED
+} csi_g2d_alpha_mode;
+
+typedef enum _csi_g2d_global_alpha_mode {
+    CSI_G2D_GLOBAL_ALPHA_MODE_OFF,
+    CSI_G2D_GLOBAL_ALPHA_MODE_ON,
+    CSI_G2D_GLOBAL_ALPHA_MODE_SCALE
+} csi_g2d_global_alpha_mode;
+
+typedef enum _csi_g2d_global_multiply_mode {
+    CSI_G2D_GLOBAL_COLOR_MULTIPLY_DISABLE,
+    CSI_G2D_GLOBAL_COLOR_MULTIPLY_ALPHA,
+    CSI_G2D_GLOBAL_COLOR_MULTIPLY_COLOR
+} csi_g2d_global_multiply_mode;
+
+typedef enum _csi_g2d_yuv_mode {
+    CSI_G2D_YUV_MODE_BT601,
+    CSI_G2D_YUV_MODE_BT709,
+    CSI_G2D_YUV_MODE_BT2020,
+    CSI_G2D_YUV_MODE_USER_DEFINED,
+    CSI_G2D_YUV_MODE_USER_DEFINED_CLAMP,
+    CSI_G2D_YUV_MODE_NUM,
+} csi_g2d_yuv_mode;
+
+typedef enum _csi_g2d_filter_tap {
+    CSI_G2D_FILTER_TAP_1,
+    CSI_G2D_FILTER_TAP_3,
+    CSI_G2D_FILTER_TAP_5
+} csi_g2d_filter_tap;
+
+typedef struct _csi_g2d_point {
+    int x;
+    int y;
+} csi_g2d_point;
+
+typedef struct _csi_g2d_line {
+    csi_g2d_point start;
+    csi_g2d_point end;
+} csi_g2d_line;
+
+typedef struct _csi_g2d_triangle {
+    csi_g2d_line line[3];
+} csi_g2d_triangle;
+
+typedef struct _csi_g2d_rectangle {
+    csi_g2d_line line[4];
+} csi_g2d_rectangle;
+
+typedef struct _csi_g2d_region {
+    unsigned int left;
+    unsigned int top;
+    unsigned int right;
+    unsigned int bottom;
+} csi_g2d_region;
+
+typedef struct _csi_g2d_surface {
+    g2d_surface *priv;	/* point to g2d_surface */
+    int width;		/* in pixels */
+    int height;		/* in pixels */
+    int cpp[3];		/* bytes per pixel (per plane) */
+    int stride[3];	/* in bytes  */
+    int nplanes;	/* planes number */
+    int alignment;	/* in pixels */
+    unsigned int format; /* in fourcc */
+    csi_g2d_tiling tiling;
+    void *lgcaddr[3];
+    unsigned int flags;
+} csi_g2d_surface;
+
+int csi_g2d_open(void);
+int csi_g2d_close(void);
+int csi_g2d_flush(void);
+
+/* csi_g2d_surface APIs */
+int csi_g2d_surface_create(csi_g2d_surface *csi_surface);
+int csi_g2d_surface_destroy(csi_g2d_surface *csi_surface);
+int csi_g2d_surface_select_source(unsigned int id);
+int csi_g2d_surface_set_source(csi_g2d_surface *surface);
+int csi_g2d_surface_set_target(csi_g2d_surface *surface);
+int csi_g2d_surface_set_source_clipping(csi_g2d_region *region);
+int csi_g2d_surface_set_target_clipping(csi_g2d_region *region);
+int csi_g2d_surface_set_source_yuv_mode(csi_g2d_yuv_mode yuv_mode);
+int csi_g2d_surface_set_target_yuv_mode(csi_g2d_yuv_mode yuv_mode);
+
+int csi_g2d_surface_set_source_alpha_mode(
+	csi_g2d_alpha_mode alpha_mode,
+	csi_g2d_blend_mode blend_mode
+);
+int csi_g2d_surface_set_source_global_alpha_mode(
+	csi_g2d_global_alpha_mode global_mode,
+	unsigned int global_color
+);
+int csi_g2d_surface_set_source_multiply_mode(
+	bool multiply,
+	csi_g2d_global_multiply_mode global_mode
+);
+
+int csi_g2d_surface_set_target_alpha_mode(
+	csi_g2d_alpha_mode alpha_mode,
+	csi_g2d_blend_mode blend_mode
+);
+int csi_g2d_surface_set_target_global_alpha_mode(
+	csi_g2d_global_alpha_mode global_mode,
+	unsigned int global_color
+);
+int csi_g2d_surface_set_target_multiply_mode(
+	bool multiply,
+	bool demultiply
+);
+
+int csi_g2d_surface_enable_disable_alpha_blend(bool enable);
+
+/* csi_g2d_brush APIs */
+int csi_g2d_brush_create(unsigned int argb_color, bool convert);
+int csi_g2d_brush_destroy(void);
+
+int csi_g2d_palette_load(unsigned int *table,
+			 unsigned int count,
+			 bool convert);
+
+/* csi_g2d_line APIs: draw line(s) in target */
+int csi_g2d_line_draw_line(csi_g2d_line *lines, int nlines);
+int csi_g2d_line_draw_triangle(csi_g2d_triangle *triangles,
+			       int ntriangles);
+int csi_g2d_line_draw_rectangle(csi_g2d_rectangle *rectangles,
+				int nrectangles);
+
+/* blit properties config APIs */
+int csi_g2d_blit_set_rotation(csi_g2d_rotation rotation);
+int csi_g2d_blit_set_mirror(bool hmirror, bool vmirror);
+int csi_g2d_blit_set_filter_tap(csi_g2d_filter_tap htap,
+				csi_g2d_filter_tap vtap);
+
+/* clear target: clear color should be ARGB8888 */
+int csi_g2d_fill(csi_g2d_region *regions,
+		 int nregions,
+		 unsigned int argb_color);
+
+/* blit without resize, support alpha blending */
+int csi_g2d_blit_bitblit(csi_g2d_region *target_regions, int nregions);
+
+/* scaling up or down APIs */
+int csi_g2d_blit_stretchblit(csi_g2d_region *target_regions, int nregions);
+int csi_g2d_blit_filterblit(csi_g2d_region *target_regions, int nregions);
+
+/* multisrc blit API */
+int csi_g2d_blit_multisrc_blit(
+	unsigned int src_mask,
+	csi_g2d_region *target_regions,
+	int nregions
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

Some files were not shown because too many files changed in this diff