Browse Source

Linux_SDK_V1.0.3

thead_admin 1 year ago
parent
commit
3d0966dbf7

+ 27 - 0
.gitignore

@@ -1,2 +1,29 @@
+/.auto.deps
+/.config.cmd
+/.config.old
+/..config.tmp
+/.config
 /.vscode
+*.tmp
+*.depend
+*.o
+*.a
+*.o.d
+*.o.cmd
+*.a.cmd
+*.ko.cmd
+*.ko
+*.mod
+*.mod.c
+*.mod.cmd
+*.order
+*.orig
+*.symvers.cmd
+*.order.cmd
+test/ivs_test
+user_mode/libivs.so
+Module.symvers
+out/
 output/
+obj/
+dependencies/

+ 106 - 33
Makefile

@@ -1,47 +1,120 @@
+##
+ # Copyright (C) 2020 Alibaba Group Holding Limited
+##
 ifneq ($(wildcard ../.param),)
-	include ../.param
+  include ../.param
 endif
 
-INC_PATH ?= /usr/include
-LIB_PATH ?= /usr/lib
+#CONFIG_DEBUG_MODE=1
+CONFIG_OUT_ENV=hwlinux
 
-OUTPUTDIR = ./output
-LIBNAME = $(OUTPUTDIR)/libplink.so
-server_NAME = $(OUTPUTDIR)/plinkserver
-client_NAME = $(OUTPUTDIR)/plinkclient
-stitcher_NAME = $(OUTPUTDIR)/plinkstitcher
+CONFIG_BUILD_DRV_EXTRA_PARAM:=""    	
+CONFIG_BUILD_LIB_EXTRA_PARAM:=""
+CONFIG_BUILD_TST_EXTRA_PARAM:=""	
 
-INCS = ./inc
-LIBSRCS = ./src/process_linker.c
-LIBOBJS = $(LIBSRCS:.c=.o)
-server_SRCS = ./test/plink_server.c
-server_OBJS = $(server_SRCS:.c=.o)
-client_SRCS = ./test/plink_client.c
-client_OBJS = $(client_SRCS:.c=.o)
-stitcher_SRCS = ./test/plink_stitcher.c
-stitcher_OBJS = $(stitcher_SRCS:.c=.o)
+DIR_TARGET_BASE=bsp/ivs		
+DIR_TARGET_LIB =bsp/ivs/lib
+DIR_TARGET_KO  =bsp/ivs/ko
+DIR_TARGET_TEST=bsp/ivs/test
 
-CFLAGS = -I$(INCS) -I$(INC_PATH)/vidmem
-CFLAGS += -pthread -fPIC -O
+MODULE_NAME=IVS
+BUILD_LOG_START="\033[47;30m>>> $(MODULE_NAME) $@ begin\033[0m"
+BUILD_LOG_END  ="\033[47;30m<<< $(MODULE_NAME) $@ end\033[0m"
 
-$(shell if [ ! -e $(OUTPUTDIR) ];then mkdir -p $(OUTPUTDIR); fi)
+#
+# Do a parallel build with multiple jobs, based on the number of CPUs online
+# in this system: 'make -j8' on a 8-CPU system, etc.
+#
+# (To override it, run 'make JOBS=1' and similar.)
+#
 
-all: lib server client stitcher
+ifeq ($(JOBS),)
+  JOBS := $(shell grep -c ^processor /proc/cpuinfo 2>/dev/null)
+  ifeq ($(JOBS),)
+    JOBS := 1
+  endif
+endif
+
+all:    info driver lib test install_local_output install_rootfs
+.PHONY: info driver lib test install_local_output install_rootfs \
+        install_prepare install_addons clean_driver clean_lib clean_test clean_output clean
+
+info:
+	@echo $(BUILD_LOG_START)
+	@echo "  ====== Build Info from repo project ======"
+	@echo "    BUILDROOT_DIR="$(BUILDROOT_DIR)
+	@echo "    CROSS_COMPILE="$(CROSS_COMPILE)
+	@echo "    LINUX_DIR="$(LINUX_DIR)
+	@echo "    ARCH="$(ARCH)
+	@echo "    BOARD_NAME="$(BOARD_NAME)
+	@echo "    KERNEL_ID="$(KERNELVERSION)
+	@echo "    KERNEL_DIR="$(LINUX_DIR)
+	@echo "    INSTALL_DIR_ROOTFS="$(INSTALL_DIR_ROOTFS)
+	@echo "    INSTALL_DIR_SDK="$(INSTALL_DIR_SDK)
+	@echo "  ====== Build configuration by settings ======"
+#	@echo "    CONFIG_DEBUG_MODE="$(CONFIG_DEBUG_MODE)
+	@echo "    CONFIG_OUT_ENV="$(CONFIG_OUT_ENV)
+	@echo "    JOBS="$(JOBS)
+	@echo $(BUILD_LOG_END)
+
+driver:
+	@echo $(BUILD_LOG_START)
+	make -C $(LINUX_DIR) M=$(PWD)/kernel_mode ARCH=$(ARCH) modules
+	@echo $(BUILD_LOG_END)
+
+clean_driver:
+	@echo $(BUILD_LOG_START)
+	make -C kernel_mode KDIR=$(LINUX_DIR) clean
+	@echo $(BUILD_LOG_END)
+
+lib:
+	@echo $(BUILD_LOG_START)
+	make -w -C user_mode hwlinux
+	@echo $(BUILD_LOG_END)
+
+clean_lib:
+	@echo $(BUILD_LOG_START)
+	make clean -C user_mode
+	@echo $(BUILD_LOG_END)
+
+test: lib driver
+	@echo $(BUILD_LOG_START)
+	make -w -C test hwlinux
+	@echo $(BUILD_LOG_END)
+
+clean_test:
+	@echo $(BUILD_LOG_START)
+	make clean -C test
+	@echo $(BUILD_LOG_END)
+
+install_prepare:
+	mkdir -p ./output/rootfs/$(DIR_TARGET_KO)
+	mkdir -p ./output/rootfs/$(DIR_TARGET_LIB)
+	mkdir -p ./output/rootfs/$(DIR_TARGET_TEST)
 
-lib: 
-	$(CC) $(LIBSRCS) $(CFLAGS) -shared -o $(LIBNAME)
+install_addons: install_prepare
+	@echo $(BUILD_LOG_START)
+	@echo $(BUILD_LOG_END)
 
-server: lib
-	$(CC) $(server_SRCS) $(CFLAGS) -L$(OUTPUTDIR) -L$(LIB_PATH)/vidmem -lplink -lvmem -ldl -pthread -o $(server_NAME)
+install_local_output: driver lib test install_addons
+	@echo $(BUILD_LOG_START)
+	find ./kernel_mode -name "*.ko" | xargs -i cp -f {} ./output/rootfs/$(DIR_TARGET_KO)
+	find ./user_mode -name "*.so" | xargs -i cp -f {} ./output/rootfs/$(DIR_TARGET_LIB)
+	find ./user_mode -name "*.a" | xargs -i cp -f {} ./output/rootfs/$(DIR_TARGET_LIB)
+	cp -f ./test/ivs_test ./output/rootfs/$(DIR_TARGET_TEST)
+	@if [ `command -v tree` != "" ]; then \
+	    tree ./output/rootfs;             \
+	fi
+	@echo $(BUILD_LOG_END)
 
-client: lib
-	$(CC) $(client_SRCS) $(CFLAGS) -L$(OUTPUTDIR) -L$(LIB_PATH)/vidmem -lplink -lvmem -ldl -pthread -o $(client_NAME)
+install_rootfs: install_local_output
+	@echo $(BUILD_LOG_START)
+	@echo $(BUILD_LOG_END)
 
-stitcher: lib
-	$(CC) $(stitcher_SRCS) $(CFLAGS) -L$(OUTPUTDIR) -L$(LIB_PATH)/vidmem -lplink -lvmem -ldl -pthread -o $(stitcher_NAME)
+clean_output:
+	@echo $(BUILD_LOG_START)
+	rm -rf ./output
+	@echo $(BUILD_LOG_END)
 
-clean:
-	rm -rf $(OUTPUTDIR)
+clean: clean_output clean_driver clean_lib clean_test
 
-%.o : %.c
-	$(CC) $(CFLAGS) -c $< -o $@

+ 12 - 57
README.md

@@ -1,57 +1,12 @@
-# Process Linker Repository
-This git module contains a linker library which can be used to connect two process for data sharing and passing file descriptor.
-
-- **src**: c source code of process linker library.
-- **inc**: public header files of process linker library. User should include these files to use process linker.
-- **test**: sample applications. Two sample applications, server and client, are implimented for test and reference purpose.
-
-## How to build
-Just run `make` and binaries will be generated in **output** folder.
-
-## How to use
-- **libplink.so**: shared library of process link. See API doc for more details of usage.
-- **plinkserver**: sample server application
-```shell
-usage: ./plinkserver [options]
-
-  Available options:
-    -l      plink file name (default: /tmp/plink.test)
-    -i      input YUV file name (mandatory)
-    -f      input color format (default: 3)
-                2 - I420
-                3 - NV12
-                4 - P010
-                14 - Bayer Raw 10bit
-                15 - Bayer Raw 12bit
-    -w      video width (mandatory)
-    -h      video height (mandatory)
-    -s      video buffer stride in bytes (default: video width)
-    -n      number of frames to send (default: 10)
-```
-- **plinkclient**: sample client application
-```shell
-./plinkclient [frames] [plink server name] [dump file name]
-```
-
-- **plinkstitcher**: sample implementation of stitching filter, which can stitch up to 4 source videos (NV12 or RAW) into one as NV12 output
-
-```
-usage: ./plinkstitcher [options]
-
-  Stitch multiple pictures to one. Maximum # of pictures to be stitched is 4
-  Available options:
-    -i<n>   plink file name of input port #n (default: /tmp/plink.stitch.in<n>). n is 0 based.
-    -o      plink file name of output port (default: /tmp/plink.stitch.out)
-    -l      layout (default: 0)
-                0 - vertical
-                1 - horizontal
-                2 - matrix
-    -f      output color format (default: 3)
-                3 - NV12
-    -w      output video width (default: 800)
-    -h      output video height (default: 1280)
-    -s      output video buffer stride (default: video width)
-    --help  print this message
-```
-
-Please note the sample applications have dependency on **video-memory** module for memory allocating and dma-buf operations. 
+# How to build
+- Just run 'make' to build kernel mode driver, user mode driver and test application.
+
+Find all the binaries in following folders:
+- output/rootfs/bsp/ivs/ko: kernel mode driver
+- output/rootfs/bsp/ivs/lib: user mode driver static linked library and dynamic linked library
+- output/rootfs/bsp/ivs/test: test application
+
+# Description of each directories
+- kernel_mode: kernel mode driver source
+- user_mode: user mode driver source
+- test: test application source

BIN
doc/pics/comm.PNG


BIN
doc/pics/packet.PNG


BIN
doc/pics/plink-sw-stack.PNG


BIN
doc/pics/thead-logo-eng-white-wide.png


File diff suppressed because it is too large
+ 0 - 23
doc/plink-api.md


+ 0 - 225
inc/process_linker.h

@@ -1,225 +0,0 @@
-/*
- * Copyright (c) 2021-2022 Alibaba Group. All rights reserved.
- * License-Identifier: Apache-2.0
- *
- * 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 _PROCESS_LINKER_H_
-#define _PROCESS_LINKER_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define PLINK_VERSION_MAJOR     0
-#define PLINK_VERSION_MINOR     1
-#define PLINK_VERSION_REVISION  1
-
-/* Maximum data descriptors in one packet */
-#define PLINK_MAX_DATA_DESCS 10
-
-/* Close all the connections from client. */
-/* Can be used as the second parameter of PLINK_close when the instance is created as SERVER */
-#define PLINK_CLOSE_ALL -1
-
-/* invalid file descriptor */
-#define PLINK_INVALID_FD -1
-
-#define DATA_HEADER_SIZE (sizeof(PlinkDescHdr))
-#define DATA_SIZE(type) (sizeof(type) - DATA_HEADER_SIZE)
-
-typedef void *PlinkHandle;
-typedef void PlinkDescriptor;
-typedef int PlinkChannelID;
-
-typedef enum _PlinkStatus
-{
-    PLINK_STATUS_OK = 0,
-    PLINK_STATUS_MORE_DATA = 1,     /* have more data to parse in the receive buffer */
-    PLINK_STATUS_TIMEOUT = 2,       /* wait timeout, which means no data received within the time */
-    PLINK_STATUS_NO_DATA = 3,       /* no data recieved */
-    PLINK_STATUS_ERROR = -1,        /* general error */
-    PLINK_STATUS_WRONG_PARAMS = -2, /* wrong parameters */
-    PLINK_STATUS_NO_MEMORY = -3,    /* not enough memory */
-} PlinkStatus;
-
-/* plink mode */
-typedef enum _PlinkMode
-{
-    PLINK_MODE_SERVER = 0,      /* run plink as server; server should be launched before client */
-    PLINK_MODE_CLIENT,          /* run plink as client which can connect to server */
-    PLINK_MODE_MAX
-} PlinkMode;
-
-typedef union _PlinkVersion
-{
-    struct process_linker
-    {
-        unsigned char major;
-        unsigned char minor;
-        unsigned char revision;
-        unsigned char step;
-    } v;
-    unsigned int version;
-} PlinkVersion;
-
-typedef struct _PlinkDescHdr
-{
-    unsigned int size;      /* data size, excluding this header */
-    int type;               /* type of this data descriptor */
-    int id;                 /* buffer id if it's buffer descriptor. Only values greater than 0 are valid */
-} PlinkDescHdr;
-
-/* data packet can be sent/received in one send/recv call */
-typedef struct _PlinkPacket
-{
-    int fd;                                         /* file descriptor. If PLINK_INVALID_FD, it's invalid */
-    unsigned int timestamp;                         /* timestamp of this packet, the time for rendering */
-    int num;                                        /* number of valid data descriptor entries in list[] */
-    PlinkDescriptor *list[PLINK_MAX_DATA_DESCS];    /* list of pointers which point to data descriptor. */
-} PlinkPacket;
-
-/**
- * \brief Create a plink instance.
- *
- * Create a plink object with the specified name as server or client.
- * When mode is PLINK_MODE_SERVER, a file of the specified name will be created.
- *
- * \param plink Point to the pointer of plink instance.
- * \param name Socket file name.
- * \param mode plink mode, server or client.
- * \return PLINK_STATUS_OK successful, 
- * \return other unsuccessful.
- */
-PlinkStatus PLINK_getVersion(PlinkVersion *version);
-
-/**
- * \brief Create a plink instance.
- *
- * Create a plink object with the specified name as server or client.
- * When mode is PLINK_MODE_SERVER, a file of the specified name will be created.
- *
- * \param plink Point to the pointer of plink instance.
- * \param name Socket file name.
- * \param mode plink mode, server or client.
- * \return PLINK_STATUS_OK successful, 
- * \return other unsuccessful.
- */
-PlinkStatus PLINK_create(PlinkHandle *plink, const char *name, PlinkMode mode);
-
-/**
- * \brief Create a connection between server and client
- *
- * Server calls this function to wait for connection and accept.
- * Client calls this function to connect to server.
- *
- * \param plink Pointer of plink instance.
- * \param channel id of the new connection. Valid for server only. Should be 0 for client
- * \return PLINK_STATUS_OK successful, 
- * \return other unsuccessful.
- */
-PlinkStatus PLINK_connect(PlinkHandle plink, PlinkChannelID *channel);
-
-/**
- * \brief Create a connection between server and client with timeout
- *
- * Server calls this function to wait for connection and accept with timeout.
- * Client calls this function to connect to server with timeout.
- *
- * \param plink Pointer of plink instance.
- * \param channel id of the new connection. Valid for server only. Should be 0 for client
- * \param timeout_ms timeout in unit of milliseconds.
- * \return PLINK_STATUS_OK successful, 
- * \return PLINK_STATUS_TIMEOUT if no data received within timeout_ms, 
- * \return other unsuccessful.
- */
-PlinkStatus PLINK_connect_ex(PlinkHandle plink, PlinkChannelID *channel, int timeout_ms);
-
-/**
- * \brief Send a packet
- *
- * Send a packet through the channel.
- *
- * \param plink Pointer of plink instance.
- * \param channel The channel to send this packet. Valid for server only. Should be 0 for client
- * \param pkt Point to the packet to be sent.
- * \return PLINK_STATUS_OK successful, 
- * \return other unsuccessful.
- */
-PlinkStatus PLINK_send(PlinkHandle plink, PlinkChannelID channel, PlinkPacket *pkt);
-
-/**
- * \brief Wait for data from channel
- *
- * This function returns once there is data received from the channel.
- *
- * \param plink Pointer of plink instance.
- * \param channel The channel to receive data. Valid for server only. Should be 0 for client
- * \param timeout_ms timeout in unit of milliseconds.
- * \return PLINK_STATUS_OK successful, 
- * \return PLINK_STATUS_TIMEOUT if no data received within timeout_ms, 
- * \return other unsuccessful.
- */
-PlinkStatus PLINK_wait(PlinkHandle plink, PlinkChannelID channel, int timeout_ms);
-
-/**
- * \brief Receive data
- *
- * Receive data from the channel.
- * Data descriptors of the packet are stored in the internal buffer, 
- * and may be overwritten in the next PLINK_recv call. 
- *
- * \param plink Pointer of plink instance.
- * \param channel The channel to receive data. Valid for server only. Should be 0 for client
- * \param pkt Point to the received packet.
- * \return PLINK_STATUS_OK successful, 
- * \return other unsuccessful.
- */
-PlinkStatus PLINK_recv(PlinkHandle plink, PlinkChannelID channel, PlinkPacket *pkt);
-
-/**
- * \brief Receive data with timeout
- *
- * Receive data from the channel with timeout.
- * Data descriptors of the packet are stored in the internal buffer, 
- * and may be overwritten in the next PLINK_recv call. 
- *
- * \param plink Pointer of plink instance.
- * \param channel The channel to receive data. Valid for server only. Should be 0 for client
- * \param pkt Point to the received packet.
- * \param timeout_ms timeout in unit of milliseconds.
- * \return PLINK_STATUS_OK successful, 
- * \return PLINK_STATUS_TIMEOUT if no data received within timeout_ms, 
- * \return other unsuccessful.
- */
-PlinkStatus PLINK_recv_ex(PlinkHandle plink, PlinkChannelID channel, PlinkPacket *pkt, int timeout_ms);
-
-/**
- * \brief Close connections
- *
- * Close connections. Server can set channel to PLINK_CLOSE_ALL to close all connections.
- *
- * \param plink Pointer of plink instance.
- * \param channel The connection to be closed. Valid for server only. Should be 0 for client
- * \return PLINK_STATUS_OK successful, 
- * \return other unsuccessful.
- */
-PlinkStatus PLINK_close(PlinkHandle plink, PlinkChannelID channel);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* !_PROCESS_LINKER_H_ */

+ 0 - 196
inc/process_linker_types.h

@@ -1,196 +0,0 @@
-/*
- * Copyright (c) 2021-2022 Alibaba Group. All rights reserved.
- * License-Identifier: Apache-2.0
- *
- * 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 _PROCESS_LINKER_TYPES_H_
-#define _PROCESS_LINKER_TYPES_H_
-
-#include "process_linker.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* When set PlinkMsg.msg to this exit code, it means to close the connection */
-#define PLINK_EXIT_CODE -1
-
-/* image/video color format */
-typedef enum _PlinkColorFormat
-{
-    PLINK_COLOR_FormatUnused,
-    PLINK_COLOR_FormatMonochrome,
-    PLINK_COLOR_FormatYUV420Planar,
-    PLINK_COLOR_FormatYUV420SemiPlanar,
-    PLINK_COLOR_FormatYUV420SemiPlanarP010,
-    PLINK_COLOR_FormatYUV422Planar,
-    PLINK_COLOR_FormatYUV422SemiPlanar,
-    PLINK_COLOR_Format32bitBGRA8888,
-    PLINK_COLOR_Format32bitARGB8888,
-    PLINK_COLOR_Format24BitRGB888,
-    PLINK_COLOR_Format24BitRGB888Planar,
-    PLINK_COLOR_Format24BitBGR888,
-    PLINK_COLOR_Format24BitBGR888Planar,
-    PLINK_COLOR_FormatRawBayer8bit,
-    PLINK_COLOR_FormatRawBayer10bit,
-    PLINK_COLOR_FormatRawBayer12bit,
-    PLINK_COLOR_FormatMax
-} PlinkColorFormat;
-
-typedef enum _PlinkBayerPattern
-{
-    PLINK_BAYER_PATTERN_RGGB,
-    PLINK_BAYER_PATTERN_BGGR,
-    PLINK_BAYER_PATTERN_GRBG,
-    PLINK_BAYER_PATTERN_GBRG,
-    PLINK_BAYER_PATTERN_MAX
-} PlinkBayerPattern;
-
-/* Data descriptor type */
-typedef enum _PlinkDescType
-{
-    PLINK_TYPE_1D_BUFFER = 0,   /* PlinkBufferInfo */
-    PLINK_TYPE_2D_YUV,          /* PlinkYuvInfo */
-    PLINK_TYPE_2D_RGB,          /* PlinkRGBInfo */
-    PLINK_TYPE_OBJECT,          /* PlinkObjectInfo */
-    PLINK_TYPE_MESSAGE,         /* PlinkMsg */
-    PLINK_TYPE_TIME,            /* PlinkTimeInfo */
-    PLINK_TYPE_2D_RAW,          /* PlinkRawInfo */
-    PLINK_TYPE_MAX
-} PlinkDescType;
-
-/* time type */
-typedef enum _PlinkTimeType
-{
-    PLINK_TIME_START = 0,       /* start time */
-    PLINK_TIME_CALIBRATION,     /* time delta for calibration */
-    PLINK_TIME_MAX
-} PlinkTimeType;
-
-/* 1D buffer */
-typedef struct _PlinkBufferInfo
-{
-    PlinkDescHdr header;
-    unsigned long long bus_address;
-    unsigned int offset;
-    unsigned int size;
-} PlinkBufferInfo;
-
-/* 2D YUV surface */
-typedef struct _PlinkYuvInfo
-{
-    PlinkDescHdr header;
-    PlinkColorFormat format;
-    unsigned long long bus_address_y;
-    unsigned long long bus_address_u;
-    unsigned long long bus_address_v;
-    unsigned int offset_y;
-    unsigned int offset_u;
-    unsigned int offset_v;
-    unsigned int pic_width;
-    unsigned int pic_height;
-    unsigned int stride_y;
-    unsigned int stride_u;
-    unsigned int stride_v;
-} PlinkYuvInfo;
-
-/* 2D RGB surface */
-typedef struct _PlinkRGBInfo
-{
-    PlinkDescHdr header;
-    PlinkColorFormat format;
-    unsigned long long bus_address_r;
-    unsigned long long bus_address_g;
-    unsigned long long bus_address_b;
-    unsigned long long bus_address_a;
-    unsigned int offset_r;
-    unsigned int offset_g;
-    unsigned int offset_b;
-    unsigned int offset_a;
-    unsigned int img_width;
-    unsigned int img_height;
-    unsigned int stride_r;
-    unsigned int stride_g;
-    unsigned int stride_b;
-    unsigned int stride_a;
-} PlinkRGBInfo;
-
-/* 2D Bayer Raw surface */
-typedef struct _PlinkRawInfo
-{
-    PlinkDescHdr header;
-    PlinkColorFormat format;
-    PlinkBayerPattern pattern;
-    unsigned long long bus_address;
-    unsigned int offset;
-    unsigned int img_width;
-    unsigned int img_height;
-    unsigned int stride;
-} PlinkRawInfo;
-
-/* Feature map buffer after NPU inference */
-typedef struct _PlinkBox
-{
-    float x1;
-    float y1;
-    float x2;
-    float y2;
-} PlinkBox;
-
-typedef struct _PlinkLandmark
-{
-    float x[5];
-    float y[5];
-} PlinkLandmark;
-
-typedef struct _PlinkObjectDetect
-{
-    float score;
-    PlinkBox box;
-    PlinkLandmark landmark;
-} PlinkObjectDetect;
-
-typedef struct _PlinkObjectInfo
-{
-    PlinkDescHdr header;
-    unsigned long long bus_address;
-    unsigned int object_cnt;
-} PlinkObjectInfo;
-
-/* Used to send message */
-typedef struct _PlinkMsg
-{
-    PlinkDescHdr header;
-    int msg;                /* When greater than 0, it means the id of buffer which can be released */
-                            /* When set to 0, it means a buffer can be released, but id is unknown */
-                            /* When set to PLINK_EXIT_CODE, it means to close connection */
-                            /* Other values are reserved */
-} PlinkMsg;
-
-/* time information */
-typedef struct _PlinkTimeInfo
-{
-    PlinkDescHdr header;
-    PlinkTimeType type;
-    long long seconds;
-    long long useconds;
-} PlinkTimeInfo;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* !_PROCESS_LINKER_TYPES_H_ */

+ 6 - 0
kernel_mode/Makefile

@@ -0,0 +1,6 @@
+shake-objs := isp_venc_shake_driver.o
+obj-m         += shake.o
+
+clean:
+	rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.ur-safe .cache.mk
+	rm -rf modules.order Module.symvers

+ 439 - 0
kernel_mode/isp_venc_shake_driver.c

@@ -0,0 +1,439 @@
+/*
+ * Copyright (C) 2021 - 2022  Alibaba Group. All rights reserved.
+ * 
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+#include <asm/io.h>
+#include <linux/cdev.h>
+#include <linux/pci.h>
+#include <linux/uaccess.h>
+#include <linux/ioport.h>
+#include <asm/irq.h>
+#include <linux/version.h>
+#include <linux/vmalloc.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include "isp_venc_shake_driver.h"
+
+#define IVS_SWREG_AMOUNT 27
+
+typedef struct _theadivs_dev
+{
+	struct cdev cdev;
+	dev_t devt;
+	struct class *class;
+    unsigned long base_addr;
+    u32 iosize;
+    volatile u8 *hwregs;
+    int irq;
+    int state;
+} theadivs_dev;
+
+static int theadivs_major = 0;  /* dynamic */
+static int theadivs_minor = 0;
+static theadivs_dev* theadivs_data = NULL;
+static unsigned int device_register_index = 0;
+struct class *theadivs_class;
+
+static irqreturn_t theadivs_isr(int irq, void *dev_id);
+
+static void print_registers(void)
+{
+    printk("pic_width = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x00)));
+    printk("pic_height = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x04)));
+    printk("encode_width = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x08)));
+    printk("encode_height = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x0c)));
+    printk("wid_y = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x10)));
+    printk("wid_uv = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x14)));
+    printk("sram_size = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x18)));
+    printk("encode_n = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x1c)));
+    printk("stride_y = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x20)));
+    printk("stride_uv = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x24)));
+    printk("encode_x = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x2c)));
+    printk("encode_y = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x30)));
+    printk("int_state = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x38)));
+    printk("int_mask = %d\n", ioread32((void*)(theadivs_data->hwregs + 0x40)));
+}
+
+static int config_ivs(struct file *filp, struct ivs_parameter *params)
+{
+    iowrite32(params->pic_width, (void*)(theadivs_data->hwregs + 0x00));
+    iowrite32(params->pic_height, (void*)(theadivs_data->hwregs + 0x04));
+    iowrite32(params->encode_width, (void*)(theadivs_data->hwregs + 0x08));
+    iowrite32(params->encode_height, (void*)(theadivs_data->hwregs + 0x0c));
+    iowrite32(params->wid_y, (void*)(theadivs_data->hwregs + 0x10));
+    iowrite32(params->wid_uv, (void*)(theadivs_data->hwregs + 0x14));
+    iowrite32(params->sram_size, (void*)(theadivs_data->hwregs + 0x18));
+    iowrite32(params->encode_n, (void*)(theadivs_data->hwregs + 0x1c));
+    iowrite32(params->stride_y, (void*)(theadivs_data->hwregs + 0x20));
+    iowrite32(params->stride_uv, (void*)(theadivs_data->hwregs + 0x24));
+    iowrite32(1, (void*)(theadivs_data->hwregs + 0x28)); // CLEAR
+    iowrite32(params->encode_x, (void*)(theadivs_data->hwregs + 0x2c));
+    iowrite32(params->encode_y, (void*)(theadivs_data->hwregs + 0x30));
+    iowrite32(0, (void*)(theadivs_data->hwregs + 0x34)); // START
+    iowrite32(0, (void*)(theadivs_data->hwregs + 0x3c)); // INT_CLEAN
+    iowrite32(params->int_mask, (void*)(theadivs_data->hwregs + 0x40));
+
+    return 0;
+}
+
+static long theadivs_ioctl(struct file *filp,
+                          unsigned int cmd, unsigned long arg)
+{
+    int err = 0;
+
+    if (_IOC_TYPE(cmd) != THEAD_IOC_MAGIC)
+        return -ENOTTY;
+    else if (_IOC_NR(cmd) > THEAD_IOC_MAXNR)
+        return -ENOTTY;
+
+    if (_IOC_DIR(cmd) & _IOC_READ)
+        err = !access_ok((void *) arg, _IOC_SIZE(cmd));
+    else if (_IOC_DIR(cmd) & _IOC_WRITE)
+        err = !access_ok((void *) arg, _IOC_SIZE(cmd));
+    if (err)
+        return -EFAULT;
+
+    switch (cmd)
+    {
+    case THEAD_IOCH_CONFIG_IVS:
+    {
+        struct ivs_parameter params;
+        printk("%s: THEAD_IOCH_CONFIG_IVS\n", __func__);
+        err = copy_from_user(&params, (struct ivs_parameter*)arg, sizeof(struct ivs_parameter));
+        config_ivs(filp, &params);
+        print_registers();
+        theadivs_data->state = THEADIVS_READY;
+        break;
+    }
+    case THEAD_IOCH_START_IVS:
+    {
+        printk("%s: THEAD_IOCH_START_IVS\n", __func__);
+        iowrite32(1, theadivs_data->hwregs + 0x34); // START
+        print_registers();
+        theadivs_data->state = THEADIVS_RUNNING;
+        break;
+    }
+    case THEAD_IOCH_RESET_IVS:
+    {
+        printk("%s: THEAD_IOCH_RESET_IVS\n", __func__);
+        iowrite32(1, theadivs_data->hwregs + 0x40); // INT_MASK
+        iowrite32(1, theadivs_data->hwregs + 0x28); // CLEAR
+        iowrite32(0, theadivs_data->hwregs + 0x40); // INT_MASK
+        print_registers();
+        theadivs_data->state = THEADIVS_IDLE;
+        break;
+    }
+    case THEAD_IOCH_GET_STATE:
+    {
+        printk("%s: THEAD_IOCH_GET_STATE: %d\n", __func__, theadivs_data->state);
+        err = copy_to_user((int *)arg, &theadivs_data->state, sizeof(int));
+        break;
+    }
+    default:
+    {
+        printk("%s: undefined command: 0x%x\n", __func__, cmd);
+    }
+    }
+    return 0;
+}
+
+static int theadivs_open(struct inode *inode, struct file *filp)
+{
+    int result = 0;
+    //theadivs_dev *dev = theadivs_data;
+    //filp->private_data = (void *) dev;
+
+    return result;
+}
+static int theadivs_release(struct inode *inode, struct file *filp)
+{
+    //theadivs_dev *dev = (theadivs_dev *) filp->private_data;
+
+    return 0;
+}
+
+static struct file_operations theadivs_fops = {
+    .owner= THIS_MODULE,
+    .open = theadivs_open,
+    .release = theadivs_release,
+    .unlocked_ioctl = theadivs_ioctl,
+    .fasync = NULL,
+};
+
+static const struct of_device_id thead_of_match[] = {
+        { .compatible = "thead,light-ivs",  },
+        { /* sentinel */  },
+};
+
+static int theadivs_reserve_IO(void)
+{
+    if(!request_mem_region
+        (theadivs_data->base_addr, theadivs_data->iosize, "shake"))
+    {
+        printk(KERN_INFO "theadivs: failed to reserve HW regs\n");
+        printk(KERN_INFO "theadivs: base_addr = 0x%08lx, iosize = %d\n",
+                          theadivs_data->base_addr,
+                          theadivs_data->iosize);
+        return -1;
+    }
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(4,17,0))
+    theadivs_data->hwregs =
+        (volatile u8 *) ioremap_nocache(theadivs_data->base_addr,
+                                        theadivs_data->iosize);
+#else
+    theadivs_data->hwregs =
+        (volatile u8 *) ioremap(theadivs_data->base_addr,
+                                        theadivs_data->iosize);
+#endif
+
+    if (theadivs_data->hwregs == NULL)
+    {
+        printk(KERN_INFO "theadivs: failed to ioremap HW regs\n");
+        release_mem_region(theadivs_data->base_addr, theadivs_data->iosize);
+        return -1;
+    }
+
+    printk("theadivs: mapped from 0x%lx to %p with size %d\n", 
+        theadivs_data->base_addr, theadivs_data->hwregs, theadivs_data->iosize);
+
+    return 0;
+}
+
+static void theadivs_release_IO(void)
+{
+    if(theadivs_data->hwregs)
+    {
+        iounmap((void *) theadivs_data->hwregs);
+        release_mem_region(theadivs_data->base_addr, theadivs_data->iosize);
+        theadivs_data->hwregs = NULL;
+    }
+}
+
+int __init theadivs_probe(struct platform_device *pdev)
+{
+    int result = -1;
+    struct resource *mem;
+    printk("enter %s\n",__func__);
+
+    theadivs_data = (theadivs_dev *)vmalloc(sizeof(theadivs_dev));
+    if (theadivs_data == NULL)
+        return result;
+    memset(theadivs_data, 0, sizeof(theadivs_dev));
+
+    mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+    if(mem->start)
+        theadivs_data->base_addr = mem->start; 
+    theadivs_data->irq = platform_get_irq(pdev, 0);
+    printk("%s:get irq %d\n", __func__, theadivs_data->irq);
+    theadivs_data->iosize = IVS_SWREG_AMOUNT * 4;
+#if 1
+	if (device_register_index == 0)
+	{
+		if (theadivs_major == 0)
+		{
+			result = alloc_chrdev_region(&theadivs_data->devt, 0, 1, "shake");
+			if (result != 0)
+			{
+				printk("%s:alloc_chrdev_region error\n", __func__);
+				goto err1;
+			}
+			theadivs_major = MAJOR(theadivs_data->devt);
+			theadivs_minor = MINOR(theadivs_data->devt);
+		}
+		else
+		{
+			theadivs_data->devt = MKDEV(theadivs_major, theadivs_minor);
+			result = register_chrdev_region(theadivs_data->devt, 1, "shake");
+			if (result)
+			{
+				printk("%s:register_chrdev_region error\n", __func__);
+				goto err1;
+			}
+		}
+
+		theadivs_class = class_create(THIS_MODULE, "shake");
+		if (IS_ERR(theadivs_class))
+		{
+			printk("%s[%d]:class_create error!\n", __func__, __LINE__);
+			goto err;
+		}
+	}
+	theadivs_data->devt = MKDEV(theadivs_major, theadivs_minor + pdev->id);
+
+	cdev_init(&theadivs_data->cdev, &theadivs_fops);
+	result = cdev_add(&theadivs_data->cdev, theadivs_data->devt, 1);
+	if ( result )
+	{
+		printk("%s[%d]:cdev_add error!\n", __func__, __LINE__);
+		goto err;
+	}
+	theadivs_data->class = theadivs_class;
+	device_create(theadivs_data->class, NULL, theadivs_data->devt,
+			theadivs_data, "shake");
+
+	device_register_index++;
+#else
+    result = register_chrdev(theadivs_major, "shake", &theadivs_fops);
+    if (result < 0)
+    {
+        printk(KERN_INFO "theadivs_driver: unable to get major <%d>\n",
+              theadivs_major);
+        goto err1;
+    }
+    else if (result != 0)    /* this is for dynamic major */
+    {
+        theadivs_major = result;
+    }
+#endif
+
+    theadivs_reserve_IO();
+
+    /* get the IRQ line */
+    if (theadivs_data->irq!= -1)
+    {
+        result = request_irq(theadivs_data->irq, theadivs_isr,
+                              IRQF_SHARED,
+                              "shake", (void *)theadivs_data);
+        if (result == -EINVAL)
+        {
+            printk(KERN_ERR "theadivs_driver: Bad irq number or handler.\n");
+            theadivs_release_IO();
+            goto err;
+        }
+        else if (result == -EBUSY)
+        {
+            printk(KERN_ERR "theadivs_driver: IRQ <%d> busy, change your config.\n",
+                    theadivs_data->irq);
+            theadivs_release_IO();
+            goto err;
+        }
+    }
+    else
+    {
+        printk(KERN_INFO "theadivs_driver: IRQ not in use!\n");
+    }
+
+    printk(KERN_INFO "theadivs_driver: module inserted. Major <%d>\n", theadivs_major);
+
+    return 0;
+err:
+    //unregister_chrdev(theadivs_major, "shake");
+    unregister_chrdev_region(theadivs_data->devt, 1);
+err1:
+    if (theadivs_data != NULL)
+        vfree(theadivs_data);
+    printk(KERN_INFO "theadivs_driver: module not inserted\n");
+    return result;
+}
+
+static int theadivs_remove(struct platform_device *pdev)
+{
+    free_irq(theadivs_data->irq, theadivs_data);
+    theadivs_release_IO();
+    //unregister_chrdev(theadivs_major, "shake");
+    device_register_index--;
+	cdev_del(&theadivs_data->cdev);
+	device_destroy(theadivs_data->class, theadivs_data->devt);
+    unregister_chrdev_region(theadivs_data->devt, 1);
+	if (device_register_index == 0)
+	{
+		class_destroy(theadivs_data->class);
+	}
+    if (theadivs_data != NULL)
+        vfree(theadivs_data);
+
+    printk(KERN_INFO "theadivs_driver: module removed\n");
+    return 0;
+}
+
+
+static struct platform_driver theadivs_driver = {
+    .probe = theadivs_probe,
+    .remove = theadivs_remove,
+    .driver = {
+        .name = "shake",
+        .owner = THIS_MODULE,
+        .of_match_table = of_match_ptr(thead_of_match),
+    }
+};
+
+
+int __init theadivs_init(void)
+{
+    int ret = 0;
+    printk("enter %s\n",__func__);
+#if 1
+    ret = platform_driver_register(&theadivs_driver);
+    if (ret)
+    {
+        pr_err("register platform driver failed!\n");
+    }
+#endif
+    return ret;
+}
+
+void __exit theadivs_cleanup(void)
+{
+    printk("enter %s\n",__func__);
+    platform_driver_unregister(&theadivs_driver);
+    return;
+}
+
+static irqreturn_t theadivs_isr(int irq, void *dev_id)
+{
+    theadivs_dev *dev = (theadivs_dev *) dev_id;
+    u32 irq_status = 0;
+
+    printk( "theadivs_isr: received IRQ!\n");
+    irq_status = (u32)ioread32((void*)dev->hwregs + 0x38); // INT_STATE
+    printk( "INT_STATE of is: 0x%x\n", irq_status);
+    theadivs_data->state = THEADIVS_ERROR;
+
+    iowrite32(1, theadivs_data->hwregs + 0x40); // INT_MASK
+    iowrite32(1, theadivs_data->hwregs + 0x3c); // INT_CLEAN
+    iowrite32(1, theadivs_data->hwregs + 0x28); // CLEAR
+    iowrite32(0, theadivs_data->hwregs + 0x40); // INT_MASK
+
+    return IRQ_HANDLED;
+}
+
+
+module_init(theadivs_init);
+module_exit(theadivs_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("T-HEAD");
+MODULE_DESCRIPTION("T-HEAD ISP-VENC-SHAKE driver");
+

+ 71 - 0
kernel_mode/isp_venc_shake_driver.h

@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2021 - 2022  Alibaba Group. All rights reserved.
+ * 
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _ISP_VENC_SHAKE_DRIVER_H_
+#define _ISP_VENC_SHAKE_DRIVER_H_
+#include <linux/ioctl.h>
+
+#define THEAD_IOC_MAGIC  't'
+
+#define THEAD_IOCH_CONFIG_IVS    _IOR(THEAD_IOC_MAGIC, 3, unsigned long *)
+#define THEAD_IOCH_START_IVS    _IOR(THEAD_IOC_MAGIC, 4, unsigned long *)
+#define THEAD_IOCH_RESET_IVS    _IOR(THEAD_IOC_MAGIC, 5, unsigned long *)
+#define THEAD_IOCH_GET_STATE    _IOR(THEAD_IOC_MAGIC, 6, int *)
+
+#define THEAD_IOC_MAXNR 6
+
+typedef int8_t    i8;
+typedef uint8_t   u8;
+typedef int16_t   i16;
+typedef uint16_t  u16;
+typedef int32_t   i32;
+typedef uint32_t  u32;
+typedef int64_t   i64;
+typedef uint64_t  u64;
+
+typedef enum _theadivs_state
+{
+    THEADIVS_IDLE,
+    THEADIVS_READY,
+    THEADIVS_RUNNING,
+    THEADIVS_ERROR
+} theadivs_state;
+
+struct ivs_parameter
+{
+  u32 pic_width;
+  u32 pic_height;
+  u32 encode_width;
+  u32 encode_height;
+  u32 wid_y;
+  u32 wid_uv;
+  u32 sram_size;
+  u32 encode_n;
+  u32 stride_y;
+  u32 stride_uv;
+  //u32 clear;
+  u32 encode_x;
+  u32 encode_y;
+  //u32 start;
+  //u32 int_state;
+  //u32 int_clean;
+  u32 int_mask;
+  //u32 signal_resv;
+};
+
+#endif /* !_ISP_VENC_SHAKE_DRIVER_H_ */

+ 0 - 552
src/process_linker.c

@@ -1,552 +0,0 @@
-/*
- * Copyright (c) 2021-2022 Alibaba Group. All rights reserved.
- * License-Identifier: Apache-2.0
- *
- * 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.
- *
- */
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdint.h>
-#include "process_linker.h"
-
-#ifndef NULL
-#define NULL    ((void *)0)
-#endif
-
-#define MAX_CONNECTIONS 3
-#define MAX_BUFFER_SIZE (4 * 1024 * 1024)
-
-#define PLINK_PRINT(level, ...) \
-    { \
-        if (log_level >= PLINK_LOG_##level) \
-        { \
-            struct timeval ts; \
-            gettimeofday(&ts, 0); \
-            printf("PLINK[%d][%ld.%06ld] %s: ", pid, ts.tv_sec, ts.tv_usec, #level); \
-            printf(__VA_ARGS__); \
-        } \
-    }
-
-#define PLINK_PRINT_RETURN(retcode, level, ...) \
-    { \
-        PLINK_PRINT(level, __VA_ARGS__) \
-        return retcode; \
-    }
-
-typedef enum _PlinkLogLevel
-{
-    PLINK_LOG_QUIET = 0,
-    PLINK_LOG_ERROR,
-    PLINK_LOG_WARNING,
-    PLINK_LOG_INFO,
-    PLINK_LOG_DEBUG,
-    PLINK_LOG_TRACE,
-    PLINK_LOG_MAX
-} PlinkLogLevel;
-
-typedef struct _PlinkContext
-{
-    PlinkMode mode;
-    struct sockaddr_un addr;
-    struct iovec ioIn[PLINK_MAX_DATA_DESCS];
-    struct iovec ioOut[PLINK_MAX_DATA_DESCS];
-    int sockfd;
-    int cfd[MAX_CONNECTIONS];
-    int connect[MAX_CONNECTIONS];
-    int count; // connected client number
-    char *buffer;
-    int offset;
-    int pid;
-} PlinkContext;
-
-int log_level = PLINK_LOG_ERROR;
-int pid = 0;
-
-static PlinkStatus parseData(PlinkContext *ctx, PlinkPacket *pkt, int total);
-static PlinkStatus wait(int sockfd, int timeout_ms);
-static int getLogLevel();
-
-PlinkStatus
-PLINK_getVersion(PlinkVersion *version)
-{
-    if (version != NULL)
-    {
-        version->v.major = PLINK_VERSION_MAJOR;
-        version->v.minor = PLINK_VERSION_MINOR;
-        version->v.revision = PLINK_VERSION_REVISION;
-        version->v.step = 0;
-        return PLINK_STATUS_OK;
-    }
-    else
-        return PLINK_STATUS_ERROR;
-}
-
-PlinkStatus 
-PLINK_create(PlinkHandle *plink, const char *name, PlinkMode mode)
-{
-    PlinkContext *ctx = NULL;
-    int sockfd;
-
-    log_level = getLogLevel();
-    pid = getpid();
-
-    if (plink == NULL || name == NULL)
-        PLINK_PRINT_RETURN(PLINK_STATUS_WRONG_PARAMS, ERROR,
-            "Wrong parameters: plink = %p, name = %s\n", plink, name);
-
-    ctx = (PlinkContext *)malloc(sizeof(*ctx));
-    if (NULL == ctx)
-        PLINK_PRINT_RETURN(PLINK_STATUS_NO_MEMORY, ERROR,
-            "Failed to allocate memory for plink\n");
-    memset(ctx, 0, sizeof(*ctx));
-    *plink = (PlinkHandle)ctx;
-
-    sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
-    if (-1 == sockfd)
-        PLINK_PRINT_RETURN(PLINK_STATUS_ERROR, ERROR,
-            "Failed to create socket as AF_UNIX, SOCK_STREAM\n");
-
-    ctx->sockfd = sockfd;
-    ctx->mode = mode;
-    ctx->addr.sun_family = AF_UNIX;
-    strncpy(ctx->addr.sun_path, name, sizeof(ctx->addr.sun_path) - 1);
-
-    if (mode == PLINK_MODE_SERVER)
-    {
-        if (unlink (name) == -1 && errno != ENOENT)
-            PLINK_PRINT_RETURN(PLINK_STATUS_ERROR, ERROR,
-                "Failed to unlink %s\n", name);
-
-        if (bind(sockfd, (struct sockaddr *)&ctx->addr, sizeof(struct sockaddr_un)) == -1)
-            PLINK_PRINT_RETURN(PLINK_STATUS_ERROR, ERROR,
-                "Failed to bind to AF_UNIX address: %s\n", ctx->addr.sun_path);
-
-        if (listen(sockfd, MAX_CONNECTIONS) == -1)
-            PLINK_PRINT_RETURN(PLINK_STATUS_ERROR, ERROR,
-                "Failed to listen for connection request\n");
-    }
-
-    ctx->buffer = malloc(MAX_BUFFER_SIZE);
-    if (ctx->buffer == NULL)
-        PLINK_PRINT_RETURN(PLINK_STATUS_NO_MEMORY, ERROR,
-            "Failed to allocate memory for internal buffer\n");
-
-    ctx->pid = getpid();
-
-    return PLINK_STATUS_OK;
-}
-
-PlinkStatus 
-PLINK_connect(PlinkHandle plink, PlinkChannelID *channel)
-{
-    PlinkContext *ctx = (PlinkContext *)plink;
-
-    if (ctx == NULL)
-        PLINK_PRINT_RETURN(PLINK_STATUS_WRONG_PARAMS, ERROR,
-            "Wrong parameters: plink = %p\n", plink);
-
-    if (ctx->mode == PLINK_MODE_SERVER)
-    {
-        if (channel == NULL)
-            PLINK_PRINT_RETURN(PLINK_STATUS_WRONG_PARAMS, ERROR,
-                "Wrong parameters: channel = %p\n", channel);
-
-        if (ctx->count >= MAX_CONNECTIONS)
-            PLINK_PRINT_RETURN(PLINK_STATUS_ERROR, ERROR,
-               "Too many connections %d while it is limited to %d\n", ctx->count, MAX_CONNECTIONS);
-
-        // find available slot
-        int i;
-        for (i = 0; i < MAX_CONNECTIONS; i++)
-        {
-            if (ctx->connect[i] == 0)
-            {
-                ctx->connect[i] = 1;
-                *channel = i;
-                break;
-            }
-        }
-
-        // wait for connection from client
-        PLINK_PRINT(INFO, "Waiting for connection...\n");
-        int fd = accept(ctx->sockfd, NULL, NULL);
-        if (fd == -1)
-            PLINK_PRINT_RETURN(PLINK_STATUS_ERROR, ERROR,
-               "Failed to accept connection\n");
-
-        ctx->cfd[i] = fd;
-        ctx->count++;
-        PLINK_PRINT(INFO, "Accepted connection request from client %d (%d/%d): %d\n", 
-                i, ctx->count, MAX_CONNECTIONS, fd);
-    }
-    else
-    {
-        if (connect(ctx->sockfd, (struct sockaddr *)&ctx->addr, sizeof(struct sockaddr_un)) == -1)
-            PLINK_PRINT_RETURN(PLINK_STATUS_ERROR, ERROR,
-               "Failed to connect to server %s: %s\n", ctx->addr.sun_path, strerror(errno));
-
-        PLINK_PRINT(INFO, "Connected to server: %d\n", ctx->sockfd);
-    }
-
-    return PLINK_STATUS_OK;
-}
-
-PlinkStatus 
-PLINK_send(PlinkHandle plink, PlinkChannelID channel, PlinkPacket *pkt)
-{
-    PlinkContext *ctx = (PlinkContext *)plink;
-
-    if (ctx == NULL || pkt == NULL)
-        PLINK_PRINT_RETURN(PLINK_STATUS_WRONG_PARAMS, ERROR,
-            "Wrong parameters: plink = %p, pkt = %p\n", plink, pkt);
-
-    if (pkt->num > PLINK_MAX_DATA_DESCS)
-        PLINK_PRINT_RETURN(PLINK_STATUS_WRONG_PARAMS, ERROR,
-            "Too many data nodes to send: %d\n", pkt->num);
-
-    char buf[CMSG_SPACE(sizeof(int))];
-    memset(buf, 0, sizeof(buf));
-    for (int i = 0; i < pkt->num; i++)
-    {
-        PlinkDescHdr *hdr = (PlinkDescHdr *)(pkt->list[i]);
-        ctx->ioOut[i].iov_base = pkt->list[i];
-        ctx->ioOut[i].iov_len = hdr->size + DATA_HEADER_SIZE;
-        PLINK_PRINT(INFO, "Sending Out %ld bytes\n", ctx->ioOut[i].iov_len);
-    }
-
-    struct msghdr msg = {0};
-    msg.msg_iov = ctx->ioOut;
-    msg.msg_iovlen = pkt->num;
-
-    if (pkt->fd > PLINK_INVALID_FD)
-    {
-        msg.msg_control = buf;
-        msg.msg_controllen = sizeof(buf);
-
-        struct cmsghdr *cmsg;
-        cmsg = CMSG_FIRSTHDR(&msg);
-        cmsg->cmsg_level = SOL_SOCKET;
-        cmsg->cmsg_type = SCM_RIGHTS;
-        cmsg->cmsg_len = CMSG_LEN(sizeof(int));
-        *((int *)CMSG_DATA(cmsg)) = pkt->fd;
-        PLINK_PRINT(INFO, "Sent fd %d\n", pkt->fd);
-    }
-
-    int sockfd = ctx->mode == PLINK_MODE_SERVER ? ctx->cfd[channel] : ctx->sockfd;
-    if (sendmsg(sockfd, &msg, 0) == -1)
-        PLINK_PRINT_RETURN(PLINK_STATUS_ERROR, ERROR,
-            "sendmsg() failed: %s\n", strerror(errno));
-    PLINK_PRINT(INFO, "Sent data to %d\n", sockfd);
-
-    return PLINK_STATUS_OK;
-}
-
-PlinkStatus 
-PLINK_recv(PlinkHandle plink, PlinkChannelID channel, PlinkPacket *pkt)
-{
-    PlinkContext *ctx = (PlinkContext *)plink;
-
-    if (ctx == NULL || pkt == NULL)
-        PLINK_PRINT_RETURN(PLINK_STATUS_WRONG_PARAMS, ERROR,
-            "Wrong parameters: plink = %p, pkt = %p\n", plink, pkt);
-
-    pkt->num = 0;
-
-    char buf[CMSG_SPACE(sizeof(int))];
-    memset(buf, 0, sizeof(buf));
-    ctx->ioIn[0].iov_base = ctx->buffer + ctx->offset;
-    ctx->ioIn[0].iov_len = MAX_BUFFER_SIZE - ctx->offset;
-
-    struct msghdr msg = {0};
-    msg.msg_iov = ctx->ioIn;
-    msg.msg_iovlen = 1;
-    msg.msg_control = buf;
-    msg.msg_controllen = sizeof(buf);
-
-    int sockfd = ctx->mode == PLINK_MODE_SERVER ? ctx->cfd[channel] : ctx->sockfd;
-    PLINK_PRINT(INFO, "Receiving data from %d\n", sockfd);
-    int total = recvmsg (sockfd, &msg, 0);
-    if (total > 0)
-        PLINK_PRINT(INFO, "Received %d bytes\n", total)
-    else if (total == 0)
-        PLINK_PRINT_RETURN(PLINK_STATUS_NO_DATA, WARNING,
-            "recvmsg() returns %d\n", total)
-    else
-        PLINK_PRINT_RETURN(PLINK_STATUS_ERROR, ERROR,
-            "Failed to recieve data from %d: %s\n", sockfd, strerror(errno))
-
-    if (msg.msg_controllen >= CMSG_SPACE(sizeof(int)))
-    {
-        struct cmsghdr *cmsg;
-        cmsg = CMSG_FIRSTHDR(&msg);
-        pkt->fd = *((int *)CMSG_DATA(cmsg));
-        PLINK_PRINT(INFO, "Received fd %d\n", pkt->fd);
-    }
-    else
-        pkt->fd = PLINK_INVALID_FD;
-
-    return parseData(ctx, pkt, ctx->offset + total);
-}
-
-PlinkStatus 
-PLINK_wait(PlinkHandle plink, PlinkChannelID channel, int timeout_ms)
-{
-    PlinkContext *ctx = (PlinkContext *)plink;
-
-    if (ctx == NULL)
-        PLINK_PRINT_RETURN(PLINK_STATUS_WRONG_PARAMS, ERROR,
-            "Wrong parameters: plink = %p\n", plink);
-
-    int sockfd = ctx->mode == PLINK_MODE_SERVER ? ctx->cfd[channel] : ctx->sockfd;
-    return wait(sockfd, timeout_ms);
-}
-
-PlinkStatus 
-PLINK_close(PlinkHandle plink, PlinkChannelID channel)
-{
-    PlinkContext *ctx = (PlinkContext *)plink;
-
-    if (ctx == NULL)
-        PLINK_PRINT_RETURN(PLINK_STATUS_WRONG_PARAMS, ERROR,
-            "Wrong parameters: plink = %p\n", plink);
-
-    if (ctx->mode == PLINK_MODE_SERVER)
-    {
-        if (channel == PLINK_CLOSE_ALL)
-        {
-            // close all connections
-            int i;
-            for (i = 0; i < MAX_CONNECTIONS; i++)
-            {
-                if (ctx->connect[i] != 0)
-                {
-                    ctx->connect[i] = 0;
-                    close(ctx->cfd[i]);
-                    ctx->count--;
-                    PLINK_PRINT(INFO, "Closed channel %d\n", i);
-                }
-            }
-
-            unlink(ctx->addr.sun_path);
-            close(ctx->sockfd);
-            if (ctx->buffer != NULL)
-                free(ctx->buffer);
-
-            free(ctx);
-        }
-        else if (channel < MAX_CONNECTIONS && ctx->connect[channel] != 0)
-        {
-            close(ctx->cfd[channel]);
-            ctx->count--;
-            PLINK_PRINT(INFO, "Closed channel %d\n", channel);
-        }
-        else
-        {
-            PLINK_PRINT(ERROR, "Invalid channel: %d\n", channel);
-        }
-
-        unlink(ctx->addr.sun_path);
-    }
-    else
-    {
-        close(ctx->sockfd);
-        if (ctx->buffer != NULL)
-            free(ctx->buffer);
-
-        free(ctx);
-    }
-
-    return PLINK_STATUS_OK;
-}
-
-PlinkStatus
-PLINK_connect_ex(PlinkHandle plink, PlinkChannelID *channel, int timeout_ms)
-{
-    PlinkContext *ctx = (PlinkContext *)plink;
-
-    if (ctx == NULL)
-        PLINK_PRINT_RETURN(PLINK_STATUS_WRONG_PARAMS, ERROR,
-            "Wrong parameters: plink = %p\n", plink);
-
-    int i = 0;
-    if (ctx->mode == PLINK_MODE_SERVER)
-    {
-        if (channel == NULL)
-            PLINK_PRINT_RETURN(PLINK_STATUS_WRONG_PARAMS, ERROR,
-                "Wrong parameters: channel = %p\n", channel);
-
-        if (ctx->count >= MAX_CONNECTIONS)
-            PLINK_PRINT_RETURN(PLINK_STATUS_ERROR, ERROR,
-               "Too many connections %d while it is limited to %d\n", ctx->count, MAX_CONNECTIONS);
-
-        // find available slot
-        for (i = 0; i < MAX_CONNECTIONS; i++)
-        {
-            if (ctx->connect[i] == 0)
-            {
-                ctx->connect[i] = 1;
-                *channel = i;
-                break;
-            }
-        }
-
-        // wait for connection from client
-        PLINK_PRINT(INFO, "Waiting for connection...\n");
-        if (wait(ctx->sockfd, timeout_ms) == PLINK_STATUS_OK)
-        {
-            int fd = accept(ctx->sockfd, NULL, NULL);
-            if (fd == -1)
-                PLINK_PRINT_RETURN(PLINK_STATUS_ERROR, ERROR,
-                    "Failed to accept connection\n");
-
-            ctx->cfd[i] = fd;
-            ctx->count++;
-            PLINK_PRINT(INFO, "Accepted connection request from client %d (%d/%d): %d\n", 
-                    i, ctx->count, MAX_CONNECTIONS, fd);
-        }
-        else
-            PLINK_PRINT_RETURN(PLINK_STATUS_ERROR, ERROR,
-                "No connection request within %dms\n", timeout_ms);
-    }
-    else
-    {
-        int max_tries = (timeout_ms + 1000 - 1) / 1000;
-        for (i = 0; i < max_tries; i++)
-        {
-            if (connect(ctx->sockfd, (struct sockaddr *)&ctx->addr, sizeof(struct sockaddr_un)) == -1)
-                sleep(1);
-            else
-                break;
-        }
-
-        if (i >= max_tries)
-            PLINK_PRINT_RETURN(PLINK_STATUS_TIMEOUT, WARNING,
-               "Failed to connect to server %s\n", ctx->addr.sun_path);
-
-        PLINK_PRINT(INFO, "Connected to server: %d\n", ctx->sockfd);
-    }
-
-    return PLINK_STATUS_OK;
-}
-
-PlinkStatus 
-PLINK_recv_ex(PlinkHandle plink, PlinkChannelID channel, PlinkPacket *pkt, int timeout_ms)
-{
-    int ret = PLINK_wait(plink, channel, timeout_ms);
-    if (ret == PLINK_STATUS_OK)
-    {
-        return PLINK_recv(plink, channel, pkt);
-    }
-
-    return ret;
-}
-
-
-static PlinkStatus 
-parseData(PlinkContext *ctx, PlinkPacket *pkt, int remaining)
-{
-    PlinkStatus sts = PLINK_STATUS_OK;
-
-    if (ctx == NULL)
-        return PLINK_STATUS_ERROR;
-
-    int index = 0;
-    void *buffer = ctx->buffer;
-    while (remaining >= DATA_HEADER_SIZE)
-    {
-        if (index >= PLINK_MAX_DATA_DESCS)
-        {
-            // not enough buffer to store received data, need another recv call
-            sts = PLINK_STATUS_MORE_DATA;
-            PLINK_PRINT(ERROR, "sts:%d Received %d bytes,index exceed max:%d!\n",
-			    sts, remaining, PLINK_MAX_DATA_DESCS);
-            break;
-        }
-
-        PlinkDescHdr *hdr = (PlinkDescHdr *)buffer;
-        if (remaining < (unsigned int)hdr->size)
-        {
-            PLINK_PRINT(WARNING, "Not enough data received. Expect %d while only %d available\n", hdr->size, remaining);
-            // return to get more data in next recvmsg call
-            break;
-        }
-
-        pkt->list[index] = buffer;
-
-        buffer += DATA_HEADER_SIZE + hdr->size;
-        remaining -= DATA_HEADER_SIZE + hdr->size;
-        index++;
-    }
-
-    // move the remaining data to the beginning of the buffer
-    if (remaining > 0)
-    {
-        memmove(ctx->buffer, buffer, remaining);
-        ctx->offset = remaining;
-    }
-
-    pkt->num = sts == PLINK_STATUS_MORE_DATA ? index-1 : index;
-
-    return sts;
-}
-
-static int getLogLevel()
-{
-    char *env = getenv("PLINK_LOG_LEVEL");
-    if (env == NULL)
-        return PLINK_LOG_ERROR;
-    else
-    {
-        int level = atoi(env);
-        if (level >= PLINK_LOG_MAX || level < PLINK_LOG_QUIET)
-            return PLINK_LOG_ERROR;
-        else
-            return level;
-    }
-}
-
-static PlinkStatus 
-wait(int sockfd, int timeout_ms)
-{
-    fd_set rfds;
-    struct timeval tv;
-    int ret;
-
-    FD_ZERO(&rfds);
-    FD_SET(sockfd, &rfds);
-
-    tv.tv_sec = timeout_ms / 1000;
-    tv.tv_usec = (timeout_ms % 1000) * 1000;
-    PLINK_PRINT(INFO, "Waiting for data from socket %d, timeout %dms\n", sockfd, timeout_ms);
-    ret = select(sockfd+1, &rfds, NULL, NULL, &tv);
-    if (ret == -1)
-        PLINK_PRINT_RETURN(PLINK_STATUS_ERROR, ERROR,
-            "Failed to wait for data\n")
-    else if (ret)
-        return PLINK_STATUS_OK;
-    else if (timeout_ms > 0)
-        PLINK_PRINT_RETURN(PLINK_STATUS_TIMEOUT, WARNING,
-            "Wait timeout\n");
-
-    return PLINK_STATUS_TIMEOUT;
-}

+ 73 - 0
test/Makefile

@@ -0,0 +1,73 @@
+
+CFLAGS = -Wall -D_GNU_SOURCE -D_REENTRANT -D_THREAD_SAFE -O2 -Werror -Wno-unused -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function -Wno-strict-overflow -Wno-array-bounds -Wno-shift-negative-value -Wempty-body -Wtype-limits -Wno-unused-result -fPIC -Wmissing-field-initializers -std=gnu99
+
+INCLUDE += -I../user_mode
+
+SRCS = isp_venc_shake.c
+OBJS = $(SRCS:.c=.o)
+
+#source search path
+vpath %.c
+
+# name of the outputfile (library)
+IVSLIB = ../user_mode/libivs.a
+IVSSLIB = ../user_mode/libivs.so
+TARGET = ivs_test
+
+#Here are rules for building codes and generating object library.
+all:    tags
+	@echo ---------------------------------------
+	@echo "Usage: make [ system | testdata | versatile | integrator | android]"
+	@echo "system     - PC system model (== pclinux)"
+	@echo "testdata   - PC system model for test data creation"
+	@echo "eval       - PC system model for evaluation with frame limit"
+	@echo "versatile  - ARM versatile with FPGA HW"
+	@echo "integrator - ARM integrator with FPGA HW"
+	@echo "android    - ARM android"
+	@echo "NOTE! Make sure to do 'make clean'"
+	@echo "between compiling to different targets!"
+	@echo ---------------------------------------
+
+.PHONY: system_lib system testdata clean depend
+
+evaluation: eval
+eval: system
+
+system_static: testdata
+system: testdata
+
+# for libva
+system_lib: system
+
+testdata: .depend $(IVSLIB)
+
+
+.PHONY: hwlinux
+hwlinux:
+hwlinux: .depend $(TARGET)
+
+$(TARGET): $(OBJS)
+	$(CC) $(CFLAGS) $(OBJS) $(IVSLIB) -lm -lpthread -o $(TARGET)
+
+
+
+%.o: %.c
+	$(CC) -c $(CFLAGS) $(INCLUDE) $< -o $@
+
+clean:
+	$(RM) $(TARGET)
+	$(RM) .depend
+	$(RM) *.o *.gcno *.gcda
+
+tags:
+	ctags ../kernel_mode/*h ./*[ch]
+
+depend .depend: $(SRCS)
+	@echo "[CC] $@"
+	@$(CC) -M $(DEBFLAGS) $(INCLUDE) $^ > .depend
+
+ifneq (clean, $(findstring clean, $(MAKECMDGOALS)))
+ifeq (.depend, $(wildcard .depend))
+include .depend
+endif
+endif

+ 76 - 0
test/isp_venc_shake.c

@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2021-2022 Alibaba Group. All rights reserved.
+ * License-Identifier: Apache-2.0
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include "isp_venc_shake_hal.h"
+
+#ifndef NULL
+#define NULL    ((void *)0)
+#endif
+
+
+int main(void)
+{
+    void *ivs = NULL;
+    IvsConfig config;
+    IvsStatus status = IVS_STATUS_OK;
+
+    do
+    {
+        status = createIspVencShake(&ivs);
+        if (status != IVS_STATUS_OK)
+            break;
+
+        status = resetIspVencShake(ivs);
+        
+        config.mode = IVS_BUFFER_MODE_FRAME;
+        config.encode = IVS_ENCODER_FORMAT_H264;
+        config.pic_width = 640;
+        config.pic_height = 480;
+        config.encode_width = 640;
+        config.encode_height = 480;
+        config.buffer_height = 240;
+        config.stride_y = 640;
+        config.stride_uv = 640;
+        config.encode_x = 0;
+        config.encode_y = 0;
+        status = configIspVencShake(ivs, &config);
+        if (status != IVS_STATUS_OK)
+            break;
+        
+        status = startIspVencShake(ivs);
+        if (status != IVS_STATUS_OK)
+            break;
+
+        sleep(90);
+
+        status = resetIspVencShake(ivs);
+        if (status != IVS_STATUS_OK)
+            break;
+    } while (0);
+    
+    destroyIspVencShake(ivs);
+
+    if (status != IVS_STATUS_OK)
+        printf("ERROR: ivs_test exit with error!\n");
+    else
+        printf("ivs_test done!\n");
+
+    return (status == IVS_STATUS_OK ? 0 : 1);
+}
+

+ 0 - 203
test/plink_client.c

@@ -1,203 +0,0 @@
-/*
- * Copyright (c) 2021 Alibaba Group. All rights reserved.
- * License-Identifier: Apache-2.0
- *
- * 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.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <pthread.h>
-#include <memory.h>
-#include "process_linker_types.h"
-#include "video_mem.h"
-
-#ifndef NULL
-#define NULL    ((void *)0)
-#endif
-
-#define NUM_OF_BUFFERS  5
-#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
-                        } while (0)
-
-int main(int argc, char **argv) {
-    PlinkStatus sts = PLINK_STATUS_OK;
-    PlinkPacket sendpkt, recvpkt;
-    PlinkMsg msg;
-    PlinkHandle plink = NULL;
-    VmemParams params;
-    void *vmem = NULL;
-    FILE *fp = NULL;
-    int exitcode = 0;
-
-    int frames = argc > 1 ? atoi(argv[1]) : 1000;
-    char *plinkname = argc > 2 ? argv[2] : "/tmp/plink.test";
-    char *dumpname = argc > 3 ? argv[3] : NULL;
-
-    if (dumpname != NULL)
-    {
-        fp = fopen(dumpname, "wb");
-        if (fp == NULL)
-            errExit("fopen");
-    }
-
-    if (VMEM_create(&vmem) != VMEM_STATUS_OK)
-        errExit("Failed to create VMEM.");
-
-    if (PLINK_create(&plink, plinkname, PLINK_MODE_CLIENT) != PLINK_STATUS_OK)
-        errExit("Failed to create PLINK.");
-
-    if (PLINK_connect(plink, NULL) != PLINK_STATUS_OK)
-        errExit("Failed to connect to server.");
-
-    int frmcnt = 0;
-    do {
-        sts = PLINK_recv(plink, 0, &recvpkt);
-        memset(&params, 0, sizeof(params));
-        if (recvpkt.fd != PLINK_INVALID_FD)
-        {
-            params.fd = recvpkt.fd;
-            if (VMEM_import(vmem, &params) != VMEM_STATUS_OK)
-                errExit("Failed to import fd.");
-            if (VMEM_mmap(vmem, &params) != VMEM_STATUS_OK)
-                errExit("Failed to mmap buffer.");
-        }
-
-        for (int i = 0; i < recvpkt.num; i++)
-        {
-            PlinkDescHdr *hdr = (PlinkDescHdr *)(recvpkt.list[i]);
-            if (hdr->type == PLINK_TYPE_2D_YUV)
-            {
-                PlinkYuvInfo *pic = (PlinkYuvInfo *)(recvpkt.list[i]);
-                printf("[CLIENT] Received YUV frame %d 0x%010llx: fd %d, %dx%d, stride = luma %d, chroma %d\n", 
-                        pic->header.id, pic->bus_address_y, recvpkt.fd,
-                        pic->pic_width, pic->pic_height,
-                        pic->stride_y, pic->stride_u);
-
-                // Save YUV data to file
-                if (fp != NULL && params.vir_address != NULL)
-                {
-                    void *buffer = params.vir_address;
-                    for (int i = 0; i < pic->pic_height * 3 / 2; i++)
-                    {
-                        fwrite(buffer, pic->pic_width, 1, fp);
-                        buffer += pic->stride_y;
-                    }
-                }
-
-                // return the buffer to source
-                msg.header.type = PLINK_TYPE_MESSAGE;
-                msg.header.size = DATA_SIZE(PlinkMsg);
-                msg.msg = hdr->id;
-                sendpkt.list[0] = &msg;
-                sendpkt.num = 1;
-                sendpkt.fd = PLINK_INVALID_FD;
-                if (PLINK_send(plink, 0, &sendpkt) == PLINK_STATUS_ERROR)
-                    errExit("Failed to send data.");
-            }
-            if (hdr->type == PLINK_TYPE_2D_RGB)
-            {
-                PlinkRGBInfo *pic = (PlinkRGBInfo *)(recvpkt.list[i]);
-                printf("[CLIENT] Received RGB picture %d 0x%010llx: fd %d, %dx%d, stride %d/%d/%d/%d\n", 
-                        pic->header.id, pic->bus_address_r, recvpkt.fd,
-                        pic->img_width, pic->img_height,
-                        pic->stride_r, pic->stride_g, pic->stride_b, pic->stride_a);
-
-                // Save RGB data to file
-                if (fp != NULL && params.vir_address != NULL && pic->format == PLINK_COLOR_Format24BitBGR888Planar)
-                {
-                    void *buffer = params.vir_address;
-                    for (int i = 0; i < pic->img_height * 3; i++)
-                    {
-                        fwrite(buffer, pic->img_width, 1, fp);
-                        buffer += pic->stride_r;
-                    }
-                }
-
-                // return the buffer to source
-                msg.header.type = PLINK_TYPE_MESSAGE;
-                msg.header.size = DATA_SIZE(PlinkMsg);
-                msg.msg = hdr->id;
-                sendpkt.list[0] = &msg;
-                sendpkt.num = 1;
-                sendpkt.fd = PLINK_INVALID_FD;
-                if (PLINK_send(plink, 0, &sendpkt) == PLINK_STATUS_ERROR)
-                    errExit("Failed to send data.");
-            }
-            if (hdr->type == PLINK_TYPE_2D_RAW)
-            {
-                PlinkRawInfo *pic = (PlinkRawInfo *)(recvpkt.list[i]);
-                printf("[CLIENT] Received RAW picture %d 0x%010llx: fd %d, %dx%d, stride %d\n", 
-                        pic->header.id, pic->bus_address, recvpkt.fd,
-                        pic->img_width, pic->img_height, pic->stride);
-
-                // Save RAW data to file
-                if (fp != NULL && params.vir_address != NULL)
-                    fwrite(params.vir_address, pic->stride * pic->img_height, 1, fp);
-
-                // return the buffer to source
-                msg.header.type = PLINK_TYPE_MESSAGE;
-                msg.header.size = DATA_SIZE(PlinkMsg);
-                msg.msg = hdr->id;
-                sendpkt.list[0] = &msg;
-                sendpkt.num = 1;
-                sendpkt.fd = PLINK_INVALID_FD;
-                if (PLINK_send(plink, 0, &sendpkt) == PLINK_STATUS_ERROR)
-                    errExit("Failed to send data.");
-            }
-            else if (hdr->type == PLINK_TYPE_MESSAGE)
-            {
-                PlinkMsg *msg = (PlinkMsg *)(recvpkt.list[i]);
-                if (msg->msg == PLINK_EXIT_CODE)
-                {
-                    exitcode = 1;
-                    printf("Exit\n");
-                    break;
-                }
-            }
-        }
-
-        if (VMEM_release(vmem, &params) != VMEM_STATUS_OK)
-            errExit("Failed to release buffer.");
-
-        if (recvpkt.fd != PLINK_INVALID_FD)
-            close(recvpkt.fd);
-
-        frmcnt++;
-
-        if (frmcnt >= frames)
-        {
-            msg.header.type = PLINK_TYPE_MESSAGE;
-            msg.header.size = DATA_SIZE(PlinkMsg);
-            msg.msg = PLINK_EXIT_CODE;
-            sendpkt.list[0] = &msg;
-            sendpkt.num = 1;
-            sendpkt.fd = PLINK_INVALID_FD;
-            if (PLINK_send(plink, 0, &sendpkt) == PLINK_STATUS_ERROR)
-                errExit("Failed to send data.");
-            break;
-        }
-    } while (exitcode == 0);
-
-cleanup:
-    sleep(1); // Sleep one second to make sure server is ready for exit
-    PLINK_close(plink, 0);
-    VMEM_destroy(vmem);
-    if (fp != NULL)
-        fclose(fp);
-    exit(EXIT_SUCCESS);
-}

+ 0 - 432
test/plink_server.c

@@ -1,432 +0,0 @@
-/*
- * Copyright (c) 2021 Alibaba Group. All rights reserved.
- * License-Identifier: Apache-2.0
- *
- * 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.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <pthread.h>
-#include <memory.h>
-#include <errno.h>
-#include "process_linker_types.h"
-#include "video_mem.h"
-
-#ifndef NULL
-#define NULL    ((void *)0)
-#endif
-
-#define NUM_OF_BUFFERS  5
-#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
-                        } while (0)
-
-typedef struct _ServerParams
-{
-    char *plinkname;
-    char *inputfile;
-    PlinkColorFormat format;
-    int width;
-    int height;
-    int stride;
-    int frames;
-} ServerParams;
-
-typedef struct _PlinkChannel
-{
-    PlinkChannelID id;
-    PlinkHandle plink;
-    PlinkPacket pkt;
-    int sendid;
-    int backid;
-    int exit;
-    int available_bufs;
-} PlinkChannel;
-
-typedef struct _PictureBuffer
-{
-  unsigned int bus_address;
-  void *virtual_address;
-  unsigned int size;
-  int fd;
-} PictureBuffer;
-
-void printUsage(char *name)
-{
-    printf("usage: %s [options]\n"
-           "\n"
-           "  Available options:\n"
-           "    -l      plink file name (default: /tmp/plink.test)\n"
-           "    -i      input YUV file name (mandatory)\n"
-           "    -f      input color format (default: 3)\n"
-           "                2 - I420\n"
-           "                3 - NV12\n"
-           "                4 - P010\n"
-           "                14 - Bayer Raw 10bit\n"
-           "                15 - Bayer Raw 12bit\n"
-           "    -w      video width (mandatory)\n"
-           "    -h      video height (mandatory)\n"
-           "    -s      video buffer stride in bytes (default: video width)\n"
-           "    -n      number of frames to send (default: 10)\n"
-           "\n", name);
-}
-
-void parseParams(int argc, char **argv, ServerParams *params)
-{
-    int i = 1;
-    memset(params, 0, sizeof(*params));
-    params->plinkname = "/tmp/plink.test";
-    params->format = PLINK_COLOR_FormatYUV420SemiPlanar;
-    params->frames = 10;
-    while (i < argc)
-    {
-        if (argv[i][0] != '-' || strlen(argv[i]) < 2)
-        {
-            i++;
-            continue;
-        }
-
-        if (argv[i][1] == 'l')
-        {
-            if (++i < argc)
-            {
-                params->plinkname = argv[i++];
-            }
-        }
-        else if (argv[i][1] == 'i')
-        {
-            if (++i < argc)
-            {
-                params->inputfile = argv[i++];
-            }
-        }
-        else if (argv[i][1] == 'f')
-        {
-            if (++i < argc)
-            {
-                params->format = atoi(argv[i++]);
-            }
-        }
-        else if (argv[i][1] == 'w')
-        {
-            if (++i < argc)
-            {
-                params->width = atoi(argv[i++]);
-            }
-        }
-        else if (argv[i][1] == 'h')
-        {
-            if (++i < argc)
-            {
-                params->height = atoi(argv[i++]);
-            }
-        }
-        else if (argv[i][1] == 's')
-        {
-            if (++i < argc)
-            {
-                params->stride = atoi(argv[i++]);
-            }
-        }
-        else if (argv[i][1] == 'n')
-        {
-            if (++i < argc)
-            {
-                params->frames = atoi(argv[i++]);
-            }
-        }
-    }
-
-    if ((params->format == PLINK_COLOR_FormatYUV420SemiPlanarP010 ||
-            params->format == PLINK_COLOR_FormatRawBayer10bit ||
-            params->format == PLINK_COLOR_FormatRawBayer12bit) &&
-        params->stride < params->width*2)
-    {
-        params->stride = params->width*2;
-    }
-    else if (params->stride < params->width)
-    {
-        params->stride = params->width;
-    }
-}
-
-int checkParams(ServerParams *params)
-{
-    if (params->plinkname == NULL ||
-        params->inputfile == NULL ||
-        params->format == PLINK_COLOR_FormatUnused ||
-        params->width == 0 ||
-        params->height == 0 ||
-        params->stride == 0)
-        return -1;
-    return 0;
-}
-
-int getBufferSize(ServerParams *params)
-{
-    int size = 0;
-    switch (params->format)
-    {
-        case PLINK_COLOR_FormatYUV420Planar:
-        case PLINK_COLOR_FormatYUV420SemiPlanar:
-            size = params->stride * params->height * 3 / 2;
-            break;
-        case PLINK_COLOR_FormatYUV420SemiPlanarP010:
-            size = params->stride * params->height * 3;
-            break;
-        case PLINK_COLOR_FormatRawBayer10bit:
-        case PLINK_COLOR_FormatRawBayer12bit:
-            size = params->stride * params->height;
-            break;
-        default:
-            size = 0;
-    }
-    return size;
-}
-
-void AllocateBuffers(PictureBuffer 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++)
-    {
-        params.fd = 0;
-        VMEM_allocate(vmem, &params);
-        VMEM_mmap(vmem, &params);
-        VMEM_export(vmem, &params);
-        printf("[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 FreeBuffers(PictureBuffer picbuffers[NUM_OF_BUFFERS], void *vmem)
-{
-    VmemParams params;
-    memset(&params, 0, sizeof(params));
-    for (int i = 0; i < NUM_OF_BUFFERS; i++)
-    {
-        close(picbuffers[i].fd);
-        params.size = picbuffers[i].size;
-        params.vir_address = picbuffers[i].virtual_address;
-        params.phy_address = picbuffers[i].bus_address;
-        VMEM_free(vmem, &params);
-    }
-}
-
-void ProcessOneFrame(void *virtual_address, FILE *fp, int size)
-{
-    if(virtual_address != MAP_FAILED && fp != NULL)
-    {
-        if (fread(virtual_address, size, 1, fp) < 1)
-            fprintf(stderr, "ERROR: Failed to read %d bytes from file (eof %d): %s\n",
-                size, feof(fp), strerror(errno));
-    }
-}
-
-void constructYuvInfo(PlinkYuvInfo *info, ServerParams *params, unsigned int bus_address, int id)
-{
-    int size_y = params->width * params->stride;
-    int size_uv = size_y / 2;
-    int size_yuv = size_y + size_uv;
-    
-    info->header.type = PLINK_TYPE_2D_YUV;
-    info->header.size = DATA_SIZE(*info);
-    info->header.id = id + 1;
-
-    info->format = params->format;
-    info->bus_address_y = bus_address;
-    info->bus_address_u = info->bus_address_y + size_y;
-    info->bus_address_v = info->bus_address_u + (size_uv / 2);
-    info->pic_width = params->width;
-    info->pic_height = params->height;
-    info->stride_y = params->stride;
-    info->stride_u = 
-        params->format == PLINK_COLOR_FormatYUV420Planar ? 
-        params->stride/2 : params->stride;
-    info->stride_v = info->stride_u;
-}
-
-void constructRawInfo(PlinkRawInfo *info, ServerParams *params, unsigned int bus_address, int id)
-{
-    int size_y = params->width * params->stride;
-    int size_uv = size_y / 2;
-    int size_yuv = size_y + size_uv;
-    
-    info->header.type = PLINK_TYPE_2D_RAW;
-    info->header.size = DATA_SIZE(*info);
-    info->header.id = id + 1;
-
-    info->format = params->format;
-    info->bus_address = bus_address;
-    info->img_width = params->width;
-    info->img_height = params->height;
-    info->stride = params->stride;
-}
-
-int getBufferCount(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;
-}
-
-void retreiveSentBuffers(PlinkHandle plink, PlinkChannel *channel)
-{
-    PlinkStatus sts = PLINK_STATUS_OK;
-    while (channel->available_bufs < NUM_OF_BUFFERS && sts == PLINK_STATUS_OK)
-    {
-        do
-        {
-            sts = PLINK_recv(plink, channel->id, &channel->pkt);
-            int count = getBufferCount(&channel->pkt);
-            if (count > 0)
-            {
-                channel->available_bufs += count;
-            }
-        } while (sts == PLINK_STATUS_MORE_DATA);
-    }
-}
-
-
-int main(int argc, char **argv) {
-    PlinkStatus sts = PLINK_STATUS_OK;
-    ServerParams params;
-    PlinkChannel channel[2];
-    PlinkHandle plink = NULL;
-    PlinkYuvInfo pic = {0};
-    PlinkRawInfo img = {0};
-    PlinkMsg msg;
-
-    parseParams(argc, argv, &params);
-    if (checkParams(&params) != 0)
-    {
-        printUsage(argv[0]);
-        return 0;
-    }
-
-    FILE *fp = fopen(params.inputfile, "rb");
-    if (fp == NULL)
-        errExit("fopen");
-
-    void *vmem = NULL;
-    if (VMEM_create(&vmem) != VMEM_STATUS_OK)
-        errExit("Failed to create VMEM.");
-
-    int width = params.width;
-    int height = params.height;
-    int stride = params.stride;
-    int frames = params.frames;
-    int size = getBufferSize(&params);
-    if (size == 0)
-        errExit("Wrong format or wrong resolution.");
-    PictureBuffer picbuffers[NUM_OF_BUFFERS];
-    AllocateBuffers(picbuffers, size, vmem);
-
-    sts = PLINK_create(&plink, params.plinkname, PLINK_MODE_SERVER);
-
-    memset(&channel[0], 0, sizeof(channel[0]));
-    channel[0].available_bufs = NUM_OF_BUFFERS;
-    sts = PLINK_connect(plink, &channel[0].id);
-
-    int frmcnt = 0;
-    do {
-        int sendid = channel[0].sendid;
-        ProcessOneFrame(picbuffers[sendid].virtual_address, fp, size);
-        if (params.format == PLINK_COLOR_FormatRawBayer8bit ||
-            params.format == PLINK_COLOR_FormatRawBayer10bit ||
-            params.format == PLINK_COLOR_FormatRawBayer12bit)
-        {
-            constructRawInfo(&img, &params, picbuffers[sendid].bus_address, sendid);
-            printf("[SERVER] Processed frame %d 0x%010llx: %dx%d, stride %d\n", 
-                    sendid, img.bus_address, img.img_width, img.img_height, img.stride);
-            channel[0].pkt.list[0] = &img;
-        }
-        else // YUV
-        {
-            constructYuvInfo(&pic, &params, picbuffers[sendid].bus_address, sendid);
-            printf("[SERVER] Processed frame %d 0x%010llx: %dx%d, stride = luma %d, chroma %d\n", 
-                    sendid, pic.bus_address_y, 
-                    pic.pic_width, pic.pic_height,
-                    pic.stride_y, pic.stride_u);
-            channel[0].pkt.list[0] = &pic;
-        }
-
-        channel[0].pkt.num = 1;
-        channel[0].pkt.fd = picbuffers[sendid].fd;
-        sts = PLINK_send(plink, channel[0].id, &channel[0].pkt);
-        channel[0].sendid = (channel[0].sendid + 1) % NUM_OF_BUFFERS;
-        channel[0].available_bufs -= 1;
-
-        int timeout = 0;
-        if (channel[0].available_bufs == 0)
-            timeout = 60000; // wait up to 60 seconds if buffers are used up
-
-        if (PLINK_wait(plink, channel[0].id, timeout) == PLINK_STATUS_OK)
-        {
-            do
-            {
-                sts = PLINK_recv(plink, channel[0].id, &channel[0].pkt);
-                int count = getBufferCount(&channel[0].pkt);
-                if (count < 0)
-                    channel[0].exit = 1;
-                channel[0].available_bufs += count;
-            } while (sts == PLINK_STATUS_MORE_DATA);
-        }
-
-        frmcnt++;
-    } while (channel[0].exit == 0 && frmcnt < frames);
-
-cleanup:
-    msg.header.type = PLINK_TYPE_MESSAGE;
-    msg.header.size = DATA_SIZE(PlinkMsg);
-    msg.msg = PLINK_EXIT_CODE;
-    channel[0].pkt.list[0] = &msg;
-    channel[0].pkt.num = 1;
-    channel[0].pkt.fd = PLINK_INVALID_FD;
-    sts = PLINK_send(plink, channel[0].id, &channel[0].pkt);
-    retreiveSentBuffers(plink, &channel[0]);
-    PLINK_recv_ex(plink, channel[0].id, &channel[0].pkt, 1000);
-    //sleep(1); // Sleep one second to make sure client is ready for exit
-    if (vmem)
-        FreeBuffers(picbuffers, vmem);
-    PLINK_close(plink, PLINK_CLOSE_ALL);
-    VMEM_destroy(vmem);
-    if (fp != NULL)
-        fclose(fp);
-    exit(EXIT_SUCCESS);
-}
-

+ 0 - 766
test/plink_stitcher.c

@@ -1,766 +0,0 @@
-/*
- * Copyright (c) 2022 Alibaba Group. All rights reserved.
- * License-Identifier: Apache-2.0
- *
- * 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.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <pthread.h>
-#include <semaphore.h>
-#include <memory.h>
-#include "process_linker_types.h"
-#include "video_mem.h"
-
-#ifndef NULL
-#define NULL    ((void *)0)
-#endif
-
-#define MAX_NUM_OF_INPUTS   4
-#define NUM_OF_BUFFERS      5
-#define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
-                        } while (0)
-#define STITCHER_MIN(a, b) ((a) < (b) ? (a) : (b))
-
-
-typedef enum _StitchLayout
-{
-    STITCH_LAYOUT_Vertical = 0,
-    STITCH_LAYOUT_Horizontal,
-    STITCH_LAYOUT_Matrix,
-    STITCH_LAYOUT_Max
-} StitchLayout;
-
-typedef struct _StitherRegion
-{
-    int width;
-    int height;
-    int offset_uv;
-    int offset_y;
-} StitcherRegion;
-
-typedef struct _StitcherParams
-{
-    char *in_name[MAX_NUM_OF_INPUTS];
-    char *out_name;
-    StitchLayout layout;
-    PlinkColorFormat format;
-    int width;
-    int height;
-    int stride;
-} StitcherParams;
-
-typedef struct _StitcherPort
-{
-    char *name;
-    int index;
-    PlinkChannelID id;
-    PlinkHandle plink;
-    int sendid;
-    int backid;
-    int *exit;
-    int available_bufs;
-    void *vmem;
-    pthread_mutex_t pic_mutex;
-    pthread_mutex_t *count_mutex;
-    sem_t *sem_ready;
-    sem_t *sem_done;
-    StitchLayout layout;
-    PlinkColorFormat format;
-    void *buffer;
-    int width;
-    int height;
-    int stride;
-    int offset;
-    int offset_uv;
-    int *in_count;
-} StitcherPort;
-
-typedef struct _StitcherContext
-{
-    StitcherPort in[MAX_NUM_OF_INPUTS];
-    StitcherPort out;
-    pthread_mutex_t count_mutex;
-    sem_t sem_ready;
-    sem_t sem_done;
-    int in_count;
-    int exitcode;
-} StitcherContext;
-
-typedef struct _PictureBuffer
-{
-  unsigned int bus_address;
-  void *virtual_address;
-  unsigned int size;
-  int fd;
-} PictureBuffer;
-
-static void printUsage(char *name)
-{
-    printf("usage: %s [options]\n"
-           "\n"
-           "  Stitch multiple pictures to one. Maximum # of pictures to be stitched is %d\n"
-           "  Available options:\n"
-           "    -i<n>   plink file name of input port #n (default: /tmp/plink.stitch.in<n>). n is 0 based.\n"
-           "    -o      plink file name of output port (default: /tmp/plink.stitch.out)\n"
-           "    -l      layout (default: 0)\n"
-           "                0 - vertical\n"
-           "                1 - horizontal\n"
-           "                2 - matrix\n"
-           "    -f      output color format (default: 3)\n"
-           "                3 - NV12\n"
-           "    -w      output video width (default: 800)\n"
-           "    -h      output video height (default: 1280)\n"
-           "    -s      output video buffer stride (default: video width)\n"
-           "    --help  print this message\n"
-           "\n", name, MAX_NUM_OF_INPUTS);
-}
-
-static void parseParams(int argc, char **argv, StitcherParams *params)
-{
-    int i = 1;
-    memset(params, 0, sizeof(*params));
-    params->in_name[0] = "/tmp/plink.stitch.in0";
-    params->in_name[1] = "/tmp/plink.stitch.in1";
-    params->in_name[2] = "/tmp/plink.stitch.in2";
-    params->in_name[3] = "/tmp/plink.stitch.in3";
-    params->out_name = "/tmp/plink.stitch.out";
-    params->layout = STITCH_LAYOUT_Vertical;
-    params->format = PLINK_COLOR_FormatYUV420SemiPlanar;
-    params->width = 800;
-    params->height = 1280;
-    while (i < argc)
-    {
-        if (argv[i][0] != '-' || strlen(argv[i]) < 2)
-        {
-            i++;
-            continue;
-        }
-        
-        if (argv[i][1] == 'i')
-        {
-            if (++i < argc)
-            {
-                if (strlen(argv[i-1]) > 2) // input name
-                {
-                    int id = atoi(argv[i-1]+2);
-                    if (id < MAX_NUM_OF_INPUTS)
-                        params->in_name[id] = argv[i++];
-                }
-                else
-                    params->in_name[0] = argv[i++];
-            }
-        }
-        else if (argv[i][1] == 'o')
-        {
-            if (++i < argc)
-                params->out_name = argv[i++];
-        }
-        else if (argv[i][1] == 'l')
-        {
-            if (++i < argc)
-                params->layout = atoi(argv[i++]);
-        }
-        else if (argv[i][1] == 'f')
-        {
-            if (++i < argc)
-                params->format = atoi(argv[i++]);
-        }
-        else if (argv[i][1] == 'w')
-        {
-            if (++i < argc)
-                params->width = atoi(argv[i++]);
-        }
-        else if (argv[i][1] == 'h')
-        {
-            if (++i < argc)
-                params->height = atoi(argv[i++]);
-        }
-        else if (argv[i][1] == 's')
-        {
-            if (++i < argc)
-                params->stride = atoi(argv[i++]);
-        }
-        else if (strcmp(argv[i], "--help") == 0)
-        {
-            params->layout = STITCH_LAYOUT_Max;
-            i++;
-        }
-    }
-
-    if (params->stride == 0)
-        params->stride = params->width;
-
-    printf("[STITCHER] Input 0 Name         : %s\n", params->in_name[0]);
-    printf("[STITCHER] Input 1 Name         : %s\n", params->in_name[1]);
-    printf("[STITCHER] Input 2 Name         : %s\n", params->in_name[2]);
-    printf("[STITCHER] Input 3 Name         : %s\n", params->in_name[3]);
-    printf("[STITCHER] Output Name          : %s\n", params->out_name);
-    printf("[STITCHER] Output Layout        : %d\n", params->layout);
-    printf("[STITCHER] Output Format        : %d\n", params->format);
-    printf("[STITCHER] Output Resolution    : %dx%d\n", params->width, params->height);
-    printf("[STITCHER] Output Stride        : %d\n", params->stride);
-}
-
-static int checkParams(StitcherParams *params)
-{
-    if (params->format != PLINK_COLOR_FormatYUV420SemiPlanar ||
-        params->layout >= STITCH_LAYOUT_Max)
-        return -1;
-    return 0;
-}
-
-static int getBufferSize(StitcherParams *params)
-{
-    int size = 0;
-    switch (params->format)
-    {
-        case PLINK_COLOR_FormatYUV420Planar:
-        case PLINK_COLOR_FormatYUV420SemiPlanar:
-            size = params->stride * params->height * 3 / 2;
-            break;
-        default:
-            size = 0;
-    }
-    return size;
-}
-
-static void AllocateBuffers(PictureBuffer 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++)
-    {
-        params.fd = 0;
-        VMEM_allocate(vmem, &params);
-        VMEM_mmap(vmem, &params);
-        VMEM_export(vmem, &params);
-        printf("[STITCHER] 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;
-    }
-}
-
-static void FreeBuffers(PictureBuffer picbuffers[NUM_OF_BUFFERS], void *vmem)
-{
-    VmemParams params;
-    memset(&params, 0, sizeof(params));
-    for (int i = 0; i < NUM_OF_BUFFERS; i++)
-    {
-        close(picbuffers[i].fd);
-        params.size = picbuffers[i].size;
-        params.vir_address = picbuffers[i].virtual_address;
-        params.phy_address = picbuffers[i].bus_address;
-        VMEM_free(vmem, &params);
-    }
-}
-
-static void getRegion(StitcherPort *out, int index, int in_count, StitcherRegion *region)
-{
-    region->offset_uv = 0; //out->stride * out->height;
-    if (out->layout == STITCH_LAYOUT_Horizontal)
-    {
-        int width = (out->width / in_count + 1) & ~1;
-        region->offset_y = width * index;
-        region->offset_uv += width * index;
-        region->width = width;
-        region->height = out->height;
-    }
-    else if (out->layout == STITCH_LAYOUT_Matrix && in_count >= 3)
-    {
-        int y = index >> 1;
-        int x = index & 1;
-        int width = (out->width / 2 + 1) & ~1;
-        int height = (out->height / 2 + 1) & ~1;
-        region->offset_y = out->stride * (height * y);
-        region->offset_y += width * x;
-        region->offset_uv += out->stride * (height * y / 2);
-        region->offset_uv += width * x;
-        region->width = width;
-        region->height = height;
-    }
-    else // (out->layout == STITCH_LAYOUT_Vertical)
-    {
-        int height = (out->height / in_count + 1) & ~1;
-        region->offset_y = out->stride * (height * index);
-        region->offset_uv += out->stride * (height * index / 2);
-        region->width = out->width;
-        region->height = height;
-    }
-}
-
-static int stitchOneFrame(StitcherContext *ctx)
-{
-    StitcherPort *in = NULL;
-    StitcherPort *out = &ctx->out;
-    int in_count = 0;
-    do
-    {
-        pthread_mutex_lock(out->count_mutex);
-        in_count = ctx->in_count;
-        pthread_mutex_unlock(out->count_mutex);
-        if (in_count > 0)
-            break;
-        else
-            sleep(1);
-    } while (1);
-
-    for (int i = 0; i < in_count; i++)
-    {
-        in = &ctx->in[i];
-        if (in->index == 0)
-        {
-            sem_wait(&ctx->sem_ready); // wait for picture from input port0.
-            if (ctx->exitcode == 1)
-                return 1;
-        }
-        StitcherRegion region;
-        getRegion(out, in->index, in_count, &region);
-        pthread_mutex_lock(&in->pic_mutex);
-        int width = STITCHER_MIN(region.width, in->width);
-        int height = STITCHER_MIN(region.height, in->height);
-        void *dst = out->buffer + out->offset + region.offset_y;
-        void *src = in->buffer + in->offset;
-        //fprintf(stderr, "%d: %p, %d, %d, %p, %d\n", in->index, out->buffer, out->offset, region.offset_y, in->buffer, in->offset);
-        //fprintf(stderr, "%d: %dx%d, %d, %d\n", in->index, width, height, in->stride, out->stride);
-        if (in->available_bufs > 0)
-        {
-            if (in->format == PLINK_COLOR_FormatYUV420SemiPlanarP010 ||
-                in->format == PLINK_COLOR_FormatRawBayer10bit ||
-                in->format == PLINK_COLOR_FormatRawBayer12bit)
-            {
-                int shift = in->format == PLINK_COLOR_FormatYUV420SemiPlanarP010 ? 2 : 4;
-                unsigned int temp[4];
-                for (int h = 0; h < height; h++)
-                {
-                    unsigned int *dst32 = (unsigned int *)dst;
-                    unsigned short *src16 = (unsigned short *)src;
-                    for (int w = 0; w < width; w+=4)
-                    {
-                        temp[0] = ((unsigned int)(src16[w+0] >> shift) & 0xFF);
-                        temp[1] = ((unsigned int)(src16[w+1] >> shift) & 0xFF) << 8;
-                        temp[2] = ((unsigned int)(src16[w+2] >> shift) & 0xFF) << 16;
-                        temp[3] = ((unsigned int)(src16[w+3] >> shift) & 0xFF) << 24;
-                        dst32[w>>2] = temp[0] | temp[1] | temp[2] | temp[3];
-                    }
-                    dst += out->stride;
-                    src += in->stride;
-                }
-            }
-            else
-            {
-                for (int h = 0; h < height; h++)
-                {
-                    memcpy(dst, src, width);
-                    dst += out->stride;
-                    src += in->stride;
-                }
-            }
-        }
-        else
-        {
-            for (int h = 0; h < height; h++)
-            {
-                memset(dst, 0x00, width);
-                dst += out->stride;
-            }
-        }
-        dst = out->buffer + out->offset_uv + region.offset_uv;
-        src = in->buffer + in->offset_uv;
-        //fprintf(stderr, "%d: %p, %d, %d, %p, %d\n", in->index, out->buffer, out->offset_uv, region.offset_uv, in->buffer, in->offset_uv);
-        if (in->format == PLINK_COLOR_FormatYUV420SemiPlanar &&
-            in->available_bufs > 0)
-        {
-            for (int h = 0; h < height/2; h++)
-            {
-                memcpy(dst, src, width);
-                dst += out->stride;
-                src += in->stride;
-            }
-        }
-        else // treat all the other formats as monochrome
-        {
-            for (int h = 0; h < height/2; h++)
-            {
-                memset(dst, 0x80, width);
-                dst += out->stride;
-            }
-        }
-        pthread_mutex_unlock(&in->pic_mutex);
-        if (in->index == 0)
-            sem_post(&ctx->sem_done); // Resume input port0.
-        // !Assume output thread is fast enough, so input port0 won't be blocked for long time.
-    }
-
-    return 0;
-}
-
-static void constructYuvInfo(PlinkYuvInfo *info, StitcherParams *params, unsigned int bus_address, int id)
-{
-    int size_y = params->width * params->stride;
-    int size_uv = size_y / 2;
-    int size_yuv = size_y + size_uv;
-    
-    info->header.type = PLINK_TYPE_2D_YUV;
-    info->header.size = DATA_SIZE(*info);
-    info->header.id = id + 1;
-
-    info->format = params->format;
-    info->bus_address_y = bus_address;
-    info->bus_address_u = info->bus_address_y + size_y;
-    info->bus_address_v = info->bus_address_u + (size_uv / 2);
-    info->pic_width = params->width;
-    info->pic_height = params->height;
-    info->stride_y = params->stride;
-    info->stride_u = 
-        params->format == PLINK_COLOR_FormatYUV420Planar ? 
-        params->stride/2 : params->stride;
-    info->stride_v = info->stride_u;
-}
-
-int getBufferCount(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 retreiveSentBuffers(PlinkHandle plink, StitcherPort *port)
-{
-    PlinkStatus sts = PLINK_STATUS_OK;
-    PlinkPacket pkt = {0};
-    while (port->available_bufs < NUM_OF_BUFFERS && sts == PLINK_STATUS_OK)
-    {
-        do
-        {
-            sts = PLINK_recv(plink, port->id, &pkt);
-            int count = getBufferCount(&pkt);
-            if (count > 0)
-            {
-                port->available_bufs += count;
-            }
-        } while (sts == PLINK_STATUS_MORE_DATA);
-    }
-}
-
-static void *input_thread(void *args)
-{
-    StitcherPort *port = (StitcherPort *)args;
-    PlinkHandle plink = NULL;
-    PlinkStatus sts = PLINK_STATUS_OK;
-    void *vmem = port->vmem;
-
-    pthread_mutex_init(&port->pic_mutex, NULL);
-
-    if (PLINK_create(&plink, port->name, PLINK_MODE_CLIENT) != PLINK_STATUS_OK)
-        return NULL;
-
-    do
-    {
-        sts = PLINK_connect_ex(plink, NULL, 1000);
-    } while (sts == PLINK_STATUS_TIMEOUT && *port->exit == 0);
-    if (sts != PLINK_STATUS_OK)
-    {
-        PLINK_close(plink, 0);
-        return NULL;
-    }
-
-    pthread_mutex_lock(port->count_mutex);
-    port->index = *(port->in_count);
-    *(port->in_count) = *(port->in_count) + 1;
-    pthread_mutex_unlock(port->count_mutex);
-
-    PlinkPacket sendpkt = {0};
-    PlinkPacket recvpkt = {0};
-    PlinkMsg msg = {0};
-    VmemParams params;
-    int exitcode = 0;
-    do {
-        sts = PLINK_recv(plink, 0, &recvpkt);
-        if (sts == PLINK_STATUS_ERROR)
-            break;
-
-        for (int i = 0; i < recvpkt.num; i++)
-        {
-            PlinkDescHdr *hdr = (PlinkDescHdr *)(recvpkt.list[i]);
-            if (hdr->type == PLINK_TYPE_2D_YUV || 
-                hdr->type == PLINK_TYPE_2D_RAW)
-            {
-                // return previous buffer to source
-                if (sendpkt.num > 0)
-                {
-                    if (port->index == 0)
-                        sem_wait(port->sem_done);
-                    pthread_mutex_lock(&port->pic_mutex);
-                    if (VMEM_release(vmem, &params) != VMEM_STATUS_OK)
-                        fprintf(stderr, "[STITCHER] ERROR: Failed to release buffer.\n");
-                    sts = PLINK_send(plink, 0, &sendpkt);
-                    if (sts == PLINK_STATUS_ERROR)
-                        break;
-                    if (sendpkt.fd != PLINK_INVALID_FD)
-                        close(sendpkt.fd);
-                    port->available_bufs--;
-                    sendpkt.num = 0;
-                }
-                else
-                    pthread_mutex_lock(&port->pic_mutex);
-
-                memset(&params, 0, sizeof(params));
-                if (recvpkt.fd != PLINK_INVALID_FD)
-                {
-                    params.fd = recvpkt.fd;
-                    if (VMEM_import(vmem, &params) != VMEM_STATUS_OK)
-                        break;
-                    if (VMEM_mmap(vmem, &params) != VMEM_STATUS_OK)
-                        break;
-                }
-
-                if (port->index == 0)
-                    sem_post(port->sem_ready); // signal output thread that one picture is ready
-            }
-
-            if (hdr->type == PLINK_TYPE_2D_YUV)
-            {
-                PlinkYuvInfo *pic = (PlinkYuvInfo *)(recvpkt.list[i]);
-                printf("[STITCHER] Input%d: Received YUV frame %d 0x%010llx from %s: fd %d, %dx%d, stride = luma %d, chroma %d\n", 
-                        port->index, pic->header.id, pic->bus_address_y, port->name, recvpkt.fd,
-                        pic->pic_width, pic->pic_height,
-                        pic->stride_y, pic->stride_u);
-
-                port->buffer = params.vir_address;
-                port->format = pic->format;
-                port->width = pic->pic_width;
-                port->height = pic->pic_height;
-                port->stride = pic->stride_y;
-                port->offset = pic->offset_y;
-                port->offset_uv = pic->offset_u > 0 ? pic->offset_u : (pic->offset_y + pic->pic_height*pic->stride_y);
-            }
-            else if (hdr->type == PLINK_TYPE_2D_RAW)
-            {
-                PlinkRawInfo *img = (PlinkRawInfo *)(recvpkt.list[i]);
-                printf("[STITCHER] Input%d: Received RAW frame %d 0x%010llx from %s: fd %d, %dx%d, stride %d\n", 
-                        port->index, img->header.id, img->bus_address, port->name, recvpkt.fd,
-                        img->img_width, img->img_height, img->stride);
-
-                port->buffer = params.vir_address;
-                port->format = img->format;
-                port->width = img->img_width;
-                port->height = img->img_height;
-                port->stride = img->stride;
-                port->offset = img->offset;
-            }
-            else if (hdr->type == PLINK_TYPE_MESSAGE)
-            {
-                PlinkMsg *msg = (PlinkMsg *)(recvpkt.list[i]);
-                if (msg->msg == PLINK_EXIT_CODE)
-                {
-                    exitcode = 1;
-                    printf("[STITCHER] Input %d: Exit\n", port->index);
-                    break;
-                }
-            }
-
-            if (hdr->type == PLINK_TYPE_2D_YUV ||
-                hdr->type == PLINK_TYPE_2D_RAW)
-            {
-                port->available_bufs++;
-                pthread_mutex_unlock(&port->pic_mutex);
-
-                msg.header.type = PLINK_TYPE_MESSAGE;
-                msg.header.size = DATA_SIZE(PlinkMsg);
-                msg.msg = hdr->id;
-                sendpkt.list[0] = &msg;
-                sendpkt.num = 1;
-                sendpkt.fd = recvpkt.fd;
-            }
-        }
-    } while (exitcode == 0 && *port->exit == 0 && sts != PLINK_STATUS_ERROR);
-
-    if (sendpkt.num > 0)
-    {
-        pthread_mutex_lock(&port->pic_mutex);
-        if (VMEM_release(vmem, &params) != VMEM_STATUS_OK)
-            fprintf(stderr, "[STITCHER] ERROR: Failed to release buffer.\n");
-        sts = PLINK_send(plink, 0, &sendpkt);
-        port->available_bufs--;
-        pthread_mutex_unlock(&port->pic_mutex);
-    }
-
-    if (port->index == 0)
-    {
-        *port->exit = 1;
-        sem_post(port->sem_ready);
-    }
-    msg.header.type = PLINK_TYPE_MESSAGE;
-    msg.header.size = DATA_SIZE(PlinkMsg);
-    msg.msg = PLINK_EXIT_CODE;
-    sendpkt.list[0] = &msg;
-    sendpkt.num = 1;
-    sendpkt.fd = PLINK_INVALID_FD;
-    sts = PLINK_send(plink, 0, &sendpkt);
-    PLINK_close(plink, 0);
-    pthread_mutex_destroy(&port->pic_mutex);
-    return NULL;
-}
-
-int main(int argc, char **argv) {
-    PlinkStatus sts = PLINK_STATUS_OK;
-    StitcherParams params;
-    StitcherContext ctx;
-    PlinkHandle plink = NULL;
-    PlinkPacket pkt = {0};
-    PlinkYuvInfo pic;
-    PlinkMsg msg;
-
-    parseParams(argc, argv, &params);
-    if (checkParams(&params) != 0)
-    {
-        printUsage(argv[0]);
-        return 0;
-    }
-
-    memset(&ctx, 0, sizeof(ctx));
-
-    void *vmem = NULL;
-    if (VMEM_create(&vmem) != VMEM_STATUS_OK)
-        errExit("Failed to create VMEM.");
-
-    int width = params.width;
-    int height = params.height;
-    int stride = params.stride;
-    StitchLayout layout = params.layout;
-    int size = getBufferSize(&params);
-    if (size == 0)
-        errExit("Wrong format or wrong resolution.");
-    PictureBuffer picbuffers[NUM_OF_BUFFERS];
-    AllocateBuffers(picbuffers, size, vmem);
-
-    sem_init(&ctx.sem_ready, 0, 0);
-    sem_init(&ctx.sem_done, 0, 0);
-    pthread_mutex_init(&ctx.count_mutex, NULL);
-
-    pthread_t thread_in[MAX_NUM_OF_INPUTS];
-    pthread_attr_t attr;
-    pthread_attr_init(&attr);
-    for (int i = 0; i < MAX_NUM_OF_INPUTS; i++)
-    {
-        ctx.in[i].name = params.in_name[i];
-        ctx.in[i].count_mutex = &ctx.count_mutex;
-        ctx.in[i].sem_ready = &ctx.sem_ready;
-        ctx.in[i].sem_done = &ctx.sem_done;
-        ctx.in[i].in_count = &ctx.in_count;
-        ctx.in[i].exit = &ctx.exitcode;
-        ctx.in[i].vmem = vmem;
-        if (pthread_create(&thread_in[i], &attr, input_thread, &ctx.in[i]) != 0)
-            fprintf(stderr, "[STITCHER] ERROR: Failed to create thread for input %d\n", i);
-    }
-
-    sts = PLINK_create(&plink, params.out_name, PLINK_MODE_SERVER);
-
-    StitcherPort *out = &ctx.out;
-    out->available_bufs = NUM_OF_BUFFERS;
-    out->count_mutex = &ctx.count_mutex;
-    out->sem_ready = &ctx.sem_ready;
-    out->sem_done = &ctx.sem_done;
-    out->format = params.format;
-    out->layout = params.layout;
-    out->width = params.width;
-    out->height = params.height;
-    out->stride = params.stride;
-    out->offset = 0;
-    out->offset_uv = params.height * params.stride;
-    out->exit = &ctx.exitcode;
-    sts = PLINK_connect(plink, &out->id);
-
-    int exitcode = 0;
-    do {
-        int sendid = out->sendid;
-        out->buffer = picbuffers[sendid].virtual_address;
-        if (stitchOneFrame(&ctx) != 0)
-            break;
-        constructYuvInfo(&pic, &params, picbuffers[sendid].bus_address, sendid);
-        printf("[STITCHER] Processed frame %d 0x%010llx: %dx%d, stride = luma %d, chroma %d\n", 
-                sendid, pic.bus_address_y, 
-                pic.pic_width, pic.pic_height,
-                pic.stride_y, pic.stride_u);
-
-        pkt.list[0] = &pic;
-        pkt.num = 1;
-        pkt.fd = picbuffers[sendid].fd;
-        sts = PLINK_send(plink, out->id, &pkt);
-        out->sendid = (out->sendid + 1) % NUM_OF_BUFFERS;
-        out->available_bufs -= 1;
-
-        int timeout = out->available_bufs == 0 ? 100 : 0;
-        if (PLINK_wait(plink, out->id, timeout) == PLINK_STATUS_OK)
-        {
-            do
-            {
-                sts = PLINK_recv(plink, out->id, &pkt);
-                int count = getBufferCount(&pkt);
-                if (count < 0)
-                    exitcode = 1;
-                out->available_bufs += count;
-            } while (sts == PLINK_STATUS_MORE_DATA);
-        }
-    } while (exitcode == 0);
-
-cleanup:
-    ctx.exitcode = 1;
-    sem_post(&ctx.sem_done);
-    msg.header.type = PLINK_TYPE_MESSAGE;
-    msg.header.size = DATA_SIZE(PlinkMsg);
-    msg.msg = PLINK_EXIT_CODE;
-    pkt.list[0] = &msg;
-    pkt.num = 1;
-    pkt.fd = PLINK_INVALID_FD;
-    sts = PLINK_send(plink, out->id, &pkt);
-    retreiveSentBuffers(plink, out);
-    PLINK_recv_ex(plink, out->id, &pkt, 1000);
-    for (int i = 0; i < MAX_NUM_OF_INPUTS; i++)
-        pthread_join(thread_in[i], NULL);
-    //sleep(1); // Sleep one second to make sure client is ready for exit
-    if (vmem)
-        FreeBuffers(picbuffers, vmem);
-    PLINK_close(plink, PLINK_CLOSE_ALL);
-    VMEM_destroy(vmem);
-    pthread_mutex_destroy(&ctx.count_mutex);
-    sem_destroy(&ctx.sem_ready);
-    sem_destroy(&ctx.sem_done);
-    exit(EXIT_SUCCESS);
-}
-

+ 75 - 0
user_mode/Makefile

@@ -0,0 +1,75 @@
+
+CFLAGS = -Wall -D_GNU_SOURCE -D_REENTRANT -D_THREAD_SAFE -O2 -Werror -Wno-unused -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function -Wno-strict-overflow -Wno-array-bounds -Wno-shift-negative-value -Wempty-body -Wtype-limits -Wno-unused-result -fPIC -Wmissing-field-initializers -std=gnu99
+
+INCLUDE += -I../kernel_mode
+
+SRCS = isp_venc_shake_hal.c
+OBJS = $(SRCS:.c=.o)
+
+#source search path
+vpath %.c
+
+# name of the outputfile (library)
+IVSLIB = libivs.a
+IVSSLIB = libivs.so
+
+#Here are rules for building codes and generating object library.
+all:    tags
+	@echo ---------------------------------------
+	@echo "Usage: make [ system | testdata | versatile | integrator | android]"
+	@echo "system     - PC system model (== pclinux)"
+	@echo "testdata   - PC system model for test data creation"
+	@echo "eval       - PC system model for evaluation with frame limit"
+	@echo "versatile  - ARM versatile with FPGA HW"
+	@echo "integrator - ARM integrator with FPGA HW"
+	@echo "android    - ARM android"
+	@echo "NOTE! Make sure to do 'make clean'"
+	@echo "between compiling to different targets!"
+	@echo ---------------------------------------
+
+.PHONY: system_lib system testdata clean depend
+
+evaluation: eval
+eval: system
+
+system_static: testdata
+system: testdata
+
+# for libva
+system_lib: system
+
+testdata: .depend $(IVSLIB)
+
+
+.PHONY: hwlinux
+hwlinux:
+hwlinux: .depend $(IVSLIB) $(IVSSLIB)
+
+$(IVSLIB): $(OBJS)
+	@echo "[AR] $@"
+	$(AR) rcs $(IVSLIB) $(OBJS)
+
+$(IVSSLIB): $(OBJS)
+	$(CC) -fPIC -Wl,-no-undefined -shared $(CFLAGS) $(OBJS) -lm -lpthread -o $(IVSSLIB)
+
+
+%.o: %.c
+	$(CC) -c $(CFLAGS) $(INCLUDE) $< -o $@
+
+clean:
+	$(RM) $(IVSLIB) $(IVSSLIB)
+	$(RM) .depend
+	$(RM) *.o *.gcno *.gcda
+
+tags:
+	ctags ../kernel_mode/*h ./*[ch]
+
+depend .depend: $(SRCS)
+	@echo "[CC] $@"
+	@$(CC) -M $(DEBFLAGS) $(INCLUDE) $^ > .depend
+
+ifneq (clean, $(findstring clean, $(MAKECMDGOALS)))
+ifeq (.depend, $(wildcard .depend))
+include .depend
+endif
+endif

+ 160 - 0
user_mode/isp_venc_shake_hal.c

@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2021-2022 Alibaba Group. All rights reserved.
+ * License-Identifier: Apache-2.0
+ *
+ * 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.
+ */
+
+#include <stdint.h>
+#include <malloc.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "isp_venc_shake_driver.h"
+#include "isp_venc_shake_hal.h"
+#include <sys/ioctl.h>
+
+#ifndef NULL
+#define NULL    ((void *)0)
+#endif
+
+
+#ifndef IVS_MODULE_PATH
+#define IVS_MODULE_PATH             "/dev/shake"
+#endif
+
+typedef struct _IspVencShake
+{
+    unsigned int fd;
+    struct ivs_parameter params;
+} IspVencShake;
+
+IvsStatus createIspVencShake(void **ivs)
+{
+    IvsStatus status = IVS_STATUS_OK;
+    IspVencShake *shake = NULL;
+    unsigned int fd;
+    
+    shake = (IspVencShake *)malloc(sizeof(IspVencShake));
+    if (NULL == shake)
+        return IVS_STATUS_ERROR;
+
+    fd = open("/dev/shake", O_RDONLY);
+    if (fd == -1)
+    {
+        free(shake);
+        return IVS_STATUS_ERROR;
+    }
+
+    shake->fd = fd;
+    *ivs = shake;
+
+    return status;
+}
+
+IvsStatus configIspVencShake(void *ivs, IvsConfig *config)
+{
+    IvsStatus status = IVS_STATUS_OK;
+    IspVencShake *shake = (IspVencShake *)ivs;
+    struct ivs_parameter *params = NULL;
+    unsigned int buffer_height;
+
+    if (ivs == NULL || config == NULL)
+        return IVS_STATUS_ERROR;
+
+    params = &shake->params;
+    buffer_height = config->mode = IVS_BUFFER_MODE_SLICE ? 
+        config->buffer_height : config->pic_height * 3 / 2;
+
+    params->pic_width = config->pic_width;
+    params->pic_height = config->pic_height;
+    params->encode_width = config->encode_width;
+    params->encode_height = config->encode_height;
+    params->wid_y = 1;
+    params->wid_uv = 2;
+    params->sram_size = config->pic_width * buffer_height;
+    params->encode_n = config->encode == IVS_ENCODER_FORMAT_H264 ? 16 : 64;
+    params->stride_y = config->stride_y;
+    params->stride_uv = config->stride_uv;
+    params->encode_x = config->encode_x;
+    params->encode_y = config->encode_y;
+    params->int_mask = 0;
+
+    if (ioctl(shake->fd, THEAD_IOCH_CONFIG_IVS, params) == -1)
+    {
+        status = IVS_STATUS_ERROR;
+    }
+
+    return status;
+}
+
+IvsStatus startIspVencShake(void *ivs)
+{
+    IvsStatus status = IVS_STATUS_OK;
+    IspVencShake *shake = (IspVencShake *)ivs;
+
+    if (ivs == NULL)
+        return IVS_STATUS_ERROR;
+
+    if (ioctl(shake->fd, THEAD_IOCH_START_IVS, NULL) == -1)
+    {
+        status = IVS_STATUS_ERROR;
+    }
+
+    return status;
+}
+
+IvsStatus resetIspVencShake(void *ivs)
+{
+    IvsStatus status = IVS_STATUS_OK;
+    IspVencShake *shake = (IspVencShake *)ivs;
+
+    if (ivs == NULL)
+        return IVS_STATUS_ERROR;
+
+    if (ioctl(shake->fd, THEAD_IOCH_RESET_IVS, NULL) == -1)
+    {
+        status = IVS_STATUS_ERROR;
+    }
+
+    return status;
+}
+
+IvsStatus getIspVencShakeState(void *ivs, int *state)
+{
+    IvsStatus status = IVS_STATUS_OK;
+    IspVencShake *shake = (IspVencShake *)ivs;
+
+    if (ivs == NULL || state == NULL)
+        return IVS_STATUS_ERROR;
+
+    if (ioctl(shake->fd, THEAD_IOCH_GET_STATE, state) == -1)
+    {
+        status = IVS_STATUS_ERROR;
+    }
+
+    return status;
+}
+
+void destroyIspVencShake(void *ivs)
+{
+    IspVencShake *shake = (IspVencShake *)ivs;
+
+    if (NULL == ivs)
+        return;
+
+    if (shake->fd != -1)
+        close(shake->fd);
+
+    free(ivs);
+}
+

+ 75 - 0
user_mode/isp_venc_shake_hal.h

@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2021-2022 Alibaba Group. All rights reserved.
+ * License-Identifier: Apache-2.0
+ *
+ * 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 _ISP_VENC_SHAKE_HAL_H_
+#define _ISP_VENC_SHAKE_HAL_H_
+
+#ifndef IVS_MODULE_PATH
+#define IVS_MODULE_PATH "/tmp/dev/theadivs"
+#endif
+
+typedef enum _IvsStatus
+{
+    IVS_STATUS_OK = 0,
+    IVS_STATUS_ERROR = -1,
+} IvsStatus;
+
+typedef enum _IvsState
+{
+    IVS_STATE_IDLE,
+    IVS_STATE_READY,
+    IVS_STATE_RUNNING,
+    IVS_STATE_ERROR
+} IvsState;
+
+typedef enum _IvsBufferMode
+{
+    IVS_BUFFER_MODE_FRAME = 0,
+    IVS_BUFFER_MODE_SLICE,
+    IVS_BUFFER_MODE_MAX
+} IvsBufferMode;
+
+typedef enum _IvsEncoderFormat
+{
+    IVS_ENCODER_FORMAT_H264 = 0,
+    IVS_ENCODER_FORMAT_H265,
+    IVS_ENCODER_FORMAT_MAX
+} IvsEncoderFormat;
+
+typedef struct _IvsConfig
+{
+    IvsBufferMode mode;
+    IvsEncoderFormat encode;
+    unsigned int pic_width;
+    unsigned int pic_height;
+    unsigned int encode_width;
+    unsigned int encode_height;
+    unsigned int buffer_height;   // valid in slice buffer mode only
+    unsigned int stride_y;
+    unsigned int stride_uv;
+    unsigned int encode_x;
+    unsigned int encode_y;
+} IvsConfig;
+
+IvsStatus createIspVencShake(void **ivs);
+IvsStatus configIspVencShake(void *ivs, IvsConfig *config);
+IvsStatus startIspVencShake(void *ivs);
+IvsStatus resetIspVencShake(void *ivs);
+IvsStatus getIspVencShakeState(void *ivs, int *state);
+void destroyIspVencShake(void *ivs);
+
+#endif /* !_ISP_VENC_SHAKE_HAL_H_ */

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