am_ca: add am_ca_key_test for roku t5d project [1/1]

PD#SWPL-135053

Problem:
add am_ca for t5d

Solution:
add am_ca_t5d

Verify:
verified at t5d

Change-Id: Ifb4f1e2dd3936eee9ad76954a714db719cd10284
Signed-off-by: chuangcheng peng <chuangcheng.peng@amlogic.com>
diff --git a/test/am_ca_key_test/Android.bp b/test/am_ca_key_test/Android.bp
new file mode 100644
index 0000000..65cc11e
--- /dev/null
+++ b/test/am_ca_key_test/Android.bp
@@ -0,0 +1,40 @@
+package {
+    // See: http://go/android-license-faq
+    default_applicable_licenses: [
+        "Android-Apache-2.0",
+    ],
+}
+
+cc_binary {
+    name: "am_ca_key_test",
+    vendor: true,
+
+    srcs: [
+        "am_ca_t5d.c",
+		"inject_record_t5d/am_dmx/am_dmx.c",
+		"inject_record_t5d/am_dmx/linux_dvb/linux_dvb.c",
+		"inject_record_t5d/am_dvr/am_dvr.c",
+		"inject_record_t5d/am_dvr/linux_dvb/linux_dvb.c",
+		"inject_record_t5d/am_av/am_av.c",
+		"inject_record_t5d/am_av/aml/aml.c",
+		"inject_record_t5d/am_misc/am_misc.c",
+		"inject_record_t5d/am_misc/am_adplock.c",
+		"inject_record_t5d/am_tfile/am_tfile.c",
+		"inject_record_t5d/am_time/am_time.c",
+		"inject_record_t5d/am_inject_record.c",
+		"am_ca_key_test.c",
+    ],
+
+    //LOCAL_MULTILIB := 32
+
+    cflags: [
+        "-DANDROID",
+        "-DAMLINUX",
+    ],
+
+    local_include_dirs: [
+      "inject_record_t5d/include/am_adp",
+	  "inject_record_t5d/include/ndk/include/linux",
+    ],
+    shared_libs: ["libc"],
+}
diff --git a/test/am_ca_key_test/Android.mk b/test/am_ca_key_test/Android.mk
new file mode 100644
index 0000000..0dd24e2
--- /dev/null
+++ b/test/am_ca_key_test/Android.mk
@@ -0,0 +1,33 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_VENDOR_MODULE := true
+
+LOCAL_SRC_FILES:= am_ca_key_test.c am_ca_t5d.c
+		inject_record_t5d/am_dmx/am_dmx.c
+		inject_record_t5d/am_dmx/linux_dvb/linux_dvb.c
+		inject_record_t5d/am_dvr/am_dvr.c
+		inject_record_t5d/am_dvr/linux_dvb/linux_dvb.c
+		inject_record_t5d/am_av/am_av.c
+		inject_record_t5d/am_av/aml/aml.c
+		inject_record_t5d/am_misc/am_misc.c
+		inject_record_t5d/am_misc/am_adplock.c
+		inject_record_t5d/am_tfile/am_tfile.c
+		inject_record_t5d/am_time/am_time.c
+		inject_record_t5d/am_inject_record.c
+
+LOCAL_MODULE:= am_ca_key_test
+LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
+LOCAL_LICENSE_CONDITIONS := notice
+
+LOCAL_MODULE_TAGS := optional
+
+#LOCAL_MULTILIB := 32
+
+LOCAL_CFLAGS+=-DANDROID -DAMLINUX
+#LOCAL_C_INCLUDES :=  $(LOCAL_PATH)/../../android/ndk/include
+
+LOCAL_SHARED_LIBRARIES :=  libc
+
+include $(BUILD_EXECUTABLE)
+
diff --git a/test/am_ca_key_test/Makefile b/test/am_ca_key_test/Makefile
new file mode 100644
index 0000000..6ec1d0a
--- /dev/null
+++ b/test/am_ca_key_test/Makefile
@@ -0,0 +1,26 @@
+CROSS_COMPILE:=/opt/gcc-linaro-6.3.1-2017.02-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-
+#export CROSS_COMPILE=/opt/gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
+CC=$(CROSS_COMPILE)gcc
+STRIP=$(CROSS_COMPILE)strip
+
+OUTPUT = am_ca_test
+
+OBJS = $(patsubst %.c,%.o,$(SRC_FILES))
+
+SRC_FILES = am_ca_test.c am_inject.c am_dmx.c linux_dvb.c am_ca.c am_key.c
+
+CFLAGS := -c -Wall
+
+LDFLAGS := -static -lpthread -lc
+
+all : $(OBJS) $(OUTPUT)
+
+$(OBJS) : %.o : %.c
+    $(CC) $(CFLAGS) -c $< -o $@
+
+$(OUTPUT) : $(OBJS)
+    $(CC) -o $@ $^ $(LDFLAGS)
+    $(STRIP) $(OUTPUT)
+
+clean:
+    @rm -f $(OBJS)
diff --git a/test/am_ca_key_test/am_ca.h b/test/am_ca_key_test/am_ca.h
new file mode 100644
index 0000000..4f0bef3
--- /dev/null
+++ b/test/am_ca_key_test/am_ca.h
@@ -0,0 +1,112 @@
+#ifndef _AM_CA_H_
+#define _AM_CA_H_
+
+#ifdef CA_TYPES
+
+/**Descrambling algorithm.*/
+enum ca_sc2_algo_type {
+    CA_ALGO_AES_ECB_CLR_END,    /**< AES ECB clear end.*/
+    CA_ALGO_AES_ECB_CLR_FRONT,  /**< AES ECB clear head.*/
+    CA_ALGO_AES_CBC_CLR_END,    /**< AES CBC clear end.*/
+    CA_ALGO_AES_CBC_IDSA,       /**< IDSA.*/
+    CA_ALGO_CSA2,               /**< DVB-CSA2.*/
+    CA_ALGO_DES_SCTE41,         /**< DES SCTE41.*/
+    CA_ALGO_DES_SCTE52,         /**< DES SCTE52.*/
+    CA_ALGO_TDES_ECB_CLR_END,   /**< TDES ECB clear end.*/
+    CA_ALGO_CPCM_LSA_MDI_CBC,   /**< CPCM LSA MDI CBC.*/
+    CA_ALGO_CPCM_LSA_MDD_CBC,   /**< CPCM LSA MDD CBC.*/
+    CA_ALGO_CSA3,               /**< DVB-CSA3*/
+    CA_ALGO_ASA,                /**< ASA.*/
+    CA_ALGO_ASA_LIGHT,          /**< ASA light.*/
+    CA_ALGO_S17_ECB_CLR_END,    /**< S17 ECB clear end.*/
+    CA_ALGO_S17_ECB_CTS,        /**< S17 ECB CTS.*/
+    CA_ALGO_UNKNOWN
+};
+
+/**Descrambler hardware module type for T5W.*/
+enum ca_sc2_dsc_type {
+    CA_DSC_COMMON_TYPE, /**< TSN module.*/
+    CA_DSC_TSD_TYPE,    /**< TSD module..*/
+    CA_DSC_TSE_TYPE     /**< TSE module.*/
+};
+
+/**Key's parity type.*/
+enum ca_sc2_key_type {
+    CA_KEY_EVEN_TYPE,    /**< Even key.*/
+    CA_KEY_EVEN_IV_TYPE, /**< IV data for even key.*/
+    CA_KEY_ODD_TYPE,     /**< Odd key.*/
+    CA_KEY_ODD_IV_TYPE,  /**< IV data for odd key.*/
+    CA_KEY_00_TYPE,      /**< Key for packets' scrambling control flags == 00.*/
+    CA_KEY_00_IV_TYPE    /**< IV data for packets' scrambling control flags == 00.*/
+};
+
+#endif /*CA_TYPES*/
+
+/**
+ * Open the CA(descrambler) device.
+ * \param devno The CA device number.
+ * \retval 0 On success.
+ * \retval -1 On error.
+ */
+int ca_open(int devno);
+
+/**
+ * Allocate a descrambler channel from the device.
+ * \param devno The CA device number.
+ * \param pid The descrambled elementary stream's PID of this channel.
+ * \param algo The descrambling algorithm.
+ * This parameter is defined as "enum ca_sc2_algo_type".
+ * \param dsc_type The descrambler hardware module type for T5W.
+ * This parameter is defined as "enum ca_sc2_dsc_type".
+ * This parameter is not used on T5D.
+ * \return The allocated descrambler channel's index.
+ * \retval -1 On error.
+ */
+int ca_alloc_chan(int devno, unsigned int pid, int algo, int dsc_type);
+
+/**
+ * Free an unused descrambler channel.
+ * \param devno the CA device number.
+ * \param chan_index The descrambler channel's index to be freed.
+ * The index is allocated by the function ca_alloc_chan.
+ * \retval 0 On success.
+ * \retval -1 On error.
+ */
+int ca_free_chan(int devno, int chan_index);
+
+/**
+ * Set the key to the descrambler channel.
+ * \param devno The CA device number.
+ * \param chan_index The descrambler channel's index to be set.
+ * The index is allocated by the function ca_alloc_chan.
+ * \param parity The key's parity.
+ * This parameter is defined as "enum ca_sc2_key_type".
+ * \param key_handle The key's handle.
+ * The key is allocated and set by the CAS/CI+ TA.
+ * \retval 0 On success.
+ * \retval -1 On error.
+ */
+int ca_set_key(int devno, int chan_index, int parity, int key_handle);
+
+/**
+ * Set the key to the descrambler channel.
+ * \param devno The CA device number.
+ * \param chan_index The descrambler channel's index to be set.
+ * The index is allocated by the function ca_alloc_chan.
+ * \param parity The key's parity.
+ * \param key_len The key's length.
+ * \param key The key's content.
+ * \retval 0 On success.
+ * \retval -1 On error.
+ */
+int ca_set_cw_key(int devno, int chan_index, int parity, int key_len, char *key);
+
+/**
+ * Close the CA device.
+ * \param devno The CA device number.
+ * \retval 0 On success.
+ * \retval -1 On error.
+ */
+int ca_close(int devno);
+
+#endif
diff --git a/test/am_ca_key_test/am_ca_key_test.c b/test/am_ca_key_test/am_ca_key_test.c
new file mode 100644
index 0000000..b949273
--- /dev/null
+++ b/test/am_ca_key_test/am_ca_key_test.c
@@ -0,0 +1,245 @@
+#ifdef _FORTIFY_SOURCE
+#undef _FORTIFY_SOURCE
+#endif
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+
+ */
+/**\file
+ * \brief 解扰器测试程序
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-10-08: create the document
+ ***************************************************************************/
+
+#define AM_DEBUG_LEVEL 5
+
+#include <ca.h>
+#include <am_ca.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "fcntl.h"
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+/****************************************************************************
+ * API functions
+ ***************************************************************************/
+
+extern int inject_file_and_rec_open(char *inject_name,int vpid, int apid, char *record_name);
+extern int inject_file_and_rec_close(void);
+
+int main(int argc, char **argv)
+{
+	int dsccv, dscca;
+	int vpid=0, apid=0;
+	char buf[1024];
+	char *p = buf;
+	int dsc = 0, src = 0;
+	int ret;
+	int aes = 0, des = 0, sm4 = 0,iv = 0;
+	int odd_type = CA_KEY_ODD_TYPE;
+	int even_type = CA_KEY_EVEN_TYPE;
+	int odd_iv_type = 0;
+	int even_iv_type = 0;
+	char inject_name[256];
+	int inject_file = 0;
+	char record_name[256];
+	int record_file = 0;
+	int mode = 0;
+	int v_chan_index = 0;
+	int a_chan_index = 0;
+
+	int i;
+	for (i = 1; i < argc; i++) {
+		if (!strncmp(argv[i], "vid", 3))
+			sscanf(argv[i], "vid=%i", &vpid);
+		else if (!strncmp(argv[i], "aid", 3))
+			sscanf(argv[i], "aid=%i", &apid);
+		else if (!strncmp(argv[i], "dsc", 3))
+			sscanf(argv[i], "dsc=%i", &dsc);
+		else if (!strncmp(argv[i], "src", 3))
+			sscanf(argv[i], "src=%i", &src);
+		else if (!strncmp(argv[i], "aes", 3))
+			aes = 1;
+		else if (!strncmp(argv[i], "des", 3))
+			des = 1;
+		else if (!strncmp(argv[i], "sm4", 3))
+			sm4 = 1;
+		else if (!strncmp(argv[i], "mode", 4))
+			sscanf(argv[i],"mode=%i", &mode);
+		else if (!strncmp(argv[i], "inject", 6)) {
+			memset(inject_name, 0, sizeof(inject_name));
+			sscanf(argv[i], "inject=%s", &inject_name);
+			inject_file = 1;
+		}
+		else if (!strncmp(argv[i], "rec", 3)) {
+			memset(record_name, 0, sizeof(record_name));
+			sscanf(argv[i], "rec=%s", &record_name);
+			record_file = 1;
+		}
+		else if (!strncmp(argv[i], "help", 4)) {
+			printf("Usage: %s [vid=pid] [aid=pid] [dsc=n] [src=n] [aes|des|sm4] [mode=0/1/2,0:ecb,1:cbc,2:idsa]\n", argv[0]);
+			printf("\t [inject=xxx] [rec=xxx] \n");
+			printf("\t inject file and record for verify the descram function \n");
+			printf("\t if no v/a specified, will set to current running v/a\n");
+			exit(0);
+		}
+	}
+
+	printf("use dsc[%d] src[%d]\n", dsc, src);
+	if (aes) {
+		printf("aes mode\n");
+	} else if (des) {
+		printf("des mode\n");
+	} else if (sm4) {
+		printf("sm4 mode\n");
+	} else {
+		printf("csa mode\n");
+	}
+
+	ret = ca_open(dsc);
+	if (ret != 0)
+		goto end;
+
+	printf("DSC [%d] Set Source [%d]\n", dsc, src);
+#if 0
+	ret = AM_DSC_SetSource(dsc, src);
+	if(src==AM_DSC_SRC_BYPASS)
+		goto end;
+#endif
+	if(vpid>0 || apid>0) {
+		char aes_key_ecb[16] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
+		char aes_key_cbc_iv[16] = {0x49, 0x72, 0x64, 0x65, 0x74, 0x6F, 0xA9, 0x43, 0x6F,0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74};
+//		char aes_key_cbc_iv[16] = {0};
+		char aes_key_cbc[16] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
+		char aes_key_cbc_isda[16] = { 0xb2, 0x8e, 0xd9, 0x82, 0x9d, 0x91, 0xe6, 0x5d,0x8c, 0x15, 0x33, 0x51, 0xf7, 0x67, 0x0d, 0x4a};
+		char aes_key_cbc_isda_iv[16] = {0};
+
+		char sm4_ecb_key[16] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10};
+		char sm4_cbc_key[16] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10};
+		char sm4_cbc_key_iv[16] = {0};
+		char sm4_isda_key[16] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10};;
+		char sm4_isda_key_iv[16] = {0};
+
+		char des_key[8] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
+		/*char csa_key[8] = {0x11, 0x22, 0x33, 0x66, 0x55, 0x66, 0x77, 0x32};*/
+		//char csa_key[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
+		char csa_key_odd[8] = {0xe6, 0x2a, 0x3b, 0x4b, 0xd0, 0x0e, 0x38, 0x16};
+		char csa_key_even[8] = {0xe6, 0x3c, 0x7c, 0x9e, 0x00, 0x43, 0xc6, 0x09};
+
+		char *odd_key = NULL;
+		char *even_key = NULL;
+		char *key_iv = NULL;
+		int algo = 0;
+		int key_len = 0;
+
+		if (aes) {
+			if (mode == 0) {
+				algo = CA_ALGO_AES_ECB_CLR_END;
+				odd_key = aes_key_ecb;
+				even_key = aes_key_ecb;
+				key_len = 16;
+				printf("use AES ecb key\n");
+			} else if (mode == 1) {
+				algo = CA_ALGO_AES_CBC_CLR_END;
+				odd_key = aes_key_cbc;
+				even_key = aes_key_cbc;
+				key_iv = aes_key_cbc_iv;
+				odd_iv_type = CA_KEY_ODD_IV_TYPE;
+				even_iv_type = CA_KEY_EVEN_IV_TYPE;
+				key_len = 16;
+				printf("use AES cbc key\n");
+			} else if (mode == 2 ) {
+				algo = CA_ALGO_AES_CBC_IDSA;
+				odd_key = aes_key_cbc_isda;
+				even_key = aes_key_cbc_isda;
+				key_iv = aes_key_cbc_isda_iv;
+				printf("use AES isda key\n");
+				odd_iv_type = CA_KEY_ODD_IV_TYPE;
+				even_iv_type = CA_KEY_EVEN_IV_TYPE;
+				key_len = 16;
+			} else {
+				printf("mode is invalid\n");
+				return -1;
+			}
+		} else if (des) {
+			algo = CA_ALGO_DES_SCTE41;
+			odd_key = des_key;
+			even_key = des_key;
+			key_len = 8;
+			printf("use DES key\n");
+		} else {
+			algo = CA_ALGO_CSA2;
+			odd_key = csa_key_odd;
+			even_key = csa_key_even;
+			printf("use CSA key\n");
+			key_len = 16;
+		}
+
+#define AM_CHECK_ERR(_x) do {\
+		int ret = (_x);\
+		if (ret != 0)\
+			printf("ERROR (0x%x) %s\n", ret, #_x);\
+	} while(0)
+
+		if(vpid>0) {
+			v_chan_index = ca_alloc_chan(dsc, vpid, algo, CA_DSC_COMMON_TYPE);
+			if (v_chan_index < 0)
+				goto end;
+			if (key_iv)
+			{
+				AM_CHECK_ERR(ca_set_cw_key(dsc, v_chan_index, odd_iv_type, key_len, (char*)key_iv));
+				AM_CHECK_ERR(ca_set_cw_key(dsc, v_chan_index, even_iv_type, key_len, (char*)key_iv));
+			}
+			AM_CHECK_ERR(ca_set_cw_key(dsc, v_chan_index, odd_type, key_len, (char*)odd_key));
+			AM_CHECK_ERR(ca_set_cw_key(dsc, v_chan_index, even_type, key_len, (char*)even_key));
+			printf("set default key for pid[%d]\n", vpid);
+		}
+		if(apid>0) {
+			v_chan_index = ca_alloc_chan(dsc, apid, algo, CA_DSC_COMMON_TYPE);
+			if (v_chan_index < 0)
+				goto end;
+			if (key_iv)
+			{
+				AM_CHECK_ERR(ca_set_cw_key(dsc, a_chan_index, odd_iv_type, key_len, (char*)key_iv));
+				AM_CHECK_ERR(ca_set_cw_key(dsc, a_chan_index, even_iv_type, key_len, (char*)key_iv));
+			}
+			AM_CHECK_ERR(ca_set_cw_key(dsc, a_chan_index, odd_type, key_len, (char*)odd_key));
+			AM_CHECK_ERR(ca_set_cw_key(dsc, a_chan_index, even_type, key_len, (char*)even_key));
+			printf("set default key for pid[%d]\n", apid);
+		}
+
+		if (inject_file) {
+			inject_file_and_rec_open(inject_name,vpid,apid,record_file ? record_name:NULL);
+		}
+
+		while(fgets(buf, 256, stdin))
+		{
+			if(!strncmp(buf, "quit", 4))
+			{
+				goto end;
+			}
+		}
+	} else {
+		printf("No A/V playing.\n");
+	}
+
+end:
+	ca_free_chan(dsc, v_chan_index);
+	ca_free_chan(dsc, a_chan_index);
+	ca_close(dsc);
+	if (inject_file)
+		inject_file_and_rec_close();
+
+	printf("all exit\n");
+	return 0;
+}
diff --git a/test/am_ca_key_test/am_ca_t5d.c b/test/am_ca_key_test/am_ca_t5d.c
new file mode 100644
index 0000000..aca40a7
--- /dev/null
+++ b/test/am_ca_key_test/am_ca_t5d.c
@@ -0,0 +1,458 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <pthread.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include "ca.h"
+#include "am_ca.h"
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+//#define DEV_NAME "/dev/dvb/adapter0/ca"
+#define DEV_NAME "/dev/dvb0.ca"
+#define MAX_DSC_DEV         2
+#define DSC_CHANNEL_COUNT	8
+
+/****************************************************************************
+ * Static data
+ ***************************************************************************/
+typedef struct _dsc_channel {
+	int used;
+	int pid;
+	int algo;
+	int dsc_type;
+} dsc_channel;
+
+typedef struct _dsc_dev{
+	int used;
+	int fd;
+	dsc_channel channels[DSC_CHANNEL_COUNT];
+	int ref;
+} dsc_dev;
+
+static dsc_dev rec_dsc_dev[MAX_DSC_DEV];
+static pthread_mutex_t devLock  = PTHREAD_MUTEX_INITIALIZER;
+
+/****************************************************************************
+ * API functions
+ ***************************************************************************/
+#define LOG_ALL			0
+#define LOG_INFO		1
+#define LOG_DEBUG		2
+#define LOG_ERROR		3
+
+static int print_level = LOG_ALL;
+
+#define am_ca_pr(level, x...) \
+	do { \
+		if ((level) >= print_level) \
+			printf(x); \
+	} while (0)
+
+/**
+ * Open the CA(descrambler) device.
+ * \param devno The CA device number.
+ * \retval 0 On success.
+ * \retval -1 On error.
+ */
+int ca_open (int devno)
+{
+	int fd;
+	char buf[32];
+	static int init_flag = 0;
+	dsc_dev *pdev = NULL;
+	int i = 0;
+
+	am_ca_pr(LOG_DEBUG,"ca_open enter\n");
+	if (devno >= MAX_DSC_DEV || devno < 0)
+		return -1;
+	pthread_mutex_lock(&devLock);
+	if (!init_flag) {
+		init_flag = 1;
+		memset(&rec_dsc_dev, 0, sizeof(rec_dsc_dev));
+		for (i = 0; i < MAX_DSC_DEV; i++)
+			rec_dsc_dev[i].fd = -1;
+	}
+	pdev = &rec_dsc_dev[devno];
+	if (pdev->used) {
+		pdev->ref++;
+		pthread_mutex_unlock(&devLock);
+		return 0;
+	}
+
+	snprintf(buf, sizeof(buf), DEV_NAME"%d", devno);
+	fd = open(buf, O_RDWR);
+	if (fd == -1)
+	{
+		am_ca_pr(LOG_ERROR, "cannot open \"%s\" (%d:%s)", DEV_NAME, errno, strerror(errno));
+		pthread_mutex_unlock(&devLock);
+		return 0;
+	}
+	pdev->fd = fd;
+	pdev->used = 1;
+	pdev->ref++;
+	pthread_mutex_unlock(&devLock);
+	return 0;
+}
+
+/**
+ * Allocate a descrambler channel from the device.
+ * \param devno The CA device number.
+ * \param pid The descrambled elementary stream's PID of this channel.
+ * \param algo The descrambling algorithm.
+ * This parameter is defined as "enum ca_sc2_algo_type".
+ * \param dsc_type The descrambler hardware module type for T5W.
+ * This parameter is defined as "enum ca_sc2_dsc_type".
+ * This parameter is not used on T5D.
+ * \return The allocated descrambler channel's index.
+ * \retval -1 On error.
+ */
+int ca_alloc_chan (int devno, unsigned int pid, int algo, int dsc_type)
+{
+	int i = 0;
+	dsc_dev *pdev = NULL;
+	dsc_channel *pchan = NULL;
+	struct ca_pid pi;
+
+	am_ca_pr(LOG_DEBUG,"ca_alloc_chan enter\n");
+
+	if (devno >= MAX_DSC_DEV || devno < 0) {
+		am_ca_pr(LOG_ERROR,"dev no invalid\n");
+		return -1;
+	}
+	if (algo != CA_ALGO_AES_CBC_CLR_END &&
+		algo != CA_ALGO_DES_SCTE41 &&
+		algo != CA_ALGO_DES_SCTE52) {
+		am_ca_pr(LOG_ERROR,"algo invalid\n");
+		return -1;
+	}
+	if (dsc_type != CA_DSC_COMMON_TYPE) {
+		am_ca_pr(LOG_ERROR,"dsc_type use CA_DSC_COMMON_TYPE\n");
+		return -1;
+	}
+
+	pthread_mutex_lock(&devLock);
+	pdev = &rec_dsc_dev[devno];
+	if (!pdev->used) {
+		pthread_mutex_unlock(&devLock);
+		am_ca_pr(LOG_ERROR,"please call open first\n");
+		return -1;
+	}
+
+	for (i = 0; i < DSC_CHANNEL_COUNT; i++) {
+		if (!pdev->channels[i].used) {
+			pchan = &pdev->channels[i];
+			break;
+		}
+	}
+
+	if (i == DSC_CHANNEL_COUNT) {
+		pthread_mutex_unlock(&devLock);
+		am_ca_pr(LOG_ERROR,"ca chan is full\n");
+		return -1;
+	}
+	pchan->used = 1;
+	pchan->pid = pid;
+
+	pi.index = i;
+	pi.pid = pid;
+	am_ca_pr(LOG_DEBUG,"call CA_SET_PID\n");
+	if (ioctl(pdev->fd, CA_SET_PID, &pi) == -1) {
+		am_ca_pr(LOG_ERROR,"set pid failed \"%s\"", strerror(errno));
+		pchan->used = 0;
+		pthread_mutex_unlock(&devLock);
+		return -1;
+	}
+
+	pchan->algo = algo;
+	pchan->dsc_type = dsc_type;
+	pthread_mutex_unlock(&devLock);
+	am_ca_pr(LOG_DEBUG,"ca_alloc_chan exit\n");
+	return i + devno * DSC_CHANNEL_COUNT;
+}
+
+/**
+ * Free an unused descrambler channel.
+ * \param devno the CA device number.
+ * \param chan_index The descrambler channel's index to be freed.
+ * The index is allocated by the function ca_alloc_chan.
+ * \retval 0 On success.
+ * \retval -1 On error.
+ */
+int ca_free_chan (int devno, int chan_index)
+{
+	dsc_dev *pdev = NULL;
+	int index = 0;
+	struct ca_pid pi;
+
+	am_ca_pr(LOG_DEBUG,"ca_free_chan enter\n");
+
+	if (devno >= MAX_DSC_DEV || devno < 0) {
+		am_ca_pr(LOG_ERROR,"ca_free chan dev invalid:%d\n", devno);
+		return -1;
+	}
+	index = chan_index - devno * DSC_CHANNEL_COUNT;
+	if (index < 0 || index > DSC_CHANNEL_COUNT) {
+		am_ca_pr(LOG_ERROR,"ca_free chan index invalid:%d\n", chan_index);
+		return -1;
+	}
+
+	pthread_mutex_lock(&devLock);
+	pdev = &rec_dsc_dev[devno];
+	if (!pdev->used) {
+		pthread_mutex_unlock(&devLock);
+		am_ca_pr(LOG_ERROR,"ca_free device no open\n");
+		return -1;
+	}
+	if (!pdev->channels[index].used) {
+		pthread_mutex_unlock(&devLock);
+		am_ca_pr(LOG_ERROR, "ca_free have been closed\n");
+		return -1;
+	}
+	pi.index = index;
+	pi.pid = -1;
+	if (ioctl(pdev->fd, CA_SET_PID, &pi) == -1) {
+		am_ca_pr(LOG_ERROR,"free chan failed \"%s\"", strerror(errno));
+		pthread_mutex_unlock(&devLock);
+		return -1;
+	}
+	pdev->channels[index].used = 0;
+	pthread_mutex_unlock(&devLock);
+	am_ca_pr(LOG_DEBUG,"ca_free_chan exit\n");
+
+	return 0;
+}
+
+/**
+ * Set the key to the descrambler channel.
+ * \param devno The CA device number.
+ * \param chan_index The descrambler channel's index to be set.
+ * The index is allocated by the function ca_alloc_chan.
+ * \param parity The key's parity.
+ * This parameter is defined as "enum ca_sc2_key_type".
+ * \param key_handle The key's handle.
+ * The key is allocated and set by the CAS/CI+ TA.
+ * \retval 0 On success.
+ * \retval -1 On error.
+ */
+int ca_set_key (int devno, int chan_index, int parity, int key_handle)
+{
+	dsc_dev *pdev = NULL;
+	int index = 0;
+	int fd;
+	dsc_channel *pchan = NULL;
+	struct ca_descr_ex param;
+	int alg_type = 0;
+	int mode = 0;
+
+	(void)key_handle;
+
+	am_ca_pr(LOG_DEBUG,"ca_set_key enter\n");
+
+	if (devno >= MAX_DSC_DEV || devno < 0) {
+		am_ca_pr(LOG_ERROR,"ca_set_key chan dev invalid:%d\n", devno);
+		return -1;
+	}
+
+	index = chan_index - devno * DSC_CHANNEL_COUNT;
+	if (index < 0 || index > DSC_CHANNEL_COUNT) {
+		am_ca_pr(LOG_ERROR,"ca_set_key chan index invalid:%d\n", chan_index);
+		return -1;
+	}
+
+	pthread_mutex_lock(&devLock);
+	pdev = &rec_dsc_dev[devno];
+	if (!pdev->used) {
+		pthread_mutex_unlock(&devLock);
+		am_ca_pr(LOG_ERROR, "ca_set_key device no open\n");
+		return -1;
+	}
+	pchan = &pdev->channels[index];
+	if (!pchan->used) {
+		pthread_mutex_unlock(&devLock);
+		am_ca_pr(LOG_ERROR, "ca_set_key chan invalid\n");
+		return -1;
+	}
+
+	if (pchan->algo == CA_ALGO_AES_CBC_CLR_END) {
+		mode = CA_DSC_CBC;
+		if (parity ==  CA_KEY_EVEN_TYPE)
+			alg_type = CA_CW_AES_EVEN;
+		else if (parity ==  CA_KEY_ODD_TYPE)
+			alg_type = CA_CW_AES_ODD;
+		else if (parity == CA_KEY_EVEN_IV_TYPE)
+			alg_type = CA_CW_AES_EVEN_IV;
+		else if (parity == CA_KEY_ODD_IV_TYPE)
+			alg_type = CA_CW_AES_ODD_IV;
+		else
+			goto error;
+	} else {
+		mode = CA_DSC_ECB;
+		if (parity == CA_KEY_EVEN_TYPE)
+			alg_type = CA_CW_DES_EVEN;
+		else if (parity == CA_KEY_ODD_TYPE)
+			alg_type = CA_CW_DES_ODD;
+		else
+			goto error;
+	}
+
+	fd = pdev->fd;
+	memset(&param,0,sizeof(struct ca_descr_ex));
+	param.index = index;
+	param.flags = CA_CW_FROM_KL;
+	param.type = alg_type;
+	param.mode = mode;
+	if (ioctl(fd, CA_SET_DESCR_EX, &param) == -1) {
+		am_ca_pr(LOG_ERROR, "ca_set_key ioctl fail %s\n", strerror(errno));
+		goto error;
+	}
+	pthread_mutex_unlock(&devLock);
+	am_ca_pr(LOG_DEBUG,"ca_set_key exit\n");
+	return 0;
+
+error:
+	am_ca_pr(LOG_ERROR, "ca_set_key fail\n");
+	pthread_mutex_unlock(&devLock);
+	return -1;
+}
+
+/**
+ * Set the key to the descrambler channel.
+ * \param devno The CA device number.
+ * \param chan_index The descrambler channel's index to be set.
+ * The index is allocated by the function ca_alloc_chan.
+ * \param parity The key's parity.
+ * \param key_len The key's length.
+ * \param key The key's content.
+ * \retval 0 On success.
+ * \retval -1 On error.
+ */
+int ca_set_cw_key(int devno, int chan_index, int parity, int key_len, char *key)
+{
+	dsc_dev *pdev = NULL;
+	int index = 0;
+	int fd;
+	dsc_channel *pchan = NULL;
+	struct ca_descr_ex param;
+	int alg_type = 0;
+	int mode = 0;
+	int max_key_len = 16;
+	int i = 0;
+
+	am_ca_pr(LOG_DEBUG,"ca_set_cw_key enter, key_len:%d\n", key_len);
+	for (i = 0; i < key_len; i++)
+		am_ca_pr(LOG_DEBUG,"0x%0x ", key[i]);
+	am_ca_pr(LOG_DEBUG,"\n");
+
+	if (devno >= MAX_DSC_DEV || devno < 0) {
+		am_ca_pr(LOG_ERROR,"ca_set_cw_key chan dev invalid:%d\n", devno);
+		return -1;
+	}
+
+	index = chan_index - devno * DSC_CHANNEL_COUNT;
+	if (index < 0 || index > DSC_CHANNEL_COUNT) {
+		am_ca_pr(LOG_ERROR,"ca_set_cw_key chan index invalid:%d\n", chan_index);
+		return -1;
+	}
+
+	pthread_mutex_lock(&devLock);
+	pdev = &rec_dsc_dev[devno];
+	if (!pdev->used) {
+		am_ca_pr(LOG_ERROR, "ca_set_cw_key device no open\n");
+		pthread_mutex_unlock(&devLock);
+		return -1;
+	}
+	pchan = &pdev->channels[index];
+	if (!pchan->used) {
+		am_ca_pr(LOG_ERROR, "ca_set_key chan invalid\n");
+		pthread_mutex_unlock(&devLock);
+		return -1;
+	}
+	if (pchan->algo == CA_ALGO_AES_CBC_CLR_END) {
+		mode = CA_DSC_CBC;
+		if (parity ==  CA_KEY_EVEN_TYPE)
+			alg_type = CA_CW_AES_EVEN;
+		else if (parity ==  CA_KEY_ODD_TYPE)
+			alg_type = CA_CW_AES_ODD;
+		else if (parity == CA_KEY_EVEN_IV_TYPE)
+			alg_type = CA_CW_AES_EVEN_IV;
+		else if (parity == CA_KEY_ODD_IV_TYPE)
+			alg_type = CA_CW_AES_ODD_IV;
+		else
+			goto error;
+	} else {
+		mode = CA_DSC_ECB;
+		if (parity == CA_KEY_EVEN_TYPE)
+			alg_type = CA_CW_DES_EVEN;
+		else if (parity == CA_KEY_ODD_TYPE)
+			alg_type = CA_CW_DES_ODD;
+		else
+			goto error;
+	}
+
+	fd = pdev->fd;
+	memset(&param,0,sizeof(struct ca_descr_ex));
+	if (key_len < max_key_len)
+		max_key_len = key_len;
+
+	memcpy(param.cw, key, max_key_len);
+	param.index = index;
+	param.flags = 0;
+	param.type = alg_type;
+	param.mode = mode;
+	if (ioctl(fd, CA_SET_DESCR_EX, &param) == -1) {
+		am_ca_pr(LOG_ERROR, "ca_set_cw_key ioctl fail %s\n", strerror(errno));
+		goto error;
+	}
+	pthread_mutex_unlock(&devLock);
+	am_ca_pr(LOG_DEBUG,"ca_set_cw_key exit\n");
+	return 0;
+
+error:
+	am_ca_pr(LOG_ERROR, "ca_set_cw_key ioctl fail\n");
+	pthread_mutex_unlock(&devLock);
+	return -1;
+}
+
+/**
+ * Close the CA device.
+ * \param devno The CA device number.
+ * \retval 0 On success.
+ * \retval -1 On error.
+ */
+int ca_close (int devno)
+{
+	int fd;
+	dsc_dev *pdev = NULL;
+
+	am_ca_pr(LOG_DEBUG,"ca_close enter\n");
+	if (devno >= MAX_DSC_DEV || devno < 0)
+		return -1;
+	pthread_mutex_lock(&devLock);
+	pdev = &rec_dsc_dev[devno];
+
+	if (!pdev->used) {
+		pthread_mutex_unlock(&devLock);
+		am_ca_pr(LOG_ERROR, "ca_close %d not used\n", devno);
+		return 0;
+	}
+	pdev->ref--;
+	if (pdev->ref == 0) {
+		fd = pdev->fd;
+		if (fd != -1) {
+			close(fd);
+		}
+		memset(pdev, 0, sizeof(dsc_dev));
+		pdev->fd = -1;
+	}
+	pthread_mutex_unlock(&devLock);
+	am_ca_pr(LOG_DEBUG,"ca_close exit\n");
+	return 0;
+}
+
diff --git a/test/am_ca_key_test/ca.h b/test/am_ca_key_test/ca.h
new file mode 100644
index 0000000..30e66f6
--- /dev/null
+++ b/test/am_ca_key_test/ca.h
@@ -0,0 +1,323 @@
+/* SPDX-License-Identifier: LGPL-2.1+ WITH Linux-syscall-note */
+/*
+ * ca.h
+ *
+ * Copyright (C) 2000 Ralph  Metzler <ralph@convergence.de>
+ *                  & Marcus Metzler <marcus@convergence.de>
+ *                    for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Lesser Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * 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 Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#ifndef _DVBCA_H_
+#define _DVBCA_H_
+
+#define CONFIG_AMLOGIC_DVB_COMPAT
+/**
+ * struct ca_slot_info - CA slot interface types and info.
+ *
+ * @num:    slot number.
+ * @type:    slot type.
+ * @flags:    flags applicable to the slot.
+ *
+ * This struct stores the CA slot information.
+ *
+ * @type can be:
+ *
+ *    - %CA_CI - CI high level interface;
+ *    - %CA_CI_LINK - CI link layer level interface;
+ *    - %CA_CI_PHYS - CI physical layer level interface;
+ *    - %CA_DESCR - built-in descrambler;
+ *    - %CA_SC -simple smart card interface.
+ *
+ * @flags can be:
+ *
+ *    - %CA_CI_MODULE_PRESENT - module (or card) inserted;
+ *    - %CA_CI_MODULE_READY - module is ready for usage.
+ */
+
+struct ca_slot_info {
+    int num;
+    int type;
+#define CA_CI            1
+#define CA_CI_LINK       2
+#define CA_CI_PHYS       4
+#define CA_DESCR         8
+#define CA_SC          128
+
+    unsigned int flags;
+#define CA_CI_MODULE_PRESENT 1
+#define CA_CI_MODULE_READY   2
+};
+
+
+/**
+ * struct ca_descr_info - descrambler types and info.
+ *
+ * @num:    number of available descramblers (keys).
+ * @type:    type of supported scrambling system.
+ *
+ * Identifies the number of descramblers and their type.
+ *
+ * @type can be:
+ *
+ *    - %CA_ECD - European Common Descrambler (ECD) hardware;
+ *    - %CA_NDS - Videoguard (NDS) hardware;
+ *    - %CA_DSS - Distributed Sample Scrambling (DSS) hardware.
+ */
+struct ca_descr_info {
+    unsigned int num;
+    unsigned int type;
+#define CA_ECD           1
+#define CA_NDS           2
+#define CA_DSS           4
+};
+
+/**
+ * struct ca_caps - CA slot interface capabilities.
+ *
+ * @slot_num:    total number of CA card and module slots.
+ * @slot_type:    bitmap with all supported types as defined at
+ *        &struct ca_slot_info (e. g. %CA_CI, %CA_CI_LINK, etc).
+ * @descr_num:    total number of descrambler slots (keys)
+ * @descr_type:    bitmap with all supported types as defined at
+ *        &struct ca_descr_info (e. g. %CA_ECD, %CA_NDS, etc).
+ */
+struct ca_caps {
+    unsigned int slot_num;
+    unsigned int slot_type;
+    unsigned int descr_num;
+    unsigned int descr_type;
+};
+
+/**
+ * struct ca_msg - a message to/from a CI-CAM
+ *
+ * @index:    unused
+ * @type:    unused
+ * @length:    length of the message
+ * @msg:    message
+ *
+ * This struct carries a message to be send/received from a CI CA module.
+ */
+struct ca_msg {
+    unsigned int index;
+    unsigned int type;
+    unsigned int length;
+    unsigned char msg[256];
+};
+
+/**
+ * struct ca_descr - CA descrambler control words info
+ *
+ * @index: CA Descrambler slot
+ * @parity: control words parity, where 0 means even and 1 means odd
+ * @cw: CA Descrambler control words
+ */
+struct ca_descr {
+    unsigned int index;
+    unsigned int parity;
+    unsigned char cw[8];
+};
+
+#ifdef CONFIG_AMLOGIC_DVB_COMPAT
+/* CW type. */
+enum ca_cw_type {
+    CA_CW_DVB_CSA_EVEN,
+    CA_CW_DVB_CSA_ODD,
+    CA_CW_AES_EVEN,
+    CA_CW_AES_ODD,
+    CA_CW_AES_EVEN_IV,
+    CA_CW_AES_ODD_IV,
+    CA_CW_DES_EVEN,
+    CA_CW_DES_ODD,
+    CA_CW_SM4_EVEN,
+    CA_CW_SM4_ODD,
+    CA_CW_SM4_EVEN_IV,
+    CA_CW_SM4_ODD_IV,
+    CA_CW_TYPE_MAX
+};
+
+enum ca_dsc_mode {
+    CA_DSC_CBC = 1,
+    CA_DSC_ECB,
+    CA_DSC_IDSA
+};
+
+struct ca_descr_ex {
+    unsigned int index;
+    enum ca_cw_type type;
+    enum ca_dsc_mode mode;
+    int          flags;
+#define CA_CW_FROM_KL 1
+    unsigned char cw[16];
+};
+
+/* add for support sc2 ca*/
+enum ca_sc2_cmd_type {
+    CA_ALLOC,
+    CA_FREE,
+    CA_KEY,
+    CA_GET_STATUS,
+    CA_SET_SCB,
+    CA_SET_ALGO
+};
+
+enum ca_sc2_algo_type {
+    CA_ALGO_AES_ECB_CLR_END,
+    CA_ALGO_AES_ECB_CLR_FRONT,
+    CA_ALGO_AES_CBC_CLR_END,
+    CA_ALGO_AES_CBC_IDSA,
+    CA_ALGO_CSA2,
+    CA_ALGO_DES_SCTE41,
+    CA_ALGO_DES_SCTE52,
+    CA_ALGO_TDES_ECB_CLR_END,
+    CA_ALGO_CPCM_LSA_MDI_CBC,
+    CA_ALGO_CPCM_LSA_MDD_CBC,
+    CA_ALGO_CSA3,
+    CA_ALGO_ASA,
+    CA_ALGO_ASA_LIGHT,
+    CA_ALGO_S17_ECB_CLR_END,
+    CA_ALGO_S17_ECB_CTS,
+    CA_ALGO_UNKNOWN
+};
+
+enum ca_sc2_dsc_type {
+    CA_DSC_COMMON_TYPE,
+    CA_DSC_TSD_TYPE,    /*just support AES descramble.*/
+    CA_DSC_TSE_TYPE        /*just support AES enscramble.*/
+};
+
+/**
+ * struct ca_alloc - malloc ca slot index by params
+ *
+ * @pid:    slot use pid.
+ * @algo:    use the algorithm
+ * @dsc_type:    CA_DSC_COMMON_TYPE:support all ca_algo_type
+ *        CA_DSC_TSD_TYPE & CA_DSC_TSE_TYPE just support AES
+ * @ca_index:    return slot index.
+ */
+struct ca_sc2_alloc {
+	unsigned int pid;
+	enum ca_sc2_algo_type algo;
+	enum ca_sc2_dsc_type dsc_type;
+	unsigned int ca_index;
+	unsigned char loop;
+};
+
+/**
+ * struct ca_sc2_free - free slot index
+ *
+ * @ca_index:    need free slot index.
+ */
+struct ca_sc2_free {
+    unsigned int ca_index;
+};
+
+enum ca_sc2_key_type {
+    CA_KEY_EVEN_TYPE,
+    CA_KEY_EVEN_IV_TYPE,
+    CA_KEY_ODD_TYPE,
+    CA_KEY_ODD_IV_TYPE,
+    CA_KEY_00_TYPE,
+    CA_KEY_00_IV_TYPE
+};
+
+/**
+ * struct ca_sc2_key - set key slot index
+ *
+ * @ca_index:    use slot index.
+ * @parity:    key type (odd/even/key00)
+ * @key_index: key store index.
+ */
+struct ca_sc2_key {
+    unsigned int ca_index;
+    enum ca_sc2_key_type parity;
+    unsigned int key_index;
+};
+
+/**
+ * struct ca_sc2_scb - set scb
+ *
+ * @ca_index:    use slot index.
+ * @ca_scb:    ca_scb (2bit)
+ * @ca_scb_as_is:if 1, scb use original
+ *                 if 0, use ca_scb
+ */
+struct ca_sc2_scb {
+    unsigned int ca_index;
+    unsigned char ca_scb;
+    unsigned char ca_scb_as_is;
+};
+
+/**
+ * struct ca_sc2_algo - set algo
+ *
+ * @ca_index:    use slot index.
+ * @algo:    algo
+ */
+struct ca_sc2_algo {
+    unsigned int ca_index;
+    enum ca_sc2_algo_type algo;
+};
+
+/**
+ * struct ca_sc2_descr_ex - ca extend descriptor
+ *
+ * @params:    command resource params
+ */
+struct ca_sc2_descr_ex {
+    enum ca_sc2_cmd_type cmd;
+    union {
+        struct ca_sc2_alloc alloc_params;
+        struct ca_sc2_free free_params;
+        struct ca_sc2_key key_params;
+        struct ca_sc2_scb scb_params;
+        struct ca_sc2_algo algo_params;
+    } params;
+};
+
+struct ca_pid {
+    unsigned int pid;
+    int index;   /* -1 == disable*/
+};
+
+#endif /*CONFIG_AMLOGIC_DVB_COMPAT*/
+#define CA_RESET          _IO('o', 128)
+#define CA_GET_CAP        _IOR('o', 129, struct ca_caps)
+#define CA_GET_SLOT_INFO  _IOR('o', 130, struct ca_slot_info)
+#define CA_GET_DESCR_INFO _IOR('o', 131, struct ca_descr_info)
+#define CA_GET_MSG        _IOR('o', 132, struct ca_msg)
+#define CA_SEND_MSG       _IOW('o', 133, struct ca_msg)
+#define CA_SET_DESCR      _IOW('o', 134, struct ca_descr)
+#ifdef CONFIG_AMLOGIC_DVB_COMPAT
+#define CA_SET_PID        _IOW('o', 135, struct ca_pid)
+#define CA_SET_DESCR_EX   _IOW('o', 200, struct ca_descr_ex)
+#define CA_SC2_SET_DESCR_EX   _IOWR('o', 201, struct ca_sc2_descr_ex)
+#endif
+#if !defined(__KERNEL__)
+
+/* This is needed for legacy userspace support */
+typedef struct ca_slot_info ca_slot_info_t;
+typedef struct ca_descr_info  ca_descr_info_t;
+typedef struct ca_caps  ca_caps_t;
+typedef struct ca_msg ca_msg_t;
+typedef struct ca_descr ca_descr_t;
+
+#endif
+
+
+#endif
diff --git a/test/am_ca_key_test/dmx.h b/test/am_ca_key_test/dmx.h
new file mode 100644
index 0000000..b3ac317
--- /dev/null
+++ b/test/am_ca_key_test/dmx.h
@@ -0,0 +1,524 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * dmx.h
+ *
+ * Copyright (C) 2000 Marcus Metzler <marcus@convergence.de>
+ *                  & Ralph  Metzler <ralph@convergence.de>
+ *                    for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * 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 Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#ifndef _UAPI_DVBDMX_H_
+#define _UAPI_DVBDMX_H_
+
+#include <linux/types.h>
+#ifndef __KERNEL__
+#include <time.h>
+#endif
+
+
+#define DMX_FILTER_SIZE 16
+
+/**
+ * enum dmx_output - Output for the demux.
+ *
+ * @DMX_OUT_DECODER:
+ *	Streaming directly to decoder.
+ * @DMX_OUT_TAP:
+ *	Output going to a memory buffer (to be retrieved via the read command).
+ *	Delivers the stream output to the demux device on which the ioctl
+ *	is called.
+ * @DMX_OUT_TS_TAP:
+ *	Output multiplexed into a new TS (to be retrieved by reading from the
+ *	logical DVR device). Routes output to the logical DVR device
+ *	``/dev/dvb/adapter?/dvr?``, which delivers a TS multiplexed from all
+ *	filters for which @DMX_OUT_TS_TAP was specified.
+ * @DMX_OUT_TSDEMUX_TAP:
+ *	Like @DMX_OUT_TS_TAP but retrieved from the DMX device.
+ */
+enum dmx_output {
+	DMX_OUT_DECODER,
+	DMX_OUT_TAP,
+	DMX_OUT_TS_TAP,
+	DMX_OUT_TSDEMUX_TAP
+};
+
+
+/**
+ * enum dmx_input - Input from the demux.
+ *
+ * @DMX_IN_FRONTEND:	Input from a front-end device.
+ * @DMX_IN_DVR:		Input from the logical DVR device.
+ */
+enum dmx_input {
+	DMX_IN_FRONTEND,
+	DMX_IN_DVR
+};
+
+/**
+ * enum dmx_ts_pes - type of the PES filter.
+ *
+ * @DMX_PES_AUDIO0:	first audio PID. Also referred as @DMX_PES_AUDIO.
+ * @DMX_PES_VIDEO0:	first video PID. Also referred as @DMX_PES_VIDEO.
+ * @DMX_PES_TELETEXT0:	first teletext PID. Also referred as @DMX_PES_TELETEXT.
+ * @DMX_PES_SUBTITLE0:	first subtitle PID. Also referred as @DMX_PES_SUBTITLE.
+ * @DMX_PES_PCR0:	first Program Clock Reference PID.
+ *			Also referred as @DMX_PES_PCR.
+ *
+ * @DMX_PES_AUDIO1:	second audio PID.
+ * @DMX_PES_VIDEO1:	second video PID.
+ * @DMX_PES_TELETEXT1:	second teletext PID.
+ * @DMX_PES_SUBTITLE1:	second subtitle PID.
+ * @DMX_PES_PCR1:	second Program Clock Reference PID.
+ *
+ * @DMX_PES_AUDIO2:	third audio PID.
+ * @DMX_PES_VIDEO2:	third video PID.
+ * @DMX_PES_TELETEXT2:	third teletext PID.
+ * @DMX_PES_SUBTITLE2:	third subtitle PID.
+ * @DMX_PES_PCR2:	third Program Clock Reference PID.
+ *
+ * @DMX_PES_AUDIO3:	fourth audio PID.
+ * @DMX_PES_VIDEO3:	fourth video PID.
+ * @DMX_PES_TELETEXT3:	fourth teletext PID.
+ * @DMX_PES_SUBTITLE3:	fourth subtitle PID.
+ * @DMX_PES_PCR3:	fourth Program Clock Reference PID.
+ *
+ * @DMX_PES_OTHER:	any other PID.
+ */
+
+enum dmx_ts_pes {
+	DMX_PES_AUDIO0,
+	DMX_PES_VIDEO0,
+	DMX_PES_TELETEXT0,
+	DMX_PES_SUBTITLE0,
+	DMX_PES_PCR0,
+
+	DMX_PES_AUDIO1,
+	DMX_PES_VIDEO1,
+	DMX_PES_TELETEXT1,
+	DMX_PES_SUBTITLE1,
+	DMX_PES_PCR1,
+
+	DMX_PES_AUDIO2,
+	DMX_PES_VIDEO2,
+	DMX_PES_TELETEXT2,
+	DMX_PES_SUBTITLE2,
+	DMX_PES_PCR2,
+
+	DMX_PES_AUDIO3,
+	DMX_PES_VIDEO3,
+	DMX_PES_TELETEXT3,
+	DMX_PES_SUBTITLE3,
+	DMX_PES_PCR3,
+
+	DMX_PES_OTHER
+};
+
+#define DMX_PES_AUDIO    DMX_PES_AUDIO0
+#define DMX_PES_VIDEO    DMX_PES_VIDEO0
+#define DMX_PES_TELETEXT DMX_PES_TELETEXT0
+#define DMX_PES_SUBTITLE DMX_PES_SUBTITLE0
+#define DMX_PES_PCR      DMX_PES_PCR0
+
+
+
+/**
+ * struct dmx_filter - Specifies a section header filter.
+ *
+ * @filter: bit array with bits to be matched at the section header.
+ * @mask: bits that are valid at the filter bit array.
+ * @mode: mode of match: if bit is zero, it will match if equal (positive
+ *	  match); if bit is one, it will match if the bit is negated.
+ *
+ * Note: All arrays in this struct have a size of DMX_FILTER_SIZE (16 bytes).
+ */
+struct dmx_filter {
+	__u8  filter[DMX_FILTER_SIZE];
+	__u8  mask[DMX_FILTER_SIZE];
+	__u8  mode[DMX_FILTER_SIZE];
+};
+
+/**
+ * struct dmx_sct_filter_params - Specifies a section filter.
+ *
+ * @pid: PID to be filtered.
+ * @filter: section header filter, as defined by &struct dmx_filter.
+ * @timeout: maximum time to filter, in milliseconds.
+ * @flags: extra flags for the section filter.
+ *
+ * Carries the configuration for a MPEG-TS section filter.
+ *
+ * The @flags can be:
+ *
+ *	- %DMX_CHECK_CRC - only deliver sections where the CRC check succeeded;
+ *	- %DMX_ONESHOT - disable the section filter after one section
+ *	  has been delivered;
+ *	- %DMX_IMMEDIATE_START - Start filter immediately without requiring a
+ *	  :ref:`DMX_START`.
+ */
+struct dmx_sct_filter_params {
+	__u16             pid;
+	struct dmx_filter filter;
+	__u32             timeout;
+	__u32             flags;
+#define DMX_CHECK_CRC       1
+#define DMX_ONESHOT         2
+#define DMX_IMMEDIATE_START 4
+#ifdef CONFIG_AMLOGIC_DVB_COMPAT
+#define DMX_USE_SWFILTER    0x100
+
+/*bit 8~15 for mem sec_level*/
+#define DMX_MEM_SEC_LEVEL1   (1 << 10)
+#define DMX_MEM_SEC_LEVEL2   (2 << 10)
+#define DMX_MEM_SEC_LEVEL3   (3 << 10)
+#define DMX_MEM_SEC_LEVEL4   (4 << 10)
+#define DMX_MEM_SEC_LEVEL5   (5 << 10)
+#define DMX_MEM_SEC_LEVEL6   (6 << 10)
+#define DMX_MEM_SEC_LEVEL7   (7 << 10)
+#endif
+};
+
+#ifdef CONFIG_AMLOGIC_DVB_COMPAT
+
+enum dmx_input_source {
+	INPUT_DEMOD,
+	INPUT_LOCAL,
+	INPUT_LOCAL_SEC
+};
+
+/**
+ * struct dmx_non_sec_es_header - non-sec Elementary Stream (ES) Header
+ *
+ * @pts_dts_flag:[1:0], 10:pts valid, 01:dts valid
+ * @pts_dts_flag:[3:2], 10:scb is scrambled, 01:pscp invalid
+ * @pts:	pts value
+ * @dts:	dts value
+ * @len:	data len
+ */
+struct dmx_non_sec_es_header {
+	__u8 pts_dts_flag;
+	__u64 pts;
+	__u64 dts;
+	__u32 len;
+};
+
+/**
+ * struct dmx_sec_es_data - sec Elementary Stream (ES)
+ *
+ * @pts_dts_flag:[1:0], 10:pts valid, 01:dts valid
+ * @pts_dts_flag:[3:2], 10:scb is scrambled, 01:pscp invalid
+ * @pts:	pts value
+ * @dts:	dts value
+ * @buf_start:	buf start addr
+ * @buf_end:	buf end addr
+ * @data_start: data start addr
+ * @data_end: data end addr
+ */
+struct dmx_sec_es_data {
+	__u8 pts_dts_flag;
+	__u64 pts;
+	__u64 dts;
+	__u32 buf_start;
+	__u32 buf_end;
+	__u32 data_start;
+	__u32 data_end;
+};
+
+struct dmx_sec_ts_data {
+	__u32 buf_start;
+	__u32 buf_end;
+	__u32 data_start;
+	__u32 data_end;
+};
+
+struct dmx_temi_data {
+	__u8 pts_dts_flag;
+	__u64 pts;
+	__u64 dts;
+	__u8 temi[188];
+};
+
+enum dmx_audio_format {
+	AUDIO_UNKNOWN = 0,	/* unknown media */
+	AUDIO_MPX = 1,		/* mpeg audio MP2/MP3 */
+	AUDIO_AC3 = 2,		/* Dolby AC3/EAC3 */
+	AUDIO_AAC_ADTS = 3,	/* AAC-ADTS */
+	AUDIO_AAC_LOAS = 4,	/* AAC-LOAS */
+	AUDIO_DTS = 5,		/* DTS */
+	AUDIO_MAX
+};
+
+struct dmx_mem_info {
+	__u32 dmx_total_size;
+	__u32 dmx_buf_phy_start;
+	__u32 dmx_free_size;
+	__u32 dvb_core_total_size;
+	__u32 dvb_core_free_size;
+	__u32 wp_offset;
+	__u64 newest_pts;
+};
+
+struct dmx_sec_mem {
+	__u32 buff;
+	__u32 size;
+};
+#endif
+
+/**
+ * struct dmx_pes_filter_params - Specifies Packetized Elementary Stream (PES)
+ *	filter parameters.
+ *
+ * @pid:	PID to be filtered.
+ * @input:	Demux input, as specified by &enum dmx_input.
+ * @output:	Demux output, as specified by &enum dmx_output.
+ * @pes_type:	Type of the pes filter, as specified by &enum dmx_pes_type.
+ * @flags:	Demux PES flags.
+ */
+struct dmx_pes_filter_params {
+	__u16           pid;
+	enum dmx_input  input;
+	enum dmx_output output;
+	enum dmx_ts_pes pes_type;
+	__u32           flags;
+#ifdef CONFIG_AMLOGIC_DVB_COMPAT
+/*bit 8~15 for mem sec_level*/
+#define DMX_MEM_SEC_LEVEL1   (1 << 10)
+#define DMX_MEM_SEC_LEVEL2   (2 << 10)
+#define DMX_MEM_SEC_LEVEL3   (3 << 10)
+#define DMX_MEM_SEC_LEVEL4   (4 << 10)
+#define DMX_MEM_SEC_LEVEL5   (5 << 10)
+#define DMX_MEM_SEC_LEVEL6   (6 << 10)
+#define DMX_MEM_SEC_LEVEL7   (7 << 10)
+
+/*bit 16~23 for output */
+#define DMX_ES_OUTPUT        (1 << 16)
+/*set raw mode, it will send the struct dmx_sec_es_data, not es data*/
+#define DMX_OUTPUT_RAW_MODE	 (1 << 17)
+#define DMX_TEMI_FLAGS       (1 << 18)
+
+/*24~31 one byte for audio type, dmx_audio_format_t*/
+#define DMX_AUDIO_FORMAT_BIT 24
+
+#endif
+};
+
+/**
+ * struct dmx_stc - Stores System Time Counter (STC) information.
+ *
+ * @num: input data: number of the STC, from 0 to N.
+ * @base: output: divisor for STC to get 90 kHz clock.
+ * @stc: output: stc in @base * 90 kHz units.
+ */
+struct dmx_stc {
+	unsigned int num;
+	unsigned int base;
+	__u64 stc;
+};
+
+/**
+ * enum dmx_buffer_flags - DMX memory-mapped buffer flags
+ *
+ * @DMX_BUFFER_FLAG_HAD_CRC32_DISCARD:
+ *	Indicates that the Kernel discarded one or more frames due to wrong
+ *	CRC32 checksum.
+ * @DMX_BUFFER_FLAG_TEI:
+ *	Indicates that the Kernel has detected a Transport Error indicator
+ *	(TEI) on a filtered pid.
+ * @DMX_BUFFER_PKT_COUNTER_MISMATCH:
+ *	Indicates that the Kernel has detected a packet counter mismatch
+ *	on a filtered pid.
+ * @DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED:
+ *	Indicates that the Kernel has detected one or more frame discontinuity.
+ * @DMX_BUFFER_FLAG_DISCONTINUITY_INDICATOR:
+ *	Received at least one packet with a frame discontinuity indicator.
+ */
+
+enum dmx_buffer_flags {
+	DMX_BUFFER_FLAG_HAD_CRC32_DISCARD		= 1 << 0,
+	DMX_BUFFER_FLAG_TEI				= 1 << 1,
+	DMX_BUFFER_PKT_COUNTER_MISMATCH			= 1 << 2,
+	DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED		= 1 << 3,
+	DMX_BUFFER_FLAG_DISCONTINUITY_INDICATOR		= 1 << 4,
+};
+
+/**
+ * struct dmx_buffer - dmx buffer info
+ *
+ * @index:	id number of the buffer
+ * @bytesused:	number of bytes occupied by data in the buffer (payload);
+ * @offset:	for buffers with memory == DMX_MEMORY_MMAP;
+ *		offset from the start of the device memory for this plane,
+ *		(or a "cookie" that should be passed to mmap() as offset)
+ * @length:	size in bytes of the buffer
+ * @flags:	bit array of buffer flags as defined by &enum dmx_buffer_flags.
+ *		Filled only at &DMX_DQBUF.
+ * @count:	monotonic counter for filled buffers. Helps to identify
+ *		data stream loses. Filled only at &DMX_DQBUF.
+ *
+ * Contains data exchanged by application and driver using one of the streaming
+ * I/O methods.
+ *
+ * Please notice that, for &DMX_QBUF, only @index should be filled.
+ * On &DMX_DQBUF calls, all fields will be filled by the Kernel.
+ */
+struct dmx_buffer {
+	__u32			index;
+	__u32			bytesused;
+	__u32			offset;
+	__u32			length;
+	__u32			flags;
+	__u32			count;
+};
+
+/**
+ * struct dmx_requestbuffers - request dmx buffer information
+ *
+ * @count:	number of requested buffers,
+ * @size:	size in bytes of the requested buffer
+ *
+ * Contains data used for requesting a dmx buffer.
+ * All reserved fields must be set to zero.
+ */
+struct dmx_requestbuffers {
+	__u32			count;
+	__u32			size;
+};
+
+/**
+ * struct dmx_exportbuffer - export of dmx buffer as DMABUF file descriptor
+ *
+ * @index:	id number of the buffer
+ * @flags:	flags for newly created file, currently only O_CLOEXEC is
+ *		supported, refer to manual of open syscall for more details
+ * @fd:		file descriptor associated with DMABUF (set by driver)
+ *
+ * Contains data used for exporting a dmx buffer as DMABUF file descriptor.
+ * The buffer is identified by a 'cookie' returned by DMX_QUERYBUF
+ * (identical to the cookie used to mmap() the buffer to userspace). All
+ * reserved fields must be set to zero. The field reserved0 is expected to
+ * become a structure 'type' allowing an alternative layout of the structure
+ * content. Therefore this field should not be used for any other extensions.
+ */
+struct dmx_exportbuffer {
+	__u32		index;
+	__u32		flags;
+	__s32		fd;
+};
+
+#ifdef CONFIG_AMLOGIC_DVB_COMPAT
+enum {
+	DMA_0 = 0,
+	DMA_1,
+	DMA_2,
+	DMA_3,
+	DMA_4,
+	DMA_5,
+	DMA_6,
+	DMA_7,
+	FRONTEND_TS0 = 32,
+	FRONTEND_TS1,
+	FRONTEND_TS2,
+	FRONTEND_TS3,
+	FRONTEND_TS4,
+	FRONTEND_TS5,
+	FRONTEND_TS6,
+	FRONTEND_TS7,
+	DMA_0_1 = 64,
+	DMA_1_1,
+	DMA_2_1,
+	DMA_3_1,
+	DMA_4_1,
+	DMA_5_1,
+	DMA_6_1,
+	DMA_7_1,
+	FRONTEND_TS0_1 = 96,
+	FRONTEND_TS1_1,
+	FRONTEND_TS2_1,
+	FRONTEND_TS3_1,
+	FRONTEND_TS4_1,
+	FRONTEND_TS5_1,
+	FRONTEND_TS6_1,
+	FRONTEND_TS7_1,
+};
+
+/*define filter mem_info type*/
+enum {
+	DMX_VIDEO_TYPE = 0,
+	DMX_AUDIO_TYPE,
+	DMX_SUBTITLE_TYPE,
+	DMX_TELETEXT_TYPE,
+	DMX_SECTION_TYPE,
+};
+
+struct filter_mem_info {
+	__u32 type;
+	__u32 pid;
+	struct dmx_mem_info	filter_info;
+};
+
+struct dmx_filter_mem_info {
+	__u32 filter_num;
+	struct filter_mem_info info[40];
+};
+
+struct dvr_mem_info {
+	__u32 wp_offset;
+};
+
+struct decoder_mem_info {
+	__u32 rp_phy;
+};
+#endif
+
+#define DMX_START                _IO('o', 41)
+#define DMX_STOP                 _IO('o', 42)
+#define DMX_SET_FILTER           _IOW('o', 43, struct dmx_sct_filter_params)
+#define DMX_SET_PES_FILTER       _IOW('o', 44, struct dmx_pes_filter_params)
+#define DMX_SET_BUFFER_SIZE      _IO('o', 45)
+#define DMX_GET_PES_PIDS         _IOR('o', 47, __u16[5])
+#define DMX_GET_STC              _IOWR('o', 50, struct dmx_stc)
+#define DMX_ADD_PID              _IOW('o', 51, __u16)
+#define DMX_REMOVE_PID           _IOW('o', 52, __u16)
+#if !defined(__KERNEL__)
+
+/* This is needed for legacy userspace support */
+typedef enum dmx_output dmx_output_t;
+typedef enum dmx_input dmx_input_t;
+typedef enum dmx_ts_pes dmx_pes_type_t;
+typedef struct dmx_filter dmx_filter_t;
+
+#endif
+
+#define DMX_REQBUFS              _IOWR('o', 60, struct dmx_requestbuffers)
+#define DMX_QUERYBUF             _IOWR('o', 61, struct dmx_buffer)
+#define DMX_EXPBUF               _IOWR('o', 62, struct dmx_exportbuffer)
+#define DMX_QBUF                 _IOWR('o', 63, struct dmx_buffer)
+#define DMX_DQBUF                _IOWR('o', 64, struct dmx_buffer)
+
+#ifdef CONFIG_AMLOGIC_DVB_COMPAT
+#define DMX_SET_INPUT           _IO('o', 80)
+#define DMX_GET_MEM_INFO        _IOR('o', 81, struct dmx_mem_info)
+#define DMX_SET_HW_SOURCE       _IO('o', 82)
+#define DMX_GET_HW_SOURCE       _IOR('o', 83, int)
+#define DMX_GET_FILTER_MEM_INFO _IOR('o', 84, struct dmx_filter_mem_info)
+/*just for dvr sec mem, please call before DMX_SET_PES_FILTER*/
+#define DMX_SET_SEC_MEM			_IOW('o', 85, struct dmx_sec_mem)
+#define DMX_GET_DVR_MEM			_IOR('o', 86, struct dvr_mem_info)
+#define DMX_REMAP_PID			_IOR('o', 87, __u16[2])
+#define DMX_SET_DECODE_INFO     _IOW('o', 88, struct decoder_mem_info)
+#endif
+#endif /* _DVBDMX_H_ */
diff --git a/test/am_ca_key_test/inject_record_t5d/am_adp_internal.h b/test/am_ca_key_test/inject_record_t5d/am_adp_internal.h
new file mode 100644
index 0000000..171bfb1
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_adp_internal.h
@@ -0,0 +1,38 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief AMLogic adaptor layer 内部头文件
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-07-05: create the document
+ ***************************************************************************/
+
+#ifndef _AM_ADP_INTERNAL_H
+#define _AM_ADP_INTERNAL_H
+
+#include <am_thread.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Data definitions
+ ***************************************************************************/
+
+/**\brief ADP全局锁*/
+extern pthread_mutex_t am_gAdpLock;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/am_av/Makefile b/test/am_ca_key_test/inject_record_t5d/am_av/Makefile
new file mode 100644
index 0000000..3edd6ba
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_av/Makefile
@@ -0,0 +1,20 @@
+BASE=../..
+
+include $(BASE)/rule/def.mk
+
+O_TARGET=am_av
+am_av_SRCS=am_av.c
+
+SUBDIRS=
+am_av_OBJS=
+
+ifeq ($(EMU_AV), y)
+	SUBDIRS+=emu
+	am_av_OBJS+=emu/emu
+else
+	SUBDIRS+=aml
+	am_av_OBJS+=aml/aml
+endif
+
+
+include $(BASE)/rule/rule.mk
diff --git a/test/am_ca_key_test/inject_record_t5d/am_av/am_av.c b/test/am_ca_key_test/inject_record_t5d/am_av/am_av.c
new file mode 100644
index 0000000..2a53a93
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_av/am_av.c
@@ -0,0 +1,3154 @@
+#ifdef _FORTIFY_SOURCE
+#undef _FORTIFY_SOURCE
+#endif
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief 音视频解码模块
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-08-06: create the document
+ ***************************************************************************/
+
+#define AM_DEBUG_LEVEL 5
+
+#include <am_debug.h>
+#include <am_vout.h>
+#include <am_mem.h>
+#include "am_av_internal.h"
+#include "../am_adp_internal.h"
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+#define AV_DEV_COUNT      (1)
+
+/****************************************************************************
+ * Static data
+ ***************************************************************************/
+
+#ifdef EMU_AV
+extern const AM_AV_Driver_t emu_av_drv;
+#else
+extern const AM_AV_Driver_t aml_av_drv;
+#endif
+
+static AM_AV_Device_t av_devices[AV_DEV_COUNT] =
+{
+#ifdef EMU_AV
+{
+.drv = &emu_av_drv
+}
+#else
+{
+.drv = &aml_av_drv
+}
+#endif
+};
+
+/****************************************************************************
+ * Static functions
+ ***************************************************************************/
+ 
+/**\brief 根据设备号取得设备结构指针*/
+static AM_INLINE AM_ErrorCode_t av_get_dev(int dev_no, AM_AV_Device_t **dev)
+{
+	if ((dev_no < 0) || (dev_no >= AV_DEV_COUNT))
+	{
+		AM_DEBUG(1, "invalid AV device number %d, must in(%d~%d)", dev_no, 0, AV_DEV_COUNT-1);
+		return AM_AV_ERR_INVALID_DEV_NO;
+	}
+
+	*dev = &av_devices[dev_no];
+	return AM_SUCCESS;
+}
+
+/**\brief 根据设备号取得设备结构并检查设备是否已经打开*/
+static AM_INLINE AM_ErrorCode_t av_get_openned_dev(int dev_no, AM_AV_Device_t **dev)
+{
+	AM_TRY(av_get_dev(dev_no, dev));
+
+	if (!(*dev)->openned)
+	{
+		AM_DEBUG(1, "AV device %d has not been openned", dev_no);
+		return AM_AV_ERR_INVALID_DEV_NO;
+	}
+
+	return AM_SUCCESS;
+}
+
+/**\brief 释放数据参数中的相关资源*/
+static void av_free_data_para(AV_DataPlayPara_t *para)
+{
+	if (para->need_free)
+	{
+		munmap((uint8_t *)para->data, para->len);
+		close(para->fd);
+		para->need_free = AM_FALSE;
+	}
+}
+
+/**\brief 结束播放*/
+static AM_ErrorCode_t av_stop(AM_AV_Device_t *dev, AV_PlayMode_t mode)
+{
+	if (!(dev->mode&mode))
+		return AM_SUCCESS;
+
+	if (dev->drv->close_mode)
+		dev->drv->close_mode(dev, mode);
+
+	switch(mode)
+	{
+		case AV_PLAY_VIDEO_ES:
+		case AV_DECODE_JPEG:
+		case AV_GET_JPEG_INFO:
+			av_free_data_para(&dev->vid_player.para);
+		break;
+		case AV_PLAY_AUDIO_ES:
+			av_free_data_para(&dev->aud_player.para);
+		break;
+		default:
+		break;
+	}
+
+	dev->mode &= ~mode;
+	return AM_SUCCESS;
+}
+
+/**\brief 结束所有播放*/
+static AM_ErrorCode_t av_stop_all(AM_AV_Device_t *dev, AV_PlayMode_t mode)
+{
+	if (mode & AV_PLAY_VIDEO_ES)
+		av_stop(dev, AV_PLAY_VIDEO_ES);
+	if (mode & AV_PLAY_AUDIO_ES)
+		av_stop(dev, AV_PLAY_AUDIO_ES);
+	if (mode & AV_GET_JPEG_INFO)
+		av_stop(dev, AV_GET_JPEG_INFO);
+	if (mode & AV_DECODE_JPEG)
+		av_stop(dev, AV_DECODE_JPEG);
+	if (mode & AV_PLAY_TS)
+		av_stop(dev, AV_PLAY_TS);
+	if (mode & AV_PLAY_FILE)
+		av_stop(dev, AV_PLAY_FILE);
+	if (mode & AV_INJECT)
+		av_stop(dev, AV_INJECT);
+	if (mode & AV_TIMESHIFT)
+		av_stop(dev, AV_TIMESHIFT);
+
+	return AM_SUCCESS;
+}
+
+/**\brief 开始播放*/
+static AM_ErrorCode_t av_start(AM_AV_Device_t *dev, AV_PlayMode_t mode, void *para)
+{
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	AV_PlayMode_t stop_mode;
+	AV_DataPlayPara_t *dp_para;
+
+	/*检查需要停止的播放模式*/
+	switch (mode)
+	{
+		case AV_PLAY_VIDEO_ES:
+			stop_mode = AV_DECODE_JPEG|AV_GET_JPEG_INFO|AV_PLAY_TS|AV_PLAY_FILE|AV_INJECT|AV_TIMESHIFT;
+		break;
+		case AV_PLAY_AUDIO_ES:
+			stop_mode = AV_PLAY_TS|AV_PLAY_FILE|AV_PLAY_AUDIO_ES|AV_INJECT|AV_TIMESHIFT;
+		break;
+		case AV_GET_JPEG_INFO:
+			stop_mode = AV_MODE_ALL&~(AV_PLAY_AUDIO_ES|AV_PLAY_FILE);
+		break;
+		case AV_DECODE_JPEG:
+			stop_mode = AV_MODE_ALL&~(AV_PLAY_AUDIO_ES|AV_PLAY_FILE);
+		break;
+		case AV_PLAY_TS:
+			dev->ts_player.play_para = *(AV_TSPlayPara_t *)para;
+			stop_mode = AV_MODE_ALL;
+		break;
+		case AV_PLAY_FILE:
+			stop_mode = AV_MODE_ALL;
+		break;
+		case AV_INJECT:
+			stop_mode = AV_MODE_ALL;
+		break;
+		case AV_TIMESHIFT:
+			stop_mode = AV_MODE_ALL;
+		break;
+		default:
+			stop_mode = 0;
+		break;
+	}
+
+	if (stop_mode)
+		av_stop_all(dev, stop_mode);
+
+	if (dev->drv->open_mode && !(dev->mode&mode))
+	{
+		ret = dev->drv->open_mode(dev, mode);
+		if (ret != AM_SUCCESS)
+			return ret;
+	}
+	else if (!dev->drv->open_mode)
+	{
+		AM_DEBUG(1, "do not support the operation");
+		return AM_AV_ERR_NOT_SUPPORTED;
+	}
+
+	dev->mode |= mode;
+
+	/*记录相关参数数据*/
+	switch (mode)
+	{
+		case AV_PLAY_VIDEO_ES:
+		case AV_GET_JPEG_INFO:
+		case AV_DECODE_JPEG:
+			dp_para = (AV_DataPlayPara_t *)para;
+			dev->vid_player.para = *dp_para;
+			para = dp_para->para;
+		break;
+		case AV_PLAY_AUDIO_ES:
+			dp_para = (AV_DataPlayPara_t *)para;
+			dev->aud_player.para = *dp_para;
+			para = dp_para->para;
+		break;
+		default:
+		break;
+	}
+
+	/*开始播放*/
+	if (dev->drv->start_mode)
+	{
+		ret = dev->drv->start_mode(dev, mode, para);
+		if (ret != AM_SUCCESS)
+		{
+			switch (mode)
+			{
+				case AV_PLAY_VIDEO_ES:
+				case AV_GET_JPEG_INFO:
+				case AV_DECODE_JPEG:
+					dev->vid_player.para.need_free = AM_FALSE;
+				break;
+				case AV_PLAY_AUDIO_ES:
+					dev->aud_player.para.need_free = AM_FALSE;
+				break;
+				default:
+				break;
+			}
+			return ret;
+		}
+	}
+
+	return AM_SUCCESS;
+}
+
+/**\brief 视频输出模式变化事件回调*/
+static void av_vout_format_changed(long dev_no, int event_type, void *param, void *data)
+{
+	AM_AV_Device_t *dev = (AM_AV_Device_t *)data;
+
+	UNUSED(dev_no);
+
+	if (event_type == AM_VOUT_EVT_FORMAT_CHANGED)
+	{
+		AM_VOUT_Format_t fmt = (AM_VOUT_Format_t)param;
+		int w, h;
+
+		w = dev->vout_w;
+		h = dev->vout_h;
+
+		switch (fmt)
+		{
+			case AM_VOUT_FORMAT_576CVBS:
+				w = 720;
+				h = 576;
+			break;
+			case AM_VOUT_FORMAT_480CVBS:
+				w = 720;
+				h = 480;
+			break;
+			case AM_VOUT_FORMAT_576I:
+				w = 720;
+				h = 576;
+			break;
+			case AM_VOUT_FORMAT_576P:
+				w = 720;
+				h = 576;
+			break;
+			case AM_VOUT_FORMAT_480I:
+				w = 720;
+				h = 480;
+			break;
+			case AM_VOUT_FORMAT_480P:
+				w = 720;
+				h = 480;
+			break;
+			case AM_VOUT_FORMAT_720P:
+				w = 1280;
+				h = 720;
+			break;
+			case AM_VOUT_FORMAT_1080I:
+				w = 1920;
+				h = 1080;
+			break;
+			case AM_VOUT_FORMAT_1080P:
+				w = 1920;
+				h = 1080;
+			break;
+			default:
+			break;
+		}
+
+		if ((w != dev->vout_w) || (h != dev->vout_h))
+		{
+			int nx, ny, nw, nh;
+
+			if (dev->video_w == 0 || dev->video_h == 0)
+			{
+				dev->video_w = dev->vout_w;
+				dev->video_h = dev->vout_h;
+			}
+
+			nx = dev->video_x*w/dev->vout_w;
+			ny = dev->video_y*h/dev->vout_h;
+			nw = dev->video_w*w/dev->vout_w;
+			nh = dev->video_h*h/dev->vout_h;
+
+			AM_AV_SetVideoWindow(dev->dev_no, nx, ny, nw, nh);
+
+			dev->vout_w = w;
+			dev->vout_h = h;
+		}
+	}
+}
+
+extern AM_ErrorCode_t av_set_vpath(AM_AV_Device_t *dev, AM_AV_FreeScalePara_t fs, AM_AV_DeinterlacePara_t di, AM_AV_PPMGRPara_t pp)
+{
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	dev->vpath_fs = fs;
+	dev->vpath_di = di;
+	dev->vpath_ppmgr = pp;
+
+	if (dev->mode & AV_TIMESHIFT) {
+		if (dev->drv->timeshift_cmd) {
+			ret = dev->drv->timeshift_cmd(dev, AV_PLAY_RESET_VPATH, NULL);
+		}
+	} else {
+		int mode = dev->mode & ~AV_PLAY_AUDIO_ES;
+		AM_AV_PlayPara_t para = dev->curr_para;
+		void *p = NULL;
+
+		if (mode & AV_PLAY_VIDEO_ES) {
+			p = &para.ves;
+			dev->vid_player.para.need_free = AM_FALSE;
+		} else if(mode & AV_PLAY_TS) {
+			p = &para.ts;
+		} else if(mode & AV_PLAY_FILE) {
+			AM_AV_PlayStatus_t status;
+
+			p = &para.file;
+			if (dev->drv->file_status) {
+				if (dev->drv->file_status(dev, &status) == AM_SUCCESS) {
+					para.pos = status.position;
+				}
+			}
+		} else if (mode & AV_INJECT) {
+			p = &para.inject;
+		}
+
+		if (mode) {
+			av_stop_all(dev, mode);
+		}
+
+		if (dev->drv->set_vpath) {
+			ret = dev->drv->set_vpath(dev);
+		}
+
+		if (mode) {
+			av_start(dev, mode, p);
+		}
+
+		if (mode & AV_PLAY_VIDEO_ES) {
+		} else if (mode & AV_PLAY_TS) {
+		} else if (mode & AV_PLAY_FILE) {
+			if (para.start && dev->drv->file_cmd) {
+				dev->drv->file_cmd(dev, AV_PLAY_SEEK, (void*)(long)para.pos);
+				if (para.pause)
+					dev->drv->file_cmd(dev, AV_PLAY_PAUSE, NULL);
+				else if (para.speed>0)
+					dev->drv->file_cmd(dev, AV_PLAY_FF, (void*)(long)para.speed);
+				else if (para.speed<0)
+					dev->drv->file_cmd(dev, AV_PLAY_FB, (void*)(long)para.speed);
+			}
+		} else if (mode & AV_INJECT) {
+			if (para.pause) {
+				if (dev->drv->inject_cmd) {
+					dev->drv->inject_cmd(dev, AV_PLAY_PAUSE, NULL);
+				}
+			}
+		}
+	}
+
+	return ret;
+}
+
+/****************************************************************************
+ * API functions
+ ***************************************************************************/
+
+/**\brief 打开音视频解码设备
+ * \param dev_no 音视频设备号
+ * \param[in] para 音视频设备开启参数
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_Open(int dev_no, const AM_AV_OpenPara_t *para)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	assert(para);
+
+	AM_TRY(av_get_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&am_gAdpLock);
+
+	if (dev->openned)
+	{
+		AM_DEBUG(1, "AV device %d has already been openned", dev_no);
+		ret = AM_AV_ERR_BUSY;
+		goto final;
+	}
+
+	dev->dev_no  = dev_no;
+	pthread_mutex_init(&dev->lock, NULL);
+	dev->openned = AM_TRUE;
+	dev->mode    = 0;
+	dev->video_x = 0;
+	dev->video_y = 0;
+	dev->video_w = 1280;
+	dev->video_h = 720;
+	dev->video_contrast   = 0;
+	dev->video_saturation = 0;
+	dev->video_brightness = 0;
+	dev->video_enable     = AM_TRUE;
+	dev->video_blackout   = AM_TRUE;
+	dev->video_ratio      = AM_AV_VIDEO_ASPECT_AUTO;
+	dev->video_match      = AM_AV_VIDEO_ASPECT_MATCH_IGNORE;
+	dev->video_mode       = AM_AV_VIDEO_DISPLAY_NORMAL;
+	dev->vout_dev_no      = para->vout_dev_no;
+	dev->vout_w           = 0;
+	dev->vout_h           = 0;
+	dev->vpath_fs         = -1;
+	dev->vpath_di         = -1;
+	dev->vpath_ppmgr      = -1;
+	dev->afd_enable       = para->afd_enable;
+	dev->crypt_ops        = NULL;
+
+	if (dev->drv->open)
+	{
+		ret = dev->drv->open(dev, para);
+		if(ret!=AM_SUCCESS)
+			goto final;
+	}
+
+#if 0	
+	if (ret == AM_SUCCESS)
+	{
+		AM_EVT_Subscribe(dev->vout_dev_no, AM_VOUT_EVT_FORMAT_CHANGED, av_vout_format_changed, dev);
+	}
+#endif
+final:
+	pthread_mutex_unlock(&am_gAdpLock);
+
+	return ret;
+}
+
+/**\brief 关闭音视频解码设备
+ * \param dev_no 音视频设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_Close(int dev_no)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&am_gAdpLock);
+
+	/*注销事件*/
+	AM_EVT_Unsubscribe(dev->vout_dev_no, AM_VOUT_EVT_FORMAT_CHANGED, av_vout_format_changed, dev);
+
+	/*停止播放*/
+	av_stop_all(dev, dev->mode);
+
+	if (dev->drv->close)
+		dev->drv->close(dev);
+
+	/*释放资源*/
+	pthread_mutex_destroy(&dev->lock);
+
+	dev->openned = AM_FALSE;
+
+	pthread_mutex_unlock(&am_gAdpLock);
+
+	return ret;
+}
+
+/**\brief 设定TS流的输入源
+ * \param dev_no 音视频设备号
+ * \param src TS输入源
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_SetTSSource(int dev_no, AM_AV_TSSource_t src)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (dev->drv->ts_source)
+		ret = dev->drv->ts_source(dev, src);
+
+	if (ret == AM_SUCCESS)
+		dev->ts_player.src = src;
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 设置FrontEnd的锁定状态
+ * \param dev_no 音视频设备号
+ * \param value FrontEnd的状态
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+
+AM_ErrorCode_t AM_AV_setFEStatus(int dev_no,int value)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+	if (dev->drv->set_fe_status) {
+		ret = dev->drv->set_fe_status(dev,value);
+	}
+	return ret;
+}
+
+/**\brief 开始解码TS流
+ * \param dev_no 音视频设备号
+ * \param vpid 视频流PID
+ * \param apid 音频流PID
+ * \param pcrpid PCR PID
+ * \param vfmt 视频压缩格式
+ * \param afmt 音频压缩格式
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_StartTSWithPCR(int dev_no, uint16_t vpid, uint16_t apid, uint16_t pcrpid, AM_AV_VFormat_t vfmt, AM_AV_AFormat_t afmt)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	AV_TSPlayPara_t para;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	para.vpid = vpid;
+	para.vfmt = vfmt;
+	para.apid = apid;
+	para.afmt = afmt;
+	para.pcrpid = pcrpid;
+	para.sub_apid = -1;
+
+	ret = av_start(dev, AV_PLAY_TS, &para);
+	if (ret == AM_SUCCESS) {
+		dev->curr_para.ts = para;
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 开始解码TS流
+ * \param dev_no 音视频设备号
+ * \param vpid 视频流PID
+ * \param apid 音频流PID
+ * \param vfmt 视频压缩格式
+ * \param afmt 音频压缩格式
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_StartTS(int dev_no, uint16_t vpid, uint16_t apid, AM_AV_VFormat_t vfmt, AM_AV_AFormat_t afmt)
+{
+	return AM_AV_StartTSWithPCR(dev_no, vpid, apid, vpid, vfmt, afmt);
+}
+
+/**\brief 停止TS流解码
+ * \param dev_no 音视频设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_StopTS(int dev_no)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	ret = av_stop(dev, AV_PLAY_TS);
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 开始播放文件
+ * \param dev_no 音视频设备号
+ * \param[in] fname 媒体文件名
+ * \param loop 是否循环播放
+ * \param pos 播放的起始位置
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_StartFile(int dev_no, const char *fname, AM_Bool_t loop, int pos)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	AV_FilePlayPara_t para;
+
+	assert(fname);
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	para.name = fname;
+	para.loop = loop;
+	para.pos  = pos;
+	para.start= AM_TRUE;
+
+	ret = av_start(dev, AV_PLAY_FILE, &para);
+	if (ret == AM_SUCCESS)
+	{
+		snprintf(dev->file_player.name, sizeof(dev->file_player.name), "%s", fname);
+		dev->file_player.speed = 0;
+		dev->curr_para.file = para;
+		dev->curr_para.start = AM_TRUE;
+		dev->curr_para.speed = 0;
+		dev->curr_para.pause = AM_FALSE;
+		dev->curr_para.file.name = dev->curr_para.file_name;
+		snprintf(dev->curr_para.file_name, sizeof(dev->curr_para.file_name), "%s", fname);
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 切换到文件播放模式但不开始播放
+ * \param dev_no 音视频设备号
+ * \param[in] fname 媒体文件名
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_AddFile(int dev_no, const char *fname)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	AV_FilePlayPara_t para;
+
+	assert(fname);
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	para.name = fname;
+	para.start= AM_FALSE;
+
+	ret = av_start(dev, AV_PLAY_FILE, &para);
+	if (ret == AM_SUCCESS)
+	{
+		snprintf(dev->file_player.name, sizeof(dev->file_player.name), "%s", fname);
+		dev->file_player.speed = 0;
+		dev->curr_para.file = para;
+		dev->curr_para.start = AM_FALSE;
+		dev->curr_para.speed = 0;
+		dev->curr_para.pause = AM_FALSE;
+		dev->curr_para.file.name = dev->curr_para.file_name;
+		snprintf(dev->curr_para.file_name, sizeof(dev->curr_para.file_name), "%s", fname);
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 开始播放已经添加的文件,在AM_AV_AddFile后调用此函数开始播放
+ * \param dev_no 音视频设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_StartCurrFile(int dev_no)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (!(dev->mode & AV_PLAY_FILE))
+	{
+		AM_DEBUG(1, "do not in the file play mode");
+		ret = AM_AV_ERR_ILLEGAL_OP;
+	}
+
+	if (ret == AM_SUCCESS)
+	{
+		if (dev->drv->file_cmd)
+		{
+			ret = dev->drv->file_cmd(dev, AV_PLAY_START, 0);
+			if (ret == AM_SUCCESS) {
+				dev->curr_para.file.start = AM_TRUE;
+				dev->curr_para.start = AM_TRUE;
+			}
+		}
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 停止播放文件
+ * \param dev_no 音视频设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_StopFile(int dev_no)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	ret = av_stop(dev, AV_PLAY_FILE);
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 暂停文件播放
+ * \param dev_no 音视频设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_PauseFile(int dev_no)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (!(dev->mode & AV_PLAY_FILE))
+	{
+		AM_DEBUG(1, "do not in the file play mode");
+		ret = AM_AV_ERR_ILLEGAL_OP;
+	}
+
+	if (ret == AM_SUCCESS)
+	{
+		if (dev->drv->file_cmd)
+		{
+			ret = dev->drv->file_cmd(dev, AV_PLAY_PAUSE, NULL);
+			if (ret == AM_SUCCESS) {
+				dev->curr_para.pause = AM_TRUE;
+			}
+		}
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 恢复文件播放
+ * \param dev_no 音视频设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_ResumeFile(int dev_no)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (!(dev->mode & AV_PLAY_FILE))
+	{
+		AM_DEBUG(1, "do not in the file play mode");
+		ret = AM_AV_ERR_ILLEGAL_OP;
+	}
+
+	if (ret == AM_SUCCESS)
+	{
+		if (dev->drv->file_cmd)
+		{
+			ret = dev->drv->file_cmd(dev, AV_PLAY_RESUME, NULL);
+			if (ret == AM_SUCCESS) {
+				dev->curr_para.pause = AM_FALSE;
+			}
+		}
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 暂停数据注入
+ * \param dev_no 音视频设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_PauseInject(int dev_no)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (!(dev->mode & AV_INJECT))
+	{
+		AM_DEBUG(1, "do not in the inject mode");
+		ret = AM_AV_ERR_ILLEGAL_OP;
+	}
+
+	if (ret == AM_SUCCESS)
+	{
+		if (dev->drv->inject_cmd)
+		{
+			ret = dev->drv->inject_cmd(dev, AV_PLAY_PAUSE, NULL);
+			if (ret == AM_SUCCESS) {
+				dev->curr_para.pause = AM_TRUE;
+			}
+		}
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 恢复注入
+ * \param dev_no 音视频设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_ResumeInject(int dev_no)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (!(dev->mode & AV_INJECT))
+	{
+		AM_DEBUG(1, "do not in the inject mode");
+		ret = AM_AV_ERR_ILLEGAL_OP;
+	}
+
+	if (ret == AM_SUCCESS)
+	{
+		if (dev->drv->inject_cmd)
+		{
+			ret = dev->drv->inject_cmd(dev, AV_PLAY_RESUME, NULL);
+			if (ret == AM_SUCCESS) {
+				dev->curr_para.pause = AM_FALSE;
+			}
+		}
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 设定当前文件播放位置
+ * \param dev_no 音视频设备号
+ * \param pos 播放位置
+ * \param start 是否开始播放
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_SeekFile(int dev_no, int pos, AM_Bool_t start)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	AV_FileSeekPara_t para;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (!(dev->mode & AV_PLAY_FILE))
+	{
+		AM_DEBUG(1, "do not in the file play mode");
+		ret = AM_AV_ERR_ILLEGAL_OP;
+	}
+
+	if (ret == AM_SUCCESS)
+	{
+		if (dev->drv->file_cmd)
+		{
+			para.pos   = pos;
+			para.start = start;
+			ret = dev->drv->file_cmd(dev, AV_PLAY_SEEK, &para);
+		}
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+	
+	return ret;
+}
+
+/**\brief 快速向前播放
+ * \param dev_no 音视频设备号
+ * \param speed 播放速度
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_FastForwardFile(int dev_no, int speed)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	if(speed<0)
+	{
+		AM_DEBUG(1, "speed must >= 0");
+		return AM_AV_ERR_INVAL_ARG;
+	}
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (!(dev->mode & AV_PLAY_FILE))
+	{
+		AM_DEBUG(1, "do not in the file play mode");
+		ret = AM_AV_ERR_ILLEGAL_OP;
+	}
+
+	if (ret == AM_SUCCESS)
+	{
+		if (dev->drv->file_cmd && (dev->file_player.speed != speed))
+		{
+			ret = dev->drv->file_cmd(dev, AV_PLAY_FF, (void*)(long)speed);
+			if (ret == AM_SUCCESS)
+			{
+				dev->file_player.speed = speed;
+				dev->curr_para.speed = speed;
+//				AM_EVT_Signal(dev->dev_no, AM_AV_EVT_PLAYER_SPEED_CHANGED, (void*)(long)speed);
+			}
+		}
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 快速向后播放
+ * \param dev_no 音视频设备号
+ * \param speed 播放速度
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_FastBackwardFile(int dev_no, int speed)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	if (speed < 0)
+	{
+		AM_DEBUG(1, "speed must >= 0");
+		return AM_AV_ERR_INVAL_ARG;
+	}
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (!(dev->mode & AV_PLAY_FILE))
+	{
+		AM_DEBUG(1, "do not in the file play mode");
+		ret = AM_AV_ERR_ILLEGAL_OP;
+	}
+
+	if (ret == AM_SUCCESS)
+	{
+		if (dev->drv->file_cmd && (dev->file_player.speed != -speed))
+		{
+			ret = dev->drv->file_cmd(dev, AV_PLAY_FB, (void*)(long)speed);
+			if (ret == AM_SUCCESS)
+			{
+				dev->file_player.speed = -speed;
+				dev->curr_para.speed = -speed;
+//				AM_EVT_Signal(dev->dev_no, AM_AV_EVT_PLAYER_SPEED_CHANGED, (void*)(long)-speed);
+			}
+		}
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 取得当前媒体文件信息
+ * \param dev_no 音视频设备号
+ * \param[out] info 返回媒体文件信息
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_GetCurrFileInfo(int dev_no, AM_AV_FileInfo_t *info)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	assert(info);
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (!(dev->mode & AV_PLAY_FILE))
+	{
+		AM_DEBUG(1, "do not in the file play mode");
+		ret = AM_AV_ERR_ILLEGAL_OP;
+	}
+
+	if (ret == AM_SUCCESS)
+	{
+		if (dev->drv->file_info)
+		{
+			ret = dev->drv->file_info(dev, info);
+		}
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 取得媒体文件播放状态
+ * \param dev_no 音视频设备号
+ * \param[out] status 返回媒体文件播放状态
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_GetPlayStatus(int dev_no, AM_AV_PlayStatus_t *status)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	assert(status);
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (!(dev->mode & AV_PLAY_FILE))
+	{
+		AM_DEBUG(1, "do not in the file play mode");
+		ret = AM_AV_ERR_ILLEGAL_OP;
+	}
+
+	if (ret == AM_SUCCESS)
+	{
+		if (!dev->drv->file_status)
+		{
+			AM_DEBUG(1, "do not support file_status");
+			ret = AM_AV_ERR_NOT_SUPPORTED;
+		}
+	}
+
+	if (ret == AM_SUCCESS)
+	{
+		ret = dev->drv->file_status(dev, status);
+	}
+	
+	pthread_mutex_unlock(&dev->lock);
+	
+	return ret;
+}
+
+/**\brief 开始进入数据注入模式
+ * \param dev_no 音视频设备号
+ * \param[in] para 注入参数
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_StartInject(int dev_no, const AM_AV_InjectPara_t *para)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	assert(para);
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	ret = av_start(dev, AV_INJECT, (void*)para);
+	if (ret == AM_SUCCESS) {
+		dev->curr_para.inject.para = *para;
+		dev->curr_para.start = AM_TRUE;
+		dev->curr_para.speed  = 0;
+		dev->curr_para.pause  = AM_FALSE;
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief Set DRM mode
+ * \param dev_no 音视频设备号
+ * \param[in] enable enable or disable DRM mode
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_SetDRMMode(int dev_no, AM_AV_DrmMode_t drm_mode)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_AV_ERR_SYS;
+
+	//assert(para);
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (dev->drv->set_drm_mode)
+		ret = dev->drv->set_drm_mode(dev, drm_mode);
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 进入数据注入模式后,向音视频设备注入数据
+ * \param dev_no 音视频设备号
+ * \param type 注入数据类型
+ * \param[in] data 注入数据的缓冲区
+ * \param[in,out] size 传入要注入数据的长度,返回实际注入数据的长度
+ * \param timeout 等待设备的超时时间,以毫秒为单位,<0表示一直等待
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_InjectData(int dev_no, AM_AV_InjectType_t type, uint8_t *data, int *size, int timeout)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	assert(data && size);
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (!(dev->mode & AV_INJECT))
+	{
+		//AM_DEBUG(1, "do not in the file play mode");
+		ret = AM_AV_ERR_ILLEGAL_OP;
+	}
+
+	if (ret == AM_SUCCESS)
+	{
+		if (dev->drv->inject)
+			ret = dev->drv->inject(dev, type, data, size, timeout);
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 停止数据注入模式
+ * \param dev_no 音视频设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_StopInject(int dev_no)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	ret = av_stop(dev, AV_INJECT);
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 取得JPEG图片文件属性
+ * \param dev_no 音视频设备号
+ * \param[in] fname 图片文件名
+ * \param[out] info 文件属性
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_GetJPEGInfo(int dev_no, const char *fname, AM_AV_JPEGInfo_t *info)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	uint8_t *data;
+	struct stat sbuf;
+	int len;
+	int fd;
+	AV_DataPlayPara_t para;
+
+	assert(fname && info);
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	fd = open(fname, O_RDONLY);
+	if (fd == -1)
+	{
+		AM_DEBUG(1, "cannot open \"%s\"", fname);
+		return AM_AV_ERR_CANNOT_OPEN_FILE;
+	}
+
+	if (stat(fname, &sbuf) == -1)
+	{
+		AM_DEBUG(1, "stat failed");
+		close(fd);
+		return AM_AV_ERR_SYS;
+	}
+
+	len = sbuf.st_size;
+
+	data = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
+	if (data == (void *)-1)
+	{
+		AM_DEBUG(1, "mmap failed");
+		close(fd);
+		return AM_AV_ERR_SYS;
+	}
+
+	para.data  = data;
+	para.len   = len;
+	para.times = 1;
+	para.fd    = fd;
+	para.need_free = AM_TRUE;
+	para.para  = info;
+
+	pthread_mutex_lock(&dev->lock);
+
+	ret = av_start(dev, AV_GET_JPEG_INFO, &para);
+
+	if (ret == AM_SUCCESS)
+		av_stop(dev, AV_GET_JPEG_INFO);
+
+	pthread_mutex_unlock(&dev->lock);
+
+	if (ret != AM_SUCCESS)
+		av_free_data_para(&para);
+
+	return ret;
+}
+
+/**\brief 取得JPEG图片数据属性
+ * \param dev_no 音视频设备号
+ * \param[in] data 图片数据缓冲区
+ * \param len 数据缓冲区大小
+ * \param[out] info 文件属性
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_GetJPEGDataInfo(int dev_no, const uint8_t *data, int len, AM_AV_JPEGInfo_t *info)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	AV_DataPlayPara_t para;
+
+	assert(data && info);
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	para.data  = data;
+	para.len   = len;
+	para.times = 1;
+	para.fd    = -1;
+	para.need_free = AM_FALSE;
+	para.para  = info;
+
+	pthread_mutex_lock(&dev->lock);
+
+	ret = av_start(dev, AV_GET_JPEG_INFO, info);
+
+	if (ret == AM_SUCCESS)
+		av_stop(dev, AV_GET_JPEG_INFO);
+
+	pthread_mutex_unlock(&dev->lock);
+
+	if (ret != AM_SUCCESS)
+		av_free_data_para(&para);
+
+	return ret;
+}
+
+/**\brief 解码JPEG图片文件
+ * \param dev_no 音视频设备号
+ * \param[in] fname 图片文件名
+ * \param[in] para 输出JPEG的参数
+ * \param[out] surf 返回JPEG图片的surface
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_DecodeJPEG(int dev_no, const char *fname, const AM_AV_SurfacePara_t *para, AM_OSD_Surface_t **surf)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	uint8_t *data;
+	struct stat sbuf;
+	int len;
+	int fd;
+	AV_DataPlayPara_t d_para;
+	AM_AV_SurfacePara_t s_para;
+	AV_JPEGDecodePara_t jpeg;
+
+	assert(fname && surf);
+
+	if (!para)
+	{
+		para = &s_para;
+		s_para.width  = 0;
+		s_para.height = 0;
+		s_para.angle  = 0;
+		s_para.option = 0;
+	}
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	fd = open(fname, O_RDONLY);
+	if (fd == -1)
+	{
+		AM_DEBUG(1, "cannot open \"%s\"", fname);
+		return AM_AV_ERR_CANNOT_OPEN_FILE;
+	}
+
+	if (stat(fname, &sbuf) == -1)
+	{
+		AM_DEBUG(1, "stat failed");
+		close(fd);
+		return AM_AV_ERR_SYS;
+	}
+
+	len = sbuf.st_size;
+
+	data = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
+	if (data == (void *)-1)
+	{
+		AM_DEBUG(1, "mmap failed");
+		close(fd);
+		return AM_AV_ERR_SYS;
+	}
+
+	d_para.data  = data;
+	d_para.len   = len;
+	d_para.times = 1;
+	d_para.fd    = fd;
+	d_para.need_free = AM_TRUE;
+	d_para.para  = &jpeg;
+
+	jpeg.surface = NULL;
+	jpeg.para    = *para;
+
+	pthread_mutex_lock(&dev->lock);
+
+	ret = av_start(dev, AV_DECODE_JPEG, &d_para);
+
+	if (ret == AM_SUCCESS)
+		av_stop(dev, AV_DECODE_JPEG);
+
+	pthread_mutex_unlock(&dev->lock);
+
+	if (ret != AM_SUCCESS)
+		av_free_data_para(&d_para);
+	else
+		*surf = jpeg.surface;
+
+	return ret;
+}
+
+/**\brief 解码JPEG图片数据
+ * \param dev_no 音视频设备号
+ * \param[in] data 图片数据缓冲区
+ * \param len 数据缓冲区大小
+ * \param[in] para 输出JPEG的参数
+ * \param[out] surf 返回JPEG图片的surface
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_DacodeJPEGData(int dev_no, const uint8_t *data, int len, const AM_AV_SurfacePara_t *para, AM_OSD_Surface_t **surf)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	AV_DataPlayPara_t d_para;
+	AM_AV_SurfacePara_t s_para;
+	AV_JPEGDecodePara_t jpeg;
+
+	assert(data && surf);
+
+	if (!para)
+	{
+		para = &s_para;
+		s_para.width  = 0;
+		s_para.height = 0;
+		s_para.angle  = 0;
+		s_para.option = 0;
+	}
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	d_para.data  = data;
+	d_para.len   = len;
+	d_para.times = 1;
+	d_para.fd    = -1;
+	d_para.need_free = AM_FALSE;
+	d_para.para  = &jpeg;
+
+	jpeg.surface = NULL;
+	jpeg.para    = *para;
+
+	pthread_mutex_lock(&dev->lock);
+
+	ret = av_start(dev, AV_DECODE_JPEG, &d_para);
+	if (ret == AM_SUCCESS)
+		av_stop(dev, AV_DECODE_JPEG);
+
+	pthread_mutex_unlock(&dev->lock);
+
+	if (ret != AM_SUCCESS)
+		av_free_data_para(&d_para);
+	else
+		*surf = jpeg.surface;
+
+	return ret;
+}
+
+/**\brief 解码视频基础流文件
+ * \param dev_no 音视频设备号
+ * \param format 视频压缩格式
+ * \param[in] fname 视频文件名
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_StartVideoES(int dev_no, AM_AV_VFormat_t format, const char *fname)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	uint8_t *data;
+	struct stat sbuf;
+	int len;
+	int fd;
+	AV_DataPlayPara_t para;
+
+	assert(fname);
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	fd = open(fname, O_RDONLY);
+	if (fd == -1)
+	{
+		AM_DEBUG(1, "cannot open \"%s\"", fname);
+		return AM_AV_ERR_CANNOT_OPEN_FILE;
+	}
+
+	if (stat(fname, &sbuf) == -1)
+	{
+		AM_DEBUG(1, "stat failed");
+		close(fd);
+		return AM_AV_ERR_SYS;
+	}
+
+	len = sbuf.st_size;
+
+	data = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
+	if (data == (void *)-1)
+	{
+		AM_DEBUG(1, "mmap failed");
+		close(fd);
+		return AM_AV_ERR_SYS;
+	}
+
+	para.data  = data;
+	para.len   = len;
+	para.times = 1;
+	para.fd    = fd;
+	para.need_free = AM_TRUE;
+	para.para  = (void*)format;
+
+	pthread_mutex_lock(&dev->lock);
+
+	ret = av_start(dev, AV_PLAY_VIDEO_ES, &para);
+	if (ret == AM_SUCCESS) {
+		dev->curr_para.ves = para;
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	if (ret != AM_SUCCESS)
+		av_free_data_para(&para);
+
+	return ret;
+}
+
+/**\brief 解码视频基础流数据
+ * \param dev_no 音视频设备号
+ * \param format 视频压缩格式
+ * \param[in] data 视频数据缓冲区
+ * \param len 数据缓冲区大小
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_StartVideoESData(int dev_no, AM_AV_VFormat_t format, const uint8_t *data, int len)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	AV_DataPlayPara_t para;
+
+	assert(data);
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	para.data  = data;
+	para.len   = len;
+	para.times = 1;
+	para.fd    = -1;
+	para.need_free = AM_FALSE;
+	para.para  = (void*)format;
+
+	pthread_mutex_lock(&dev->lock);
+
+	ret = av_start(dev, AV_PLAY_VIDEO_ES, &para);
+	if (ret == AM_SUCCESS) {
+		dev->curr_para.ves = para;
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	if (ret != AM_SUCCESS)
+		av_free_data_para(&para);
+
+	return ret;
+}
+
+/**\brief 解码音频基础流文件
+ * \param dev_no 音视频设备号
+ * \param format 音频压缩格式
+ * \param[in] fname 视频文件名
+ * \param times 播放次数,<=0表示一直播放
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_StartAudioES(int dev_no, AM_AV_AFormat_t format, const char *fname, int times)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	uint8_t *data;
+	struct stat sbuf;
+	int len;
+	int fd;
+	AV_DataPlayPara_t para;
+
+	assert(fname);
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	fd = open(fname, O_RDONLY);
+	if (fd == -1)
+	{
+		AM_DEBUG(1, "cannot open \"%s\"", fname);
+		return AM_AV_ERR_CANNOT_OPEN_FILE;
+	}
+
+	if (stat(fname, &sbuf) == -1)
+	{
+		AM_DEBUG(1, "stat failed");
+		close(fd);
+		return AM_AV_ERR_SYS;
+	}
+
+	len = sbuf.st_size;
+
+	data = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
+	if (data == (void *)-1)
+	{
+		AM_DEBUG(1, "mmap failed");
+		close(fd);
+		return AM_AV_ERR_SYS;
+	}
+
+	para.data  = data;
+	para.len   = len;
+	para.times = times;
+	para.fd    = fd;
+	para.need_free = AM_TRUE;
+	para.para  = (void*)format;
+
+	pthread_mutex_lock(&dev->lock);
+
+	ret = av_start(dev, AV_PLAY_AUDIO_ES, &para);
+	if (ret == AM_SUCCESS) {
+		dev->curr_para.aes = para;
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	if (ret != AM_SUCCESS)
+		av_free_data_para(&para);
+
+	return ret;
+}
+
+/**\brief 解码音频基础流数据
+ * \param dev_no 音视频设备号
+ * \param format 音频压缩格式
+ * \param[in] data 音频数据缓冲区
+ * \param len 数据缓冲区大小
+ * \param times 播放次数,<=0表示一直播放
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_StartAudioESData(int dev_no, AM_AV_AFormat_t format, const uint8_t *data, int len, int times)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	AV_DataPlayPara_t para;
+
+	assert(data);
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	para.data  = data;
+	para.len   = len;
+	para.times = times;
+	para.fd    = -1;
+	para.need_free = AM_FALSE;
+	para.para  = (void*)format;
+
+	pthread_mutex_lock(&dev->lock);
+
+	ret = av_start(dev, AV_PLAY_AUDIO_ES, &para);
+	if (ret == AM_SUCCESS) {
+		dev->curr_para.aes = para;
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	if (ret != AM_SUCCESS)
+		av_free_data_para(&para);
+
+	return ret;
+}
+
+/**\brief 停止解码视频基础流
+ * \param dev_no 音视频设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_StopVideoES(int dev_no)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	ret = av_stop(dev, AV_PLAY_VIDEO_ES);
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 停止解码音频基础流
+ * \param dev_no 音视频设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_StopAudioES(int dev_no)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	ret = av_stop(dev, AV_PLAY_AUDIO_ES);
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 设定视频窗口
+ * \param dev_no 音视频设备号
+ * \param x 窗口左上顶点x坐标
+ * \param y 窗口左上顶点y坐标
+ * \param w 窗口宽度
+ * \param h 窗口高度
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_SetVideoWindow(int dev_no, int x, int y, int w, int h)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	AV_VideoWindow_t win;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	win.x = x;
+	win.y = y;
+	win.w = w;
+	win.h = h;
+
+	pthread_mutex_lock(&dev->lock);
+
+	//if ((dev->video_x != x) || (dev->video_y != y) || (dev->video_w != w) || (dev->video_h != h))
+	{
+		if (dev->drv->set_video_para)
+		{
+			ret = dev->drv->set_video_para(dev, AV_VIDEO_PARA_WINDOW, &win);
+		}
+
+		if (ret == AM_SUCCESS)
+		{
+			AM_AV_VideoWindow_t win;
+
+			dev->video_x = x;
+			dev->video_y = y;
+			dev->video_w = w;
+			dev->video_h = h;
+
+			win.x = x;
+			win.y = y;
+			win.w = w;
+			win.h = h;
+
+//			AM_EVT_Signal(dev->dev_no, AM_AV_EVT_VIDEO_WINDOW_CHANGED, &win);
+		}
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 设定视频裁切
+ * \param dev_no 音视频设备号
+ * \param x 窗口左上顶点x坐标
+ * \param y 窗口左上顶点y坐标
+ * \param w 窗口宽度
+ * \param h 窗口高度
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_SetVideoCropping(int dev_no, int Voffset0, int Hoffset0, int Voffset1, int Hoffset1)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	AV_VideoWindow_t win;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	win.x = Voffset0;
+	win.y = Hoffset0;
+	win.w = Voffset1;
+	win.h = Hoffset1;
+
+	pthread_mutex_lock(&dev->lock);
+
+	//if ((dev->video_x != x) || (dev->video_y != y) || (dev->video_w != w) || (dev->video_h != h))
+	{
+		if (dev->drv->set_video_para)
+		{
+			ret = dev->drv->set_video_para(dev, AV_VIDEO_PARA_CROP, &win);
+		}
+
+		if (ret == AM_SUCCESS)
+		{
+			AM_AV_VideoWindow_t win;
+
+			win.x = Voffset0;
+            win.y = Hoffset0;
+            win.w = Voffset1;
+            win.h = Hoffset1;
+
+//			AM_EVT_Signal(dev->dev_no, AM_AV_EVT_VIDEO_CROPPING_CHANGED, &win);
+		}
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+/**\brief 返回视频窗口
+ * \param dev_no 音视频设备号
+ * \param[out] x 返回窗口左上顶点x坐标
+ * \param[out] y 返回窗口左上顶点y坐标
+ * \param[out] w 返回窗口宽度
+ * \param[out] h 返回窗口高度
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_GetVideoWindow(int dev_no, int *x, int *y, int *w, int *h)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (x)
+		*x = dev->video_x;
+	if (y)
+		*y = dev->video_y;
+	if (w)
+		*w = dev->video_w;
+	if (h)
+		*h = dev->video_h;
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 设定视频对比度(0~100)
+ * \param dev_no 音视频设备号
+ * \param val 视频对比度值
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_SetVideoContrast(int dev_no, int val)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	val = AM_MAX(val, AM_AV_VIDEO_CONTRAST_MIN);
+	val = AM_MIN(val, AM_AV_VIDEO_CONTRAST_MAX);
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (dev->video_contrast != val)
+	{
+		if (dev->drv->set_video_para)
+		{
+			ret = dev->drv->set_video_para(dev, AV_VIDEO_PARA_CONTRAST, (void*)(long)val);
+		}
+
+		if (ret == AM_SUCCESS)
+		{
+			dev->video_contrast = val;
+//			AM_EVT_Signal(dev->dev_no, AM_AV_EVT_VIDEO_CONTRAST_CHANGED, (void*)(long)val);
+		}
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 取得当前视频对比度
+ * \param dev_no 音视频设备号
+ * \param[out] val 返回当前视频对比度值
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_GetVideoContrast(int dev_no, int *val)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (val)
+		*val = dev->video_contrast;
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 设定视频饱和度(0~100)
+ * \param dev_no 音视频设备号
+ * \param val 视频饱和度值
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_SetVideoSaturation(int dev_no, int val)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	val = AM_MAX(val, AM_AV_VIDEO_SATURATION_MIN);
+	val = AM_MIN(val, AM_AV_VIDEO_SATURATION_MAX);
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (dev->video_saturation != val)
+	{
+		if (dev->drv->set_video_para)
+		{
+			ret = dev->drv->set_video_para(dev, AV_VIDEO_PARA_SATURATION, (void*)(long)val);
+		}
+
+		if (ret == AM_SUCCESS)
+		{
+			dev->video_saturation = val;
+//			AM_EVT_Signal(dev->dev_no, AM_AV_EVT_VIDEO_SATURATION_CHANGED, (void*)(long)val);
+		}
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 取得当前视频饱和度
+ * \param dev_no 音视频设备号
+ * \param[out] val 返回当前视频饱和度值
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_GetVideoSaturation(int dev_no, int *val)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (val)
+		*val = dev->video_saturation;
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 设定视频亮度(0~100)
+ * \param dev_no 音视频设备号
+ * \param val 视频亮度值
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_SetVideoBrightness(int dev_no, int val)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	val = AM_MAX(val, AM_AV_VIDEO_BRIGHTNESS_MIN);
+	val = AM_MIN(val, AM_AV_VIDEO_BRIGHTNESS_MAX);
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (dev->video_brightness != val)
+	{
+		if (dev->drv->set_video_para)
+		{
+			ret = dev->drv->set_video_para(dev, AV_VIDEO_PARA_BRIGHTNESS, (void*)(long)val);
+		}
+
+		if (ret == AM_SUCCESS)
+		{
+			dev->video_brightness = val;
+//			AM_EVT_Signal(dev->dev_no, AM_AV_EVT_VIDEO_BRIGHTNESS_CHANGED, (void*)(long)val);
+		}
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 取得当前视频亮度
+ * \param dev_no 音视频设备号
+ * \param[out] val 返回当前视频亮度值
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_GetVideoBrightness(int dev_no, int *val)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (val)
+		*val = dev->video_brightness;
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 显示视频层
+ * \param dev_no 音视频设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_EnableVideo(int dev_no)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	//if (!dev->video_enable)
+	{
+		if (dev->drv->set_video_para)
+		{
+			ret = dev->drv->set_video_para(dev, AV_VIDEO_PARA_ENABLE, (void*)(size_t)2);
+		}
+
+		if (ret == AM_SUCCESS)
+		{
+			dev->video_enable = AM_TRUE;
+//			AM_EVT_Signal(dev->dev_no, AM_AV_EVT_VIDEO_ENABLED, NULL);
+		}
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 隐藏视频层
+ * \param dev_no 音视频设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_DisableVideo(int dev_no)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	//if (dev->video_enable)
+	{
+		if (dev->drv->set_video_para)
+		{
+			ret = dev->drv->set_video_para(dev, AV_VIDEO_PARA_ENABLE, (void*)AM_FALSE);
+		}
+
+		if (ret == AM_SUCCESS)
+		{
+			dev->video_enable = AM_FALSE;
+//			AM_EVT_Signal(dev->dev_no, AM_AV_EVT_VIDEO_DISABLED, NULL);
+		}
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 设定视频长宽比
+ * \param dev_no 音视频设备号
+ * \param ratio 长宽比
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_SetVideoAspectRatio(int dev_no, AM_AV_VideoAspectRatio_t ratio)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (dev->drv->set_video_para)
+	{
+		ret = dev->drv->set_video_para(dev, AV_VIDEO_PARA_RATIO, (void*)ratio);
+	}
+
+	if (ret == AM_SUCCESS)
+	{
+		dev->video_ratio = ratio;
+//		AM_EVT_Signal(dev->dev_no, AM_AV_EVT_VIDEO_ASPECT_RATIO_CHANGED, (void*)ratio);
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 取得视频长宽比
+ * \param dev_no 音视频设备号
+ * \param[out] ratio 长宽比
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_GetVideoAspectRatio(int dev_no, AM_AV_VideoAspectRatio_t *ratio)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (ratio)
+		*ratio = dev->video_ratio;
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 设定视频长宽比匹配模式
+ * \param dev_no 音视频设备号
+ * \param mode 长宽比匹配模式
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_SetVideoAspectMatchMode(int dev_no, AM_AV_VideoAspectMatchMode_t mode)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (dev->drv->set_video_para)
+	{
+		ret = dev->drv->set_video_para(dev, AV_VIDEO_PARA_RATIO_MATCH, (void*)mode);
+	}
+
+	if (ret == AM_SUCCESS)
+	{
+		dev->video_match = mode;
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 取得视频长宽比匹配模式
+ * \param dev_no 音视频设备号
+ * \param[out] mode 长宽比匹配模式
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_GetVideoAspectMatchMode(int dev_no, AM_AV_VideoAspectMatchMode_t *mode)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (mode)
+		*mode = dev->video_match;
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 设定视频停止时自动隐藏视频层
+ * \param dev_no 音视频设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_EnableVideoBlackout(int dev_no)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (dev->drv->set_video_para)
+	{
+		ret = dev->drv->set_video_para(dev, AV_VIDEO_PARA_BLACKOUT, (void*)AM_TRUE);
+	}
+
+	if (ret == AM_SUCCESS)
+	{
+		dev->video_blackout = AM_TRUE;
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 视频停止时不隐藏视频层
+ * \param dev_no 音视频设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_DisableVideoBlackout(int dev_no)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (dev->drv->set_video_para)
+	{
+		ret = dev->drv->set_video_para(dev, AV_VIDEO_PARA_BLACKOUT, (void*)AM_FALSE);
+	}
+
+	if (ret == AM_SUCCESS)
+	{
+		dev->video_blackout = AM_FALSE;
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 设定视频显示模式
+ * \param dev_no 音视频设备号
+ * \param mode 视频显示模式
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_SetVideoDisplayMode(int dev_no, AM_AV_VideoDisplayMode_t mode)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (dev->video_mode != mode)
+	{
+		if (dev->drv->set_video_para)
+		{
+			ret = dev->drv->set_video_para(dev, AV_VIDEO_PARA_MODE, (void*)mode);
+		}
+
+		if (ret == AM_SUCCESS)
+		{
+			dev->video_mode = mode;
+//			AM_EVT_Signal(dev->dev_no, AM_AV_EVT_VIDEO_DISPLAY_MODE_CHANGED, (void*)mode);
+		}
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 取得当前视频显示模式
+ * \param dev_no 音视频设备号
+ * \param mode 返回当前视频显示模式
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_GetVideoDisplayMode(int dev_no, AM_AV_VideoDisplayMode_t *mode)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (mode)
+		*mode = dev->video_mode;
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 清除视频缓冲区
+ * \param dev_no 音视频设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_ClearVideoBuffer(int dev_no)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (dev->drv->set_video_para)
+	{
+		ret = dev->drv->set_video_para(dev, AV_VIDEO_PARA_CLEAR_VBUF, NULL);
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 取得当前视频显示祯图形(此操作只有视频停止后才可进行)
+ * \param dev_no 音视频设备号
+ * \param[in] para 创建图像表面的参数
+ * \param[out] s 返回图像
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_GetVideoFrame(int dev_no, const AM_AV_SurfacePara_t *para, AM_OSD_Surface_t **s)
+{
+	AM_AV_Device_t *dev;
+	AM_AV_SurfacePara_t real_para;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	assert(s);
+
+	if (!para)
+	{
+		memset(&real_para, 0, sizeof(real_para));
+		para = &real_para;
+	}
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (dev->drv->video_frame)
+		ret = dev->drv->video_frame(dev, para, s);
+	else
+		ret = AM_AV_ERR_NOT_SUPPORTED;
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 取得当前视频状态
+ * \param dev_no 音视频设备号
+ * \param[out]status 返回视频状态
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+
+AM_ErrorCode_t AM_AV_GetVideoStatus(int dev_no,AM_AV_VideoStatus_t *status)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (dev->drv->get_video_status)
+		ret = dev->drv->get_video_status(dev,status);
+	else
+		ret = AM_AV_ERR_NOT_SUPPORTED;
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 取得当前音频状态
+ * \param dev_no 音视频设备号
+ * \param[out]status 返回视频状态
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_GetAudioStatus(int dev_no,AM_AV_AudioStatus_t *status)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (dev->drv->get_audio_status)
+		ret = dev->drv->get_audio_status(dev,status);
+	else
+		ret = AM_AV_ERR_NOT_SUPPORTED;
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 开始进入Timeshift模式
+ * \param dev_no 音视频设备号
+ * \param[in] para Timeshift参数
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_StartTimeshift(int dev_no, const AM_AV_TimeshiftPara_t *para)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	assert(para);
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	ret = av_start(dev, AV_TIMESHIFT, (void*)para);
+	if (ret == AM_SUCCESS) {
+		dev->curr_para.time_shift.para = *para;
+		snprintf(dev->curr_para.file_name, sizeof(dev->curr_para.file_name), "%s", para->file_path);
+		dev->curr_para.start = AM_FALSE;
+		dev->curr_para.speed = 0;
+		dev->curr_para.pause = AM_FALSE;
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 进入Timeshift模式后,写数据到timeshift文件
+ * \param dev_no 音视频设备号
+ * \param[in] data 注入数据的缓冲区
+ * \param size 传入要注入数据的长度
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_TimeshiftFillData(int dev_no, uint8_t *data, int size)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	assert(data && size);
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	/*if (!(dev->mode & AV_TIMESHIFT))
+	{
+		AM_DEBUG(1, "do not in the file play mode");
+		ret = AM_AV_ERR_ILLEGAL_OP;
+	}*/
+
+	if (ret == AM_SUCCESS)
+	{
+		if (dev->drv->timeshift_fill)
+			ret = dev->drv->timeshift_fill(dev, data, size);
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 停止Timeshift模式
+ * \param dev_no 音视频设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_StopTimeshift(int dev_no)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	ret = av_stop(dev, AV_TIMESHIFT);
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 开始播放Timeshift
+ * \param dev_no 音视频设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_PlayTimeshift(int dev_no)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (!(dev->mode & AV_TIMESHIFT))
+	{
+		AM_DEBUG(1, "do not in the timeshift play mode");
+		ret = AM_AV_ERR_ILLEGAL_OP;
+	}
+
+	if (ret == AM_SUCCESS)
+	{
+		if (dev->drv->timeshift_cmd)
+		{
+			ret = dev->drv->timeshift_cmd(dev, AV_PLAY_START, 0);
+			if (ret == AM_SUCCESS) {
+				dev->curr_para.start = AM_TRUE;
+			}
+		}
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 暂停Timeshift
+ * \param dev_no 音视频设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_PauseTimeshift(int dev_no)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (!(dev->mode & AV_TIMESHIFT))
+	{
+		AM_DEBUG(1, "do not in the timeshift play mode");
+		ret = AM_AV_ERR_ILLEGAL_OP;
+	}
+
+	if (ret == AM_SUCCESS)
+	{
+		if (dev->drv->timeshift_cmd)
+		{
+			ret = dev->drv->timeshift_cmd(dev, AV_PLAY_PAUSE, NULL);
+			if (ret == AM_SUCCESS) {
+				dev->curr_para.pause = AM_TRUE;
+			}
+		}
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 恢复Timeshift播放
+ * \param dev_no 音视频设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_ResumeTimeshift(int dev_no)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (!(dev->mode & AV_TIMESHIFT))
+	{
+		AM_DEBUG(1, "do not in the timeshift play mode");
+		ret = AM_AV_ERR_ILLEGAL_OP;
+	}
+
+	if (ret == AM_SUCCESS)
+	{
+		if (dev->drv->timeshift_cmd)
+		{
+			ret = dev->drv->timeshift_cmd(dev, AV_PLAY_RESUME, NULL);
+			if (ret == AM_SUCCESS) {
+				dev->curr_para.pause = AM_FALSE;
+			}
+		}
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 设定当前Timeshift播放位置
+ * \param dev_no 音视频设备号
+ * \param pos 播放位置
+ * \param start 是否开始播放
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_SeekTimeshift(int dev_no, int pos, AM_Bool_t start)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	AV_FileSeekPara_t para;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (!(dev->mode & AV_TIMESHIFT))
+	{
+		AM_DEBUG(1, "do not in the Timeshift play mode");
+		ret = AM_AV_ERR_ILLEGAL_OP;
+	}
+
+	if (ret == AM_SUCCESS)
+	{
+		if (dev->drv->timeshift_cmd)
+		{
+			para.pos   = pos;
+			para.start = start;
+			ret = dev->drv->timeshift_cmd(dev, AV_PLAY_SEEK, &para);
+		}
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 快速向前播放
+ * \param dev_no 音视频设备号
+ * \param speed 播放速度
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_FastForwardTimeshift(int dev_no, int speed)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	if (speed < 0)
+	{
+		AM_DEBUG(1, "speed must >= 0");
+		return AM_AV_ERR_INVAL_ARG;
+	}
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (!(dev->mode & AV_TIMESHIFT))
+	{
+		AM_DEBUG(1, "do not in the Timeshift play mode");
+		ret = AM_AV_ERR_ILLEGAL_OP;
+	}
+
+	if (ret == AM_SUCCESS)
+	{
+		if (dev->drv->timeshift_cmd)
+		{
+			ret = dev->drv->timeshift_cmd(dev, AV_PLAY_FF, (void*)(long)speed);
+			if (ret == AM_SUCCESS) {
+				dev->curr_para.speed = speed;
+			}
+		}
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 快速向后播放
+ * \param dev_no 音视频设备号
+ * \param speed 播放速度
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_FastBackwardTimeshift(int dev_no, int speed)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	if (speed < 0)
+	{
+		AM_DEBUG(1, "speed must >= 0");
+		return AM_AV_ERR_INVAL_ARG;
+	}
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (!(dev->mode & AV_TIMESHIFT))
+	{
+		AM_DEBUG(1, "do not in the Timeshift play mode");
+		ret = AM_AV_ERR_ILLEGAL_OP;
+	}
+
+	if (ret == AM_SUCCESS)
+	{
+		if (dev->drv->timeshift_cmd)
+		{
+			ret = dev->drv->timeshift_cmd(dev, AV_PLAY_FB, (void*)(long)-speed);
+			if (ret == AM_SUCCESS) {
+				dev->curr_para.speed = -speed;
+			}
+		}
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 切换当前Timeshift播放音频
+ * \param dev_no 音视频设备号
+ * \param apid the audio pid switched to
+ * \param afmt the audio fmt switched to
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_SwitchTimeshiftAudio(int dev_no, int apid, int afmt)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	AV_TSPlayPara_t para;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (!(dev->mode & AV_TIMESHIFT))
+	{
+		AM_DEBUG(1, "do not in the Timeshift play mode");
+		ret = AM_AV_ERR_ILLEGAL_OP;
+	}
+
+	if (ret == AM_SUCCESS)
+	{
+		if (dev->drv->timeshift_cmd)
+		{
+			para.apid   = apid;
+			para.afmt 	= afmt;
+			ret = dev->drv->timeshift_cmd(dev, AV_PLAY_SWITCH_AUDIO, &para);
+		}
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 获取当前Timeshift播放信息
+ * \param dev_no 音视频设备号
+ * \param [out] info 播放信息
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_GetTimeshiftInfo(int dev_no, AM_AV_TimeshiftInfo_t *info)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	AV_TSPlayPara_t para;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (!(dev->mode & AV_TIMESHIFT))
+	{
+		AM_DEBUG(1, "do not in the Timeshift play mode");
+		ret = AM_AV_ERR_ILLEGAL_OP;
+	}
+
+	if (ret == AM_SUCCESS)
+	{
+		if (dev->drv->get_timeshift_info)
+		{
+			ret = dev->drv->get_timeshift_info(dev, info);
+		}
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+AM_ErrorCode_t AM_AV_GetTimeshiftTFile(int dev_no, AM_TFile_t *tfile)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	AV_TSPlayPara_t para;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (ret == AM_SUCCESS)
+	{
+		if (dev->drv->timeshift_get_tfile)
+		{
+			ret = dev->drv->timeshift_get_tfile(dev, tfile);
+		}
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 设置视频通道参数
+ * \param dev_no 音视频设备号
+ * \param fs free scale参数
+ * \param di deinterlace参数
+ * \param pp PPMGR参数
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t
+AM_AV_SetVPathPara(int dev_no, AM_AV_FreeScalePara_t fs, AM_AV_DeinterlacePara_t di, AM_AV_PPMGRPara_t pp)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	UNUSED(dev_no);
+	UNUSED(di);
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	//ret = av_set_vpath(dev, fs, di, pp);
+	ret = av_set_vpath(dev, fs, AM_AV_DEINTERLACE_DISABLE, pp);
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief TS播放模式时切换音频,用于多音频切换,需先调用StartTS
+ * \param dev_no 音视频设备号
+ * \param apid 音频流PID
+ * \param afmt 音频压缩格式
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_SwitchTSAudio(int dev_no, uint16_t apid, AM_AV_AFormat_t afmt)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (dev->drv->switch_ts_audio)
+		ret = dev->drv->switch_ts_audio(dev, apid, afmt);
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+AM_ErrorCode_t AM_AV_ResetAudioDecoder(int dev_no)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if ((dev->mode & AV_PLAY_TS) && dev->drv->switch_ts_audio) 
+		ret = dev->drv->reset_audio_decoder(dev);
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+
+/**\brief used to set /sys/module/amvdec_h264/parameters/error_recovery_mode to choose display mosaic or not
+ * \param dev_no 音视频设备号
+ * \param error_recovery_mode : 0 ,skip mosaic and reset vdec,2 skip mosaic ,3 display mosaic
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_av.h)
+ */
+AM_ErrorCode_t AM_AV_SetVdecErrorRecoveryMode(int dev_no, uint8_t error_recovery_mode)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (dev->drv->set_video_para)
+	{
+		ret = dev->drv->set_video_para(dev, AV_VIDEO_PARA_ERROR_RECOVERY_MODE, (void*)(long)error_recovery_mode);
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+AM_ErrorCode_t AM_AV_SetInjectAudio(int dev_no, int aid, AM_AV_AFormat_t afmt)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if ((dev->mode & AV_INJECT) && dev->drv->set_inject_audio)
+		ret = dev->drv->set_inject_audio(dev, aid, afmt);
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+AM_ErrorCode_t AM_AV_SetInjectSubtitle(int dev_no, int sid, int stype)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if ((dev->mode & AV_INJECT) && dev->drv->set_inject_subtitle)
+		ret = dev->drv->set_inject_subtitle(dev, sid, stype);
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+AM_ErrorCode_t AM_AV_SetAudioAd(int dev_no, int enable, uint16_t apid, AM_AV_AFormat_t afmt)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (dev->drv->set_audio_ad)
+	{
+		ret = dev->drv->set_audio_ad(dev, enable, apid, afmt);
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+AM_ErrorCode_t AM_AV_SetAudioCallback(int dev_no,AM_AV_Audio_CB_t cb,void *user_data)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (dev->drv->set_audio_cb)
+	{
+		dev->drv->set_audio_cb(dev, cb, user_data);
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+	return 0;
+}
+
+AM_ErrorCode_t AM_AV_GetVideoPts(int dev_no, uint64_t *pts)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (dev->drv->get_pts)
+	{
+		ret = dev->drv->get_pts(dev, 0, pts);
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+AM_ErrorCode_t AM_AV_GetAudioPts(int dev_no, uint64_t *pts)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (dev->drv->get_pts)
+	{
+		ret = dev->drv->get_pts(dev, 1, pts);
+	}
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+AM_ErrorCode_t AM_AV_SetCryptOps(int dev_no, AM_Crypt_Ops_t *ops)
+{
+	AM_AV_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(av_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	dev->crypt_ops = ops;
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
diff --git a/test/am_ca_key_test/inject_record_t5d/am_av/am_av.h b/test/am_ca_key_test/inject_record_t5d/am_av/am_av.h
new file mode 100644
index 0000000..9d35902
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_av/am_av.h
@@ -0,0 +1,1255 @@
+/***************************************************************************
+ * Copyright (C) 2017 Amlogic, Inc. 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.
+ *
+ * Description:
+ */
+/**\file
+ * \brief AV decoder module
+ *
+ * AV decoder device can work in the following modes:
+ *	- play TS stream
+ *	- decode audio ES
+ *	- decode video ES
+ *	- inject AV data to decoder
+ *	- timeshifting play
+ *	- local file playing (not available on android)
+ *	- JPEG hardware decode (not available on android)
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-08-06: create the document
+ ***************************************************************************/
+
+#ifndef _AM_AV_H
+#define _AM_AV_H
+
+#include "am_types.h"
+#include "am_osd.h"
+#include "am_evt.h"
+#include "am_misc.h"
+#include "am_tfile.h"
+#include "am_userdata.h"
+#include "am_crypt.h"
+#include <amports/vformat.h>
+#include <amports/aformat.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+#define AM_AV_VIDEO_CONTRAST_MIN   -1024  /**< The minimum contrast value*/
+#define AM_AV_VIDEO_CONTRAST_MAX   1024   /**< The maximum contrast value*/
+#define AM_AV_VIDEO_SATURATION_MIN -1024  /**< The minimum saturation value*/
+#define AM_AV_VIDEO_SATURATION_MAX 1024   /**< The maximum saturation value*/
+#define AM_AV_VIDEO_BRIGHTNESS_MIN -1024  /**< The minimum brightness value*/
+#define AM_AV_VIDEO_BRIGHTNESS_MAX 1024   /**< The maximum brightness value*/
+
+/****************************************************************************
+ * Error code definitions
+ ****************************************************************************/
+
+/**\brief Error code of the AV decoder module*/
+enum AM_AV_ErrorCode
+{
+	AM_AV_ERROR_BASE=AM_ERROR_BASE(AM_MOD_AV),
+	AM_AV_ERR_INVALID_DEV_NO,          /**< Invalid decoder device number*/
+	AM_AV_ERR_BUSY,                    /**< The device has already been openned*/
+	AM_AV_ERR_ILLEGAL_OP,              /**< Illegal operation*/
+	AM_AV_ERR_INVAL_ARG,               /**< Invalid argument*/
+	AM_AV_ERR_NOT_ALLOCATED,           /**< The device has not been allocated*/
+	AM_AV_ERR_CANNOT_CREATE_THREAD,    /**< Cannot create a new thread*/
+	AM_AV_ERR_CANNOT_OPEN_DEV,         /**< Cannot open the device*/
+	AM_AV_ERR_CANNOT_OPEN_FILE,        /**< Cannot open the file*/
+	AM_AV_ERR_NOT_SUPPORTED,           /**< Not supported*/
+	AM_AV_ERR_NO_MEM,                  /**< Not enough memory*/
+	AM_AV_ERR_TIMEOUT,                 /**< Timeout*/
+	AM_AV_ERR_SYS,                     /**< System error*/
+	AM_AV_ERR_DECODE,                  /**< Decoder error*/
+	AM_AV_ERR_END
+};
+
+/****************************************************************************
+ * Event type definitions
+ ****************************************************************************/
+
+/**\brief Event type of the AV decoder module*/
+enum AM_AV_EventType
+{
+	AM_AV_EVT_BASE=AM_EVT_TYPE_BASE(AM_MOD_AV),
+	AM_AV_EVT_PLAYER_STATE_CHANGED,    /**< File player's state changed, the parameter is the new state(AM_AV_MPState_t)*/
+	AM_AV_EVT_PLAYER_SPEED_CHANGED,    /**< File player's playing speed changed, the parameter is the new speed(0:normal,<0:backward,>0:fast forward)*/
+	AM_AV_EVT_PLAYER_TIME_CHANGED,     /**< File player's current time changed,the parameter is the current time*/
+	AM_AV_EVT_PLAYER_UPDATE_INFO,      /**< Update the current player information*/
+	AM_AV_EVT_VIDEO_WINDOW_CHANGED,    /**< Video window change, the parameter is the new window(AM_AV_VideoWindow_t)*/
+	AM_AV_EVT_VIDEO_CONTRAST_CHANGED,  /**< Video contrast changed,the parameter is the new contrast(int 0~100)*/
+	AM_AV_EVT_VIDEO_SATURATION_CHANGED,/**< Video saturation changed, the parameter is the new saturation(int 0~100)*/
+	AM_AV_EVT_VIDEO_BRIGHTNESS_CHANGED,/**< Video brightness changed, the parameter is the new brightness(int 0~100)*/
+	AM_AV_EVT_VIDEO_ENABLED,           /**< Video layer enabled*/
+	AM_AV_EVT_VIDEO_DISABLED,          /**< Video layer disabled*/
+	AM_AV_EVT_VIDEO_ASPECT_RATIO_CHANGED, /**< Video aspect ratio changed,the parameter is the new aspect ratio(AM_AV_VideoAspectRatio_t)*/
+	AM_AV_EVT_VIDEO_DISPLAY_MODE_CHANGED, /**< Video display mode changed, the parameter is the new display mode(AM_AV_VideoDisplayMode_t)*/
+	AM_AV_EVT_AV_NO_DATA,		   /**< Audio/Video data stopped*/
+	AM_AV_EVT_AV_DATA_RESUME,	/**< After event AM_AV_EVT_AV_NO_DATA,audio/video data resumed*/
+	AM_AV_EVT_VIDEO_ES_END,     /**< Injected video ES data end*/
+	AM_AV_EVT_AUDIO_ES_END,     /**< Injected audio ES data end*/
+	AM_AV_EVT_VIDEO_SCAMBLED,   /**< Video is scrambled*/
+	AM_AV_EVT_AUDIO_SCAMBLED,   /**< Audio is scrambled*/
+	AM_AV_EVT_AUDIO_AC3_NO_LICENCE,     /**< AC3 audio has not licence*/
+	AM_AV_EVT_AUDIO_AC3_LICENCE_RESUME, /**< AC3 audio resumed*/
+	AM_AV_EVT_VIDEO_NOT_SUPPORT,        /**< Video format is not supported*/
+	AM_AV_EVT_VIDEO_AVAILABLE,  /**< Cannot get valid video information*/
+	AM_AV_EVT_AUDIO_CB, /**< Audio function will implement in cb */
+	AM_AV_EVT_VIDEO_RESOLUTION_CHANGED, /**< Video resolution changed, the parameter is the AM_AV_VideoStatus_t with new width&height valid only */
+	AM_AV_EVT_VIDEO_AFD_CHANGED, /**< Video AFD info changed, parameter is AM_USERDATA_AFD_t*/
+	AM_AV_EVT_VIDEO_CROPPING_CHANGED,    /**< Video cropping change, the parameter is the new cropping window(AM_AV_VideoWindow_t)*/
+	AM_AV_EVT_PLAYER_EOF,              /**< Update the current player information*/
+	AM_AV_EVT_END
+};
+
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+/**\cond */
+/**\brief File player's state*/
+typedef enum
+{
+	AM_AV_MP_STATE_UNKNOWN = 0,        /**< Unknown*/
+	AM_AV_MP_STATE_INITING,            /**< Initializing*/
+	AM_AV_MP_STATE_NORMALERROR,        /**< Error occured*/
+	AM_AV_MP_STATE_FATALERROR,         /**< Fatal error occured*/
+	AM_AV_MP_STATE_PARSERED,           /**< The file's header has been parsed*/
+	AM_AV_MP_STATE_STARTED,            /**< Start playing*/
+	AM_AV_MP_STATE_PLAYING,            /**< Playing*/
+	AM_AV_MP_STATE_PAUSED,             /**< Paused*/
+	AM_AV_MP_STATE_CONNECTING,         /**< Connecting to the server*/
+	AM_AV_MP_STATE_CONNECTDONE,        /**< Connected*/
+	AM_AV_MP_STATE_BUFFERING,          /**< Buffering*/
+	AM_AV_MP_STATE_BUFFERINGDONE,      /**< Buffering done*/
+	AM_AV_MP_STATE_SEARCHING,          /**< Set new playing position*/
+	AM_AV_MP_STATE_TRICKPLAY,          /**< Play in trick mode*/
+	AM_AV_MP_STATE_MESSAGE_EOD,        /**< Message begin*/
+	AM_AV_MP_STATE_MESSAGE_BOD,        /**< Message end*/
+	AM_AV_MP_STATE_TRICKTOPLAY,        /**< Trick mode to normal playing mode*/
+	AM_AV_MP_STATE_FINISHED,           /**< File finished*/
+	AM_AV_MP_STATE_STOPED              /**< Palyer stopped*/
+} AM_AV_MPState_t;
+/**\endcond */
+
+/**\brief Video window*/
+typedef struct
+{
+	int x;                               /**< X coordinate of the top left corner*/
+	int y;                               /**< Y coordinate of the top left corner*/
+	int w;                               /**< Width of the window*/
+	int h;                               /**< Height of the window*/
+} AM_AV_VideoWindow_t;
+
+/**\brief TS stream input source*/
+typedef enum
+{
+	AM_AV_TS_SRC_TS0,                    /**< TS input port 0*/
+	AM_AV_TS_SRC_TS1,                    /**< TS input port 1*/
+	AM_AV_TS_SRC_TS2,                    /**< TS input port 2*/
+	AM_AV_TS_SRC_HIU,                    /**< HIU port (file input)*/
+	AM_AV_TS_SRC_HIU1,
+	AM_AV_TS_SRC_DMX0,                   /**< Demux 0*/
+	AM_AV_TS_SRC_DMX1,                   /**< Demux 1*/
+	AM_AV_TS_SRC_DMX2                    /**< Demux 2*/
+} AM_AV_TSSource_t;
+
+#if 0
+typedef enum {
+	AFORMAT_MPEG   = 0,
+	AFORMAT_PCM_S16LE = 1,
+	AFORMAT_AAC   = 2,
+	AFORMAT_AC3   =3,
+	AFORMAT_ALAW = 4,
+	AFORMAT_MULAW = 5,
+	AFORMAT_DTS = 6,
+	AFORMAT_PCM_S16BE = 7,
+	AFORMAT_FLAC = 8,
+	AFORMAT_COOK = 9,
+	AFORMAT_PCM_U8 = 10,
+	AFORMAT_ADPCM = 11,
+	AFORMAT_AMR  = 12,
+	AFORMAT_RAAC  = 13,
+	AFORMAT_WMA  = 14,
+	AFORMAT_WMAPRO    = 15,
+	AFORMAT_PCM_BLURAY	= 16,
+	AFORMAT_ALAC  = 17,
+	AFORMAT_VORBIS    = 18,
+	AFORMAT_AAC_LATM   = 19,
+	AFORMAT_UNSUPPORT = 20,
+	AFORMAT_MAX    = 21
+} AM_AV_AFormat_t;
+#else
+/**
+ * Audio format
+ *
+ * detail definition in "linux/amlogic/amports/aformat.h"
+ */
+typedef aformat_t AM_AV_AFormat_t;
+#endif
+
+#if 0
+typedef enum
+{
+	VFORMAT_MPEG12 = 0,
+	VFORMAT_MPEG4,
+	VFORMAT_H264,
+	VFORMAT_MJPEG,
+	VFORMAT_REAL,
+	VFORMAT_JPEG,
+	VFORMAT_VC1,
+	VFORMAT_AVS,
+	VFORMAT_YUV,    // Use SW decoder
+	VFORMAT_H264MVC,
+	VFORMAT_MAX
+} AM_AV_VFormat_t;
+#else
+/**
+ * Video format
+ *
+ * detail definition in "linux/amlogic/amports/vformat.h"
+ */
+typedef vformat_t AM_AV_VFormat_t;
+#endif
+
+/**\brief AV stream package format*/
+typedef enum
+{
+	PFORMAT_ES = 0, /**< ES stream*/
+	PFORMAT_PS,     /**< PS stream*/
+	PFORMAT_TS,     /**< TS stream*/
+	PFORMAT_REAL    /**< REAL file*/
+} AM_AV_PFormat_t;
+
+/**\brief Video aspect ratio*/
+typedef enum
+{
+	AM_AV_VIDEO_ASPECT_AUTO,      /**< Automatic*/
+	AM_AV_VIDEO_ASPECT_4_3,       /**< 4:3*/
+	AM_AV_VIDEO_ASPECT_16_9       /**< 16:9*/
+} AM_AV_VideoAspectRatio_t;
+
+/**\brief Video aspect ratio match mode*/
+typedef enum
+{
+	AM_AV_VIDEO_ASPECT_MATCH_IGNORE,     /**< Ignoring orignal aspect ratio*/
+	AM_AV_VIDEO_ASPECT_MATCH_LETTER_BOX, /**< Letter box match mode*/
+	AM_AV_VIDEO_ASPECT_MATCH_PAN_SCAN,   /**< Pan scan match mode*/
+	AM_AV_VIDEO_ASPECT_MATCH_COMBINED    /**< Combined letter box/pan scan match mode*/
+} AM_AV_VideoAspectMatchMode_t;
+
+/**\brief Video display mode*/
+typedef enum
+{
+	AM_AV_VIDEO_DISPLAY_NORMAL,     /**< Normal display mode*/
+	AM_AV_VIDEO_DISPLAY_FULL_SCREEN /**< Full screaan display mode*/
+} AM_AV_VideoDisplayMode_t;
+
+/**\cond */
+/**\brief Freescale parameter*/
+typedef enum
+{
+	AM_AV_FREE_SCALE_DISABLE,     /**< Disable freescale*/
+	AM_AV_FREE_SCALE_ENABLE       /**< Enable freescale*/
+} AM_AV_FreeScalePara_t;
+
+/**\brief Deinterlace parameter*/
+typedef enum
+{
+	AM_AV_DEINTERLACE_DISABLE,    /**< Disable deinterlace*/
+	AM_AV_DEINTERLACE_ENABLE      /**< Enable deinterlace*/
+} AM_AV_DeinterlacePara_t;
+
+/**\brief PPMGR parameter*/
+typedef enum
+{
+	AM_AV_PPMGR_DISABLE,          /**< Disable PPMGR*/
+	AM_AV_PPMGR_ENABLE,           /**< Enable PPMGR*/
+	/*以下为3D模式设置*/
+	AM_AV_PPMGR_MODE3D_DISABLE,
+	AM_AV_PPMGR_MODE3D_AUTO,
+	AM_AV_PPMGR_MODE3D_2D_TO_3D,
+	AM_AV_PPMGR_MODE3D_LR,
+	AM_AV_PPMGR_MODE3D_BT,
+	AM_AV_PPMGR_MODE3D_OFF_LR_SWITCH,
+	AM_AV_PPMGR_MODE3D_ON_LR_SWITCH,
+	AM_AV_PPMGR_MODE3D_FIELD_DEPTH,
+	AM_AV_PPMGR_MODE3D_OFF_3D_TO_2D,
+	AM_AV_PPMGR_MODE3D_L_3D_TO_2D,
+	AM_AV_PPMGR_MODE3D_R_3D_TO_2D,
+	AM_AV_PPMGR_MODE3D_OFF_LR_SWITCH_BT,
+	AM_AV_PPMGR_MODE3D_ON_LR_SWITCH_BT,
+	AM_AV_PPMGR_MODE3D_OFF_3D_TO_2D_BT,
+	AM_AV_PPMGR_MODE3D_L_3D_TO_2D_BT,
+	AM_AV_PPMGR_MODE3D_R_3D_TO_2D_BT,
+	AM_AV_PPMGR_MODE3D_MAX,
+} AM_AV_PPMGRPara_t;
+/**\endcond */
+
+/**\brief AV decoder device open parameters*/
+typedef struct
+{
+	int      vout_dev_no;         /**< Video output device number*/
+	int      afd_enable;          /**< enable AFD*/
+} AM_AV_OpenPara_t;
+
+/**\brief Media file information*/
+typedef struct
+{
+	uint64_t size;                /**< File size in bytes*/
+	int      duration;            /**< Total duration in seconds*/
+} AM_AV_FileInfo_t;
+
+/**\brief File playing status*/
+typedef struct
+{
+	int      duration;            /**< Total duration in seconds.*/
+	int      position;            /**< Current time*/
+} AM_AV_PlayStatus_t;
+
+/**\brief JPEG file properties*/
+typedef struct
+{
+	int      width;               /**< JPEG image width*/
+	int      height;              /**< JPEG image height*/
+	int      comp_num;            /**< Color number*/
+} AM_AV_JPEGInfo_t;
+
+/**\brief JPEG rotation parameter*/
+typedef enum
+{
+	AM_AV_JPEG_CLKWISE_0    = 0,  /**< Normal*/
+	AM_AV_JPEG_CLKWISE_90   = 1,  /**< Rotate 90 degrees clockwise*/
+	AM_AV_JPEG_CLKWISE_180  = 2,  /**< Rotate 180 degrees clockwise*/
+	AM_AV_JPEG_CLKWISE_270  = 3   /**< Rotate 270 degrees clockwise*/
+} AM_AV_JPEGAngle_t;
+
+/**\brief JPEG decoder options*/
+typedef enum
+{
+	AM_AV_JPEG_OPT_THUMBNAIL_ONLY     = 1, /**< Decode in thumbnail only mode*/
+	AM_AV_JPEG_OPT_THUMBNAIL_PREFERED = 2, /**< Decode in thumbnail prefered mode*/
+	AM_AV_JPEG_OPT_FULLRANGE          = 4  /**< Normal*/
+} AM_AV_JPEGOption_t;
+
+/**\brief Image surface parameters (used in JPEG decoder)*/
+typedef struct
+{
+	int    width;                 /**< Image width, <=0 means use orignal size*/
+	int    height;                /**< Image height, <=0 means use orignal size*/
+	AM_AV_JPEGAngle_t  angle;     /**< JPEG image ratation parameter*/
+	AM_AV_JPEGOption_t option;    /**< JPEG decoder options*/
+} AM_AV_SurfacePara_t;
+
+/**\brief Decoder injection data type*/
+typedef enum
+{
+	AM_AV_INJECT_AUDIO,           /**< Audio data*/
+	AM_AV_INJECT_VIDEO,           /**< Video data*/
+	AM_AV_INJECT_MULTIPLEX        /**< Multiplexed data*/
+} AM_AV_InjectType_t;
+
+typedef enum
+{
+	AM_AV_NO_DRM,
+	AM_AV_DRM_WITH_SECURE_INPUT_BUFFER, /**< Use for HLS, input buffer is clear and protected*/
+	AM_AV_DRM_WITH_NORMAL_INPUT_BUFFER  /**< Use for IPTV, input buffer is normal and scramble*/
+} AM_AV_DrmMode_t;
+
+/**\brief Decoder injection parameters*/
+typedef struct
+{
+	AM_AV_AFormat_t  aud_fmt;     /**< Audio format*/
+	AM_AV_VFormat_t  vid_fmt;     /**< Video format*/
+	AM_AV_PFormat_t  pkg_fmt;     /**< Package format*/
+	int              sub_type;    /**< Subtitle type.*/
+	int              aud_id;      /**< Audio ID, -1 means no audio data*/
+	int              vid_id;      /**< Video ID, -1 means no video data*/
+	int              sub_id;      /**< Subtitle ID, -i means no subtitle data*/
+	int              channel;     /**< Audio channel number (used in playing audio PCM data)*/
+	int              sample_rate; /**< Audio sample rate (used in playing audio PCM data)*/
+	int              data_width;  /**< Audio data width (used in playing audio PCM data)*/
+} AM_AV_InjectPara_t;
+
+/**\brief Video decoder status*/
+typedef struct
+{
+	AM_AV_VFormat_t  vid_fmt;     /**< Video format*/
+	int              src_w;       /**< Video source width*/
+	int              src_h;       /**< Video source height*/
+	int              fps;         /**< Frames per second*/
+	char             interlaced;  /**< Is interlaced ? */
+	int              frames;      /**< Decoded frames number*/
+	int              vb_size;     /**< Video buffer size*/
+	int              vb_data;     /**< Data size in the video buffer*/
+	int              vb_free;     /**< Free size in the video buffer*/
+	AM_AV_VideoAspectRatio_t vid_ratio; /**< Video source aspect ratio*/
+}AM_AV_VideoStatus_t;
+
+/**\brief Audio decoder status*/
+typedef struct
+{
+	AM_AV_AFormat_t  aud_fmt;     		/**< Audio format*/
+	int              sample_rate; 		/**< Sample rate*/
+	int              resolution;  		/**< Data width (8/16bits)*/
+	int              channels;    		/**< Channel number*/
+	unsigned int     frames;      		/**< Decoded frames number*/
+	int              ab_size;     		/**< Audio buffer size*/
+	int              ab_data;     		/**< Data size in the audio buffer*/
+	int              ab_free;     		/**< Free size in the audio buffer*/
+	AM_AV_AFormat_t  aud_fmt_orig;     	/**< original audio format*/
+	int              sample_rate_orig; 	/**< original sample rate*/
+	int              resolution_orig;  	/**< original resolution*/
+	int              channels_orig;    	/**< original channel number*/
+	int              lfepresent;       	/**< low frequency effects present*/
+	int              lfepresent_orig;  	/**< original low frequency effects present*/
+
+}AM_AV_AudioStatus_t;
+
+/**\brief Timeshifting play mode*/
+typedef enum
+{
+	AM_AV_TIMESHIFT_MODE_TIMESHIFTING, /**< Normal timeshifting mode*/
+	AM_AV_TIMESHIFT_MODE_PLAYBACK      /**< PVR playback mode*/
+}AM_AV_TimeshiftMode_t;
+
+/**\brief Timeshifting media information*/
+typedef struct
+{
+	int duration;              /**< Duration in seconds*/
+	char program_name[16];     /**< Program name*/
+	
+	int vid_pid; /**< Video PID*/
+	int vid_fmt; /**< Video format*/
+
+	int aud_cnt; /**< Audio number*/
+	struct
+	{
+		int pid; /**< Audio PID*/
+		int fmt; /**< Audio format*/
+		char lang[4]; /**< Lanuguage descripton*/
+	}audios[8]; /**< Audio information array*/
+
+	int sub_cnt; /**< Subtitle number*/
+	struct
+	{
+		int pid;  /**< Subtitle PID*/
+		int type; /**< Subtitle type*/
+		int composition_page; /**< DVB subtitle's composition page*/
+		int ancillary_page;   /**< DVB subtitle's ancillary page*/
+		int magzine_no; /**< Teletext subtitle's magzine number*/
+		int page_no;  /**< Teletext subtitle's page number*/
+		char lang[4]; /**< Language description*/
+	}subtitles[8]; /**< Subtitle information array*/
+
+	int ttx_cnt; /**< Teletext number*/
+	struct
+	{
+		int pid; /**< Teletext PID*/
+		int magzine_no; /**< Teletext magzine number*/
+		int page_no;    /**< Teletext page number*/
+		char lang[4];   /**< Teletext language description*/
+	}teletexts[8]; /**< Teletext information array*/
+}AM_AV_TimeshiftMediaInfo_t;
+
+/**\brief Timeshift playing parameters*/
+typedef struct
+{
+	int              dmx_id;      /**< Demux device index used*/
+	char             file_path[256];     /**< File path*/
+	
+	AM_AV_TimeshiftMode_t mode;   /**< Playing mode*/
+	AM_AV_TimeshiftMediaInfo_t media_info; /**< Media information*/
+
+	AM_TFile_t tfile;
+	int offset_ms;
+	AM_Bool_t start_paused;
+#ifdef SUPPORT_CAS
+	int  secure_enable;			/*Use for cas PVR/TimeShift playback*/
+	uint8_t *secure_buffer;	/*Use for sotre cas decrypt pvr data**/
+	char cas_file_path[256];/*Store Cas info file*/
+	AM_CAS_decrypt dec_cb;
+	uint32_t cb_param;
+#endif
+} AM_AV_TimeshiftPara_t;
+
+/**\brief Timeshift lpaying information*/
+typedef struct
+{
+	int                   current_time; /**< Current time in seconds*/
+	int                   full_time;    /**< Total length in seconds*/
+	int                   status;       /**< Status*/
+}AM_AV_TimeshiftInfo_t;
+
+/**\brief Player information*/
+typedef struct player_info
+{
+	char *name;
+	int last_sta;
+	int status;		   /*stop,pause	*/
+	int full_time;	   /*Seconds	*/
+	int current_time;  /*Seconds	*/
+	int current_ms;	/*ms*/
+	int last_time;		
+	int error_no;  
+	int start_time;
+	int pts_video;
+	int pts_pcrscr;
+	int current_pts;
+	long curtime_old_time;    
+	unsigned int video_error_cnt;
+	unsigned int audio_error_cnt;
+	float audio_bufferlevel;
+	float video_bufferlevel;
+}player_info_t;
+
+/****************************************************************************
+ * Function prototypes  
+ ***************************************************************************/
+
+/**\brief Open an AV decoder device
+ * \param dev_no AV decoder device number
+ * \param[in] para Device open parameters
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_Open(int dev_no, const AM_AV_OpenPara_t *para);
+
+/**\brief Close an AV decoder device
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_Close(int dev_no);
+
+/**\brief Set the decoder's TS input source
+ * \param dev_no AV decoder device number
+ * \param src TS input source
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetTSSource(int dev_no, AM_AV_TSSource_t src);
+
+/**\brief Start TS stream playing with PCR parameter
+ * \param dev_no AV decoder device number
+ * \param vpid Video PID
+ * \param apid Audio PID
+ * \param pcrpid PCR PID
+ * \param vfmt Video format
+ * \param afmt Audio format
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StartTSWithPCR(int dev_no, uint16_t vpid, uint16_t apid, uint16_t pcrpid, AM_AV_VFormat_t vfmt, AM_AV_AFormat_t afmt);
+
+/**\brief Start TS stream playing
+ * \param dev_no AV decoder device number
+ * \param vpid Video PID
+ * \param apid Audio PID
+ * \param vfmt Video format
+ * \param afmt Audio format
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StartTS(int dev_no, uint16_t vpid, uint16_t apid, AM_AV_VFormat_t vfmt, AM_AV_AFormat_t afmt);
+
+
+/**\brief Stop TS stream playing
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StopTS(int dev_no);
+
+/**\brief Start a media file playing
+ * \param dev_no AV decoder device number
+ * \param[in] fname Filename
+ * \param loop If play in loop mode.
+ * \param pos Start position in seconds
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StartFile(int dev_no, const char *fname, AM_Bool_t loop, int pos);
+
+/**\brief Switch to file play mode but do not start
+ * \param dev_no AV decoder device number
+ * \param[in] fname Filename
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_AddFile(int dev_no, const char *fname);
+
+/**\brief Start play the file. Invoke after AM_AV_AddFile
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StartCurrFile(int dev_no);
+
+/**\brief Start file playing
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StopFile(int dev_no);
+
+/**\brief Pause the file playing
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_PauseFile(int dev_no);
+
+/**\brief Resume the file playing
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_ResumeFile(int dev_no);
+
+/**\brief Set the current file playing position
+ * \param dev_no AV decoder device number
+ * \param pos Playing position in seconds
+ * \param start Start directly or pause on the position
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SeekFile(int dev_no, int pos, AM_Bool_t start);
+
+/**\brief Fast forward the file
+ * \param dev_no AV decoder device number
+ * \param speed Playing speed (0 means normal)
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_FastForwardFile(int dev_no, int speed);
+
+/**\brief Fast backward the file
+ * \param dev_no AV decoder device number
+ * \param speed Playing speed
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_FastBackwardFile(int dev_no, int speed);
+
+/**\brief Get the current playing file's information
+ * \param dev_no AV decoder device number
+ * \param[out] info Return the file's information
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetCurrFileInfo(int dev_no, AM_AV_FileInfo_t *info);
+
+/**\brief Get the current player status
+ * \param dev_no AV decoder device number
+ * \param[out] status Return the current player status
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetPlayStatus(int dev_no, AM_AV_PlayStatus_t *status);
+
+/**\brief Get the JPEG image file's information
+ * \param dev_no AV decoder device number
+ * \param[in] fname JPEG file name
+ * \param[out] info Return the image's information
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetJPEGInfo(int dev_no, const char *fname, AM_AV_JPEGInfo_t *info);
+
+/**\brief Get the JPEG image data's information
+ * \param dev_no AV decoder device number
+ * \param[in] data JPEG image data buffer
+ * \param len JPEG data length in bytes
+ * \param[out] info Return the image's information
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetJPEGDataInfo(int dev_no, const uint8_t *data, int len, AM_AV_JPEGInfo_t *info);
+
+/**\brief Decode the JPEG image file
+ * \param dev_no AV decoder device number
+ * \param[in] fname JPEG filename
+ * \param[in] para JPEG output parameters
+ * \param[out] surf Return the JPEG image
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_DecodeJPEG(int dev_no, const char *fname, const AM_AV_SurfacePara_t *para, AM_OSD_Surface_t **surf);
+
+/**\brief Decode the JPEG data
+ * \param dev_no AV decoder device number
+ * \param[in] data JPEG data buffer
+ * \param len JPEG data length in bytes
+ * \param[in] para JPEG output parameters
+ * \param[out] surf Return the JPEG image
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_DacodeJPEGData(int dev_no, const uint8_t *data, int len, const AM_AV_SurfacePara_t *para, AM_OSD_Surface_t **surf);
+
+/**\brief Decode video ES data from a file
+ * \param dev_no AV decoder device number
+ * \param format Video format
+ * \param[in] fname ES filename
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StartVideoES(int dev_no, AM_AV_VFormat_t format, const char *fname);
+
+/**\brief Decode video ES data from a buffer
+ * \param dev_no AV decoder device number
+ * \param format Video format
+ * \param[in] data Video ES buffer
+ * \param len Video data length in bytes
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StartVideoESData(int dev_no, AM_AV_VFormat_t format, const uint8_t *data, int len);
+
+/**\brief Stop video ES data decoding
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StopVideoES(int dev_no);
+
+/**\brief Start audio ES data decoding from a file
+ * \param dev_no AV decoder device number
+ * \param format Audio format
+ * \param[in] fname Audio ES filename
+ * \param times Playing times, <=0 means loop forever
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StartAudioES(int dev_no, AM_AV_AFormat_t format, const char *fname, int times);
+
+/**\brief Start audio ES data decoding from a buffer
+ * \param dev_no AV decoder device number
+ * \param format Audio format
+ * \param[in] data Audio ES buffer
+ * \param len Audio data length in bytes
+ * \param times Playing times, <=0 means loop forever
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StartAudioESData(int dev_no, AM_AV_AFormat_t format, const uint8_t *data, int len, int times);
+
+/**\brief Stop audio ES decoding
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StopAudioES(int dev_no);
+
+/**\brief Enable/diable decoder's DRM mode
+ * \param dev_no AV decoder device number
+ * \param[in] enable enable or disable DRM mode
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetDRMMode(int dev_no, AM_AV_DrmMode_t drm_mode);
+
+/**\brief Start AV data injection playing mode
+ * \param dev_no AV decoder device number
+ * \param[in] para Injection parameters
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StartInject(int dev_no, const AM_AV_InjectPara_t *para);
+
+/**\brief In injection mode, inject AV data to decoder
+ * \param dev_no AV decoder device number
+ * \param type Input data type
+ * \param[in] data AV data buffer
+ * \param[in,out] size Input the data length, and return the injected data length
+ * \param timeout Timeout in milliseconds
+ * The function will wait until the decoder's input buffer has enough space to receive the AV data.
+ * >0 the function will return immediately to this time.
+ * <0 means waiting forever.
+ * =0 means return immediately.
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_InjectData(int dev_no, AM_AV_InjectType_t type, uint8_t *data, int *size, int timeout);
+
+/**\brief Pause the decoder in injection mode
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_PauseInject(int dev_no);
+
+/**\brief Resume the decoder in injection mode
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_ResumeInject(int dev_no);
+
+/**\brief In injection mode, change the video
+ * \param dev_no AV decoder device number
+ * \param vid Video PID
+ * \param vfmt Video format
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetInjectVideo(int dev_no, int vid, AM_AV_VFormat_t vfmt);
+
+/**\brief In injection mode, change the audio
+ * \param dev_no AV decoder device number
+ * \param aid Audio PID
+ * \param afmt Audio format
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetInjectAudio(int dev_no, int aid, AM_AV_AFormat_t afmt);
+
+/**\brief In injection mode, change the subtitle
+ * \param dev_no AV decoder device number
+ * \param sid Subtitle's PID
+ * \param stype The subtitle's type.
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetInjectSubtitle(int dev_no, int sid, int stype);
+
+/**\brief Stop the injection mode
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StopInject(int dev_no);
+
+/**\brief Set the video window
+ * \param dev_no AV decoder device number
+ * \param x X coordinate of the top left corner
+ * \param y Y coordinate of the top left corner
+ * \param w Window width
+ * \param h Window height
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetVideoWindow(int dev_no, int x, int y, int w, int h);
+
+/**\brief Set the video cropping
+ * \param dev_no AV decoder device number
+ * \param Voffset0 vertical crop of the top left corner
+ * \param Hoffset0 horizontal crop of the top left corner
+ * \param Voffset1 vertical crop of the bottom right corner
+ * \param Hoffset1 horizontal crop of the bottom right corner
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetVideoCropping(int dev_no, int Voffset0, int Hoffset0, int Voffset1, int Hoffset1);
+
+/**\brief Get the video window
+ * \param dev_no AV decoder device number
+ * \param[out] x Return x coordinate of the top left corner
+ * \param[out] y Return y coordinate of the top left corner
+ * \param[out] w Return the window width
+ * \param[out] h Return the window height
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetVideoWindow(int dev_no, int *x, int *y, int *w, int *h);
+
+/**\brief Set the video contrast (0~100)
+ * \param dev_no AV decoder device number
+ * \param val New contrast value
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetVideoContrast(int dev_no, int val);
+
+/**\brief Get the current video contrast value
+ * \param dev_no AV decoder device number
+ * \param[out] val Return the current video contrast value
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetVideoContrast(int dev_no, int *val);
+
+/**\brief Set the video saturation value (0~100)
+ * \param dev_no AV decoder device number
+ * \param val The new video saturation value
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetVideoSaturation(int dev_no, int val);
+
+/**\brief Get the current video saturation value
+ * \param dev_no AV decoder device number
+ * \param[out] val Return the saturation value
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetVideoSaturation(int dev_no, int *val);
+
+/**\brief Set the video brightness value (0~100)
+ * \param dev_no AV decoder device number
+ * \param val New video brightness value
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetVideoBrightness(int dev_no, int val);
+
+/**\brief Get the current video brightness value
+ * \param dev_no AV decoder device number
+ * \param[out] val Return the current video brightness value
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetVideoBrightness(int dev_no, int *val);
+
+/**\brief Enable the video layer
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_EnableVideo(int dev_no);
+
+/**\brief Disable the video layer
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_DisableVideo(int dev_no);
+
+/**\brief Set the video aspect ratio
+ * \param dev_no AV decoder device number
+ * \param ratio New aspect ratio value
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetVideoAspectRatio(int dev_no, AM_AV_VideoAspectRatio_t ratio);
+
+/**\brief Get the video aspect ratio
+ * \param dev_no AV decoder device number
+ * \param[out] ratio Return the video aspect ratio
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetVideoAspectRatio(int dev_no, AM_AV_VideoAspectRatio_t *ratio);
+
+/**\brief Set the video aspect ratio match mode
+ * \param dev_no AV decoder device number
+ * \param mode New match mode
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetVideoAspectMatchMode(int dev_no, AM_AV_VideoAspectMatchMode_t mode);
+
+/**\brief Get the video aspect ratio match mode
+ * \param dev_no AV decoder device number
+ * \param[out] mode Return the current match mode
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetVideoAspectMatchMode(int dev_no, AM_AV_VideoAspectMatchMode_t *mode);
+
+/**\brief Set the video layer disabled automatically when video stopped
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_EnableVideoBlackout(int dev_no);
+
+/**\brief Set the video layer do not disabled when video stopped
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_DisableVideoBlackout(int dev_no);
+
+/**\brief Set the video display mode
+ * \param dev_no AV decoder device number
+ * \param mode New display mode
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetVideoDisplayMode(int dev_no, AM_AV_VideoDisplayMode_t mode);
+
+/**\brief Get the current video display mode
+ * \param dev_no AV decoder device number
+ * \param[out] mode Return the current display mode
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetVideoDisplayMode(int dev_no, AM_AV_VideoDisplayMode_t *mode);
+
+/**\brief Clear the video layer
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_ClearVideoBuffer(int dev_no);
+
+/**\brief Get the video frame data (after video stopped)
+ *
+ * This function is not available on android.
+ * \param dev_no AV decoder device number
+ * \param[in] para Surface create parameters
+ * \param[out] s Return the video frame
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetVideoFrame(int dev_no, const AM_AV_SurfacePara_t *para, AM_OSD_Surface_t **s);
+
+/**\brief Get the current video decoder's status
+ * \param dev_no AV decoder device number
+ * \param[out] status Return the current video decoder's status
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetVideoStatus(int dev_no, AM_AV_VideoStatus_t *status);
+
+/**\brief Get the current audio decoder's status
+ * \param dev_no AV decoder device number
+ * \param[out] status Return the current audio decoder's status
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetAudioStatus(int dev_no, AM_AV_AudioStatus_t *status);
+
+
+/**\brief Start the timeshifting mode
+ * \param dev_no AV decoder device number
+ * \param[in] para Timeshifting parameters
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StartTimeshift(int dev_no, const AM_AV_TimeshiftPara_t *para);
+
+/**\brief In timeshifting mode, write AV data to decoder
+ * \param dev_no AV decoder device number
+ * \param[in] data Injected data buffer
+ * \param size Data length in the buffer
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_TimeshiftFillData(int dev_no, uint8_t *data, int size);
+
+/**\brief Stop timeshifting mode
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StopTimeshift(int dev_no);
+
+/**\brief Start playing in timeshifting mode
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_PlayTimeshift(int dev_no);
+
+/**\brief Pause playing in timeshifting mode
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_PauseTimeshift(int dev_no);
+
+/**\brief Resume playing in timeshifting mode
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_ResumeTimeshift(int dev_no);
+
+/**\brief Set the current playing position in timeshifting mode
+ * \param dev_no AV decoder device number
+ * \param pos New position in seconds
+ * \param start Start playing directly after seek
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SeekTimeshift(int dev_no, int pos, AM_Bool_t start);
+
+/**\brief Fast forward playing in timeshifting mode
+ * \param dev_no AV decoder device number
+ * \param speed Playing speed
+ * 0 means normal speed.
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_FastForwardTimeshift(int dev_no, int speed);
+
+/**\brief Fast backward playing in timeshifting mode
+ * \param dev_no AV decoder device number
+ * \param speed Playing speed
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_FastBackwardTimeshift(int dev_no, int speed);
+
+/**\brief Switch audio in timeshifting mode
+ * \param dev_no AV decoder device number
+ * \param apid The new audio PID
+ * \param afmt The new audio format
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SwitchTimeshiftAudio(int dev_no, int apid, int afmt);
+
+/**\brief Get the current timeshifting play information
+ * \param dev_no AV decoder device number
+ * \param [out] info Return the timeshifting information
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetTimeshiftInfo(int dev_no, AM_AV_TimeshiftInfo_t *info);
+
+/**\brief Get the current timeshifting play information
+ * \param dev_no AV decoder device number
+ * \param [out] tfile the tfile used for timeshift
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetTimeshiftTFile(int dev_no, AM_TFile_t *tfile);
+
+/**\cond */
+/**\brief Set video path parameters
+ * \param dev_no AV decoder device number
+ * \param fs free scale parameter
+ * \param di deinterlace parameter
+ * \param pp PPMGR parameter
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetVPathPara(int dev_no, AM_AV_FreeScalePara_t fs, AM_AV_DeinterlacePara_t di, AM_AV_PPMGRPara_t pp);
+/**\endcond */
+
+/**\brief Switch audio in TS playing mode
+ * \param dev_no AV decoder device number
+ * \param apid New audio PID
+ * \param afmt New audio format
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SwitchTSAudio(int dev_no, uint16_t apid, AM_AV_AFormat_t afmt);
+
+/**
+ * Reset the audio decoder
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_ResetAudioDecoder(int dev_no);
+
+
+/**\brief Used to set /sys/module/amvdec_h264/parameters/error_recovery_mode to choose display mosaic or not
+ * \param dev_no AV decoder device number
+ * \param error_recovery_mode : 0 ,skip mosaic and reset vdec,2 skip mosaic ,3 display mosaic
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetVdecErrorRecoveryMode(int dev_no, uint8_t error_recovery_mode);
+
+/**
+ * Set audio description output in TS playing mode
+ * \param dev_no AV decoder device number
+ * \param enable 1 to enable AD output, 0 to disable AD output
+ * \param apid AD audio PID
+ * \param afmt AD audio format
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetAudioAd(int dev_no, int enable, uint16_t apid, AM_AV_AFormat_t afmt);
+
+typedef struct _AUDIO_PARMS_
+{
+	int cmd;
+	int param1;
+	int param2;
+}AudioParms;
+
+#if 0
+typedef struct _AUDIO_STATUS_
+{
+	int sample_rate_orig;
+	int channels_orig;
+	int lfepresent_orig;
+	int channels;
+	int sample_rate;
+}AudioStatus;
+#endif
+
+#define ADEC_START_DECODE 		1
+#define ADEC_PAUSE_DECODE 		2
+#define ADEC_RESUME_DECODE 		3
+#define ADEC_STOP_DECODE  		4
+#define ADEC_SET_DECODE_AD 		5
+#define ADEC_SET_VOLUME 		6
+#define ADEC_SET_MUTE			7
+#define ADEC_SET_OUTPUT_MODE 	8
+#define ADEC_SET_PRE_GAIN		9
+#define ADEC_SET_PRE_MUTE 		10
+#define ADEC_GET_STATUS			11
+
+typedef void (*AM_AV_Audio_CB_t)(int event_type, AudioParms* parm, void *user_data);
+
+extern AM_ErrorCode_t AM_AV_SetAudioCallback(int dev_no,AM_AV_Audio_CB_t cb,void *user_data);
+
+/**
+ * brief Get current video pts
+ * \param dev_no AV decoder device number
+ * \param[out] Return the 33-bit pts value
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetVideoPts(int dev_no, uint64_t *pts);
+
+/**
+ * brief Get current audio pts
+ * \param dev_no AV decoder device number
+ * \param[out] Return the 33-bit pts value
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetAudioPts(int dev_no, uint64_t *pts);
+
+/**
+ * brief Set Crypt operators
+ * \param dev_no AV decoder device number
+ * \param ops Crypt ops
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetCryptOps(int dev_no, AM_Crypt_Ops_t *ops);
+
+/**
+ * brief Set Crypt operators
+ * \param dev_no AV decoder device number
+ * \param value Fendend Status
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_setFEStatus(int dev_no,int value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/am_av/am_av_internal.h b/test/am_ca_key_test/inject_record_t5d/am_av/am_av_internal.h
new file mode 100644
index 0000000..527ef36
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_av/am_av_internal.h
@@ -0,0 +1,311 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief 音视频解码模块内部头文件
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-08-06: create the document
+ ***************************************************************************/
+
+#ifndef _AM_AV_INTERNAL_H
+#define _AM_AV_INTERNAL_H
+
+#include <am_av.h>
+#include <limits.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+typedef struct AM_AV_Driver    AM_AV_Driver_t;
+typedef struct AM_AV_Device    AM_AV_Device_t;
+typedef struct AV_TSPlayer     AV_TSPlayer_t;
+typedef struct AV_FilePlayer   AV_FilePlayer_t;
+typedef struct AV_DataPlayer   AV_DataPlayer_t;
+typedef struct AV_InjectPlayer AV_InjectPlayer_t;
+typedef struct AV_TimeshiftPlayer AV_TimeshiftPlayer_t;
+
+typedef struct {
+	pthread_t av_mon_thread;
+	AM_Bool_t av_thread_running;
+} AV_Monitor_t;
+
+/**\brief TS播放参数*/
+typedef struct
+{
+	uint16_t        vpid;            /**< 视频流PID*/
+	uint16_t        apid;            /**< 音频流PID*/
+	uint16_t        pcrpid;          /**< PCR PID*/
+	AM_AV_VFormat_t vfmt;            /**< 视频流格式*/
+	AM_AV_AFormat_t afmt;            /**< 音频流格式*/
+	uint16_t        sub_apid;        /**< sub音频流PID*/
+	AM_AV_AFormat_t sub_afmt;        /**< sub音频流格式*/
+	AM_AV_DrmMode_t drm_mode;
+} AV_TSPlayPara_t;
+
+/**\brief TS流播放器*/
+struct AV_TSPlayer
+{
+	void            *drv_data;       /**< 解码驱动相关数据*/
+	AM_AV_TSSource_t src;            /**< TS源*/
+	AV_Monitor_t     mon;
+	int             av_start_time;
+	AV_TSPlayPara_t play_para;	/**< 播放参数*/
+};
+
+/**\brief 文件播放器*/
+struct AV_FilePlayer
+{
+	void            *drv_data;       /**< 解码驱动相关数据*/
+	char             name[PATH_MAX]; /**< 文件名*/
+	int              speed;          /**< 播放速度*/
+};
+
+/**\brief 数据播放参数*/
+typedef struct
+{
+	const uint8_t  *data;            /**< 数据缓冲区指针*/
+	int             len;             /**< 数据缓冲区长度*/
+	int             times;           /**< 播放次数*/
+	int             fd;              /**< 数据对应的文件描述符*/
+	AM_Bool_t       need_free;       /**< 缓冲区播放完成后需要释放*/
+	void           *para;            /**< 播放器相关参数指针*/
+} AV_DataPlayPara_t;
+
+/**\brief 数据播放器(ES, JPEG)*/
+struct AV_DataPlayer
+{
+	void            *drv_data;       /**< 解码驱动相关数据*/
+	AV_DataPlayPara_t para;          /**< 播放参数*/
+};
+
+typedef struct {
+	AM_AV_InjectPara_t para;
+	int                sub_aud_pid;
+	AM_AV_AFormat_t    sub_aud_fmt;
+	AM_AV_DrmMode_t    drm_mode;
+}AV_InjectPlayPara_t;
+
+/**\brief 数据注入播放器参数*/
+struct AV_InjectPlayer
+{
+	void            *drv_data;       /**< 解码驱动相关数据*/
+	AV_InjectPlayPara_t para;
+};
+
+typedef struct {
+	AM_AV_TimeshiftPara_t para;
+	int                sub_aud_pid;
+	AM_AV_AFormat_t    sub_aud_fmt;
+}AV_TimeShiftPlayPara_t;
+
+/**\brief Timeshift播放器参数*/
+struct AV_TimeshiftPlayer
+{
+	void            *drv_data;       /**< 解码驱动相关数据*/
+	AV_Monitor_t    mon;
+	AV_TimeShiftPlayPara_t para;
+};
+
+/**\brief JPEG解码参数*/
+typedef struct
+{
+	AM_OSD_Surface_t *surface;       /**< 返回JPEG图像*/
+	AM_AV_SurfacePara_t para;        /**< 图片参数*/
+} AV_JPEGDecodePara_t;
+
+/**\brief 播放模式*/
+typedef enum
+{
+	AV_PLAY_STOP     = 0,            /**< 播放停止*/
+	AV_PLAY_VIDEO_ES = 1,            /**< 播放视频ES流*/
+	AV_PLAY_AUDIO_ES = 2,            /**< 播放音频ES流*/
+	AV_PLAY_TS       = 4,            /**< TS流*/
+	AV_PLAY_FILE     = 8,            /**< 播放文件*/
+	AV_GET_JPEG_INFO = 16,           /**< 读取JPEG图片信息*/
+	AV_DECODE_JPEG   = 32,           /**< 解码JPEG图片*/
+	AV_INJECT        = 64,           /**< 数据注入*/
+	AV_TIMESHIFT	 = 128			 /**< Timeshift*/
+} AV_PlayMode_t;
+
+#define AV_MODE_ALL  (AV_PLAY_VIDEO_ES|AV_PLAY_AUDIO_ES|AV_PLAY_TS|AV_PLAY_FILE|AV_GET_JPEG_INFO|AV_DECODE_JPEG|AV_INJECT|AV_TIMESHIFT)
+
+/**\brief 播放命令*/
+typedef enum
+{
+	AV_PLAY_START,                   /**< 开始播放*/
+	AV_PLAY_PAUSE,                   /**< 暂停播放*/
+	AV_PLAY_RESUME,                  /**< 恢复播放*/
+	AV_PLAY_FF,                      /**< 快速前进*/
+	AV_PLAY_FB,                      /**< 快速后退*/
+	AV_PLAY_SEEK,                    /**< 设定播放位置*/
+	AV_PLAY_RESET_VPATH,             /**< 重新设定Video path*/
+	AV_PLAY_SWITCH_AUDIO			 /**< 切换音频*/
+} AV_PlayCmd_t;
+
+/**\brief 文件播放参数*/
+typedef struct
+{
+	const char     *name;            /**< 文件名*/
+	AM_Bool_t       loop;            /**< 是否循环播放*/
+	AM_Bool_t       start;           /**< 是否开始播放*/
+	int             pos;             /**< 开始播放的位置*/
+} AV_FilePlayPara_t;
+
+/**\brief 文件播放位置设定参数*/
+typedef struct
+{
+	int             pos;             /**< 播放位置*/
+	AM_Bool_t       start;           /**< 是否开始播放*/
+} AV_FileSeekPara_t;
+
+/**\brief 视频参数设置类型*/
+typedef enum
+{
+	AV_VIDEO_PARA_WINDOW,
+	AV_VIDEO_PARA_CONTRAST,
+	AV_VIDEO_PARA_SATURATION,
+	AV_VIDEO_PARA_BRIGHTNESS,
+	AV_VIDEO_PARA_ENABLE,
+	AV_VIDEO_PARA_BLACKOUT,
+	AV_VIDEO_PARA_RATIO,
+	AV_VIDEO_PARA_RATIO_MATCH,
+	AV_VIDEO_PARA_MODE,
+	AV_VIDEO_PARA_CLEAR_VBUF,
+	AV_VIDEO_PARA_ERROR_RECOVERY_MODE,
+	AV_VIDEO_PARA_CROP,
+} AV_VideoParaType_t;
+
+/**\brief 视频窗口参数*/
+typedef struct
+{
+	int    x;
+	int    y;
+	int    w;
+	int    h;
+} AV_VideoWindow_t;
+
+/**\brief 音视频解码驱动*/
+struct AM_AV_Driver
+{
+	AM_ErrorCode_t (*open)(AM_AV_Device_t *dev, const AM_AV_OpenPara_t *para);
+	AM_ErrorCode_t (*close)(AM_AV_Device_t *dev);
+	AM_ErrorCode_t (*open_mode)(AM_AV_Device_t *dev, AV_PlayMode_t mode);
+	AM_ErrorCode_t (*start_mode)(AM_AV_Device_t *dev, AV_PlayMode_t mode, void *para);
+	AM_ErrorCode_t (*close_mode)(AM_AV_Device_t *dev, AV_PlayMode_t mode);
+	AM_ErrorCode_t (*ts_source)(AM_AV_Device_t *dev, AM_AV_TSSource_t src);
+	AM_ErrorCode_t (*file_cmd)(AM_AV_Device_t *dev, AV_PlayCmd_t cmd, void *data);
+	AM_ErrorCode_t (*inject_cmd)(AM_AV_Device_t *dev, AV_PlayCmd_t cmd, void *data);
+	AM_ErrorCode_t (*file_status)(AM_AV_Device_t *dev, AM_AV_PlayStatus_t *status);
+	AM_ErrorCode_t (*file_info)(AM_AV_Device_t *dev, AM_AV_FileInfo_t *info);
+	AM_ErrorCode_t (*set_video_para)(AM_AV_Device_t *dev, AV_VideoParaType_t para, void *val);
+	AM_ErrorCode_t (*inject)(AM_AV_Device_t *dev, AM_AV_InjectType_t type, uint8_t *data, int *size, int timeout);
+	AM_ErrorCode_t (*video_frame)(AM_AV_Device_t *dev, const AM_AV_SurfacePara_t *para, AM_OSD_Surface_t **s);
+	AM_ErrorCode_t (*get_audio_status)(AM_AV_Device_t *dev, AM_AV_AudioStatus_t *s);
+	AM_ErrorCode_t (*get_video_status)(AM_AV_Device_t *dev, AM_AV_VideoStatus_t *s);
+	AM_ErrorCode_t (*timeshift_fill)(AM_AV_Device_t *dev, uint8_t *data, int size);
+	AM_ErrorCode_t (*timeshift_cmd)(AM_AV_Device_t *dev, AV_PlayCmd_t cmd, void *para);
+	AM_ErrorCode_t (*get_timeshift_info)(AM_AV_Device_t *dev, AM_AV_TimeshiftInfo_t *info);
+	AM_ErrorCode_t (*set_vpath)(AM_AV_Device_t *dev);
+	AM_ErrorCode_t (*switch_ts_audio)(AM_AV_Device_t *dev, uint16_t apid, AM_AV_AFormat_t afmt);
+	AM_ErrorCode_t (*reset_audio_decoder)(AM_AV_Device_t *dev);
+	AM_ErrorCode_t (*set_drm_mode)(AM_AV_Device_t *dev, int enable);
+	AM_ErrorCode_t (*set_audio_ad)(AM_AV_Device_t *dev, int enable, uint16_t apid, AM_AV_AFormat_t afmt);
+	AM_ErrorCode_t (*set_inject_audio)(AM_AV_Device_t *dev, uint16_t apid, AM_AV_AFormat_t afmt);
+	AM_ErrorCode_t (*set_inject_subtitle)(AM_AV_Device_t *dev, uint16_t spid, int stype);
+	AM_ErrorCode_t (*timeshift_get_tfile)(AM_AV_Device_t *dev, AM_TFile_t *tfile);
+	void (*set_audio_cb)(AM_AV_Device_t *dev,AM_AV_Audio_CB_t cb,void *user_data);
+	AM_ErrorCode_t (*get_pts)(AM_AV_Device_t *dev, int type, uint64_t *pts);
+    AM_ErrorCode_t (*set_fe_status)(AM_AV_Device_t *dev, int value);
+};
+
+/**\brief 音视频播放参数*/
+typedef struct {
+	AV_InjectPlayPara_t   inject;
+	AV_TSPlayPara_t       ts;
+	AV_FilePlayPara_t     file;
+	char                  file_name[256];
+	AM_Bool_t             pause;
+	AM_Bool_t             loop;
+	AM_Bool_t             start;
+	int                   speed;
+	int                   pos;
+	AV_DataPlayPara_t     aes;
+	AV_DataPlayPara_t     ves;
+	AV_TimeShiftPlayPara_t   time_shift;
+	AM_AV_DrmMode_t       drm_mode;
+}AM_AV_PlayPara_t;
+
+/**\brief 音视频解码设备*/
+struct AM_AV_Device
+{
+	int              dev_no;         /**< 设备ID*/
+	int              vout_dev_no;    /**< 视频解码设备对应的视频输出设备*/
+	int              vout_w;         /**< 视频输出宽度*/
+	int              vout_h;         /**< 视频输出高度*/
+	const AM_AV_Driver_t  *drv;      /**< 解码驱动*/
+	void            *drv_data;       /**< 解码驱动相关数据*/
+	AV_TSPlayer_t    ts_player;      /**< TS流播放器*/
+	AV_FilePlayer_t  file_player;    /**< 文件播放器*/
+	AV_DataPlayer_t  vid_player;     /**< 视频数据播放器*/
+	AV_DataPlayer_t  aud_player;     /**< 音频数据播放器*/
+	AV_InjectPlayer_t inject_player; /**< 数据注入播放器*/
+	AV_TimeshiftPlayer_t timeshift_player;	/**< Timeshift 播放器*/
+	pthread_mutex_t  lock;           /**< 设备资源保护互斥体*/
+	AM_Bool_t        openned;        /**< 设备是否已经打开*/
+	AV_PlayMode_t    mode;           /**< 当前播放模式*/
+	int              video_x;        /**< 当前视频窗口左上角X坐标*/
+	int              video_y;        /**< 当前视频窗口左上角Y坐标*/
+	int              video_w;        /**< 当前视频窗口宽度*/
+	int              video_h;        /**< 当前视频窗口高度*/
+	int              video_contrast;       /**< 视频对比度*/
+	int              video_saturation;     /**< 视频饱和度*/
+	int              video_brightness;     /**< 视频亮度*/
+	AM_Bool_t        audio_switch;         /**< 音频是否需要切换*/
+	AM_Bool_t        video_enable;         /**< 视频层是否显示*/
+	AM_Bool_t        video_blackout;       /**< 无数据时是否黑屏*/
+	AM_AV_VideoAspectRatio_t     video_ratio;  /**< 视频长宽比*/
+	AM_AV_VideoAspectMatchMode_t video_match;  /**< 长宽比匹配模式*/
+	AM_AV_VideoDisplayMode_t     video_mode;   /**< 视频显示模式*/
+	AM_AV_FreeScalePara_t        vpath_fs;       /**< free scale参数*/
+	AM_AV_DeinterlacePara_t      vpath_di;       /**< deinterlace参数*/
+	AM_AV_PPMGRPara_t            vpath_ppmgr;    /**< ppmgr参数*/
+	AM_AV_PlayPara_t curr_para;      /**< 当前播放参数*/
+	void				*ad_date;
+	int                          afd_enable;
+	AM_USERDATA_AFD_t            afd;
+	AM_Crypt_Ops_t               *crypt_ops;
+	void                         *cryptor;
+	AM_Bool_t	replay_enable;		/*enable or disable replay when abnormal*/
+
+	/*for audio switching*/
+	uint16_t                     alt_apid;
+	AM_AV_AFormat_t              alt_afmt;
+};
+
+/****************************************************************************
+ * Function prototypes  
+ ***************************************************************************/
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/am_av/aml/Makefile b/test/am_ca_key_test/inject_record_t5d/am_av/aml/Makefile
new file mode 100644
index 0000000..7204768
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_av/aml/Makefile
@@ -0,0 +1,9 @@
+BASE=../../..
+
+include $(BASE)/rule/def.mk
+
+CFLAGS += -DUSE_ADEC_IN_DVB
+O_TARGET=aml
+aml_SRCS=aml.c
+
+include $(BASE)/rule/rule.mk
diff --git a/test/am_ca_key_test/inject_record_t5d/am_av/aml/aml.c b/test/am_ca_key_test/inject_record_t5d/am_av/aml/aml.c
new file mode 100644
index 0000000..8e4948c
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_av/aml/aml.c
@@ -0,0 +1,8154 @@
+#ifdef _FORTIFY_SOURCE
+#undef _FORTIFY_SOURCE
+#endif
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief AMLogic 音视频解码驱动
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-08-09: create the document
+ ***************************************************************************/
+
+#define AM_DEBUG_LEVEL 5
+#define _LARGEFILE64_SOURCE
+
+#include <am_debug.h>
+#include <am_misc.h>
+#include <am_mem.h>
+#include <am_evt.h>
+#include <am_time.h>
+#include "am_dmx.h"
+#include <am_thread.h>
+#include "../am_av_internal.h"
+#include "am_aout_internal.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <poll.h>
+#include <errno.h>
+#include <signal.h>
+#include <amports/amstream.h>
+//#ifdef ANDROID
+//#include <cutils/properties.h>
+//#endif
+#include "am_ad.h"
+#include "am_queue.h"
+
+#ifdef SUPPORT_CAS
+#include "aml_drm.h"
+#endif
+#include <am_cond.h>
+#include "am_userdata.h"
+
+//#ifdef ANDROID
+//#include <cutils/properties.h>
+//#include <sys/system_properties.h>
+//#endif
+
+
+#ifdef CHIP_8226H
+#include <linux/jpegdec.h>
+#endif
+#if defined(CHIP_8226M) || defined(CHIP_8626X)
+#include <linux/amports/jpegdec.h>
+#endif
+
+//#define PLAYER_API_NEW
+#define ADEC_API_NEW
+
+#include "player.h"
+#define PLAYER_INFO_POP_INTERVAL 500
+#define FILENAME_LENGTH_MAX 2048
+
+#include <codec_type.h>
+#ifdef USE_ADEC_IN_DVB
+#include <adec-external-ctrl.h>
+#endif
+void *adec_handle = NULL;
+
+#ifndef TRICKMODE_NONE
+#define TRICKMODE_NONE      0x00
+#define TRICKMODE_I         0x01
+#define TRICKMODE_FFFB      0x02
+#define TRICK_STAT_DONE     0x01
+#define TRICK_STAT_WAIT     0x00
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+#define AOUT_DEV_NO 0
+
+#define ENABLE_AUDIO_RESAMPLE
+#if 0
+#define ENABLE_DROP_BFRAME
+#endif
+//#define ENABLE_BYPASS_DI
+#ifdef ANDROID
+#define ENABLE_PCR
+#endif
+
+#define ADEC_START_AUDIO_LEVEL       1024
+#define ADEC_START_VIDEO_LEVEL       2048
+#define ADEC_FORCE_START_AUDIO_LEVEL 2048
+#define DEC_STOP_AUDIO_LEVEL         16
+#define DEC_STOP_VIDEO_LEVEL         512
+#define UP_RESAMPLE_AUDIO_LEVEL      128
+#define UP_RESAMPLE_VIDEO_LEVEL      1024
+#define DOWN_RESAMPLE_CACHE_TIME     90000*2
+#define NO_DATA_CHECK_TIME           2000
+#define VMASTER_REPLAY_TIME          4000
+#define SCRAMBLE_CHECK_TIME          1000
+#define TIMESHIFT_INJECT_DIFF_TIME	 (90000*4)
+#define TIMESHIFT_FFFB_ERROR_CNT	 5
+#define VIDEO_AVAILABLE_MIN_CNT     2
+#define TIME_UNIT90K                 90000
+#define AUDIO_NO_DATA_TIME          20
+#define FFFB_JUMP_STEP               500
+#ifdef ENABLE_PCR
+#ifndef AMSTREAM_IOC_PCRID
+#define AMSTREAM_IOC_PCRID        _IOW(AMSTREAM_IOC_MAGIC, 0x4f, int)
+#endif
+#endif
+
+#if !defined (AMLOGIC_LIBPLAYER)
+#define  AUDIO_CTRL_DEVICE    "/dev/amaudio_ctl"
+#define AMAUDIO_IOC_MAGIC  'A'
+#define AMAUDIO_IOC_SET_LEFT_MONO               _IOW(AMAUDIO_IOC_MAGIC, 0x0e, int)
+#define AMAUDIO_IOC_SET_RIGHT_MONO              _IOW(AMAUDIO_IOC_MAGIC, 0x0f, int)
+#define AMAUDIO_IOC_SET_STEREO                  _IOW(AMAUDIO_IOC_MAGIC, 0x10, int)
+#define AMAUDIO_IOC_SET_CHANNEL_SWAP            _IOW(AMAUDIO_IOC_MAGIC, 0x11, int)
+#endif
+
+
+#ifdef ANDROID
+/*for add new path*/
+#define DVB_STB_SOURCE_FILE "/sys/class/stb/source"
+#define TSYNCPCR_RESETFLAG_FILE "/sys/class/tsync_pcr/tsync_pcr_reset_flag"
+#define DI_BYPASS_ALL_FILE "/sys/module/di/parameters/bypass_all"
+#define DVB_STB_DEMUXSOURCE_FILE "/sys/class/stb/demux%d_source"
+#define DVB_STB_ASYNCFIFO_FLUSHSIZE_FILE "/sys/class/stb/asyncfifo0_flush_size"
+#define TSYNC_ENABLE_FILE "/sys/class/tsync/enable"
+#define VIDEO_SHOW_FIRSTFRM_NOSYNC_FILE "/sys/class/video/show_first_frame_nosync"
+
+
+#define STREAM_VBUF_FILE    "/dev/amstream_vbuf"
+#define STREAM_ABUF_FILE    "/dev/amstream_abuf"
+#define STREAM_TS_FILE      "/dev/amstream_mpts"
+#define STREAM_TS_SCHED_FILE      "/dev/amstream_mpts_sched"
+#define STREAM_PS_FILE      "/dev/amstream_mpps"
+#define STREAM_RM_FILE      "/dev/amstream_rm"
+#define JPEG_DEC_FILE       "/dev/amjpegdec"
+#define AMVIDEO_FILE        "/dev/amvideo"
+
+#define PPMGR_FILE			"/dev/ppmgr"
+
+#define VID_AXIS_FILE       "/sys/class/video/axis"
+#define VID_CROP_FILE       "/sys/class/video/crop"
+#define VID_CONTRAST_FILE   "/sys/class/video/contrast"
+#define VID_SATURATION_FILE "/sys/class/video/saturation"
+#define VID_BRIGHTNESS_FILE "/sys/class/video/brightness"
+#define VID_DISABLE_FILE    "/sys/class/video/disable_video"
+#define VID_BLACKOUT_FILE   "/sys/class/video/blackout_policy"
+#define VID_SCREEN_MODE_FILE  "/sys/class/video/screen_mode"
+#define VID_SCREEN_MODE_FILE  "/sys/class/video/screen_mode"
+#define VID_ASPECT_RATIO_FILE "/sys/class/video/aspect_ratio"
+#define VID_ASPECT_MATCH_FILE "/sys/class/video/matchmethod"
+
+
+#define VDEC_H264_ERROR_RECOVERY_MODE_FILE "/sys/module/amvdec_h264/parameters/error_recovery_mode"
+#define VDEC_H264_FATAL_ERROR_RESET_FILE "/sys/module/amvdec_h264/parameters/fatal_error_reset"
+#define DISP_MODE_FILE      "/sys/class/display/mode"
+#define ASTREAM_FORMAT_FILE "/sys/class/astream/format"
+#define VIDEO_DROP_BFRAME_FILE  "/sys/module/amvdec_h264/parameters/enable_toggle_drop_B_frame"
+#define DI_BYPASS_FILE    "/sys/module/di/parameters/bypass_post"
+#define ENABLE_RESAMPLE_FILE    "/sys/class/amaudio/enable_resample"
+#define RESAMPLE_TYPE_FILE      "/sys/class/amaudio/resample_type"
+#define AUDIO_DMX_PTS_FILE	"/sys/class/stb/audio_pts"
+#define VIDEO_DMX_PTS_FILE	"/sys/class/stb/video_pts"
+#define AUDIO_DMX_PTS_BIT32_FILE	"/sys/class/stb/audio_pts_bit32"
+#define VIDEO_DMX_PTS_BIT32_FILE	"/sys/class/stb/video_pts_bit32"
+#define AUDIO_PTS_FILE	"/sys/class/tsync/pts_audio"
+#define VIDEO_PTS_FILE	"/sys/class/tsync/pts_video"
+#define TSYNC_MODE_FILE "/sys/class/tsync/mode"
+#define AV_THRESHOLD_MIN_FILE "/sys/class/tsync/av_threshold_min"
+#define AV_THRESHOLD_MAX_FILE "/sys/class/tsync/av_threshold_max"
+#define AVS_PLUS_DECT_FILE "/sys/module/amvdec_avs/parameters/profile"
+#define DEC_CONTROL_H264 "/sys/module/amvdec_h264/parameters/dec_control"
+#define DEC_CONTROL_MPEG12 "/sys/module/amvdec_mpeg12/parameters/dec_control"
+#define VIDEO_NEW_FRAME_COUNT_FILE "/sys/module/amvideo/parameters/new_frame_count"
+#define AUDIO_DSP_DIGITAL_RAW_FILE "/sys/class/audiodsp/digital_raw"
+#define VID_FRAME_FMT_FILE   "/sys/class/video/frame_format"
+#define VIDEO_NEW_FRAME_TOGGLED_FILE "/sys/module/amvideo/parameters/first_frame_toggled"
+#define TSYNC_FIRSTCHECKIN_APTS_FILE "/sys/class/tsync/checkin_firstapts"
+#define TSYNC_FIRSTCHECKIN_VPTS_FILE "/sys/class/tsync/checkin_firstvpts"
+#define TSYNC_PCR_MODE_FILE	"/sys/class/tsync_pcr/tsync_pcr_mode"
+#define TSYNC_AUDIO_STATE_FILE	"/sys/class/tsync_pcr/tsync_audio_state"
+#else
+
+/*for add new path*/
+#define DVB_STB_SOURCE_FILE "/sys/class/stb/source"
+#define TSYNCPCR_RESETFLAG_FILE "/sys/class/tsync_pcr/tsync_pcr_reset_flag"
+#define DI_BYPASS_ALL_FILE "/sys/module/di/parameters/bypass_all"
+#define DVB_STB_DEMUXSOURCE_FILE "/sys/class/stb/demux%d_source"
+#define DVB_STB_ASYNCFIFO_FLUSHSIZE_FILE "/sys/class/stb/asyncfifo0_flush_size"
+#define TSYNC_ENABLE_FILE "/sys/class/tsync/enable"
+#define VIDEO_SHOW_FIRSTFRM_NOSYNC_FILE "/sys/class/video/show_first_frame_nosync"
+
+
+#define STREAM_VBUF_FILE    "/dev/amstream_vbuf"
+#define STREAM_ABUF_FILE    "/dev/amstream_abuf"
+#define STREAM_TS_FILE      "/dev/amstream_mpts"
+#define STREAM_TS_SCHED_FILE      "/dev/amstream_mpts_sched"
+#define STREAM_PS_FILE      "/dev/amstream_mpps"
+#define STREAM_RM_FILE      "/dev/amstream_rm"
+#define JPEG_DEC_FILE       "/dev/amjpegdec"
+#define AMVIDEO_FILE        "/dev/amvideo"
+
+#define PPMGR_FILE			"/dev/ppmgr"
+
+#define VID_AXIS_FILE       "/sys/class/video/axis"
+#define VID_CROP_FILE       "/sys/class/video/crop"
+#define VID_CONTRAST_FILE   "/sys/class/video/contrast"
+
+/*not find,but android is exist*/
+#define VID_SATURATION_FILE "/sys/class/video/saturation"
+
+#define VID_BRIGHTNESS_FILE "/sys/class/video/brightness"
+#define VID_DISABLE_FILE    "/sys/class/video/disable_video"
+#define VID_BLACKOUT_FILE   "/sys/class/video/blackout_policy"
+#define VID_SCREEN_MODE_FILE  "/sys/class/video/screen_mode"
+#define VID_FRAME_FMT_FILE   "/sys/class/video/frame_format"
+
+#define VDEC_H264_ERROR_RECOVERY_MODE_FILE "/sys/module/vh264/parameters/error_recovery_mode"
+#define VDEC_H264_FATAL_ERROR_RESET_FILE "/sys/module/vh264/parameters/fatal_error_reset"
+#define DISP_MODE_FILE      "/sys/class/display/mode"
+#define ASTREAM_FORMAT_FILE "/sys/class/astream/format"
+
+/*not find,android is not find*/
+#define VIDEO_DROP_BFRAME_FILE  "/sys/module/amvdec_h264/parameters/enable_toggle_drop_B_frame"
+
+
+#define DI_BYPASS_FILE    "/sys/module/di/parameters/bypass_post"
+#define VIDEO_NEW_FRAME_TOGGLED_FILE "/sys/module/amvideo/parameters/first_frame_toggled"
+
+/*not find,android is not find*/
+#define ENABLE_RESAMPLE_FILE    "/sys/class/amaudio/enable_resample"
+#define RESAMPLE_TYPE_FILE      "/sys/class/amaudio/resample_type"
+
+#define AUDIO_DMX_PTS_FILE	"/sys/class/stb/audio_pts"
+#define VIDEO_DMX_PTS_FILE	"/sys/class/stb/video_pts"
+#define AUDIO_PTS_FILE	"/sys/class/tsync/pts_audio"
+#define VIDEO_PTS_FILE	"/sys/class/tsync/pts_video"
+#define TSYNC_MODE_FILE "/sys/class/tsync/mode"
+#define AV_THRESHOLD_MIN_FILE "/sys/class/tsync/av_threshold_min"
+#define AV_THRESHOLD_MAX_FILE "/sys/class/tsync/av_threshold_max"
+#define TSYNC_FIRSTCHECKIN_APTS_FILE "/sys/class/tsync/checkin_firstapts"
+#define TSYNC_FIRSTCHECKIN_VPTS_FILE "/sys/class/tsync/checkin_firstvpts"
+#define AUDIO_DMX_PTS_BIT32_FILE	"/sys/class/stb/audio_pts_bit32"
+#define VIDEO_DMX_PTS_BIT32_FILE	"/sys/class/stb/video_pts_bit32"
+
+/*not find,android is not find*/
+#define AVS_PLUS_DECT_FILE "/sys/module/amvdec_avs/parameters/profile"
+
+#define DEC_CONTROL_H264 "/sys/module/vh264/parameters/dec_control"
+#define DEC_CONTROL_MPEG12 "/sys/module/vmpeg12/parameters/dec_control"
+#define VIDEO_NEW_FRAME_COUNT_FILE "/sys/module/frame_sink/parameters/new_frame_count"
+#define AUDIO_DSP_DIGITAL_RAW_FILE "/sys/class/audiodsp/digital_raw"
+#define TSYNC_PCR_MODE_FILE	"/sys/class/tsync_pcr/tsync_pcr_mode"
+#define TSYNC_AUDIO_STATE_FILE	"/sys/class/tsync_pcr/tsync_audio_state"
+#endif
+
+#ifdef ANDROID
+#define DEC_CONTROL_PROP "media.dec_control"
+#define AC3_AMASTER_PROP "media.ac3_amaster"
+#endif
+#define SHOW_FIRSTFRAME_NOSYNC_PROP "tv.dtv.showfirstframe_nosync"
+#define REPLAY_ENABLE_PROP	"tv.dtv.replay_enable"
+
+#define CANVAS_ALIGN(x)    (((x)+7)&~7)
+#define JPEG_WRTIE_UNIT    (32*1024)
+#define AV_SYNC_THRESHOLD	60
+#define AV_SMOOTH_SYNC_VAL "100"
+
+#ifdef ANDROID
+#define open(a...)\
+	({\
+	 int ret, times=300;\
+	 do{\
+	 	ret = open(a);\
+	 	if(ret==-1)\
+	 		usleep(10000);\
+	 }while(ret==-1 && times--);\
+	 ret;\
+	 })
+#endif
+
+#define PPMGR_IOC_MAGIC         'P'
+#define PPMGR_IOC_2OSD0         _IOW(PPMGR_IOC_MAGIC, 0x00, unsigned int)
+#define PPMGR_IOC_ENABLE_PP     _IOW(PPMGR_IOC_MAGIC, 0X01, unsigned int)
+#define PPMGR_IOC_CONFIG_FRAME  _IOW(PPMGR_IOC_MAGIC, 0X02, unsigned int)
+#define PPMGR_IOC_VIEW_MODE     _IOW(PPMGR_IOC_MAGIC, 0X03, unsigned int)
+
+#define MODE_3D_DISABLE         0x00000000
+#define MODE_3D_ENABLE          0x00000001
+#define MODE_AUTO               0x00000002
+#define MODE_2D_TO_3D           0x00000004
+#define MODE_LR                 0x00000008
+#define MODE_BT                 0x00000010
+#define MODE_LR_SWITCH          0x00000020
+#define MODE_FIELD_DEPTH        0x00000040
+#define MODE_3D_TO_2D_L         0x00000080
+#define MODE_3D_TO_2D_R         0x00000100
+#define LR_FORMAT_INDICATOR     0x00000200
+#define BT_FORMAT_INDICATOR     0x00000400
+
+#define VALID_PID(_pid_) ((_pid_)>0 && (_pid_)<0x1fff)
+
+static AM_ErrorCode_t set_dec_control(AM_Bool_t enable);
+
+#define VALID_VIDEO(_pid_, _fmt_) (VALID_PID(_pid_))
+#define VALID_PCR(_pid_) (VALID_PID(_pid_))
+
+#ifdef USE_ADEC_IN_DVB
+#define VALID_AUDIO(_pid_, _fmt_) (VALID_PID(_pid_) && audio_get_format_supported(_fmt_))
+#else
+#define VALID_AUDIO(_pid_, _fmt_) (VALID_PID(_pid_))
+#endif
+
+/*
+ * As not inlude "adec-external-ctrl.h", so we need declare
+ * audio_decode_set_volume. Otherwise it will lost the value of the second
+ * param, AKA volume.
+ */
+extern int audio_decode_set_volume(void *, float);
+#ifdef SUPPORT_CAS
+#define SECURE_BLOCK_SIZE 256*1024
+/* Round up the even multiple of size, size has to be a multiple of 2 */
+#define ROUNDUP(v, size) (((v) + ((__typeof__(v))(size) - 1)) & \
+													~((__typeof__(v))(size) - 1))
+#endif
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+/**\brief 音视频数据注入*/
+typedef struct
+{
+	int             fd;
+	int             video_fd;
+	pthread_t       thread;
+	pthread_mutex_t lock;
+	pthread_cond_t  cond;
+	const uint8_t  *data;
+	int             len;
+	int             times;
+	int             pos;
+	int             dev_no;
+	AM_Bool_t       is_audio;
+	AM_Bool_t       running;
+	void           *adec;
+} AV_DataSource_t;
+
+/**\brief JPEG解码相关数据*/
+typedef struct
+{
+	int             vbuf_fd;
+	int             dec_fd;
+} AV_JPEGData_t;
+
+/**\brief JPEG解码器状态*/
+typedef enum {
+	AV_JPEG_DEC_STAT_DECDEV,
+	AV_JPEG_DEC_STAT_INFOCONFIG,
+	AV_JPEG_DEC_STAT_INFO,
+	AV_JPEG_DEC_STAT_DECCONFIG,
+	AV_JPEG_DEC_STAT_RUN
+} AV_JPEGDecState_t;
+
+#ifdef PLAYER_API_NEW
+/**\brief 文件播放器数据*/
+typedef struct
+{
+	int                media_id;
+	play_control_t pctl;
+	pthread_mutex_t    lock;
+	pthread_cond_t     cond;
+	AM_AV_Device_t    *av;
+} AV_FilePlayerData_t;
+#endif
+
+/**\brief 数据注入播放模式相关数据*/
+typedef struct
+{
+	AM_AV_AFormat_t    aud_fmt;
+	AM_AV_VFormat_t    vid_fmt;
+	int                sub_type;
+	AM_AV_PFormat_t    pkg_fmt;
+	int                aud_fd;
+	int                vid_fd;
+	int                aud_id;
+	int                vid_id;
+	int                sub_id;
+	int                cntl_fd;
+	void              *adec;
+	AM_AD_Handle_t ad;
+} AV_InjectData_t;
+
+/**\brief TS player 相关数据*/
+typedef struct
+{
+	int fd;
+	int vid_fd;
+	void *adec;
+	AM_AD_Handle_t ad;
+} AV_TSData_t;
+
+/**\brief Timeshift播放状态*/
+typedef enum
+{
+	AV_TIMESHIFT_STAT_STOP,
+	AV_TIMESHIFT_STAT_PLAY,
+	AV_TIMESHIFT_STAT_PAUSE,
+	AV_TIMESHIFT_STAT_FFFB,
+	AV_TIMESHIFT_STAT_EXIT,
+	AV_TIMESHIFT_STAT_INITOK,
+	AV_TIMESHIFT_STAT_SEARCHOK,
+} AV_TimeshiftState_t;
+
+typedef struct {
+	AV_PlayCmd_t cmd;
+	int done;
+	union {
+		struct {
+			int seek_pos;
+		} seek;
+		struct {
+			int speed;
+		} speed;
+	};
+} AV_PlayCmdPara_t;
+
+#define TIMESHIFT_CMD_Q_SIZE (32)
+QUEUE_DECLARATION(timeshift_cmd_q, AV_PlayCmdPara_t, TIMESHIFT_CMD_Q_SIZE);
+
+/**\brief Timeshift播放模式相关数据*/
+typedef struct
+{
+	int					running;
+	int					rate;	/**< bytes/s*/
+	int					duration;	/**< dur for playback, ms*/
+	int					dmxfd;
+	int					start;/**< start time, ms*/
+	int					end;/**< end time, ms*/
+	int					current;/**< current time, ms*/
+	int					left;
+	int					inject_size;
+	int					timeout;
+	loff_t				rtotal;
+	int					rtime;
+	struct timeshift_cmd_q  cmd_q;
+	AV_PlayCmdPara_t        last_cmd[2];
+	pthread_t			thread;
+	pthread_mutex_t		lock;
+	pthread_cond_t		cond;
+	AV_TimeshiftState_t	state;
+	AM_TFile_t	file;
+	int offset;
+	#define TIMESHIFT_TFILE_AUTOCREATE 1
+	#define TIMESHIFT_TFILE_DETACHED 2
+	int file_flag;
+	AM_AV_Device_t       *dev;
+	AM_AV_TimeshiftInfo_t	info;
+	char 				last_stb_src[16];
+	char 				last_dmx_src[16];
+
+	AV_TimeShiftPlayPara_t para;
+
+	AV_TSPlayPara_t		tp;
+
+	AV_TSData_t			ts;
+
+	int                     pause_time;
+#ifdef SUPPORT_CAS
+	int cas_open;
+	uint8_t *buf;
+#endif
+	int                     fffb_start;
+	int                     fffb_current;
+	int                     eof;
+} AV_TimeshiftData_t;
+
+struct AM_AUDIO_Driver
+{
+	void (*adec_start_decode)(int fd, int fmt, int has_video, void **padec);
+	void (*adec_stop_decode)(void **padec);
+	void (*adec_pause_decode)(void *adec);
+	void (*adec_resume_decode)(void *adec);
+	void (*adec_set_decode_ad)(int enable, int pid, int fmt, void *adec);
+	void (*adec_get_status)(void *adec, AM_AV_AudioStatus_t *para);
+	AM_ErrorCode_t (*adec_set_volume)(AM_AOUT_Device_t *dev, int vol);
+	AM_ErrorCode_t (*adec_set_mute)(AM_AOUT_Device_t *dev, AM_Bool_t mute);
+	AM_ErrorCode_t (*adec_set_output_mode)(AM_AOUT_Device_t *dev, AM_AOUT_OutputMode_t mode);
+	AM_ErrorCode_t (*adec_set_pre_gain)(AM_AOUT_Device_t *dev, float gain);
+	AM_ErrorCode_t (*adec_set_pre_mute)(AM_AOUT_Device_t *dev, AM_Bool_t mute);
+};
+typedef struct AM_AUDIO_Driver  AM_AUDIO_Driver_t;
+
+static AM_AV_Audio_CB_t s_audio_cb = NULL;
+static void *pUserData = NULL;
+
+enum AV_SyncForce_e {
+	FORCE_NONE,
+	FORCE_AC3_AMASTER,
+};
+
+/****************************************************************************
+ * Static data
+ ***************************************************************************/
+
+/*音视频设备操作*/
+static AM_ErrorCode_t aml_open(AM_AV_Device_t *dev, const AM_AV_OpenPara_t *para);
+static AM_ErrorCode_t aml_close(AM_AV_Device_t *dev);
+static AM_ErrorCode_t aml_open_mode(AM_AV_Device_t *dev, AV_PlayMode_t mode);
+static AM_ErrorCode_t aml_start_mode(AM_AV_Device_t *dev, AV_PlayMode_t mode, void *para);
+static AM_ErrorCode_t aml_close_mode(AM_AV_Device_t *dev, AV_PlayMode_t mode);
+static AM_ErrorCode_t aml_ts_source(AM_AV_Device_t *dev, AM_AV_TSSource_t src);
+static AM_ErrorCode_t aml_file_cmd(AM_AV_Device_t *dev, AV_PlayCmd_t cmd, void *data);
+static AM_ErrorCode_t aml_inject_cmd(AM_AV_Device_t *dev, AV_PlayCmd_t cmd, void *data);
+static AM_ErrorCode_t aml_file_status(AM_AV_Device_t *dev, AM_AV_PlayStatus_t *status);
+static AM_ErrorCode_t aml_file_info(AM_AV_Device_t *dev, AM_AV_FileInfo_t *info);
+static AM_ErrorCode_t aml_set_video_para(AM_AV_Device_t *dev, AV_VideoParaType_t para, void *val);
+static AM_ErrorCode_t aml_inject(AM_AV_Device_t *dev, AM_AV_InjectType_t type, uint8_t *data, int *size, int timeout);
+static AM_ErrorCode_t aml_video_frame(AM_AV_Device_t *dev, const AM_AV_SurfacePara_t *para, AM_OSD_Surface_t **s);
+static AM_ErrorCode_t aml_get_astatus(AM_AV_Device_t *dev, AM_AV_AudioStatus_t *para);
+static AM_ErrorCode_t aml_get_vstatus(AM_AV_Device_t *dev, AM_AV_VideoStatus_t *para);
+static AM_ErrorCode_t aml_timeshift_fill_data(AM_AV_Device_t *dev, uint8_t *data, int size);
+static AM_ErrorCode_t aml_timeshift_cmd(AM_AV_Device_t *dev, AV_PlayCmd_t cmd, void *para);
+static AM_ErrorCode_t aml_timeshift_get_info(AM_AV_Device_t *dev, AM_AV_TimeshiftInfo_t *info);
+static AM_ErrorCode_t aml_set_vpath(AM_AV_Device_t *dev);
+static AM_ErrorCode_t aml_switch_ts_audio_fmt(AM_AV_Device_t *dev, AV_TSData_t *ts, AV_TSPlayPara_t *tp);
+static AM_ErrorCode_t aml_switch_ts_audio(AM_AV_Device_t *dev, uint16_t apid, AM_AV_AFormat_t afmt);
+static AM_ErrorCode_t aml_reset_audio_decoder(AM_AV_Device_t *dev);
+static AM_ErrorCode_t aml_set_drm_mode(AM_AV_Device_t *dev, AM_AV_DrmMode_t drm_mode);
+static AM_ErrorCode_t aml_set_audio_ad(AM_AV_Device_t *dev, int enable, uint16_t apid, AM_AV_AFormat_t afmt);
+static AM_ErrorCode_t aml_set_inject_audio(AM_AV_Device_t *dev, uint16_t apid, AM_AV_AFormat_t afmt);
+static AM_ErrorCode_t aml_set_inject_subtitle(AM_AV_Device_t *dev, uint16_t spid, int stype);
+static AM_ErrorCode_t aml_timeshift_get_tfile(AM_AV_Device_t *dev, AM_TFile_t *tfile);
+static void 		  aml_set_audio_cb(AM_AV_Device_t *dev,AM_AV_Audio_CB_t cb,void *user_data);
+
+static int aml_restart_inject_mode(AM_AV_Device_t *dev, AM_Bool_t destroy_thread);
+static AM_ErrorCode_t aml_get_pts(AM_AV_Device_t *dev, int type, uint64_t *pts);
+static AM_ErrorCode_t aml_get_timeout_real(int timeout, struct timespec *ts);
+static void aml_timeshift_update_info(AV_TimeshiftData_t *tshift, AM_AV_TimeshiftInfo_t *info);
+static AM_ErrorCode_t aml_set_fe_status(AM_AV_Device_t *dev, int value);
+
+
+const AM_AV_Driver_t aml_av_drv =
+{
+.open        = aml_open,
+.close       = aml_close,
+.open_mode   = aml_open_mode,
+.start_mode  = aml_start_mode,
+.close_mode  = aml_close_mode,
+.ts_source   = aml_ts_source,
+.file_cmd    = aml_file_cmd,
+.inject_cmd  = aml_inject_cmd,
+.file_status = aml_file_status,
+.file_info   = aml_file_info,
+.set_video_para = aml_set_video_para,
+.inject      = aml_inject,
+.video_frame = aml_video_frame,
+.get_audio_status = aml_get_astatus,
+.get_video_status = aml_get_vstatus,
+.timeshift_fill = aml_timeshift_fill_data,
+.timeshift_cmd = aml_timeshift_cmd,
+.get_timeshift_info = aml_timeshift_get_info,
+.set_vpath   = aml_set_vpath,
+.switch_ts_audio = aml_switch_ts_audio,
+.reset_audio_decoder = aml_reset_audio_decoder,
+.set_drm_mode = aml_set_drm_mode,
+.set_audio_ad = aml_set_audio_ad,
+.set_inject_audio = aml_set_inject_audio,
+.set_inject_subtitle = aml_set_inject_subtitle,
+.timeshift_get_tfile = aml_timeshift_get_tfile,
+.set_audio_cb = aml_set_audio_cb,
+.get_pts = aml_get_pts,
+.set_fe_status = aml_set_fe_status,
+
+};
+
+/*音频控制(通过解码器)操作*/
+static AM_ErrorCode_t adec_aout_open(AM_AOUT_Device_t *dev, const AM_AOUT_OpenPara_t *para);
+static AM_ErrorCode_t adec_aout_set_volume(AM_AOUT_Device_t *dev, int vol);
+static AM_ErrorCode_t adec_aout_set_mute(AM_AOUT_Device_t *dev, AM_Bool_t mute);
+static AM_ErrorCode_t adec_aout_set_output_mode(AM_AOUT_Device_t *dev, AM_AOUT_OutputMode_t mode);
+static AM_ErrorCode_t adec_aout_close(AM_AOUT_Device_t *dev);
+static AM_ErrorCode_t adec_aout_set_pre_gain(AM_AOUT_Device_t *dev, float gain);
+static AM_ErrorCode_t adec_aout_set_pre_mute(AM_AOUT_Device_t *dev, AM_Bool_t mute);
+
+const AM_AOUT_Driver_t adec_aout_drv =
+{
+.open         = adec_aout_open,
+.set_volume   = adec_aout_set_volume,
+.set_mute     = adec_aout_set_mute,
+.set_output_mode = adec_aout_set_output_mode,
+.close        = adec_aout_close,
+.set_pre_gain = adec_aout_set_pre_gain,
+.set_pre_mute = adec_aout_set_pre_mute,
+};
+
+static AM_ErrorCode_t adec_aout_open_cb(AM_AOUT_Device_t *dev, const AM_AOUT_OpenPara_t *para);
+static AM_ErrorCode_t adec_aout_set_volume_cb(AM_AOUT_Device_t *dev, int vol);
+static AM_ErrorCode_t adec_aout_set_mute_cb(AM_AOUT_Device_t *dev, AM_Bool_t mute);
+static AM_ErrorCode_t adec_aout_set_output_mode_cb(AM_AOUT_Device_t *dev, AM_AOUT_OutputMode_t mode);
+static AM_ErrorCode_t adec_aout_close_cb(AM_AOUT_Device_t *dev);
+static AM_ErrorCode_t adec_aout_set_pre_gain_cb(AM_AOUT_Device_t *dev, float gain);
+static AM_ErrorCode_t adec_aout_set_pre_mute_cb(AM_AOUT_Device_t *dev, AM_Bool_t mute);
+
+const AM_AOUT_Driver_t adec_aout_drv_cb =
+{
+.open         = adec_aout_open_cb,
+.set_volume   = adec_aout_set_volume_cb,
+.set_mute     = adec_aout_set_mute_cb,
+.set_output_mode = adec_aout_set_output_mode_cb,
+.close        = adec_aout_close_cb,
+.set_pre_gain = adec_aout_set_pre_gain_cb,
+.set_pre_mute = adec_aout_set_pre_mute_cb,
+};
+
+#if 0
+/*音频控制(通过amplayer2)操作*/
+static AM_ErrorCode_t amp_open(AM_AOUT_Device_t *dev, const AM_AOUT_OpenPara_t *para);
+static AM_ErrorCode_t amp_set_volume(AM_AOUT_Device_t *dev, int vol);
+static AM_ErrorCode_t amp_set_mute(AM_AOUT_Device_t *dev, AM_Bool_t mute);
+static AM_ErrorCode_t amp_set_output_mode(AM_AOUT_Device_t *dev, AM_AOUT_OutputMode_t mode);
+static AM_ErrorCode_t amp_close(AM_AOUT_Device_t *dev);
+
+const AM_AOUT_Driver_t amplayer_aout_drv =
+{
+.open         = amp_open,
+.set_volume   = amp_set_volume,
+.set_mute     = amp_set_mute,
+.set_output_mode = amp_set_output_mode,
+.close        = amp_close
+};
+#endif
+static void adec_start_decode(int fd, int fmt, int has_video, void **padec);
+static void adec_stop_decode(void **padec);
+static void adec_set_decode_ad(int enable, int pid, int fmt, void *adec);
+static AM_ErrorCode_t adec_set_volume(AM_AOUT_Device_t *dev, int vol);
+static AM_ErrorCode_t adec_set_mute(AM_AOUT_Device_t *dev, AM_Bool_t mute);
+static AM_ErrorCode_t adec_set_output_mode(AM_AOUT_Device_t *dev, AM_AOUT_OutputMode_t mode);
+static AM_ErrorCode_t adec_set_pre_gain(AM_AOUT_Device_t *dev, float gain);
+static AM_ErrorCode_t adec_set_pre_mute(AM_AOUT_Device_t *dev, AM_Bool_t mute);
+static void adec_pause_decode(void *handle);
+static void adec_resume_decode(void *handle);
+static void adec_get_status(void *adec, AM_AV_AudioStatus_t *para);
+
+#ifdef USE_ADEC_IN_DVB
+const AM_AUDIO_Driver_t native_audio_drv =
+{
+.adec_start_decode = adec_start_decode,
+.adec_pause_decode = adec_pause_decode,
+.adec_resume_decode = adec_resume_decode,
+.adec_stop_decode = adec_stop_decode,
+.adec_set_decode_ad = adec_set_decode_ad,
+.adec_set_volume = adec_set_volume,
+.adec_set_mute = adec_set_mute,
+.adec_set_output_mode = adec_set_output_mode,
+.adec_set_pre_gain = adec_set_pre_gain,
+.adec_set_pre_mute = adec_set_pre_mute,
+.adec_get_status = adec_get_status
+};
+#endif
+static void adec_start_decode_cb(int fd, int fmt, int has_video, void **padec);
+static void adec_stop_decode_cb(void **padec);
+static void adec_set_decode_ad_cb(int enable, int pid, int fmt, void *adec);
+static AM_ErrorCode_t adec_set_volume_cb(AM_AOUT_Device_t *dev, int vol);
+static AM_ErrorCode_t adec_set_mute_cb(AM_AOUT_Device_t *dev, AM_Bool_t mute);
+static AM_ErrorCode_t adec_set_output_mode_cb(AM_AOUT_Device_t *dev, AM_AOUT_OutputMode_t mode);
+static AM_ErrorCode_t adec_set_pre_gain_cb(AM_AOUT_Device_t *dev, float gain);
+static AM_ErrorCode_t adec_set_pre_mute_cb(AM_AOUT_Device_t *dev, AM_Bool_t mute);
+static void adec_pause_decode_cb(void *adec);
+static void adec_resume_decode_cb(void *adec);
+static void adec_get_status_cb(void *adec, AM_AV_AudioStatus_t *para);
+
+const AM_AUDIO_Driver_t callback_audio_drv =
+{
+.adec_start_decode = adec_start_decode_cb,
+.adec_pause_decode = adec_pause_decode_cb,
+.adec_resume_decode = adec_resume_decode_cb,
+.adec_stop_decode = adec_stop_decode_cb,
+.adec_set_decode_ad = adec_set_decode_ad_cb,
+.adec_set_volume = adec_set_volume_cb,
+.adec_set_mute = adec_set_mute_cb,
+.adec_set_output_mode = adec_set_output_mode_cb,
+.adec_set_pre_gain = adec_set_pre_gain_cb,
+.adec_set_pre_mute = adec_set_pre_mute_cb,
+.adec_get_status = adec_get_status_cb
+};
+
+#ifdef USE_ADEC_IN_DVB
+static AM_AUDIO_Driver_t *audio_ops = &native_audio_drv;
+#else
+static AM_AUDIO_Driver_t *audio_ops = &callback_audio_drv;
+#endif
+int g_festatus = 0;
+
+/*监控AV buffer, PTS 操作*/
+static pthread_mutex_t gAVMonLock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t gAVMonCond = PTHREAD_COND_INITIALIZER;
+
+static void* aml_av_monitor_thread(void *arg);
+
+/*Timeshift 操作*/
+static void *aml_timeshift_thread(void *arg);
+
+static AV_TimeshiftData_t *m_tshift = NULL;
+
+#if 0
+typedef struct {
+	unsigned int    format;  ///< video format, such as H264, MPEG2...
+	unsigned int    width;   ///< video source width
+	unsigned int    height;  ///< video source height
+	unsigned int    rate;    ///< video source frame duration
+	unsigned int    extra;   ///< extra data information of video stream
+	unsigned int    status;  ///< status of video stream
+	float           ratio;   ///< aspect ratio of video source
+	void *          param;   ///< other parameters for video decoder
+} dec_sysinfo_t;
+#endif
+static dec_sysinfo_t am_sysinfo;
+
+
+static AM_ErrorCode_t aml_set_ad_source(AM_AD_Handle_t *ad, int enable, int pid, int fmt, void *user);
+static int aml_calc_sync_mode(AM_AV_Device_t *dev, int has_audio, int has_video, int has_pcr, int afmt, int *force_reason);
+static int aml_set_sync_mode(AM_AV_Device_t *dev, int mode);
+static void *aml_try_open_crypt(AM_Crypt_Ops_t *ops);
+/****************************************************************************
+ * Static functions
+ ***************************************************************************/
+
+/****************************************************************************
+ * for now only mpeg2/h264/h265/vp9/avs2/mjpeg/mpeg4
+ * support multi instance video decoder
+ * use /dev/amstream_mpts_sched
+ ***************************************************************************/
+static float getUptimeSeconds() {
+    struct timespec ts;
+    clock_gettime(CLOCK_MONOTONIC, &ts);
+
+    return (float)(ts.tv_sec +(float)ts.tv_nsec / 1000000000);
+}
+
+static AM_Bool_t configure_vdec_info(int fd, char *p_info, uint32_t len)
+{
+	struct am_ioctl_parm_ptr param;
+
+	memset(&param, 0, sizeof(param));
+	param.cmd = AMSTREAM_SET_PTR_CONFIGS;
+	param.pointer = p_info;
+	param.len = len;
+
+	if (ioctl(fd, AMSTREAM_IOC_SET_PTR, (unsigned long)&param) == -1)
+	{
+		AM_DEBUG(1, "configure vdec info [%s] failed\n", p_info);
+		return AM_FALSE;
+	}
+	AM_DEBUG(1, "configure vdec info [%s] success\n", p_info);
+	return AM_TRUE;
+}
+static AM_Bool_t check_vfmt_support_sched(AM_AV_VFormat_t vfmt)
+{
+	if (vfmt == VFORMAT_MPEG12 ||
+			vfmt == VFORMAT_H264 ||
+			vfmt == VFORMAT_HEVC ||
+			vfmt == VFORMAT_MJPEG ||
+			vfmt == VFORMAT_MPEG4 ||
+			vfmt == VFORMAT_VP9 ||
+			vfmt == VFORMAT_AVS2)
+		return AM_TRUE;
+	else
+		return AM_FALSE;
+}
+
+static AM_Bool_t show_first_frame_nosync(void)
+{
+	char buf[32];
+
+	if (AM_FileRead(VIDEO_SHOW_FIRSTFRM_NOSYNC_FILE, buf, sizeof(buf)) >= 0) {
+		int v = atoi(buf);
+
+		return (v == 1) ? AM_TRUE : AM_FALSE;
+	}
+
+	return AM_FALSE;
+}
+
+static void set_first_frame_nosync(void)
+{
+#ifdef ANDROID
+//	int syncmode = property_get_int32(SHOW_FIRSTFRAME_NOSYNC_PROP, 1);
+//	AM_DEBUG(1, "%s %d", __FUNCTION__,syncmode);
+//	AM_FileEcho(VIDEO_SHOW_FIRSTFRM_NOSYNC_FILE, syncmode?"1":"0");
+#else
+	AM_FileEcho(VIDEO_SHOW_FIRSTFRM_NOSYNC_FILE, "1");
+#endif
+}
+
+static int get_amstream(AM_AV_Device_t *dev)
+{
+	if (dev->mode & AV_PLAY_TS)
+	{
+		if(dev->ts_player.drv_data)
+			return ((AV_TSData_t *)dev->ts_player.drv_data)->fd;
+		else
+			return -1;
+	}
+	else if (dev->mode & AV_INJECT)
+	{
+		AV_InjectData_t *inj = (AV_InjectData_t *)dev->inject_player.drv_data;
+		if (inj->vid_fd != -1)
+			return inj->vid_fd;
+		else
+			return inj->aud_fd;
+	}
+	else if (dev->mode & AV_PLAY_VIDEO_ES)
+	{
+		AV_DataSource_t *src = (AV_DataSource_t *)dev->vid_player.drv_data;
+		return src->fd;
+	}
+	else if (dev->mode & AV_PLAY_AUDIO_ES)
+	{
+		AV_DataSource_t *src = (AV_DataSource_t *)dev->aud_player.drv_data;
+		return src->fd;
+	}
+	// else if (dev->mode & (AV_GET_JPEG_INFO | AV_DECODE_JPEG))
+	// {
+	// 	AV_JPEGData_t *jpeg = (AV_JPEGData_t *)dev->vid_player.drv_data;
+	// 	return jpeg->vbuf_fd;
+	// }
+
+	return -1;
+}
+
+
+#define AUD_ASSO_PROP "media.audio.enable_asso"
+#define AUD_ASSO_MIX_PROP "media.audio.mix_asso"
+#define TIMESHIFT_DBG_PROP "tv.dvb.tf.debug"
+/*mode/enable -1=ignore*/
+#define TSYNC_FORCE_PROP "tv.dvb.tsync.force"
+/*v,a,p -1=ignore*/
+#define PID_FORCE_PROP "tv.dvb.pid.force"
+#define FMT_FORCE_PROP "tv.dvb.fmt.force"
+
+static int _get_prop_int(char *prop, int def) {
+	char v[32];
+	int val = 0;
+#ifdef ANDROID
+//	property_get(prop, v, "0");
+#else
+	strcpy(v, "0");
+#endif
+	if (sscanf(v, "%d", &val) != 1)
+		val = def;
+	return val;
+}
+
+static int _get_prop_int3(char *prop, int *val1, int *val2, int *val3, int def1, int def2, int def3) {
+	char v[32];
+	int v1 = -1, v2 = -1, v3 = -1;
+	int cnt = 0;
+#ifdef ANDROID
+//	property_get(prop, v, "-1,-1,-1");
+#else
+	strcpy(v, "-1,-1,-1");
+#endif
+	cnt = sscanf(v, "%i,%i,%i", &v1, &v2, &v3);
+	if (cnt < 3)
+		v3 = def3;
+	if (cnt < 2)
+		v2 = def2;
+	if (cnt < 1)
+		v1 = def1;
+	if (val1)
+		*val1 = v1;
+	if (val2)
+		*val2 = v2;
+	if (val3)
+		*val3 = v3;
+	return 0;
+}
+
+#define DVB_LOGLEVEL_PROP "tv.dvb.loglevel"
+
+static int _get_asso_enable() {
+#ifdef ANDROID
+//	return property_get_int32(AUD_ASSO_PROP, 0);
+	return 0;
+#else
+	return 0;
+#endif
+}
+static int _get_asso_mix() {
+#ifdef ANDROID
+//	return property_get_int32(AUD_ASSO_MIX_PROP, 50);
+	return 0;
+#else
+	return 0;
+#endif
+}
+static int _get_dvb_loglevel() {
+#ifdef ANDROID
+//	return property_get_int32(DVB_LOGLEVEL_PROP, AM_DEBUG_LOGLEVEL_DEFAULT);
+	return 0;
+#else
+	return 0;//AM_DEBUG_LOGLEVEL_DEFAULT;
+#endif
+}
+static int _get_timethift_dbg() {
+#ifdef ANDROID
+//	return property_get_int32(TIMESHIFT_DBG_PROP, 0);
+	return 0;
+#else
+	return 0;;
+#endif
+}
+static int _get_tsync_mode_force() {
+	int v;
+	_get_prop_int3(TSYNC_FORCE_PROP, &v, NULL, NULL, -1, -1, -1);
+	return v;
+}
+static int _get_tsync_enable_force() {
+	int v;
+	_get_prop_int3(TSYNC_FORCE_PROP, NULL, &v, NULL, -1, -1, -1);
+	return v;
+}
+
+static void setup_forced_pid(AV_TSPlayPara_t *tp)
+{
+	int v, a, p;
+
+	_get_prop_int3(PID_FORCE_PROP, &v, &a, &p, -1, -1, -1);
+
+	if (v != -1) {
+		tp->vpid = v;
+		AM_DEBUG(1, "force vpid: %d", tp->vpid);
+	}
+	if (a != -1) {
+		tp->apid = a;
+		AM_DEBUG(1, "force apid: %d", tp->apid);
+	}
+	if (p != -1) {
+		tp->pcrpid = p;
+		AM_DEBUG(1, "force ppid: %d", tp->pcrpid);
+	}
+
+	_get_prop_int3(FMT_FORCE_PROP, &v, &a, NULL, -1, -1, -1);
+
+	if (v != -1) {
+		tp->vfmt = v;
+		AM_DEBUG(1, "force vfmt: %d", tp->vfmt);
+	}
+	if (a != -1) {
+		tp->afmt = a;
+		AM_DEBUG(1, "force afmt: %d", tp->afmt);
+	}
+}
+
+static AM_ErrorCode_t adec_aout_open_cb(AM_AOUT_Device_t *dev, const AM_AOUT_OpenPara_t *para)
+{
+	return 0;
+}
+static AM_ErrorCode_t adec_aout_set_volume_cb(AM_AOUT_Device_t *dev, int vol)
+{
+	AudioParms audio_parms;
+
+	AM_DEBUG(1, "%s %d", __FUNCTION__,__LINE__);
+
+	memset(&audio_parms,0,sizeof(AudioParms));
+	audio_parms.cmd = ADEC_SET_VOLUME;
+	audio_parms.param1 = vol;
+
+	if (s_audio_cb) {
+	    s_audio_cb(AM_AV_EVT_AUDIO_CB,&audio_parms,pUserData);
+	}
+
+	return 0;
+}
+static AM_ErrorCode_t adec_aout_set_mute_cb(AM_AOUT_Device_t *dev, AM_Bool_t mute)
+{
+	AudioParms audio_parms;
+
+	AM_DEBUG(1, "%s %d", __FUNCTION__,__LINE__);
+
+	memset(&audio_parms,0,sizeof(AudioParms));
+	audio_parms.cmd = ADEC_SET_MUTE;
+	audio_parms.param1 = mute;
+
+	if (s_audio_cb) {
+	    s_audio_cb(AM_AV_EVT_AUDIO_CB,&audio_parms,pUserData);
+	}
+
+	return 0;
+}
+static AM_ErrorCode_t adec_aout_set_output_mode_cb(AM_AOUT_Device_t *dev, AM_AOUT_OutputMode_t mode)
+{
+	AudioParms audio_parms;
+
+	AM_DEBUG(1, "%s %d", __FUNCTION__,__LINE__);
+
+	memset(&audio_parms,0,sizeof(AudioParms));
+	audio_parms.cmd = ADEC_SET_OUTPUT_MODE;
+	audio_parms.param1 = mode;
+
+	if (s_audio_cb) {
+	    s_audio_cb(AM_AV_EVT_AUDIO_CB,&audio_parms,pUserData);
+	}
+	return 0;
+}
+static AM_ErrorCode_t adec_aout_close_cb(AM_AOUT_Device_t *dev)
+{
+	return 0;
+}
+static AM_ErrorCode_t adec_aout_set_pre_gain_cb(AM_AOUT_Device_t *dev, float gain)
+{
+	AudioParms audio_parms;
+
+	AM_DEBUG(1, "%s %d", __FUNCTION__,__LINE__);
+
+	memset(&audio_parms,0,sizeof(AudioParms));
+	audio_parms.cmd = ADEC_SET_PRE_GAIN;
+	audio_parms.param1 = gain*100;
+
+	if (s_audio_cb) {
+	    s_audio_cb(AM_AV_EVT_AUDIO_CB,&audio_parms,pUserData);
+	}
+
+	return 0;
+}
+static AM_ErrorCode_t adec_aout_set_pre_mute_cb(AM_AOUT_Device_t *dev, AM_Bool_t mute)
+{
+	AudioParms audio_parms;
+
+	AM_DEBUG(1, "%s %d", __FUNCTION__,__LINE__);
+
+	memset(&audio_parms,0,sizeof(AudioParms));
+	audio_parms.cmd = ADEC_SET_PRE_MUTE;
+	audio_parms.param1 = mute;
+
+	if (s_audio_cb) {
+	    s_audio_cb(AM_AV_EVT_AUDIO_CB,&audio_parms,pUserData);
+	}
+
+	return 0;
+}
+
+static void adec_start_decode_cb(int fd, int fmt, int has_video, void **padec)
+{
+	AudioParms audio_parms;
+
+	AM_DEBUG(1, "%s %d", __FUNCTION__,__LINE__);
+
+	memset(&audio_parms,0,sizeof(AudioParms));
+	audio_parms.cmd = ADEC_START_DECODE;
+	audio_parms.param1 = fmt;
+	audio_parms.param2 = has_video;
+
+	if (s_audio_cb) {
+	    s_audio_cb(AM_AV_EVT_AUDIO_CB,&audio_parms,pUserData);
+	}
+
+//	AM_AOUT_SetDriver(AOUT_DEV_NO, &adec_aout_drv_cb, NULL);
+
+	// just for compatile with native decoder.
+	*padec = (void *)1;
+	adec_handle = (void *) 1;
+}
+
+static void adec_pause_decode_cb(void *adec)
+{
+	AudioParms audio_parms;
+
+	AM_DEBUG(1, "%s %d", __FUNCTION__,__LINE__);
+
+	if (!adec) {
+		AM_DEBUG(1, "audio closed, ignore");
+		return;
+	}
+
+	memset(&audio_parms,0,sizeof(AudioParms));
+	audio_parms.cmd = ADEC_PAUSE_DECODE;
+
+	if (s_audio_cb) {
+	    s_audio_cb(AM_AV_EVT_AUDIO_CB,&audio_parms,pUserData);
+	}
+}
+static void adec_resume_decode_cb(void *adec)
+{
+	AudioParms audio_parms;
+
+	AM_DEBUG(1, "%s %d", __FUNCTION__,__LINE__);
+
+	if (!adec) {
+		AM_DEBUG(1, "audio closed, ignore");
+		return;
+	}
+
+	memset(&audio_parms,0,sizeof(AudioParms));
+	audio_parms.cmd = ADEC_RESUME_DECODE;
+
+	if (s_audio_cb) {
+	    s_audio_cb(AM_AV_EVT_AUDIO_CB,&audio_parms,pUserData);
+	}
+}
+
+static void adec_stop_decode_cb(void **padec)
+{
+	AudioParms audio_parms;
+
+	AM_DEBUG(1, "%s %d", __FUNCTION__,__LINE__);
+
+	if (!padec || !*padec) {
+		AM_DEBUG(1, "audio closed, ignore");
+		return;
+	}
+
+	memset(&audio_parms,0,sizeof(AudioParms));
+	audio_parms.cmd = ADEC_STOP_DECODE;
+
+	if (s_audio_cb) {
+	    s_audio_cb(AM_AV_EVT_AUDIO_CB,&audio_parms,pUserData);
+	}
+
+	*padec = NULL;
+	adec_handle = NULL;
+	return ;
+}
+static void adec_set_decode_ad_cb(int enable, int pid, int fmt, void *adec)
+{
+	AudioParms audio_parms;
+
+	AM_DEBUG(1, "%s %d pid:%d,fmt:%d\n", __FUNCTION__,__LINE__,pid,fmt);
+
+	if (!adec) {
+		AM_DEBUG(1, "audio closed, ignore");
+		return;
+	}
+
+	memset(&audio_parms,0,sizeof(AudioParms));
+	audio_parms.cmd = ADEC_SET_DECODE_AD;
+	audio_parms.param1 = fmt;
+	audio_parms.param2 = pid;
+
+	if (s_audio_cb) {
+	    s_audio_cb(AM_AV_EVT_AUDIO_CB,&audio_parms,pUserData);
+	}
+	return ;
+}
+static AM_ErrorCode_t adec_set_volume_cb(AM_AOUT_Device_t *dev, int vol)
+{
+	AudioParms audio_parms;
+
+	AM_DEBUG(1, "%s %d", __FUNCTION__,__LINE__);
+
+	memset(&audio_parms,0,sizeof(AudioParms));
+	audio_parms.cmd = ADEC_SET_VOLUME;
+	audio_parms.param1 = vol;
+
+	if (s_audio_cb) {
+	    s_audio_cb(AM_AV_EVT_AUDIO_CB,&audio_parms,pUserData);
+	}
+	return 0;
+}
+static AM_ErrorCode_t adec_set_mute_cb(AM_AOUT_Device_t *dev, AM_Bool_t mute)
+{
+	AudioParms audio_parms;
+
+	AM_DEBUG(1, "%s %d", __FUNCTION__,__LINE__);
+
+	memset(&audio_parms,0,sizeof(AudioParms));
+	audio_parms.cmd = ADEC_SET_MUTE;
+	audio_parms.param1 = mute;
+
+	if (s_audio_cb) {
+	    s_audio_cb(AM_AV_EVT_AUDIO_CB,&audio_parms,pUserData);
+	}
+	return 0;
+}
+static AM_ErrorCode_t adec_set_output_mode_cb(AM_AOUT_Device_t *dev, AM_AOUT_OutputMode_t mode)
+{
+	AudioParms audio_parms;
+
+	AM_DEBUG(1, "%s %d", __FUNCTION__,__LINE__);
+
+	memset(&audio_parms,0,sizeof(AudioParms));
+	audio_parms.cmd = ADEC_SET_OUTPUT_MODE;
+	audio_parms.param1 = mode;
+
+	if (s_audio_cb) {
+	    s_audio_cb(AM_AV_EVT_AUDIO_CB,&audio_parms,pUserData);
+	}
+	return 0;
+}
+static AM_ErrorCode_t adec_set_pre_gain_cb(AM_AOUT_Device_t *dev, float gain)
+{
+	AudioParms audio_parms;
+
+	AM_DEBUG(1, "%s %d", __FUNCTION__,__LINE__);
+
+	memset(&audio_parms,0,sizeof(AudioParms));
+	audio_parms.cmd = ADEC_SET_PRE_GAIN;
+	audio_parms.param1 = gain*100;
+
+	if (s_audio_cb) {
+	    s_audio_cb(AM_AV_EVT_AUDIO_CB,&audio_parms,pUserData);
+	}
+	return 0;
+}
+static AM_ErrorCode_t adec_set_pre_mute_cb(AM_AOUT_Device_t *dev, AM_Bool_t mute)
+{
+	AudioParms audio_parms;
+
+	AM_DEBUG(1, "%s %d", __FUNCTION__,__LINE__);
+
+	memset(&audio_parms,0,sizeof(AudioParms));
+	audio_parms.cmd = ADEC_SET_PRE_MUTE;
+	audio_parms.param1 = mute;
+
+	if (s_audio_cb) {
+	    s_audio_cb(AM_AV_EVT_AUDIO_CB,&audio_parms,pUserData);
+	}
+	return 0;
+}
+static void adec_get_status_cb(void *adec, AM_AV_AudioStatus_t *para)
+{
+	AudioParms audio_parms;
+
+	AM_DEBUG(1, "%s %d", __FUNCTION__,__LINE__);
+
+	if (!adec) {
+		AM_DEBUG(1, "audio closed, ignore");
+		return;
+	}
+
+	memset(&audio_parms,0,sizeof(AudioParms));
+	audio_parms.cmd = ADEC_GET_STATUS;
+
+	if (s_audio_cb) {
+	    s_audio_cb(AM_AV_EVT_AUDIO_CB,&audio_parms,pUserData);
+	}
+	//TBD for get audio para
+}
+#ifdef USE_ADEC_IN_DVB
+static void adec_start_decode(int fd, int fmt, int has_video, void **padec)
+{
+	AM_DEBUG(1, "%s %d", __FUNCTION__,__LINE__);
+
+#if !defined(ADEC_API_NEW)
+		adec_cmd("start");
+#else
+		if (padec) {
+			arm_audio_info param;
+			memset(&param, 0, sizeof(param));
+			param.handle = fd;
+			param.format = fmt;
+			param.has_video = has_video;
+			param.associate_dec_supported = _get_asso_enable();
+			param.mixing_level = _get_asso_mix();
+#ifndef ANDROID
+			param.use_hardabuf = 1; //linux use hardabuf
+#endif
+			audio_decode_init(padec, &param);
+			audio_set_av_sync_threshold(*padec, AV_SYNC_THRESHOLD);
+			audio_decode_set_volume(*padec, 1.);
+			adec_handle = *padec;
+//			AM_AOUT_SetDriver(AOUT_DEV_NO, &adec_aout_drv, *padec);
+		}
+#endif
+}
+static void adec_pause_decode(void *adec)
+{
+	AM_DEBUG(1, "%s %d", __FUNCTION__,__LINE__);
+	audio_decode_pause(adec);
+}
+static void adec_resume_decode(void *adec)
+{
+	AM_DEBUG(1, "%s %d", __FUNCTION__,__LINE__);
+	audio_decode_resume(adec);
+}
+
+static void adec_stop_decode(void **padec)
+{
+	AM_DEBUG(1, "%s %d", __FUNCTION__,__LINE__);
+
+#if !defined(ADEC_API_NEW)
+		adec_cmd("stop");
+#else
+		if (padec && *padec) {
+//			AM_AOUT_SetDriver(AOUT_DEV_NO, NULL, NULL);
+			audio_decode_stop(*padec);
+			audio_decode_release(padec);
+			*padec = NULL;
+			adec_handle = *padec;
+		}
+#endif
+}
+
+static void adec_set_decode_ad(int enable, int pid, int fmt, void *adec)
+{
+#if !defined(ADEC_API_NEW)
+#else
+	UNUSED(pid);
+	UNUSED(fmt);
+
+	if (adec)
+		audio_set_associate_enable(adec, enable);
+#endif
+}
+
+/*音频控制(通过解码器)操作*/
+static AM_ErrorCode_t adec_cmd(const char *cmd)
+{
+#if !defined(ADEC_API_NEW)
+	AM_ErrorCode_t ret;
+	char buf[32];
+	int fd;
+
+	ret = AM_LocalConnect("/tmp/amadec_socket", &fd);
+	if (ret != AM_SUCCESS)
+		return ret;
+
+	ret = AM_LocalSendCmd(fd, cmd);
+
+	if (ret == AM_SUCCESS)
+	{
+		ret = AM_LocalGetResp(fd, buf, sizeof(buf));
+	}
+
+	close(fd);
+
+	return ret;
+#else
+	UNUSED(cmd);
+	return 0;
+#endif
+}
+#endif
+static AM_ErrorCode_t adec_aout_open(AM_AOUT_Device_t *dev, const AM_AOUT_OpenPara_t *para)
+{
+	UNUSED(dev);
+	UNUSED(para);
+	return AM_SUCCESS;
+}
+static AM_ErrorCode_t adec_aout_set_volume(AM_AOUT_Device_t *dev, int vol)
+{
+	return audio_ops->adec_set_volume(dev,vol);
+}
+#ifdef USE_ADEC_IN_DVB
+static AM_ErrorCode_t adec_set_volume(AM_AOUT_Device_t *dev, int vol)
+{
+#ifndef ADEC_API_NEW
+	char buf[32];
+
+	snprintf(buf, sizeof(buf), "volset:%d", vol);
+
+	return adec_cmd(buf);
+#else
+	int ret=0;
+
+	UNUSED(dev);
+
+#ifdef CHIP_8626X
+	ret = audio_decode_set_volume(vol);
+#else
+	ret = audio_decode_set_volume(dev->drv_data, ((float)vol)/100);
+#endif
+	if (ret == -1)
+		return AM_FAILURE;
+	else
+		return AM_SUCCESS;
+#endif
+}
+#endif
+
+static AM_ErrorCode_t adec_aout_set_mute(AM_AOUT_Device_t *dev, AM_Bool_t mute)
+{
+	return audio_ops->adec_set_mute(dev,mute);
+}
+#ifdef USE_ADEC_IN_DVB
+static AM_ErrorCode_t adec_set_mute(AM_AOUT_Device_t *dev, AM_Bool_t mute)
+{
+#ifndef ADEC_API_NEW
+	const char *cmd = mute?"mute":"unmute";
+
+	return adec_cmd(cmd);
+#else
+	int ret=0;
+
+	UNUSED(dev);
+	AM_DEBUG(1, "set_mute %d\n", mute?1:0);
+	ret = audio_decode_set_mute(dev->drv_data, mute?1:0);
+
+	if (ret == -1)
+		return AM_FAILURE;
+	else
+		return AM_SUCCESS;
+#endif
+}
+#endif
+
+static AM_ErrorCode_t adec_aout_set_output_mode(AM_AOUT_Device_t *dev, AM_AOUT_OutputMode_t mode)
+{
+	return audio_ops->adec_set_output_mode(dev,mode);
+}
+#ifdef USE_ADEC_IN_DVB
+static AM_ErrorCode_t adec_set_output_mode(AM_AOUT_Device_t *dev, AM_AOUT_OutputMode_t mode)
+{
+#ifndef ADEC_API_NEW
+
+
+	switch (mode)
+	{
+		case AM_AOUT_OUTPUT_STEREO:
+		default:
+			cmd = "stereo";
+		break;
+		case AM_AOUT_OUTPUT_DUAL_LEFT:
+			cmd = "leftmono";
+		break;
+		case AM_AOUT_OUTPUT_DUAL_RIGHT:
+			cmd = "rightmono";
+		break;
+		case AM_AOUT_OUTPUT_SWAP:
+			cmd = "swap";
+		break;
+	}
+
+	return adec_cmd(cmd);
+#else
+	int ret=0;
+
+	UNUSED(dev);
+
+	switch(mode)
+	{
+		case AM_AOUT_OUTPUT_STEREO:
+		default:
+			ret=audio_channel_stereo(dev->drv_data);
+		break;
+		case AM_AOUT_OUTPUT_DUAL_LEFT:
+			ret=audio_channel_left_mono(dev->drv_data);
+		break;
+		case AM_AOUT_OUTPUT_DUAL_RIGHT:
+			ret=audio_channel_right_mono(dev->drv_data);
+		break;
+		case AM_AOUT_OUTPUT_SWAP:
+			ret=audio_channels_swap(dev->drv_data);
+		break;
+	}
+
+	if(ret==-1)
+		return AM_FAILURE;
+	else
+		return AM_SUCCESS;
+#endif
+}
+#endif
+
+static AM_ErrorCode_t adec_aout_close(AM_AOUT_Device_t *dev)
+{
+	UNUSED(dev);
+	return AM_SUCCESS;
+}
+
+
+static AM_ErrorCode_t adec_aout_set_pre_gain(AM_AOUT_Device_t *dev, float gain)
+{
+	return audio_ops->adec_set_pre_gain(dev,gain);
+}
+
+#ifdef USE_ADEC_IN_DVB
+static AM_ErrorCode_t adec_set_pre_gain(AM_AOUT_Device_t *dev, float gain)
+{
+#ifndef ADEC_API_NEW
+	return AM_FAILURE;
+#else
+	int ret=0;
+
+	UNUSED(dev);
+
+#ifdef CHIP_8626X
+	ret = -1;
+#else
+	AM_DEBUG(1, "set_pre_gain %f\n", gain);
+	ret = audio_decode_set_pre_gain(dev->drv_data, gain);
+#endif
+	if (ret == -1)
+		return AM_FAILURE;
+	else
+		return AM_SUCCESS;
+#endif
+}
+#endif
+static AM_ErrorCode_t adec_aout_set_pre_mute(AM_AOUT_Device_t *dev, AM_Bool_t mute)
+{
+	return audio_ops->adec_set_pre_mute(dev,mute);
+}
+#ifdef USE_ADEC_IN_DVB
+static AM_ErrorCode_t adec_set_pre_mute(AM_AOUT_Device_t *dev, AM_Bool_t mute)
+{
+#ifndef ADEC_API_NEW
+	return AM_FAILURE;
+#else
+	int ret=0;
+
+	UNUSED(dev);
+
+#ifdef CHIP_8626X
+	ret = -1;
+#else
+	AM_DEBUG(1, "set_pre_mute %d\n", mute?1:0);
+	ret = audio_decode_set_pre_mute(dev->drv_data, mute?1:0);
+#endif
+	if (ret == -1)
+		return AM_FAILURE;
+	else
+		return AM_SUCCESS;
+#endif
+}
+
+static void adec_get_status(void *adec, AM_AV_AudioStatus_t *para)
+{
+	int rc;
+	struct adec_status armadec;
+
+	para->lfepresent = -1;
+	para->aud_fmt_orig = -1;
+	para->resolution_orig = -1;
+	para->channels_orig = -1;
+	para->sample_rate_orig = -1;
+	para->lfepresent_orig = -1;
+	rc = audio_decpara_get(adec, &para->sample_rate_orig, &para->channels_orig, &para->lfepresent_orig);
+	if (rc == -1)
+	{
+		AM_DEBUG(1, "cannot get decpara");
+		return ;
+	}
+
+	rc = get_decoder_status(adec, &armadec);
+	if (rc == -1)
+	{
+		AM_DEBUG(1, "cannot get status in this mode");
+		return ;
+	}
+
+	para->channels    = armadec.channels;
+	para->sample_rate = armadec.sample_rate;
+	switch (armadec.resolution)
+	{
+		case 0:
+			para->resolution  = 8;
+			break;
+		case 1:
+			para->resolution  = 16;
+			break;
+		case 2:
+			para->resolution  = 32;
+			break;
+		case 3:
+			para->resolution  = 32;
+			break;
+		case 4:
+			para->resolution  = 64;
+			break;
+		default:
+			para->resolution  = 16;
+			break;
+	}
+
+}
+#endif
+#if 0
+/*音频控制(通过amplayer2)操作*/
+static AM_ErrorCode_t amp_open(AM_AOUT_Device_t *dev, const AM_AOUT_OpenPara_t *para)
+{
+	UNUSED(dev);
+	UNUSED(para);
+	return AM_SUCCESS;
+}
+static AM_ErrorCode_t amp_set_volume(AM_AOUT_Device_t *dev, int vol)
+{
+#ifdef PLAYER_API_NEW
+	int media_id = (long)dev->drv_data;
+
+	if (audio_set_volume(media_id, vol) == -1)
+	{
+		AM_DEBUG(1, "audio_set_volume failed");
+		return AM_AV_ERR_SYS;
+	}
+#endif
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t amp_set_mute(AM_AOUT_Device_t *dev, AM_Bool_t mute)
+{
+#ifdef PLAYER_API_NEW
+	int media_id = (long)dev->drv_data;
+
+	AM_DEBUG(1, "audio_set_mute %d\n", mute);
+	if (audio_set_mute(media_id, mute?0:1) == -1)
+	{
+		AM_DEBUG(1, "audio_set_mute failed");
+		return AM_AV_ERR_SYS;
+	}
+#endif
+	return AM_SUCCESS;
+}
+
+#if !defined(AMLOGIC_LIBPLAYER)
+static int audio_hardware_ctrl( AM_AOUT_OutputMode_t mode)
+{
+    int fd;
+
+    fd = open(AUDIO_CTRL_DEVICE, O_RDONLY);
+    if (fd < 0) {
+        AM_DEBUG(1,"Open Device %s Failed!", AUDIO_CTRL_DEVICE);
+        return -1;
+    }
+
+    switch (mode) {
+    case AM_AOUT_OUTPUT_SWAP:
+        ioctl(fd, AMAUDIO_IOC_SET_CHANNEL_SWAP, 0);
+        break;
+
+    case AM_AOUT_OUTPUT_DUAL_LEFT:
+        ioctl(fd, AMAUDIO_IOC_SET_LEFT_MONO, 0);
+        break;
+
+    case AM_AOUT_OUTPUT_DUAL_RIGHT:
+        ioctl(fd, AMAUDIO_IOC_SET_RIGHT_MONO, 0);
+        break;
+
+    case AM_AOUT_OUTPUT_STEREO:
+        ioctl(fd, AMAUDIO_IOC_SET_STEREO, 0);
+        break;
+
+    default:
+        AM_DEBUG(1,"Unknow mode %d!", mode);
+        break;
+
+    };
+
+    close(fd);
+
+    return 0;
+}
+#endif
+
+static AM_ErrorCode_t amp_set_output_mode(AM_AOUT_Device_t *dev, AM_AOUT_OutputMode_t mode)
+{
+#ifdef PLAYER_API_NEW
+	int media_id = (long)dev->drv_data;
+	int ret=0;
+
+	switch (mode)
+	{
+		case AM_AOUT_OUTPUT_STEREO:
+		default:
+#ifdef AMLOGIC_LIBPLAYER
+                	ret = audio_stereo(media_id);
+#else
+                        ret = audio_hardware_ctrl(mode);
+#endif
+		break;
+		case AM_AOUT_OUTPUT_DUAL_LEFT:
+#ifdef AMLOGIC_LIBPLAYER
+			ret = audio_left_mono(media_id);
+#else
+                        ret = audio_hardware_ctrl(mode);
+#endif
+		break;
+		case AM_AOUT_OUTPUT_DUAL_RIGHT:
+#ifdef AMLOGIC_LIBPLAYER
+			ret = audio_right_mono(media_id);
+#else
+                        ret = audio_hardware_ctrl(mode);
+#endif
+		break;
+		case AM_AOUT_OUTPUT_SWAP:
+#ifdef AMLOGIC_LIBPLAYER
+			ret = audio_swap_left_right(media_id);
+#else
+                        ret = audio_hardware_ctrl(mode);
+#endif
+		break;
+	}
+	if (ret == -1)
+	{
+		AM_DEBUG(1, "audio_set_mode failed");
+		return AM_AV_ERR_SYS;
+	}
+#endif
+
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t amp_close(AM_AOUT_Device_t *dev)
+{
+	UNUSED(dev);
+	return AM_SUCCESS;
+}
+#endif
+
+#if 0
+void afd_evt_callback(long dev_no, int event_type, void *param, void *user_data)
+{
+	UNUSED(user_data);
+
+	if (event_type == AM_USERDATA_EVT_AFD) {
+		AM_USERDATA_AFD_t *afd = (AM_USERDATA_AFD_t *)param;
+		AM_AV_Device_t *dev = (AM_AV_Device_t *)user_data;
+		if (memcmp(afd, &dev->afd, sizeof(*afd))) {
+			dev->afd = *afd;
+			AM_DEBUG(1, "AFD evt: [%02x %01x]", afd->af_flag, afd->af);
+			AM_EVT_Signal(dev->dev_no, AM_AV_EVT_VIDEO_AFD_CHANGED, afd);
+		}
+	}
+}
+
+
+static int aml_start_afd(AM_AV_Device_t *dev, int vfmt)
+{
+	int afd_dev = 0;
+	AM_ErrorCode_t err;
+	AM_USERDATA_OpenPara_t para;
+	int mode;
+
+	memset(&dev->afd, 0, sizeof(dev->afd));
+
+	memset(&para, 0, sizeof(para));
+	para.vfmt = vfmt;
+	para.cc_default_stop = 1;
+
+	err = AM_USERDATA_Open(afd_dev, &para);
+	if (err != AM_SUCCESS) {
+		AM_DEBUG(1, "userdata open fail.");
+		return err;
+	}
+	AM_USERDATA_GetMode(afd_dev, &mode);
+	AM_USERDATA_SetMode(afd_dev, mode | AM_USERDATA_MODE_AFD);
+	AM_EVT_Subscribe(afd_dev, AM_USERDATA_EVT_AFD, afd_evt_callback, dev);
+	AM_DEBUG(1, "AFD started.");
+	return 0;
+}
+
+static int aml_stop_afd(AM_AV_Device_t *dev)
+{
+	int afd_dev = 0;
+	AM_EVT_Unsubscribe(afd_dev, AM_USERDATA_EVT_AFD, afd_evt_callback, dev);
+	AM_USERDATA_Close(afd_dev);
+	memset(&dev->afd, 0, sizeof(dev->afd));
+	AM_DEBUG(1, "AFD stopped.");
+	return 0;
+}
+#endif
+
+
+/**\brief 音视频数据注入线程*/
+static void* aml_data_source_thread(void *arg)
+{
+	AV_DataSource_t *src = (AV_DataSource_t*)arg;
+	struct pollfd pfd;
+	struct timespec ts;
+	int cnt;
+
+	while (src->running)
+	{
+		pthread_mutex_lock(&src->lock);
+
+		if (src->pos  >= 0)
+		{
+			pfd.fd     = src->fd;
+			pfd.events = POLLOUT;
+
+			if (poll(&pfd, 1, 20) == 1)
+			{
+				cnt = src->len-src->pos;
+				cnt = write(src->fd, src->data+src->pos, cnt);
+				if (cnt <= 0)
+				{
+					AM_DEBUG(1, "write data failed");
+				}
+				else
+				{
+					src->pos += cnt;
+				}
+			}
+
+			if (src->pos == src->len)
+			{
+				if (src->times > 0)
+				{
+					src->times--;
+					if (src->times)
+					{
+						src->pos = 0;
+//						AM_EVT_Signal(src->dev_no, src->is_audio?AM_AV_EVT_AUDIO_ES_END:AM_AV_EVT_VIDEO_ES_END, NULL);
+					}
+					else
+					{
+						src->pos = -1;
+					}
+				}
+			}
+
+			AM_TIME_GetTimeSpecTimeout(20, &ts);
+			pthread_cond_timedwait(&src->cond, &src->lock, &ts);
+		}
+		else
+		{
+			pthread_cond_wait(&src->cond, &src->lock);
+		}
+
+		pthread_mutex_unlock(&src->lock);
+
+	}
+
+	return NULL;
+}
+
+/**\brief 创建一个音视频数据注入数据*/
+static AV_DataSource_t* aml_create_data_source(const char *fname, int dev_no, AM_Bool_t is_audio)
+{
+	AV_DataSource_t *src;
+
+	src = (AV_DataSource_t*)malloc(sizeof(AV_DataSource_t));
+	if (!src)
+	{
+		AM_DEBUG(1, "not enough memory");
+		return NULL;
+	}
+
+	memset(src, 0, sizeof(AV_DataSource_t));
+
+	src->fd = open(fname, O_RDWR);
+	if (src->fd == -1)
+	{
+		AM_DEBUG(1, "cannot open file \"%s\"", fname);
+		free(src);
+		return NULL;
+	}
+
+	src->dev_no   = dev_no;
+	src->is_audio = is_audio;
+
+	pthread_mutex_init(&src->lock, NULL);
+	pthread_cond_init(&src->cond, NULL);
+
+	return src;
+}
+
+/**\brief 运行数据注入线程*/
+static AM_ErrorCode_t aml_start_data_source(AV_DataSource_t *src, const uint8_t *data, int len, int times)
+{
+	int ret;
+
+	if (!src->running)
+	{
+		src->running = AM_TRUE;
+		src->data    = data;
+		src->len     = len;
+		src->times   = times;
+		src->pos     = 0;
+
+		ret = pthread_create(&src->thread, NULL, aml_data_source_thread, src);
+		if (ret)
+		{
+			AM_DEBUG(1, "create the thread failed");
+			src->running = AM_FALSE;
+			return AM_AV_ERR_SYS;
+		}
+	}
+	else
+	{
+		pthread_mutex_lock(&src->lock);
+
+		src->data  = data;
+		src->len   = len;
+		src->times = times;
+		src->pos   = 0;
+
+		pthread_mutex_unlock(&src->lock);
+		pthread_cond_signal(&src->cond);
+	}
+
+	return AM_SUCCESS;
+}
+
+/**\brief 释放数据注入数据*/
+static void aml_destroy_data_source(AV_DataSource_t *src)
+{
+	if (src->running)
+	{
+		src->running = AM_FALSE;
+		pthread_cond_signal(&src->cond);
+		pthread_join(src->thread, NULL);
+	}
+
+	close(src->fd);
+	pthread_mutex_destroy(&src->lock);
+	pthread_cond_destroy(&src->cond);
+	free(src);
+}
+
+#ifdef PLAYER_API_NEW
+/**\brief 释放文件播放数据*/
+static void aml_destroy_fp(AV_FilePlayerData_t *fp)
+{
+	/*等待播放器停止*/
+	if (fp->media_id >= 0)
+	{
+		player_exit(fp->media_id);
+	}
+
+	pthread_mutex_destroy(&fp->lock);
+	pthread_cond_destroy(&fp->cond);
+
+	free(fp);
+}
+
+/**\brief 创建文件播放器数据*/
+static AV_FilePlayerData_t* aml_create_fp(AM_AV_Device_t *dev)
+{
+	AV_FilePlayerData_t *fp;
+
+	fp = (AV_FilePlayerData_t*)malloc(sizeof(AV_FilePlayerData_t));
+	if (!fp)
+	{
+		AM_DEBUG(1, "not enough memory");
+		return NULL;
+	}
+
+	if (player_init() < 0)
+	{
+		AM_DEBUG(1, "player_init failed");
+		free(fp);
+		return NULL;
+	}
+
+	memset(fp, 0, sizeof(AV_FilePlayerData_t));
+	pthread_mutex_init(&fp->lock, NULL);
+	pthread_cond_init(&fp->cond, NULL);
+
+	fp->av       = dev;
+	fp->media_id = -1;
+
+	return fp;
+}
+
+static int aml_update_player_info_callback(int pid,player_info_t * info)
+{
+	UNUSED(pid);
+//	if (info)
+//		AM_EVT_Signal(0, AM_AV_EVT_PLAYER_UPDATE_INFO, (void*)info);
+
+	return 0;
+}
+#endif
+
+int aml_set_tsync_enable(int enable)
+{
+	int fd;
+	char  bcmd[16];
+	int f_en = _get_tsync_enable_force();
+
+	if (f_en != -1) {
+		enable = f_en;
+		AM_DEBUG(1, "force tsync enable to %d", enable);
+	}
+
+	snprintf(bcmd,sizeof(bcmd),"%d",enable);
+
+	return AM_FileEcho(TSYNC_ENABLE_FILE, bcmd);
+
+	// fd=open(path, O_CREAT|O_RDWR | O_TRUNC, 0644);
+	// if(fd>=0)
+	// {
+	// 	snprintf(bcmd,sizeof(bcmd),"%d",enable);
+	// 	write(fd,bcmd,strlen(bcmd));
+	// 	close(fd);
+	// 	return 0;
+	// }
+
+	// return -1;
+}
+
+/**\brief 初始化JPEG解码器*/
+static AM_ErrorCode_t aml_init_jpeg(AV_JPEGData_t *jpeg)
+{
+// 	if (jpeg->dec_fd != -1)
+// 	{
+// 		close(jpeg->dec_fd);
+// 		jpeg->dec_fd = -1;
+// 	}
+
+// 	if (jpeg->vbuf_fd != -1)
+// 	{
+// 		close(jpeg->vbuf_fd);
+// 		jpeg->vbuf_fd = -1;
+// 	}
+
+// 	jpeg->vbuf_fd = open(STREAM_VBUF_FILE, O_RDWR|O_NONBLOCK);
+// 	if (jpeg->vbuf_fd == -1)
+// 	{
+// 		AM_DEBUG(1, "cannot open amstream_vbuf");
+// 		goto error;
+// 	}
+
+// 	if (ioctl(jpeg->vbuf_fd, AMSTREAM_IOC_VFORMAT, VFORMAT_JPEG) == -1)
+// 	{
+// 		AM_DEBUG(1, "set jpeg video format failed (\"%s\")", strerror(errno));
+// 		goto error;
+// 	}
+
+// 	if (ioctl(jpeg->vbuf_fd, AMSTREAM_IOC_PORT_INIT) == -1)
+// 	{
+// 		AM_DEBUG(1, "amstream init failed (\"%s\")", strerror(errno));
+// 		goto error;
+// 	}
+
+// 	return AM_SUCCESS;
+// error:
+// 	if (jpeg->dec_fd != -1)
+// 	{
+// 		close(jpeg->dec_fd);
+// 		jpeg->dec_fd = -1;
+// 	}
+// 	if (jpeg->vbuf_fd != -1)
+// 	{
+// 		close(jpeg->vbuf_fd);
+// 		jpeg->vbuf_fd = -1;
+// 	}
+	return AM_AV_ERR_SYS;
+}
+
+/**\brief 创建JPEG解码相关数据*/
+static AV_JPEGData_t* aml_create_jpeg_data(void)
+{
+	// AV_JPEGData_t *jpeg;
+
+	// jpeg = malloc(sizeof(AV_JPEGData_t));
+	// if (!jpeg)
+	// {
+	// 	AM_DEBUG(1, "not enough memory");
+	// 	return NULL;
+	// }
+
+	// jpeg->vbuf_fd = -1;
+	// jpeg->dec_fd  = -1;
+
+	// if (aml_init_jpeg(jpeg) != AM_SUCCESS)
+	// {
+	// 	free(jpeg);
+	// 	return NULL;
+	// }
+
+	return NULL;
+}
+
+/**\brief 释放JPEG解码相关数据*/
+static void aml_destroy_jpeg_data(AV_JPEGData_t *jpeg)
+{
+	// if (jpeg->dec_fd != -1)
+	// 	close(jpeg->dec_fd);
+	// if (jpeg->vbuf_fd != -1)
+	// 	close(jpeg->vbuf_fd);
+
+	// free(jpeg);
+}
+
+/**\brief 创建数据注入相关数据*/
+static AV_InjectData_t* aml_create_inject_data(void)
+{
+	AV_InjectData_t *inj;
+
+	inj = (AV_InjectData_t *)malloc(sizeof(AV_InjectData_t));
+	if (!inj)
+		return NULL;
+
+	inj->aud_fd = -1;
+	inj->vid_fd = -1;
+	inj->aud_id = -1;
+	inj->vid_id = -1;
+	inj->cntl_fd = -1;
+	inj->adec = NULL;
+	inj->ad = NULL;
+
+	return inj;
+}
+
+/**\brief 设置数据注入参赛*/
+static AM_ErrorCode_t aml_start_inject(AM_AV_Device_t *dev, AV_InjectData_t *inj, AV_InjectPlayPara_t *inj_para)
+{
+	int vfd=-1, afd=-1;
+	AM_AV_InjectPara_t *para = &inj_para->para;
+	AM_Bool_t has_video = VALID_VIDEO(para->vid_id, para->vid_fmt);
+	AM_Bool_t has_audio = VALID_AUDIO(para->aud_id, para->aud_fmt);
+	char vdec_info[256];
+	int double_write_mode = 3;
+
+	if (para->aud_id != dev->alt_apid || para->aud_fmt != dev->alt_afmt) {
+		AM_DEBUG(1, "switch to pending audio: A[%d:%d] -> A[%d:%d]",
+			para->aud_id, para->aud_fmt, dev->alt_apid, dev->alt_afmt);
+		para->aud_id = dev->alt_apid;
+		para->aud_fmt = dev->alt_afmt;
+
+		has_audio = VALID_AUDIO(para->aud_id, para->aud_fmt);
+	}
+
+	inj->pkg_fmt = para->pkg_fmt;
+
+	switch (para->pkg_fmt)
+	{
+		case PFORMAT_ES:
+			if (has_video)
+			{
+				vfd = open(STREAM_VBUF_FILE, O_RDWR);
+				if (vfd == -1)
+				{
+					AM_DEBUG(1, "cannot open device \"%s\"", STREAM_VBUF_FILE);
+					return AM_AV_ERR_CANNOT_OPEN_FILE;
+				}
+				inj->vid_fd = vfd;
+			}
+			if (has_audio)
+			{
+				afd = open(STREAM_ABUF_FILE, O_RDWR);
+				if (afd == -1)
+				{
+					AM_DEBUG(1, "cannot open device \"%s\"", STREAM_ABUF_FILE);
+					return AM_AV_ERR_CANNOT_OPEN_FILE;
+				}
+				inj->aud_fd = afd;
+			}
+		break;
+		case PFORMAT_PS:
+			vfd = open(STREAM_PS_FILE, O_RDWR);
+			if (vfd == -1)
+			{
+				AM_DEBUG(1, "cannot open device \"%s\"", STREAM_PS_FILE);
+				return AM_AV_ERR_CANNOT_OPEN_FILE;
+			}
+			inj->vid_fd = afd = vfd;
+		break;
+		case PFORMAT_TS:
+			if (check_vfmt_support_sched(para->vid_fmt) == AM_FALSE)
+			{
+				vfd = open(STREAM_TS_FILE, O_RDWR);
+				if (vfd == -1)
+				{
+					AM_DEBUG(1, "cannot open device \"%s\"", STREAM_TS_FILE);
+					return AM_AV_ERR_CANNOT_OPEN_FILE;
+				}
+			}
+			else
+			{
+				vfd = open(STREAM_TS_SCHED_FILE, O_RDWR);
+				if (vfd == -1)
+				{
+					AM_DEBUG(1, "cannot open device \"%s\"", STREAM_TS_SCHED_FILE);
+					return AM_AV_ERR_CANNOT_OPEN_FILE;
+				}
+			}
+			if (inj_para->drm_mode == AM_AV_DRM_WITH_SECURE_INPUT_BUFFER)
+			{
+				if (ioctl(vfd, AMSTREAM_IOC_SET_DRMMODE, (void *)(long)inj_para->drm_mode) == -1)
+				{
+					AM_DEBUG(1, "set drm_mode with secure buffer failed\n");
+					return AM_AV_ERR_SYS;
+				}
+			}
+			if (inj_para->drm_mode == AM_AV_DRM_WITH_NORMAL_INPUT_BUFFER)
+			{
+				if (ioctl(vfd, AMSTREAM_IOC_SET_DRMMODE, (void *)(long)inj_para->drm_mode) == -1)
+				{
+					AM_DEBUG(1, "set drm_mode with normal buffer failed\n");
+					return AM_AV_ERR_SYS;
+				}
+			}
+			inj->vid_fd = afd = vfd;
+		break;
+		case PFORMAT_REAL:
+			vfd = open(STREAM_RM_FILE, O_RDWR);
+			if (vfd == -1)
+			{
+				AM_DEBUG(1, "cannot open device \"%s\"", STREAM_RM_FILE);
+				return AM_AV_ERR_CANNOT_OPEN_FILE;
+			}
+			inj->vid_fd = afd = vfd;
+		break;
+		default:
+			AM_DEBUG(1, "unknown package format %d", para->pkg_fmt);
+		return AM_AV_ERR_NOT_SUPPORTED;
+	}
+
+	if (has_video)
+	{
+		dec_sysinfo_t am_sysinfo;
+
+		if (ioctl(vfd, AMSTREAM_IOC_VFORMAT, para->vid_fmt) == -1)
+		{
+			AM_DEBUG(1, "set video format failed");
+			return AM_AV_ERR_SYS;
+		}
+		if (ioctl(vfd, AMSTREAM_IOC_VID, para->vid_id) == -1)
+		{
+			AM_DEBUG(1, "set video PID failed");
+			return AM_AV_ERR_SYS;
+		}
+
+		memset(&am_sysinfo,0,sizeof(dec_sysinfo_t));
+		if (para->vid_fmt == VFORMAT_VC1)
+		{
+			am_sysinfo.format = VIDEO_DEC_FORMAT_WVC1;
+			am_sysinfo.width  = 1920;
+			am_sysinfo.height = 1080;
+		}
+		else if (para->vid_fmt == VFORMAT_H264)
+		{
+			am_sysinfo.format = VIDEO_DEC_FORMAT_H264;
+			am_sysinfo.width  = 1920;
+			am_sysinfo.height = 1080;
+		}
+		else if (para->vid_fmt == VFORMAT_AVS)
+		{
+			am_sysinfo.format = VIDEO_DEC_FORMAT_AVS;
+			/*am_sysinfo.width  = 1920;
+			am_sysinfo.height = 1080;*/
+		}
+		else if (para->vid_fmt == VFORMAT_HEVC)
+		{
+			am_sysinfo.format = VIDEO_DEC_FORMAT_HEVC;
+			am_sysinfo.width  = 3840;
+			am_sysinfo.height = 2160;
+		}
+
+		if (ioctl(vfd, AMSTREAM_IOC_SYSINFO, (unsigned long)&am_sysinfo) == -1)
+		{
+			AM_DEBUG(1, "set AMSTREAM_IOC_SYSINFO");
+			return AM_AV_ERR_SYS;
+		}
+		/*configure double wirte mode*/
+		memset(vdec_info, 0, sizeof(vdec_info));
+		if (para->vid_fmt == VFORMAT_HEVC) {
+			sprintf(vdec_info, "hevc_double_write_mode:%d", double_write_mode);
+			configure_vdec_info(vfd, vdec_info, strlen(vdec_info));
+		} else if (para->vid_fmt == VFORMAT_VP9) {
+			sprintf(vdec_info, "vp9_double_write_mode:%d", double_write_mode);
+			configure_vdec_info(vfd, vdec_info, strlen(vdec_info));
+		}
+
+	}
+
+	if (has_audio)
+	{
+		if (ioctl(afd, AMSTREAM_IOC_AFORMAT, para->aud_fmt) == -1)
+		{
+			AM_DEBUG(1, "set audio format failed");
+			return AM_AV_ERR_SYS;
+		}
+		if (ioctl(afd, AMSTREAM_IOC_AID, para->aud_id) == -1)
+		{
+			AM_DEBUG(1, "set audio PID failed");
+			return AM_AV_ERR_SYS;
+		}
+		if ((para->aud_fmt == AFORMAT_PCM_S16LE) || (para->aud_fmt == AFORMAT_PCM_S16BE) ||
+				(para->aud_fmt == AFORMAT_PCM_U8)) {
+			ioctl(afd, AMSTREAM_IOC_ACHANNEL, para->channel);
+			ioctl(afd, AMSTREAM_IOC_SAMPLERATE, para->sample_rate);
+			ioctl(afd, AMSTREAM_IOC_DATAWIDTH, para->data_width);
+		}
+	}
+
+	if (para->sub_id && (para->sub_id<0x1fff))
+	{
+		if (ioctl(vfd, AMSTREAM_IOC_SID, para->sub_id) == -1)
+		{
+			AM_DEBUG(1, "set subtitle PID failed");
+			return AM_AV_ERR_SYS;
+		}
+
+		if (ioctl(vfd, AMSTREAM_IOC_SUB_TYPE, para->sub_type) == -1)
+		{
+			AM_DEBUG(1, "set subtitle type failed");
+			return AM_AV_ERR_SYS;
+		}
+	}
+
+	if (vfd != -1)
+	{
+		if (ioctl(vfd, AMSTREAM_IOC_PORT_INIT, 0) == -1)
+		{
+			AM_DEBUG(1, "amport init failed");
+			return AM_AV_ERR_SYS;
+		}
+
+		inj->cntl_fd = open(AMVIDEO_FILE, O_RDWR);
+		if (inj->cntl_fd == -1)
+		{
+			AM_DEBUG(1, "cannot open \"%s\"", AMVIDEO_FILE);
+			return AM_AV_ERR_CANNOT_OPEN_FILE;
+		}
+		ioctl(inj->cntl_fd, AMSTREAM_IOC_TRICKMODE, TRICKMODE_NONE);
+	}
+
+	if ((afd != -1) && (afd != vfd))
+	{
+		if (ioctl(afd, AMSTREAM_IOC_PORT_INIT, 0) == -1)
+		{
+			AM_DEBUG(1, "amport init failed");
+			return AM_AV_ERR_SYS;
+		}
+	}
+
+	if ((para->pkg_fmt == PFORMAT_ES) && ((afd != -1) || (vfd != -1))) {
+		if ((vfd == -1) && (afd != -1)) {
+			if (ioctl(afd, AMSTREAM_IOC_TSTAMP, 0) == -1)
+				AM_DEBUG(1, "checkin first apts failed [%s]", strerror(errno));
+		}
+	}
+
+#if defined(ANDROID) || defined(CHIP_8626X)
+	if (has_video && has_audio)
+		aml_set_tsync_enable(1);
+	else
+		aml_set_tsync_enable(0);
+#endif
+
+	aml_set_sync_mode(dev,
+		aml_calc_sync_mode(dev, has_audio, has_video, 0, para->aud_fmt, NULL));
+
+
+	if (has_audio)
+	{
+		audio_ops->adec_start_decode(afd, para->aud_fmt, has_video, &inj->adec);
+	}
+
+	inj->aud_fmt  = para->aud_fmt;
+	inj->vid_fmt  = para->vid_fmt;
+	inj->sub_type = para->sub_type;
+	inj->aud_id   = para->aud_id;
+	inj->vid_id   = para->vid_id;
+	inj->sub_id   = para->sub_id;
+
+	return AM_SUCCESS;
+}
+
+/**\brief 释放数据注入相关数据*/
+static void aml_destroy_inject_data(AV_InjectData_t *inj)
+{
+	if (inj->aud_id != -1) {
+		aml_set_ad_source(&inj->ad, 0, 0, 0, inj->adec);
+		audio_ops->adec_set_decode_ad(0, 0, 0, inj->adec);
+		audio_ops->adec_stop_decode(&inj->adec);
+	}
+	if (inj->aud_fd != -1)
+		close(inj->aud_fd);
+	if (inj->vid_fd != -1)
+		close(inj->vid_fd);
+	if (inj->cntl_fd != -1) {
+		ioctl(inj->cntl_fd, AMSTREAM_IOC_VPAUSE, 0);
+		close(inj->cntl_fd);
+	}
+	free(inj);
+}
+void aml_term_signal_handler(int signo)
+{
+	AM_DEBUG(1,"PVR_DEBUG recive a signal:%d", signo);
+	if (signo == SIGTERM)
+	{
+		AM_DEBUG(1,"PVR_DEBUG recive SIGTERM");
+		if (m_tshift == NULL)
+			return;
+		AM_TFile_t tfile = m_tshift->file;
+		struct stat tfile_stat;
+
+		if (tfile) {
+			if (tfile->opened == 1)
+			{
+				AM_DEBUG(1, "PVR_DEBUG in timeshift mode, fd:%d ,fname:%s", tfile->sub_files->rfd, tfile->name);
+			} else {
+				AM_DEBUG(1, "PVR_DEBUG timeshift file was not open");
+			}
+		}
+		else
+		{
+			AM_DEBUG(1, "PVR_DEBUG tfile is NULL");
+		}
+	}
+}
+
+static char *cmd2string(int cmd)
+{
+	char buf[64];
+	char *string_cmd[] = {
+	"play_start",        /*AV_PLAY_START*/
+	"play_pause",        /*AV_PLAY_PAUSE*/
+	"play_resume",       /*AV_PLAY_RESUME*/
+	"play_ff",           /*AV_PLAY_FF*/
+	"play_fb",           /*AV_PLAY_FB*/
+	"play_seek",         /*AV_PLAY_SEEK*/
+	"play_reset_vpath",  /*AV_PLAY_RESET_VPATH*/
+	"play_switch_audio"  /*AV_PLAY_SWITCH_AUDIO*/
+	};
+	if (cmd < 0 || cmd > AV_PLAY_SWITCH_AUDIO) {
+		sprintf(buf, "invalid cmd[%d]", cmd);
+		return buf;
+	}
+	return string_cmd[cmd];
+}
+
+
+QUEUE_DEFINITION(timeshift_cmd_q, AV_PlayCmdPara_t);
+
+static void timeshift_cmd_init(AV_PlayCmdPara_t *cmd, int c)
+{
+	cmd->cmd = c;
+	cmd->done = 0;
+}
+static int timeshift_cmd_diff(AV_PlayCmdPara_t *cmd1, AV_PlayCmdPara_t *cmd2)
+{
+	if (cmd1->cmd != cmd2->cmd)
+		return 1;
+	else if ((cmd1->cmd == AV_PLAY_FF) || (cmd1->cmd == AV_PLAY_FB))
+		return (cmd1->speed.speed != cmd2->speed.speed) ? 1 : 0;
+	else if (cmd1->cmd == AV_PLAY_SEEK)
+		return (cmd1->seek.seek_pos != cmd2->seek.seek_pos) ? 1 : 0;
+	return 0;
+}
+static int timeshift_cmd_put(AV_TimeshiftData_t *tshift, AV_PlayCmdPara_t *cmd)
+{
+	AV_PlayCmdPara_t last;
+	enum enqueue_result e_ret;
+	enum dequeue_result d_ret = timeshift_cmd_q_dequeue(&tshift->cmd_q, &last);
+
+	if (d_ret == DEQUEUE_RESULT_EMPTY)
+		e_ret = timeshift_cmd_q_enqueue(&tshift->cmd_q, cmd);
+	else if (last.cmd == cmd->cmd) {
+		e_ret = timeshift_cmd_q_enqueue(&tshift->cmd_q, cmd);
+	} else {
+		e_ret = timeshift_cmd_q_enqueue(&tshift->cmd_q, &last);
+		e_ret |= timeshift_cmd_q_enqueue(&tshift->cmd_q, cmd);
+	}
+	if (e_ret != ENQUEUE_RESULT_SUCCESS) {
+		AM_DEBUG(1, "[timeshift] warning: cmd lost, max:%d", TIMESHIFT_CMD_Q_SIZE);
+		return -1;
+	}
+	return 0;
+}
+static int timeshift_cmd_get(AV_TimeshiftData_t *tshift, AV_PlayCmdPara_t *cmd)
+{
+	if (timeshift_cmd_q_is_empty(&tshift->cmd_q))
+		return -1;
+	if (timeshift_cmd_q_dequeue(&tshift->cmd_q, cmd) != DEQUEUE_RESULT_SUCCESS)
+		return -1;
+	return 0;
+}
+static int timeshift_cmd_more(AV_TimeshiftData_t *tshift)
+{
+	return !timeshift_cmd_q_is_empty(&tshift->cmd_q);
+}
+
+/**\brief 创建Timeshift相关数据*/
+static AV_TimeshiftData_t* aml_create_timeshift_data(void)
+{
+	AV_TimeshiftData_t *tshift;
+
+	tshift = (AV_TimeshiftData_t *)malloc(sizeof(AV_TimeshiftData_t));
+	if (!tshift)
+		return NULL;
+
+	memset(tshift, 0, sizeof(AV_TimeshiftData_t));
+	tshift->ts.fd = -1;
+	tshift->ts.vid_fd = -1;
+	timeshift_cmd_q_init(&tshift->cmd_q);
+#ifdef SUPPORT_CAS
+	tshift->buf = malloc(SECURE_BLOCK_SIZE);
+	if (!tshift->buf) {
+		AM_DEBUG(0, "alloc timeshihft buffer failed");
+		free(tshift);
+		return NULL;
+	}
+#endif
+
+	return tshift;
+}
+
+static int aml_timeshift_inject(AV_TimeshiftData_t *tshift, uint8_t *data, int size, int timeout)
+{
+	int ret;
+	int real_written = 0;
+	int fd = tshift->ts.fd;
+
+	if (timeout >= 0)
+	{
+		struct pollfd pfd;
+
+		pfd.fd = fd;
+		pfd.events = POLLOUT;
+
+		ret = poll(&pfd, 1, timeout);
+		if (ret != 1)
+		{
+			AM_DEBUG(1, "timeshift poll timeout");
+			goto inject_end;
+		}
+	}
+
+	if (size && fd > 0)
+	{
+		ret = write(fd, data, size);
+		if ((ret == -1) && (errno != EAGAIN))
+		{
+			AM_DEBUG(1, "inject data failed errno:%d msg:%s", errno, strerror(errno));
+			goto inject_end;
+		}
+		else if ((ret == -1) && (errno == EAGAIN))
+		{
+			AM_DEBUG(1, "ret=%d,inject data failed errno:%d msg:%s",ret, errno, strerror(errno));
+			real_written = 0;
+		}
+		else if (ret >= 0)
+		{
+			real_written = ret;
+		}
+	}
+
+inject_end:
+	return real_written;
+}
+
+static int aml_timeshift_get_trick_stat(AV_TimeshiftData_t *tshift)
+{
+	int state;
+
+	if (tshift->ts.vid_fd == -1)
+		return -1;
+
+	ioctl(tshift->ts.vid_fd, AMSTREAM_IOC_TRICK_STAT, (unsigned long)&state);
+
+	return state;
+}
+
+void tfile_evt_callback ( long dev_no, int event_type, void *param, void *user_data )
+{
+	if (event_type == AM_TFILE_EVT_RATE_CHANGED) {
+		AM_DEBUG(1, "tfile evt: rate[%dBps]", (int)param);
+		AV_TimeshiftData_t *tshift = (AV_TimeshiftData_t *)(((AM_AV_Device_t*)user_data)->timeshift_player.drv_data);
+		tshift->rate = (int)param;
+		pthread_cond_signal(&tshift->cond);
+	}
+}
+
+static int aml_av_get_delay(int fd, int video_not_audio)
+{
+	int d = 0;
+
+	if (ioctl(fd, (video_not_audio)?
+			AMSTREAM_IOC_GET_VIDEO_CUR_DELAY_MS:
+			AMSTREAM_IOC_GET_AUDIO_CUR_DELAY_MS,
+			&d) != -1)
+		return ((d > (30 * 1000)) || (d < (1 * 1000))) ? 0 : d;
+
+	return 0;
+}
+
+static int aml_timeshift_get_delay(AV_TimeshiftData_t *tshift)
+{
+	AM_Bool_t has_video = VALID_VIDEO(tshift->tp.vpid, tshift->tp.vfmt);
+
+	return aml_av_get_delay(tshift->ts.fd, has_video);
+}
+
+static void aml_timeshift_get_current(AV_TimeshiftData_t *tshift, int *current, int *start, int *end)
+{
+	int timeshift = (tshift->para.para.mode == AM_AV_TIMESHIFT_MODE_TIMESHIFTING)? 1 : 0;
+
+	if (current)
+		*current = (timeshift)?
+			AM_TFile_TimeGetReadNow(tshift->file)
+			: (tshift->rate ? AM_TFile_Tell(tshift->file) * 1000 / tshift->rate : 0);
+	if (start)
+		*start = (timeshift)? AM_TFile_TimeGetStart(tshift->file) : 0;
+	if (end)
+		*end = (timeshift)? AM_TFile_TimeGetEnd(tshift->file) : tshift->duration;
+}
+
+/*track current status internally*/
+static void aml_timeshift_update_current(AV_TimeshiftData_t *tshift)
+{
+	aml_timeshift_get_current(tshift, &tshift->current, &tshift->start, &tshift->end);
+	AM_DEBUG(5, "[timeshift] update: state[%d] start[%d] current[%d] end[%d]", tshift->state, tshift->start, tshift->current, tshift->end);
+}
+
+/*update from internal status*/
+static void aml_timeshift_update(AV_TimeshiftData_t *tshift, AM_AV_TimeshiftInfo_t *info)
+{
+	info->current_time = tshift->current;
+	info->full_time = tshift->end;
+	info->status = tshift->state;
+}
+
+/*notification current status*/
+static void aml_timeshift_notify(AV_TimeshiftData_t *tshift, AM_AV_TimeshiftInfo_t *info, AM_Bool_t calc_delay)
+{
+	AM_AV_TimeshiftInfo_t inf;
+	AM_Bool_t has_video = VALID_VIDEO(tshift->tp.vpid, tshift->tp.vfmt);
+	int delay = 0;
+
+	if (!info) {
+		info = &inf;
+		aml_timeshift_update(tshift, info);
+	}
+
+	delay = aml_timeshift_get_delay(tshift);
+
+	if (calc_delay)
+		info->current_time -= delay;
+
+	if (info->current_time < 0)
+		info->current_time = 10;
+
+	AM_DEBUG(1, "[timeshift] notify: status[%d] current[%d] full[%d] -delay[%d]",
+		info->status, info->current_time, info->full_time, delay);
+
+//	AM_EVT_Signal(0, AM_AV_EVT_PLAYER_UPDATE_INFO, (void*)info);
+	aml_timeshift_update_info(tshift, info);
+}
+
+/**\brief 设置Timeshift参数*/
+static AM_ErrorCode_t aml_start_timeshift(AV_TimeshiftData_t *tshift, AV_TimeShiftPlayPara_t *tshift_para, AM_Bool_t create_thread, AM_Bool_t start_audio)
+{
+	char buf[64];
+	AM_AV_TimeshiftPara_t *para = &tshift_para->para;
+	AV_TSData_t *ts = &tshift->ts;
+	AV_TSPlayPara_t *tp = &tshift->tp;
+	AM_AV_Device_t *dev = tshift->dev;
+	int val;
+	int sync_mode, sync_force;
+	char vdec_info[256];
+	int double_write_mode = 3;
+
+	AM_Bool_t has_video = VALID_VIDEO(tp->vpid, tp->vfmt);
+	AM_Bool_t has_audio = VALID_AUDIO(tp->apid, tp->afmt);
+
+	if (tp->apid != dev->alt_apid || tp->afmt != dev->alt_afmt) {
+		AM_DEBUG(1, "switch to pending audio: A[%d:%d] -> A[%d:%d]",
+			tp->apid, tp->afmt, dev->alt_apid, dev->alt_afmt);
+		tp->apid = dev->alt_apid;
+		tp->afmt = dev->alt_afmt;
+
+		has_audio = VALID_AUDIO(tp->apid, tp->afmt);
+	}
+
+	AM_DEBUG(1, "aml start timeshift: V[%d:%d] A[%d:%d]", tp->vpid, tp->vfmt, tp->apid, tp->afmt);
+
+	if (create_thread)//check sth critical 1st.
+	{
+		AM_Bool_t loop = AM_TRUE;
+		if (para->mode == AM_AV_TIMESHIFT_MODE_PLAYBACK)
+			loop = AM_FALSE;
+		if (tshift_para->para.tfile && tshift_para->para.tfile->loop != loop) {
+			AM_DEBUG(1, "FATAL: [timeshift]: playmode[%d] != filemode[%d]",
+				para->mode,
+				tshift_para->para.tfile->is_timeshift? AM_AV_TIMESHIFT_MODE_TIMESHIFTING : AM_AV_TIMESHIFT_MODE_PLAYBACK);
+			AM_DEBUG(1, "[timeshift] tmode:%d fmode:%d tdur:%d floop:%d",
+				para->mode, tshift_para->para.tfile->is_timeshift, para->media_info.duration, tshift_para->para.tfile->loop);
+			return AM_AV_ERR_ILLEGAL_OP;
+		}
+	}
+
+	/*patch dec control*/
+	set_dec_control(has_video);
+
+	AM_DEBUG(1, "Openning demux%d",para->dmx_id);
+	snprintf(buf, sizeof(buf), "/dev/dvb0.demux%d", para->dmx_id);
+	tshift->dmxfd = open(buf, O_RDWR);
+	if (tshift->dmxfd == -1)
+	{
+		AM_DEBUG(1, "cannot open \"/dev/dvb0.demux%d\" error:%d \"%s\"", para->dmx_id, errno, strerror(errno));
+		return AM_AV_ERR_CANNOT_OPEN_DEV;
+	}
+
+	AM_FileRead(DVB_STB_SOURCE_FILE, tshift->last_stb_src, 16);
+	snprintf(buf, sizeof(buf), "dmx%d", para->dmx_id);
+	AM_FileEcho(DVB_STB_SOURCE_FILE, buf);
+
+	snprintf(buf, sizeof(buf), DVB_STB_DEMUXSOURCE_FILE, para->dmx_id);
+	AM_FileRead(buf, tshift->last_dmx_src, 16);
+	AM_FileEcho(buf, "hiu");
+#ifdef SUPPORT_CAS
+        if (para->secure_enable)
+                snprintf(buf, sizeof(buf), "%d", 256*1024);
+        else
+#endif
+	snprintf(buf, sizeof(buf), "%d", 32*1024);
+	AM_FileEcho(DVB_STB_ASYNCFIFO_FLUSHSIZE_FILE, buf);
+
+	if (check_vfmt_support_sched(tp->vfmt) == AM_FALSE)
+	{
+		AM_DEBUG(1, "Openning mpts");
+		ts->fd = open(STREAM_TS_FILE, O_RDWR);
+		if (ts->fd == -1)
+		{
+			AM_DEBUG(1, "cannot open device \"%s\"", STREAM_TS_FILE);
+			return AM_AV_ERR_CANNOT_OPEN_FILE;
+		}
+	}
+	else
+	{
+		AM_DEBUG(1, "Openning mpts_sched");
+		ts->fd = open(STREAM_TS_SCHED_FILE, O_RDWR);
+		if (ts->fd == -1)
+		{
+			AM_DEBUG(1, "cannot open device \"%s\"", STREAM_TS_SCHED_FILE);
+			return AM_AV_ERR_CANNOT_OPEN_FILE;
+		}
+	}
+
+	if (has_video) {
+		AM_DEBUG(1, "Openning video");
+		ts->vid_fd = open(AMVIDEO_FILE, O_RDWR);
+		if (ts->vid_fd == -1)
+		{
+			AM_DEBUG(1, "cannot create data source \"/dev/amvideo\"");
+			return AM_AV_ERR_CANNOT_OPEN_DEV;
+		}
+	}
+#ifdef USE_AMSTREAM_SUB_BUFFER
+	AM_DEBUG(1, "try to init subtitle ring buf");
+	int sid = 0xffff;
+	if (ioctl(ts->fd, AMSTREAM_IOC_SID, sid) == -1)
+	{
+		AM_DEBUG(1, "set sub PID failed");
+	}
+#endif
+#if defined(ANDROID) || defined(CHIP_8626X)
+	/*Set tsync enable/disable*/
+	if (has_video && (has_audio && start_audio))
+	{
+		AM_DEBUG(1, "Set tsync enable to 1");
+		aml_set_tsync_enable(1);
+	}
+	else
+	{
+		AM_DEBUG(1, "Set tsync enable to 0");
+		aml_set_tsync_enable(0);
+	}
+#endif
+
+	AM_DEBUG(1, "Setting play param");
+	if (has_video) {
+		val = tp->vfmt;
+		if (ioctl(ts->fd, AMSTREAM_IOC_VFORMAT, val) == -1)
+		{
+			AM_DEBUG(1, "set video format failed");
+			return AM_AV_ERR_SYS;
+		}
+		val = tp->vpid;
+		if (ioctl(ts->fd, AMSTREAM_IOC_VID, val) == -1)
+		{
+			AM_DEBUG(1, "set video PID failed");
+			return AM_AV_ERR_SYS;
+		}
+#if 0		
+		if (dev->afd_enable) {
+			AM_DEBUG(1, "start afd...");
+			aml_start_afd(dev, tp->vfmt);
+		}
+#endif		
+	}
+
+	/*if ((tp->vfmt == VFORMAT_H264) || (tp->vfmt == VFORMAT_VC1))*/
+	if (has_video) {
+		memset(&am_sysinfo,0,sizeof(dec_sysinfo_t));
+		if (tp->vfmt == VFORMAT_VC1)
+		{
+			am_sysinfo.format = VIDEO_DEC_FORMAT_WVC1;
+			am_sysinfo.width  = 1920;
+			am_sysinfo.height = 1080;
+		}
+		else if (tp->vfmt == VFORMAT_H264)
+		{
+			am_sysinfo.format = VIDEO_DEC_FORMAT_H264;
+			am_sysinfo.width  = 1920;
+			am_sysinfo.height = 1080;
+		}
+		else if (tp->vfmt == VFORMAT_AVS)
+		{
+			am_sysinfo.format = VIDEO_DEC_FORMAT_AVS;
+			/*am_sysinfo.width  = 1920;
+			am_sysinfo.height = 1080;*/
+		}
+		else if (tp->vfmt == VFORMAT_HEVC)
+		{
+			am_sysinfo.format = VIDEO_DEC_FORMAT_HEVC;
+			am_sysinfo.width  = 3840;
+			am_sysinfo.height = 2160;
+		}
+
+		if (ioctl(ts->fd, AMSTREAM_IOC_SYSINFO, (unsigned long)&am_sysinfo) == -1)
+		{
+			AM_DEBUG(1, "set AMSTREAM_IOC_SYSINFO");
+			return AM_AV_ERR_SYS;
+		}
+		/*configure double write mode*/
+		memset(vdec_info, 0, sizeof(vdec_info));
+		if (tp->vfmt == VFORMAT_HEVC) {
+			sprintf(vdec_info, "hevc_double_write_mode:%d", double_write_mode);
+			configure_vdec_info(ts->fd, vdec_info, strlen(vdec_info));
+		} else if (tp->vfmt == VFORMAT_VP9) {
+			sprintf(vdec_info, "vp9_double_write_mode:%d", double_write_mode);
+			configure_vdec_info(ts->fd, vdec_info, strlen(vdec_info));
+		}
+	}
+
+	if (has_audio && start_audio) {
+		if ((tp->afmt == AFORMAT_AC3) || (tp->afmt == AFORMAT_DTS)) {
+			//set_arc_freq(1);
+		}
+
+		val = tp->afmt;
+		if (ioctl(ts->fd, AMSTREAM_IOC_AFORMAT, val) == -1)
+		{
+			AM_DEBUG(1, "set audio format failed");
+			return AM_AV_ERR_SYS;
+		}
+		val = tp->apid;
+		if (ioctl(ts->fd, AMSTREAM_IOC_AID, val) == -1)
+		{
+			AM_DEBUG(1, "set audio PID failed");
+			return AM_AV_ERR_SYS;
+		}
+	}
+
+	sync_mode = aml_calc_sync_mode(tshift->dev, (has_audio && start_audio), has_video, 0, tp->afmt, &sync_force);
+	aml_set_sync_mode(tshift->dev, sync_mode);
+
+	if ((has_audio && start_audio) && (sync_force != FORCE_AC3_AMASTER)) {
+		if (!show_first_frame_nosync()) {
+#ifdef ANDROID
+			//property_set("sys.amplayer.drop_pcm", "1");
+#endif
+		}
+		AM_FileEcho(ENABLE_RESAMPLE_FILE, "1");
+
+		audio_ops->adec_start_decode(ts->fd, tp->afmt, has_video, &ts->adec);
+
+		if (VALID_PID(tp->sub_apid))
+			aml_set_audio_ad(tshift->dev, 1, tp->sub_apid, tp->sub_afmt);
+	}
+	if (ioctl(ts->fd, AMSTREAM_IOC_PORT_INIT, 0) == -1)
+	{
+		AM_DEBUG(1, "amport init failed");
+		return AM_AV_ERR_SYS;
+	}
+#ifdef SUPPORT_CAS
+	if (para->secure_enable) {
+		AM_FileEcho("/sys/module/decoder_common/parameters/force_nosecure_even_drm", "1");
+		if (ioctl(ts->fd, AMSTREAM_IOC_SET_DRMMODE, (void *)(long)(1)) == -1)
+		{
+			AM_DEBUG(0, "%s, set drm enable failed", __func__);
+			return AM_AV_ERR_SYS;
+		}
+		AM_DEBUG(3, "%s, set drm enable success", __func__);
+	} else {
+		AM_FileEcho("/sys/module/decoder_common/parameters/force_nosecure_even_drm", "0");
+		if (ioctl(ts->fd, AMSTREAM_IOC_SET_DRMMODE, (void *)(long)(0)) == -1)
+		{
+			AM_DEBUG(0, "%s, set drm disable failed", __func__);
+			return AM_AV_ERR_SYS;
+		}
+		AM_DEBUG(3, "%s, set drm disable success", __func__);
+	}
+#endif
+	/*no blank for timeshifting play*/
+	AM_FileEcho(VID_BLACKOUT_FILE, "0");
+
+#ifdef SUPPORT_CAS
+//	AM_EVT_Signal(tshift->dev->dev_no, AM_AV_EVT_PLAYER_STATE_CHANGED, NULL);
+#endif
+
+	if (create_thread)
+	{
+		tshift->state = AV_TIMESHIFT_STAT_STOP;
+		tshift->duration = para->media_info.duration * 1000;
+
+		AM_DEBUG(1, "[timeshift] mode %d, duration %d", para->mode, tshift->duration);
+		/*check if use tfile external, for compatible*/
+		if (!tshift_para->para.tfile) {
+			tshift->file_flag |= TIMESHIFT_TFILE_AUTOCREATE;
+			AM_TRY(AM_TFile_Open(&tshift->file,
+						para->file_path,
+						(para->mode == AM_AV_TIMESHIFT_MODE_TIMESHIFTING && tshift->duration > 0),
+						tshift->duration,
+						0));
+#ifdef SUPPORT_CAS
+			if (para->secure_enable && !tshift->cas_open) {
+				if (AM_SUCCESS == AM_TFile_CasOpen(para->cas_file_path)) {
+					AM_TFile_CasDump();
+					tshift->cas_open = 1;
+				}
+			}
+#endif
+			if (para->mode == AM_AV_TIMESHIFT_MODE_TIMESHIFTING) {
+				AM_TFile_TimeStart(tshift->file);
+				AM_DEBUG(1, "[timeshift] start TFile timer %p", tshift->file);
+			}
+		} else {
+			tshift->file = tshift_para->para.tfile;
+			tshift->file_flag |= TIMESHIFT_TFILE_DETACHED;
+//			AM_EVT_Subscribe((long)tshift->file, AM_TFILE_EVT_RATE_CHANGED, tfile_evt_callback, tshift->dev);
+			AM_DEBUG(1, "[timeshift] using TFile %p", tshift->file);
+		}
+
+		if (! tshift->file->loop && tshift->duration)
+		{
+			tshift->rate = tshift->file->size * 1000 / tshift->duration;
+			AM_DEBUG(1, "[timeshift] Playback file size %lld, duration %d ms, the bitrate is %d bps", tshift->file->size, tshift->duration, tshift->rate);
+		}
+		tshift->running = 1;
+		tshift->offset = tshift_para->para.offset_ms;
+		tshift->para = *tshift_para;
+		pthread_mutex_init(&tshift->lock, NULL);
+		pthread_cond_init(&tshift->cond, NULL);
+		if (pthread_create(&tshift->thread, NULL, aml_timeshift_thread, (void*)tshift))
+		{
+			AM_DEBUG(1, "create the timeshift thread failed");
+			tshift->running = 0;
+		}
+		AM_DEBUG(1, "[timeshift] create aml_term_signal_handler");
+		signal(SIGTERM, &aml_term_signal_handler);
+	}
+
+	return AM_SUCCESS;
+}
+
+static int aml_start_av_monitor(AM_AV_Device_t *dev, AV_Monitor_t *mon)
+{
+	AM_DEBUG(1, "[avmon] start av monitor SwitchSourceTime = %fs",getUptimeSeconds());
+	mon->av_thread_running = AM_TRUE;
+	if (pthread_create(&mon->av_mon_thread, NULL, aml_av_monitor_thread, (void*)dev))
+	{
+		AM_DEBUG(1, "[avmon] create the av buf monitor thread failed");
+		mon->av_thread_running = AM_FALSE;
+		return -1;
+	}
+	return 0;
+}
+
+static void aml_stop_av_monitor(AM_AV_Device_t *dev, AV_Monitor_t *mon)
+{
+	AM_DEBUG(1, "[avmon] stop av monitor");
+	if (mon->av_thread_running) {
+		mon->av_thread_running = AM_FALSE;
+		pthread_cond_broadcast(&gAVMonCond);
+		AM_DEBUG(1, "[avmon] stop av monitor ---broardcast end join start\r\n");
+		pthread_join(mon->av_mon_thread, NULL);
+		AM_DEBUG(1, "[avmon] stop av monitor ---join end\r\n");
+	}
+	if (dev)
+		dev->audio_switch = AM_FALSE;
+}
+
+static void aml_check_audio_state(void)
+{
+	char buf[32];
+	int tsync_audio_state = 0;
+	int check_count = 0;
+	while (check_count++ < 10) {
+		usleep(100 * 1000);
+		if (AM_FileRead(TSYNC_AUDIO_STATE_FILE, buf, sizeof(buf)) >= 0) {
+			sscanf(buf, "%x", &tsync_audio_state);
+		} else {
+			break;
+		}
+		AM_DEBUG(1, "tsync_audio_state %d", tsync_audio_state);
+		if (tsync_audio_state == 7) {
+			break;
+		} else if (tsync_audio_state == 0) {
+			usleep(100 * 1000);
+			break;
+		}
+	}
+}
+
+
+
+static void aml_stop_timeshift(AV_TimeshiftData_t *tshift, AM_Bool_t destroy_thread)
+{
+	char buf[64];
+	AM_Bool_t has_audio = VALID_AUDIO(tshift->tp.apid, tshift->tp.afmt);
+#if 0
+	if (tshift->dev->afd_enable)
+		aml_stop_afd(tshift->dev);
+#endif
+	if (tshift->running && destroy_thread)
+	{
+		tshift->running = 0;
+		pthread_cond_broadcast(&tshift->cond);
+		pthread_join(tshift->thread, NULL);
+
+		aml_stop_av_monitor(tshift->dev, &tshift->dev->timeshift_player.mon);
+
+		if (!(tshift->file_flag & TIMESHIFT_TFILE_DETACHED))
+			AM_TFile_Close(tshift->file);
+#ifdef SUPPORT_CAS
+		if (tshift->cas_open) {
+			AM_TFile_CasClose();
+			tshift->cas_open = 0;
+		}
+#endif
+	}
+
+	if (tshift->ts.fd != -1) {
+            AM_DEBUG(1, "Stopping Audio decode");
+            if (has_audio) {
+                aml_set_ad_source(&tshift->ts.ad, 0, 0, 0, tshift->ts.adec);
+                audio_ops->adec_set_decode_ad(0, 0, 0, tshift->ts.adec);
+                audio_ops->adec_stop_decode(&tshift->ts.adec);
+            }
+            AM_DEBUG(1, "Closing mpts");
+            close(tshift->ts.fd);
+            tshift->ts.fd = -1;
+	}
+	AM_DEBUG(1, "Closing demux 1");
+	if (tshift->dmxfd != -1)
+		close(tshift->dmxfd);
+	AM_DEBUG(1, "Closing video");
+	if (tshift->ts.vid_fd != -1)
+		close(tshift->ts.vid_fd);
+
+	AM_FileEcho(DVB_STB_SOURCE_FILE, tshift->last_stb_src);
+	snprintf(buf, sizeof(buf), DVB_STB_DEMUXSOURCE_FILE, tshift->para.para.dmx_id);
+	AM_FileEcho(buf, tshift->last_dmx_src);
+
+	if (AM_FileRead(DI_BYPASS_ALL_FILE, buf, sizeof(buf)) == AM_SUCCESS) {
+		if (!strncmp(buf, "1", 1)) {
+			AM_FileEcho(DI_BYPASS_ALL_FILE,"0");
+		}
+	}
+}
+
+/**\brief 释放Timeshift相关数据*/
+static void aml_destroy_timeshift_data(AV_TimeshiftData_t *tshift)
+{
+#ifdef SUPPORT_CAS
+	if (tshift->buf) {
+		free(tshift->buf);
+		tshift->buf = NULL;
+	}
+#endif
+	free(tshift);
+}
+
+static int am_timeshift_reset(AV_TimeshiftData_t *tshift, int deinterlace_val, AM_Bool_t start_audio)
+{
+	UNUSED(deinterlace_val);
+
+	AM_DEBUG(1, "am_timeshift_reset");
+	aml_stop_timeshift(tshift, AM_FALSE);
+	if (start_audio)
+		aml_check_audio_state();
+	aml_start_timeshift(tshift, &tshift->para, AM_FALSE, start_audio);
+
+	/*Set the left to 0, we will read from the new point*/
+	tshift->left = 0;
+
+	return 0;
+}
+
+static int am_timeshift_reset_continue(AV_TimeshiftData_t *tshift, int deinterlace_val, AM_Bool_t start_audio)
+{
+
+	UNUSED(deinterlace_val);
+	AM_DEBUG(1, "am_timeshift_reset_continue reset inject size");
+	tshift->inject_size = 0;
+	aml_stop_timeshift(tshift, AM_FALSE);
+
+	aml_start_timeshift(tshift, &tshift->para, AM_FALSE, start_audio);
+	tshift->inject_size = 64*1024;
+	return 0;
+}
+
+static int am_timeshift_playback_time_check(AV_TimeshiftData_t *tshift, int time)
+{
+	if (time < 0)
+		return 0;
+	else if (time >= (tshift->duration))
+		return tshift->duration;
+	return time;
+}
+
+static int am_timeshift_fffb(AV_TimeshiftData_t *tshift, AV_PlayCmdPara_t *cmd)
+{
+	int now, ret, next_time;
+	int speed = cmd->speed.speed;
+
+	if (1/*speed*/)
+	{
+		if (tshift->para.para.mode == AM_AV_TIMESHIFT_MODE_TIMESHIFTING) {
+			next_time = tshift->fffb_current + speed * FFFB_JUMP_STEP;
+			AM_TFile_TimeSeek(tshift->file, next_time);
+			AM_DEBUG(2, "[timeshift] fffb cur[%d] -> next[%d]", tshift->fffb_current, next_time);
+		} else {
+			loff_t offset;
+			next_time = tshift->fffb_current + speed * FFFB_JUMP_STEP;
+			next_time = am_timeshift_playback_time_check(tshift, next_time);
+			offset = (loff_t)next_time * tshift->rate / 1000;
+#ifdef SUPPORT_CAS
+			if (tshift->para.para.secure_enable) {
+				offset = ROUNDUP(offset, SECURE_BLOCK_SIZE);
+				if (tshift->para.para.mode == AM_AV_TIMESHIFT_MODE_PLAYBACK)
+					offset += 188*11;//skip pat and meida info header,clear data not encrypt
+			}
+#endif
+			AM_TFile_Seek(tshift->file, offset);
+			AM_DEBUG(2, "[timeshift] fffb cur[%d] -> next[%d],offset[%lld]", tshift->fffb_current, next_time, offset);
+			tshift->eof = (next_time == tshift->duration) ? 1 : 0;
+			if (tshift->eof) {
+				AM_DEBUG(1, "[timeshift] fffb eof");
+			}
+		}
+		tshift->fffb_current = next_time;
+		AM_TIME_GetClock(&tshift->fffb_start);
+		am_timeshift_reset(tshift, 0, AM_FALSE);
+	}
+	else
+	{
+		/*speed is 0/1, turn to play*/
+		ret = 1;
+		AM_DEBUG(1, "[timeshift] speed == [%d]", speed);
+	}
+
+	return 0;
+}
+
+static int aml_timeshift_pause_av(AV_TimeshiftData_t *tshift)
+{
+	if (VALID_AUDIO(tshift->tp.apid, tshift->tp.afmt))
+	{
+#if defined(ADEC_API_NEW)
+		audio_ops->adec_pause_decode(tshift->ts.adec);
+#else
+		//TODO
+#endif
+	}
+
+	if (VALID_VIDEO(tshift->tp.vpid, tshift->tp.vfmt))
+	{
+		ioctl(tshift->ts.vid_fd, AMSTREAM_IOC_VPAUSE, 1);
+	}
+
+	return 0;
+}
+
+static int aml_timeshift_resume_av(AV_TimeshiftData_t *tshift)
+{
+	if (VALID_AUDIO(tshift->tp.apid, tshift->tp.afmt))
+	{
+#if defined(ADEC_API_NEW)
+		audio_ops->adec_resume_decode(tshift->ts.adec);
+#else
+		//TODO
+#endif
+	}
+	if (VALID_VIDEO(tshift->tp.vpid, tshift->tp.vfmt))
+	{
+		ioctl(tshift->ts.vid_fd, AMSTREAM_IOC_VPAUSE, 0);
+	}
+
+
+	return 0;
+}
+
+static int aml_timeshift_do_cmd_start(AV_TimeshiftData_t *tshift)
+{
+	loff_t offset;
+	int seeked = 0;
+
+        AV_TimeshiftState_t last_stat =  tshift->state;
+	tshift->inject_size = 64*1024;
+	tshift->timeout = 0;
+	tshift->state = AV_TIMESHIFT_STAT_PLAY;
+	AM_DEBUG(1, "[timeshift] [start] seek to time %d ms...", tshift->current);
+	if (tshift->para.para.mode == AM_AV_TIMESHIFT_MODE_TIMESHIFTING) {
+		if (AM_TFile_TimeGetReadNow(tshift->file) != tshift->current) {
+			AM_TFile_TimeSeek(tshift->file, tshift->current);
+			seeked = 1;
+		}
+	} else {//rec play
+		loff_t off = AM_TFile_Tell(tshift->file);
+		int current = off * 1000 / (loff_t)tshift->rate;
+		AM_DEBUG(1, "[timeshift] [start] file now[%lld][%dms] rate[%dbps]", off, current, tshift->rate);
+		if (current != tshift->current) {
+			offset = (loff_t)tshift->current / 1000 * (loff_t)tshift->rate;
+			AM_TFile_Seek(tshift->file, offset);
+			seeked = 1;
+		}
+	}
+	if (VALID_VIDEO(tshift->tp.vpid, tshift->tp.vfmt))
+		ioctl(tshift->ts.vid_fd, AMSTREAM_IOC_TRICKMODE, TRICKMODE_NONE);
+
+	if (seeked || last_stat == AV_TIMESHIFT_STAT_FFFB)
+		am_timeshift_reset(tshift, 2, AM_TRUE);
+
+	//if (tshift->last_cmd == AV_PLAY_FF || tshift->last_cmd == AV_PLAY_FB)
+	{
+		//usleep(200*1000);
+		AM_DEBUG(1, "set di bypass_all to 0");
+		AM_FileEcho("/sys/module/di/parameters/bypass_all","0");
+	}
+	aml_start_av_monitor(tshift->dev, &tshift->dev->timeshift_player.mon);
+	return 0;
+}
+
+static int aml_timeshift_do_play_cmd(AV_TimeshiftData_t *tshift, AV_PlayCmdPara_t *cmd)
+{
+	AV_TimeshiftState_t	last_state = tshift->state;
+	loff_t offset;
+	int state_changed = 0, cmd_changed = 0;
+
+	if ((tshift->para.para.mode != AM_AV_TIMESHIFT_MODE_TIMESHIFTING && !tshift->rate)
+		&& (cmd->cmd == AV_PLAY_FF || cmd->cmd == AV_PLAY_FB || cmd->cmd == AV_PLAY_SEEK))
+	{
+		AM_DEBUG(1, "zzz [timeshift] Have not got the rate, skip this command");
+		return -1;
+	}
+
+	if ((tshift->last_cmd[0].cmd == AV_PLAY_SEEK && tshift->last_cmd[0].done)
+		|| timeshift_cmd_diff(&tshift->last_cmd[0], cmd))
+	{
+		switch (cmd->cmd)
+		{
+		case AV_PLAY_START:
+			//if (tshift->state != AV_TIMESHIFT_STAT_PLAY) {
+				aml_timeshift_do_cmd_start(tshift);
+				aml_timeshift_update_current(tshift);
+			//}
+			break;
+		case AV_PLAY_PAUSE:
+			//if (tshift->state != AV_TIMESHIFT_STAT_PAUSE)
+			{
+				AM_DEBUG(1, "[timeshift] [pause]");
+				aml_stop_av_monitor(tshift->dev, &tshift->dev->timeshift_player.mon);
+				tshift->inject_size = 0;
+				tshift->timeout = 1000;
+				tshift->state = AV_TIMESHIFT_STAT_PAUSE;
+				if (VALID_VIDEO(tshift->tp.vpid, tshift->tp.vfmt))
+					ioctl(tshift->ts.vid_fd, AMSTREAM_IOC_TRICKMODE, TRICKMODE_NONE);
+				aml_timeshift_pause_av(tshift);
+				aml_timeshift_update_current(tshift);
+			}
+			break;
+		case AV_PLAY_RESUME:
+			if (tshift->state == AV_TIMESHIFT_STAT_PAUSE)
+			{
+				if (tshift->pause_time && tshift->current > tshift->pause_time) {
+					AM_DEBUG(1, "[timeshift] [resume] [replay]");
+					aml_timeshift_do_cmd_start(tshift);
+				} else {
+					tshift->inject_size = 64*1024;
+					tshift->timeout = 0;
+					tshift->state = AV_TIMESHIFT_STAT_PLAY;
+					if (VALID_VIDEO(tshift->tp.vpid, tshift->tp.vfmt))
+						ioctl(tshift->ts.vid_fd, AMSTREAM_IOC_TRICKMODE, TRICKMODE_NONE);
+					aml_timeshift_resume_av(tshift);
+					aml_start_av_monitor(tshift->dev, &tshift->dev->timeshift_player.mon);
+					AM_DEBUG(1, "[timeshift] [resume]");
+				}
+
+				aml_timeshift_update_current(tshift);
+				tshift->fffb_start = 0;
+				tshift->fffb_current = 0;
+			}
+			break;
+		case AV_PLAY_FF:
+		case AV_PLAY_FB:
+			if (tshift->state != AV_TIMESHIFT_STAT_FFFB)
+			{
+				if (cmd->speed.speed == 0 && tshift->state == AV_TIMESHIFT_STAT_PLAY)
+					return 0;
+				aml_stop_av_monitor(tshift->dev, &tshift->dev->timeshift_player.mon);
+				tshift->inject_size = 64*1024;
+				tshift->timeout = 0;
+				tshift->state = AV_TIMESHIFT_STAT_FFFB;
+				AM_DEBUG(1, "[timeshift] [fast] speed: %d", cmd->speed.speed);
+				if (tshift->last_cmd[0].cmd == AV_PLAY_START)
+				{
+					AM_DEBUG(1, "set di bypass_all to 1");
+					AM_FileEcho(DI_BYPASS_ALL_FILE,"1");
+					usleep(200*1000);
+				}
+				if (VALID_VIDEO(tshift->tp.vpid, tshift->tp.vfmt))
+					ioctl(tshift->ts.vid_fd, AMSTREAM_IOC_TRICKMODE, TRICKMODE_FFFB);
+				/*reset the fffb start*/
+				tshift->fffb_current = tshift->current;
+				am_timeshift_fffb(tshift, cmd);
+				aml_timeshift_update_current(tshift);
+			}
+			break;
+		case AV_PLAY_SEEK:
+			aml_stop_av_monitor(tshift->dev, &tshift->dev->timeshift_player.mon);
+			if (tshift->para.para.mode == AM_AV_TIMESHIFT_MODE_TIMESHIFTING) {
+				AM_DEBUG(1, "[timeshift] [seek] offset: time: %dms", cmd->seek.seek_pos);
+				AM_TFile_TimeSeek(tshift->file, cmd->seek.seek_pos);
+			} else {
+				int pos = am_timeshift_playback_time_check(tshift, cmd->seek.seek_pos);
+				offset = (loff_t)pos / 1000 * (loff_t)tshift->rate;
+#ifdef SUPPORT_CAS
+				if (tshift->para.para.secure_enable) {
+					offset = ROUNDUP(offset, SECURE_BLOCK_SIZE);
+					offset += 188*11;//skip pat and meida info header,clear data not encrypt
+				}
+#endif
+				AM_DEBUG(1, "[timeshift] [seek] offset: time:%dms off:%lld", pos, offset);
+				AM_TFile_Seek(tshift->file, offset);
+			}
+			if (VALID_VIDEO(tshift->tp.vpid, tshift->tp.vfmt))
+				ioctl(tshift->ts.vid_fd, AMSTREAM_IOC_TRICKMODE, TRICKMODE_FFFB);
+			am_timeshift_reset(tshift, 0, AM_TRUE);
+			tshift->inject_size = 64*1024;
+			tshift->timeout = 0;
+			aml_timeshift_update_current(tshift);
+			break;
+#if 0
+		case AV_PLAY_RESET_VPATH:
+			if (VALID_VIDEO(tshift->tp.vpid, tshift->tp.vfmt))
+				ioctl(tshift->ts.vid_fd, AMSTREAM_IOC_TRICKMODE, TRICKMODE_NONE);
+			/*stop play first*/
+			aml_stop_timeshift(tshift, AM_FALSE);
+			/*reset the vpath*/
+			aml_set_vpath(tshift->dev);
+			/*restart play now*/
+			aml_start_timeshift(tshift, &tshift->para, AM_FALSE, AM_TRUE);
+
+			/*Set the left to 0, we will read from the new point*/
+			tshift->left = 0;
+			tshift->inject_size = 0;
+			tshift->timeout = 0;
+			/* will turn to play state from current_time */
+			tshift->state = AV_TIMESHIFT_STAT_SEARCHOK;
+			break;
+#endif
+#if 0
+		case AV_PLAY_SWITCH_AUDIO:
+			/* just restart play using the new audio para */
+			AM_DEBUG(1, "[timeshift] [switch audio] pid=%d, fmt=%d",tshift->tp.apid, tshift->tp.afmt);
+			/*Set the left to 0, we will read from the new point*/
+			tshift->left = 0;
+			tshift->inject_size = 0;
+			tshift->timeout = 0;
+			if (tshift->state == AV_TIMESHIFT_STAT_PAUSE)
+			{
+				/* keep pause with the new audio */
+				if (VALID_VIDEO(tshift->tp.vpid, tshift->tp.vfmt))
+					ioctl(tshift->ts.vid_fd, AMSTREAM_IOC_TRICKMODE, TRICKMODE_NONE);
+				am_timeshift_reset(tshift, 2, AM_TRUE);
+				tshift->timeout = 1000;
+				aml_timeshift_pause_av(tshift);
+			}
+			else
+			{
+				/* will turn to play state from current_time */
+				tshift->state = AV_TIMESHIFT_STAT_SEARCHOK;
+			}
+			break;
+#endif
+		default:
+			AM_DEBUG(1, "[timeshift] Unsupported timeshift play command %d", cmd);
+			return -1;
+			break;
+		}
+	}
+
+	if (timeshift_cmd_diff(&tshift->last_cmd[0], cmd)) {
+		cmd_changed = 1;
+		if (tshift->last_cmd[0].cmd != AV_PLAY_SEEK)/*for resume from seek*/
+			tshift->last_cmd[1] = tshift->last_cmd[0];
+		tshift->last_cmd[0] = *cmd;
+	}
+
+	if (tshift->state != last_state)
+		state_changed = 1;
+
+	return (cmd_changed || state_changed);
+}
+
+int aml_timeshift_do_cmd(AV_TimeshiftData_t *tshift, AV_PlayCmdPara_t *cmd, int notify)
+{
+	int state_changed;
+	AV_PlayCmdPara_t last;
+
+	if ((tshift->last_cmd[0].cmd == AV_PLAY_FF || tshift->last_cmd[0].cmd == AV_PLAY_FB)
+		&& (cmd->cmd == AV_PLAY_PAUSE || cmd->cmd == AV_PLAY_RESUME))
+	{
+		/*
+		 * $ID: 101093,Fixed, timeshift resume decoder is stop when status from FastForward(or FastBack) to Pause directly
+		 */
+		AM_DEBUG(1, "[timeshift] last cmd is %s, cur_cmd is %s, do AV_PLAY_START first",
+			cmd2string(tshift->last_cmd[0].cmd),
+			cmd2string(cmd->cmd));
+		{
+			AV_PlayCmdPara_t c;
+			timeshift_cmd_init(&c, AV_PLAY_START);
+			aml_timeshift_do_play_cmd(tshift, &c);
+		}
+	}
+
+	last = tshift->last_cmd[0];
+	state_changed = aml_timeshift_do_play_cmd(tshift, cmd);
+
+	AM_DEBUG(5, ">>>done cmd:%d, state_changed:%d, do_notify:%d, last:%d", cmd->cmd, state_changed, notify, last.cmd);
+
+	if ((state_changed || notify)
+		&& !((tshift->state == AV_TIMESHIFT_STAT_FFFB || tshift->state == AV_TIMESHIFT_STAT_PAUSE)
+			&& (last.cmd == AV_PLAY_SEEK || last.cmd == AV_PLAY_FF || last.cmd == AV_PLAY_FB || last.cmd == AV_PLAY_PAUSE)))
+	{
+		aml_timeshift_notify(tshift, NULL, AM_TRUE);
+	}
+
+	if (cmd->cmd != AV_PLAY_PAUSE)
+		tshift->pause_time = 0;
+
+	return 0;
+}
+
+static void aml_timeshift_update_info(AV_TimeshiftData_t *tshift, AM_AV_TimeshiftInfo_t *info)
+{
+	pthread_mutex_lock(&tshift->lock);
+	tshift->info = *info;
+	pthread_mutex_unlock(&tshift->lock);
+}
+
+static int aml_timeshift_fetch_data(AV_TimeshiftData_t *tshift, uint8_t *buf, size_t size, int timeout)
+{
+	int cnt = 0;
+	int ret;
+	uint8_t ts_pkt[188];
+	AM_Crypt_Ops_t *crypt_ops = tshift->dev->crypt_ops;
+	void *cryptor = tshift->dev->cryptor;
+
+	if (CRYPT_SET(crypt_ops)) {
+		int skip = 0;
+
+		/*skip the header*/
+		if (tshift->para.para.mode == AM_AV_TIMESHIFT_MODE_PLAYBACK) {
+			if (AM_TFile_Tell(tshift->file) == 0)
+				skip = 2;
+		}
+
+		while ((cnt + 188) <= size) {
+			if (AM_TFile_GetAvailable(tshift->file) < 188)
+				break;
+
+			ret = AM_TFile_Read(tshift->file, ts_pkt, 1, timeout);
+			if (ret <= 0 || ret != 1) {
+				if (!cnt)
+					return 0;
+				else
+					break;
+			}
+
+			if (ts_pkt[0] != 0x47)
+				continue;
+
+			ret = AM_TFile_Read(tshift->file, ts_pkt+1, sizeof(ts_pkt)-1, timeout);
+			if (ret <= 0 || ret != (sizeof(ts_pkt)-1)) {
+				if (!cnt)
+					return 0;
+				else
+					break;
+			}
+
+			if (!skip) {
+				if (crypt_ops && crypt_ops->crypt)
+					crypt_ops->crypt(cryptor, buf+cnt, ts_pkt, 188, 1);
+			} else {
+				skip--;
+				memcpy(buf+cnt, ts_pkt, 188);
+			}
+
+			cnt += 188;
+		}
+	} else {
+		cnt = AM_TFile_Read(tshift->file, buf, size, timeout);
+	}
+	return cnt;
+}
+
+
+#ifdef SUPPORT_CAS
+static int build_drm_pkg(uint8_t *outpktdata, uint8_t *addr, uint32_t size)
+{
+	drminfo_t drminfo;
+
+	memset(&drminfo, 0, sizeof(drminfo_t));
+	drminfo.drm_level = DRM_LEVEL1;
+	drminfo.drm_pktsize = size;
+	drminfo.drm_hasesdata = 0;
+	drminfo.drm_phy = (unsigned int)addr;
+	drminfo.drm_flag = TYPE_DRMINFO;
+	memcpy(outpktdata, &drminfo, sizeof(drminfo_t));
+
+	return 0;
+}
+#endif
+
+/**\brief Timeshift 线程*/
+static void *aml_timeshift_thread(void *arg)
+{
+	AV_TimeshiftData_t *tshift = (AV_TimeshiftData_t *)arg;
+	int speed, update_time, now/*, fffb_time*/;
+	int len, ret;
+	int /*dmxfd,*/ trick_stat;
+#ifdef SUPPORT_CAS
+	int secure_enable = tshift->para.para.secure_enable;
+	uint8_t *buf = tshift->buf;
+	AM_CAS_CryptPara_t cparam;
+	uint64_t pos, offset, sec_remain_data_len;
+	uint8_t drm_pkt[sizeof(drminfo_t)];
+	uint8_t store_info[512];
+	uint8_t rec_info[16];
+#else
+	uint8_t buf[64*1024];
+#endif
+	const int FFFB_STEP = 150;
+	struct timespec rt;
+	AM_AV_TimeshiftInfo_t info;
+	struct am_io_param astatus;
+	struct am_io_param vstatus;
+	int playback_alen=0, playback_vlen=0;
+	AM_Bool_t is_playback_mode = (tshift->para.para.mode == AM_AV_TIMESHIFT_MODE_PLAYBACK);
+	int vbuf_len = 0;
+	int abuf_len = 0;
+	int skip_flag_count = 0;
+	int dmx_vpts = 0,  vpts = 0, last_vpts = 0;
+	int dmx_apts = 0,  apts = 0, last_apts = 0;
+	char pts_buf[32];
+	int diff = 0, last_diff = 0;
+	int adiff = 0, last_adiff = 0;
+	int error_cnt = 0;
+	int fetch_fail = 0;
+	int debug_print = 0;
+
+	AV_TSPlayPara_t *tp = &tshift->tp;
+	AM_Bool_t has_video = VALID_VIDEO(tp->vpid, tp->vfmt);
+	AM_Bool_t has_audio = VALID_AUDIO(tp->apid, tp->afmt);
+
+	int do_update;
+	AV_PlayCmdPara_t cmd;
+	int cmd_more;
+	int write_pass;
+
+	int alarm_eof = 0;
+
+	memset(&cmd, 0, sizeof(cmd));
+	memset(pts_buf, 0, sizeof(pts_buf));
+	memset(&info, 0, sizeof(info));
+	timeshift_cmd_init(&tshift->last_cmd[0], -1);
+
+	pthread_mutex_lock(&tshift->lock);
+	timeshift_cmd_init(&cmd, tshift->para.para.start_paused ? AV_PLAY_PAUSE : AV_PLAY_START);
+	timeshift_cmd_put(tshift, &cmd);
+	pthread_mutex_unlock(&tshift->lock);
+	AM_DEBUG(1, "[timeshift] start in \"%s\" mode", cmd2string(cmd.cmd));
+
+	tshift->current = tshift->offset;
+	AM_DEBUG(1, "[timeshift] start from offset(%dms)", tshift->offset);
+
+	tshift->dev->cryptor = aml_try_open_crypt(tshift->dev->crypt_ops);
+	AM_DEBUG(1, "[timeshift] crypt mode : %d", (tshift->dev->cryptor)? 1 : 0);
+
+	debug_print = _get_timethift_dbg();
+
+	AM_DEBUG(1, "Starting timeshift player thread ...");
+	info.status = AV_TIMESHIFT_STAT_INITOK;
+
+	AM_TIME_GetClock(&update_time);
+
+	while (tshift->running)
+	{
+		/*check the audio, in case of audio switch*/
+		has_audio = VALID_AUDIO(tp->apid, tp->afmt);
+
+		/*consume the cmds*/
+		do {
+			pthread_mutex_lock(&tshift->lock);
+			cmd_more = timeshift_cmd_more(tshift);
+			if (cmd_more)
+				timeshift_cmd_get(tshift, &cmd);
+			AM_DEBUG(5, ">>>exec cmd:%d pos:%d more:%d", cmd.cmd, cmd.seek.seek_pos, cmd_more);
+			pthread_mutex_unlock(&tshift->lock);
+
+			AM_TIME_GetClock(&now);
+
+			do_update = 0;
+			if ((now - update_time) >= 500) {
+				update_time = now;
+				do_update = 1;
+			}
+
+			aml_timeshift_do_cmd(tshift, &cmd, do_update);
+		} while (tshift->running && cmd_more);
+
+		/*start data inject*/
+		/*read some bytes*/
+		write_pass = 0;
+
+#ifdef SUPPORT_CAS
+		len = SECURE_BLOCK_SIZE - tshift->left;
+#else
+		len = sizeof(buf) - tshift->left;
+#endif
+		if (len > 0)
+		{
+			if (has_video) {
+				if (AM_FileRead(VIDEO_DMX_PTS_FILE, pts_buf, sizeof(pts_buf)) >= 0) {
+					sscanf(pts_buf, "%u", &dmx_vpts);
+				} else {
+					AM_DEBUG(1, "cannot read \"%s\"", VIDEO_DMX_PTS_FILE);
+					dmx_vpts = 0;
+				}
+				if (AM_FileRead(VIDEO_PTS_FILE, pts_buf, sizeof(pts_buf)) >= 0) {
+					sscanf(pts_buf+2, "%x", &vpts);
+				} else {
+					AM_DEBUG(1, "cannot read \"%s\"", VIDEO_PTS_FILE);
+					vpts = 0;
+				}
+			}
+
+			if (has_audio) {
+				if (AM_FileRead(AUDIO_DMX_PTS_FILE, pts_buf, sizeof(pts_buf)) >= 0) {
+					sscanf(pts_buf, "%u", &dmx_apts);
+				} else {
+					AM_DEBUG(1, "cannot read \"%s\"", AUDIO_DMX_PTS_FILE);
+					dmx_apts = 0;
+				}
+				if (AM_FileRead(AUDIO_PTS_FILE, pts_buf, sizeof(pts_buf)) >= 0) {
+					sscanf(pts_buf+2, "%x", &apts);
+				} else {
+					AM_DEBUG(1, "cannot read \"%s\"", AUDIO_PTS_FILE);
+					apts = 0;
+				}
+			}
+
+
+			if (tshift->state == AV_TIMESHIFT_STAT_PLAY) {
+				if (has_video) {
+					if (ioctl(tshift->ts.fd, AMSTREAM_IOC_VB_STATUS, (unsigned long)&vstatus) != 0) {
+						AM_DEBUG(1,"get v_stat_len failed, %d(%s)", errno, strerror(errno));
+					}
+				}
+
+				if (has_audio) {
+					if (ioctl(tshift->ts.fd, AMSTREAM_IOC_AB_STATUS, (unsigned long)&astatus) != 0) {
+						AM_DEBUG(1,"get a_stat_len failed, %d(%s)", errno, strerror(errno));
+					}
+				}
+
+				int wait_next = 0;
+
+				if (vpts > dmx_vpts) {
+					diff = 0;
+				} else {
+					diff = dmx_vpts - vpts;
+				}
+
+				if (apts > dmx_apts) {
+					adiff = 0;
+				} else {
+					adiff = dmx_apts - apts;
+				}
+
+
+				/*fixme: may need more condition according to fmt*/
+				#define IS_ALEVEL_OK(_data_len, _afmt) ((_data_len) > 768)
+				#define IS_ADUR_OK(_adiff, _afmt)      ((_adiff) >= TIMESHIFT_INJECT_DIFF_TIME)
+				#define IS_ADATA_OK(_data_len, _adiff, _afmt)  (IS_ALEVEL_OK(_data_len, _afmt) || IS_ADUR_OK(_adiff, _afmt))
+
+				#define IS_VLEVEL_OK(_data_len, _vfmt) ((_data_len) > DEC_STOP_VIDEO_LEVEL)
+				#define IS_VDUR_OK(_vdiff, _vfmt)      ((_vdiff) >= TIMESHIFT_INJECT_DIFF_TIME)
+				#define IS_VDATA_OK(_data_len, _vdiff, _vfmt)  (IS_VLEVEL_OK(_data_len, _vfmt) && IS_VDUR_OK(_vdiff, _vfmt))
+
+				/*prevent the data sink into buffer all, which causes sub/txt lost*/
+				if (
+					(has_video ? IS_VDATA_OK(vstatus.status.data_len, diff, tp->vfmt) : AM_TRUE)
+					&& (has_audio ? IS_ADATA_OK(astatus.status.data_len, adiff, tp->afmt) : AM_TRUE)
+					/*none? just inject*/
+					&& (has_audio || has_video)
+				)
+					wait_next = 1;
+				else
+					wait_next = 0;
+
+				if (debug_print) {
+					AM_DEBUG(1, ">> wait_next[%d] a/v[%d:%d] lvl[0x%x:0x%x] vpts/vdmx/diff[%#x:%#x:%d], apts/admx/diff[%#x:%#x:%d]\n",
+						wait_next,
+						has_audio, has_video,
+						astatus.status.data_len, vstatus.status.data_len,
+						vpts, dmx_vpts, diff,
+						apts, dmx_apts, adiff);
+				}
+
+				if (wait_next) {
+					last_diff = diff;
+					last_adiff = adiff;
+					tshift->timeout = 10;
+					write_pass = 1;
+					goto wait_for_next_loop;
+				}
+			}
+#ifdef SUPPORT_CAS
+                        if (secure_enable && AM_TFile_Tell(tshift->file) == 0 && is_playback_mode) {
+                                /*Skip pat and media_info ts packet, not encrypt*/
+                                ret = AM_TFile_Read(tshift->file, buf, 188*11, 100);
+                                AM_DEBUG(0, "%s skip pat and media info, %#x,%#x,%#x,%#x", __func__,
+                                                buf[0], buf[1], buf[2], buf[3]);
+                        }
+			do {
+#endif
+				ret = aml_timeshift_fetch_data(tshift, buf+tshift->left, len - tshift->left, 100);
+				if (ret > 0)
+				{
+					tshift->left += ret;
+					fetch_fail = 0;
+				}
+				else if (len - tshift->left != 0)
+				{
+					int error = errno;
+					//AM_DEBUG(4, "read playback file failed: %s", strerror(errno));
+					fetch_fail++;
+					/*fetch fail, treat as data break*/
+					if (fetch_fail == 1000)
+					{
+						AM_DEBUG(1, "[timeshift] data break, eof, try:%d", len);
+						//AM_EVT_Signal(tshift->dev->dev_no, AM_AV_EVT_PLAYER_EOF, NULL);
+					}
+
+					if (errno == EIO && is_playback_mode)
+					{
+						AM_DEBUG(1, "Disk may be plugged out, exit playback.");
+						break;
+					}
+				}
+#ifdef SUPPORT_CAS
+			} 
+while (secure_enable && (tshift->left < len) && tshift->running);
+#endif
+		}
+
+		/*Inject*/
+		if (tshift->inject_size > 0)
+		{
+			if (has_video &&
+				tshift->state == AV_TIMESHIFT_STAT_PLAY &&
+				ioctl(tshift->ts.fd, AMSTREAM_IOC_AB_STATUS, (unsigned long)&astatus) != -1 &&
+				ioctl(tshift->ts.fd, AMSTREAM_IOC_VB_STATUS, (unsigned long)&vstatus) != -1)
+			{
+				if (vstatus.status.data_len == 0 && astatus.status.data_len > 100*1024)
+				{
+					tshift->timeout = 10;
+					goto wait_for_next_loop;
+				}
+				else
+				{
+					tshift->timeout = 0;
+				}
+			}
+#ifdef SUPPORT_CAS
+			ret = AM_MIN(tshift->left , tshift->inject_size);
+			if (ret > 0 && secure_enable && tshift->para.para.dec_cb) {
+				//AM_TFile_CasDump();
+				offset = 0;
+				//offset %= SECURE_BLOCK_SIZE;
+				AM_DEBUG(0, "tshift cas dec. offset[%lld]", offset);
+				if (!offset) {
+					/*Last chunk inject completed,*/
+					memset(&cparam, 0, sizeof(cparam));
+					cparam.store_info.data = store_info;
+					cparam.rec_info.data = rec_info;
+					ret = AM_TFile_CasGetRecInfo(&cparam.rec_info);
+					pos = AM_TFile_Tell(tshift->file);
+					AM_DEBUG(0, "%s, get cas rec info:%d, blk_size:%d, left:%d, tell pos:%lld",
+							__func__, ret, cparam.rec_info.blk_size, tshift->left, pos);
+					ret = AM_TFile_CasGetStoreInfo(pos, &cparam.store_info);
+					if (ret == AM_SUCCESS) {
+						cparam.buf_in = buf;
+						cparam.buf_out = tshift->para.para.secure_buffer;
+						cparam.buf_len = tshift->left;
+						tshift->para.para.dec_cb(&cparam, tshift->para.para.cb_param);
+					} else {
+						AM_DEBUG(0, "%s get cas store info failed, ts_pos:%lld", __func__, pos);
+					}
+				}
+				AM_DEBUG(0, "need inject = %#x, inject_unit = %#x", tshift->left, tshift->inject_size);
+				while (tshift->left && tshift->running) {
+					ret = AM_MIN(tshift->left, tshift->inject_size);
+					build_drm_pkg(drm_pkt, cparam.buf_out + offset, ret);
+					ret = aml_timeshift_inject(tshift, drm_pkt, ret, -1);
+					if (!ret) {
+						AM_DEBUG(0, "%s, secure inject failed, offset:%d, remain:%d", __func__, offset, tshift->left);
+						continue;
+					}
+					offset += ret;
+					tshift->left -= ret;
+					AM_DEBUG(0, "cas injected = %#x, offset = %#x, left = %#x", ret, offset, tshift->left);
+				};
+			} else
+#endif
+                        {
+				ret = AM_MIN(tshift->left , tshift->inject_size);
+				if (ret > 0)
+					ret = aml_timeshift_inject(tshift, buf, ret, -1);
+
+				if (ret > 0)
+				{
+					/*ret bytes written*/
+					tshift->left -= ret;
+					if (tshift->left > 0)
+						memmove(buf, buf+ret, tshift->left);
+				}
+			}
+		}
+
+wait_for_next_loop:
+		/*Update the playing info*/
+		if (tshift->state == AV_TIMESHIFT_STAT_FFFB
+			|| tshift->last_cmd[0].cmd == AV_PLAY_SEEK)
+		{
+			if(has_video && vpts == 0)
+			{
+				AM_DEBUG(1, "[timeshift] FFFB/Seek get vpts==0");
+				error_cnt++;
+			}
+			else
+			{
+				error_cnt = 0;
+			}
+			if (error_cnt > TIMESHIFT_FFFB_ERROR_CNT)
+			{
+				AM_DEBUG(1, "[timeshift] FFFB/Seek error_cnt is overflow, reset trick_mode");
+				ioctl(tshift->ts.vid_fd, AMSTREAM_IOC_TRICKMODE, TRICKMODE_NONE);
+				ioctl(tshift->ts.vid_fd, AMSTREAM_IOC_TRICKMODE, TRICKMODE_FFFB);
+				error_cnt = 0;
+
+				if (is_playback_mode
+					&& tshift->state == AV_TIMESHIFT_STAT_FFFB
+					&& tshift->eof)
+				{
+					AM_DEBUG(1, "[timeshift] seems to be eof");
+					alarm_eof = 1;
+				}
+			}
+			tshift->timeout = 0;
+
+			trick_stat = (has_video) ? aml_timeshift_get_trick_stat(tshift) : 1;
+
+			AM_DEBUG(1, "[timeshift] trick_stat is %d vpts 0x%x", trick_stat, vpts);
+			if (trick_stat > 0)
+			{
+				cmd.done = 1;
+
+				AM_DEBUG(1, "[timeshift] last cmd:%d, state:%d", tshift->last_cmd[0].cmd, tshift->state);
+				if (cmd.cmd == AV_PLAY_SEEK) {
+					AV_PlayCmdPara_t c;
+
+					/*notify for seek ready*/
+					aml_timeshift_notify(tshift, NULL, AM_FALSE);
+
+					/*update for cmd next*/
+					aml_timeshift_update_current(tshift);
+
+					/*seek is not a state, set the next cmd to back to previous state*/
+					if (tshift->state == AV_TIMESHIFT_STAT_PAUSE) {
+						timeshift_cmd_init(&cmd, AV_PLAY_PAUSE);
+						aml_timeshift_do_cmd(tshift, &cmd, 1);
+					} else if (tshift->state == AV_TIMESHIFT_STAT_FFFB) {
+						cmd = tshift->last_cmd[1];
+						aml_timeshift_do_cmd(tshift, &cmd, 1);
+					} else if (tshift->state == AV_TIMESHIFT_STAT_PLAY) {
+						timeshift_cmd_init(&cmd, AV_PLAY_START);
+						aml_timeshift_do_cmd(tshift, &cmd, 1);
+					}
+					aml_timeshift_update_current(tshift);
+				} else {
+					int fffb_now;
+					tshift->timeout = FFFB_STEP;
+					AM_TIME_GetClock(&fffb_now);
+					if ((fffb_now - tshift->fffb_start) > FFFB_JUMP_STEP) {
+						AM_DEBUG(1, "[timeshift] now:%d start:%d", fffb_now, tshift->fffb_start);
+						/*notify by each step for fffb*/
+						aml_timeshift_notify(tshift, NULL, AM_FALSE);
+
+						am_timeshift_fffb(tshift, &cmd);
+						aml_timeshift_update_current(tshift);
+					}
+				}
+			} else {
+				if (alarm_eof) {
+					/*not too noisy*/
+					tshift->timeout = 1000;
+
+					AM_AV_TimeshiftInfo_t info;
+					AM_DEBUG(1, "[timeshift] alarm eof: Playback End");
+//					AM_EVT_Signal(tshift->dev->dev_no, AM_AV_EVT_PLAYER_EOF, NULL);
+					aml_timeshift_update(tshift, &info);
+					info.current_time = info.full_time;
+					aml_timeshift_notify(tshift, &info, AM_FALSE);
+				}
+			}
+		} else {
+			if (!write_pass)
+				aml_timeshift_update_current(tshift);
+
+			if (tshift->state == AV_TIMESHIFT_STAT_PAUSE) {
+				if (tshift->pause_time == 0) {
+					tshift->pause_time = tshift->current;
+					AM_DEBUG(1, "[timeshift] paused time: %d", tshift->pause_time);
+				}
+			}
+
+			if (do_update)
+			{
+				if (ioctl(tshift->ts.fd, AMSTREAM_IOC_AB_STATUS, (unsigned long)&astatus) != -1 &&
+					((has_video)? (ioctl(tshift->ts.fd, AMSTREAM_IOC_VB_STATUS, (unsigned long)&vstatus) != -1) : AM_TRUE))
+				{
+					int play_eof = 0;
+
+					AM_DEBUG(1, "[timeshift] is_playback:%d, loop:%d, timeout:%d len:%d inj:%d, cur:%d, delay:%d",
+						is_playback_mode,
+						tshift->file->loop,
+						tshift->timeout,
+						len,
+						tshift->inject_size,
+						tshift->current,
+						aml_timeshift_get_delay(tshift));
+
+					/*no data available in playback only mode*/
+					if (is_playback_mode
+						&& tshift->state != AV_TIMESHIFT_STAT_PAUSE
+						&& abs(tshift->current - aml_timeshift_get_delay(tshift)) >= tshift->end)
+					{
+						if (playback_alen == astatus.status.data_len &&
+							playback_vlen == vstatus.status.data_len)
+						{
+							AM_AV_TimeshiftInfo_t info;
+							AM_DEBUG(1, "[timeshift] Playback End");
+							aml_timeshift_update(tshift, &info);
+							info.current_time = info.full_time;
+							aml_timeshift_notify(tshift, &info, AM_FALSE);
+//							AM_EVT_Signal(tshift->dev->dev_no, AM_AV_EVT_PLAYER_EOF, NULL);
+							play_eof = 1;
+						}
+						else
+						{
+							playback_alen = astatus.status.data_len;
+							playback_vlen = vstatus.status.data_len;
+						}
+					}
+
+					if (tshift->current <= tshift->start) {
+						AM_DEBUG(1, "[timeshift] reaches start");
+					} else if (tshift->current >= tshift->end) {
+						AM_DEBUG(1, "[timeshift] reaches end");
+					}
+
+					if (tshift->state == AV_TIMESHIFT_STAT_PLAY
+						&& !play_eof)
+					{
+						/********Skip inject error*********/
+						if (has_audio && (abuf_len != astatus.status.data_len)) {
+							abuf_len = astatus.status.data_len;
+							skip_flag_count &= 0xFF00;
+						}
+						if (has_video && (vbuf_len != vstatus.status.data_len)) {
+							vbuf_len =vstatus.status.data_len;
+							skip_flag_count &= 0xFF;
+						}
+
+						if (tshift->current > 0
+							&& ((has_video) ? (vstatus.status.data_len == vbuf_len) : AM_FALSE)) {
+							skip_flag_count += 0x100;
+						}
+						if (tshift->current > 0
+							&& ((has_audio) ? (astatus.status.data_len == abuf_len) : AM_FALSE)) {
+							skip_flag_count += 0x1;
+						}
+
+						if ((skip_flag_count & 0xff) >= 4
+							|| (skip_flag_count & 0xff00) >= 0x400) {
+							AM_DEBUG(1, "[timeshift] av buf stuck, reset DISABLED, skip_cnt:0x%04x", skip_flag_count);
+							if (tshift->dev->replay_enable) {
+								am_timeshift_reset_continue(tshift, -1, AM_TRUE);
+								vbuf_len = 0;
+								abuf_len = 0;
+								skip_flag_count=0;
+							}
+						}
+					}
+
+				}
+			}
+		}
+
+		if (tshift->timeout == -1)
+		{
+			pthread_mutex_lock(&tshift->lock);
+			pthread_cond_wait(&tshift->cond, &tshift->lock);
+			pthread_mutex_unlock(&tshift->lock);
+		}
+		else if (tshift->timeout > 0)
+		{
+			pthread_mutex_lock(&tshift->lock);
+			AM_TIME_GetTimeSpecTimeout(tshift->timeout, &rt);
+			pthread_cond_timedwait(&tshift->cond, &tshift->lock, &rt);
+			pthread_mutex_unlock(&tshift->lock);
+		}
+	}
+
+	if (tshift->dev->crypt_ops && tshift->dev->crypt_ops->close) {
+		tshift->dev->crypt_ops->close(tshift->dev->cryptor);
+		tshift->dev->cryptor = NULL;
+	}
+
+	AM_DEBUG(1, "[timeshift] timeshift player thread exit now");
+	{
+		AM_AV_TimeshiftInfo_t info;
+		aml_timeshift_update(tshift, &info);
+		info.status = AV_TIMESHIFT_STAT_EXIT;
+		aml_timeshift_notify(tshift, &info, AM_FALSE);
+	}
+
+	ioctl(tshift->ts.vid_fd, AMSTREAM_IOC_TRICKMODE, TRICKMODE_NONE);
+	AM_FileEcho(VID_BLACKOUT_FILE, tshift->dev->video_blackout ? "1" : "0");
+	AM_DEBUG(1, "[timeshift] timeshift player thread exit end");
+	return NULL;
+}
+
+static AM_ErrorCode_t aml_timeshift_fill_data(AM_AV_Device_t *dev, uint8_t *data, int size)
+{
+	AV_TimeshiftData_t *tshift = (AV_TimeshiftData_t *)dev->timeshift_player.drv_data;
+	int now;
+
+	if (tshift)
+	{
+		ssize_t ret;
+
+		if (size > 0 && !tshift->rate)
+		{
+			AM_TIME_GetClock(&now);
+			if (! tshift->rtime)
+			{
+				tshift->rtotal = 0;
+				tshift->rtime = now;
+			}
+			else
+			{
+				if ((now - tshift->rtime) >= 3000)
+				{
+					tshift->rtotal += size;
+					/*Calcaulate the rate*/
+					tshift->rate = (tshift->rtotal*1000)/(now - tshift->rtime);
+					if (tshift->rate && tshift->file->loop)
+					{
+						/*Calculate the file size*/
+						tshift->file->size = (loff_t)tshift->rate * (loff_t)(tshift->duration / 1000);
+						pthread_cond_signal(&tshift->cond);
+						AM_DEBUG(1, "zzz @@@wirte record data %lld bytes in %d ms,so the rate is assumed to %d Bps, ring file size %lld",
+							tshift->rtotal, now - tshift->rtime, tshift->rate, tshift->file->size);
+					}
+					else
+					{
+						tshift->rtime = 0;
+						AM_DEBUG(1, "zzz rtime =  0");
+					}
+				}
+				else
+				{
+					tshift->rtotal += size;
+				}
+			}
+		}
+
+		ret = AM_TFile_Write(tshift->file, data, size, NULL);
+		if (ret != (ssize_t)size)
+		{
+			AM_DEBUG(1, "Write timeshift data to file failed");
+			/*A write error*/
+			return AM_AV_ERR_SYS;
+		}
+	}
+
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t aml_timeshift_cmd(AM_AV_Device_t *dev, AV_PlayCmd_t cmd, void *para)
+{
+	AV_TimeshiftData_t *data;
+	AV_PlayCmdPara_t cmd_para;
+
+	data = (AV_TimeshiftData_t *)dev->timeshift_player.drv_data;
+
+	pthread_mutex_lock(&data->lock);
+	timeshift_cmd_init(&cmd_para, cmd);
+	if (cmd == AV_PLAY_FF || cmd == AV_PLAY_FB)
+		cmd_para.speed.speed = (long)para;
+	else if (cmd == AV_PLAY_SEEK)
+		cmd_para.seek.seek_pos = ((AV_FileSeekPara_t *)para)->pos;
+	timeshift_cmd_put(data, &cmd_para);
+	AM_DEBUG(5, ">>>set cmd:%d pos:%d", cmd, cmd_para.seek.seek_pos);
+
+#if 0
+	/*cmd obsoleted, use aml_switch_ts_audio_fmt instead*/
+	if (cmd == AV_PLAY_SWITCH_AUDIO)
+	{
+		AV_TSPlayPara_t *audio_para = (AV_TSPlayPara_t *)para;
+		if (audio_para)
+		{
+			int i;
+
+			for (i=0; i<data->para.para.media_info.aud_cnt; i++)
+			{
+				if (data->para.para.media_info.audios[i].pid == audio_para->apid &&
+					data->para.para.media_info.audios[i].fmt == audio_para->afmt)
+				{
+					data->tp.apid = audio_para->apid;
+					data->tp.afmt = audio_para->afmt;
+					break;
+				}
+			}
+		}
+	}
+#endif
+	pthread_cond_signal(&data->cond);
+	pthread_mutex_unlock(&data->lock);
+
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t aml_timeshift_get_info(AM_AV_Device_t *dev, AM_AV_TimeshiftInfo_t *info)
+{
+	AV_TimeshiftData_t *data;
+
+	data = (AV_TimeshiftData_t *)dev->timeshift_player.drv_data;
+
+	pthread_mutex_lock(&data->lock);
+	*info = data->info;
+	pthread_mutex_unlock(&data->lock);
+
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t aml_timeshift_get_tfile(AM_AV_Device_t *dev, AM_TFile_t *tfile)
+{
+	AV_TimeshiftData_t *data;
+
+	data = (AV_TimeshiftData_t *)dev->timeshift_player.drv_data;
+
+	pthread_mutex_lock(&data->lock);
+	*tfile = data->file;
+	pthread_mutex_unlock(&data->lock);
+
+	return AM_SUCCESS;
+}
+
+extern unsigned long CMEM_getPhys(unsigned long virts);
+
+/**\brief 解码JPEG数据*/
+static AM_ErrorCode_t aml_decode_jpeg(AV_JPEGData_t *jpeg, const uint8_t *data, int len, int mode, void *para)
+{
+	AM_ErrorCode_t ret = AM_SUCCESS;
+// #if !defined(ANDROID)
+// 	AV_JPEGDecodePara_t *dec_para = (AV_JPEGDecodePara_t *)para;
+// 	AV_JPEGDecState_t s;
+// 	AM_Bool_t decLoop = AM_TRUE;
+// 	int decState = 0;
+// 	int try_count = 0;
+// 	int decode_wait = 0;
+// 	const uint8_t *src = data;
+// 	int left = len;
+// 	AM_OSD_Surface_t *surf = NULL;
+// 	jpegdec_info_t info;
+
+// 	char tmp_buf[64];
+
+// 	s = AV_JPEG_DEC_STAT_INFOCONFIG;
+// 	while (decLoop)
+// 	{
+// 		if (jpeg->dec_fd == -1)
+// 		{
+// 			jpeg->dec_fd = open(JPEG_DEC_FILE, O_RDWR);
+// 			if (jpeg->dec_fd != -1)
+// 			{
+// 				s = AV_JPEG_DEC_STAT_INFOCONFIG;
+// 			}
+// 			else
+// 			{
+// 				try_count++;
+// 				if (try_count > 40)
+// 				{
+// 					AM_DEBUG(1, "jpegdec init timeout");
+// 					try_count=0;
+// 					ret = aml_init_jpeg(jpeg);
+// 					if (ret != AM_SUCCESS)
+// 						break;
+// 				}
+// 				usleep(10000);
+// 				continue;
+// 			}
+// 		}
+// 		else
+// 		{
+// 			decState = ioctl(jpeg->dec_fd, JPEGDEC_IOC_STAT);
+
+// 			if (decState & JPEGDEC_STAT_ERROR)
+// 			{
+// 				AM_DEBUG(1, "jpegdec JPEGDEC_STAT_ERROR");
+// 				ret = AM_AV_ERR_DECODE;
+// 				break;
+// 			}
+
+// 			if (decState & JPEGDEC_STAT_UNSUPPORT)
+// 			{
+// 				AM_DEBUG(1, "jpegdec JPEGDEC_STAT_UNSUPPORT");
+// 				ret = AM_AV_ERR_DECODE;
+// 				break;
+// 			}
+
+// 			if (decState & JPEGDEC_STAT_DONE)
+// 				break;
+
+// 			if (decState & JPEGDEC_STAT_WAIT_DATA)
+// 			{
+// 				if (left > 0)
+// 				{
+// 					int send = AM_MIN(left, JPEG_WRTIE_UNIT);
+// 					int rc;
+// 					rc = write(jpeg->vbuf_fd, src, send);
+// 					if (rc == -1)
+// 					{
+// 						AM_DEBUG(1, "write data to the jpeg decoder failed");
+// 						ret = AM_AV_ERR_DECODE;
+// 						break;
+// 					}
+// 					left -= rc;
+// 					src  += rc;
+// 				}
+// 				else if (decode_wait == 0)
+// 				{
+// 					int i, times = JPEG_WRTIE_UNIT/sizeof(tmp_buf);
+
+// 					memset(tmp_buf, 0, sizeof(tmp_buf));
+
+// 					for (i=0; i<times; i++)
+// 						write(jpeg->vbuf_fd, tmp_buf, sizeof(tmp_buf));
+// 					decode_wait++;
+// 				}
+// 				else
+// 				{
+// 					if (decode_wait > 300)
+// 					{
+// 						AM_DEBUG(1, "jpegdec wait data error");
+// 						ret = AM_AV_ERR_DECODE;
+// 						break;
+// 					}
+// 					decode_wait++;
+// 					usleep(10);
+// 				}
+// 			}
+
+// 			switch (s)
+// 			{
+// 				case AV_JPEG_DEC_STAT_INFOCONFIG:
+// 					if (decState & JPEGDEC_STAT_WAIT_INFOCONFIG)
+// 					{
+// 						if (ioctl(jpeg->dec_fd, JPEGDEC_IOC_INFOCONFIG, 0) == -1)
+// 						{
+// 							AM_DEBUG(1, "jpegdec JPEGDEC_IOC_INFOCONFIG error");
+// 							ret = AM_AV_ERR_DECODE;
+// 							decLoop = AM_FALSE;
+// 						}
+// 						s = AV_JPEG_DEC_STAT_INFO;
+// 					}
+// 					break;
+// 				case AV_JPEG_DEC_STAT_INFO:
+// 					if (decState & JPEGDEC_STAT_INFO_READY)
+// 					{
+// 						if (ioctl(jpeg->dec_fd, JPEGDEC_IOC_INFO, &info) == -1)
+// 						{
+// 							AM_DEBUG(1, "jpegdec JPEGDEC_IOC_INFO error");
+// 							ret = AM_AV_ERR_DECODE;
+// 							decLoop = AM_FALSE;
+// 						}
+// 						if (mode & AV_GET_JPEG_INFO)
+// 						{
+// 							AM_AV_JPEGInfo_t *jinfo = (AM_AV_JPEGInfo_t *)para;
+// 							jinfo->width    = info.width;
+// 							jinfo->height   = info.height;
+// 							jinfo->comp_num = info.comp_num;
+// 							decLoop = AM_FALSE;
+// 						}
+// 						AM_DEBUG(2, "jpegdec width:%d height:%d", info.width, info.height);
+// 						s = AV_JPEG_DEC_STAT_DECCONFIG;
+// 					}
+// 					break;
+// 				case AV_JPEG_DEC_STAT_DECCONFIG:
+// 					if (decState & JPEGDEC_STAT_WAIT_DECCONFIG)
+// 					{
+// 						jpegdec_config_t config;
+// 						int dst_w, dst_h;
+
+// 						switch (dec_para->para.angle)
+// 						{
+// 							case AM_AV_JPEG_CLKWISE_0:
+// 							default:
+// 								dst_w = info.width;
+// 								dst_h = info.height;
+// 							break;
+// 							case AM_AV_JPEG_CLKWISE_90:
+// 								dst_w = info.height;
+// 								dst_h = info.width;
+// 							break;
+// 							case AM_AV_JPEG_CLKWISE_180:
+// 								dst_w = info.width;
+// 								dst_h = info.height;
+// 							break;
+// 							case AM_AV_JPEG_CLKWISE_270:
+// 								dst_w = info.height;
+// 								dst_h = info.width;
+// 							break;
+// 						}
+
+// 						if (dec_para->para.width > 0)
+// 							dst_w = AM_MIN(dst_w, dec_para->para.width);
+// 						if (dec_para->para.height > 0)
+// 							dst_h = AM_MIN(dst_h, dec_para->para.height);
+
+// 						ret = AM_OSD_CreateSurface(AM_OSD_FMT_YUV_420, dst_w, dst_h, AM_OSD_SURFACE_FL_HW, &surf);
+// 						if (ret != AM_SUCCESS)
+// 						{
+// 							AM_DEBUG(1, "cannot create the YUV420 surface");
+// 							decLoop = AM_FALSE;
+// 						}
+// 						else
+// 						{
+// 							config.addr_y = CMEM_getPhys((unsigned long)surf->buffer);
+// 							config.addr_u = config.addr_y+CANVAS_ALIGN(surf->width)*surf->height;
+// 							config.addr_v = config.addr_u+CANVAS_ALIGN(surf->width/2)*(surf->height/2);
+// 							config.opt    = dec_para->para.option;
+// 							config.dec_x  = 0;
+// 							config.dec_y  = 0;
+// 							config.dec_w  = surf->width;
+// 							config.dec_h  = surf->height;
+// 							config.angle  = dec_para->para.angle;
+// 							config.canvas_width = CANVAS_ALIGN(surf->width);
+
+// 							if (ioctl(jpeg->dec_fd, JPEGDEC_IOC_DECCONFIG, &config) == -1)
+// 							{
+// 								AM_DEBUG(1, "jpegdec JPEGDEC_IOC_DECCONFIG error");
+// 								ret = AM_AV_ERR_DECODE;
+// 								decLoop = AM_FALSE;
+// 							}
+// 							s = AV_JPEG_DEC_STAT_RUN;
+// 						}
+// 					}
+// 				break;
+
+// 				default:
+// 					break;
+// 			}
+// 		}
+// 	}
+
+// 	if (surf)
+// 	{
+// 		if (ret == AM_SUCCESS)
+// 		{
+// 			dec_para->surface = surf;
+// 		}
+// 		else
+// 		{
+// 			AM_OSD_DestroySurface(surf);
+// 		}
+// 	}
+// #else
+// 	UNUSED(jpeg);
+// 	UNUSED(data);
+// 	UNUSED(len);
+// 	UNUSED(mode);
+// 	UNUSED(para);
+// #endif
+
+	return ret;
+}
+
+static AM_ErrorCode_t aml_open(AM_AV_Device_t *dev, const AM_AV_OpenPara_t *para)
+{
+//#ifndef ANDROID
+	char buf[32];
+	int v;
+
+	UNUSED(para);
+	pthread_cond_init(&gAVMonCond, NULL);
+	if (AM_FileRead(VID_AXIS_FILE, buf, sizeof(buf)) == AM_SUCCESS)
+	{
+		int left, top, right, bottom;
+
+		if (sscanf(buf, "%d %d %d %d", &left, &top, &right, &bottom) == 4)
+		{
+			dev->video_x = left;
+			dev->video_y = top;
+			dev->video_w = right-left;
+			dev->video_h = bottom-top;
+		}
+	}
+	if (AM_FileRead(VID_CONTRAST_FILE, buf, sizeof(buf)) == AM_SUCCESS)
+	{
+		if (sscanf(buf, "%d", &v) == 1)
+		{
+			dev->video_contrast = v;
+		}
+	}
+	if (AM_FileRead(VID_SATURATION_FILE, buf, sizeof(buf)) == AM_SUCCESS)
+	{
+		if (sscanf(buf, "%d", &v) == 1)
+		{
+			dev->video_saturation = v;
+		}
+	}
+	if (AM_FileRead(VID_BRIGHTNESS_FILE, buf, sizeof(buf)) == AM_SUCCESS)
+	{
+		if (sscanf(buf, "%d", &v) == 1)
+		{
+			dev->video_brightness = v;
+		}
+	}
+	if (AM_FileRead(VID_DISABLE_FILE, buf, sizeof(buf)) == AM_SUCCESS)
+	{
+		if (sscanf(buf, "%d", &v) == 1)
+		{
+			dev->video_enable = v?AM_FALSE:AM_TRUE;
+		}
+	}
+	if (AM_FileRead(VID_BLACKOUT_FILE, buf, sizeof(buf)) == AM_SUCCESS)
+	{
+		if (sscanf(buf, "%d", &v) == 1)
+		{
+			dev->video_blackout = v?AM_TRUE:AM_FALSE;
+		}
+	}
+	if (AM_FileRead(VID_SCREEN_MODE_FILE, buf, sizeof(buf)) == AM_SUCCESS)
+	{
+		if (sscanf(buf, "%d", &v) == 1)
+		{
+			dev->video_mode = v;
+#ifndef 	CHIP_8226H
+			switch(v) {
+				case 0:
+				case 1:
+					dev->video_ratio = AM_AV_VIDEO_ASPECT_AUTO;
+					dev->video_mode = v;
+					break;
+				case 2:
+					dev->video_ratio = AM_AV_VIDEO_ASPECT_4_3;
+					dev->video_mode = AM_AV_VIDEO_DISPLAY_FULL_SCREEN;
+					break;
+				case 3:
+					dev->video_ratio = AM_AV_VIDEO_ASPECT_16_9;
+					dev->video_mode = AM_AV_VIDEO_DISPLAY_FULL_SCREEN;
+					break;
+			}
+ #endif
+		}
+	}
+	if (AM_FileRead(DISP_MODE_FILE, buf, sizeof(buf)) == AM_SUCCESS)
+	{
+		if (!strncmp(buf, "576cvbs", 7) || !strncmp(buf, "576i", 4) || !strncmp(buf, "576i", 4))
+		{
+			dev->vout_w = 720;
+			dev->vout_h = 576;
+		}
+		else if (!strncmp(buf, "480cvbs", 7) || !strncmp(buf, "480i", 4) || !strncmp(buf, "480i", 4))
+		{
+			dev->vout_w = 720;
+			dev->vout_h = 480;
+		}
+		else if (!strncmp(buf, "720p", 4))
+		{
+			dev->vout_w = 1280;
+			dev->vout_h = 720;
+		}
+		else if (!strncmp(buf, "1080i", 5) || !strncmp(buf, "1080p", 5))
+		{
+			dev->vout_w = 1920;
+			dev->vout_h = 1080;
+		}
+	}
+#ifdef CHIP_8226H
+	if (AM_FileRead(VID_ASPECT_RATIO_FILE, buf, sizeof(buf)) == AM_SUCCESS)
+	{
+		if (!strncmp(buf, "auto", 4))
+		{
+			dev->video_ratio = AM_AV_VIDEO_ASPECT_AUTO;
+		}
+		else if (!strncmp(buf, "16x9", 4))
+		{
+			dev->video_ratio = AM_AV_VIDEO_ASPECT_16_9;
+		}
+		else if (!strncmp(buf, "4x3", 3))
+		{
+			dev->video_ratio = AM_AV_VIDEO_ASPECT_4_3;
+		}
+	}
+	if (AM_FileRead(VID_ASPECT_MATCH_FILE, buf, sizeof(buf)) == AM_SUCCESS)
+	{
+		if (!strncmp(buf, "ignore", 4))
+		{
+			dev->video_match = AM_AV_VIDEO_ASPECT_MATCH_IGNORE;
+		}
+		else if (!strncmp(buf, "letter box", 10))
+		{
+			dev->video_match = AM_AV_VIDEO_ASPECT_MATCH_LETTER_BOX;
+		}
+		else if (!strncmp(buf, "pan scan", 8))
+		{
+			dev->video_match = AM_AV_VIDEO_ASPECT_MATCH_PAN_SCAN;
+		}
+		else if (!strncmp(buf, "combined", 8))
+		{
+			dev->video_match = AM_AV_VIDEO_ASPECT_MATCH_COMBINED;
+		}
+	}
+#else
+#ifdef ANDROID
+	if (AM_FileRead(VID_ASPECT_MATCH_FILE, buf, sizeof(buf)) == AM_SUCCESS)
+	{
+		if (sscanf(buf, "%d", &v) == 1)
+		{
+			switch (v)
+			{
+				case 0:
+				case 1:
+					dev->video_match = AM_AV_VIDEO_ASPECT_MATCH_IGNORE;
+					break;
+				case 2:
+					dev->video_match = AM_AV_VIDEO_ASPECT_MATCH_PAN_SCAN;
+					break;
+				case 3:
+					dev->video_match = AM_AV_VIDEO_ASPECT_MATCH_LETTER_BOX;
+					break;
+				case 4:
+					dev->video_match = AM_AV_VIDEO_ASPECT_MATCH_COMBINED;
+					break;
+			}
+		}
+	}
+#endif
+#endif
+//#endif
+
+#if !defined(ADEC_API_NEW)
+	adec_cmd("stop");
+	return AM_SUCCESS;
+#else
+#ifdef USE_ADEC_IN_DVB
+	if (s_audio_cb == NULL)
+		audio_decode_basic_init();
+#endif
+	return AM_SUCCESS;
+#endif
+}
+
+static AM_ErrorCode_t aml_close(AM_AV_Device_t *dev)
+{
+	UNUSED(dev);
+	pthread_cond_destroy(&gAVMonCond);
+	return AM_SUCCESS;
+}
+
+#define ARC_FREQ_FILE "/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq"
+
+static void set_arc_freq(int hi)
+{
+	static int old_freq = 200000;
+	int freq;
+	char buf[32];
+
+	if (AM_FileRead(ARC_FREQ_FILE, buf, sizeof(buf)) == AM_SUCCESS) {
+		sscanf(buf, "%d", &freq);
+		if (hi) {
+			old_freq = freq;
+			snprintf(buf, sizeof(buf), "%d", 300000);
+			AM_FileEcho(ARC_FREQ_FILE, buf);
+		} else {
+			snprintf(buf, sizeof(buf), "%d", old_freq);
+			AM_FileEcho(ARC_FREQ_FILE, buf);
+		}
+	}
+}
+
+static AM_ErrorCode_t set_dec_control(AM_Bool_t enable)
+{
+	char v[32], vv[32];
+	int dc=0;
+	char *pch = v;
+
+	static char *dec_control[] = {
+		DEC_CONTROL_H264,
+		DEC_CONTROL_MPEG12
+	};
+	int cnt = sizeof(dec_control)/sizeof(dec_control[0]);
+	int i;
+	if (enable) {//format: "0xaa|0xbb"
+#ifdef ANDROID
+//		property_get(DEC_CONTROL_PROP, v, "");
+#endif
+		for (i=0; i<cnt; i++) {
+			dc = 0;
+			if (!pch || !pch[0])
+				break;
+			int j = sscanf(pch, "%i", &dc);
+			if (j) {
+				snprintf(vv, 31, "%#x", dc);
+				AM_FileEcho(dec_control[i], vv);
+				AM_DEBUG(1, "dec control: %d==%s\n", i, vv);
+			}
+			pch = strchr(pch, '|');
+			if (pch)
+				pch++;
+		}
+	} else {
+		for (i=0; i<cnt; i++)
+			AM_FileEcho(dec_control[i], "0");
+	}
+
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t aml_open_ts_mode(AM_AV_Device_t *dev)
+{
+	AV_TSData_t *ts;
+	ts = (AV_TSData_t *)malloc(sizeof(AV_TSData_t));
+	if (!ts)
+	{
+		AM_DEBUG(1, "not enough memory");
+		return AM_AV_ERR_NO_MEM;
+	}
+
+	memset(ts, 0, sizeof(*ts));
+	ts->fd     = -1;
+	ts->vid_fd = -1;
+
+	dev->ts_player.drv_data = (void*)ts;
+
+	return AM_SUCCESS;
+}
+
+static int aml_get_audio_digital_raw(void)
+{
+	int mode;
+	char buf[32];
+	/*0:pcm 1:spdif 2:hdmi*/
+	if (AM_FileRead(AUDIO_DSP_DIGITAL_RAW_FILE, buf, sizeof(buf)) >= 0) {
+		sscanf(buf, "%d", &mode);
+	} else {
+		mode = 0;
+	}
+	return mode;
+}
+
+static int aml_calc_sync_mode(AM_AV_Device_t *dev, int has_audio, int has_video, int has_pcr, int afmt, int *force_reason)
+{
+	int is_dts_dolby = 0;
+	int ac3_amaster = 0;
+	int is_digital_output = 0;
+	int tsync_mode = 2;
+
+#define VMASTER   0
+#define AMASTER   1
+#define PCRMASTER 2
+
+	if (force_reason)
+		*force_reason = FORCE_NONE;
+
+#ifdef ANDROID
+	if ((afmt == AFORMAT_AC3) || (afmt == AFORMAT_EAC3)) {
+		char buf[32];
+//		property_get(AC3_AMASTER_PROP, buf, "0");
+		if (!strcmp(buf, "1"))
+			ac3_amaster = 1;
+	}
+#endif
+
+	if (afmt == AFORMAT_AC3 ||
+		afmt == AFORMAT_DTS ||
+		afmt == AFORMAT_EAC3) {
+		is_dts_dolby = 1;
+	}
+
+	tsync_mode = PCRMASTER;
+
+	if (ac3_amaster) {
+		//force
+		tsync_mode = AMASTER;
+		if (force_reason)
+			*force_reason = FORCE_AC3_AMASTER;
+	}
+
+	if ((aml_get_audio_digital_raw() != 0) && is_dts_dolby)
+		tsync_mode = AMASTER;
+
+	if ((tsync_mode == AMASTER) && !has_audio)
+		tsync_mode = VMASTER;
+	else if (ac3_amaster == 0)
+		tsync_mode = PCRMASTER; /*Force use pcrmaster for live-pvr-tf*/
+
+	//printf("tsync mode calc:%d v:%d a:%d af:%d force:%d\n",
+	//	tsync_mode, has_video, has_audio, afmt, force_reason? *force_reason : 0);
+
+	return tsync_mode;
+}
+
+static int aml_set_sync_mode(AM_AV_Device_t *dev, int mode)
+{
+	char mode_str[4];
+	int f_m = _get_tsync_mode_force();
+
+	if (f_m != -1) {
+		mode = f_m;
+		AM_DEBUG(1, "force tsync mode to %d", mode);
+	}
+
+	set_first_frame_nosync();
+	snprintf(mode_str, 4, "%d", mode);
+	AM_DEBUG(1, "set sync mode: %d", mode);
+	return AM_FileEcho(TSYNC_MODE_FILE, mode_str);
+}
+
+static AM_ErrorCode_t aml_start_ts_mode(AM_AV_Device_t *dev, AV_TSPlayPara_t *tp, AM_Bool_t create_thread)
+{
+	AV_TSData_t *ts;
+	int val;
+	AM_Bool_t has_video = VALID_VIDEO(tp->vpid, tp->vfmt);
+	AM_Bool_t has_audio = VALID_AUDIO(tp->apid, tp->afmt);
+	AM_Bool_t has_pcr = VALID_PCR(tp->pcrpid);
+	int sync_mode, sync_force;
+	char vdec_info[256];
+	int double_write_mode = 3;
+
+	if (tp->apid != dev->alt_apid || tp->afmt != dev->alt_afmt) {
+		AM_DEBUG(1, "switch to pending audio: A[%d:%d] -> A[%d:%d]",
+			tp->apid, tp->afmt, dev->alt_apid, dev->alt_afmt);
+		tp->apid = dev->alt_apid;
+		tp->afmt = dev->alt_afmt;
+
+		has_audio = VALID_AUDIO(tp->apid, tp->afmt);
+	}
+
+	AM_DEBUG(1, "aml start ts: V[%d:%d] A[%d:%d] P[%d]", tp->vpid, tp->vfmt, tp->apid, tp->afmt, tp->pcrpid);
+	ts = (AV_TSData_t *)dev->ts_player.drv_data;
+
+	/*patch dec control*/
+	set_dec_control(has_video);
+
+#ifndef ENABLE_PCR
+	if (ts->vid_fd != -1){
+		AM_DEBUG(1, "%s, enable video pause", __FUNCTION__);
+		ioctl(ts->vid_fd, AMSTREAM_IOC_VPAUSE, 1);
+	}else{
+		AM_DEBUG(1, "%s, disenable video pause", __FUNCTION__);
+	}
+#else
+	AM_DEBUG(1, "%s, enable pcr -------", __FUNCTION__);
+#endif
+
+	ts->vid_fd = open(AMVIDEO_FILE, O_RDWR);
+
+#ifndef MPTSONLYAUDIOVIDEO
+	if (check_vfmt_support_sched(tp->vfmt) == AM_FALSE)
+	{
+		ts->fd = open(STREAM_TS_FILE, O_RDWR);
+		if (ts->fd == -1)
+		{
+			AM_DEBUG(1, "cannot open \"/dev/amstream_mpts\" error:%d \"%s\"", errno, strerror(errno));
+			free(ts);
+			return AM_AV_ERR_CANNOT_OPEN_DEV;
+		}
+	}
+	else
+	{
+		ts->fd = open(STREAM_TS_SCHED_FILE, O_RDWR);
+		if (ts->fd == -1)
+		{
+			AM_DEBUG(1, "cannot open \"/dev/amstream_mpts_sched\" error:%d \"%s\"", errno, strerror(errno));
+			free(ts);
+			return AM_AV_ERR_CANNOT_OPEN_DEV;
+		}
+	}
+#ifdef USE_AMSTREAM_SUB_BUFFER
+	AM_DEBUG(1, "try to init subtitle ring buf");
+	int sid = 0xffff;
+	if (ioctl(ts->fd, AMSTREAM_IOC_SID, sid) == -1)
+	{
+		AM_DEBUG(1, "set sub PID failed");
+	}
+#endif
+#else
+	if (ts->fd == -1)
+	{
+
+		AM_DEBUG(1, "aml_start_ts_mode used MPTSONLYAUDIOVIDEO %d %d %d %d", tp->vpid, has_video, tp->apid, has_audio);
+
+		if (has_video && has_audio)
+		{
+			if (check_vfmt_support_sched(tp->vfmt) == AM_FALSE)
+			{
+				ts->fd = open(STREAM_TS_FILE, O_RDWR);
+			}
+			else
+			{
+				ts->fd = open(STREAM_TS_SCHED_FILE, O_RDWR);
+			}
+		}
+		else if ((!has_video) && has_audio)
+		{
+			ts->fd = open(STREAM_TSONLYAUDIO_FILE, O_RDWR);
+		}
+		else if((!has_audio) && has_video)
+		{
+			ts->fd = open(STREAM_TSONLYVIDEO_FILE, O_RDWR);
+		}
+		else
+		{
+			if (check_vfmt_support_sched(tp->vfmt) == AM_FALSE)
+			{
+				ts->fd = open(STREAM_TS_FILE, O_RDWR);
+			}
+			else
+			{
+				ts->fd = open(STREAM_TS_SCHED_FILE, O_RDWR);
+			}
+		}
+
+		if (ts->fd == -1)
+		{
+			AM_DEBUG(1, "cannot open \"/dev/amstream_mpts\" error:%d \"%s\"", errno, strerror(errno));
+			return AM_AV_ERR_CANNOT_OPEN_DEV;
+		}
+	}
+#endif
+
+	if (tp->drm_mode == AM_AV_DRM_WITH_SECURE_INPUT_BUFFER)
+	{
+		if (ioctl(ts->fd, AMSTREAM_IOC_SET_DRMMODE, (void *)(long)tp->drm_mode) == -1)
+		{
+			AM_DEBUG(1, "set drm_mode with secure buffer failed\n");
+			return AM_AV_ERR_SYS;
+		}
+	}
+	if (tp->drm_mode == AM_AV_DRM_WITH_NORMAL_INPUT_BUFFER)
+	{
+		if (ioctl(ts->fd, AMSTREAM_IOC_SET_DRMMODE, (void *)(long)tp->drm_mode) == -1)
+		{
+			AM_DEBUG(1, "set drm_mode with normal buffer failed\n");
+			return AM_AV_ERR_SYS;
+		}
+	}
+
+	/*Set tsync enable/disable*/
+	if ((has_video && has_audio) || has_pcr)
+	{
+		AM_DEBUG(1, "Set tsync enable to 1");
+		aml_set_tsync_enable(1);
+	}
+	else
+	{
+		AM_DEBUG(1, "Set tsync enable to 0");
+		aml_set_tsync_enable(0);
+	}
+
+	if (has_video) {
+		val = tp->vfmt;
+		if (ioctl(ts->fd, AMSTREAM_IOC_VFORMAT, val) == -1)
+		{
+			AM_DEBUG(1, "set video format failed");
+			return AM_AV_ERR_SYS;
+		}
+		val = tp->vpid;
+		if (ioctl(ts->fd, AMSTREAM_IOC_VID, val) == -1)
+		{
+			AM_DEBUG(1, "set video PID failed");
+			return AM_AV_ERR_SYS;
+		}
+#if 0		
+		if (dev->afd_enable) {
+			AM_DEBUG(1, "start afd...");
+			aml_start_afd(dev, tp->vfmt);
+		}
+#endif		
+	}
+
+	/*if ((tp->vfmt == VFORMAT_H264) || (tp->vfmt == VFORMAT_VC1))*/
+	if (has_video) {
+
+		memset(&am_sysinfo,0,sizeof(dec_sysinfo_t));
+		if (tp->vfmt == VFORMAT_VC1)
+		{
+			am_sysinfo.format = VIDEO_DEC_FORMAT_WVC1;
+			am_sysinfo.width  = 1920;
+			am_sysinfo.height = 1080;
+		}
+		else if (tp->vfmt == VFORMAT_H264)
+		{
+			am_sysinfo.format = VIDEO_DEC_FORMAT_H264;
+			am_sysinfo.width  = 1920;
+			am_sysinfo.height = 1080;
+		}
+		else if (tp->vfmt == VFORMAT_AVS)
+		{
+			am_sysinfo.format = VIDEO_DEC_FORMAT_AVS;
+			/*am_sysinfo.width  = 1920;
+			am_sysinfo.height = 1080;*/
+		}
+		else if (tp->vfmt == VFORMAT_HEVC)
+		{
+			am_sysinfo.format = VIDEO_DEC_FORMAT_HEVC;
+			am_sysinfo.width  = 3840;
+			am_sysinfo.height = 2160;
+		}
+
+		if (ioctl(ts->fd, AMSTREAM_IOC_SYSINFO, (unsigned long)&am_sysinfo) == -1)
+		{
+			AM_DEBUG(1, "set AMSTREAM_IOC_SYSINFO");
+			return AM_AV_ERR_SYS;
+		}
+		/*configure double wirte mode*/
+		memset(vdec_info, 0, sizeof(vdec_info));
+		if (tp->vfmt == VFORMAT_HEVC) {
+			sprintf(vdec_info, "hevc_double_write_mode:%d", double_write_mode);
+			configure_vdec_info(ts->fd, vdec_info, strlen(vdec_info));
+		} else if (tp->vfmt == VFORMAT_VP9) {
+			sprintf(vdec_info, "vp9_double_write_mode:%d", double_write_mode);
+			configure_vdec_info(ts->fd, vdec_info, strlen(vdec_info));
+		}
+	}
+
+	if (has_audio) {
+		if ((tp->afmt == AFORMAT_AC3) || (tp->afmt == AFORMAT_DTS)) {
+			//set_arc_freq(1);
+		}
+
+		val = tp->afmt;
+		if (ioctl(ts->fd, AMSTREAM_IOC_AFORMAT, val) == -1)
+		{
+			AM_DEBUG(1, "set audio format failed");
+			return AM_AV_ERR_SYS;
+		}
+		val = tp->apid;
+		if (ioctl(ts->fd, AMSTREAM_IOC_AID, val) == -1)
+		{
+			AM_DEBUG(1, "set audio PID failed");
+			return AM_AV_ERR_SYS;
+		}
+	}
+
+//#ifdef ENABLE_PCR
+	sync_mode = aml_calc_sync_mode(dev, has_audio, has_video, has_pcr, tp->afmt, &sync_force);
+
+	if ((sync_force != FORCE_AC3_AMASTER)) {
+		if (has_pcr) {
+			val = tp->pcrpid;
+			if (ioctl(ts->fd, AMSTREAM_IOC_PCRID, val) == -1)
+			{
+				AM_DEBUG(1, "set PCR PID failed");
+				return AM_AV_ERR_SYS;
+			}
+		}
+	}
+
+	aml_set_sync_mode(dev, sync_mode);
+	if (has_audio && (sync_force != FORCE_AC3_AMASTER)) {
+		if (!show_first_frame_nosync()) {
+#ifdef ANDROID
+			//property_set("sys.amplayer.drop_pcm", "1");
+#endif
+		}
+		AM_FileEcho(ENABLE_RESAMPLE_FILE, "1");
+
+		if (VALID_PID(tp->sub_apid))
+			aml_set_audio_ad(dev, 1, tp->sub_apid, tp->sub_afmt);
+
+		audio_ops->adec_start_decode(ts->fd, tp->afmt, has_video, &ts->adec);
+	}
+//#endif /*ENABLE_PCR*/
+
+	if (ioctl(ts->fd, AMSTREAM_IOC_PORT_INIT, 0) == -1)
+	{
+		AM_DEBUG(1, "amport init failed");
+		return AM_AV_ERR_SYS;
+	}
+	AM_DEBUG(1, "set ts skipbyte to 0");
+	if (ioctl(ts->fd, AMSTREAM_IOC_TS_SKIPBYTE, 0) == -1)
+	{
+		AM_DEBUG(1, "set ts skipbyte failed");
+		return AM_AV_ERR_SYS;
+	}
+
+	AM_TIME_GetClock(&dev->ts_player.av_start_time);
+
+	/*创建AV监控线程*/
+	if (create_thread)
+		aml_start_av_monitor(dev, &dev->ts_player.mon);
+
+	dev->ts_player.play_para = *tp;
+
+	return AM_SUCCESS;
+}
+
+static int aml_close_ts_mode(AM_AV_Device_t *dev, AM_Bool_t destroy_thread)
+{
+	AV_TSData_t *ts;
+	int fd;
+#if 0
+	if (dev->afd_enable)
+		aml_stop_afd(dev);
+#endif
+	if (destroy_thread)
+		aml_stop_av_monitor(dev, &dev->ts_player.mon);
+
+	ts = (AV_TSData_t*)dev->ts_player.drv_data;
+	if (ts->fd != -1)
+		close(ts->fd);
+	if (ts->vid_fd != -1)
+		close(ts->vid_fd);
+
+	aml_set_tsync_enable(0);
+	aml_set_ad_source(&ts->ad, 0, 0, 0, ts->adec);
+	audio_ops->adec_set_decode_ad(0, 0, 0, ts->adec);
+	audio_ops->adec_stop_decode(&ts->adec);
+
+	free(ts);
+
+	dev->ts_player.drv_data = NULL;
+
+//#ifdef ENABLE_PCR
+#ifdef ANDROID
+	//property_set("sys.amplayer.drop_pcm", "0");
+#endif
+	AM_FileEcho(ENABLE_RESAMPLE_FILE, "0");
+	AM_FileEcho(TSYNC_MODE_FILE, "0");
+//#endif /*ENABLE_PCR*/
+
+	//set_arc_freq(0);
+
+	/*unpatch dec control*/
+	set_dec_control(AM_FALSE);
+
+	AM_DEBUG(1, "close ts mode end.");
+	return 0;
+}
+
+static int aml_restart_ts_mode(AM_AV_Device_t *dev, AM_Bool_t destroy_thread)
+{
+	aml_close_ts_mode(dev, destroy_thread);
+	aml_open_ts_mode(dev);
+	setup_forced_pid(&dev->ts_player.play_para);
+	aml_start_ts_mode(dev, &dev->ts_player.play_para, destroy_thread);
+	return 0;
+}
+
+static inline AM_AV_VideoAspectRatio_t
+convert_aspect_ratio(enum E_ASPECT_RATIO euAspectRatio)
+{
+	switch (euAspectRatio) {
+	case ASPECT_RATIO_16_9:
+		return AM_AV_VIDEO_ASPECT_16_9;
+	case ASPECT_RATIO_4_3:
+		return AM_AV_VIDEO_ASPECT_4_3;
+	default:
+		return AM_AV_VIDEO_ASPECT_AUTO;
+	}
+	return AM_AV_VIDEO_ASPECT_AUTO;
+}
+
+int am_av_restart_pts_repeat_count = 2;
+
+/**\brief AV buffer 监控线程*/
+static void* aml_av_monitor_thread(void *arg)
+{
+	AM_AV_Device_t *dev = (AM_AV_Device_t *)arg;
+	AM_Bool_t adec_start = AM_FALSE;
+	AM_Bool_t av_paused = AM_TRUE;
+	AM_Bool_t has_audio;
+	AM_Bool_t has_video;
+	AM_Bool_t bypass_di = AM_FALSE;
+	AM_Bool_t drop_b_frame = AM_FALSE;
+	AM_Bool_t is_hd_video = AM_FALSE;
+	AM_Bool_t audio_scrambled = AM_FALSE;
+	AM_Bool_t video_scrambled = AM_FALSE;
+	AM_Bool_t no_audio_data = AM_TRUE, no_video_data = AM_TRUE, no_data_evt = AM_FALSE;
+	AM_Bool_t no_video = AM_TRUE;
+	AM_Bool_t has_amaster = AM_FALSE;
+	AM_Bool_t need_replay;
+	int resample_type = 0;
+	int next_resample_type = resample_type;
+	int now, next_resample_start_time = 0;
+	int abuf_level = 0, vbuf_level = 0;
+	int abuf_size = 0, vbuf_size = 0;
+	unsigned int abuf_read_ptr = 0, vbuf_read_ptr = 0;
+	unsigned int last_abuf_read_ptr = 0, last_vbuf_read_ptr = 0;
+	int arp_stop_time = 0, vrp_stop_time = 0;
+	int arp_stop_dur = 0, vrp_stop_dur = 0;
+	int apts = 0, vpts = 0, last_apts = 0, last_vpts = 0;
+	int dmx_apts = 0, dmx_vpts = 0, last_dmx_apts = 0, last_dmx_vpts = 0;
+	int apts_stop_time = 0, vpts_stop_time = 0, apts_stop_dur = 0, vpts_stop_dur = 0;
+	int dmx_apts_stop_time = 0, dmx_vpts_stop_time = 0, dmx_apts_stop_dur = 0, dmx_vpts_stop_dur = 0;
+	int tsync_mode, vmaster_time = 0, vmaster_dur = 0;
+	int abuf_level_empty_time = 0, abuf_level_empty_dur = 0, vbuf_level_empty_time = 0, vbuf_level_empty_dur = 0;
+	int down_audio_cache_time = 0, down_video_cache_time = 0;
+	int vdec_stop_time = 0, vdec_stop_dur = 0;
+	int checkin_firstapts = 0, checkin_firstvpts = 0;
+	int apts_discontinue = 0, vpts_discontinue = 0;
+	struct am_io_param astatus;
+	struct am_io_param vstatus;
+	int vdec_status, frame_width, frame_height, aspect_ratio;
+	int frame_width_old = -1, frame_height_old = -1, aspect_ratio_old = -1;
+	struct timespec rt;
+	char buf[32];
+	AM_Bool_t is_avs_plus = AM_FALSE;
+	int avs_fmt = 0;
+
+	unsigned int vframes_now = 0, vframes_last = 0;
+
+	int mChange_audio_flag = -1;
+	//int mCur_audio_digital_raw_value = 0;
+	int is_dts_dolby = 0, tsync_pcr_mode = 0;
+
+	AV_Monitor_t *mon;
+	AV_TSData_t *ts,ts_temp;
+	AV_TSPlayPara_t *tp;
+	AV_InjectData_t *inj;
+	unsigned int cur_time = 0;
+	unsigned int last_replay_time = 0;
+#define REPLAY_TIME_INTERVAL   1000
+
+	int replay_done = 0;
+
+	if (dev->mode == AV_TIMESHIFT) {
+		AV_TimeshiftData_t *tshift_d = (AV_TimeshiftData_t*)dev->timeshift_player.drv_data;
+		mon = &dev->timeshift_player.mon;
+		tp = &tshift_d->tp;
+		ts = &tshift_d->ts;
+	} else if (dev->mode == AV_INJECT){
+		mon = &dev->ts_player.mon;
+		tp = &dev->ts_player.play_para;
+		inj = (AV_InjectData_t *)dev->inject_player.drv_data;
+		ts_temp.fd = (inj->vid_fd != -1) ? inj->vid_fd : inj-> aud_fd;
+		ts_temp.vid_fd = inj->cntl_fd;
+		ts_temp.adec = inj->adec;
+		ts = &ts_temp;
+	} else {//ts mode default
+		mon = &dev->ts_player.mon;
+		tp = &dev->ts_player.play_para;
+		ts = (AV_TSData_t*)dev->ts_player.drv_data;
+	}
+
+	has_audio = VALID_AUDIO(tp->apid, tp->afmt);
+	has_video = VALID_VIDEO(tp->vpid, tp->vfmt);
+
+#ifndef ENABLE_PCR
+	if (!show_first_frame_nosync()) {
+#ifdef ANDROID
+		//property_set("sys.amplayer.drop_pcm", "1");
+#endif
+	}
+#else
+	av_paused  = AM_FALSE;
+	adec_start = (adec_handle != NULL);
+#endif
+
+	if (dev->mode != AV_TIMESHIFT)
+		AM_FileEcho(VID_BLACKOUT_FILE, dev->video_blackout ? "1" : "0");
+
+	pthread_mutex_lock(&gAVMonLock);
+
+	if (tp->afmt == AFORMAT_AC3 ||
+		tp->afmt == AFORMAT_DTS ||
+		tp->afmt == AFORMAT_EAC3) {
+		is_dts_dolby = 1;
+	}
+
+	while (mon->av_thread_running) {
+
+		if (!adec_start || (has_video && no_video))
+			AM_TIME_GetTimeSpecTimeout(20, &rt);
+		else
+			AM_TIME_GetTimeSpecTimeout(200, &rt);
+
+		pthread_cond_timedwait(&gAVMonCond, &gAVMonLock, &rt);
+
+		if (! mon->av_thread_running)
+		{
+			AM_DEBUG(1,"[aml_av_monitor_thread] ending");
+			break;
+		}
+
+		if (is_dts_dolby == 1) {
+			if (mChange_audio_flag == -1) {
+				mChange_audio_flag = aml_get_audio_digital_raw();
+			} else if (mChange_audio_flag != aml_get_audio_digital_raw()) {
+				mChange_audio_flag = aml_get_audio_digital_raw();
+				dev->audio_switch = AM_TRUE;
+			}
+		}
+		//switch audio pid or fmt
+		if (dev->audio_switch == AM_TRUE)
+		{
+			aml_switch_ts_audio_fmt(dev, ts, tp);
+			dev->audio_switch = AM_FALSE;
+			adec_start = (adec_handle != NULL);
+		}
+
+		has_audio = VALID_AUDIO(tp->apid, tp->afmt);
+		has_video = VALID_VIDEO(tp->vpid, tp->vfmt);
+		if ((!has_audio) && (!has_video)) {
+			AM_DEBUG(1,"Audio && Video is None");
+			continue;
+		} else {
+			//AM_DEBUG(1,"Audio:%d or Video:%d is Running.",has_audio,has_video);
+		}
+
+		AM_TIME_GetClock(&now);
+		if (has_audio && (ioctl(ts->fd, AMSTREAM_IOC_AB_STATUS, (unsigned long)&astatus) != -1)) {
+			abuf_size  = astatus.status.size;
+			abuf_level = astatus.status.data_len;
+			abuf_read_ptr = astatus.status.read_pointer;
+		} else {
+			if (has_audio)
+				AM_DEBUG(1, "cannot get audio buffer status [%s]", strerror(errno));
+			abuf_size  = 0;
+			abuf_level = 0;
+			abuf_read_ptr = 0;
+		}
+
+		if (has_video && (ioctl(ts->fd, AMSTREAM_IOC_VB_STATUS, (unsigned long)&vstatus) != -1)) {
+			vbuf_size  = vstatus.status.size;
+			vbuf_level = vstatus.status.data_len;
+			vbuf_read_ptr = vstatus.status.read_pointer;
+			//is_hd_video = vstatus.vstatus.width > 720;
+		} else {
+			if (has_video)
+				AM_DEBUG(1, "cannot get video buffer status");
+			vbuf_size  = 0;
+			vbuf_level = 0;
+			vbuf_read_ptr = 0;
+		}
+
+		if (vbuf_level == 0) {
+			if(!vbuf_level_empty_time)
+				vbuf_level_empty_time = now;
+			vbuf_level_empty_dur = now - vbuf_level_empty_time;
+		} else {
+			vbuf_level_empty_time = 0;
+			vbuf_level_empty_dur = 0;
+		}
+		if (abuf_level == 0) {
+			if (!abuf_level_empty_time)
+				abuf_level_empty_time = now;
+			abuf_level_empty_dur = now - abuf_level_empty_time;
+		} else {
+			abuf_level_empty_time = 0;
+			abuf_level_empty_dur = 0;
+		}
+		if (abuf_read_ptr == last_abuf_read_ptr) {
+			if (!arp_stop_time)
+				arp_stop_time = now;
+			arp_stop_dur = now - arp_stop_time;
+		} else {
+			arp_stop_time = 0;
+			arp_stop_dur  = 0;
+		}
+		last_abuf_read_ptr = abuf_read_ptr;
+
+		if (vbuf_read_ptr == last_vbuf_read_ptr) {
+			if(!vrp_stop_time)
+				vrp_stop_time = now;
+			vrp_stop_dur = now - vrp_stop_time;
+		} else {
+			vrp_stop_time = 0;
+			vrp_stop_dur  = 0;
+		}
+		last_vbuf_read_ptr = vbuf_read_ptr;
+		//check video frame available
+		if (has_video && !no_video_data) {
+#ifdef ANDROID
+			if (AM_FileRead(VIDEO_NEW_FRAME_COUNT_FILE, buf, sizeof(buf)) >= 0) {
+				sscanf(buf, "%i", &vframes_now);
+				if ((vframes_now >= 1) ) {
+					if (no_video) {
+						AM_DEBUG(1, "[avmon] video available SwitchSourceTime = %fs",getUptimeSeconds());
+//						AM_EVT_Signal(dev->dev_no, AM_AV_EVT_VIDEO_AVAILABLE, NULL);
+					}
+					no_video = AM_FALSE;
+					} else {
+						no_video = AM_TRUE;
+					}
+					vframes_last = vframes_now;
+				} else {
+				AM_DEBUG(1, "[avmon] cannot read \"%s\"", VIDEO_NEW_FRAME_TOGGLED_FILE);
+				vframes_now = 0;
+			}
+#endif
+		}
+
+		if (has_video)
+		{
+			memset(&vstatus, 0, sizeof(vstatus));
+			if (ioctl(ts->fd, AMSTREAM_IOC_VDECSTAT, (unsigned long)&vstatus) != -1) {
+				is_hd_video = (vstatus.vstatus.width > 720)? 1 : 0;
+				vdec_status = vstatus.vstatus.status;
+				frame_width = vstatus.vstatus.width;
+				frame_height= vstatus.vstatus.height;
+				aspect_ratio = vstatus.vstatus.euAspectRatio;
+				//AM_DEBUG(1, "vdec width %d height %d status 0x%08x", frame_width, frame_height, vdec_status);
+				if (!no_video) {
+					if (frame_width != frame_width_old || frame_height != frame_height_old) {
+						AM_DEBUG(1, "[avmon] video resolution changed: %dx%d -> %dx%d",
+							frame_width_old, frame_height_old,
+							frame_width, frame_height);
+						frame_width_old = frame_width;
+						frame_height_old = frame_height;
+						{
+							AM_AV_VideoStatus_t vstatus;
+							memset(&vstatus, 0, sizeof(vstatus));
+							vstatus.src_w = frame_width;
+							vstatus.src_h = frame_height;
+//							AM_EVT_Signal(dev->dev_no, AM_AV_EVT_VIDEO_RESOLUTION_CHANGED, &vstatus);
+						}
+					}
+					if (aspect_ratio != aspect_ratio_old) {
+						AM_DEBUG(1, "[avmon] video aspect ratio changed: %d -> %d(kernel's definition)",
+							aspect_ratio_old, aspect_ratio);
+						aspect_ratio_old = aspect_ratio;
+//						AM_EVT_Signal(dev->dev_no, AM_AV_EVT_VIDEO_ASPECT_RATIO_CHANGED, (void*)convert_aspect_ratio(aspect_ratio));
+					}
+				}
+			} else {
+				vdec_status = 0;
+				frame_width = 0;
+				frame_height= 0;
+			}
+		}
+		// if (AM_FileRead(AVS_PLUS_DECT_FILE, buf, sizeof(buf)) >= 0) {
+		// 	sscanf(buf, "%d", &avs_fmt);
+		// } else {
+		// 	//AM_DEBUG(1, "cannot read \"%s\"", AVS_PLUS_DECT_FILE);
+		// 	avs_fmt = 0;
+		// }
+		avs_fmt = 0;
+		//AM_DEBUG(1, "avs_fmt: \"%x\"", avs_fmt);
+		if (avs_fmt == 0x148) //bit8
+			is_avs_plus = AM_TRUE;
+		else
+			is_avs_plus = AM_FALSE;
+
+		if (AM_FileRead(AUDIO_PTS_FILE, buf, sizeof(buf)) >= 0) {
+			sscanf(buf+2, "%x", &apts);
+		} else {
+			AM_DEBUG(1, "[avmon] cannot read \"%s\"", AUDIO_PTS_FILE);
+			apts = 0;
+		}
+
+		if (AM_FileRead(VIDEO_PTS_FILE, buf, sizeof(buf)) >= 0) {
+			sscanf(buf+2, "%x", &vpts);
+		} else {
+			AM_DEBUG(1, "[avmon] cannot read \"%s\"", VIDEO_PTS_FILE);
+			vpts = 0;
+		}
+
+		if (AM_FileRead(TSYNC_MODE_FILE, buf, sizeof(buf)) >= 0) {
+			sscanf(buf, "%d", &tsync_mode);
+		} else {
+			tsync_mode = 1;
+		}
+
+		if (tsync_mode == 0) {
+			if (vmaster_time == 0) {
+				vmaster_time = now;
+			}
+			vmaster_dur = now - vmaster_time;
+		} else {
+			vmaster_time = 0;
+			vmaster_dur = 0;
+			has_amaster = AM_TRUE;
+		}
+
+		if (AM_FileRead(AUDIO_DMX_PTS_FILE, buf, sizeof(buf)) >= 0) {
+			sscanf(buf, "%u", &dmx_apts);
+		} else {
+			AM_DEBUG(1, "[avmon] cannot read \"%s\"", AUDIO_DMX_PTS_FILE);
+			dmx_apts = 0;
+		}
+
+		if (AM_FileRead(VIDEO_DMX_PTS_FILE, buf, sizeof(buf)) >= 0) {
+			sscanf(buf, "%u", &dmx_vpts);
+		} else {
+			AM_DEBUG(1, "[avmon] cannot read \"%s\"", VIDEO_DMX_PTS_FILE);
+			dmx_vpts = 0;
+		}
+
+		if (AM_FileRead(TSYNC_FIRSTCHECKIN_APTS_FILE, buf, sizeof(buf)) >= 0) {
+			sscanf(buf, "0x%x", &checkin_firstapts);
+		} else {
+			AM_DEBUG(1, "[avmon] cannot read \"%s\"", TSYNC_FIRSTCHECKIN_APTS_FILE);
+			checkin_firstapts = 0;
+		}
+
+		if (AM_FileRead(TSYNC_FIRSTCHECKIN_VPTS_FILE, buf, sizeof(buf)) >= 0) {
+			sscanf(buf, "0x%x", &checkin_firstvpts);
+		} else {
+			AM_DEBUG(1, "[avmon] cannot read \"%s\"", TSYNC_FIRSTCHECKIN_VPTS_FILE);
+			checkin_firstvpts = 0;
+		}
+
+		if (apts == last_apts) {
+			if (!apts_stop_time)
+				apts_stop_time = now;
+			apts_stop_dur = now - apts_stop_time;
+		} else {
+			last_apts = apts;
+			apts_stop_time = 0;
+			apts_stop_dur = 0;
+			apts_stop_time = 0;
+		}
+
+		if (vpts == last_vpts) {
+			if(!vpts_stop_time)
+				vpts_stop_time = now;
+			vpts_stop_dur = now - vpts_stop_time;
+		} else {
+			last_vpts = vpts;
+			vpts_stop_time = 0;
+			vpts_stop_dur = 0;
+			vpts_stop_time = 0;
+		}
+
+		if (dmx_apts == last_dmx_apts) {
+			if(!dmx_apts_stop_time)
+				dmx_apts_stop_time = now;
+			dmx_apts_stop_dur = now - dmx_apts_stop_time;
+		} else {
+			last_dmx_apts = dmx_apts;
+			dmx_apts_stop_dur = 0;
+			dmx_apts_stop_time = 0;
+		}
+
+		if (dmx_vpts == last_dmx_vpts) {
+			if (!dmx_vpts_stop_time)
+				dmx_vpts_stop_time = now;
+			dmx_vpts_stop_dur = now - dmx_vpts_stop_time;
+		} else {
+			last_dmx_vpts = dmx_vpts;
+			dmx_vpts_stop_dur = 0;
+			dmx_vpts_stop_time = 0;
+		}
+
+#if 0
+		AM_DEBUG(3, "audio level:%d cache:%d, video level:%d cache:%d, resample:%d",
+				abuf_level, adec_start ? dmx_apts - apts : dmx_apts - first_dmx_apts,
+				vbuf_level, vpts ? dmx_vpts - vpts : dmx_vpts - first_dmx_vpts,
+				resample_type);
+#endif
+
+#ifndef ENABLE_PCR
+		if (has_audio && !adec_start) {
+			adec_start = AM_TRUE;
+
+			if (abuf_level < ADEC_START_AUDIO_LEVEL)
+				adec_start = AM_FALSE;
+
+			if (has_video) {
+				if (vbuf_level < ADEC_START_VIDEO_LEVEL) {
+					adec_start = AM_FALSE;
+				}
+			}
+
+			if (abuf_level >= ADEC_FORCE_START_AUDIO_LEVEL)
+				adec_start = AM_TRUE;
+
+			if (adec_start) {
+				audio_info_t info;
+
+				/*Set audio info*/
+				memset(&info, 0, sizeof(info));
+				info.valid  = 1;
+				ioctl(ts->fd, AMSTREAM_IOC_AUDIO_INFO, (unsigned long)&info);
+
+				audio_ops->adec_start_decode(ts->fd, tp->afmt, has_video, &ts->adec);
+				if (VALID_PID(tp->sub_apid))
+					aml_set_audio_ad(dev, 1, tp->sub_apid, tp->sub_afmt);
+
+				if (av_paused) {
+					audio_ops->adec_pause_decode(ts->adec);
+				}
+
+				audio_scrambled = AM_FALSE;
+				video_scrambled = AM_FALSE;
+				resample_type = 0;
+				next_resample_type = resample_type;
+				next_resample_start_time = 0;
+				down_audio_cache_time = 0;
+				down_video_cache_time = 0;
+				AM_FileEcho(ENABLE_RESAMPLE_FILE, "0");
+				AM_FileEcho(RESAMPLE_TYPE_FILE, "0");
+
+				AM_DEBUG(1, "[avmon] start audio decoder vlevel %d alevel %d", vbuf_level, abuf_level);
+			}
+		}
+
+		if (!av_paused) {
+			if (has_video && (vbuf_level < DEC_STOP_VIDEO_LEVEL))
+				av_paused = AM_TRUE;
+			if (has_audio && adec_start && (abuf_level < DEC_STOP_AUDIO_LEVEL))
+				av_paused = AM_TRUE;
+
+			if (av_paused) {
+				if (has_audio && adec_start) {
+					audio_ops->adec_pause_decode(ts->adec);
+				}
+				if (has_video) {
+					ioctl(ts->vid_fd, AMSTREAM_IOC_VPAUSE, 1);
+				}
+
+				AM_DEBUG(1, "[avmon] pause av play vlevel %d alevel %d", vbuf_level, abuf_level);
+			}
+		}
+
+		if (av_paused) {
+			av_paused = AM_FALSE;
+
+			if (has_video && (vbuf_level < ADEC_START_VIDEO_LEVEL))
+				av_paused = AM_TRUE;
+			if (has_audio && (abuf_level < ADEC_START_AUDIO_LEVEL))
+				av_paused = AM_TRUE;
+
+			if (!av_paused) {
+				if (has_audio && adec_start) {
+					audio_ops->adec_resume_decode(ts->adec);
+				}
+				if (has_video) {
+					ioctl(ts->vid_fd, AMSTREAM_IOC_VPAUSE, 0);
+				}
+				apts_stop_time = 0;
+				vpts_stop_time = 0;
+				resample_type = 0;
+				next_resample_type = resample_type;
+				next_resample_start_time = 0;
+				down_audio_cache_time = 0;
+				down_video_cache_time = 0;
+				AM_FileEcho(ENABLE_RESAMPLE_FILE, "0");
+				AM_FileEcho(RESAMPLE_TYPE_FILE, "0");
+				AM_DEBUG(1, "[avmon] resume av play vlevel %d alevel %d", vbuf_level, abuf_level);
+			}
+		}
+
+		if (has_audio && adec_start && !av_paused) {
+			AM_Bool_t af = AM_FALSE, vf = AM_FALSE;
+			int resample = 0;
+
+			if (has_audio && (abuf_level < UP_RESAMPLE_AUDIO_LEVEL))
+				resample = 2;
+			if (has_video && (vbuf_level < UP_RESAMPLE_VIDEO_LEVEL))
+				resample = 2;
+
+			if (has_audio && dmx_apts && apts) {
+				if (down_audio_cache_time == 0) {
+					down_audio_cache_time = dmx_apts - apts;
+					if (down_audio_cache_time < DOWN_RESAMPLE_CACHE_TIME)
+						down_audio_cache_time = DOWN_RESAMPLE_CACHE_TIME;
+					else
+						down_audio_cache_time *= 2;
+				}
+				if (has_audio && (dmx_apts - apts > down_audio_cache_time))
+					af = AM_TRUE;
+			}
+
+			if (has_video && dmx_vpts && vpts) {
+				if (down_video_cache_time == 0) {
+					down_video_cache_time = dmx_vpts - vpts;
+					if (down_video_cache_time < DOWN_RESAMPLE_CACHE_TIME)
+						down_video_cache_time = DOWN_RESAMPLE_CACHE_TIME;
+					else
+						down_video_cache_time *= 2;
+				}
+				if (has_video && (dmx_vpts - vpts > down_video_cache_time))
+					vf = AM_TRUE;
+			}
+
+			if (af && vf)
+				resample = 1;
+
+			if (has_audio && (abuf_level * 5 > abuf_size * 4))
+				resample = 1;
+
+			if (has_video && (vbuf_level * 5 > vbuf_size * 4))
+				resample = 1;
+
+#ifdef ENABLE_AUDIO_RESAMPLE
+			if (resample != resample_type) {
+				if (resample != next_resample_type) {
+					next_resample_type = resample;
+					next_resample_start_time = now;
+				}
+
+				if (now - next_resample_start_time > 500) {
+					const char *cmd = "";
+
+					switch (resample) {
+						case 1: cmd = "1"; break;
+						case 2: cmd = "2"; break;
+						default: cmd = "0"; break;
+					}
+#ifdef ENABLE_AUDIO_RESAMPLE
+					AM_FileEcho(ENABLE_RESAMPLE_FILE, resample?"1":"0");
+					AM_FileEcho(RESAMPLE_TYPE_FILE, cmd);
+					AM_DEBUG(1, "[avmon] audio resample %d vlevel %d alevel %d",
+						resample, vbuf_level, abuf_level);
+					resample_type = resample;
+#endif
+					next_resample_start_time = 0;
+				}
+			}
+#endif
+		}
+
+#else /*defined(ENABLE_PCR)*/
+		if (has_audio && !adec_start) {
+			adec_start = AM_TRUE;
+
+			if (abuf_level < ADEC_START_AUDIO_LEVEL)
+				adec_start = AM_FALSE;
+
+			if (has_video) {
+				if (vbuf_level < ADEC_START_VIDEO_LEVEL) {
+					adec_start = AM_FALSE;
+				}
+			}
+
+			if (abuf_level >= ADEC_FORCE_START_AUDIO_LEVEL)
+				adec_start = AM_TRUE;
+
+			if (adec_start) {
+				audio_ops->adec_start_decode(ts->fd, tp->afmt, has_video, &ts->adec);
+				AM_DEBUG(1, "[avmon] start audio decoder vlevel %d alevel %d", vbuf_level, abuf_level);
+				if (VALID_PID(tp->sub_apid))
+				    aml_set_audio_ad(dev, 1, tp->sub_apid, tp->sub_afmt);
+			}
+		}
+#endif /*!defined ENABLE_PCR*/
+
+#ifdef USE_ADEC_IN_DVB
+            if (s_audio_cb == NULL) {
+		        int status = audio_decoder_get_enable_status(ts->adec);
+				if (status == 1) {
+//					AM_EVT_Signal(dev->dev_no, AM_AV_EVT_AUDIO_AC3_LICENCE_RESUME, NULL);
+				}
+				else if (status == 0) {
+//					AM_EVT_Signal(dev->dev_no, AM_AV_EVT_AUDIO_AC3_NO_LICENCE, NULL);
+				}
+				else if (status == -1) {
+
+				}
+	        }
+#endif
+
+#ifdef ENABLE_BYPASS_DI
+		if (has_video && is_hd_video && !bypass_di && (vbuf_level * 6 > vbuf_size * 5)) {
+			AM_FileEcho(DI_BYPASS_FILE, "1");
+			bypass_di = AM_TRUE;
+			AM_DEBUG(1, "[avmon] bypass HD deinterlace vlevel %d", vbuf_level);
+		}
+#endif
+
+#ifdef ENABLE_DROP_BFRAME
+		if (has_video && is_hd_video && !drop_b_frame) {
+			if (vbuf_level * 6 > vbuf_size * 5) {
+				drop_b_frame = AM_TRUE;
+			}
+
+			if (has_audio && adec_start && has_amaster && AM_ABS(apts - vpts) > 45000) {
+				drop_b_frame = AM_TRUE;
+			}
+
+			if (drop_b_frame) {
+				AM_FileEcho(VIDEO_DROP_BFRAME_FILE ,"1");
+				AM_DEBUG(1, "[avmon] drop B frame vlevel %d", vbuf_level);
+			}
+		}
+#endif
+
+		//first no_data
+		if (has_audio && adec_start && !no_audio_data && (dmx_apts_stop_dur > NO_DATA_CHECK_TIME) && (arp_stop_dur > NO_DATA_CHECK_TIME)) {
+			AM_Bool_t sf[2];
+			AM_DEBUG(1, "[avmon] audio stoped");
+			no_audio_data = AM_TRUE;
+			//second scramble
+			if (abuf_level_empty_dur > SCRAMBLE_CHECK_TIME) {
+				AM_DMX_GetScrambleStatus(0, sf);
+				if (sf[1]) {
+					audio_scrambled = AM_TRUE;
+					if (!no_data_evt || g_festatus) {
+//						AM_EVT_Signal(dev->dev_no, AM_AV_EVT_AUDIO_SCAMBLED, NULL);
+						AM_DEBUG(1, "[avmon] audio scrambled > stoped");
+						no_data_evt = AM_TRUE;
+						g_festatus = 0;
+					}
+				}
+			}
+		}
+
+		if (has_video && (dmx_vpts_stop_dur > NO_DATA_CHECK_TIME) && (vpts_stop_dur > NO_DATA_CHECK_TIME)) {
+			AM_Bool_t sf[2];
+			no_video_data = AM_TRUE;
+			no_video = AM_TRUE;
+			AM_DEBUG(1, "[avmon] video data stopped");
+			if (vbuf_level_empty_dur > SCRAMBLE_CHECK_TIME) {
+				AM_DMX_GetScrambleStatus(0, sf);
+				if (sf[0]) {
+					video_scrambled = AM_TRUE;
+					if (!no_data_evt || g_festatus) {
+//						AM_EVT_Signal(dev->dev_no, AM_AV_EVT_VIDEO_SCAMBLED, NULL);
+						AM_DEBUG(1, "[avmon] video scrambled");
+						no_data_evt = AM_TRUE;
+						g_festatus = 0;
+					}
+				}
+			}
+		} else if (is_avs_plus &&(tp->vfmt == VFORMAT_AVS)) {
+//			AM_EVT_Signal(dev->dev_no, AM_AV_EVT_VIDEO_NOT_SUPPORT, NULL);//not  unsupport , just  FORMAT  is AVS
+		}
+        //this Radio Program Stop
+        if (has_audio && !has_video && adec_start && !no_audio_data && (dmx_apts_stop_dur > AUDIO_NO_DATA_TIME) && (arp_stop_dur > AUDIO_NO_DATA_TIME)) {
+            AM_DEBUG(1, "[avmon] radio program data stopped");
+            no_audio_data = AM_TRUE;
+        }
+		//add (vpts_stop_dur > NO_DATA_CHECK_TIME) for first into thread,because no_audio_data no_video_data
+		//init value is true and no_data_evt init value is false.
+		if (no_audio_data && no_video_data && !no_data_evt && vpts_stop_dur > NO_DATA_CHECK_TIME) {
+			no_data_evt = AM_TRUE;
+			AM_DEBUG(1, "[avmon] send no video data signal");
+//			AM_EVT_Signal(dev->dev_no, AM_AV_EVT_AV_NO_DATA, NULL);
+		}
+
+		//when no signal, switch channel, it can trigger no data event
+		if (has_audio && !adec_start && no_video_data && !no_data_evt && vpts_stop_dur > NO_DATA_CHECK_TIME) {
+			no_data_evt = AM_TRUE;
+			AM_DEBUG(1, "[avmon] send no AV data signal");
+//			AM_EVT_Signal(dev->dev_no, AM_AV_EVT_AV_NO_DATA, NULL);
+		}
+
+		//AM_DEBUG(3,"no_audio = %d, dmx_a_stop = %d, a_stop= %d, no_video=%d, dmx_v_stop=%d, v_stop=%d, abuf_empty=%d, vbuf_empty=%d\n",no_audio_data,dmx_apts_stop_dur,apts_stop_dur, no_video_data, dmx_vpts_stop_dur, vpts_stop_dur, abuf_level_empty_dur,vbuf_level_empty_dur);
+
+		if (has_audio && no_audio_data && dmx_apts_stop_dur == 0) {
+			no_audio_data = AM_FALSE;
+			audio_scrambled = AM_FALSE;
+			no_data_evt = AM_FALSE;
+//			AM_EVT_Signal(dev->dev_no, AM_AV_EVT_AV_DATA_RESUME, NULL);
+			AM_DEBUG(1, "[avmon] audio data resumed");
+		}
+
+		if (has_video && no_video_data && dmx_vpts_stop_dur == 0) {
+			no_video_data = AM_FALSE;
+			video_scrambled = AM_FALSE;
+			no_data_evt = AM_FALSE;
+//			AM_EVT_Signal(dev->dev_no, AM_AV_EVT_AV_DATA_RESUME, NULL);
+			AM_DEBUG(1, "[avmon] video data resumed");
+		}
+
+		/*AM_DEBUG(3, "apts_dmx_stop: %d arp_stop: %d vpts_dmx_stop: %d vrp_stop: %d",
+					dmx_apts_stop_dur, arp_stop_dur, dmx_vpts_stop_dur, vrp_stop_dur);*/
+		need_replay = AM_FALSE;
+		if (!no_video_data && /*!av_paused &&*/ (dmx_vpts_stop_dur == 0) && (vrp_stop_dur > NO_DATA_CHECK_TIME))
+		{
+			if (vdec_stop_time == 0) {
+				vdec_stop_time = now;
+				vdec_stop_dur  = 0;
+			} else {
+				vdec_stop_dur = now - vdec_stop_time;
+			}
+		} else {
+			vdec_stop_time = 0;
+			vdec_stop_dur  = 0;
+		}
+
+		if (dev->mode != AV_TIMESHIFT
+			&& (dev->mode != AV_INJECT)
+			&& (has_video && (vdec_stop_dur > NO_DATA_CHECK_TIME))) {
+			if (AM_ABS(checkin_firstapts - checkin_firstvpts) < TIME_UNIT90K * 5)
+			if (dev->replay_enable)
+				need_replay = AM_TRUE;
+			AM_DEBUG(1, "[avmon] should't replay vdec_stop_dur=%d\n",
+				vdec_stop_dur);
+			AM_DEBUG(1, "[avmon] apts_dmx_stop: %d arp_stop: %d vpts_dmx_stop: %d vrp_stop: %d",
+					dmx_apts_stop_dur, arp_stop_dur, dmx_vpts_stop_dur, vrp_stop_dur);
+		}
+		if (dev->mode == AV_PLAY_TS) {
+			if (has_video && (vbuf_level * 5 > vbuf_size * 4))
+			{
+				if (dev->replay_enable)
+					need_replay = AM_TRUE;
+				AM_DEBUG(1, "[avmon] 1 shouldn't replay ts vlevel %d vbuf_size %d",vbuf_level*6, vbuf_size*5);
+			}
+			if (has_audio && (abuf_level * 5 > abuf_size * 4))
+			{
+				if (dev->replay_enable)
+					need_replay = AM_TRUE;
+				AM_DEBUG(1, "[avmon] 2 shouldn't replay ts alevel %d abuf_size %d",abuf_level*6, abuf_size*5);
+			}
+		}
+		//if(adec_start && !av_paused && has_amaster && !apts_stop_dur && !vpts_stop_dur && (vmaster_dur > VMASTER_REPLAY_TIME))
+			//need_replay = AM_TRUE;
+		//AM_DEBUG(0, "vdec status %08x", vdec_status);
+#ifdef DECODER_FATAL_ERROR_SIZE_OVERFLOW
+		if (has_video && (tp->vfmt == VFORMAT_H264) && (vdec_status & DECODER_FATAL_ERROR_SIZE_OVERFLOW)) {
+			AM_DEBUG(1, "[avmon] switch to h264 4K/2K");
+			tp->vfmt = VFORMAT_H264_4K2K;
+			AM_DEBUG(1, "DECODER_FTAL_ERROR_SIZE_OVERFLOW, vdec_status=0x%x\n",
+				vdec_status);
+			if (dev->replay_enable)
+				need_replay = AM_TRUE;
+		} else
+#endif
+		if (has_video && (tp->vfmt == VFORMAT_H264) && ((vdec_status >> 16) & 0xFFFF)) {
+			AM_DEBUG(1, "[avmon] H264 fatal error,vdec_status=0x%x",
+				vdec_status);
+			if (dev->replay_enable)
+				need_replay = AM_TRUE;
+		}
+#ifndef USE_ADEC_IN_DVB
+#ifdef ANDROID
+		if (AM_FileRead(TSYNCPCR_RESETFLAG_FILE, buf, sizeof(buf)) >= 0) {
+			int val = 0;
+			sscanf(buf, "%d", &val);
+			if (val == 1) {
+				if (dev->replay_enable)
+					need_replay = AM_TRUE;
+				AM_DEBUG(1, "[avmon] pcr need reset");
+			}
+		}
+
+		//AM_DEBUG(1, "tsync_mode:%d--vbuf_level--0x%08x---- abuf_level---0x%08x",
+		//	tsync_mode,vbuf_level,abuf_level);
+#endif
+#endif
+		if (!av_paused && dev->mode == AV_INJECT) {
+			if (has_video && (vbuf_level < DEC_STOP_VIDEO_LEVEL))
+				av_paused = AM_TRUE;
+			if (has_audio && adec_start && (abuf_level < DEC_STOP_AUDIO_LEVEL))
+				av_paused = AM_TRUE;
+
+			if (av_paused) {
+				if (has_audio && adec_start) {
+					AM_DEBUG(1, "[avmon] AV_INJECT audio pause");
+					audio_ops->adec_pause_decode(ts->adec);
+				}
+				if (has_video) {
+					AM_DEBUG(1, "[avmon] AV_INJECT video pause");
+					ioctl(ts->vid_fd, AMSTREAM_IOC_VPAUSE, 1);
+				}
+				//AM_DEBUG(1, "[avmon] pause av play vlevel %d alevel %d", vbuf_level, abuf_level);
+			}
+		}
+
+		if (av_paused && dev->mode == AV_INJECT) {
+			av_paused = AM_FALSE;
+			if (has_audio && (abuf_level < (ADEC_START_AUDIO_LEVEL/2)))
+				av_paused = AM_TRUE;
+			if (has_video && (vbuf_level < (ADEC_START_VIDEO_LEVEL*16))) {
+				av_paused = AM_TRUE;
+			} else {
+				av_paused = AM_FALSE;
+			}
+
+			if (!av_paused) {
+				if (has_audio && adec_start) {
+					AM_DEBUG(1, "[avmon] AV_INJECT audio resume");
+					audio_ops->adec_resume_decode(ts->adec);
+				}
+				if (has_video) {
+					AM_DEBUG(1, "[avmon] AV_INJECT video resume");
+					ioctl(ts->vid_fd, AMSTREAM_IOC_VPAUSE, 0);
+				}
+				//AM_DEBUG(1, "[avmon] resume av play vlevel %d alevel %d", vbuf_level, abuf_level);
+			}
+		}
+
+		if (has_audio && (apts - dmx_apts) > TIME_UNIT90K*2) {
+			apts_discontinue = 1;
+			AM_DEBUG(1, "[avmon] dmx_apts:0x%x,apts:0x%x",dmx_apts,apts);
+		}
+
+		if (has_video && (vpts - dmx_vpts) > TIME_UNIT90K*2) {
+			vpts_discontinue = 1;
+			AM_DEBUG(1, "[avmon] dmx_vpts:0x%x,vpts:0x%x",dmx_vpts,vpts);
+		}
+
+		if (AM_FileRead(TSYNC_PCR_MODE_FILE, buf, sizeof(buf)) >= 0) {
+            sscanf(buf, "%x", &tsync_pcr_mode);
+        } else {
+			AM_DEBUG(1, "[avmon] cannot read \"%s\"", TSYNC_PCR_MODE_FILE);
+            tsync_pcr_mode = 0;
+        }
+
+		if (apts_discontinue && vpts_discontinue && tsync_pcr_mode == 1) {
+			AM_Bool_t sf[2];
+			AM_DEBUG(1, "[avmon] apts_discontinue vpts_discontinue replay %d",need_replay);
+			apts_discontinue = 0;
+			vpts_discontinue = 0;
+
+			AM_DMX_GetScrambleStatus(0, sf);
+			if (sf[0] == 0 && sf[1] == 0) {
+				if (dev->replay_enable)
+					need_replay = AM_TRUE;
+				AM_DEBUG(1, "[avmon] sf[0]=sf[1]=0");
+			}
+		}
+
+		//if (need_replay && (AM_ABS(checkin_firstapts - checkin_firstvpts) > TIME_UNIT90K * 5)) {
+		//	AM_DEBUG(1, "[avmon] avoid replay checkin_firstapts checkin_firstvpts %d",need_replay);
+		//	need_replay = AM_FALSE;
+		//}
+
+		if (dev->mode == AV_TIMESHIFT
+			&& (
+				(has_audio && apts_discontinue
+					&& (abuf_level > (DEC_STOP_AUDIO_LEVEL*2))
+					&& (arp_stop_dur > NO_DATA_CHECK_TIME))
+				||
+				(has_video && no_video_data
+					&& (vbuf_level > (DEC_STOP_VIDEO_LEVEL*2))
+					&& (vrp_stop_dur > NO_DATA_CHECK_TIME))
+				)
+			) {
+			AM_DEBUG(1, "[avmon] not replay timeshift adec stuck or vdec stuck");
+			if (dev->replay_enable)
+				need_replay = AM_TRUE;
+		}
+
+		{
+			int r2;
+			do {
+				struct timespec rt2;
+				aml_get_timeout_real(20, &rt2);
+				r2 = pthread_mutex_timedlock(&dev->lock, &rt2);
+			} while (mon->av_thread_running && (r2 == ETIMEDOUT));
+
+			if (!mon->av_thread_running) {
+				if (r2 == 0)
+					pthread_mutex_unlock(&dev->lock);
+				break;
+			}
+		}
+
+		AM_TIME_GetClock(&cur_time);
+		if (need_replay && (dev->mode == AV_PLAY_TS) && (AM_ABS(cur_time - last_replay_time) > REPLAY_TIME_INTERVAL)) {
+			AM_DEBUG(1, "[avmon] replay ts vlevel %d alevel %d vpts_stop %d vmaster %d",
+				vbuf_level, abuf_level, vpts_stop_dur, vmaster_dur);
+			aml_restart_ts_mode(dev, AM_FALSE);
+			tp = &dev->ts_player.play_para;
+			ts = (AV_TSData_t*)dev->ts_player.drv_data;
+#ifndef ENABLE_PCR
+			adec_start = AM_FALSE;
+			av_paused  = AM_TRUE;
+#else
+			adec_start = (adec_handle != NULL);
+			av_paused  = AM_FALSE;
+#endif
+			resample_type = 0;
+			next_resample_type = resample_type;
+			next_resample_start_time = 0;
+			last_apts = 0;
+			last_vpts = 0;
+			last_dmx_apts = 0;
+			last_dmx_vpts = 0;
+			apts_stop_time = 0;
+			vpts_stop_time = 0;
+			dmx_apts_stop_time = 0;
+			dmx_vpts_stop_time = 0;
+			vmaster_time = 0;
+			down_audio_cache_time = 0;
+			down_video_cache_time = 0;
+			vdec_stop_time = 0;
+			vdec_stop_dur  = 0;
+			has_amaster = AM_FALSE;
+			AM_TIME_GetClock(&last_replay_time);
+			replay_done = 1;
+		}else if (need_replay && (dev->mode == AV_TIMESHIFT) && (AM_ABS(cur_time - last_replay_time) > REPLAY_TIME_INTERVAL)) {
+			AM_DEBUG(1, "[avmon] replay timshift vlevel %d alevel %d vpts_stop %d vmaster %d",
+				vbuf_level, abuf_level, vpts_stop_dur, vmaster_dur);
+			AV_TimeshiftData_t *tshift = NULL;
+
+			tshift = dev->timeshift_player.drv_data;
+			am_timeshift_reset_continue(tshift, -1, AM_TRUE);
+#ifndef ENABLE_PCR
+			adec_start = AM_FALSE;
+			av_paused  = AM_TRUE;
+#else
+			adec_start = (adec_handle != NULL);
+			av_paused  = AM_FALSE;
+#endif
+			resample_type = 0;
+			next_resample_type = resample_type;
+			next_resample_start_time = 0;
+			last_apts = 0;
+			last_vpts = 0;
+			last_dmx_apts = 0;
+			last_dmx_vpts = 0;
+			apts_stop_time = 0;
+			vpts_stop_time = 0;
+			dmx_apts_stop_time = 0;
+			dmx_vpts_stop_time = 0;
+			vmaster_time = 0;
+			down_audio_cache_time = 0;
+			down_video_cache_time = 0;
+			vdec_stop_time = 0;
+			vdec_stop_dur  = 0;
+			has_amaster = AM_FALSE;
+			AM_TIME_GetClock(&last_replay_time);
+			replay_done = 1;
+		}
+		else if (need_replay && (dev->mode == AV_INJECT) && (AM_ABS(cur_time - last_replay_time) > REPLAY_TIME_INTERVAL)) {
+			AM_DEBUG(1, "[avmon] replay AV_INJECT vlevel %d alevel %d vpts_stop %d vmaster %d",
+				vbuf_level, abuf_level, vpts_stop_dur, vmaster_dur);
+			aml_restart_inject_mode(dev, AM_FALSE);
+			tp = &dev->ts_player.play_para;
+			inj = (AV_InjectData_t *)dev->inject_player.drv_data;
+			ts_temp.fd = inj->vid_fd;
+			ts_temp.vid_fd = inj->cntl_fd;
+			ts_temp.adec = inj->adec;
+			ts = &ts_temp;
+#ifndef ENABLE_PCR
+			adec_start = AM_FALSE;
+			av_paused  = AM_TRUE;
+#else
+			adec_start = (adec_handle != NULL);
+			av_paused  = AM_FALSE;
+#endif
+			resample_type = 0;
+			next_resample_type = resample_type;
+			next_resample_start_time = 0;
+			last_apts = 0;
+			last_vpts = 0;
+			last_dmx_apts = 0;
+			last_dmx_vpts = 0;
+			apts_stop_time = 0;
+			vpts_stop_time = 0;
+			dmx_apts_stop_time = 0;
+			dmx_vpts_stop_time = 0;
+			vmaster_time = 0;
+			down_audio_cache_time = 0;
+			down_video_cache_time = 0;
+			vdec_stop_time = 0;
+			vdec_stop_dur  = 0;
+			has_amaster = AM_FALSE;
+			AM_TIME_GetClock(&last_replay_time);
+			replay_done = 1;
+		}
+
+		pthread_mutex_unlock(&dev->lock);
+
+		if (replay_done) {
+//			AM_EVT_Signal(dev->dev_no, AM_AV_EVT_PLAYER_STATE_CHANGED, NULL);
+			replay_done = 0;
+		}
+
+	}
+
+	pthread_mutex_unlock(&gAVMonLock);
+
+#ifndef ENABLE_PCR
+	if (resample_type) {
+		AM_FileEcho(ENABLE_RESAMPLE_FILE, "0");
+	}
+#endif
+
+	if (dev->mode != AV_TIMESHIFT)
+		AM_FileEcho(VID_BLACKOUT_FILE, dev->video_blackout ? "1" : "0");
+
+	if (bypass_di) {
+		AM_FileEcho(DI_BYPASS_FILE, "0");
+	}
+
+	if (drop_b_frame) {
+		AM_FileEcho(VIDEO_DROP_BFRAME_FILE, "0");
+	}
+
+	AM_DEBUG(1, "[avmon] AV monitor thread exit now");
+	return NULL;
+}
+
+static AM_ErrorCode_t aml_open_mode(AM_AV_Device_t *dev, AV_PlayMode_t mode)
+{
+	AV_DataSource_t *src;
+#ifdef PLAYER_API_NEW
+	AV_FilePlayerData_t *data;
+#endif
+	//AV_JPEGData_t *jpeg;
+	AV_InjectData_t *inj;
+	AV_TimeshiftData_t *tshift;
+	AV_TSData_t *ts;
+	int fd;
+
+	AM_DebugSetLogLevel(_get_dvb_loglevel());
+
+	switch (mode)
+	{
+		case AV_PLAY_VIDEO_ES:
+			src = aml_create_data_source(STREAM_VBUF_FILE, dev->dev_no, AM_FALSE);
+			if (!src)
+			{
+				AM_DEBUG(1, "cannot create data source \"/dev/amstream_vbuf\"");
+				return AM_AV_ERR_CANNOT_OPEN_DEV;
+			}
+
+			fd = open(AMVIDEO_FILE, O_RDWR);
+			if (fd == -1)
+			{
+				AM_DEBUG(1, "cannot create data source \"/dev/amvideo\"");
+				return AM_AV_ERR_CANNOT_OPEN_DEV;
+			}
+			ioctl(fd, AMSTREAM_IOC_TRICKMODE, TRICKMODE_I);
+			src->video_fd = fd;
+			dev->vid_player.drv_data = src;
+
+		break;
+		case AV_PLAY_AUDIO_ES:
+			src = aml_create_data_source(STREAM_ABUF_FILE, dev->dev_no, AM_TRUE);
+			if (!src)
+			{
+				AM_DEBUG(1, "cannot create data source \"/dev/amstream_abuf\"");
+				return AM_AV_ERR_CANNOT_OPEN_DEV;
+			}
+			dev->aud_player.drv_data = src;
+		break;
+		case AV_PLAY_TS:
+			if (aml_open_ts_mode(dev) != AM_SUCCESS)
+				return AM_AV_ERR_SYS;
+		break;
+		case AV_PLAY_FILE:
+#ifdef PLAYER_API_NEW
+			data = aml_create_fp(dev);
+			if (!data)
+			{
+				AM_DEBUG(1, "not enough memory");
+				return AM_AV_ERR_NO_MEM;
+			}
+			dev->file_player.drv_data = data;
+#endif
+		break;
+		// case AV_GET_JPEG_INFO:
+		// case AV_DECODE_JPEG:
+		// 	jpeg = aml_create_jpeg_data();
+		// 	if (!jpeg)
+		// 	{
+		// 		AM_DEBUG(1, "not enough memory");
+		// 		return AM_AV_ERR_NO_MEM;
+		// 	}
+		// 	dev->vid_player.drv_data = jpeg;
+		// break;
+		case AV_INJECT:
+			inj = aml_create_inject_data();
+			if (!inj)
+			{
+				AM_DEBUG(1, "not enough memory");
+				return AM_AV_ERR_NO_MEM;
+			}
+			dev->inject_player.drv_data = inj;
+		break;
+		case AV_TIMESHIFT:
+			tshift = aml_create_timeshift_data();
+			if (!tshift)
+			{
+				AM_DEBUG(1, "not enough memory");
+				return AM_AV_ERR_NO_MEM;
+			}
+			tshift->dev = dev;
+			dev->timeshift_player.drv_data = tshift;
+		break;
+		default:
+		break;
+	}
+
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t aml_start_mode(AM_AV_Device_t *dev, AV_PlayMode_t mode, void *para)
+{
+	AV_DataSource_t *src;
+	int fd, val;
+	AV_TSPlayPara_t *tp;
+	AV_TSData_t *ts;
+#ifdef PLAYER_API_NEW
+	AV_FilePlayerData_t *data;
+	AV_FilePlayPara_t *pp;
+#endif
+	// AV_JPEGData_t *jpeg;
+	AV_InjectPlayPara_t inj_p;
+	AV_InjectData_t *inj;
+	AV_TimeShiftPlayPara_t *tshift_p;
+	AV_TimeshiftData_t *tshift;
+
+	int ctrl_fd = open(AMVIDEO_FILE, O_RDWR);
+	if (ctrl_fd >= 0) {
+		ioctl(ctrl_fd, AMSTREAM_IOC_SET_VSYNC_UPINT, 0);
+		close(ctrl_fd);
+	} else {
+		AM_DEBUG(1, "open /dev/amvideo error");
+	}
+#ifdef ANDROID
+//	dev->replay_enable = property_get_int32(REPLAY_ENABLE_PROP, 0);
+//	AM_DEBUG(1, "set replay_enable=%d\n", dev->replay_enable);
+#endif
+	switch (mode)
+	{
+		case AV_PLAY_VIDEO_ES:
+			src = dev->vid_player.drv_data;
+			val = (long)para;
+			if (ioctl(src->fd, AMSTREAM_IOC_VFORMAT, val) == -1)
+			{
+				AM_DEBUG(1, "set video format failed");
+				return AM_AV_ERR_SYS;
+			}
+			aml_start_data_source(src, dev->vid_player.para.data, dev->vid_player.para.len, dev->vid_player.para.times+1);
+		break;
+		case AV_PLAY_AUDIO_ES:
+			src = dev->aud_player.drv_data;
+			val = (long)para;
+			if (ioctl(src->fd, AMSTREAM_IOC_AFORMAT, val) == -1)
+			{
+				AM_DEBUG(1, "set audio format failed");
+				return AM_AV_ERR_SYS;
+			}
+			if (ioctl(src->fd, AMSTREAM_IOC_PORT_INIT, 0) == -1)
+			{
+				AM_DEBUG(1, "amport init failed");
+				return AM_AV_ERR_SYS;
+			}
+			if (ioctl(src->fd, AMSTREAM_IOC_TSTAMP, 0) == -1)
+				AM_DEBUG(1, "checkin first apts failed [%s]", strerror(errno));
+			AM_DEBUG(1, "aml start aes:  A[fmt:%d, loop:%d]", val, dev->aud_player.para.times);
+			aml_start_data_source(src, dev->aud_player.para.data, dev->aud_player.para.len, dev->aud_player.para.times);
+			audio_ops->adec_start_decode(src->fd, val, 0, &src->adec);
+		break;
+		case AV_PLAY_TS:
+			tp = (AV_TSPlayPara_t *)para;
+			setup_forced_pid(tp);
+			dev->alt_apid = tp->apid;
+			dev->alt_afmt = tp->afmt;
+			tp->drm_mode = dev->curr_para.drm_mode;
+#if defined(ANDROID) || defined(CHIP_8626X)
+#ifdef ENABLE_PCR_RECOVER
+			AM_FileEcho(PCR_RECOVER_FILE, "1");
+#endif
+#endif
+			AM_TRY(aml_start_ts_mode(dev, tp, AM_TRUE));
+		break;
+		case AV_PLAY_FILE:
+#ifdef PLAYER_API_NEW
+			data = (AV_FilePlayerData_t*)dev->file_player.drv_data;
+			pp = (AV_FilePlayPara_t*)para;
+
+			if (pp->start)
+			{
+				memset((void*)&data->pctl,0,sizeof(play_control_t));
+
+				//player_register_update_callback(&data->pctl.callback_fn, aml_update_player_info_callback, PLAYER_INFO_POP_INTERVAL);
+
+				data->pctl.file_name = strndup(pp->name,FILENAME_LENGTH_MAX);
+				data->pctl.video_index = -1;
+				data->pctl.audio_index = -1;
+				data->pctl.hassub = 1;
+
+				/*data->pctl.t_pos = st;*/
+				aml_set_tsync_enable(1);
+
+				if (pp->loop)
+				{
+					data->pctl.loop_mode =1;
+				}
+				data->pctl.need_start = 1;
+				data->pctl.is_variable = 1;
+
+				data->media_id = player_start(&data->pctl,0);
+
+				if (data->media_id < 0)
+				{
+					AM_DEBUG(1, "play file failed");
+					return AM_AV_ERR_SYS;
+				}
+
+				player_start_play(data->media_id);
+				//AM_AOUT_SetDriver(AOUT_DEV_NO, &amplayer_aout_drv, (void*)(long)data->media_id);
+			}
+#endif
+		break;
+		// case AV_GET_JPEG_INFO:
+		// case AV_DECODE_JPEG:
+		// 	jpeg = dev->vid_player.drv_data;
+		// 	return aml_decode_jpeg(jpeg, dev->vid_player.para.data, dev->vid_player.para.len, mode, para);
+		// break;
+		case AV_INJECT:
+			memcpy(&inj_p, para, sizeof(AM_AV_InjectPara_t));
+			inj = dev->inject_player.drv_data;
+			inj_p.drm_mode = dev->curr_para.drm_mode;
+			dev->alt_apid = inj_p.para.aud_id;
+			dev->alt_afmt = inj_p.para.aud_fmt;
+			if (aml_start_inject(dev, inj, &inj_p) != AM_SUCCESS)
+			{
+				AM_DEBUG(1,"[aml_start_mode]  AM_AV_ERR_SYS");
+				return AM_AV_ERR_SYS;
+			} else {
+				dev->ts_player.play_para.afmt = inj->aud_fmt;
+				dev->ts_player.play_para.apid = inj->aud_id;
+				dev->ts_player.play_para.vfmt = inj->vid_fmt;
+				dev->ts_player.play_para.vpid = inj->vid_id;
+				dev->ts_player.play_para.sub_afmt = inj->sub_type;
+				dev->ts_player.play_para.sub_apid = inj->sub_id;
+				dev->ts_player.play_para.pcrpid = 0x1fff;
+				aml_start_av_monitor(dev, &dev->ts_player.mon);
+			}
+		break;
+		case AV_TIMESHIFT:
+			tshift_p = (AV_TimeShiftPlayPara_t *)para;
+			tshift = dev->timeshift_player.drv_data;
+			m_tshift = tshift;
+			tshift->tp.vpid = tshift_p->para.media_info.vid_pid;
+			tshift->tp.vfmt = tshift_p->para.media_info.vid_fmt;
+			tshift->tp.pcrpid = -1;
+			if (tshift_p->para.media_info.aud_cnt > 0) {
+				tshift->tp.apid = tshift_p->para.media_info.audios[0].pid;
+				tshift->tp.afmt = tshift_p->para.media_info.audios[0].fmt;
+			}
+			setup_forced_pid(&tshift->tp);
+			dev->alt_apid = tshift->tp.apid;
+			dev->alt_afmt = tshift->tp.afmt;
+			if (aml_start_timeshift(tshift, tshift_p, AM_TRUE, AM_TRUE) != AM_SUCCESS)
+				return AM_AV_ERR_SYS;
+		break;
+		default:
+		break;
+	}
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t aml_close_mode(AM_AV_Device_t *dev, AV_PlayMode_t mode)
+{
+	AV_DataSource_t *src;
+#ifdef PLAYER_API_NEW
+	AV_FilePlayerData_t *data;
+#endif
+	// AV_JPEGData_t *jpeg;
+	AV_InjectData_t *inj;
+	AV_TimeshiftData_t *tshift;
+	int fd, ret;
+
+	switch (mode)
+	{
+		case AV_PLAY_VIDEO_ES:
+			src = dev->vid_player.drv_data;
+			ioctl(src->video_fd, AMSTREAM_IOC_TRICKMODE, TRICKMODE_NONE);
+			close(src->video_fd);
+			aml_destroy_data_source(src);
+		break;
+		case AV_PLAY_AUDIO_ES:
+			src = dev->aud_player.drv_data;
+			audio_ops->adec_stop_decode(&src->adec);
+			aml_destroy_data_source(src);
+		break;
+		case AV_PLAY_TS:
+#if defined(ANDROID) || defined(CHIP_8626X)
+#ifdef ENABLE_PCR_RECOVER
+			AM_FileEcho(PCR_RECOVER_FILE, "0");
+#endif
+#endif
+		ret = aml_close_ts_mode(dev, AM_TRUE);
+		break;
+		case AV_PLAY_FILE:
+#ifdef PLAYER_API_NEW
+			data = (AV_FilePlayerData_t *)dev->file_player.drv_data;
+			aml_destroy_fp(data);
+			adec_cmd("stop");
+#endif
+		break;
+		// case AV_GET_JPEG_INFO:
+		// case AV_DECODE_JPEG:
+		// 	jpeg = dev->vid_player.drv_data;
+		// 	aml_destroy_jpeg_data(jpeg);
+		// break;
+		case AV_INJECT:
+			aml_stop_av_monitor(dev, &dev->ts_player.mon);
+			inj = dev->inject_player.drv_data;
+			aml_destroy_inject_data(inj);
+		break;
+		case AV_TIMESHIFT:
+			tshift = dev->timeshift_player.drv_data;
+			aml_stop_timeshift(tshift, AM_TRUE);
+			aml_destroy_timeshift_data(tshift);
+			dev->timeshift_player.drv_data = NULL;
+			m_tshift = NULL;
+		break;
+		default:
+		break;
+	}
+
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t aml_ts_source(AM_AV_Device_t *dev, AM_AV_TSSource_t src)
+{
+	char *cmd;
+
+	UNUSED(dev);
+
+	switch (src)
+	{
+		case AM_AV_TS_SRC_TS0:
+			cmd = "ts0";
+		break;
+		case AM_AV_TS_SRC_TS1:
+			cmd = "ts1";
+		break;
+#if defined(CHIP_8226M) || defined(CHIP_8626X)
+		case AM_AV_TS_SRC_TS2:
+			cmd = "ts2";
+		break;
+#endif
+		case AM_AV_TS_SRC_HIU:
+			cmd = "hiu";
+		break;
+		case AM_AV_TS_SRC_HIU1:
+			cmd = "hiu1";
+		break;
+		case AM_AV_TS_SRC_DMX0:
+			cmd = "dmx0";
+		break;
+		case AM_AV_TS_SRC_DMX1:
+			cmd = "dmx1";
+		break;
+#if defined(CHIP_8226M) || defined(CHIP_8626X)
+		case AM_AV_TS_SRC_DMX2:
+			cmd = "dmx2";
+		break;
+#endif
+		default:
+			AM_DEBUG(1, "illegal ts source %d", src);
+			return AM_AV_ERR_NOT_SUPPORTED;
+		break;
+	}
+
+	return AM_FileEcho(DVB_STB_SOURCE_FILE, cmd);
+}
+
+static AM_ErrorCode_t aml_file_cmd(AM_AV_Device_t *dev, AV_PlayCmd_t cmd, void *para)
+{
+#ifdef PLAYER_API_NEW
+	AV_FilePlayerData_t *data;
+	AV_FileSeekPara_t *sp;
+	int rc = -1;
+
+	data = (AV_FilePlayerData_t *)dev->file_player.drv_data;
+
+	if (data->media_id < 0)
+	{
+		AM_DEBUG(1, "player do not start");
+		return AM_AV_ERR_SYS;
+	}
+
+	switch(cmd)
+	{
+		case AV_PLAY_START:
+			player_start_play(data->media_id);
+		break;
+		case AV_PLAY_PAUSE:
+			player_pause(data->media_id);
+		break;
+		case AV_PLAY_RESUME:
+			player_resume(data->media_id);
+		break;
+		case AV_PLAY_FF:
+			player_forward(data->media_id, (long)para);
+		break;
+		case AV_PLAY_FB:
+			player_backward(data->media_id, (long)para);
+		break;
+		case AV_PLAY_SEEK:
+			sp = (AV_FileSeekPara_t *)para;
+			 player_timesearch(data->media_id, sp->pos);
+		break;
+		default:
+			AM_DEBUG(1, "illegal media player command");
+			return AM_AV_ERR_NOT_SUPPORTED;
+		break;
+	}
+#endif
+
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t aml_inject_cmd(AM_AV_Device_t *dev, AV_PlayCmd_t cmd, void *para)
+{
+	AV_InjectData_t *data;
+
+	UNUSED(para);
+
+	data = (AV_InjectData_t *)dev->inject_player.drv_data;
+
+	switch (cmd)
+	{
+		case AV_PLAY_PAUSE:
+			if (data->aud_id != -1)
+			{
+#if defined(ADEC_API_NEW)
+				audio_ops->adec_pause_decode(data->adec);
+#else
+				//TODO
+#endif
+			}
+			if (data->vid_fd != -1 && data->cntl_fd != -1)
+			{
+				ioctl(data->cntl_fd, AMSTREAM_IOC_VPAUSE, 1);
+			}
+			AM_DEBUG(1, "pause inject");
+		break;
+		case AV_PLAY_RESUME:
+			if (data->aud_id != -1)
+			{
+#if defined(ADEC_API_NEW)
+				audio_ops->adec_resume_decode(data->adec);
+#else
+				//TODO
+#endif
+			}
+			if (data->vid_fd != -1 && data->cntl_fd != -1)
+			{
+				ioctl(data->cntl_fd, AMSTREAM_IOC_VPAUSE, 0);
+			}
+			AM_DEBUG(1, "resume inject");
+		break;
+		default:
+			AM_DEBUG(1, "illegal media player command");
+			return AM_AV_ERR_NOT_SUPPORTED;
+		break;
+	}
+
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t aml_file_status(AM_AV_Device_t *dev, AM_AV_PlayStatus_t *status)
+{
+#ifdef PLAYER_API_NEW
+	AV_FilePlayerData_t *data;
+	int rc;
+
+	data = (AV_FilePlayerData_t *)dev->file_player.drv_data;
+	if (data->media_id == -1)
+	{
+		AM_DEBUG(1, "player do not start");
+		return AM_AV_ERR_SYS;
+	}
+
+	player_info_t pinfo;
+
+	if (player_get_play_info(data->media_id,&pinfo) < 0)
+	{
+		AM_DEBUG(1, "player_get_play_info failed");
+		return AM_AV_ERR_SYS;
+	}
+	status->duration = pinfo.full_time;
+	status->position = pinfo.current_time;
+#endif
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t aml_file_info(AM_AV_Device_t *dev, AM_AV_FileInfo_t *info)
+{
+#ifdef PLAYER_API_NEW
+	AV_FilePlayerData_t *data;
+	int rc;
+
+	data = (AV_FilePlayerData_t *)dev->file_player.drv_data;
+	if (data->media_id == -1)
+	{
+		AM_DEBUG(1, "player do not start");
+		return AM_AV_ERR_SYS;
+	}
+
+	media_info_t minfo;
+
+	if (player_get_media_info(data->media_id,&minfo) < 0)
+	{
+		AM_DEBUG(1, "player_get_media_info failed");
+		return AM_AV_ERR_SYS;
+	}
+	info->duration = minfo.stream_info.duration;
+	info->size = minfo.stream_info.file_size;
+#endif
+
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t aml_set_video_para(AM_AV_Device_t *dev, AV_VideoParaType_t para, void *val)
+{
+	const char *name = NULL, *cmd = "";
+	char buf[32];
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	AV_VideoWindow_t *win;
+
+	switch (para)
+	{
+		case AV_VIDEO_PARA_WINDOW:
+			name = VID_AXIS_FILE;
+			win = (AV_VideoWindow_t *)val;
+			snprintf(buf, sizeof(buf), "%d %d %d %d", win->x, win->y, win->x+win->w, win->y+win->h);
+			cmd = buf;
+		break;
+		case AV_VIDEO_PARA_CROP:
+			name = VID_CROP_FILE;
+			win = (AV_VideoWindow_t *)val;
+			snprintf(buf, sizeof(buf), "%d %d %d %d", win->x, win->y, win->w, win->h);
+			cmd = buf;
+		break;
+		case AV_VIDEO_PARA_CONTRAST:
+			name = VID_CONTRAST_FILE;
+			snprintf(buf, sizeof(buf), "%ld", (long)val);
+			cmd = buf;
+		break;
+		case AV_VIDEO_PARA_SATURATION:
+			name = VID_SATURATION_FILE;
+			snprintf(buf, sizeof(buf), "%ld", (long)val);
+			cmd = buf;
+		break;
+		case AV_VIDEO_PARA_BRIGHTNESS:
+			name = VID_BRIGHTNESS_FILE;
+			snprintf(buf, sizeof(buf), "%ld", (long)val);
+			cmd = buf;
+		break;
+		case AV_VIDEO_PARA_ENABLE:
+			name = VID_DISABLE_FILE;
+			cmd = ((long)val)?"0":"1";
+		break;
+		case AV_VIDEO_PARA_BLACKOUT:
+			if (!(dev->mode & (AV_PLAY_TS | AV_TIMESHIFT))) {
+				name = VID_BLACKOUT_FILE;
+				cmd = ((long)val)?"1":"0";
+			}
+			dev->video_blackout = (long)val;
+#if 0
+#ifdef AMSTREAM_IOC_CLEAR_VBUF
+			if((int)val)
+			{
+				int fd = open(AMVIDEO_FILE, O_RDWR);
+				if(fd!=-1)
+				{
+					ioctl(fd, AMSTREAM_IOC_CLEAR_VBUF, 0);
+					close(fd);
+				}
+			}
+#endif
+#endif
+		break;
+		case AV_VIDEO_PARA_RATIO:
+#ifndef 	CHIP_8226H
+			name = VID_SCREEN_MODE_FILE;
+			switch ((long)val)
+			{
+				case AM_AV_VIDEO_ASPECT_AUTO:
+					cmd = "0";
+				break;
+				case AM_AV_VIDEO_ASPECT_16_9:
+					cmd = "3";
+				break;
+				case AM_AV_VIDEO_ASPECT_4_3:
+					cmd = "2";
+				break;
+			}
+#else
+			name = VID_ASPECT_RATIO_FILE;
+			switch ((long)val)
+			{
+				case AM_AV_VIDEO_ASPECT_AUTO:
+					cmd = "auto";
+				break;
+				case AM_AV_VIDEO_ASPECT_16_9:
+					cmd = "16x9";
+				break;
+				case AM_AV_VIDEO_ASPECT_4_3:
+					cmd = "4x3";
+				break;
+			}
+ #endif
+		break;
+		case AV_VIDEO_PARA_RATIO_MATCH:
+#ifndef 	CHIP_8226H
+			switch ((long)val)
+			{
+				case AM_AV_VIDEO_ASPECT_MATCH_IGNORE:
+					cmd = "1";
+				break;
+				case AM_AV_VIDEO_ASPECT_MATCH_LETTER_BOX:
+					cmd = "3";
+				break;
+				case AM_AV_VIDEO_ASPECT_MATCH_PAN_SCAN:
+					cmd = "2";
+				break;
+				case AM_AV_VIDEO_ASPECT_MATCH_COMBINED:
+					cmd = "4";
+				break;
+			}
+#else
+			name = VID_ASPECT_MATCH_FILE;
+			switch ((long)val)
+			{
+				case AM_AV_VIDEO_ASPECT_MATCH_IGNORE:
+					cmd = "ignore";
+				break;
+				case AM_AV_VIDEO_ASPECT_MATCH_LETTER_BOX:
+					cmd = "letter box";
+				break;
+				case AM_AV_VIDEO_ASPECT_MATCH_PAN_SCAN:
+					cmd = "pan scan";
+				break;
+				case AM_AV_VIDEO_ASPECT_MATCH_COMBINED:
+					cmd = "combined";
+				break;
+			}
+#endif
+		break;
+		case AV_VIDEO_PARA_MODE:
+			name = VID_SCREEN_MODE_FILE;
+			cmd = ((AM_AV_VideoDisplayMode_t)val)?"1":"0";
+		break;
+		case AV_VIDEO_PARA_CLEAR_VBUF:
+#if 0
+#ifdef AMSTREAM_IOC_CLEAR_VBUF
+			{
+				int fd = open(AMVIDEO_FILE, O_RDWR);
+				if(fd!=-1)
+				{
+					ioctl(fd, AMSTREAM_IOC_CLEAR_VBUF, 0);
+					close(fd);
+				}
+			}
+#endif
+#endif
+			name = VID_DISABLE_FILE;
+			cmd = "2";
+		break;
+		case AV_VIDEO_PARA_ERROR_RECOVERY_MODE:
+			name = VDEC_H264_ERROR_RECOVERY_MODE_FILE;
+			snprintf(buf, sizeof(buf), "%ld", (long)val);
+			cmd = buf;
+		break;
+	}
+
+	if(name)
+	{
+		ret = AM_FileEcho(name, cmd);
+	}
+
+	return ret;
+}
+
+static AM_ErrorCode_t aml_inject(AM_AV_Device_t *dev, AM_AV_InjectType_t type, uint8_t *data, int *size, int timeout)
+{
+	AV_InjectData_t *inj = (AV_InjectData_t*)dev->inject_player.drv_data;
+	int fd, send, ret;
+
+	if ((inj->pkg_fmt == PFORMAT_ES) && (type == AM_AV_INJECT_AUDIO))
+		fd = inj->aud_fd;
+	else
+		fd = inj->vid_fd;
+
+	if (fd == -1)
+	{
+		AM_DEBUG(1, "device is not openned");
+		return AM_AV_ERR_NOT_ALLOCATED;
+	}
+
+	if (timeout >= 0)
+	{
+		struct pollfd pfd;
+
+		pfd.fd = fd;
+		pfd.events = POLLOUT;
+
+		ret = poll(&pfd, 1, timeout);
+		if (ret != 1)
+			return AM_AV_ERR_TIMEOUT;
+	}
+
+	send = *size;
+	if (send)
+	{
+		ret = write(fd, data, send);
+		if ((ret == -1) && (errno != EAGAIN))
+		{
+			AM_DEBUG(1, "inject data failed errno:%d msg:%s", errno, strerror(errno));
+			return AM_AV_ERR_SYS;
+		}
+		else if ((ret == -1) && (errno == EAGAIN))
+		{
+			ret = 0;
+		}
+	}
+	else
+		ret = 0;
+
+	*size = ret;
+
+	return AM_SUCCESS;
+}
+
+#ifdef AMSTREAM_IOC_GET_VBUF
+extern AM_ErrorCode_t ge2d_blit_yuv(struct vbuf_info *info, AM_OSD_Surface_t *surf);
+#endif
+
+static AM_ErrorCode_t aml_video_frame(AM_AV_Device_t *dev, const AM_AV_SurfacePara_t *para, AM_OSD_Surface_t **s)
+{
+#ifdef AMSTREAM_IOC_GET_VBUF
+	int fd = -1, rc;
+	struct vbuf_info info;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	AM_OSD_PixelFormatType_t type;
+	AM_OSD_Surface_t *surf = NULL;
+	int w, h, append;
+
+	fd = open(AMVIDEO_FILE, O_RDWR);
+	if (fd == -1)
+	{
+		AM_DEBUG(1, "cannot open \"%s\"", AMVIDEO_FILE);
+		ret = AM_AV_ERR_SYS;
+		goto end;
+	}
+
+	rc = ioctl(fd, AMSTREAM_IOC_GET_VBUF, &info);
+	if (rc == -1)
+	{
+		AM_DEBUG(1, "AMSTREAM_IOC_GET_VBUF_INFO failed");
+		ret = AM_AV_ERR_SYS;
+		goto end;
+	}
+
+	type = AM_OSD_FMT_COLOR_RGB_888;
+	w = info.width;
+	h = info.height;
+
+	ret = AM_OSD_CreateSurface(type, w, h, AM_OSD_SURFACE_FL_HW, &surf);
+	if (ret != AM_SUCCESS)
+		goto end;
+
+	ret = ge2d_blit_yuv(&info, surf);
+	if (ret != AM_SUCCESS)
+		goto end;
+
+	*s = surf;
+	return AM_SUCCESS;
+
+end:
+	if (surf)
+		AM_OSD_DestroySurface(surf);
+	if (fd != -1)
+		close(fd);
+	return ret;
+#else
+	UNUSED(dev);
+	UNUSED(para);
+	UNUSED(s);
+
+	return AM_AV_ERR_NOT_SUPPORTED;
+#endif
+}
+static AM_Bool_t aml_is_audio_valid(AM_AV_Device_t *dev)
+{
+	AM_Bool_t has_audio = AM_FALSE;
+	AV_TimeshiftData_t *tshift = NULL;
+
+	if ((dev->mode & AV_PLAY_TS) || (dev->mode & AV_INJECT))
+	{
+		has_audio = VALID_AUDIO(dev->ts_player.play_para.apid, dev->ts_player.play_para.afmt);
+	}
+	else if(dev->mode & AV_TIMESHIFT)
+	{
+		tshift = dev->timeshift_player.drv_data;
+		if (tshift != NULL)
+			has_audio =  VALID_AUDIO(tshift->tp.apid, tshift->tp.afmt);
+	}
+
+	return has_audio;
+}
+
+static AM_ErrorCode_t aml_get_astatus(AM_AV_Device_t *dev, AM_AV_AudioStatus_t *para)
+{
+	struct am_io_param astatus;
+
+	int fd, rc;
+	char buf[32];
+
+	void *adec = NULL;
+	AM_Bool_t has_audio = aml_is_audio_valid(dev);
+
+	if (!has_audio)
+	{
+		AM_DEBUG(1,"there is no audio pid data ,pls check your parameters");
+		return AM_FAILURE;
+	}
+
+#if 1
+	switch (dev->mode) {
+		case AV_PLAY_TS:
+			adec = ((AV_TSData_t *)dev->ts_player.drv_data)->adec;
+			break;
+		case AV_INJECT:
+			adec = ((AV_InjectData_t *)dev->inject_player.drv_data)->adec;
+			break;
+		case AV_TIMESHIFT:
+			adec = ((AV_TimeshiftData_t *)dev->timeshift_player.drv_data)->ts.adec;
+			break;
+		default:
+			AM_DEBUG(1, "only valid in TS/INJ/TIMESHIFT mode");
+			break;
+	}
+
+	audio_ops->adec_get_status(adec,para);
+
+	para->frames      = 1;
+	para->aud_fmt     = -1;
+#else
+	rc = ioctl(fd, AMSTREAM_IOC_ADECSTAT, (int)&astatus);
+	if (rc==-1)
+	{
+		AM_DEBUG(1, "AMSTREAM_IOC_ADECSTAT failed");
+		goto get_fail;
+	}
+
+	para->channels    = astatus.astatus.channels;
+	para->sample_rate = astatus.astatus.sample_rate;
+	para->resolution  = astatus.astatus.resolution;
+	para->frames      = 1;
+	para->aud_fmt     = -1;
+#endif
+
+	if (AM_FileRead(ASTREAM_FORMAT_FILE, buf, sizeof(buf)) == AM_SUCCESS)
+	{
+		if (!strncmp(buf, "amadec_mpeg", 11))
+			para->aud_fmt = AFORMAT_MPEG;
+		else if (!strncmp(buf, "amadec_pcm_s16le", 16))
+			para->aud_fmt = AFORMAT_PCM_S16LE;
+		else if (!strncmp(buf, "amadec_aac", 10))
+			para->aud_fmt = AFORMAT_AAC;
+		else if (!strncmp(buf, "amadec_ac3", 10))
+			para->aud_fmt = AFORMAT_AC3;
+		else if (!strncmp(buf, "amadec_alaw", 11))
+			para->aud_fmt = AFORMAT_ALAW;
+		else if (!strncmp(buf, "amadec_mulaw", 12))
+			para->aud_fmt = AFORMAT_MULAW;
+		else if (!strncmp(buf, "amadec_dts", 10))
+			para->aud_fmt = AFORMAT_MULAW;
+		else if (!strncmp(buf, "amadec_pcm_s16be", 16))
+			para->aud_fmt = AFORMAT_PCM_S16BE;
+		else if (!strncmp(buf, "amadec_flac", 11))
+			para->aud_fmt = AFORMAT_FLAC;
+		else if (!strncmp(buf, "amadec_cook", 11))
+			para->aud_fmt = AFORMAT_COOK;
+		else if (!strncmp(buf, "amadec_pcm_u8", 13))
+			para->aud_fmt = AFORMAT_PCM_U8;
+		else if (!strncmp(buf, "amadec_adpcm", 12))
+			para->aud_fmt = AFORMAT_ADPCM;
+		else if (!strncmp(buf, "amadec_amr", 10))
+			para->aud_fmt = AFORMAT_AMR;
+		else if (!strncmp(buf, "amadec_raac", 11))
+			para->aud_fmt = AFORMAT_RAAC;
+		else if (!strncmp(buf, "amadec_wma", 10))
+			para->aud_fmt = AFORMAT_WMA;
+		else if (!strncmp(buf,"amadec_dra",10))
+			para->aud_fmt = AFORMAT_DRA;
+	}
+
+	if (para->aud_fmt_orig == -1)
+		para->aud_fmt_orig = para->aud_fmt;
+	if (para->resolution_orig == -1)
+		para->resolution_orig = para->resolution;
+	if (para->sample_rate_orig == -1)
+		para->sample_rate_orig = para->sample_rate;
+	if (para->channels_orig == -1)
+		para->channels_orig = para->channels;
+	if (para->lfepresent_orig == -1)
+		para->lfepresent_orig = 0;
+	if (para->lfepresent == -1)
+		para->lfepresent = 0;
+
+	fd = get_amstream(dev);
+	if (fd == -1)
+	{
+		//AM_DEBUG(1, "cannot get status in this mode");
+		goto get_fail;
+	}
+
+	rc = ioctl(fd, AMSTREAM_IOC_AB_STATUS, (long)&astatus);
+	if (rc == -1)
+	{
+		AM_DEBUG(1, "AMSTREAM_IOC_AB_STATUS failed");
+		goto get_fail;
+	}
+
+	para->ab_size = astatus.status.size;
+	para->ab_data = astatus.status.data_len;
+	para->ab_free = astatus.status.free_len;
+
+	return AM_SUCCESS;
+
+get_fail:
+	return AM_FAILURE;
+}
+static AM_Bool_t aml_is_video_valid(AM_AV_Device_t *dev)
+{
+	AM_Bool_t has_video = AM_FALSE;
+	AV_TimeshiftData_t *tshift = NULL;
+
+	if ((dev->mode & AV_PLAY_TS) || (dev->mode & AV_INJECT))
+	{
+		has_video = VALID_VIDEO(dev->ts_player.play_para.vpid, dev->ts_player.play_para.vfmt);
+	}
+	else if(dev->mode & AV_TIMESHIFT)
+	{
+		tshift = dev->timeshift_player.drv_data;
+		if (tshift != NULL)
+			has_video =  VALID_VIDEO(tshift->tp.vpid, tshift->tp.vfmt);
+	}
+
+	return has_video;
+}
+static AM_ErrorCode_t aml_get_vstatus(AM_AV_Device_t *dev, AM_AV_VideoStatus_t *para)
+{
+	struct am_io_param vstatus;
+	char buf[32];
+	int fd, rc;
+	AM_Bool_t has_video = aml_is_video_valid(dev);
+
+	if (!has_video)
+	{
+	//	AM_DEBUG(1, "has no video pid data pls check your parameters");
+		return AM_FAILURE;
+	}
+
+	fd = get_amstream(dev);
+	if (fd == -1)
+	{
+		//AM_DEBUG(1, "cannot get status in this mode");
+		goto get_fail;
+	}
+
+	rc = ioctl(fd, AMSTREAM_IOC_VDECSTAT, &vstatus);
+
+	if (rc == -1)
+	{
+		AM_DEBUG(1, "AMSTREAM_IOC_VDECSTAT failed");
+		goto get_fail;
+	}
+
+	para->vid_fmt   = dev->ts_player.play_para.vfmt;
+	para->src_w     = vstatus.vstatus.width;
+	para->src_h     = vstatus.vstatus.height;
+	para->fps       = vstatus.vstatus.fps;
+	para->vid_ratio = convert_aspect_ratio(vstatus.vstatus.euAspectRatio);
+	para->frames    = 1;
+	para->interlaced  = 1;
+
+#if 1
+	if (AM_FileRead(VID_FRAME_FMT_FILE, buf, sizeof(buf)) >= 0) {
+		char *ptr = strstr(buf, "interlace");
+		if (ptr) {
+			para->interlaced = 1;
+		} else {
+			para->interlaced = 0;
+		}
+	}
+#else
+	if(AM_FileRead("/sys/module/amvdec_mpeg12/parameters/pic_type", buf, sizeof(buf))>=0){
+		int i = strtol(buf, NULL, 0);
+		if(i==1)
+			para->interlaced = 0;
+		else if(i==2)
+			para->interlaced = 1;
+	}
+	if(AM_FileRead("/sys/module/amvdec_h264/parameters/pic_type", buf, sizeof(buf))>=0){
+		int i = strtol(buf, NULL, 0);
+		if(i==1)
+			para->interlaced = 0;
+		else if(i==2)
+			para->interlaced = 1;
+       }
+       if(AM_FileRead("/sys/module/amvdec_avs/parameters/pic_type", buf, sizeof(buf))>=0){
+                int i = strtol(buf, NULL, 0);
+                if(i==1)
+                        para->interlaced = 0;
+                else if(i==2)
+                        para->interlaced = 1;
+       }
+#endif
+
+	rc = ioctl(fd, AMSTREAM_IOC_VB_STATUS, (long)&vstatus);
+	if (rc == -1)
+	{
+		AM_DEBUG(1, "AMSTREAM_IOC_VB_STATUS failed");
+		goto get_fail;
+	}
+
+	para->vb_size = vstatus.status.size;
+	para->vb_data = vstatus.status.data_len;
+	para->vb_free = vstatus.status.free_len;
+
+	return AM_SUCCESS;
+
+get_fail:
+	return AM_FAILURE;
+}
+
+static AM_ErrorCode_t aml_set_ppmgr_3dcmd(int cmd)
+{
+	int ppmgr_fd;
+	int arg = -1, ret;
+
+	ppmgr_fd = open(PPMGR_FILE, O_RDWR);
+	if (ppmgr_fd < 0)
+	{
+		AM_DEBUG(0, "Open /dev/ppmgr error(%s)!\n", strerror(errno));
+		return AM_AV_ERR_SYS;
+	}
+
+    switch (cmd)
+    {
+    case AM_AV_PPMGR_MODE3D_DISABLE:
+        arg = MODE_3D_DISABLE;
+        AM_DEBUG(1,"3D fucntion (0: Disalbe!)\n");
+        break;
+    case AM_AV_PPMGR_MODE3D_AUTO:
+        arg = MODE_3D_ENABLE|MODE_AUTO;
+        AM_DEBUG(1,"3D fucntion (1: Auto!)\n");
+        break;
+    case AM_AV_PPMGR_MODE3D_2D_TO_3D:
+        arg = MODE_3D_ENABLE|MODE_2D_TO_3D;
+        AM_DEBUG(1,"3D fucntion (2: 2D->3D!)\n");
+        break;
+    case AM_AV_PPMGR_MODE3D_LR:
+        arg = MODE_3D_ENABLE|MODE_LR;
+        AM_DEBUG(1,"3D fucntion (3: L/R!)\n");
+        break;
+    case AM_AV_PPMGR_MODE3D_BT:
+        arg = MODE_3D_ENABLE|MODE_BT;
+        AM_DEBUG(1,"3D fucntion (4: B/T!)\n");
+        break;
+    case AM_AV_PPMGR_MODE3D_OFF_LR_SWITCH:
+        arg = MODE_3D_ENABLE|MODE_LR;
+        AM_DEBUG(1,"3D fucntion (5: LR SWITCH OFF!)\n");
+        break;
+    case AM_AV_PPMGR_MODE3D_ON_LR_SWITCH:
+        arg = MODE_3D_ENABLE|MODE_LR_SWITCH;
+        AM_DEBUG(1,"3D fucntion (6: LR SWITCH!)\n");
+        break;
+    case AM_AV_PPMGR_MODE3D_FIELD_DEPTH:
+        arg = MODE_3D_ENABLE|MODE_FIELD_DEPTH;
+        AM_DEBUG(1,"3D function (7: FIELD_DEPTH!)\n");
+        break;
+    case AM_AV_PPMGR_MODE3D_OFF_3D_TO_2D:
+        arg = MODE_3D_ENABLE|MODE_LR;
+        AM_DEBUG(1,"3D fucntion (8: 3D_TO_2D_TURN_OFF!)\n");
+        break;
+    case AM_AV_PPMGR_MODE3D_L_3D_TO_2D:
+        arg = MODE_3D_ENABLE|MODE_3D_TO_2D_L;
+        AM_DEBUG(1,"3D function (9: 3D_TO_2D_L!)\n");
+        break;
+    case AM_AV_PPMGR_MODE3D_R_3D_TO_2D:
+        arg = MODE_3D_ENABLE|MODE_3D_TO_2D_R;
+        AM_DEBUG(1,"3D function (10: 3D_TO_2D_R!)\n");
+        break;
+    case AM_AV_PPMGR_MODE3D_OFF_LR_SWITCH_BT:
+        arg = MODE_3D_ENABLE|MODE_BT|BT_FORMAT_INDICATOR;
+        AM_DEBUG(1,"3D function (11: BT SWITCH OFF!)\n");
+        break;
+    case AM_AV_PPMGR_MODE3D_ON_LR_SWITCH_BT:
+        arg = MODE_3D_ENABLE|MODE_LR_SWITCH|BT_FORMAT_INDICATOR;
+        AM_DEBUG(1,"3D fucntion (12: BT SWITCH!)\n");
+        break;
+    case AM_AV_PPMGR_MODE3D_OFF_3D_TO_2D_BT:
+        arg = MODE_3D_ENABLE|MODE_BT;
+        AM_DEBUG(1,"3D fucntion (13: 3D_TO_2D_TURN_OFF_BT!)\n");
+        break;
+    case AM_AV_PPMGR_MODE3D_L_3D_TO_2D_BT:
+        arg = MODE_3D_ENABLE|MODE_3D_TO_2D_L|BT_FORMAT_INDICATOR;
+        AM_DEBUG(1,"3D function (14: 3D TO 2D L BT!)\n");
+        break;
+    case AM_AV_PPMGR_MODE3D_R_3D_TO_2D_BT:
+        arg = MODE_3D_ENABLE|MODE_3D_TO_2D_R|BT_FORMAT_INDICATOR;
+        AM_DEBUG(1,"3D function (15: 3D TO 2D R BT!)\n");
+        break;
+    default:
+    	AM_DEBUG(1, "Unkown set 3D cmd %d", cmd);
+    	arg = -1;
+    	break;
+    }
+
+    if (arg != -1)
+    {
+    	if (ioctl(ppmgr_fd, PPMGR_IOC_ENABLE_PP, arg) == -1)
+    	{
+    		AM_DEBUG(1, "Set 3D function failed: %s", strerror(errno));
+    		close(ppmgr_fd);
+    		return AM_AV_ERR_SYS;
+    	}
+    }
+
+	close(ppmgr_fd);
+
+    return AM_SUCCESS;
+}
+
+static int
+get_osd_prop(const char *mode, const char *p, const char *defv)
+{
+	char n[32];
+	char v[32];
+	int r;
+
+	snprintf(n, sizeof(n), "ubootenv.var.%soutput%s", mode, p);
+#ifdef ANDROID
+//	property_get(n,v,defv);
+#endif
+	sscanf(v, "%d", &r);
+
+	return r;
+}
+
+static void
+get_osd_rect(const char *mode, int *x, int *y, int *w, int *h)
+{
+	const char *m = mode?mode:"720p";
+	char defw[16], defh[16];
+	int r;
+
+	r = get_osd_prop(m, "x", "0");
+	*x = r;
+	r = get_osd_prop(m, "y", "0");
+	*y = r;
+	if (!strncmp(m, "480", 3)) {
+		snprintf(defw, sizeof(defw), "%d", 720);
+		snprintf(defh, sizeof(defh), "%d", 480);
+	} else if (!strncmp(m, "576", 3)) {
+		snprintf(defw, sizeof(defw), "%d", 720);
+		snprintf(defh, sizeof(defh), "%d", 576);
+	} else if (!strncmp(m, "720", 3)) {
+		snprintf(defw, sizeof(defw), "%d", 1280);
+		snprintf(defh, sizeof(defh), "%d", 720);
+	} else if (!strncmp(m, "1080", 4)) {
+		snprintf(defw, sizeof(defw), "%d", 1920);
+		snprintf(defh, sizeof(defh), "%d", 1080);
+	}
+
+
+	r = get_osd_prop(m, "width", defw);
+	*w = r;
+	r = get_osd_prop(m, "height", defh);
+	*h = r;
+}
+
+static AM_ErrorCode_t
+aml_set_vpath(AM_AV_Device_t *dev)
+{
+#if 0
+	static char s_bypass_hd[2];
+	static char s_bypass_hd_prog[2];
+	static char s_bypass_prog[2];
+	static char s_bypass_1080p[2];
+	static char s_bypass_dynamic[2];
+
+	AM_ErrorCode_t ret;
+	int times = 10;
+
+	AM_DEBUG(1, "set video path fs:%d di:%d ppmgr:%d", dev->vpath_fs, dev->vpath_di, dev->vpath_ppmgr);
+
+	//AM_FileEcho("/sys/class/deinterlace/di0/config", "disable");
+	/*
+	do{
+		ret = AM_FileEcho("/sys/class/vfm/map", "rm default");
+		if(ret!=AM_SUCCESS){
+			usleep(10000);
+		}
+	}while(ret!=AM_SUCCESS && times--);
+	*/
+
+	char video_axis[32];
+	AM_FileRead("/sys/class/video/axis", video_axis, sizeof(video_axis));
+
+	if(dev->vpath_fs==AM_AV_FREE_SCALE_ENABLE){
+		char mode[16];
+		char ppr[32];
+		AM_Bool_t blank = AM_TRUE;
+#ifdef ANDROID
+		{
+			int x, y, w, h;
+
+			AM_FileRead("/sys/class/display/mode", mode, sizeof(mode));
+
+			if(!strncmp(mode, "480i", 4)){
+				get_osd_rect("480i", &x, &y, &w, &h);
+			}else if(!strncmp(mode, "480p", 4)){
+				get_osd_rect("480p", &x, &y, &w, &h);
+			}else if(!strncmp(mode, "480cvbs", 7)){
+				get_osd_rect("480cvbs", &x, &y, &w, &h);
+			}else if(!strncmp(mode, "576i", 4)){
+				get_osd_rect("576i", &x, &y, &w, &h);
+			}else if(!strncmp(mode, "576p", 4)){
+				get_osd_rect("576p", &x, &y, &w, &h);
+			}else if(!strncmp(mode, "576cvbs", 7)){
+				get_osd_rect("576cvbs", &x, &y, &w, &h);
+			}else if(!strncmp(mode, "720p", 4)){
+				get_osd_rect("720p", &x, &y, &w, &h);
+				blank = AM_FALSE;
+			}else if(!strncmp(mode, "1080i", 5)){
+				get_osd_rect("1080i", &x, &y, &w, &h);
+			}else if(!strncmp(mode, "1080p", 5)){
+				get_osd_rect("1080p", &x, &y, &w, &h);
+			}else{
+				get_osd_rect(NULL, &x, &y, &w, &h);
+			}
+			snprintf(ppr, sizeof(ppr), "%d %d %d %d 0", x, y, x+w, y+h);
+		}
+#endif
+		AM_FileRead("/sys/class/graphics/fb0/request2XScale", mode, sizeof(mode));
+		if (blank && !strncmp(mode, "2", 1)) {
+			blank = AM_FALSE;
+		}
+		if(blank){
+			//AM_FileEcho("/sys/class/graphics/fb0/blank", "1");
+		}
+		//AM_FileEcho("/sys/class/graphics/fb0/free_scale", "1");
+		//AM_FileEcho("/sys/class/graphics/fb1/free_scale", "1");
+#ifdef ANDROID
+		{
+			AM_FileEcho("/sys/class/graphics/fb0/request2XScale", "2");
+			AM_FileEcho("/sys/class/graphics/fb1/scale", "0");
+
+			AM_FileEcho("/sys/module/amvdec_h264/parameters/dec_control", "0");
+			AM_FileEcho("/sys/module/amvdec_mpeg12/parameters/dec_control", "0");
+
+			s_bypass_hd[1] = '\0';
+			s_bypass_hd_prog[1] = '\0';
+			s_bypass_prog[1] = '\0';
+			s_bypass_1080p[1] = '\0';
+			AM_FileEcho("/sys/module/di/parameters/bypass_hd", s_bypass_hd);
+			AM_FileEcho("/sys/module/di/parameters/bypass_hd_prog", s_bypass_hd_prog);
+			AM_FileEcho("/sys/module/di/parameters/bypass_prog", s_bypass_prog);
+			AM_FileEcho("/sys/module/di/parameters/bypass_1080p", s_bypass_1080p);
+#ifdef ENABLE_CORRECR_AV_SYNC
+#else
+			s_bypass_dynamic[1] = '\0';
+			AM_FileEcho("/sys/module/di/parameters/bypass_dynamic", s_bypass_dynamic);
+#endif
+
+			AM_FileEcho("/sys/class/ppmgr/ppscaler","1");
+
+			AM_FileEcho("/sys/module/amvideo/parameters/smooth_sync_enable", "0");
+			usleep(200*1000);
+		}
+#endif
+	}else{
+		AM_Bool_t blank = AM_TRUE;
+		char m1080scale[8];
+		char mode[16];
+		char verstr[32];
+		char *reqcmd, *osd1axis, *osd1cmd;
+		int version;
+		AM_Bool_t scale=AM_TRUE;
+
+#ifdef ANDROID
+		{
+//			property_get("ro.platform.has.1080scale",m1080scale,"fail");
+			if(!strncmp(m1080scale, "fail", 4)){
+				scale = AM_FALSE;
+			}
+
+			AM_FileRead("/sys/class/display/mode", mode, sizeof(mode));
+
+			if(strncmp(m1080scale, "2", 1) && (strncmp(m1080scale, "1", 1) || (strncmp(mode, "1080i", 5) && strncmp(mode, "1080p", 5) && strncmp(mode, "720p", 4)))){
+				scale = AM_FALSE;
+			}
+
+			AM_FileRead("/sys/class/graphics/fb0/request2XScale", verstr, sizeof(verstr));
+			if(!strncmp(mode, "480i", 4) || !strncmp(mode, "480p", 4) || !strncmp(mode, "480cvbs", 7)){
+				reqcmd   = "16 720 480";
+				osd1axis = "1280 720 720 480";
+				osd1cmd  = "0x10001";
+			}else if(!strncmp(mode, "576i", 4) || !strncmp(mode, "576p", 4) || !strncmp(mode, "576cvbs", 7)){
+				reqcmd   = "16 720 576";
+				osd1axis = "1280 720 720 576";
+				osd1cmd  = "0x10001";
+			}else if(!strncmp(mode, "1080i", 5) || !strncmp(mode, "1080p", 5)){
+				reqcmd   = "8";
+				osd1axis = "1280 720 1920 1080";
+				osd1cmd  = "0x10001";
+			}else{
+				reqcmd   = "2";
+				osd1axis = NULL;
+				osd1cmd  = "0";
+				blank    = AM_FALSE;
+			}
+
+			if (blank && !strncmp(verstr, reqcmd, strlen(reqcmd))) {
+				blank = AM_FALSE;
+			}
+
+//			property_get("ro.build.version.sdk",verstr,"10");
+			if(sscanf(verstr, "%d", &version)==1){
+				if(version < 15){
+					blank = AM_FALSE;
+				}
+			}
+		}
+#endif
+		if(blank && scale){
+			//AM_FileEcho("/sys/class/graphics/fb0/blank", "1");
+		}
+
+		AM_FileEcho("/sys/class/graphics/fb0/free_scale", "0");
+		AM_FileEcho("/sys/class/graphics/fb1/free_scale", "0");
+
+#ifdef ANDROID
+		{
+			if(scale){
+				AM_FileEcho("/sys/class/graphics/fb0/request2XScale", reqcmd);
+				if(osd1axis){
+					AM_FileEcho("/sys/class/graphics/fb1/scale_axis", osd1axis);
+				}
+				AM_FileEcho("/sys/class/graphics/fb1/scale", osd1cmd);
+			}
+
+
+			AM_FileEcho("/sys/module/amvdec_h264/parameters/dec_control", "3");
+			AM_FileEcho("/sys/module/amvdec_mpeg12/parameters/dec_control", "62");
+
+			AM_FileRead("/sys/module/di/parameters/bypass_hd", s_bypass_hd, sizeof(s_bypass_hd));
+			AM_FileRead("/sys/module/di/parameters/bypass_hd_prog", s_bypass_hd_prog, sizeof(s_bypass_hd_prog));
+			AM_FileRead("/sys/module/di/parameters/bypass_prog", s_bypass_prog, sizeof(s_bypass_prog));
+			AM_FileRead("/sys/module/di/parameters/bypass_1080p", s_bypass_1080p, sizeof(s_bypass_1080p));
+
+#ifdef ENABLE_CORRECR_AV_SYNC
+			AM_DEBUG(1, "ENABLE_CORRECR_AV_SYNC");
+
+			AM_FileEcho("/sys/module/di/parameters/bypass_hd","0");
+			AM_FileEcho("/sys/module/di/parameters/bypass_hd_prog","0");
+			AM_FileEcho("/sys/module/di/parameters/bypass_prog","0");
+			AM_FileEcho("/sys/module/di/parameters/bypass_1080p","0");
+#else
+			AM_FileRead("/sys/module/di/parameters/bypass_dynamic", s_bypass_dynamic, sizeof(s_bypass_dynamic));
+
+			AM_DEBUG(1, "Not ENABLE_CORRECR_AV_SYNC");
+
+			AM_FileEcho("/sys/module/di/parameters/bypass_hd","0");
+			AM_FileEcho("/sys/module/di/parameters/bypass_hd_prog","0");
+			AM_FileEcho("/sys/module/di/parameters/bypass_prog","0");
+			AM_FileEcho("/sys/module/di/parameters/bypass_1080p","0");
+			AM_FileEcho("/sys/module/di/parameters/bypass_dynamic","1");
+
+			//AM_FileEcho("/sys/module/di/parameters/bypass_hd","1");
+#endif
+			AM_FileEcho("/sys/class/ppmgr/ppscaler","0");
+
+			//AM_FileEcho("/sys/class/ppmgr/ppscaler_rect","0 0 0 0 1");
+			//AM_FileEcho("/sys/class/video/axis", "0 0 0 0");
+			AM_FileEcho("/sys/module/amvideo/parameters/smooth_sync_enable", AV_SMOOTH_SYNC_VAL);
+			AM_FileEcho(DI_BYPASS_ALL_FILE,"0");
+			usleep(2000*1000);
+		}
+#endif
+	}
+
+	/*
+	if(dev->vpath_ppmgr!=AM_AV_PPMGR_DISABLE){
+		if (dev->vpath_ppmgr == AM_AV_PPMGR_MODE3D_2D_TO_3D){
+			AM_FileEcho("/sys/class/vfm/map", "add default decoder deinterlace d2d3 amvideo");
+			AM_FileEcho("/sys/class/d2d3/d2d3/debug", "enable");
+		}else{
+			AM_FileEcho("/sys/class/vfm/map", "add default decoder ppmgr amvideo");
+			if (dev->vpath_ppmgr!=AM_AV_PPMGR_ENABLE) {
+				//Set 3D mode
+				AM_TRY(aml_set_ppmgr_3dcmd(dev->vpath_ppmgr));
+			}
+		}
+
+	}else if(dev->vpath_di==AM_AV_DEINTERLACE_ENABLE){
+		AM_FileEcho("/sys/class/vfm/map", "add default decoder deinterlace amvideo");
+		AM_FileEcho("/sys/class/deinterlace/di0/config", "enable");
+	}else{
+		AM_FileEcho("/sys/class/vfm/map", "add default decoder amvideo");
+	}
+	*/
+
+	AM_FileEcho("/sys/class/video/axis", video_axis);
+	AM_FileRead("/sys/class/video/axis", video_axis, sizeof(video_axis));
+#else
+	UNUSED(dev);
+#endif
+	return AM_SUCCESS;
+}
+
+/**\brief 切换TS播放的音频*/
+static AM_ErrorCode_t aml_switch_ts_audio_legacy(AM_AV_Device_t *dev, uint16_t apid, AM_AV_AFormat_t afmt)
+{
+	int fd = -1;
+	AM_Bool_t audio_valid = VALID_AUDIO(apid, afmt);
+	AM_Bool_t has_video = VALID_VIDEO(dev->ts_player.play_para.vpid, dev->ts_player.play_para.vfmt);
+	AV_TSData_t *ts = NULL;
+
+	AM_DEBUG(1, "switch ts audio: A[%d:%d]", apid, afmt);
+
+	if (dev->ts_player.drv_data) {
+		ts = (AV_TSData_t*)dev->ts_player.drv_data;
+		fd = ts->fd;
+	}
+
+	if (fd < 0)
+	{
+		AM_DEBUG(1, "ts_player fd < 0, error!");
+		return AM_AV_ERR_SYS;
+	}
+
+	/*Stop Audio first*/
+	aml_stop_av_monitor(dev, &dev->ts_player.mon);
+
+	aml_set_ad_source(&ts->ad, 0, 0, 0, ts->adec);
+	audio_ops->adec_set_decode_ad(0, 0, 0, ts->adec);
+	audio_ops->adec_stop_decode(&ts->adec);
+
+	/*Set Audio PID & fmt*/
+	if (audio_valid)
+	{
+		if (ioctl(fd, AMSTREAM_IOC_AFORMAT, (int)afmt) == -1)
+		{
+			AM_DEBUG(1, "set audio format failed");
+			return AM_AV_ERR_SYS;
+		}
+		if (ioctl(fd, AMSTREAM_IOC_AID, (int)apid) == -1)
+		{
+			AM_DEBUG(1, "set audio PID failed");
+			return AM_AV_ERR_SYS;
+		}
+	}
+
+	/*reset audio*/
+	if (ioctl(fd, AMSTREAM_IOC_AUDIO_RESET, 0) == -1)
+	{
+		AM_DEBUG(1, "audio reset failed");
+		return AM_AV_ERR_SYS;
+	}
+
+	AM_TIME_GetClock(&dev->ts_player.av_start_time);
+
+	dev->ts_player.play_para.apid = apid;
+	dev->ts_player.play_para.afmt = afmt;
+
+#ifdef ENABLE_PCR
+	if (!show_first_frame_nosync()) {
+#ifdef ANDROID
+		//property_set("sys.amplayer.drop_pcm", "1");
+#endif
+	}
+	AM_FileEcho(ENABLE_RESAMPLE_FILE, "1");
+	aml_set_sync_mode(dev,
+		aml_calc_sync_mode(dev, audio_valid, has_video, 1, afmt, NULL));
+	audio_ops->adec_start_decode(fd, afmt, has_video, &ts->adec);
+	uint16_t sub_apid = dev->ts_player.play_para.sub_apid ;
+	AM_AV_AFormat_t sub_afmt = dev->ts_player.play_para.sub_afmt;
+	if (VALID_PID(sub_apid))
+		aml_set_audio_ad(dev, 1, sub_apid, sub_afmt);
+#endif /*ENABLE_PCR*/
+
+	/*Start Audio*/
+	aml_start_av_monitor(dev, &dev->ts_player.mon);
+
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t aml_switch_ts_audio_fmt(AM_AV_Device_t *dev, AV_TSData_t *ts, AV_TSPlayPara_t *tp)
+{
+	AM_Bool_t has_audio = AM_FALSE;
+	AM_Bool_t has_video = AM_FALSE;
+	AM_Bool_t has_pcr = AM_FALSE;
+
+	if (!ts || !tp) {
+		AM_DEBUG(1, "do switch ts audio, illegal operation, current mode [%d]", dev->mode);
+		return AM_AV_ERR_ILLEGAL_OP;
+	}
+
+	if (tp->apid != dev->alt_apid
+		|| tp->afmt != dev->alt_afmt) {
+		AM_DEBUG(1, "do switch ts audio: A[%d:%d] -> A[%d:%d]",
+			tp->apid, tp->afmt, dev->alt_apid, dev->alt_afmt);
+		tp->apid = dev->alt_apid;
+		tp->afmt = dev->alt_afmt;
+	} else {
+		AM_DEBUG(1, "do switch ts audio: A[%d:%d] -> A[%d:%d], ignore",
+			tp->apid, tp->afmt, dev->alt_apid, dev->alt_afmt);
+		return AM_SUCCESS;
+	}
+
+	if (ts->fd < 0)
+	{
+		AM_DEBUG(1, "amstream fd < 0, error!");
+		return AM_AV_ERR_SYS;
+	}
+
+	has_audio = VALID_AUDIO(tp->apid, tp->afmt);
+	has_video = VALID_VIDEO(tp->vpid, tp->vfmt);
+	has_pcr = VALID_PCR(tp->pcrpid);
+
+	aml_set_ad_source(&ts->ad, 0, 0, 0, ts->adec);
+	audio_ops->adec_set_decode_ad(0, 0, 0, ts->adec);
+	audio_ops->adec_stop_decode(&ts->adec);
+
+	/*Set Audio PID & fmt*/
+	if (has_audio)
+	{
+		if (ioctl(ts->fd, AMSTREAM_IOC_AFORMAT, (int)tp->afmt) == -1)
+		{
+			AM_DEBUG(1, "set audio format failed");
+			return AM_AV_ERR_SYS;
+		}
+		if (ioctl(ts->fd, AMSTREAM_IOC_AID, (int)tp->apid) == -1)
+		{
+			AM_DEBUG(1, "set audio PID failed");
+			return AM_AV_ERR_SYS;
+		}
+	}
+	else
+	{
+		return AM_SUCCESS;
+	}
+
+	/*reset audio*/
+	if (ioctl(ts->fd, AMSTREAM_IOC_AUDIO_RESET, 0) == -1)
+	{
+		AM_DEBUG(1, "audio reset failed");
+		return AM_AV_ERR_SYS;
+	}
+
+#ifdef ENABLE_PCR
+	if (!show_first_frame_nosync()) {
+#ifdef ANDROID
+		//property_set("sys.amplayer.drop_pcm", "1");
+#endif
+	}
+	AM_FileEcho(ENABLE_RESAMPLE_FILE, "1");
+
+	if ((has_video && has_audio) || has_pcr)
+		aml_set_tsync_enable(1);
+	else
+		aml_set_tsync_enable(0);
+
+	aml_set_sync_mode(dev,
+		aml_calc_sync_mode(dev, has_audio, has_video, has_pcr, tp->afmt, NULL));
+	audio_ops->adec_start_decode(ts->fd, tp->afmt, has_video, &ts->adec);
+
+	if (VALID_PID(tp->sub_apid))
+		aml_set_audio_ad(dev, 1, tp->sub_apid, tp->sub_afmt);
+#endif /*ENABLE_PCR*/
+	AM_DEBUG(1, "switch ts audio: end");
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t aml_switch_ts_audio(AM_AV_Device_t *dev, uint16_t apid, AM_AV_AFormat_t afmt)
+{
+	AM_ErrorCode_t err = AM_SUCCESS;
+
+	AM_DEBUG(1, "switch ts audio: A[%d:%d]", apid, afmt);
+
+	{
+		AV_TSPlayPara_t tp = {.apid = apid, .afmt = afmt};
+		setup_forced_pid(&tp);
+		apid = tp.apid;
+		afmt = tp.afmt;
+	}
+
+	dev->alt_apid = apid;
+	dev->alt_afmt = afmt;
+	dev->audio_switch = AM_TRUE;
+
+	return err;
+}
+
+
+/**\brief set vdec_h264 error_recovery_mode :0 or 2 -> skip display Mosaic  ,3: display mosaic in case of vdec hit error*/
+static AM_ErrorCode_t aml_set_vdec_error_recovery_mode(AM_AV_Device_t *dev, uint8_t error_recovery_mode)
+{
+    char buf[32];
+
+    UNUSED(dev);
+
+    if (error_recovery_mode > 3)
+    {
+       AM_DEBUG(1, "set error_recovery_mode input parameters error!");
+       return AM_FAILURE;
+    }
+
+    snprintf(buf, sizeof(buf), "%d", error_recovery_mode);
+    AM_FileEcho(VDEC_H264_ERROR_RECOVERY_MODE_FILE, buf);
+
+    return AM_SUCCESS;
+}
+
+AM_ErrorCode_t aml_reset_audio_decoder(AM_AV_Device_t *dev)
+{
+      int fd = -1;
+
+       if (dev->ts_player.drv_data)
+               fd = ((AV_TSData_t *)dev->ts_player.drv_data)->fd;
+
+       if (fd < 0)
+       {
+               AM_DEBUG(1, "ts_player fd < 0, error!");
+              return AM_AV_ERR_SYS;
+       }
+
+       /*reset audio*/
+       if (ioctl(fd, AMSTREAM_IOC_AUDIO_RESET, 0) == -1)
+       {
+               AM_DEBUG(1, "audio reset failed");
+               return AM_AV_ERR_SYS;
+       }
+
+       return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t aml_set_drm_mode(AM_AV_Device_t *dev, AM_AV_DrmMode_t drm_mode)
+{
+	int fd = -1;
+
+	dev->curr_para.drm_mode = drm_mode;
+
+	return AM_SUCCESS;
+}
+
+AM_ErrorCode_t aml_set_inject_audio(AM_AV_Device_t *dev, uint16_t apid, AM_AV_AFormat_t afmt)
+{
+	AV_InjectData_t *data;
+	AM_Bool_t audio_valid, video_valid;
+	int fd;
+	AM_Bool_t has_video = VALID_VIDEO(dev->ts_player.play_para.vpid, dev->ts_player.play_para.vfmt);
+
+	data = (AV_InjectData_t *)dev->inject_player.drv_data;
+
+	fd = (data->aud_fd == -1) ? data->vid_fd : data->aud_fd;
+
+	if (data->aud_id != -1) {
+		audio_ops->adec_stop_decode(&data->adec);
+		data->aud_id = -1;
+	}
+
+	if (apid && (apid<0x1fff)) {
+		if (ioctl(fd, AMSTREAM_IOC_AFORMAT, (int)afmt) == -1)
+		{
+			AM_DEBUG(1, "set audio format failed");
+			return AM_AV_ERR_SYS;
+		}
+
+		if (ioctl(fd, AMSTREAM_IOC_AID, (int)apid) == -1)
+		{
+			AM_DEBUG(1, "set audio PID failed");
+			return AM_AV_ERR_SYS;
+		}
+	}
+
+	/*reset audio*/
+	if (ioctl(fd, AMSTREAM_IOC_AUDIO_RESET, 0) == -1)
+	{
+		AM_DEBUG(1, "audio reset failed");
+		return AM_AV_ERR_SYS;
+	}
+
+	/*Start audio decoder*/
+	if (apid && (apid<0x1fff))
+	{
+		audio_ops->adec_start_decode(fd, afmt, has_video, &data->adec);
+	}
+
+	data->aud_id  = apid;
+	data->aud_fmt = afmt;
+
+	return AM_SUCCESS;
+}
+
+AM_ErrorCode_t aml_set_inject_subtitle(AM_AV_Device_t *dev, uint16_t spid, int stype)
+{
+	AV_InjectData_t *data;
+	int fd;
+
+	data = (AV_InjectData_t *)dev->inject_player.drv_data;
+
+	fd = (data->aud_fd == -1) ? data->vid_fd : data->aud_fd;
+
+	if (spid && (spid<0x1fff)) {
+		if (ioctl(fd, AMSTREAM_IOC_SID, spid) == -1)
+		{
+			AM_DEBUG(1, "set subtitle PID failed");
+			return AM_AV_ERR_SYS;
+		}
+
+		if (ioctl(fd, AMSTREAM_IOC_SUB_TYPE, stype) == -1)
+		{
+			AM_DEBUG(1, "set subtitle type failed");
+			return AM_AV_ERR_SYS;
+		}
+
+		if (ioctl(fd, AMSTREAM_IOC_SUB_RESET) == -1)
+		{
+			AM_DEBUG(1, "reset subtitle failed");
+			return AM_AV_ERR_SYS;
+		}
+	}
+
+	data->sub_id   = spid;
+	data->sub_type = stype;
+
+	return AM_SUCCESS;
+}
+
+static void ad_callback(const uint8_t * data,int len,void * user_data)
+{
+#ifdef USE_ADEC_IN_DVB
+	if (s_audio_cb == NULL) {
+	    printf("ad_callback [%d:%p] [user:%p]\n", len, data, user_data);
+	    audio_send_associate_data(user_data, (uint8_t *)data, len);
+	}
+#endif
+}
+
+static AM_ErrorCode_t aml_set_ad_source(AM_AD_Handle_t *ad, int enable, int pid, int fmt, void *user)
+{
+	AM_ErrorCode_t err = AM_SUCCESS;
+
+	UNUSED(fmt);
+
+	if (!ad)
+		return AM_AV_ERR_INVAL_ARG;
+
+	AM_DEBUG(1, "AD set source enable[%d] pid[%d] fmt[%d]", enable, pid, fmt);
+
+#ifdef USE_ADEC_IN_DVB
+
+	if (enable) {
+		AM_AD_Para_t para = {.dmx_id = 0, .pid = pid, .fmt = fmt};
+		err = AM_AD_Create(ad, &para);
+		if (err == AM_SUCCESS) {
+			err = AM_AD_SetCallback(*ad, ad_callback, user);
+			err = AM_AD_Start(*ad);
+			if (err != AM_SUCCESS)
+				AM_AD_Destroy(*ad);
+		}
+	} else {
+		if (*ad) {
+			err = AM_AD_Stop(*ad);
+			err = AM_AD_Destroy(*ad);
+			*ad = NULL;
+		}
+	}
+#else
+	if (enable) {
+		*ad = (AM_AD_Handle_t) 1;
+	} else {
+		if (*ad) {
+			err = AM_SUCCESS;
+			*ad = NULL;
+		}
+	}
+#endif
+	return err;
+}
+static AM_ErrorCode_t aml_set_audio_ad(AM_AV_Device_t *dev, int enable, uint16_t apid, AM_AV_AFormat_t afmt)
+{
+	AM_AD_Handle_t *pad = NULL;
+	void *adec = NULL;
+	uint16_t sub_apid;
+	AM_AV_AFormat_t sub_afmt;
+	AM_Bool_t is_valid_audio = VALID_AUDIO(apid, afmt);
+
+	AM_DEBUG(1, "AD aml set audio ad: enable[%d] pid[%d] fmt[%d]", enable, apid, afmt);
+
+	switch (dev->mode) {
+		case AV_PLAY_TS:
+			adec = ((AV_TSData_t*)dev->ts_player.drv_data)->adec;
+			pad = &((AV_TSData_t*)dev->ts_player.drv_data)->ad;
+			sub_apid = dev->ts_player.play_para.sub_apid;
+			sub_afmt = dev->ts_player.play_para.sub_afmt;
+			break;
+		case AV_INJECT:
+			adec = ((AV_InjectData_t*)dev->inject_player.drv_data)->adec;
+			pad = &((AV_InjectData_t*)dev->inject_player.drv_data)->ad;
+			sub_apid = dev->inject_player.para.sub_aud_pid;
+			sub_afmt = dev->inject_player.para.sub_aud_fmt;
+			break;
+		case AV_TIMESHIFT:
+			adec = ((AV_TimeshiftData_t*)dev->timeshift_player.drv_data)->ts.adec;
+			pad = &((AV_TimeshiftData_t*)dev->timeshift_player.drv_data)->ts.ad;
+			sub_apid = ((AV_TimeshiftData_t*)dev->timeshift_player.drv_data)->tp.sub_apid;
+			sub_afmt = ((AV_TimeshiftData_t*)dev->timeshift_player.drv_data)->tp.sub_afmt;
+			break;
+		default:
+			AM_DEBUG(1, "only valid in TS/INJ/TIMESHIFT mode");
+			return AM_AV_ERR_NOT_SUPPORTED;
+	}
+#ifdef USE_ADEC_IN_DVB
+	if (enable && !adec) {
+		AM_DEBUG(1, "no main audio, this is associate audio setting");
+		return AM_AV_ERR_ILLEGAL_OP;
+	}
+#endif
+
+	/*assume ad is enabled if ad handle is not NULL*/
+	if ((enable && *pad && (apid == sub_apid) && (afmt == sub_afmt))
+		|| (!enable && !*pad))
+		return AM_SUCCESS;
+
+	if (enable && is_valid_audio) {
+
+		if ((apid != sub_apid) || (afmt != sub_afmt))
+			aml_set_ad_source(pad, 0, sub_apid, sub_afmt, adec);
+
+		/*enable adec's ad*/
+		audio_ops->adec_set_decode_ad(1, apid, afmt, adec);
+
+		/*setup date source*/
+		aml_set_ad_source(pad, 1, apid, afmt, adec);
+
+	} else if (!enable && pad && *pad) {
+
+		/*shutdown date source*/
+		aml_set_ad_source(pad, 0, apid, afmt, adec);
+
+		/*disable adec's ad*/
+		audio_ops->adec_set_decode_ad(0, apid, afmt, adec);
+
+		apid = -1;
+		afmt = 0;
+	}
+
+	switch (dev->mode) {
+		case AV_PLAY_TS:
+			dev->ts_player.play_para.sub_apid = apid;
+			dev->ts_player.play_para.sub_afmt = afmt;
+			break;
+		case AV_INJECT:
+			dev->inject_player.para.sub_aud_pid = apid;
+			dev->inject_player.para.sub_aud_fmt = afmt;
+			break;
+		case AV_TIMESHIFT:
+			((AV_TimeshiftData_t*)dev->timeshift_player.drv_data)->tp.sub_apid = apid;
+			((AV_TimeshiftData_t*)dev->timeshift_player.drv_data)->tp.sub_afmt = afmt;
+			break;
+		default:
+			break;
+	}
+
+	return AM_SUCCESS;
+}
+
+static int aml_restart_inject_mode(AM_AV_Device_t *dev, AM_Bool_t destroy_thread)
+{
+	AV_InjectData_t *inj,pre_inject_data;
+	AV_InjectPlayPara_t inj_data;
+
+	AM_DEBUG(1, "aml_restart_inject_mode");
+
+	inj = dev->inject_player.drv_data;
+	memcpy(&pre_inject_data,inj,sizeof(AV_InjectData_t));
+	aml_destroy_inject_data(inj);
+	if (destroy_thread) {
+		aml_stop_av_monitor(dev, &dev->ts_player.mon);
+	}
+	//malloc
+	inj = aml_create_inject_data();
+	if (!inj)
+	{
+		AM_DEBUG(1, "not enough memory");
+		return AM_AV_ERR_NO_MEM;
+	}
+	dev->inject_player.drv_data = inj;
+	///replace the inject data
+
+	inj_data.para.aud_fmt = pre_inject_data.aud_fmt;
+	inj_data.para.aud_id = pre_inject_data.aud_id;
+	inj_data.para.pkg_fmt = pre_inject_data.pkg_fmt;
+	inj_data.para.vid_fmt = pre_inject_data.vid_fmt;
+	inj_data.para.vid_id = pre_inject_data.vid_id;
+	inj_data.para.sub_id = pre_inject_data.sub_id;
+	inj_data.para.sub_type = pre_inject_data.sub_type;
+	inj_data.para.channel = 0;
+	inj_data.para.data_width = 0;
+	inj_data.para.sample_rate = 0;
+
+	if (aml_start_inject(dev, inj, &inj_data) != AM_SUCCESS)
+	{
+		AM_DEBUG(1,"[aml_start_mode]  AM_AV_ERR_SYS");
+		return AM_AV_ERR_SYS;
+	} else {
+		dev->ts_player.play_para.afmt = inj->aud_fmt;
+		dev->ts_player.play_para.apid = inj->aud_id;
+		dev->ts_player.play_para.vfmt = inj->vid_fmt;
+		dev->ts_player.play_para.vpid = inj->vid_id;
+		dev->ts_player.play_para.sub_afmt = inj->sub_type;
+		dev->ts_player.play_para.sub_apid = inj->sub_id;
+		dev->ts_player.play_para.pcrpid = 0x1fff;
+
+		//ts = (AV_TSData_t*)dev->ts_player.drv_data;
+		//ts->fd = inj->vid_fd;//"/dev/amstream_mpts"
+		//ts->vid_fd = inj->cntl_fd;//"/dev/amvideo"
+		if (destroy_thread)
+			aml_start_av_monitor(dev, &dev->ts_player.mon);
+	}
+
+	return AM_SUCCESS;
+}
+static void aml_set_audio_cb(AM_AV_Device_t *dev,AM_AV_Audio_CB_t cb,void *user_data)
+{
+	AM_DEBUG(1, "%s %d", __FUNCTION__,__LINE__);
+
+	if (cb != NULL) {
+		audio_ops = &callback_audio_drv;
+		s_audio_cb = cb;
+		pUserData = user_data;
+	} else {
+#ifdef USE_ADEC_IN_DVB
+		audio_ops = &native_audio_drv;
+#else
+		audio_ops = &callback_audio_drv;
+#endif
+	}
+}
+
+static AM_ErrorCode_t aml_get_pts(AM_AV_Device_t *dev, int type, uint64_t *pts)
+{
+#define GAP_10SEC (90000*10)/*10s*/
+	char pts_buf[32];
+	const char *pts_file, *pts_bit32_file, *pts_tsync_file;
+	uint32_t pts_dmx = 0, pts_dmx_bit32 = 0, pts_dmx_2 = 0, pts_tsync = 0;
+	int retry = 0;
+
+	switch (type) {
+	case 1:
+		pts_file = AUDIO_DMX_PTS_FILE;
+		pts_bit32_file = AUDIO_DMX_PTS_BIT32_FILE;
+		pts_tsync_file = AUDIO_PTS_FILE;
+		break;
+	default:
+		pts_file = VIDEO_DMX_PTS_FILE;
+		pts_bit32_file = VIDEO_DMX_PTS_BIT32_FILE;
+		pts_tsync_file = VIDEO_PTS_FILE;
+		break;
+	}
+
+	retry = 2;
+	do {
+		memset(pts_buf, 0, sizeof(pts_buf));
+		if (AM_FileRead(pts_file, pts_buf, sizeof(pts_buf)) >= 0)
+			sscanf(pts_buf, "%d", &pts_dmx);
+
+		memset(pts_buf, 0, sizeof(pts_buf));
+		if (AM_FileRead(pts_bit32_file, pts_buf, sizeof(pts_buf)) >= 0)
+			sscanf(pts_buf, "%d", &pts_dmx_bit32);
+
+		memset(pts_buf, 0, sizeof(pts_buf));
+		if (AM_FileRead(pts_file, pts_buf, sizeof(pts_buf)) >= 0)
+			sscanf(pts_buf, "%d", &pts_dmx_2);
+	} while (retry-- && (abs(pts_dmx_2 - pts_dmx) > GAP_10SEC));
+
+	if ((abs(pts_dmx_2 - pts_dmx) > GAP_10SEC)) {
+		AM_DEBUG(1, "something wrong with the stream's pts");
+		*pts = 0L;
+		return AM_SUCCESS;
+	}
+
+	memset(pts_buf, 0, sizeof(pts_buf));
+	if (AM_FileRead(pts_tsync_file, pts_buf, sizeof(pts_buf)) >= 0)
+		sscanf(pts_buf, "%i", &pts_tsync);
+
+	*pts = pts_tsync;
+	if (pts_dmx_bit32 && (abs(pts_dmx_2 - pts_tsync) < (GAP_10SEC * 3)))
+		*pts += 0x100000000L;
+
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t aml_set_fe_status(AM_AV_Device_t *dev, int value)
+{
+    AM_DEBUG(1,"aml_set_fe_status value = %d",value);
+    g_festatus = value;
+    return AM_SUCCESS;
+}
+
+AM_ErrorCode_t aml_get_timeout_real(int timeout, struct timespec *ts)
+{
+	struct timespec ots;
+	int left, diff;
+
+	clock_gettime(CLOCK_REALTIME, &ots);
+
+	ts->tv_sec  = ots.tv_sec + timeout/1000;
+	ts->tv_nsec = ots.tv_nsec;
+
+	left = timeout % 1000;
+	left *= 1000000;
+	diff = 1000000000-ots.tv_nsec;
+
+	if (diff <= left)
+	{
+		ts->tv_sec++;
+		ts->tv_nsec = left-diff;
+	}
+	else
+	{
+		ts->tv_nsec += left;
+	}
+
+	return AM_SUCCESS;
+}
+
+#ifdef open
+#undef open
+#endif
+static void *aml_try_open_crypt(AM_Crypt_Ops_t *ops)
+{
+	if (ops && ops->open)
+		return ops->open();
+	return NULL;
+}
diff --git a/test/am_ca_key_test/inject_record_t5d/am_av/aml/player.h b/test/am_ca_key_test/inject_record_t5d/am_av/aml/player.h
new file mode 100644
index 0000000..b6c9bfe
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_av/aml/player.h
@@ -0,0 +1,260 @@
+/*
+* Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+*
+* This source code is subject to the terms and conditions defined in the
+* file 'LICENSE' which is part of this source code package. *
+* Description:
+*/
+#ifndef _PLAYER_H_
+#define _PLAYER_H_
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#define MSG_SIZE                    64
+#define MAX_VIDEO_STREAMS           8
+#define MAX_AUDIO_STREAMS           8
+#define MAX_SUB_INTERNAL            8
+#define MAX_SUB_EXTERNAL            24
+#define MAX_SUB_STREAMS             (MAX_SUB_INTERNAL + MAX_SUB_EXTERNAL)
+#define MAX_PLAYER_THREADS          32
+
+#define CALLBACK_INTERVAL			(300)
+ #define DEBUG_VARIABLE_DUR
+
+typedef enum
+{      
+	/******************************
+	* 0x1000x: 
+	* player do parse file
+	* decoder not running
+	******************************/
+	PLAYER_INITING  	= 0x10001,
+	PLAYER_TYPE_REDY  = 0x10002,
+	PLAYER_INITOK   	= 0x10003,	
+
+	/******************************
+	* 0x2000x: 
+	* playback status
+	* decoder is running
+	******************************/
+	PLAYER_RUNNING  	= 0x20001,
+	PLAYER_BUFFERING 	= 0x20002,
+	PLAYER_PAUSE    	= 0x20003,
+	PLAYER_SEARCHING	= 0x20004,
+	
+	PLAYER_SEARCHOK 	= 0x20005,
+	PLAYER_START    	= 0x20006,	
+	PLAYER_FF_END   	= 0x20007,
+	PLAYER_FB_END   	= 0x20008,
+
+	PLAYER_PLAY_NEXT	= 0x20009,	
+
+	/******************************
+	* 0x3000x: 
+	* player will exit	
+	******************************/
+	PLAYER_ERROR		= 0x30001,
+	PLAYER_PLAYEND  	= 0x30002,	
+	PLAYER_STOPED   	= 0x30003,  
+	PLAYER_EXIT   		= 0x30004, 
+	
+}player_status;
+
+typedef enum 
+{
+    UNKNOWN_FILE = 0,
+    AVI_FILE 		,
+    MPEG_FILE		,
+    WAV_FILE		,
+    MP3_FILE		,
+    AAC_FILE		,
+    AC3_FILE		,
+    RM_FILE			,
+    DTS_FILE		,        
+    MKV_FILE		,    
+    MOV_FILE       ,
+    MP4_FILE		,		
+    FLAC_FILE		,
+    H264_FILE		,
+    M2V_FILE        ,
+    FLV_FILE		,
+    P2P_FILE        ,
+    ASF_FILE        ,
+    FILE_MAX		,        
+}pfile_type;
+
+typedef struct
+{
+	char id;
+	char internal_external; //0:internal_sub 1:external_sub       
+	unsigned short width;
+	unsigned short height;
+	unsigned int sub_type;
+	char resolution;
+	long long subtitle_size;  
+	char *sub_language;   
+}msub_info_t;
+
+typedef struct
+{	
+	char *filename;
+	int  duration;  
+	long long  file_size;
+	pfile_type type;
+	int bitrate;
+	int has_video;
+	int has_audio;
+	int has_sub;
+	int nb_streams;
+	int total_video_num;
+	int cur_video_index;
+	int total_audio_num;
+	int cur_audio_index;
+	int total_sub_num;      
+	int cur_sub_index;	
+	int seekable;
+}mstream_info_t;
+
+typedef struct
+{	
+	mstream_info_t stream_info;
+	void *video_info[MAX_VIDEO_STREAMS];
+	void *audio_info[MAX_AUDIO_STREAMS];
+    	msub_info_t *sub_info[MAX_SUB_STREAMS];
+}media_info_t;
+
+typedef struct pid_info
+{
+	int num;
+	int pid[MAX_PLAYER_THREADS];
+}pid_info_t;
+
+typedef struct player_file_type
+{
+	const char *fmt_string;
+	int video_tracks;
+	int audio_tracks;
+	int subtitle_tracks;
+	/**/
+}player_file_type_t;
+
+
+#define state_pre(sta) (sta>>16)
+#define player_thread_init(sta)	(state_pre(sta)==0x1)
+#define player_thread_run(sta)	(state_pre(sta)==0x2)
+#define player_thread_stop(sta)	(state_pre(sta)==0x3)
+
+typedef int (*update_state_fun_t)(int pid,player_info_t *) ;
+typedef int (*notify_callback)(int pid,int msg,unsigned long ext1,unsigned long ext2);
+typedef enum
+{      
+	PLAYER_EVENTS_PLAYER_INFO=1,			///<ext1=player_info*,ext2=0,same as update_statue_callback 
+	PLAYER_EVENTS_STATE_CHANGED,			///<ext1=new_state,ext2=0,
+	PLAYER_EVENTS_ERROR,					///<ext1=error_code,ext2=message char *
+	PLAYER_EVENTS_BUFFERING,				///<ext1=buffered=d,d={0-100},ext2=0,
+	PLAYER_EVENTS_FILE_TYPE,				///<ext1=player_file_type_t*,ext2=0
+}player_events;
+
+typedef struct
+{
+    update_state_fun_t update_statue_callback;
+    int update_interval;
+    long callback_old_time;
+	notify_callback	   notify_fn;
+}callback_t;
+
+typedef struct
+ {
+	char  *file_name;	
+    char  *headers;
+	//List  *play_list;
+	int	video_index;
+	int	audio_index;
+	int sub_index;
+	int t_pos;	
+	int	read_max_cnt;
+	union
+	{     
+		struct{
+			unsigned int loop_mode:1;
+			unsigned int nosound:1;	
+			unsigned int novideo:1;	
+			unsigned int hassub:1;
+			unsigned int need_start:1;
+			#ifdef DEBUG_VARIABLE_DUR
+			unsigned int is_variable:1;
+			#endif
+		};
+		int mode;
+	};  
+	callback_t callback_fn;
+	int byteiobufsize;
+	int loopbufsize;
+	int enable_rw_on_pause;
+	/*
+	data%<min && data% <max  enter buffering;
+	data% >middle exit buffering;
+	*/
+	int auto_buffing_enable;
+	float buffing_min;
+	float buffing_middle;
+	float buffing_max;
+	int is_playlist;
+ }play_control_t; 
+ 
+int 	player_init();
+int     player_start(play_control_t *p,unsigned long  priv);
+int 	player_stop(int pid);
+int 	player_stop_async(int pid);
+int     player_exit(int pid);
+int 	player_pause(int pid);
+int	 	player_resume(int pid);
+int 	player_timesearch(int pid,int s_time);
+int     player_forward(int pid,int speed);
+int     player_backward(int pid,int speed);
+int     player_aid(int pid,int audio_id);
+int     player_sid(int pid,int sub_id);
+int 	player_progress_exit(void);
+int     player_list_allpid(pid_info_t *pid);
+int     check_pid_valid(int pid);
+int 	player_get_play_info(int pid,player_info_t *info);
+int 	player_get_media_info(int pid,media_info_t *minfo);
+int 	player_video_overlay_en(unsigned enable);
+int 	player_start_play(int pid);
+//int 	player_send_message(int pid, player_cmd_t *cmd);
+player_status 	player_get_state(int pid);
+unsigned int 	player_get_extern_priv(int pid);
+
+
+int 	audio_set_mute(int pid,int mute);
+int 	audio_get_volume_range(int pid,int *min,int *max);
+int 	audio_set_volume(int pid,float val);
+int 	audio_get_volume(int pid);
+int 	audio_set_volume_balance(int pid,int balance);
+int 	audio_swap_left_right(int pid);
+int 	audio_left_mono(int pid);
+int 	audio_right_mono(int pid);
+int 	audio_stereo(int pid);
+int 	audio_set_spectrum_switch(int pid,int isStart,int interval);
+int 	player_register_update_callback(callback_t *cb,update_state_fun_t up_fn,int interval_s);
+char 	*player_status2str(player_status status);
+
+//control interface
+int     player_loop(int pid);
+int     player_noloop(int pid);
+
+int 	check_url_type(char *filename);
+int 	play_list_player(play_control_t *pctrl,unsigned long priv);
+
+//freescale
+int 	enable_freescale(int cfg);
+int 	disable_freescale(int cfg);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/am_av/emu/Makefile b/test/am_ca_key_test/inject_record_t5d/am_av/emu/Makefile
new file mode 100644
index 0000000..b9a90bb
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_av/emu/Makefile
@@ -0,0 +1,8 @@
+BASE=../../..
+
+include $(BASE)/rule/def.mk
+
+O_TARGET=emu
+emu_SRCS=emu.c
+
+include $(BASE)/rule/rule.mk
diff --git a/test/am_ca_key_test/inject_record_t5d/am_av/emu/emu.c b/test/am_ca_key_test/inject_record_t5d/am_av/emu/emu.c
new file mode 100644
index 0000000..46e9560
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_av/emu/emu.c
@@ -0,0 +1,29 @@
+#ifdef _FORTIFY_SOURCE
+#undef _FORTIFY_SOURCE
+#endif
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-10-20: create the document
+ ***************************************************************************/
+
+#define AM_DEBUG_LEVEL 0
+
+#include <am_debug.h>
+#include "../am_av_internal.h"
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+const AM_AV_Driver_t emu_av_drv;
+
diff --git a/test/am_ca_key_test/inject_record_t5d/am_dmx/Makefile b/test/am_ca_key_test/inject_record_t5d/am_dmx/Makefile
new file mode 100644
index 0000000..dcb226f
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_dmx/Makefile
@@ -0,0 +1,19 @@
+BASE=../..
+
+include $(BASE)/rule/def.mk
+
+O_TARGET=am_dmx
+am_dmx_SRCS=am_dmx.c
+
+SUBDIRS=
+am_dmx_OBJS=
+
+ifeq ($(EMU_DEMUX), y)
+	SUBDIRS+=emu
+	am_dmx_OBJS+=emu/emu
+else
+	SUBDIRS+=linux_dvb dvr
+	am_dmx_OBJS+=linux_dvb/linux_dvb dvr/dvr
+endif
+
+include $(BASE)/rule/rule.mk
diff --git a/test/am_ca_key_test/inject_record_t5d/am_dmx/am_dmx.c b/test/am_ca_key_test/inject_record_t5d/am_dmx/am_dmx.c
new file mode 100644
index 0000000..ffea075
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_dmx/am_dmx.c
@@ -0,0 +1,887 @@
+#ifdef _FORTIFY_SOURCE
+#undef _FORTIFY_SOURCE
+#endif
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-05-21: create the document
+ ***************************************************************************/
+
+#define AM_DEBUG_LEVEL 1
+
+#include <am_debug.h>
+#include <am_mem.h>
+#include "am_dmx_internal.h"
+#include "../am_adp_internal.h"
+#include <string.h>
+#include <assert.h>
+#include <unistd.h>
+#include "am_misc.h"
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+//#define DMX_WAIT_CB /*Wait callback function stop in API*/
+
+#define DMX_SYNC
+
+#define DMX_BUF_SIZE       (4096)
+#define DMX_POLL_TIMEOUT   (200)
+#ifdef CHIP_8226H
+#define DMX_DEV_COUNT      (2)
+#elif defined(CHIP_8226M) || defined(CHIP_8626X)
+#define DMX_DEV_COUNT      (3)
+#else
+#define DMX_DEV_COUNT      (2)
+#endif
+
+#define DMX_CHAN_ISSET_FILTER(chan,fid)    ((chan)->filter_mask[(fid)>>3]&(1<<((fid)&3)))
+#define DMX_CHAN_SET_FILTER(chan,fid)      ((chan)->filter_mask[(fid)>>3]|=(1<<((fid)&3)))
+#define DMX_CHAN_CLR_FILTER(chan,fid)      ((chan)->filter_mask[(fid)>>3]&=~(1<<((fid)&3)))
+
+/****************************************************************************
+ * Static data
+ ***************************************************************************/
+
+#ifdef EMU_DEMUX
+extern const AM_DMX_Driver_t emu_dmx_drv;
+#define HW_DMX_DRV emu_dmx_drv
+#else
+extern const AM_DMX_Driver_t linux_dvb_dmx_drv;
+#define HW_DMX_DRV linux_dvb_dmx_drv
+#endif
+//extern const AM_DMX_Driver_t dvr_dmx_drv;
+//#define SW_DMX_DRV dvr_dmx_drv
+
+static AM_DMX_Device_t dmx_devices[DMX_DEV_COUNT] =
+{
+#ifdef EMU_DEMUX
+{
+.drv = &emu_dmx_drv,
+.src = AM_DMX_SRC_TS0
+},
+{
+.drv = &emu_dmx_drv,
+.src = AM_DMX_SRC_TS0
+}
+#else
+{
+.drv = &linux_dvb_dmx_drv,
+.src = AM_DMX_SRC_TS0
+},
+{
+.drv = &linux_dvb_dmx_drv,
+.src = AM_DMX_SRC_TS0
+}
+#if defined(CHIP_8226M) || defined(CHIP_8626X)
+,
+{
+.drv = &linux_dvb_dmx_drv,
+.src = AM_DMX_SRC_TS0
+}
+#endif
+#endif
+};
+
+/****************************************************************************
+ * Static functions
+ ***************************************************************************/
+ 
+/**\brief 根据设备号取得设备结构指针*/
+static AM_INLINE AM_ErrorCode_t dmx_get_dev(int dev_no, AM_DMX_Device_t **dev)
+{
+	if((dev_no<0) || (dev_no>=DMX_DEV_COUNT))
+	{
+		AM_DEBUG(1, "invalid demux device number %d, must in(%d~%d)", dev_no, 0, DMX_DEV_COUNT-1);
+		return AM_DMX_ERR_INVALID_DEV_NO;
+	}
+	
+	*dev = &dmx_devices[dev_no];
+	return AM_SUCCESS;
+}
+
+/**\brief 根据设备号取得设备结构并检查设备是否已经打开*/
+static AM_INLINE AM_ErrorCode_t dmx_get_openned_dev(int dev_no, AM_DMX_Device_t **dev)
+{
+	AM_TRY(dmx_get_dev(dev_no, dev));
+	
+	if((*dev)->open_count <= 0)
+	{
+		AM_DEBUG(1, "demux device %d has not been openned", dev_no);
+		return AM_DMX_ERR_INVALID_DEV_NO;
+	}
+	
+	return AM_SUCCESS;
+}
+
+/**\brief 根据ID取得对应filter结构,并检查设备是否在使用*/
+static AM_INLINE AM_ErrorCode_t dmx_get_used_filter(AM_DMX_Device_t *dev, int filter_id, AM_DMX_Filter_t **pf)
+{
+	AM_DMX_Filter_t *filter;
+	
+	if((filter_id<0) || (filter_id>=DMX_FILTER_COUNT))
+	{
+		AM_DEBUG(1, "invalid filter id, must in %d~%d", 0, DMX_FILTER_COUNT-1);
+		return AM_DMX_ERR_INVALID_ID;
+	}
+	
+	filter = &dev->filters[filter_id];
+	
+	if(!filter->used)
+	{
+		AM_DEBUG(1, "filter %d has not been allocated", filter_id);
+		return AM_DMX_ERR_NOT_ALLOCATED;
+	}
+	
+	*pf = filter;
+	return AM_SUCCESS;
+}
+
+/**\brief 数据检测线程*/
+static void* dmx_data_thread(void *arg)
+{
+	AM_DMX_Device_t *dev = (AM_DMX_Device_t*)arg;
+	uint8_t *sec_buf;
+	uint8_t *sec;
+	int sec_len;
+	AM_DMX_FilterMask_t mask;
+	AM_ErrorCode_t ret;
+
+#define BUF_SIZE (4096)
+
+	sec_buf = (uint8_t*)malloc(BUF_SIZE);
+	
+	while(dev->enable_thread)
+	{
+		AM_DMX_FILTER_MASK_CLEAR(&mask);
+		int id;
+		
+		ret = dev->drv->poll(dev, &mask, DMX_POLL_TIMEOUT);
+		if(ret==AM_SUCCESS)
+		{
+			if(AM_DMX_FILTER_MASK_ISEMPTY(&mask))
+				continue;
+
+#if defined(DMX_WAIT_CB) || defined(DMX_SYNC)
+			pthread_mutex_lock(&dev->lock);
+			dev->flags |= DMX_FL_RUN_CB;
+			pthread_mutex_unlock(&dev->lock);
+#endif
+				
+			for(id=0; id<DMX_FILTER_COUNT; id++)
+			{
+				AM_DMX_Filter_t *filter=&dev->filters[id];
+				AM_DMX_DataCb cb;
+				void *data;
+				
+				if(!AM_DMX_FILTER_MASK_ISSET(&mask, id))
+					continue;
+				
+				if(!filter->enable || !filter->used)
+					continue;
+				
+				sec_len = BUF_SIZE;
+
+#ifndef DMX_WAIT_CB
+				pthread_mutex_lock(&dev->lock);
+#endif
+				if(!filter->enable || !filter->used)
+				{
+					ret = AM_FAILURE;
+				}
+				else
+				{
+					cb   = filter->cb;
+					data = filter->user_data;
+					ret  = dev->drv->read(dev, filter, sec_buf, &sec_len);
+				}
+#ifndef DMX_WAIT_CB
+				pthread_mutex_unlock(&dev->lock);
+#endif
+				if(ret==AM_DMX_ERR_TIMEOUT)
+				{
+					sec = NULL;
+					sec_len = 0;
+				}
+				else if(ret!=AM_SUCCESS)
+				{
+					continue;
+				}
+				else
+				{
+					sec = sec_buf;
+				}
+				
+				if(cb)
+				{
+					if(id && sec)
+					AM_DEBUG(5, "filter %d data callback len fd:%ld len:%d, %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
+						id, (long)filter->drv_data, sec_len,
+						sec[0], sec[1], sec[2], sec[3], sec[4],
+						sec[5], sec[6], sec[7], sec[8], sec[9]);
+					cb(dev->dev_no, id, sec, sec_len, data);
+					if(id && sec)
+					AM_DEBUG(5, "filter %d data callback ok", id);
+				}
+			}
+#if defined(DMX_WAIT_CB) || defined(DMX_SYNC)
+			pthread_mutex_lock(&dev->lock);
+			dev->flags &= ~DMX_FL_RUN_CB;
+			pthread_mutex_unlock(&dev->lock);
+			pthread_cond_broadcast(&dev->cond);
+#endif
+		}
+		else
+		{
+			usleep(10000);
+		}
+	}
+
+	if(sec_buf)
+	{
+		free(sec_buf);
+	}
+	
+	return NULL;
+}
+
+/**\brief 等待回调函数停止运行*/
+static AM_INLINE AM_ErrorCode_t dmx_wait_cb(AM_DMX_Device_t *dev)
+{
+#ifdef DMX_WAIT_CB
+	if(dev->thread!=pthread_self())
+	{
+		while(dev->flags&DMX_FL_RUN_CB)
+			pthread_cond_wait(&dev->cond, &dev->lock);
+	}
+#else
+	UNUSED(dev);
+#endif
+	return AM_SUCCESS;
+}
+
+/**\brief 停止Section过滤器*/
+static AM_ErrorCode_t dmx_stop_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter)
+{
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	
+	if(!filter->used || !filter->enable)
+	{
+		return ret;
+	}
+	
+	if(dev->drv->enable_filter)
+	{
+		ret = dev->drv->enable_filter(dev, filter, AM_FALSE);
+	}
+	
+	if(ret>=0)
+	{
+		filter->enable = AM_FALSE;
+	}
+	
+	return ret;
+}
+
+/**\brief 释放过滤器*/
+static int dmx_free_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter)
+{
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	
+	if(!filter->used)
+		return ret;
+		
+	ret = dmx_stop_filter(dev, filter);
+	
+	if(ret==AM_SUCCESS)
+	{
+		if(dev->drv->free_filter)
+		{
+			ret = dev->drv->free_filter(dev, filter);
+		}
+	}
+	
+	if(ret==AM_SUCCESS)
+	{
+		filter->used=AM_FALSE;
+	}
+	
+	return ret;
+}
+
+/****************************************************************************
+ * API functions
+ ***************************************************************************/
+
+/**\brief 打开解复用设备
+ * \param dev_no 解复用设备号
+ * \param[in] para 解复用设备开启参数
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_dmx.h)
+ */
+AM_ErrorCode_t AM_DMX_Open(int dev_no, const AM_DMX_OpenPara_t *para)
+{
+	AM_DMX_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	
+	assert(para);
+	
+	AM_TRY(dmx_get_dev(dev_no, &dev));
+	
+	pthread_mutex_lock(&am_gAdpLock);
+	
+	if(dev->open_count > 0)
+	{
+		AM_DEBUG(1, "demux device %d has already been openned", dev_no);
+		dev->open_count++;
+		ret = AM_SUCCESS;
+		goto final;
+	}
+	
+	dev->dev_no = dev_no;
+
+//	if(para->use_sw_filter){
+//		dev->drv = &SW_DMX_DRV;
+//	}else{
+		dev->drv = &HW_DMX_DRV;
+//	}
+	
+	if(dev->drv->open)
+	{
+		ret = dev->drv->open(dev, para);
+	}
+	
+	if(ret==AM_SUCCESS)
+	{
+		pthread_mutex_init(&dev->lock, NULL);
+		pthread_cond_init(&dev->cond, NULL);
+		dev->enable_thread = AM_TRUE;
+		dev->flags = 0;
+		
+		if(pthread_create(&dev->thread, NULL, dmx_data_thread, dev))
+		{
+			pthread_mutex_destroy(&dev->lock);
+			pthread_cond_destroy(&dev->cond);
+			ret = AM_DMX_ERR_CANNOT_CREATE_THREAD;
+		}
+	}
+	
+	if(ret==AM_SUCCESS)
+	{
+		dev->open_count = 1;
+	}
+final:
+	pthread_mutex_unlock(&am_gAdpLock);
+	
+	return ret;
+}
+
+/**\brief 关闭解复用设备
+ * \param dev_no 解复用设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_dmx.h)
+ */
+AM_ErrorCode_t AM_DMX_Close(int dev_no)
+{
+	AM_DMX_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	int i;
+	
+	AM_TRY(dmx_get_openned_dev(dev_no, &dev));
+	
+	pthread_mutex_lock(&am_gAdpLock);
+
+	if (dev->open_count == 1)
+	{
+		dev->enable_thread = AM_FALSE;
+		pthread_join(dev->thread, NULL);
+
+		for(i=0; i<DMX_FILTER_COUNT; i++)
+		{
+			dmx_free_filter(dev, &dev->filters[i]);
+		}
+
+		if(dev->drv->close)
+		{
+			dev->drv->close(dev);
+		}
+
+		pthread_mutex_destroy(&dev->lock);
+		pthread_cond_destroy(&dev->cond);
+	}
+	dev->open_count--;
+	
+	pthread_mutex_unlock(&am_gAdpLock);
+	
+	return ret;
+}
+
+/**\brief 分配一个过滤器
+ * \param dev_no 解复用设备号
+ * \param[out] fhandle 返回过滤器句柄
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_dmx.h)
+ */
+AM_ErrorCode_t AM_DMX_AllocateFilter(int dev_no, int *fhandle)
+{
+	AM_DMX_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	int fid;
+	
+	assert(fhandle);
+	
+	AM_TRY(dmx_get_openned_dev(dev_no, &dev));
+	
+	pthread_mutex_lock(&dev->lock);
+	
+	for(fid=0; fid<DMX_FILTER_COUNT; fid++)
+	{
+		if(!dev->filters[fid].used)
+			break;
+	}
+	
+	if(fid>=DMX_FILTER_COUNT)
+	{
+		AM_DEBUG(1, "no free section filter");
+		ret = AM_DMX_ERR_NO_FREE_FILTER;
+	}
+	
+	if(ret==AM_SUCCESS)
+	{
+		dmx_wait_cb(dev);
+		
+		dev->filters[fid].id   = fid;
+		if(dev->drv->alloc_filter)
+		{
+			ret = dev->drv->alloc_filter(dev, &dev->filters[fid]);
+		}
+	}
+	
+	if(ret==AM_SUCCESS)
+	{
+		dev->filters[fid].used = AM_TRUE;
+		*fhandle = fid;
+	}
+	
+	pthread_mutex_unlock(&dev->lock);
+	
+	return ret;
+}
+
+/**\brief 设定Section过滤器
+ * \param dev_no 解复用设备号
+ * \param fhandle 过滤器句柄
+ * \param[in] params Section过滤器参数
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_dmx.h)
+ */
+AM_ErrorCode_t AM_DMX_SetSecFilter(int dev_no, int fhandle, const struct dmx_sct_filter_params *params)
+{
+	AM_DMX_Device_t *dev;
+	AM_DMX_Filter_t *filter;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	
+	assert(params);
+	
+	AM_TRY(dmx_get_openned_dev(dev_no, &dev));
+	
+	if(!dev->drv->set_sec_filter)
+	{
+		AM_DEBUG(1, "demux do not support set_sec_filter");
+		return AM_DMX_ERR_NOT_SUPPORTED;
+	}
+	
+	pthread_mutex_lock(&dev->lock);
+	
+	ret = dmx_get_used_filter(dev, fhandle, &filter);
+	
+	if(ret==AM_SUCCESS)
+	{
+		dmx_wait_cb(dev);
+		ret = dmx_stop_filter(dev, filter);
+	}
+	
+	if(ret==AM_SUCCESS)
+	{
+		ret = dev->drv->set_sec_filter(dev, filter, params);
+		AM_DEBUG(5, "set sec filter %d PID: %d filter: %02x:%02x %02x:%02x %02x:%02x %02x:%02x %02x:%02x %02x:%02x %02x:%02x %02x:%02x",
+				fhandle, params->pid,
+				params->filter.filter[0], params->filter.mask[0],
+				params->filter.filter[1], params->filter.mask[1],
+				params->filter.filter[2], params->filter.mask[2],
+				params->filter.filter[3], params->filter.mask[3],
+				params->filter.filter[4], params->filter.mask[4],
+				params->filter.filter[5], params->filter.mask[5],
+				params->filter.filter[6], params->filter.mask[6],
+				params->filter.filter[7], params->filter.mask[7]);
+	}
+	
+	pthread_mutex_unlock(&dev->lock);
+	
+	return ret;
+}
+
+/**\brief 设定PES过滤器
+ * \param dev_no 解复用设备号
+ * \param fhandle 过滤器句柄
+ * \param[in] params PES过滤器参数
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_dmx.h)
+ */
+AM_ErrorCode_t AM_DMX_SetPesFilter(int dev_no, int fhandle, const struct dmx_pes_filter_params *params)
+{
+	AM_DMX_Device_t *dev;
+	AM_DMX_Filter_t *filter;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	
+	assert(params);
+	
+	AM_TRY(dmx_get_openned_dev(dev_no, &dev));
+	
+	if(!dev->drv->set_pes_filter)
+	{
+		AM_DEBUG(1, "demux do not support set_pes_filter");
+		return AM_DMX_ERR_NOT_SUPPORTED;
+	}
+	
+	pthread_mutex_lock(&dev->lock);
+	
+	ret = dmx_get_used_filter(dev, fhandle, &filter);
+	
+	if(ret==AM_SUCCESS)
+	{
+		dmx_wait_cb(dev);
+		ret = dmx_stop_filter(dev, filter);
+	}
+	
+	if(ret==AM_SUCCESS)
+	{
+		ret = dev->drv->set_pes_filter(dev, filter, params);
+		AM_DEBUG(2, "set pes filter %d PID %d", fhandle, params->pid);
+	}
+	
+	pthread_mutex_unlock(&dev->lock);
+	
+	return ret;
+}
+
+/**\brief 释放一个过滤器
+ * \param dev_no 解复用设备号
+ * \param fhandle 过滤器句柄
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_dmx.h)
+ */
+AM_ErrorCode_t AM_DMX_FreeFilter(int dev_no, int fhandle)
+{
+	AM_DMX_Device_t *dev;
+	AM_DMX_Filter_t *filter;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	
+	AM_TRY(dmx_get_openned_dev(dev_no, &dev));
+	
+	pthread_mutex_lock(&dev->lock);
+	
+	ret = dmx_get_used_filter(dev, fhandle, &filter);
+	
+	if(ret==AM_SUCCESS)
+	{
+		dmx_wait_cb(dev);
+		ret = dmx_free_filter(dev, filter);
+	}
+	
+	pthread_mutex_unlock(&dev->lock);
+	
+	return ret;
+}
+
+/**\brief 让一个过滤器开始运行
+ * \param dev_no 解复用设备号
+ * \param fhandle 过滤器句柄
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_dmx.h)
+ */
+AM_ErrorCode_t AM_DMX_StartFilter(int dev_no, int fhandle)
+{
+	AM_DMX_Device_t *dev;
+	AM_DMX_Filter_t *filter = NULL;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	
+	AM_TRY(dmx_get_openned_dev(dev_no, &dev));
+	
+	pthread_mutex_lock(&dev->lock);
+	
+	ret = dmx_get_used_filter(dev, fhandle, &filter);
+	
+	if(!filter->enable)
+	{
+		if(ret==AM_SUCCESS)
+		{
+			if(dev->drv->enable_filter)
+			{
+				ret = dev->drv->enable_filter(dev, filter, AM_TRUE);
+			}
+		}
+		
+		if(ret==AM_SUCCESS)
+		{
+			filter->enable = AM_TRUE;
+		}
+	}
+	
+	pthread_mutex_unlock(&dev->lock);
+	
+	return ret;
+}
+
+/**\brief 停止一个过滤器
+ * \param dev_no 解复用设备号
+ * \param fhandle 过滤器句柄
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_dmx.h)
+ */
+AM_ErrorCode_t AM_DMX_StopFilter(int dev_no, int fhandle)
+{
+	AM_DMX_Device_t *dev;
+	AM_DMX_Filter_t *filter = NULL;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	
+	AM_TRY(dmx_get_openned_dev(dev_no, &dev));
+	
+	pthread_mutex_lock(&dev->lock);
+	
+	ret = dmx_get_used_filter(dev, fhandle, &filter);
+	
+	if(ret==AM_SUCCESS)
+	{
+		if(filter->enable)
+		{
+			dmx_wait_cb(dev);
+			ret = dmx_stop_filter(dev, filter);
+		}
+	}
+	
+	pthread_mutex_unlock(&dev->lock);
+	
+	return ret;
+}
+
+/**\brief 设置一个过滤器的缓冲区大小
+ * \param dev_no 解复用设备号
+ * \param fhandle 过滤器句柄
+ * \param size 缓冲区大小
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_dmx.h)
+ */
+AM_ErrorCode_t AM_DMX_SetBufferSize(int dev_no, int fhandle, int size)
+{
+	AM_DMX_Device_t *dev;
+	AM_DMX_Filter_t *filter;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	
+	AM_TRY(dmx_get_openned_dev(dev_no, &dev));
+	
+	pthread_mutex_lock(&dev->lock);
+	
+	if(!dev->drv->set_buf_size)
+	{
+		AM_DEBUG(1, "do not support set_buf_size");
+		ret = AM_DMX_ERR_NOT_SUPPORTED;
+	}
+	
+	if(ret==AM_SUCCESS)
+		ret = dmx_get_used_filter(dev, fhandle, &filter);
+	
+	if(ret==AM_SUCCESS)
+		ret = dev->drv->set_buf_size(dev, filter, size);
+	
+	pthread_mutex_unlock(&dev->lock);
+	
+	return ret;
+}
+
+/**\brief 取得一个过滤器对应的回调函数和用户参数
+ * \param dev_no 解复用设备号
+ * \param fhandle 过滤器句柄
+ * \param[out] cb 返回过滤器对应的回调函数
+ * \param[out] data 返回用户参数
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_dmx.h)
+ */
+AM_ErrorCode_t AM_DMX_GetCallback(int dev_no, int fhandle, AM_DMX_DataCb *cb, void **data)
+{
+	AM_DMX_Device_t *dev;
+	AM_DMX_Filter_t *filter;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	
+	AM_TRY(dmx_get_openned_dev(dev_no, &dev));
+	
+	pthread_mutex_lock(&dev->lock);
+	
+	ret = dmx_get_used_filter(dev, fhandle, &filter);
+	
+	if(ret==AM_SUCCESS)
+	{
+		if(cb)
+			*cb = filter->cb;
+	
+		if(data)
+			*data = filter->user_data;
+	}
+	
+	pthread_mutex_unlock(&dev->lock);
+	
+	return ret;
+}
+
+/**\brief 设置一个过滤器对应的回调函数和用户参数
+ * \param dev_no 解复用设备号
+ * \param fhandle 过滤器句柄
+ * \param[in] cb 回调函数
+ * \param[in] data 回调函数的用户参数
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_dmx.h)
+ */
+AM_ErrorCode_t AM_DMX_SetCallback(int dev_no, int fhandle, AM_DMX_DataCb cb, void *data)
+{
+	AM_DMX_Device_t *dev;
+	AM_DMX_Filter_t *filter;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	
+	AM_TRY(dmx_get_openned_dev(dev_no, &dev));
+	
+	pthread_mutex_lock(&dev->lock);
+	
+	ret = dmx_get_used_filter(dev, fhandle, &filter);
+	
+	if(ret==AM_SUCCESS)
+	{
+		dmx_wait_cb(dev);
+	
+		filter->cb = cb;
+		filter->user_data = data;
+	}
+	
+	pthread_mutex_unlock(&dev->lock);
+	
+	return ret;
+}
+
+/**\brief 设置解复用设备的输入源
+ * \param dev_no 解复用设备号
+ * \param src 输入源
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_dmx.h)
+ */
+AM_ErrorCode_t AM_DMX_SetSource(int dev_no, AM_DMX_Source_t src)
+{
+	AM_DMX_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	
+	AM_TRY(dmx_get_openned_dev(dev_no, &dev));
+	
+	pthread_mutex_lock(&dev->lock);
+	if(!dev->drv->set_source)
+	{
+		AM_DEBUG(1, "do not support set_source");
+		ret = AM_DMX_ERR_NOT_SUPPORTED;
+	}
+	
+	if(ret==AM_SUCCESS)
+	{
+		ret = dev->drv->set_source(dev, src);
+	}
+	
+	pthread_mutex_unlock(&dev->lock);
+	
+	if(ret==AM_SUCCESS)
+	{
+		pthread_mutex_lock(&am_gAdpLock);
+		dev->src = src;
+		pthread_mutex_unlock(&am_gAdpLock);
+	}
+	
+	return ret;
+}
+
+/**\brief DMX同步,可用于等待回调函数执行完毕
+ * \param dev_no 解复用设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_dmx.h)
+ */
+AM_ErrorCode_t AM_DMX_Sync(int dev_no)
+{
+	AM_DMX_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	
+	AM_TRY(dmx_get_openned_dev(dev_no, &dev));
+	
+	pthread_mutex_lock(&dev->lock);
+	if(dev->thread!=pthread_self())
+	{
+		while(dev->flags&DMX_FL_RUN_CB)
+			pthread_cond_wait(&dev->cond, &dev->lock);
+	}
+	pthread_mutex_unlock(&dev->lock);
+	
+	return ret;
+}
+
+AM_ErrorCode_t AM_DMX_GetScrambleStatus(int dev_no, AM_Bool_t dev_status[2])
+{
+	char buf[32];
+	char class_file[64];
+	int vflag, aflag;
+	int i;
+
+	dev_status[0] = dev_status[1] = AM_FALSE;
+	snprintf(class_file,sizeof(class_file), "/sys/class/dmx/demux%d_scramble", dev_no);
+	for (i=0; i<5; i++)
+	{
+		if(AM_FileRead(class_file, buf, sizeof(buf))==AM_SUCCESS)
+		{
+			sscanf(buf,"%d %d", &vflag, &aflag);
+			if (!dev_status[0])
+				dev_status[0] = vflag ? AM_TRUE : AM_FALSE;
+			if (!dev_status[1])
+				dev_status[1] = aflag ? AM_TRUE : AM_FALSE;
+			//AM_DEBUG(1, "AM_DMX_GetScrambleStatus video scamble %d, audio scamble %d\n", vflag, aflag);
+			if (dev_status[0] && dev_status[1])
+			{
+				return AM_SUCCESS;
+			}
+			usleep(10*1000);
+		}
+		else
+		{
+			AM_DEBUG(1, "AM_DMX_GetScrambleStatus read scamble status failed\n");
+			return AM_FAILURE;
+		}
+	}
+
+	return AM_SUCCESS;
+}
+
+
diff --git a/test/am_ca_key_test/inject_record_t5d/am_dmx/am_dmx.h b/test/am_ca_key_test/inject_record_t5d/am_dmx/am_dmx.h
new file mode 100644
index 0000000..8c8ba3b
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_dmx/am_dmx.h
@@ -0,0 +1,228 @@
+/***************************************************************************
+ * Copyright (C) 2017 Amlogic, Inc. 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.
+ *
+ * Description:
+ */
+/**\file
+ * \brief Demux module
+ *
+ * Basic data strucutres definition in "linux/dvb/dmx.h"
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-05-21: create the document
+ ***************************************************************************/
+
+#ifndef _AM_DMX_H
+#define _AM_DMX_H
+
+#include "am_types.h"
+/*add for config define for linux dvb *.h*/
+#include "am_config.h"
+#include <linux/dvb/dmx.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+/****************************************************************************
+ * Error code definitions
+ ****************************************************************************/
+
+/**\brief Error code of the demux module*/
+enum AM_DMX_ErrorCode
+{
+	AM_DMX_ERROR_BASE=AM_ERROR_BASE(AM_MOD_DMX),
+	AM_DMX_ERR_INVALID_DEV_NO,          /**< Invalid device number*/
+	AM_DMX_ERR_INVALID_ID,              /**< Invalid filer handle*/
+	AM_DMX_ERR_BUSY,                    /**< The device has already been openned*/
+	AM_DMX_ERR_NOT_ALLOCATED,           /**< The device has not been allocated*/
+	AM_DMX_ERR_CANNOT_CREATE_THREAD,    /**< Cannot create new thread*/
+	AM_DMX_ERR_CANNOT_OPEN_DEV,         /**< Cannot open device*/
+	AM_DMX_ERR_NOT_SUPPORTED,           /**< Not supported*/
+	AM_DMX_ERR_NO_FREE_FILTER,          /**< No free filter*/
+	AM_DMX_ERR_NO_MEM,                  /**< Not enough memory*/
+	AM_DMX_ERR_TIMEOUT,                 /**< Timeout*/
+	AM_DMX_ERR_SYS,                     /**< System error*/
+	AM_DMX_ERR_NO_DATA,                 /**< No data received*/
+	AM_DMX_ERR_END
+};
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+/**\brief Input source of the demux*/
+typedef enum
+{
+	AM_DMX_SRC_TS0,                    /**< TS input port 0*/
+	AM_DMX_SRC_TS1,                    /**< TS input port 1*/
+	AM_DMX_SRC_TS2,                    /**< TS input port 2*/
+	AM_DMX_SRC_TS3,                    /**< TS input port 3*/
+	AM_DMX_SRC_HIU,                     /**< HIU input (memory)*/
+	AM_DMX_SRC_HIU1
+} AM_DMX_Source_t;
+
+/**\brief Demux device open parameters*/
+typedef struct
+{
+	AM_Bool_t use_sw_filter;           /**< M_TURE to use DVR software filters.*/
+	int       dvr_fifo_no;             /**< Async fifo number if use software filters.*/
+	int       dvr_buf_size;            /**< Async fifo buffer size if use software filters.*/
+} AM_DMX_OpenPara_t;
+
+/**\brief Filter received data callback function
+ * \a fandle is the filter's handle.
+ * \a data is the received data buffer pointer.
+ * \a len is the data length.
+ * If \a data == null, means timeout.
+ */
+typedef void (*AM_DMX_DataCb) (int dev_no, int fhandle, const uint8_t *data, int len, void *user_data);
+
+
+/****************************************************************************
+ * Function prototypes  
+ ***************************************************************************/
+
+/**\brief Open a demux device
+ * \param dev_no Demux device number
+ * \param[in] para Demux device's open parameters
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DMX_Open(int dev_no, const AM_DMX_OpenPara_t *para);
+
+/**\brief Close a demux device
+ * \param dev_no Demux device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DMX_Close(int dev_no);
+
+/**\brief Allocate a filter
+ * \param dev_no Demux device number
+ * \param[out] fhandle Return the allocated filter's handle
+ * \retval AM_SUCCESS On success
+ * \return Error Code
+ */
+extern AM_ErrorCode_t AM_DMX_AllocateFilter(int dev_no, int *fhandle);
+
+/**\brief Set a section filter's parameters
+ * \param dev_no Demux device number
+ * \param fhandle Filter handle
+ * \param[in] params Section filter's parameters
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DMX_SetSecFilter(int dev_no, int fhandle, const struct dmx_sct_filter_params *params);
+
+/**\brief Set a PES filter's parameters
+ * \param dev_no Demux device number
+ * \param fhandle Filter handle
+ * \param[in] params PES filter's parameters
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DMX_SetPesFilter(int dev_no, int fhandle, const struct dmx_pes_filter_params *params);
+
+/**\brief Release an unused filter
+ * \param dev_no Demux device number
+ * \param fhandle Filter handle
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DMX_FreeFilter(int dev_no, int fhandle);
+
+/**\brief Start filtering
+ * \param dev_no Demux device number
+ * \param fhandle Filter handle
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DMX_StartFilter(int dev_no, int fhandle);
+
+/**\brief Stop filtering
+ * \param dev_no Demux device number
+ * \param fhandle Filter handle
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DMX_StopFilter(int dev_no, int fhandle);
+
+/**\brief Set the ring queue buffer size of a filter
+ * \param dev_no Demux device number
+ * \param fhandle Filter handle
+ * \param size Ring queue buffer size in bytes
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DMX_SetBufferSize(int dev_no, int fhandle, int size);
+
+/**\brief Get a filter's data callback function
+ * \param dev_no Demux device number
+ * \param fhandle Filter handle
+ * \param[out] cb Return the data callback function of the filter
+ * \param[out] data Return the user defined parameter of the callback function
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DMX_GetCallback(int dev_no, int fhandle, AM_DMX_DataCb *cb, void **data);
+
+/**\brief Set a filter's data callback function
+ * \param dev_no Demux device number
+ * \param fhandle Filter handle
+ * \param[in] cb New data callback function
+ * \param[in] data User defined parameter of the callback function
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DMX_SetCallback(int dev_no, int fhandle, AM_DMX_DataCb cb, void *data);
+
+/**\brief Set the demux's input source
+ * \param dev_no Demux device number
+ * \param src Input source
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DMX_SetSource(int dev_no, AM_DMX_Source_t src);
+
+/**\cond */
+/**\brief Sync the demux data
+ * \param dev_no Demux device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DMX_Sync(int dev_no);
+/**\endcond */
+
+/**
+ * Get the scramble status of the AV channels in the demux
+ * \param dev_no Demux device number
+ * \param[out] dev_status Return the AV channels's scramble status.
+ * dev_status[0] is the video status, dev_status[1] is the audio status.
+ * AM_TRUE means the channel is scrambled, AM_FALSE means the channel is not scrambled.
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DMX_GetScrambleStatus(int dev_no, AM_Bool_t dev_status[2]);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/am_dmx/am_dmx_internal.h b/test/am_ca_key_test/inject_record_t5d/am_dmx/am_dmx_internal.h
new file mode 100644
index 0000000..983449a
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_dmx/am_dmx_internal.h
@@ -0,0 +1,108 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief 解复用设备
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-05-21: create the document
+ ***************************************************************************/
+
+#ifndef _AM_DMX_INTERNAL_H
+#define _AM_DMX_INTERNAL_H
+
+#include <am_dmx.h>
+#include <am_util.h>
+#include <am_thread.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+#define DMX_FILTER_COUNT      (32)
+
+#define DMX_FL_RUN_CB         (1)
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+/**\brief 解复用设备*/
+typedef struct AM_DMX_Device AM_DMX_Device_t;
+
+/**\brief 过滤器*/
+typedef struct AM_DMX_Filter AM_DMX_Filter_t;
+
+/**\brief 过滤器位屏蔽*/
+typedef uint32_t AM_DMX_FilterMask_t;
+
+#define AM_DMX_FILTER_MASK_ISEMPTY(m)    (!(*(m)))
+#define AM_DMX_FILTER_MASK_CLEAR(m)      (*(m)=0)
+#define AM_DMX_FILTER_MASK_ISSET(m,i)    (*(m)&(1<<(i)))
+#define AM_DMX_FILTER_MASK_SET(m,i)      (*(m)|=(1<<(i)))
+
+/**\brief 解复用设备驱动*/
+typedef struct
+{
+	AM_ErrorCode_t (*open)(AM_DMX_Device_t *dev, const AM_DMX_OpenPara_t *para);
+	AM_ErrorCode_t (*close)(AM_DMX_Device_t *dev);
+	AM_ErrorCode_t (*alloc_filter)(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter);
+	AM_ErrorCode_t (*free_filter)(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter);
+	AM_ErrorCode_t (*set_sec_filter)(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, const struct dmx_sct_filter_params *params);
+	AM_ErrorCode_t (*set_pes_filter)(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, const struct dmx_pes_filter_params *params);
+	AM_ErrorCode_t (*enable_filter)(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, AM_Bool_t enable);
+	AM_ErrorCode_t (*set_buf_size)(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, int size);
+	AM_ErrorCode_t (*poll)(AM_DMX_Device_t *dev, AM_DMX_FilterMask_t *mask, int timeout);
+	AM_ErrorCode_t (*read)(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, uint8_t *buf, int *size);
+	AM_ErrorCode_t (*set_source)(AM_DMX_Device_t *dev, AM_DMX_Source_t src);
+} AM_DMX_Driver_t;
+
+/**\brief Section过滤器*/
+struct AM_DMX_Filter
+{
+	void      *drv_data; /**< 驱动私有数据*/
+	AM_Bool_t  used;     /**< 此Filter是否已经分配*/
+	AM_Bool_t  enable;   /**< 此Filter设备是否使能*/
+	int        id;       /**< Filter ID*/
+	AM_DMX_DataCb       cb;        /**< 解复用数据回调函数*/
+	void               *user_data; /**< 数据回调函数用户参数*/
+};
+
+/**\brief 解复用设备*/
+struct AM_DMX_Device
+{
+	int                 dev_no;  /**< 设备号*/
+	const AM_DMX_Driver_t *drv;  /**< 设备驱动*/
+	void               *drv_data;/**< 驱动私有数据*/
+	AM_DMX_Filter_t     filters[DMX_FILTER_COUNT];   /**< 设备中的Filter*/
+	int                 open_count; /**< 设备已经打开次数*/
+	AM_Bool_t           enable_thread; /**< 数据线程已经运行*/
+	int                 flags;   /**< 线程运行状态控制标志*/
+	pthread_t           thread;  /**< 数据检测线程*/
+	pthread_mutex_t     lock;    /**< 设备保护互斥体*/
+	pthread_cond_t      cond;    /**< 条件变量*/
+	AM_DMX_Source_t     src;     /**< TS输入源*/
+};
+
+
+/****************************************************************************
+ * Function prototypes  
+ ***************************************************************************/
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/am_dmx/dvr/Makefile b/test/am_ca_key_test/inject_record_t5d/am_dmx/dvr/Makefile
new file mode 100644
index 0000000..5f3ece2
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_dmx/dvr/Makefile
@@ -0,0 +1,8 @@
+BASE=../../..
+
+include $(BASE)/rule/def.mk
+
+O_TARGET=dvr
+dvr_SRCS=dvr.c
+
+include $(BASE)/rule/rule.mk
diff --git a/test/am_ca_key_test/inject_record_t5d/am_dmx/dvr/dvr.c b/test/am_ca_key_test/inject_record_t5d/am_dmx/dvr/dvr.c
new file mode 100644
index 0000000..ab7ae52
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_dmx/dvr/dvr.c
@@ -0,0 +1,700 @@
+#ifdef _FORTIFY_SOURCE
+#undef _FORTIFY_SOURCE
+#endif
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief DVR demux 驱动
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2012-02-4: create the document
+ ***************************************************************************/
+
+#define AM_DEBUG_LEVEL 5
+
+#include <am_debug.h>
+#include <am_mem.h>
+#include <am_misc.h>
+#include <am_dvr.h>
+#include "../am_dmx_internal.h"
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <poll.h>
+/*add for config define for linux dvb *.h*/
+#include <am_config.h>
+#include <linux/dvb/dmx.h>
+
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+typedef struct DVR_Channel_s DVR_Channel;
+typedef struct DVR_Filter_s  DVR_Filter;
+
+struct DVR_Channel_s
+{
+	int          used;
+	int          pid;
+	DVR_Filter  *filters;
+	uint8_t      buf[4096];
+	int          size;
+	int          cc;
+	AM_Bool_t    is_sec;
+};
+
+struct DVR_Filter_s
+{
+	AM_Bool_t    used;
+	AM_Bool_t    sec_filter;
+	AM_DMX_Filter_t *dmx_filter;
+	DVR_Channel *chan;
+	int          pid;
+	uint8_t      filter[DMX_FILTER_SIZE];
+	uint8_t      maskandmode[DMX_FILTER_SIZE];
+	uint8_t      maskandnotmode[DMX_FILTER_SIZE];
+};
+
+#define DVR_CHANNEL_COUNT 32
+#define DVR_FILTER_COUNT  32
+#define DVR_PID_COUNT     32
+
+typedef struct{
+	uint8_t      buf[256*1024];
+	size_t       start;
+	DVR_Channel  dvr_channels[DVR_CHANNEL_COUNT];
+	DVR_Filter   dvr_filters[DVR_FILTER_COUNT];
+	int          dvr_fd;
+	int          dmx_fds[DVR_PID_COUNT];
+	int          dmx_cnt;
+}DVR_Demux;
+
+/****************************************************************************
+ * Static data definitions
+ ***************************************************************************/
+
+static AM_ErrorCode_t dvr_open(AM_DMX_Device_t *dev, const AM_DMX_OpenPara_t *para);
+static AM_ErrorCode_t dvr_close(AM_DMX_Device_t *dev);
+static AM_ErrorCode_t dvr_alloc_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter);
+static AM_ErrorCode_t dvr_free_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter);
+static AM_ErrorCode_t dvr_set_sec_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, const struct dmx_sct_filter_params *params);
+static AM_ErrorCode_t dvr_set_pes_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, const struct dmx_pes_filter_params *params);
+static AM_ErrorCode_t dvr_enable_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, AM_Bool_t enable);
+static AM_ErrorCode_t dvr_set_buf_size(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, int size);
+static AM_ErrorCode_t dvr_poll(AM_DMX_Device_t *dev, AM_DMX_FilterMask_t *mask, int timeout);
+static AM_ErrorCode_t dvr_read(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, uint8_t *buf, int *size);
+static AM_ErrorCode_t dvr_set_source(AM_DMX_Device_t *dev, AM_DMX_Source_t src);
+
+const AM_DMX_Driver_t dvr_dmx_drv = {
+.open  = dvr_open,
+.close = dvr_close,
+.alloc_filter = dvr_alloc_filter,
+.free_filter  = dvr_free_filter,
+.set_sec_filter = dvr_set_sec_filter,
+.set_pes_filter = dvr_set_pes_filter,
+.enable_filter  = dvr_enable_filter,
+.set_buf_size   = dvr_set_buf_size,
+.poll           = dvr_poll,
+.read           = dvr_read,
+.set_source     = dvr_set_source
+};
+
+
+/****************************************************************************
+ * Static functions
+ ***************************************************************************/
+
+static AM_ErrorCode_t dvr_open(AM_DMX_Device_t *dev, const AM_DMX_OpenPara_t *para)
+{
+	char name[64];
+	DVR_Demux *dmx;
+	int fd;
+	AM_ErrorCode_t ret;
+
+	snprintf(name, sizeof(name), "/dev/dvb0.dvr%d", dev->dev_no);
+	fd = open(name, O_RDONLY);
+	if(fd == -1){
+		AM_DEBUG(1, "cannot open %s %s", name, strerror(errno));
+		return AM_DMX_ERR_CANNOT_OPEN_DEV;
+	}
+
+	fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK, 0);
+
+	if(para->dvr_buf_size > 0){
+		ret = ioctl(fd, DMX_SET_BUFFER_SIZE, para->dvr_buf_size);
+		if(ret == -1){
+			AM_DEBUG(1, "set dvr buffer size to %d failed", para->dvr_buf_size);
+		}
+	}
+
+	if(para->dvr_fifo_no >= 0){
+		char cmd[32];
+
+		snprintf(name, sizeof(name), "/sys/class/stb/asyncfifo%d_source", para->dvr_fifo_no);
+		snprintf(cmd, sizeof(cmd), "dmx%d", dev->dev_no);
+
+		AM_FileEcho(name, cmd);
+		AM_DEBUG(1, "%s -> %s", name, cmd);
+	}
+
+	dmx = (DVR_Demux*)malloc(sizeof(DVR_Demux));
+	if(!dmx){
+		AM_DEBUG(1, "not enough memory");
+		close(fd);
+		return AM_DMX_ERR_NO_MEM;
+	}
+
+	memset(dmx, 0, sizeof(DVR_Demux));
+	dmx->dvr_fd = fd;
+	dev->drv_data = dmx;
+
+	AM_DEBUG(1, "open DVR demux");
+
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t dvr_close(AM_DMX_Device_t *dev)
+{
+	DVR_Demux *dmx = (DVR_Demux*)dev->drv_data;
+	int i;
+
+	AM_DEBUG(1, "try to close DVR demux");
+	for(i=0; i<DVR_PID_COUNT; i++){
+		close(dmx->dmx_fds[i]);
+	}
+
+	close(dmx->dvr_fd);
+	free(dmx);
+
+	AM_DEBUG(1, "close DVR demux");
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t dvr_alloc_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter)
+{
+	DVR_Demux *dmx = (DVR_Demux*)dev->drv_data;
+	DVR_Filter *f;
+	int i;
+
+	for(i=0; i<DVR_FILTER_COUNT; i++){
+		f = &dmx->dvr_filters[i];
+		if(!f->used){
+			break;
+		}
+	}
+	
+	if(i >= DVR_FILTER_COUNT){
+		return AM_DMX_ERR_NO_FREE_FILTER;
+	}
+
+	f->used = AM_TRUE;
+	f->dmx_filter = filter;
+	f->sec_filter = AM_TRUE;
+	f->pid  = 0x1FFF;
+
+	filter->drv_data = f;
+
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t dvr_free_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter)
+{
+	DVR_Demux *dmx = (DVR_Demux*)dev->drv_data;
+	DVR_Filter *f = (DVR_Filter*)filter->drv_data;
+
+	dvr_enable_filter(dev, filter, AM_FALSE);
+	f->used = AM_FALSE;
+
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t dvr_set_sec_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, const struct dmx_sct_filter_params *params)
+{
+	DVR_Demux *dmx = (DVR_Demux*)dev->drv_data;
+	DVR_Filter *f = (DVR_Filter*)filter->drv_data;
+	AM_Bool_t enable = filter->enable;
+	int i;
+
+	if(enable){
+		dvr_enable_filter(dev, filter, AM_FALSE);
+	}
+
+	f->sec_filter = AM_TRUE;
+	f->pid = params->pid;
+
+	for(i=0; i<DMX_FILTER_SIZE; i++){
+		uint8_t mode, mask;
+
+		if((i == 1) || (i == 2)){
+			f->filter[i] = 0;
+			f->maskandmode[i] = 0;
+			f->maskandnotmode[i] = 0;
+			continue;
+		}
+
+		mask = params->filter.mask[i];
+		mode = ~params->filter.mode[i];
+
+		f->filter[i] = params->filter.filter[i];
+		f->maskandmode[i] = mask & mode;
+		f->maskandnotmode[i] = mask & ~mode;
+	}
+
+	if(enable){
+		dvr_enable_filter(dev, filter, AM_TRUE);
+	}
+
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t dvr_set_pes_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, const struct dmx_pes_filter_params *params)
+{
+	DVR_Demux *dmx = (DVR_Demux*)dev->drv_data;
+	DVR_Filter *f = (DVR_Filter*)filter->drv_data;
+	AM_Bool_t enable = filter->enable;
+	int i;
+
+	if(enable){
+		dvr_enable_filter(dev, filter, AM_FALSE);
+	}
+
+	f->sec_filter = AM_FALSE;
+	f->pid = params->pid;
+
+	if(enable){
+		dvr_enable_filter(dev, filter, AM_TRUE);
+	}
+
+	return AM_SUCCESS;
+}
+
+static DVR_Channel* dvr_find_channel(DVR_Demux *dmx, int pid, AM_Bool_t is_sec)
+{
+	DVR_Channel *ch;
+	int i;
+
+	for(i=0; i<DVR_CHANNEL_COUNT; i++){
+		ch = &dmx->dvr_channels[i];
+		if(ch->used && ch->pid==pid){
+			if(ch->is_sec != is_sec){
+				AM_DEBUG(1, "channel type and filter type mismatch");
+				return NULL;
+			}
+			ch->used++;
+			return ch;
+		}
+	}
+
+	for(i=0; i<DVR_CHANNEL_COUNT; i++){
+		ch = &dmx->dvr_channels[i];
+		if(!ch->used){
+			ch->used = 1;
+			ch->is_sec = is_sec;
+			ch->pid = pid;
+			ch->cc  = -1;
+			ch->filters = NULL;
+			return ch;
+		}
+	}
+
+	return NULL;
+}
+
+static AM_ErrorCode_t dvr_enable_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, AM_Bool_t enable)
+{
+	DVR_Demux *dmx = (DVR_Demux*)dev->drv_data;
+	DVR_Filter *f = (DVR_Filter*)filter->drv_data;
+	DVR_Channel *ch;
+	AM_Bool_t reset = AM_FALSE;
+
+	if(filter->enable == enable)
+		return AM_SUCCESS;
+
+	AM_DEBUG(1, "enable DVR filter %d", enable);
+	if(enable){
+		ch = dvr_find_channel(dmx, f->pid, f->sec_filter);
+		if(!ch){
+			return AM_DMX_ERR_NO_FREE_FILTER;
+		}
+
+		f->chan = ch;
+
+		if(ch->used == 1)
+			reset = AM_TRUE;
+	}else{
+		ch = f->chan;
+
+		ch->used--;
+
+		if(ch->used == 0)
+			reset = AM_TRUE;
+	}
+
+	if(reset){
+		char name[64];
+		struct dmx_pes_filter_params pparam;
+		int i;
+
+		for(i=0; i<dmx->dmx_cnt; i++){
+			close(dmx->dmx_fds[i]);
+		}
+		dmx->dmx_cnt = 0;
+
+		snprintf(name, sizeof(name), "/dev/dvb0.demux%d", dev->dev_no);
+
+		for(i=0; i<DVR_CHANNEL_COUNT; i++){
+			ch = &dmx->dvr_channels[i];
+			if(ch->used){
+				int fd;
+				int r;
+
+				fd = open(name, O_RDONLY);
+				if(fd==-1){
+					AM_DEBUG(1, "cannot open %s", name);
+					continue;
+				}
+
+				memset(&pparam, 0, sizeof(pparam));
+				pparam.pid = ch->pid;
+				pparam.input = DMX_IN_FRONTEND;
+				pparam.output = DMX_OUT_TS_TAP;
+				pparam.pes_type = DMX_PES_OTHER;
+
+				r = ioctl(fd, DMX_SET_PES_FILTER, &pparam);
+				if(r==-1){
+					AM_DEBUG(1, "DMX_SET_PES_FILTER failed");
+				}
+
+				r = ioctl(fd, DMX_START);
+				if(r==-1){
+					AM_DEBUG(1, "DMX_START failed");
+				}
+
+				AM_DEBUG(1, "dvr record pid %d", ch->pid);
+				dmx->dmx_fds[dmx->dmx_cnt++] = fd;
+			}
+		}
+	}
+	
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t dvr_set_buf_size(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, int size)
+{
+	UNUSED(dev);
+	UNUSED(filter);
+	UNUSED(size);
+	return AM_SUCCESS;
+}
+
+static void data_cb(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, uint8_t *data, int len)
+{
+	AM_DMX_DataCb cb;
+	void *udata;
+
+	cb = filter->cb;
+	udata = filter->user_data;
+
+	pthread_mutex_unlock(&dev->lock);
+	if(cb){
+		cb(dev->dev_no, filter->id, data, len, udata);
+	}
+	pthread_mutex_lock(&dev->lock);
+}
+
+static int check_sec(AM_DMX_Device_t *dev, DVR_Channel *ch, uint8_t *data, int left)
+{
+	DVR_Demux *dmx = (DVR_Demux*)dev->drv_data;
+	int slen;
+	int cpy, ret=0;
+
+	if(ch->size + left < 3){
+		memcpy(ch->buf+ch->size, data, left);
+		return left;
+	}
+
+	if(ch->size < 3){
+		cpy = 3 - ch->size;
+		memcpy(ch->buf+ch->size, data, cpy);
+		data += cpy;
+		left -= cpy;
+		ret += cpy;
+		ch->size = 3;
+	}
+
+	slen = (((ch->buf[1]<<8)|ch->buf[2])&0xFFF) + 3;
+	cpy = AM_MIN(slen - ch->size, left);
+	if(cpy){
+		memcpy(ch->buf+ch->size, data, cpy);
+		ret += cpy;
+		ch->size += cpy;
+	}
+
+	if(slen==ch->size){
+		int fid;
+		DVR_Filter *f;
+
+		for(fid=0; fid<DVR_FILTER_COUNT; fid++){
+			AM_Bool_t match = AM_TRUE;
+			AM_Bool_t check_neq = AM_FALSE, neq = AM_FALSE;
+			int i;
+
+			f = &dmx->dvr_filters[fid];
+
+			if(!f->used || f->chan!=ch)
+				continue;
+
+			for(i=0; i<DMX_FILTER_SIZE; i++){
+				uint8_t xor = ch->buf[i]^f->filter[i];
+
+				if(xor & f->maskandmode[i]){
+					match = AM_FALSE;
+					break;
+				}
+
+				if(f->maskandnotmode[i])
+					check_neq = AM_TRUE;
+
+				if(xor & f->maskandnotmode[i])
+					neq = AM_TRUE;
+			}
+
+			if(match && check_neq && !neq)
+				match = AM_FALSE;
+
+			if(match){
+				data_cb(dev, f->dmx_filter, ch->buf, ch->size);
+				break;
+			}
+		}
+
+		ch->size = 0;
+	}
+
+	return ret;
+}
+
+static void parse_sec(AM_DMX_Device_t *dev, DVR_Channel *ch, uint8_t *data, int left, AM_Bool_t p_start)
+{
+	int first = 1;
+	int slen;
+
+	if(p_start){
+		int pointer = data[0];
+
+		data++;
+		left--;
+
+		if(left>=pointer){
+			check_sec(dev, ch, data, pointer);
+		}
+
+		if(pointer){
+			data += pointer;
+			left -= pointer;
+		}
+
+		ch->size = 0;
+	}
+
+	while((left>0) && (first || data[0]!=0xFF)){
+		int cnt;
+
+		cnt = check_sec(dev, ch, data, left);
+		data += cnt;
+		left -= cnt;
+		first = 0;
+	}
+}
+
+static void parse_pes(AM_DMX_Device_t *dev, DVR_Channel *ch, uint8_t *data, int left)
+{
+	AM_DMX_Filter_t *filter;
+
+	filter = ch->filters->dmx_filter;
+	data_cb(dev, filter, data, left);
+}
+
+static int parse_ts_packet(AM_DMX_Device_t *dev, uint8_t *buf, int left)
+{
+	uint8_t *p = buf;
+	int off;
+	int pid, error, cc, ap_flags, s_flags, p_start;
+
+	for(off=0; off<left; off++){
+		if(p[off] == 0x47)
+			break;
+	}
+
+	if(off){
+		AM_DEBUG(1, "skip %d bytes", off);
+		p += off;
+		left -= off;
+	}
+
+	if(left < 188)
+		return off;
+
+	pid     = ((p[1]<<8)|p[2])&0x1FFF;
+	error   = p[1]&0x80;
+	p_start = p[1]&0x40;
+	s_flags = p[3]&0xC0;
+	ap_flags= p[3]&0x30;
+	cc      = p[3]&0x0F;
+
+	if((pid!=0x1FFF) && !s_flags && !error && (ap_flags&0x10)){
+		DVR_Demux *dmx = (DVR_Demux*)dev->drv_data;
+		int i;
+		DVR_Channel *ch;
+
+		pthread_mutex_lock(&dev->lock);
+
+		for(i=0; i<DVR_CHANNEL_COUNT; i++){
+			ch = &dmx->dvr_channels[i];
+
+			if(ch->used && ch->pid==pid)
+				break;
+		}
+
+		if(i<DVR_CHANNEL_COUNT){
+			uint8_t *payload;
+			int plen;
+
+			if(ch->cc >= 0){
+				int ecc;
+
+				if(ap_flags & 0x10){
+					ecc = (ch->cc+1)&0x0F;
+				}else{
+					ecc = ch->cc;
+				}
+				if(ecc != cc){
+					AM_DEBUG(1, "TS packet discontinue");
+				}
+			}
+
+			payload = p+4;
+			plen = 188-4;
+
+			if(ap_flags & 0x20){
+				int alen = payload[0] + 1;
+
+				payload += alen;
+				plen -= alen;
+			}
+
+			if(plen > 0){
+				if(ch->is_sec){
+					parse_sec(dev, ch, payload, plen, p_start);
+				}else{
+					parse_pes(dev, ch, payload, plen);
+				}
+			}
+
+			ch->cc = cc;
+		}
+
+		pthread_mutex_unlock(&dev->lock);
+	}
+
+	return off + 188;
+}
+
+static AM_ErrorCode_t dvr_poll(AM_DMX_Device_t *dev, AM_DMX_FilterMask_t *mask, int timeout)
+{
+	DVR_Demux *dmx = (DVR_Demux*)dev->drv_data;
+	struct pollfd pf;
+	int ret;
+	
+	UNUSED(mask);
+
+	pf.fd = dmx->dvr_fd;
+	pf.events = POLLIN|POLLERR;
+
+	ret = poll(&pf, 1, timeout);
+	if(ret <= 0){
+		//AM_DEBUG(1, "poll DVR timeout");
+		return AM_SUCCESS;
+	}
+
+	ret = read(dmx->dvr_fd, dmx->buf+dmx->start, sizeof(dmx->buf)-dmx->start);
+	if(ret > 0){
+		uint8_t *data = dmx->buf;
+		int total = ret + dmx->start;
+		int left = total;
+		int cnt;
+
+		//AM_DEBUG(1, "read DVR %d bytes", ret);
+
+		do{
+			cnt = parse_ts_packet(dev, data, left);
+			data += cnt;
+			left -= cnt;
+		}while(cnt && left);
+		
+		if(left)
+			memmove(dmx->buf, dmx->buf + total - left, left);
+
+		dmx->start = left;
+	}
+
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t dvr_read(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, uint8_t *buf, int *size)
+{
+	UNUSED(dev);
+	UNUSED(filter);
+	UNUSED(buf);
+	UNUSED(size);
+
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t dvr_set_source(AM_DMX_Device_t *dev, AM_DMX_Source_t src)
+{
+	char buf[32];
+	char *cmd;
+	
+	snprintf(buf, sizeof(buf), "/sys/class/stb/demux%d_source", dev->dev_no);
+	
+	switch(src)
+	{
+		case AM_DMX_SRC_TS0:
+			cmd = "ts0";
+		break;
+		case AM_DMX_SRC_TS1:
+			cmd = "ts1";
+		break;
+#if defined(CHIP_8226M) || defined(CHIP_8626X)
+		case AM_DMX_SRC_TS2:
+			cmd = "ts2";
+		break;
+#endif
+
+		case AM_DMX_SRC_HIU:
+			cmd = "hiu";
+		break;
+		case AM_DMX_SRC_HIU1:
+			cmd = "hiu1";
+		break;
+		default:
+			AM_DEBUG(1, "do not support demux source %d", src);
+		return AM_DMX_ERR_NOT_SUPPORTED;
+	}
+	
+	return AM_FileEcho(buf, cmd);
+}
+
diff --git a/test/am_ca_key_test/inject_record_t5d/am_dmx/emu/Makefile b/test/am_ca_key_test/inject_record_t5d/am_dmx/emu/Makefile
new file mode 100644
index 0000000..b9a90bb
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_dmx/emu/Makefile
@@ -0,0 +1,8 @@
+BASE=../../..
+
+include $(BASE)/rule/def.mk
+
+O_TARGET=emu
+emu_SRCS=emu.c
+
+include $(BASE)/rule/rule.mk
diff --git a/test/am_ca_key_test/inject_record_t5d/am_dmx/emu/emu.c b/test/am_ca_key_test/inject_record_t5d/am_dmx/emu/emu.c
new file mode 100644
index 0000000..bff03aa
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_dmx/emu/emu.c
@@ -0,0 +1,1044 @@
+#ifdef _FORTIFY_SOURCE
+#undef _FORTIFY_SOURCE
+#endif
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief 文件模拟解复用设备
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-06-03: create the document
+ ***************************************************************************/
+
+#define AM_DEBUG_LEVEL 5
+
+#include <am_debug.h>
+#include <am_mem.h>
+#include <am_util.h>
+#include <am_time.h>
+#include <am_time.h>
+#include <am_thread.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <limits.h>
+#include "../am_dmx_internal.h"
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+#define FILTER_BUF_SIZE        (4096+4)
+#define PARSER_BUF_SIZE        (512*1024)
+ 
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+/**\brief Channel type*/
+typedef enum {
+	CHAN_TYPE_SEC,
+	CHAN_TYPE_PES
+} ChannelType_t;
+
+/**\brief Filter*/
+typedef struct Filter Filter_t;
+struct Filter {
+	union {
+		__u16  pid;
+		struct dmx_sct_filter_params sct;
+		struct dmx_pes_filter_params pes;
+	} params;
+	uint8_t   value[DMX_FILTER_SIZE+2];
+	uint8_t   maskandmode[DMX_FILTER_SIZE+2];
+	uint8_t   maskandnotmode[DMX_FILTER_SIZE+2];
+	AM_Bool_t neq;
+	int       id;
+	ChannelType_t type;
+	Filter_t *prev;
+	Filter_t *next;
+	uint8_t  *buf;
+	int       buf_size;
+	int       begin;
+	int       bytes;
+	AM_Bool_t enable;
+	int       start_time;
+};
+
+/**\brief Parse stage*/
+typedef enum {
+	CHAN_STAGE_START,
+	CHAN_STAGE_HEADER,
+	CHAN_STAGE_PTS,
+	CHAN_STAGE_PTR,
+	CHAN_STAGE_DATA,
+	CHAN_STAGE_END
+} ChannelStage_t;
+
+/**\brief PID channel*/
+typedef struct Channel Channel_t;
+struct Channel {
+	uint16_t   pid;
+	Channel_t *prev;
+	Channel_t *next;
+	uint8_t    buf[FILTER_BUF_SIZE];
+	int        bytes;
+	uint8_t    cc;
+	ChannelStage_t stage;
+	ChannelType_t  type;
+	uint64_t       pts;
+	int            offset;
+};
+
+/**\brief TS parser*/
+typedef struct {
+	Channel_t *channels;
+	Filter_t  *filters;
+	char       fname[PATH_MAX];
+	FILE      *fp;
+	uint8_t    buf[PARSER_BUF_SIZE];
+	int        bytes;
+	int        parsed;
+	int        packet_len;
+	int        start_time;
+	int        rate;
+	pthread_t  thread;
+	pthread_mutex_t lock;
+	pthread_cond_t  cond;
+	AM_Bool_t  running;
+} TSParser_t;
+
+/****************************************************************************
+ * Static data definitions
+ ***************************************************************************/
+
+static AM_ErrorCode_t emu_open(AM_DMX_Device_t *dev, const AM_DMX_OpenPara_t *para);
+static AM_ErrorCode_t emu_close(AM_DMX_Device_t *dev);
+static AM_ErrorCode_t emu_alloc_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter);
+static AM_ErrorCode_t emu_free_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter);
+static AM_ErrorCode_t emu_set_sec_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, const struct dmx_sct_filter_params *params);
+static AM_ErrorCode_t emu_set_pes_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, const struct dmx_pes_filter_params *params);
+static AM_ErrorCode_t emu_enable_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, AM_Bool_t enable);
+static AM_ErrorCode_t emu_set_buf_size(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, int size);
+static AM_ErrorCode_t emu_poll(AM_DMX_Device_t *dev, AM_DMX_FilterMask_t *mask, int timeout);
+static AM_ErrorCode_t emu_read(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, uint8_t *buf, int *size);
+static AM_ErrorCode_t emu_set_source(AM_DMX_Device_t *dev, AM_DMX_Source_t src);
+
+const AM_DMX_Driver_t emu_dmx_drv = {
+.open  = emu_open,
+.close = emu_close,
+.alloc_filter = emu_alloc_filter,
+.free_filter  = emu_free_filter,
+.set_sec_filter = emu_set_sec_filter,
+.set_pes_filter = emu_set_pes_filter,
+.enable_filter  = emu_enable_filter,
+.set_buf_size   = emu_set_buf_size,
+.poll  = emu_poll,
+.read  = emu_read,
+.set_source     = emu_set_source
+};
+
+/****************************************************************************
+ * Static functions
+ ***************************************************************************/
+
+/**\brief Reset the channel*/
+static void chan_reset(Channel_t *chan)
+{
+	chan->bytes  = 0;
+	chan->cc     = 0xFF;
+	chan->offset = 0;
+	chan->pts    = 0;
+	chan->stage  = CHAN_STAGE_START;
+}
+
+/**\brief Reset the TS parser*/
+static void parser_reset(TSParser_t *parser)
+{
+	Channel_t *chan;
+	
+	parser->packet_len = 0;
+	parser->bytes = 0;
+	parser->rate = 0;
+	
+	if(parser->channels)
+	{
+		for(chan=parser->channels; chan; chan=chan->next)
+		{
+			chan_reset(chan);
+		}
+	}
+}
+
+/**\brief Get the channel in the parser*/
+static Channel_t* parser_get_chan(TSParser_t *parser, uint16_t pid)
+{
+	Channel_t *chan = NULL;
+	
+	if(parser->channels)
+	{
+		for(chan=parser->channels; chan; chan=chan->next)
+		{
+			if(chan->pid==pid)
+				return chan;
+		}
+	}
+	
+	chan = (Channel_t*)malloc(sizeof(Channel_t));
+	if(!chan)
+	{
+		AM_DEBUG(1, "not enough memory");
+		return NULL;
+	}
+	
+	chan->pid = pid;
+	
+	chan_reset(chan);
+	
+	if(parser->channels)
+	{
+		chan->prev = NULL;
+		chan->next = parser->channels;
+		parser->channels->prev = chan;
+		parser->channels = chan;
+	}
+	else
+	{
+		chan->prev = NULL;
+		chan->next = NULL;
+		parser->channels = chan;
+	}
+	
+	return chan;
+}
+
+/**\brief Parse the PTS from the PES header*/
+static int parse_pts(uint8_t *buf, uint64_t *pts)
+{
+	uint8_t sid, flags;
+	uint64_t v1, v2, v3;
+	
+	sid = buf[3];
+	if((sid==0xBC) || (sid==0xBE) || (sid==0xBF) || (sid==0xF0) || (sid==0xF1) || (sid==0xFF) ||
+			(sid==0xF2) || (sid==0xF8))
+		return -1;
+	
+	flags = buf[7]>>6;
+	if(!(flags&2))
+		return -1;
+	
+	v1 = (buf[9]>>1)&7;
+	v2 = (buf[10]<<7)|(buf[11]>>1);
+	v3 = (buf[12]<<7)|(buf[13]>>1);
+	*pts = (v1<<30)|(v2<<15)|v3;
+	return 0;
+}
+
+/**\brief Parse the payload data*/
+static int parse_payload(TSParser_t *parser, Channel_t *chan, uint8_t *ptr, int len, int start)
+{
+	if(start)
+	{
+		chan->bytes = 0;
+		chan->stage = CHAN_STAGE_HEADER;
+	}
+	else if(chan->stage==CHAN_STAGE_START)
+	{
+		return 0;
+	}
+
+	memcpy(chan->buf+chan->bytes, ptr, len);
+	chan->bytes += len;
+
+	if(chan->bytes<3)
+		return 0;
+	
+	if(chan->stage==CHAN_STAGE_HEADER)
+	{
+		if((chan->buf[0]==0x00) && (chan->buf[1]==0x00) && (chan->buf[2]==0x01))
+		{
+			chan->type  = CHAN_TYPE_PES;
+			chan->stage = CHAN_STAGE_PTS;
+		}
+		else
+		{
+			chan->type  = CHAN_TYPE_SEC;
+			chan->stage = CHAN_STAGE_PTR;
+		}
+	}
+	
+	if(chan->stage==CHAN_STAGE_PTS)
+	{
+		uint64_t pts;
+		
+		if(chan->bytes<14)
+			return 0;
+		
+		if(parse_pts(chan->buf, &pts)>=0)
+		{
+			int offset = ftell(parser->fp)-parser->bytes+parser->parsed;
+			if(chan->pts)
+			{
+				parser->rate = ((uint64_t)(offset-chan->offset))*1000/((pts-chan->pts)/90);
+				//AM_DEBUG(2, "ts bits rate %d", parser->rate*8);
+			}
+			
+			if(!chan->pts)
+			{
+				chan->pts    = pts;
+				chan->offset = offset;
+			}
+		}
+		
+		chan->stage = CHAN_STAGE_DATA;
+	}
+	else if(chan->stage==CHAN_STAGE_PTR)
+	{
+		int len = chan->buf[0]+1;
+		int left = chan->bytes-len;
+		
+		if(chan->bytes<len)
+			return 0;
+		
+		if(left)
+			memmove(chan->buf, chan->buf+len, left);
+		chan->bytes = left;
+		chan->stage = CHAN_STAGE_DATA;
+	}
+	
+	if(!chan->bytes)
+		return 0;
+	
+retry:
+	if(chan->stage==CHAN_STAGE_DATA)
+	{
+		Filter_t *f;
+		
+		switch(chan->type)
+		{
+			case CHAN_TYPE_PES:
+				for(f=parser->filters; f; f=f->next)
+				{
+					if(f->enable && (f->params.pid==chan->pid) && (f->type==chan->type))
+						break;
+				}
+				if(f)
+				{
+					int left = f->buf_size-f->bytes;
+					int len = AM_MIN(left, chan->bytes);
+					int pos = (f->begin+f->bytes)%f->buf_size;
+					int cnt = f->buf_size-pos;
+					
+					if(cnt>=len)
+					{
+						memcpy(f->buf+pos, chan->buf, len);
+					}
+					else
+					{
+						int cnt2 = len-cnt;
+						memcpy(f->buf+pos, chan->buf, cnt);
+						memcpy(f->buf, chan->buf+cnt, cnt2);
+					}
+					
+					pthread_cond_broadcast(&parser->cond);
+				}
+				chan->bytes = 0;
+			break;
+			case CHAN_TYPE_SEC:
+				if(chan->bytes<1)
+					return 0;
+				
+				if(chan->buf[0]==0xFF)
+				{
+					chan->stage = CHAN_STAGE_END;
+				}
+				else
+				{
+					int sec_len, left;
+
+					if(chan->bytes<3)
+						return 0;
+
+					sec_len = ((chan->buf[1]<<8)|chan->buf[2])&0xFFF;
+					sec_len += 3;
+
+					if(chan->bytes<sec_len)
+						return 0;
+
+					for(f=parser->filters; f; f=f->next)
+					{
+						AM_Bool_t match = AM_TRUE;
+						AM_Bool_t neq = AM_FALSE;
+						int i;
+						
+						if(!f->enable || (f->type!=chan->type) || (f->params.pid!=chan->pid))
+							continue;
+						
+						for(i=0; i<DMX_FILTER_SIZE+2; i++)
+						{
+							uint8_t xor = chan->buf[i]^f->value[i];
+							
+							if(xor&f->maskandmode[i])
+							{
+								match = AM_FALSE;
+								break;
+							}
+							
+							if(xor&f->maskandnotmode[i])
+								neq = AM_TRUE;
+						}
+						
+						if(match && f->neq && !neq)
+							match = AM_FALSE;
+						if(!match) continue;
+						
+						break;
+					}
+					
+					if(f)
+					{
+						int left = f->buf_size-f->bytes;
+						int pos = (f->begin+f->bytes)%f->buf_size;
+						int cnt = f->buf_size-pos;
+
+						if(left<sec_len)
+						{
+							AM_DEBUG(1, "section buffer overflow");
+							return 0;
+						}
+						
+						if(cnt>=sec_len)
+						{
+							memcpy(f->buf+pos, chan->buf, sec_len);
+						}
+						else
+						{
+							int cnt2 = sec_len-cnt;
+							memcpy(f->buf+pos, chan->buf, cnt);
+							memcpy(f->buf, chan->buf+cnt, cnt2);
+						}
+						
+						f->bytes += sec_len;
+						pthread_cond_broadcast(&parser->cond);
+					}
+					
+					left = chan->bytes-sec_len;
+					if(left)
+					{
+						memmove(chan->buf, chan->buf+sec_len, left);
+					}
+					chan->bytes = left;
+					if(left)
+						goto retry;
+				}
+			break;
+		}
+	}
+	
+	if(chan->stage==CHAN_STAGE_END)
+		chan->bytes = 0;
+	
+	return 0;
+}
+
+/**\brief Parse the TS packet*/
+static int parse_ts_packet(TSParser_t *parser)
+{
+	int p = parser->parsed, left=188;
+	uint8_t *ptr;
+	uint16_t pid;
+	uint8_t tei, cc, af_avail, p_avail, ts_start, sc;
+	Channel_t *chan;
+	
+	/*Scan the sync byte*/
+	while(parser->buf[p]!=0x47)
+	{
+		p++;
+		if(p>=parser->bytes)
+		{
+			parser->parsed = parser->bytes;
+			return 0;
+		}
+	}
+	
+	if(p!=parser->parsed)
+		AM_DEBUG(3, "skip %d bytes", p-parser->parsed);
+	
+	parser->parsed = p;
+	
+	/*Check the packet length*/
+	if(!parser->packet_len)
+	{
+		if(parser->bytes-p>188)
+		{
+			if(parser->buf[p+188]==0x47)
+			{
+				parser->packet_len = 188;
+			}
+		}
+		if(!parser->packet_len && (parser->bytes-p>204))
+		{
+			if(parser->buf[p+204]==0x47)
+			{
+				parser->packet_len = 204;
+			}
+		}
+		
+		if(!parser->packet_len)
+		{
+			return 0;
+		}
+		else
+		{
+			AM_DEBUG(2, "packet length %d", parser->packet_len);
+		}
+	}
+	
+	if(parser->bytes-p<parser->packet_len)
+		return 0;
+	
+	ptr = &parser->buf[p];
+	tei = ptr[1]&0x80;
+	ts_start = ptr[1]&0x40;
+	pid = ((ptr[1]<<8)|ptr[2])&0x1FFF;
+	sc  = ptr[3]&0xC0;
+	cc  = ptr[3]&0x0F;
+	af_avail = ptr[3]&0x20;
+	p_avail  = ptr[3]&0x10;
+
+	if(pid==0x1FFF)
+		goto end;
+	
+	if(tei)
+	{
+		AM_DEBUG(3, "ts error");
+		goto end;
+	}
+	
+	chan = parser_get_chan(parser, pid);
+	if(!chan)
+		goto end;
+	
+	/*if(chan->cc!=0xFF)
+	{
+		if(chan->cc!=cc)
+			AM_DEBUG(3, "discontinuous");
+	}*/
+	
+	if(p_avail)
+		cc = (cc+1)&0x0f;
+	chan->cc = cc;
+	
+	ptr += 4;
+	left-= 4;
+	
+	if(af_avail)
+	{
+		left-= ptr[0]+1;
+		ptr += ptr[0]+1;
+	}
+	
+	if(p_avail && (left>0) && !sc)
+	{
+		parse_payload(parser, chan, ptr, left, ts_start);
+	}
+	
+end:
+	parser->parsed += parser->packet_len;
+	return 1;
+}
+
+/**\brief TS file parser thread*/
+static void* parser_thread(void *arg)
+{
+	TSParser_t *parser = (TSParser_t*)arg;
+	
+	parser->fname[0] = 0;
+	parser->fp = NULL;
+	parser_reset(parser);
+	
+	while(parser->running)
+	{
+		char *fname;
+		FILE *fp;
+		
+		/*Reset the input file*/
+		fname = getenv("AM_TSFILE");
+		if(fname)
+		{
+			if(!strcmp(fname, parser->fname))
+			{
+				fp = parser->fp;
+			}
+			else
+			{
+				int len = AM_MIN(strlen(fname), sizeof(parser->fname)-1);
+				
+				strncpy(parser->fname, fname, len);
+				parser->fname[len] = 0;
+				fp = fopen(fname, "r");
+				if(!fp)
+					AM_DEBUG(2, "cannot open \"%s\"", fname);
+				else
+					AM_DEBUG(2, "switch to ts file \"%s\"", fname);
+				AM_TIME_GetClock(&parser->start_time);
+			}
+		}
+		else
+		{
+			fp = NULL;
+		}
+		
+		if(fp!=parser->fp)
+		{
+			if(parser->fp)
+				fclose(parser->fp);
+			parser->fp = fp;
+			parser_reset(parser);
+		}
+		
+		/*Read the TS file*/
+		if(parser->fp)
+		{
+			int left = sizeof(parser->buf)-parser->bytes;
+			int cnt;
+			
+			if(feof(parser->fp))
+			{
+				rewind(parser->fp);
+				parser_reset(parser);
+				AM_TIME_GetClock(&parser->start_time);
+				AM_DEBUG(2, "ts file rewind");
+			}
+			
+			cnt = fread(parser->buf+parser->bytes, 1, left, parser->fp);
+			if(cnt==0)
+			{
+				AM_DEBUG(1, "read ts file error");
+				sleep(1);
+				continue;
+			}
+			
+			parser->bytes += cnt;
+		}
+		
+		/*Parse the TS file*/
+		if(parser->bytes)
+		{
+			int left;
+			
+			if(parser->bytes<parser->packet_len)
+				continue;
+			
+			parser->parsed = 0;
+			
+			pthread_mutex_lock(&parser->lock);
+			
+			while(1)
+			{
+				if(!parse_ts_packet(parser))
+					break;
+			}
+			
+			pthread_mutex_unlock(&parser->lock);
+			
+			left = parser->bytes-parser->parsed;
+			if(left)
+			{
+				memmove(parser->buf, parser->buf+parser->parsed, left);
+			}
+			parser->bytes = left;
+		}
+		
+		if(parser->fp)
+		{
+			/*Sleep according to the bit rate*/
+			if(parser->rate)
+			{
+				int end_clock, end_pos;
+				int wait;
+				
+				end_pos = ftell(parser->fp);
+				AM_TIME_GetClock(&end_clock);
+				wait = (((uint64_t)end_pos)*1000)/parser->rate-(end_clock-parser->start_time);
+				if(wait>0)
+				{
+					usleep(wait*1000);
+				}
+			}
+		}
+		else
+		{
+			usleep(100000);
+		}
+	}
+	
+	if(parser->fp)
+	{
+		fclose(parser->fp);
+	}
+	
+	return NULL;
+}
+
+static AM_ErrorCode_t emu_open(AM_DMX_Device_t *dev, const AM_DMX_OpenPara_t *para)
+{
+	TSParser_t *parser;
+	
+	parser = (TSParser_t*)malloc(sizeof(TSParser_t));
+	if(!parser)
+	{
+		AM_DEBUG(1, "not enough memory");
+		return AM_DMX_ERR_NO_MEM;
+	}
+	
+	parser->channels = NULL;
+	parser->filters  = NULL;
+	parser->running  = AM_TRUE;
+	
+	pthread_mutex_init(&parser->lock, NULL);
+	pthread_cond_init(&parser->cond, NULL);
+	
+	if(pthread_create(&parser->thread, NULL, parser_thread, parser))
+	{
+		pthread_mutex_destroy(&parser->lock);
+		pthread_cond_destroy(&parser->cond);
+		free(parser);
+		AM_DEBUG(1, "cannot create ts parser thread");
+		return AM_DMX_ERR_CANNOT_CREATE_THREAD;
+	}
+	
+	dev->drv_data = parser;
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t emu_close(AM_DMX_Device_t *dev)
+{
+	TSParser_t *parser = (TSParser_t*)dev->drv_data;
+	Channel_t *chan, *cnext;
+	Filter_t *f, *fnext;
+	
+	parser->running = AM_FALSE;
+	pthread_join(parser->thread, NULL);
+	pthread_mutex_destroy(&parser->lock);
+	pthread_cond_destroy(&parser->cond);
+	
+	for(f=parser->filters; f; f=fnext)
+	{
+		fnext = f->next;
+		if(f->buf)
+			free(f->buf);
+		free(f);
+	}
+	
+	for(chan=parser->channels; chan; chan=cnext)
+	{
+		cnext = chan->next;
+		free(chan);
+	}
+
+	free(parser);
+	
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t emu_alloc_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter)
+{
+	TSParser_t *parser = (TSParser_t*)dev->drv_data;
+	Filter_t *f;
+	
+	f = (Filter_t*)malloc(sizeof(Filter_t));
+	if(!f)
+	{
+		AM_DEBUG(1, "not enough memory");
+		return AM_DMX_ERR_NO_MEM;
+	}
+	
+	memset(f, 0, sizeof(Filter_t));
+	
+	f->id  = filter->id;
+	f->buf_size = FILTER_BUF_SIZE;
+	f->buf = (uint8_t*)malloc(f->buf_size);
+	if(!f->buf)
+	{
+		free(f);
+		AM_DEBUG(1, "not enough memory");
+		return AM_DMX_ERR_NO_MEM;
+	}
+	
+	pthread_mutex_lock(&parser->lock);
+	
+	if(parser->filters)
+	{
+		f->next = parser->filters;
+		parser->filters->prev = f;
+		parser->filters = f;
+	}
+	else
+	{
+		parser->filters = f;
+	}
+	
+	pthread_mutex_unlock(&parser->lock);
+	
+	filter->drv_data = f;
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t emu_free_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter)
+{
+	TSParser_t *parser = (TSParser_t*)dev->drv_data;
+	Filter_t *f = (Filter_t*)filter->drv_data;
+	
+	pthread_mutex_lock(&parser->lock);
+	
+	if(f->prev)
+	{
+		f->prev->next = f->next;
+	}
+	else
+	{
+		parser->filters = f->next;
+	}
+	
+	if(f->next)
+		f->next->prev = f->prev;
+	
+	pthread_mutex_unlock(&parser->lock);
+	
+	if(f->buf)
+		free(f->buf);
+	
+	free(f);
+	
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t emu_set_sec_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, const struct dmx_sct_filter_params *params)
+{
+	TSParser_t *parser = (TSParser_t*)dev->drv_data;
+	Filter_t *f = (Filter_t*)filter->drv_data;
+	int i;
+	
+	pthread_mutex_lock(&parser->lock);
+	
+	f->type = CHAN_TYPE_SEC;
+	f->params.sct = *params;
+	f->neq = AM_FALSE;
+	
+	for(i=0; i<DMX_FILTER_SIZE; i++)
+	{
+		int pos = i?(i+2):i;
+		uint8_t mask = params->filter.mask[i];
+		uint8_t mode = params->filter.mode[i];
+		
+		f->value[pos] = params->filter.filter[i];
+		
+		mode = ~mode;
+		f->maskandmode[pos] = mask&mode;
+		f->maskandnotmode[pos] = mask&~mode;
+		
+		if(f->maskandnotmode[pos])
+			f->neq = AM_TRUE;
+	}
+	
+	f->maskandmode[1] = 0;
+	f->maskandmode[2] = 0;
+	f->maskandnotmode[1] = 0;
+	f->maskandnotmode[2] = 0;
+	
+	pthread_mutex_unlock(&parser->lock);
+	
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t emu_set_pes_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, const struct dmx_pes_filter_params *params)
+{
+	TSParser_t *parser = (TSParser_t*)dev->drv_data;
+	Filter_t *f = (Filter_t*)filter->drv_data;
+	
+	pthread_mutex_lock(&parser->lock);
+	
+	f->type = CHAN_TYPE_PES;
+	f->params.pes = *params;
+	
+	pthread_mutex_unlock(&parser->lock);
+	
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t emu_enable_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, AM_Bool_t enable)
+{
+	TSParser_t *parser = (TSParser_t*)dev->drv_data;
+	Filter_t *f = (Filter_t*)filter->drv_data;
+	
+	pthread_mutex_lock(&parser->lock);
+	
+	f->enable = enable;
+	f->bytes  = 0;
+
+	if(enable && (f->type==CHAN_TYPE_SEC))
+	{
+		AM_TIME_GetClock(&f->start_time);
+	}
+	
+	pthread_mutex_unlock(&parser->lock);
+	
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t emu_set_buf_size(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, int size)
+{
+	TSParser_t *parser = (TSParser_t*)dev->drv_data;
+	Filter_t *f = (Filter_t*)filter->drv_data;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	
+	pthread_mutex_lock(&parser->lock);
+	
+	if(f->buf_size!=size)
+	{
+		uint8_t *nbuf;
+		
+		nbuf = (uint8_t*)realloc(f->buf, size);
+		if(nbuf)
+		{
+			f->buf = nbuf;
+			f->buf_size = size;
+		}
+		else
+		{
+			ret = AM_DMX_ERR_NO_MEM;
+		}
+	}
+	
+	pthread_mutex_unlock(&parser->lock);
+	
+	return ret;
+}
+
+static int emu_check_data(TSParser_t *parser, AM_DMX_FilterMask_t *mask)
+{
+	Filter_t *f;
+	
+	for(f=parser->filters; f; f=f->next)
+	{
+		if(f->enable)
+		{
+			if(f->bytes)
+				AM_DMX_FILTER_MASK_SET(mask, f->id);
+			else if((f->type==CHAN_TYPE_SEC) && f->params.sct.timeout && f->start_time)
+			{
+				int now, diff;
+
+				AM_TIME_GetClock(&now);
+				diff = f->start_time+f->params.sct.timeout-now;
+
+				if(diff<=0)
+				{
+					AM_DMX_FILTER_MASK_SET(mask, f->id);
+				}
+			}
+		}
+	}
+	
+	return AM_DMX_FILTER_MASK_ISEMPTY(mask)?AM_FALSE:AM_TRUE;
+}
+
+static AM_ErrorCode_t emu_poll(AM_DMX_Device_t *dev, AM_DMX_FilterMask_t *mask, int timeout)
+{
+	TSParser_t *parser = (TSParser_t*)dev->drv_data;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	
+	pthread_mutex_lock(&parser->lock);
+	
+	if(timeout<0)
+	{
+		while(!emu_check_data(parser, mask))
+			pthread_cond_wait(&parser->cond, &parser->lock);
+	}
+	else
+	{
+		if(!emu_check_data(parser, mask))
+		{
+			struct timespec ts;
+			
+			AM_TIME_GetTimeSpecTimeout(timeout, &ts);
+			pthread_cond_timedwait(&parser->cond, &parser->lock, &ts);
+			
+			if(!emu_check_data(parser, mask))
+				ret = AM_DMX_ERR_TIMEOUT;
+		}
+	}
+	
+	pthread_mutex_unlock(&parser->lock);
+	
+	return ret;
+}
+
+static AM_ErrorCode_t emu_read(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, uint8_t *buf, int *size)
+{
+	TSParser_t *parser = (TSParser_t*)dev->drv_data;
+	Filter_t *f = (Filter_t*)filter->drv_data;
+	int len = 0, cpy = 0, cnt, cnt2, pos;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	
+	pthread_mutex_lock(&parser->lock);
+	
+	if(f->bytes)
+	{
+		switch(f->type)
+		{
+			case CHAN_TYPE_SEC:
+				pos = (f->begin+1)%f->buf_size;
+				len = f->buf[pos]<<8;
+				pos = (pos+1)%f->buf_size;
+				len |= f->buf[pos];
+				len &= 0xFFF;
+				len += 3;
+				cpy = AM_MIN(len, *size);
+			break;
+			case CHAN_TYPE_PES:
+				cpy = AM_MIN(f->bytes, *size);
+				len = cpy;
+			break;
+		}
+		
+		cnt = f->buf_size-f->begin;
+		if(cnt>=cpy)
+		{
+			memcpy(buf, f->buf+f->begin, cpy);
+		}
+		else
+		{
+			cnt2 = cpy-cnt;
+			memcpy(buf, f->buf+f->begin, cnt);
+			memcpy(buf+cnt, f->buf, cnt2);
+		}
+		
+		*size = cpy;
+		f->begin += len;
+		f->begin %= f->buf_size;
+		f->bytes -= len;
+	}
+	else
+	{
+		f->start_time = 0;
+		ret = AM_DMX_ERR_TIMEOUT;
+	}
+	
+	pthread_mutex_unlock(&parser->lock);
+	
+	return ret;
+}
+
+static AM_ErrorCode_t emu_set_source(AM_DMX_Device_t *dev, AM_DMX_Source_t src)
+{
+	AM_DEBUG(1, "set demux source to %d", src);
+	return AM_SUCCESS;
+}
+
diff --git a/test/am_ca_key_test/inject_record_t5d/am_dmx/linux_dvb/Makefile b/test/am_ca_key_test/inject_record_t5d/am_dmx/linux_dvb/Makefile
new file mode 100644
index 0000000..a978c87
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_dmx/linux_dvb/Makefile
@@ -0,0 +1,8 @@
+BASE=../../..
+
+include $(BASE)/rule/def.mk
+
+O_TARGET=linux_dvb
+linux_dvb_SRCS=linux_dvb.c
+
+include $(BASE)/rule/rule.mk
diff --git a/test/am_ca_key_test/inject_record_t5d/am_dmx/linux_dvb/linux_dvb.c b/test/am_ca_key_test/inject_record_t5d/am_dmx/linux_dvb/linux_dvb.c
new file mode 100644
index 0000000..5c29a3f
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_dmx/linux_dvb/linux_dvb.c
@@ -0,0 +1,345 @@
+#ifdef _FORTIFY_SOURCE
+#undef _FORTIFY_SOURCE
+#endif
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief Linux DVB demux 驱动
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-07-21: create the document
+ ***************************************************************************/
+
+#define AM_DEBUG_LEVEL 5
+
+#include <am_debug.h>
+#include <am_mem.h>
+#include <am_misc.h>
+#include "../am_dmx_internal.h"
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <poll.h>
+/*add for config define for linux dvb *.h*/
+#include <am_config.h>
+#include <linux/dvb/dmx.h>
+
+#define open(a...)\
+	({\
+	 int ret, times=3;\
+	 do {\
+        ret = open(a);\
+        if (ret == -1)\
+        {\
+           usleep(100*1000);\
+        }\
+	 }while(ret==-1 && times--);\
+	 ret;\
+	 })
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+typedef struct
+{
+	char   dev_name[32];
+	int    fd[DMX_FILTER_COUNT];
+} DVBDmx_t;
+
+/****************************************************************************
+ * Static data definitions
+ ***************************************************************************/
+
+static AM_ErrorCode_t dvb_open(AM_DMX_Device_t *dev, const AM_DMX_OpenPara_t *para);
+static AM_ErrorCode_t dvb_close(AM_DMX_Device_t *dev);
+static AM_ErrorCode_t dvb_alloc_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter);
+static AM_ErrorCode_t dvb_free_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter);
+static AM_ErrorCode_t dvb_set_sec_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, const struct dmx_sct_filter_params *params);
+static AM_ErrorCode_t dvb_set_pes_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, const struct dmx_pes_filter_params *params);
+static AM_ErrorCode_t dvb_enable_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, AM_Bool_t enable);
+static AM_ErrorCode_t dvb_set_buf_size(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, int size);
+static AM_ErrorCode_t dvb_poll(AM_DMX_Device_t *dev, AM_DMX_FilterMask_t *mask, int timeout);
+static AM_ErrorCode_t dvb_read(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, uint8_t *buf, int *size);
+static AM_ErrorCode_t dvb_set_source(AM_DMX_Device_t *dev, AM_DMX_Source_t src);
+
+const AM_DMX_Driver_t linux_dvb_dmx_drv = {
+.open  = dvb_open,
+.close = dvb_close,
+.alloc_filter = dvb_alloc_filter,
+.free_filter  = dvb_free_filter,
+.set_sec_filter = dvb_set_sec_filter,
+.set_pes_filter = dvb_set_pes_filter,
+.enable_filter  = dvb_enable_filter,
+.set_buf_size   = dvb_set_buf_size,
+.poll           = dvb_poll,
+.read           = dvb_read,
+.set_source     = dvb_set_source
+};
+
+
+/****************************************************************************
+ * Static functions
+ ***************************************************************************/
+
+static AM_ErrorCode_t dvb_open(AM_DMX_Device_t *dev, const AM_DMX_OpenPara_t *para)
+{
+	DVBDmx_t *dmx;
+	int i;
+
+	UNUSED(para);
+
+	dmx = (DVBDmx_t*)malloc(sizeof(DVBDmx_t));
+	if(!dmx)
+	{
+		AM_DEBUG(1, "not enough memory");
+		return AM_DMX_ERR_NO_MEM;
+	}
+	
+	snprintf(dmx->dev_name, sizeof(dmx->dev_name), "/dev/dvb0.demux%d", dev->dev_no);
+	
+	for(i=0; i<DMX_FILTER_COUNT; i++)
+		dmx->fd[i] = -1;
+	
+	dev->drv_data = dmx;
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t dvb_close(AM_DMX_Device_t *dev)
+{
+	DVBDmx_t *dmx = (DVBDmx_t*)dev->drv_data;
+	
+	free(dmx);
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t dvb_alloc_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter)
+{
+	DVBDmx_t *dmx = (DVBDmx_t*)dev->drv_data;
+	int fd;
+
+	fd = open(dmx->dev_name, O_RDWR);
+	if(fd==-1)
+	{
+		AM_DEBUG(1, "cannot open \"%s\" (%s)", dmx->dev_name, strerror(errno));
+		return AM_DMX_ERR_CANNOT_OPEN_DEV;
+	}
+	
+	dmx->fd[filter->id] = fd;
+
+	filter->drv_data = (void*)(long)fd;
+	
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t dvb_free_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter)
+{
+	DVBDmx_t *dmx = (DVBDmx_t*)dev->drv_data;
+	int fd = (long)filter->drv_data;
+
+	close(fd);
+	dmx->fd[filter->id] = -1;
+	
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t dvb_set_sec_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, const struct dmx_sct_filter_params *params)
+{
+	struct dmx_sct_filter_params p;
+	int fd = (long)filter->drv_data;
+	int ret;
+
+	UNUSED(dev);
+
+	p = *params;
+	/*
+	if(p.filter.mask[0] == 0){
+		p.filter.filter[0] = 0x00;
+		p.filter.mask[0]   = 0x80;
+	}
+	*/
+	ret = ioctl(fd, DMX_SET_FILTER, &p);
+	if(ret==-1)
+	{
+		AM_DEBUG(1, "set section filter failed (%s)", strerror(errno));
+		return AM_DMX_ERR_SYS;
+	}
+	
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t dvb_set_pes_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, const struct dmx_pes_filter_params *params)
+{
+	int fd = (long)filter->drv_data;
+	int ret;
+
+	UNUSED(dev);
+
+	fcntl(fd,F_SETFL,O_NONBLOCK);
+
+	ret = ioctl(fd, DMX_SET_PES_FILTER, params);
+	if(ret==-1)
+	{
+		AM_DEBUG(1, "set section filter failed (%s)", strerror(errno));
+		return AM_DMX_ERR_SYS;
+	}
+	
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t dvb_enable_filter(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, AM_Bool_t enable)
+{
+	int fd = (long)filter->drv_data;
+	int ret;
+
+	UNUSED(dev);
+
+	if(enable)
+		ret = ioctl(fd, DMX_START, 0);
+	else
+		ret = ioctl(fd, DMX_STOP, 0);
+	
+	if(ret==-1)
+	{
+		AM_DEBUG(1, "start filter failed (%s)", strerror(errno));
+		return AM_DMX_ERR_SYS;
+	}
+	
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t dvb_set_buf_size(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, int size)
+{
+	int fd = (long)filter->drv_data;
+	int ret;
+
+	UNUSED(dev);
+	
+	ret = ioctl(fd, DMX_SET_BUFFER_SIZE, size);
+	if(ret==-1)
+	{
+		AM_DEBUG(1, "set buffer size failed (%s)", strerror(errno));
+		return AM_DMX_ERR_SYS;
+	}
+	
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t dvb_poll(AM_DMX_Device_t *dev, AM_DMX_FilterMask_t *mask, int timeout)
+{
+	DVBDmx_t *dmx = (DVBDmx_t*)dev->drv_data;
+	struct pollfd fds[DMX_FILTER_COUNT];
+	int fids[DMX_FILTER_COUNT];
+	int i, cnt = 0, ret;
+	
+	for(i=0; i<DMX_FILTER_COUNT; i++)
+	{
+		if(dmx->fd[i]!=-1)
+		{
+			fds[cnt].events = POLLIN|POLLERR;
+			fds[cnt].fd     = dmx->fd[i];
+			fids[cnt] = i;
+			cnt++;
+		}
+	}
+	
+	if(!cnt)
+		return AM_DMX_ERR_TIMEOUT;
+	
+	ret = poll(fds, cnt, timeout);
+	if(ret<=0)
+	{
+		return AM_DMX_ERR_TIMEOUT;
+	}
+	
+	for(i=0; i<cnt; i++)
+	{
+		if(fds[i].revents&(POLLIN|POLLERR))
+		{
+			AM_DMX_FILTER_MASK_SET(mask, fids[i]);
+		}
+	}
+	
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t dvb_read(AM_DMX_Device_t *dev, AM_DMX_Filter_t *filter, uint8_t *buf, int *size)
+{
+	int fd = (long)filter->drv_data;
+	int len = *size;
+	int ret;
+	struct pollfd pfd;
+
+	UNUSED(dev);
+	
+	if(fd==-1)
+		return AM_DMX_ERR_NOT_ALLOCATED;
+	
+	pfd.events = POLLIN|POLLERR;
+	pfd.fd     = fd;
+	
+	ret = poll(&pfd, 1, 0);
+	if(ret<=0)
+		return AM_DMX_ERR_NO_DATA;
+	
+	ret = read(fd, buf, len);
+	if(ret<=0)
+	{
+		if(errno==ETIMEDOUT)
+			return AM_DMX_ERR_TIMEOUT;
+		AM_DEBUG(1, "read demux failed (%s) %d", strerror(errno), errno);
+		return AM_DMX_ERR_SYS;
+	}
+	
+	*size = ret;
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t dvb_set_source(AM_DMX_Device_t *dev, AM_DMX_Source_t src)
+{
+	char buf[32];
+	char *cmd;
+	
+	snprintf(buf, sizeof(buf), "/sys/class/stb/demux%d_source", dev->dev_no);
+	
+	switch(src)
+	{
+		case AM_DMX_SRC_TS0:
+			cmd = "ts0";
+		break;
+		case AM_DMX_SRC_TS1:
+			cmd = "ts1";
+		break;
+#if defined(CHIP_8226M) || defined(CHIP_8626X)
+		case AM_DMX_SRC_TS2:
+			cmd = "ts2";
+		break;
+#endif
+		case AM_DMX_SRC_TS3:
+			cmd = "ts3";
+		break;
+		case AM_DMX_SRC_HIU:
+			cmd = "hiu";
+		break;
+		case AM_DMX_SRC_HIU1:
+			cmd = "hiu1";
+		break;
+		default:
+			AM_DEBUG(1, "do not support demux source %d", src);
+		return AM_DMX_ERR_NOT_SUPPORTED;
+	}
+	
+	return AM_FileEcho(buf, cmd);
+}
+
diff --git a/test/am_ca_key_test/inject_record_t5d/am_dvr/Makefile b/test/am_ca_key_test/inject_record_t5d/am_dvr/Makefile
new file mode 100644
index 0000000..2c72f57
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_dvr/Makefile
@@ -0,0 +1,19 @@
+BASE=../..
+
+include $(BASE)/rule/def.mk
+
+O_TARGET=am_dvr
+am_dvr_SRCS=am_dvr.c
+
+SUBDIRS=
+am_dvr_OBJS=
+
+ifeq ($(EMU_DVR), y)
+	SUBDIRS+=emu
+	am_dvr_OBJS+=emu/emu
+else
+	SUBDIRS+=linux_dvb
+	am_dvr_OBJS+=linux_dvb/linux_dvb
+endif
+
+include $(BASE)/rule/rule.mk
diff --git a/test/am_ca_key_test/inject_record_t5d/am_dvr/am_dvr.c b/test/am_ca_key_test/inject_record_t5d/am_dvr/am_dvr.c
new file mode 100644
index 0000000..049c249
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_dvr/am_dvr.c
@@ -0,0 +1,472 @@
+#ifdef _FORTIFY_SOURCE
+#undef _FORTIFY_SOURCE
+#endif
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief
+ *
+ * \author Xia Lei Peng <leipeng.xia@amlogic.com>
+ * \date 2010-12-13: create the document
+ ***************************************************************************/
+
+#define AM_DEBUG_LEVEL 2
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <poll.h>
+#include <am_debug.h>
+#include "am_dvr_internal.h"
+#include <am_dmx.h>
+#include <am_fend.h>
+#include <am_time.h>
+#include <am_mem.h>
+
+#include "../am_adp_internal.h"
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+#ifdef CHIP_8226H
+#define DVR_DEV_COUNT      (2)
+#elif defined(CHIP_8226M) || defined(CHIP_8626X)
+#define DVR_DEV_COUNT      (3)
+#else
+#define DVR_DEV_COUNT      (2)
+#endif
+
+/****************************************************************************
+ * Static data
+ ***************************************************************************/
+ 
+#ifdef EMU_DVR
+extern const AM_DVR_Driver_t emu_dvr_drv;
+#else
+extern const AM_DVR_Driver_t linux_dvb_dvr_drv;
+#endif
+
+static ssize_t dvr_read(int dvr_no, void *buf, size_t size);
+static ssize_t dvr_write(int dvr_no, void *buf, size_t size);
+static loff_t dvr_seek(int dev_no, loff_t offset, int whence);
+
+static AM_DVR_Device_t dvr_devices[DVR_DEV_COUNT] =
+{
+#ifdef EMU_DVR
+{
+.drv = &emu_dvr_drv,
+},
+{
+.drv = &emu_dvr_drv,
+}
+#else
+{
+.drv = &linux_dvb_dvr_drv,
+},
+{
+.drv = &linux_dvb_dvr_drv,
+}
+#if defined(CHIP_8226M) || defined(CHIP_8626X)
+,
+{
+.drv = &linux_dvb_dvr_drv,
+}
+#endif
+#endif
+};
+
+/****************************************************************************
+ * Static functions
+ ***************************************************************************/
+ 
+/**\brief 根据设备号取得设备结构指针*/
+static AM_INLINE AM_ErrorCode_t dvr_get_dev(int dev_no, AM_DVR_Device_t **dev)
+{
+	if((dev_no<0) || (dev_no>=DVR_DEV_COUNT))
+	{
+		AM_DEBUG(1, "invalid dvr device number %d, must in(%d~%d)", dev_no, 0, DVR_DEV_COUNT-1);
+		return AM_DVR_ERR_INVALID_DEV_NO;
+	}
+	
+	*dev = &dvr_devices[dev_no];
+	return AM_SUCCESS;
+}
+
+/**\brief 根据设备号取得设备结构并检查设备是否已经打开*/
+static AM_INLINE AM_ErrorCode_t dvr_get_openned_dev(int dev_no, AM_DVR_Device_t **dev)
+{
+	AM_TRY(dvr_get_dev(dev_no, dev));
+	
+	if(!(*dev)->open_cnt)
+	{
+		AM_DEBUG(1, "dvr device %d has not been openned", dev_no);
+		return AM_DVR_ERR_INVALID_DEV_NO;
+	}
+	
+	return AM_SUCCESS;
+}
+
+/**\brief 添加一个流*/
+static AM_ErrorCode_t dvr_add_stream(AM_DVR_Device_t *dev, uint16_t pid)
+{
+	int i;
+	
+	if (dev->stream_cnt >= AM_DVR_MAX_PID_COUNT)
+	{
+		AM_DEBUG(1, "PID count overflow, Max support %d", AM_DVR_MAX_PID_COUNT);
+		return AM_DVR_ERR_TOO_MANY_STREAMS;
+	}
+
+	i = dev->stream_cnt;
+
+	dev->streams[i].pid = pid;
+	dev->streams[i].fid = -1;
+	dev->stream_cnt++;
+	
+	return AM_SUCCESS;
+}
+
+
+/**\brief 启动所有流的录制*/
+static AM_ErrorCode_t dvr_start_all_streams(AM_DVR_Device_t *dev)
+{
+	int i;
+	struct dmx_pes_filter_params pparam;
+
+	AM_DEBUG(1, "Start DVR%d recording, pid count %d", dev->dev_no, dev->stream_cnt);
+	for(i=0; i<dev->stream_cnt; i++)
+	{
+		if (dev->streams[i].fid == -1)
+		{
+			if (AM_DMX_AllocateFilter(dev->dmx_no, &dev->streams[i].fid) == AM_SUCCESS)
+			{
+				memset(&pparam, 0, sizeof(pparam));
+				pparam.pid = dev->streams[i].pid;
+				pparam.input = DMX_IN_FRONTEND;
+				pparam.output = DMX_OUT_TS_TAP;
+				pparam.pes_type = DMX_PES_OTHER;
+				AM_DMX_SetPesFilter(dev->dmx_no, dev->streams[i].fid, &pparam);
+				AM_DMX_StartFilter(dev->dmx_no, dev->streams[i].fid);
+				AM_DEBUG(1, "Stream(pid=%d) start recording...", dev->streams[i].pid);
+			}
+			else
+			{
+				dev->streams[i].fid = -1;
+				AM_DEBUG(1, "Cannot alloc filter, stream(pid=%d) will not record.", dev->streams[i].pid);
+			}
+		}
+	}
+
+	return AM_SUCCESS;
+}
+
+/**\brief 停止所有流的录制*/
+static AM_ErrorCode_t dvr_stop_all_streams(AM_DVR_Device_t *dev)
+{
+	int i;
+	
+	for(i=0; i<dev->stream_cnt; i++)
+	{
+		if (dev->streams[i].fid != -1)
+		{
+			AM_DEBUG(1, "Stop stream(pid=%d)...", dev->streams[i].pid);
+			AM_DMX_StopFilter(dev->dmx_no, dev->streams[i].fid);
+			AM_DMX_FreeFilter(dev->dmx_no, dev->streams[i].fid);
+			dev->streams[i].fid = -1;
+		}
+	}
+
+	dev->stream_cnt = 0;
+
+	return AM_SUCCESS;
+}
+
+/****************************************************************************
+ * API functions
+ ***************************************************************************/
+ 
+/**\brief 打开DVR设备
+ * \param dev_no DVR设备号
+ * \param[in] para DVR设备开启参数
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_dvr.h)
+ */
+AM_ErrorCode_t AM_DVR_Open(int dev_no, const AM_DVR_OpenPara_t *para)
+{
+	AM_DVR_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	int i;
+	
+	assert(para);
+	
+	AM_TRY(dvr_get_dev(dev_no, &dev));
+	
+	pthread_mutex_lock(&am_gAdpLock);
+	
+	if(dev->open_cnt)
+	{
+		AM_DEBUG(1, "dvr device %d has already been openned", dev_no);
+		dev->open_cnt++;
+		goto final;
+	}
+
+	dev->dev_no = dev_no;
+	/*DVR与使用的DMX设备号一致*/
+	dev->dmx_no = dev_no;
+
+	for(i=0; i<AM_DVR_MAX_PID_COUNT; i++)
+	{
+		dev->streams[i].fid = -1;
+	}
+	
+	if(dev->drv->open)
+	{
+		ret = dev->drv->open(dev, para);
+	}
+	
+	if(ret==AM_SUCCESS)
+	{
+		pthread_mutex_init(&dev->lock, NULL);
+		dev->open_cnt++;
+		dev->record = AM_FALSE;
+		dev->stream_cnt = 0;
+	}
+	
+final:
+	pthread_mutex_unlock(&am_gAdpLock);
+	
+	return ret;
+}
+
+/**\brief 关闭DVR设备
+ * \param dev_no DVR设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_dvr.h)
+ */
+AM_ErrorCode_t AM_DVR_Close(int dev_no)
+{
+	AM_DVR_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	
+	AM_TRY(dvr_get_dev(dev_no, &dev));
+	
+	pthread_mutex_lock(&am_gAdpLock);
+
+	if(dev->open_cnt > 0){
+		/*停止数据源*/
+		dvr_stop_all_streams(dev);
+			
+		if(dev->drv->close)
+		{
+			dev->drv->close(dev);
+		}
+
+		pthread_mutex_destroy(&dev->lock);
+		dev->record = AM_FALSE;
+
+		dev->open_cnt--;
+	}
+	
+	pthread_mutex_unlock(&am_gAdpLock);
+	
+	return ret;
+}
+
+/**\brief 设置DVR设备缓冲区大小
+ * \param dev_no DVR设备号
+ * \param size 缓冲区大小
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_dvr.h)
+ */
+AM_ErrorCode_t AM_DVR_SetBufferSize(int dev_no, int size)
+{
+	AM_DVR_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	
+	AM_TRY(dvr_get_openned_dev(dev_no, &dev));
+	
+	pthread_mutex_lock(&dev->lock);
+	
+	if(!dev->drv->set_buf_size)
+	{
+		AM_DEBUG(1, "do not support set_buf_size");
+		ret = AM_DVR_ERR_NOT_SUPPORTED;
+	}
+	
+	if(ret==AM_SUCCESS)
+		ret = dev->drv->set_buf_size(dev, size);
+	
+	pthread_mutex_unlock(&dev->lock);
+	
+	return ret;
+}
+
+/**\brief 开始录像
+ * \param dev_no DVR设备号
+ * \param [in] para 录像参数
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_dvr.h)
+ */
+AM_ErrorCode_t AM_DVR_StartRecord(int dev_no, const AM_DVR_StartRecPara_t *para)
+{
+	AM_DVR_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	int pid_cnt;
+
+	assert(para);
+	if (para->pid_count <= 0)
+	{
+		AM_DEBUG(1, "Invalid pid count %d", para->pid_count);
+		return AM_DVR_ERR_INVALID_ARG;
+	}
+	pid_cnt = para->pid_count;
+	if (pid_cnt > AM_DVR_MAX_PID_COUNT)
+		pid_cnt = AM_DVR_MAX_PID_COUNT;
+		
+	AM_TRY(dvr_get_openned_dev(dev_no, &dev));
+	
+	pthread_mutex_lock(&dev->lock);
+	if (dev->record)
+	{
+		AM_DEBUG(1, "dvr device %d already recording.", dev_no);
+		ret = AM_DVR_ERR_BUSY;
+	}
+	else
+	{
+		int i;
+
+		for (i=0; i<pid_cnt; i++)
+		{
+			dvr_add_stream(dev, (uint16_t)para->pids[i]);
+		}
+		
+		/*启动数据*/
+		dvr_start_all_streams(dev);
+		dev->record = AM_TRUE;
+		dev->start_para = *para;
+	}
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 停止录像
+ * \param dev_no DVR设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_dvr.h)
+ */
+AM_ErrorCode_t AM_DVR_StopRecord(int dev_no)
+{
+	AM_DVR_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	
+	AM_TRY(dvr_get_openned_dev(dev_no, &dev));
+	
+	pthread_mutex_lock(&dev->lock);
+	if (dev->record)
+	{
+		/*停止数据源*/
+		dvr_stop_all_streams(dev);
+		
+		dev->record = AM_FALSE;
+	}
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+/**\brief 从DVR读取录像数据
+ * \param dev_no DVR设备号
+ * \param	[out] buf 缓冲区
+ * \param size	需要读取的数据长度
+ * \param timeout 读取超时时间 ms 
+ * \return
+ *   - 实际读取的字节数
+ */
+int AM_DVR_Read(int dev_no, uint8_t *buf, int size, int timeout_ms)
+{
+	AM_DVR_Device_t *dev;
+	AM_ErrorCode_t ret;
+	int cnt = -1;
+
+	AM_TRY(dvr_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+	if(!dev->drv->read)
+	{
+		AM_DEBUG(1, "do not support read");
+	}
+	else
+	{
+		ret = dev->drv->poll(dev, timeout_ms);
+		if(ret==AM_SUCCESS)
+		{
+			cnt = size;
+			ret = dev->drv->read(dev, buf, &cnt);
+			if (ret != AM_SUCCESS)
+				cnt = -1;
+		}
+	}
+	pthread_mutex_unlock(&dev->lock);
+
+	return cnt;
+}
+
+/**\brief 设置DVR源
+ * \param dev_no DVR设备号
+ * \param	src DVR源
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_dvr.h)
+ */
+AM_ErrorCode_t AM_DVR_SetSource(int dev_no, AM_DVR_Source_t src)
+{
+	AM_DVR_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	
+	AM_TRY(dvr_get_openned_dev(dev_no, &dev));
+	
+	pthread_mutex_lock(&dev->lock);
+	if(!dev->drv->set_source)
+	{
+		AM_DEBUG(1, "do not support set_source");
+		ret = AM_DVR_ERR_NOT_SUPPORTED;
+	}
+	
+	if(ret==AM_SUCCESS)
+	{
+		ret = dev->drv->set_source(dev, src);
+	}
+	
+	pthread_mutex_unlock(&dev->lock);
+	
+	if(ret==AM_SUCCESS)
+	{
+		pthread_mutex_lock(&am_gAdpLock);
+		dev->src = src;
+		pthread_mutex_unlock(&am_gAdpLock);
+	}
+
+	return ret;
+}
+
diff --git a/test/am_ca_key_test/inject_record_t5d/am_dvr/am_dvr.h b/test/am_ca_key_test/inject_record_t5d/am_dvr/am_dvr.h
new file mode 100644
index 0000000..cf5a3f3
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_dvr/am_dvr.h
@@ -0,0 +1,148 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief DVR module
+ *
+ * DVR module use asyncfifo to record TS stream from a demux.
+ * Each demux has a corresponding DVR device.
+ *
+ * \author Xia Lei Peng <leipeng.xia@amlogic.com>
+ * \date 2010-12-13: create the document
+ ***************************************************************************/
+
+#ifndef _AM_DVR_H
+#define _AM_DVR_H
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <am_types.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+#define AM_DVR_MAX_PID_COUNT  (32)
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+/**\brief DVR module's error code*/
+enum AM_DVR_ErrorCode
+{
+	AM_DVR_ERROR_BASE=AM_ERROR_BASE(AM_MOD_DVR),
+	AM_DVR_ERR_INVALID_ARG,			/**< Invalid argument*/
+	AM_DVR_ERR_INVALID_DEV_NO,		/**< Invalid decide number*/
+	AM_DVR_ERR_BUSY,                        /**< The device has already been openned*/
+	AM_DVR_ERR_NOT_ALLOCATED,           /**< The device has not been allocated*/
+	AM_DVR_ERR_CANNOT_CREATE_THREAD,    /**< Cannot create a new thread*/
+	AM_DVR_ERR_CANNOT_OPEN_DEV,         /**< Cannot open the device*/
+	AM_DVR_ERR_NOT_SUPPORTED,           /**< Not supported*/
+	AM_DVR_ERR_NO_MEM,                  /**< Not enough memory*/
+	AM_DVR_ERR_TIMEOUT,                 /**< Timeout*/
+	AM_DVR_ERR_SYS,                     /**< System error*/
+	AM_DVR_ERR_NO_DATA,                 /**< No data received*/
+	AM_DVR_ERR_CANNOT_OPEN_OUTFILE,		/**< Cannot open the output file*/
+	AM_DVR_ERR_TOO_MANY_STREAMS,		/**< PID number is too big*/
+	AM_DVR_ERR_STREAM_ALREADY_ADD,		/**< The elementary stream has already been added*/
+	AM_DVR_ERR_END
+};
+
+
+/**\brief DVR device open parameters*/
+typedef struct
+{
+	int    foo;	
+} AM_DVR_OpenPara_t;
+
+/**\brief Recording parameters*/
+typedef struct
+{
+	int		pid_count; /**< PID number*/
+	int		pids[AM_DVR_MAX_PID_COUNT]; /**< PID array*/
+} AM_DVR_StartRecPara_t;
+
+/**\brief DVR recording source*/
+typedef enum
+{
+	AM_DVR_SRC_ASYNC_FIFO0, /**< asyncfifo 0*/
+	AM_DVR_SRC_ASYNC_FIFO1, /**< asyncfifo 1*/
+	AM_DVR_SRC_ASYNC_FIFO2, /**< asyncfifo 2*/
+}AM_DVR_Source_t;
+
+/****************************************************************************
+ * Function prototypes  
+ ***************************************************************************/
+
+/**\brief Open a DVR device
+ * \param dev_no DVR device number
+ * \param[in] para DVR device open parameters
+ * \retval AM_SUCCESS On succes
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DVR_Open(int dev_no, const AM_DVR_OpenPara_t *para);
+
+/**\brief Close an unused DVR device
+ * \param dev_no DVR device number
+ * \retval AM_SUCCESS On succes
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DVR_Close(int dev_no);
+
+/**\brief Set the DVR device's ring queue buffer size.
+ * \param dev_no DVR device number
+ * \param size Ring queue buffer size
+ * \retval AM_SUCCESS On succes
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DVR_SetBufferSize(int dev_no, int size);
+
+/**\brief Start recording
+ * \param dev_no DVR device number
+ * \param [in] para Recording parameters
+ * \retval AM_SUCCESS On succes
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DVR_StartRecord(int dev_no, const AM_DVR_StartRecPara_t *para);
+
+/**\brief Stop recording
+ * \param dev_no DVR device number
+ * \retval AM_SUCCESS On succes
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DVR_StopRecord(int dev_no);
+
+/**\brief Set the DVR input source
+ * \param dev_no DVR device number
+ * \param	src DVR input source
+ * \retval AM_SUCCESS On succes
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DVR_SetSource(int dev_no, AM_DVR_Source_t src);
+
+/**\brief Read TS data from a DVR device
+ * \param dev_no DVR device number
+ * \param[out] buf TS output buffer
+ * \param size	The buffer size in bytes
+ * \param timeout_ms Timeout in milliseconds
+ * \return Read data size in bytes
+ */
+extern int AM_DVR_Read(int dev_no, uint8_t *buf, int size, int timeout_ms);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/am_dvr/am_dvr_internal.h b/test/am_ca_key_test/inject_record_t5d/am_dvr/am_dvr_internal.h
new file mode 100644
index 0000000..edc6254
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_dvr/am_dvr_internal.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief DVR设备内部头文件
+ *
+ * \author Xia Lei Peng <leipeng.xia@amlogic.com>
+ * \date 2010-12-13: create the document
+ ***************************************************************************/
+
+#ifndef _AM_DVR_INTERNAL_H
+#define _AM_DVR_INTERNAL_H
+
+#include <am_dvr.h>
+#include <am_util.h>
+#include <am_thread.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+ 
+/**\brief DVR设备*/
+typedef struct AM_DVR_Device AM_DVR_Device_t;
+
+
+typedef struct
+{
+	int			fid;	/**< DMX Filter ID*/
+	uint16_t	pid;	/**< Stream PID*/
+}AM_DVR_Stream_t;
+
+/**\brief DVR设备驱动*/
+typedef struct
+{
+	AM_ErrorCode_t (*open)(AM_DVR_Device_t *dev, const AM_DVR_OpenPara_t *para);
+	AM_ErrorCode_t (*close)(AM_DVR_Device_t *dev);
+	AM_ErrorCode_t (*set_buf_size)(AM_DVR_Device_t *dev, int size);
+	AM_ErrorCode_t (*poll)(AM_DVR_Device_t *dev, int timeout);
+	AM_ErrorCode_t (*read)(AM_DVR_Device_t *dev, uint8_t *buf, int *size);
+	AM_ErrorCode_t (*set_source)(AM_DVR_Device_t *dev, AM_DVR_Source_t src);
+} AM_DVR_Driver_t;
+
+/**\brief DVR设备*/
+struct AM_DVR_Device
+{
+	int                 dev_no;  /**< 设备号*/
+	int					dmx_no;	 /**< DMX设备号*/
+	const AM_DVR_Driver_t *drv;  /**< 设备驱动*/
+	void               *drv_data;/**< 驱动私有数据*/
+	int                 open_cnt;   /**< 设备打开计数*/
+	int					stream_cnt;	/**< 流个数*/
+	AM_DVR_Stream_t		streams[AM_DVR_MAX_PID_COUNT]; /**< Streams*/
+	AM_Bool_t	   		record;/**< 是否正在录像标志*/
+	pthread_mutex_t     	lock;    /**< 设备保护互斥体*/
+	AM_DVR_StartRecPara_t	start_para;	/**< 启动参数*/
+	AM_DVR_Source_t		src;			/**< 源数据*/
+};
+
+
+
+/****************************************************************************
+ * Function prototypes  
+ ***************************************************************************/
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/am_dvr/emu/Makefile b/test/am_ca_key_test/inject_record_t5d/am_dvr/emu/Makefile
new file mode 100644
index 0000000..b9a90bb
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_dvr/emu/Makefile
@@ -0,0 +1,8 @@
+BASE=../../..
+
+include $(BASE)/rule/def.mk
+
+O_TARGET=emu
+emu_SRCS=emu.c
+
+include $(BASE)/rule/rule.mk
diff --git a/test/am_ca_key_test/inject_record_t5d/am_dvr/emu/emu.c b/test/am_ca_key_test/inject_record_t5d/am_dvr/emu/emu.c
new file mode 100644
index 0000000..ef2e458
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_dvr/emu/emu.c
@@ -0,0 +1,76 @@
+#ifdef _FORTIFY_SOURCE
+#undef _FORTIFY_SOURCE
+#endif
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief  emu dvr 驱动
+ *
+ * \author Xia Lei Peng <leipeng.xia@amlogic.com>
+ * \date 2010-12-13: create the document
+ ***************************************************************************/
+
+#define AM_DEBUG_LEVEL 2
+
+#include <am_debug.h>
+#include "../am_dvr_internal.h"
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+
+/****************************************************************************
+ * Static data definitions
+ ***************************************************************************/
+
+static AM_ErrorCode_t emu_open(AM_DVR_Device_t *dev, const AM_DVR_OpenPara_t *para);
+static AM_ErrorCode_t emu_close(AM_DVR_Device_t *dev);
+static AM_ErrorCode_t emu_set_buf_size(AM_DVR_Device_t *dev, int size);
+static AM_ErrorCode_t emu_poll(AM_DVR_Device_t *dev, int timeout);
+static AM_ErrorCode_t emu_read(AM_DVR_Device_t *dev, uint8_t *buf, int *size);
+
+const AM_DVR_Driver_t emu_dvr_drv = {
+.open  			= emu_open,
+.close 			= emu_close,
+.set_buf_size   = emu_set_buf_size,
+.poll           = emu_poll,
+.read           = emu_read,
+};
+
+
+/****************************************************************************
+ * Static functions
+ ***************************************************************************/
+
+static AM_ErrorCode_t emu_open(AM_DVR_Device_t *dev, const AM_DVR_OpenPara_t *para)
+{
+	return AM_DVR_ERR_NOT_SUPPORTED;
+}
+
+static AM_ErrorCode_t emu_close(AM_DVR_Device_t *dev)
+{
+	return AM_DVR_ERR_NOT_SUPPORTED;
+}
+
+static AM_ErrorCode_t emu_set_buf_size(AM_DVR_Device_t *dev, int size)
+{
+	return AM_DVR_ERR_NOT_SUPPORTED;
+}
+
+static AM_ErrorCode_t emu_poll(AM_DVR_Device_t *dev, int timeout)
+{
+	return AM_DVR_ERR_NOT_SUPPORTED;
+}
+
+static AM_ErrorCode_t emu_read(AM_DVR_Device_t *dev, uint8_t *buf, int *size)
+{
+	return AM_DVR_ERR_NOT_SUPPORTED;
+}
+
diff --git a/test/am_ca_key_test/inject_record_t5d/am_dvr/linux_dvb/Makefile b/test/am_ca_key_test/inject_record_t5d/am_dvr/linux_dvb/Makefile
new file mode 100644
index 0000000..a978c87
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_dvr/linux_dvb/Makefile
@@ -0,0 +1,8 @@
+BASE=../../..
+
+include $(BASE)/rule/def.mk
+
+O_TARGET=linux_dvb
+linux_dvb_SRCS=linux_dvb.c
+
+include $(BASE)/rule/rule.mk
diff --git a/test/am_ca_key_test/inject_record_t5d/am_dvr/linux_dvb/linux_dvb.c b/test/am_ca_key_test/inject_record_t5d/am_dvr/linux_dvb/linux_dvb.c
new file mode 100644
index 0000000..468269c
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_dvr/linux_dvb/linux_dvb.c
@@ -0,0 +1,177 @@
+#ifdef _FORTIFY_SOURCE
+#undef _FORTIFY_SOURCE
+#endif
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief Linux DVB dvr 驱动
+ *
+ * \author Xia Lei Peng <leipeng.xia@amlogic.com>
+ * \date 2010-12-13: create the document
+ ***************************************************************************/
+
+#define AM_DEBUG_LEVEL 2
+
+#include <am_debug.h>
+#include <am_mem.h>
+#include "../am_dvr_internal.h"
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <poll.h>
+/*add for config define for linux dvb *.h*/
+#include <am_config.h>
+#include <linux/dvb/dmx.h>
+#include <am_misc.h>
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+
+/****************************************************************************
+ * Static data definitions
+ ***************************************************************************/
+
+static AM_ErrorCode_t dvb_open(AM_DVR_Device_t *dev, const AM_DVR_OpenPara_t *para);
+static AM_ErrorCode_t dvb_close(AM_DVR_Device_t *dev);
+static AM_ErrorCode_t dvb_set_buf_size(AM_DVR_Device_t *dev, int size);
+static AM_ErrorCode_t dvb_poll(AM_DVR_Device_t *dev, int timeout);
+static AM_ErrorCode_t dvb_read(AM_DVR_Device_t *dev, uint8_t *buf, int *size);
+static AM_ErrorCode_t dvb_set_source(AM_DVR_Device_t *dev, AM_DVR_Source_t src);
+
+const AM_DVR_Driver_t linux_dvb_dvr_drv = {
+.open  = dvb_open,
+.close = dvb_close,
+.set_buf_size   = dvb_set_buf_size,
+.poll           = dvb_poll,
+.read           = dvb_read,
+.set_source = dvb_set_source,
+};
+
+
+/****************************************************************************
+ * Static functions
+ ***************************************************************************/
+
+static AM_ErrorCode_t dvb_open(AM_DVR_Device_t *dev, const AM_DVR_OpenPara_t *para)
+{
+	char dev_name[32];
+	int fd;
+	
+	UNUSED(para);
+
+	snprintf(dev_name, sizeof(dev_name), "/dev/dvb0.dvr%d", dev->dev_no);
+	fd = open(dev_name, O_RDONLY);
+	if (fd == -1)
+	{
+		AM_DEBUG(1, "cannot open \"%s\" (%s)", dev_name, strerror(errno));
+		return AM_DVR_ERR_CANNOT_OPEN_DEV;
+	}
+	fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK, 0);
+	dev->drv_data = (void*)(long)fd;
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t dvb_close(AM_DVR_Device_t *dev)
+{
+	int fd = (long)dev->drv_data;
+	
+	close(fd);
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t dvb_set_buf_size(AM_DVR_Device_t *dev, int size)
+{
+	int fd = (long)dev->drv_data;
+	int ret;
+	
+	ret = ioctl(fd, DMX_SET_BUFFER_SIZE, size);
+	if(ret==-1)
+	{
+		AM_DEBUG(1, "set buffer size failed (%s)", strerror(errno));
+		return AM_DVR_ERR_SYS;
+	}
+	
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t dvb_poll(AM_DVR_Device_t *dev, int timeout)
+{
+	int fd = (long)dev->drv_data;
+	struct pollfd fds;
+	int ret;
+	
+	fds.events = POLLIN|POLLERR;
+	fds.fd     = fd;
+
+	ret = poll(&fds, 1, timeout);
+	if(ret<=0)
+	{
+		return AM_DVR_ERR_TIMEOUT;
+	}
+	
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t dvb_read(AM_DVR_Device_t *dev, uint8_t *buf, int *size)
+{
+	int fd = (long)dev->drv_data;
+	int len = *size;
+	int ret;
+	
+	if(fd==-1)
+		return AM_DVR_ERR_NOT_ALLOCATED;
+	
+	ret = read(fd, buf, len);
+	if(ret<=0)
+	{
+		if(errno==ETIMEDOUT)
+			return AM_DVR_ERR_TIMEOUT;
+		AM_DEBUG(1, "read dvr failed (%s) %d", strerror(errno), errno);
+		return AM_DVR_ERR_SYS;
+	}
+	
+	*size = ret;
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t dvb_set_source(AM_DVR_Device_t *dev, AM_DVR_Source_t src)
+{
+	char buf[64];
+	char *cmd;
+	
+	snprintf(buf, sizeof(buf), "/sys/class/stb/asyncfifo%d_source", src);
+	
+	switch(dev->dev_no)
+	{
+		case 0:
+			cmd = "dmx0";
+		break;
+		case 1:
+			cmd = "dmx1";
+		break;
+#if defined(CHIP_8226M) || defined(CHIP_8626X)
+		case 2:
+			cmd = "dmx2";
+		break;
+#endif
+		default:
+			AM_DEBUG(1, "do not support demux no %d", src);
+		return -1;
+	}
+	
+	return AM_FileEcho(buf, cmd);
+}
+	
diff --git a/test/am_ca_key_test/inject_record_t5d/am_inject_record.c b/test/am_ca_key_test/inject_record_t5d/am_inject_record.c
new file mode 100644
index 0000000..0c1aae8
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_inject_record.c
@@ -0,0 +1,350 @@
+#ifdef _FORTIFY_SOURCE
+#undef _FORTIFY_SOURCE
+#endif
+/***************************************************************************
+ *  Copyright C 2009 by Amlogic, Inc. All Rights Reserved.
+ */
+/**\file
+ * \brief DVR测试程序
+ *
+ * \author Xia Lei Peng <leipeng.xia@amlogic.com>
+ * \date 2010-12-10: create the document
+ ***************************************************************************/
+
+#define AM_DEBUG_LEVEL 1
+
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "am_debug.h"
+#include <am_dmx.h>
+#include <am_av.h>
+#include <am_dvr.h>
+#include <am_misc.h>
+#include <errno.h>
+#include <am_dsc.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <am_misc.h>
+#include <am_kl.h>
+#include <sys/time.h>
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+#ifdef CHIP_8226H
+#define DVR_DEV_COUNT      (2)
+#elif defined(CHIP_8226M) || defined(CHIP_8626X)
+#define DVR_DEV_COUNT      (3)
+#else
+#define DVR_DEV_COUNT      (2)
+#endif
+
+#undef DVR_DEV_COUNT
+#define DVR_DEV_COUNT      (2)
+
+#define FEND_DEV_NO 0
+#define AV_DEV_NO 0
+#define PLAY_DMX_DEV_NO 1
+
+#define DMX_DEV_NO 0
+#define DVR_DEV_NO 0
+#define ASYNC_FIFO 0
+
+typedef struct
+{
+	int id;
+	char file_name[256];
+	pthread_t thread;
+	int running;
+	int fd;
+}DVRData;
+
+static DVRData data_threads[DVR_DEV_COUNT];
+
+static int dvr_data_write(int fd, uint8_t *buf, int size)
+{
+	int ret;
+	int left = size;
+	uint8_t *p = buf;
+
+	while (left > 0)
+	{
+		ret = write(fd, p, left);
+		if (ret == -1)
+		{
+			if (errno != EINTR)
+			{
+				printf("Write DVR data failed: %s", strerror(errno));
+				break;
+			}
+			ret = 0;
+		}
+
+		left -= ret;
+		p += ret;
+	}
+
+	return (size - left);
+}
+static void* dvr_data_thread(void *arg)
+{
+	DVRData *dd = (DVRData*)arg;
+	int cnt;
+	uint8_t buf[256*1024];
+
+	printf("Data thread for DVR%d start ,record file will save to '%s'", dd->id, dd->file_name);
+
+	while (dd->running)
+	{
+		cnt = AM_DVR_Read(dd->id, buf, sizeof(buf), 1000);
+		if (cnt <= 0)
+		{
+			printf("No data available from DVR%d", dd->id);
+			usleep(200*1000);
+			continue;
+		}
+		printf("read from DVR%d return %d bytes", dd->id, cnt);
+		if (dd->fd != -1)
+		{
+			dvr_data_write(dd->fd, buf, cnt);
+		}
+	}
+
+	if (dd->fd != -1)
+	{
+		close(dd->fd);
+		dd->fd = -1;
+	}
+	printf("Data thread for DVR%d now exit", dd->id);
+
+	return NULL;
+}
+
+static void start_data_thread(int dev_no)
+{
+	DVRData *dd = &data_threads[dev_no];
+
+	if (dd->running)
+		return;
+	dd->fd = open(dd->file_name, O_TRUNC | O_WRONLY | O_CREAT, 0666);
+	if (dd->fd == -1)
+	{
+		AM_DEBUG(1, "Cannot open record file '%s' for DVR%d", dd->file_name, dd->id);
+		return;
+	}
+	dd->running = 1;
+	pthread_create(&dd->thread, NULL, dvr_data_thread, dd);
+}
+
+static void stop_data_thread(int dev_no)
+{
+	DVRData *dd = &data_threads[dev_no];
+
+	if (! dd->running)
+		return;
+	dd->running = 0;
+	pthread_join(dd->thread, NULL);
+	AM_DEBUG(1, "Data thread for DVR%d has exit", dd->id);
+}
+
+static void handle_signal(int signal)
+{
+	int i;
+	UNUSED(signal);
+	AM_FileEcho("/sys/class/graphics/fb0/blank","0");
+	for (i=0; i< DVR_DEV_COUNT; i++) {
+		AM_DVR_Close(i);
+		AM_DEBUG(1, "Closing DMX%d...", i);
+		AM_DMX_Close(i);
+	}
+
+	exit(0);
+}
+
+static void init_signal_handler()
+{
+	struct sigaction act;
+	act.sa_handler = handle_signal;
+	sigaction(SIGINT, &act, NULL);
+}
+
+static int start_record(int pid0, int pid1, int len, char *record_name)
+{
+	AM_DVR_StartRecPara_t spara;
+	int dev_no, pid_cnt, i;
+	int pids[8];
+	char name[256] = "a.ts";
+
+	dev_no = DVR_DEV_NO;
+	pid_cnt = len;
+	pids[0] = pid0;
+	pids[1] = pid1;
+	data_threads[DVR_DEV_NO].id = dev_no;
+
+	if (record_name)
+		strcpy(data_threads[dev_no].file_name, record_name);
+	else
+		strcpy(data_threads[dev_no].file_name, name);
+
+	spara.pid_count = pid_cnt;
+	memcpy(&spara.pids, pids, sizeof(pids));
+	if (AM_DVR_StartRecord(dev_no, &spara) == AM_SUCCESS)
+	{
+		start_data_thread(dev_no);
+	}
+	printf("started dvr dev_no=%d pid=%d %d out file:%s ..\n", dev_no, pids[0], pids[1],data_threads[dev_no].file_name);
+	return 0;
+}
+
+static int inject_running=0;
+static int inject_loop=0;
+static int inject_type=AM_AV_INJECT_MULTIPLEX;
+static void* inject_entry(void *arg)
+{
+	int sock = (int)(long)arg;
+	uint8_t buf[32*1024];
+	int len, left=0, send, ret;
+	int cnt=50;
+	struct timeval start_tv;
+	struct timeval now_tv;
+	unsigned int diff_time = 0;
+	unsigned int total_len = 0;
+
+	gettimeofday(&start_tv, NULL);
+	AM_DEBUG(1, "inject thread start");
+	while (inject_running) {
+		len = sizeof(buf) - left;
+		ret = read(sock, buf+left, len);
+		if (ret > 0) {
+			printf("recv %d bytes", ret);
+/*			if (!cnt){
+				cnt=50;
+				printf("recv %d\n", ret);
+			}
+			cnt--; */
+			left += ret;
+			total_len += ret;
+		} else {
+			if (inject_loop && ((ret == 0) || (errno == EAGAIN))) {
+				printf("loop\n");
+				lseek(sock, 0, SEEK_SET);
+				left=0;
+				continue;
+			} else {
+				fprintf(stderr, "read file failed [%d:%s] ret=%d left=%d\n", errno, strerror(errno), ret, left);
+				break;
+			}
+		}
+		if (left) {
+			gettimeofday(&now_tv, NULL);
+			if (now_tv.tv_usec < start_tv.tv_usec) {
+				diff_time = (now_tv.tv_sec - 1 - start_tv.tv_sec) * 1000 + (now_tv.tv_usec + 1*1000*1000 - start_tv.tv_usec) / 1000;
+			} else {
+				diff_time = (now_tv.tv_sec - start_tv.tv_sec) * 1000 + (now_tv.tv_usec - start_tv.tv_usec) / 1000;
+			}
+
+			if ( diff_time != 0 && total_len/1024/1024*8*1000/diff_time > 4) {
+				usleep(20*1000);
+			}
+
+			send = left;
+			AM_AV_InjectData(AV_DEV_NO, inject_type, buf, &send, -1);
+			if (send) {
+				left -= send;
+				if (left)
+					memmove(buf, buf+send, left);
+				//AM_DEBUG(1, "inject %d bytes", send);
+			}
+		}
+	}
+	printf("inject thread end");
+
+	return NULL;
+}
+
+int inject_file_and_rec_open(char *inject_name,int vpid, int apid, char *record_name)
+{
+	AM_DMX_OpenPara_t para;
+	AM_DVR_OpenPara_t dpara;
+	int pid_cnt = 0;
+	int pids[8];
+	int loop = 0;
+	int ofd;
+	pthread_t th;
+
+	printf("inject file name=%s\n", inject_name);
+
+	if (vpid > 0) {
+		pids[0] = vpid;
+		pid_cnt ++;
+	}
+	if (apid > 0) {
+		pids[1] = apid;
+		pid_cnt ++;
+	}
+
+	init_signal_handler();
+	AM_FileEcho("/sys/class/graphics/fb0/blank","1");
+
+	AM_AV_InjectPara_t av_para;
+	AM_AV_OpenPara_t av_open_para;
+	av_para.vid_fmt = 0;//VFORMAT_H264
+	av_para.aud_fmt = 0;
+	av_para.pkg_fmt = PFORMAT_TS;
+	av_para.vid_id  = pids[0];
+	av_para.aud_id  = pids[1];
+
+	AM_DEBUG(1, "Openning DMX%d...", 0);
+	memset(&para, 0, sizeof(para));
+	AM_TRY(AM_DMX_Open(DMX_DEV_NO, &para));
+	AM_DMX_SetSource(DMX_DEV_NO, AM_DMX_SRC_HIU);
+	AM_DEBUG(1, "Openning DVR%d...", 0);
+	memset(&dpara, 0, sizeof(dpara));
+	AM_TRY(AM_DVR_Open(DVR_DEV_NO, &dpara));
+
+	data_threads[0].id =0;
+	data_threads[0].fd = -1;
+	data_threads[0].running = 0;
+
+	AM_TRY(AM_AV_Open(AV_DEV_NO, &av_open_para));
+	AM_AV_SetTSSource(AV_DEV_NO, AM_AV_TS_SRC_HIU);
+	AM_AV_StartInject(AV_DEV_NO, &av_para);
+	AM_DVR_SetSource(DVR_DEV_NO,ASYNC_FIFO);
+
+	start_record(pids[0], pids[1], pid_cnt,record_name);
+	ofd = open(inject_name, O_RDWR, S_IRUSR);
+
+	sleep(1);
+	inject_loop = loop;
+	inject_running = 1;
+	inject_type = (pids[1]==-1)? AM_AV_INJECT_VIDEO :
+		(pids[0]==-1)? AM_AV_INJECT_AUDIO :
+		AM_AV_INJECT_MULTIPLEX;
+	pthread_create(&th, NULL, inject_entry, (void*)(long)ofd);
+
+	return 0;
+}
+int inject_file_and_rec_close(void) {
+	int i = 0;
+
+	printf("inject_file_and_rec_close start\n");
+	for (i=0; i< DVR_DEV_COUNT; i++)
+	{
+		AM_DEBUG(1, "Closing DVR%d...", i);
+		if (data_threads[i].running)
+			stop_data_thread(i);
+		AM_DVR_Close(i);
+		AM_DEBUG(1, "Closing DMX%d...", i);
+		AM_DMX_Close(i);
+	}
+	printf("inject_file_and_rec_close end\n");
+	AM_FileEcho("/sys/class/graphics/fb0/blank","0");
+	printf("inject_file_and_rec_close end1\n");
+	return 0;
+}
+
diff --git a/test/am_ca_key_test/inject_record_t5d/am_misc/Makefile b/test/am_ca_key_test/inject_record_t5d/am_misc/Makefile
new file mode 100644
index 0000000..7188dea
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_misc/Makefile
@@ -0,0 +1,8 @@
+BASE=../..
+
+include $(BASE)/rule/def.mk
+
+O_TARGET=am_misc
+am_misc_SRCS=am_adplock.c am_misc.c am_thread.c
+
+include $(BASE)/rule/rule.mk
diff --git a/test/am_ca_key_test/inject_record_t5d/am_misc/am_adplock.c b/test/am_ca_key_test/inject_record_t5d/am_misc/am_adplock.c
new file mode 100644
index 0000000..e3736c2
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_misc/am_adplock.c
@@ -0,0 +1,31 @@
+#ifdef _FORTIFY_SOURCE
+#undef _FORTIFY_SOURCE
+#endif
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief AMLogic adaptor layer全局锁
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-07-05: create the document
+ ***************************************************************************/
+
+#define AM_DEBUG_LEVEL 0
+
+#include <am_debug.h>
+#include <am_mem.h>
+#include "../am_adp_internal.h"
+
+/****************************************************************************
+ * Data definitions
+ ***************************************************************************/
+
+pthread_mutex_t am_gAdpLock = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t am_gHwDmxLock = PTHREAD_MUTEX_INITIALIZER;
+
diff --git a/test/am_ca_key_test/inject_record_t5d/am_misc/am_iconv.c b/test/am_ca_key_test/inject_record_t5d/am_misc/am_iconv.c
new file mode 100644
index 0000000..3bf7cd6
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_misc/am_iconv.c
@@ -0,0 +1,60 @@
+#ifdef _FORTIFY_SOURCE
+#undef _FORTIFY_SOURCE
+#endif
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief iconv functions
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2014-03-18: create the document
+ ***************************************************************************/
+
+#define AM_DEBUG_LEVEL 1
+
+#include <stdlib.h>
+#include <am_iconv.h>
+#include <am_debug.h>
+#include <stdbool.h>
+
+
+UConverter* (*am_ucnv_open_ptr)(const char *converterName, UErrorCode *err);
+void (*am_ucnv_close_ptr)(UConverter * converter);
+void (*am_ucnv_convertEx_ptr)(UConverter *targetCnv, UConverter *sourceCnv,
+		char **target, const char *targetLimit,
+		const char **source, const char *sourceLimit,
+		UChar *pivotStart, UChar **pivotSource,
+		UChar **pivotTarget, const UChar *pivotLimit,
+		UBool reset, UBool flush,
+		UErrorCode *pErrorCode);
+void (*am_u_setDataDirectory_ptr)(const char *directory);
+void (*am_u_init_ptr)(long *status);
+
+#ifdef USE_VENDOR_ICU
+bool actionFlag = false;
+void am_first_action(void)
+{
+	if (!actionFlag) {
+		setenv("ICU_DATA", "/vendor/usr/icu", 1);
+		u_setDataDirectory("/vendor/usr/icu");
+		long status = 0;
+		u_init((UErrorCode *)&status);
+		if (status > 0)
+			AM_DEBUG(1, "icu init fail. [%ld]", status);
+		actionFlag = true;
+	}
+}
+#endif
+
+void
+am_ucnv_dlink(void)
+{
+
+}
+
diff --git a/test/am_ca_key_test/inject_record_t5d/am_misc/am_misc.c b/test/am_ca_key_test/inject_record_t5d/am_misc/am_misc.c
new file mode 100644
index 0000000..e63f66b
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_misc/am_misc.c
@@ -0,0 +1,694 @@
+#ifdef _FORTIFY_SOURCE
+#undef _FORTIFY_SOURCE
+#endif
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief Misc functions
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-08-05: create the document
+ ***************************************************************************/
+
+#define AM_DEBUG_LEVEL 1
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <am_types.h>
+#include <am_debug.h>
+#include <am_mem.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <assert.h>
+#include <dlfcn.h>
+#include "am_misc.h"
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+/****************************************************************************
+ * Static functions
+ ***************************************************************************/
+int (*Write_Sysfs_ptr)(const char *path, char *value);
+int (*ReadNum_Sysfs_ptr)(const char *path, char *value, int size);
+int (*Read_Sysfs_ptr)(const char *path, char *value);
+
+static int AM_SYSTEMCONTROL_INIT=0;
+
+typedef struct am_rw_sysfs_cb_s
+{
+	AM_Read_Sysfs_Cb readSysfsCb;
+	AM_Write_Sysfs_Cb writeSysfsCb;
+}am_rw_sysfs_cb_t;
+
+am_rw_sysfs_cb_t rwSysfsCb = {.readSysfsCb = NULL, .writeSysfsCb = NULL};
+
+typedef struct am_rw_prop_cb_s
+{
+	AM_Read_Prop_Cb readPropCb;
+	AM_Write_Prop_Cb writePropCb;
+}am_rw_prop_cb_t;
+
+am_rw_prop_cb_t rwPropCb = {.readPropCb = NULL, .writePropCb = NULL};
+
+#ifdef ANDROID
+
+# define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un*) 0)->sun_path) + strlen ((ptr)->sun_path) )
+
+#endif
+
+/**\brief init systemcontrol rw api ptr
+ * \param null
+ * \param[in] null
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码
+ */
+static AM_ErrorCode_t am_init_syscontrol_api()
+{
+#ifdef ANDROID
+	if(AM_SYSTEMCONTROL_INIT==0)
+	{
+		void* handle = NULL;
+#ifndef NO_SYSFS
+		if(handle == NULL) {
+			handle = dlopen("libam_sysfs.so", RTLD_NOW);//RTLD_NOW  RTLD_LAZY
+		}
+#endif
+		if(handle==NULL)
+		{
+			//AM_DEBUG(1, "open lib error--%s\r\n",dlerror());
+			return AM_FAILURE;
+		}
+		AM_DEBUG(1, "open lib ok--\r\n");
+		Write_Sysfs_ptr = dlsym(handle, "AM_SystemControl_Write_Sysfs");
+		ReadNum_Sysfs_ptr = dlsym(handle, "AM_SystemControl_ReadNum_Sysfs");
+		Read_Sysfs_ptr = dlsym(handle, "AM_SystemControl_Read_Sysfs");
+
+		AM_SYSTEMCONTROL_INIT=1;
+		if(Write_Sysfs_ptr==NULL)
+		{
+			AM_DEBUG(1, "cannot get write sysfs api\r\n");
+		}
+		if(ReadNum_Sysfs_ptr==NULL)
+		{
+			AM_DEBUG(1, "cannot get read num sysfs api\r\n");
+		}
+		if(Read_Sysfs_ptr==NULL)
+		{
+			AM_DEBUG(1, "cannot get read sysfs api\r\n");
+		}
+	}
+#endif
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t try_write(int fd, const char *buf, int len)
+{
+	const char *ptr = buf;
+	int left = len;
+	int ret;
+	
+	while(left)
+	{
+		ret = write(fd, ptr, left);
+		if(ret==-1)
+		{
+			if(errno!=EINTR)
+				return AM_FAILURE;
+			ret = 0;
+		}
+		
+		ptr += ret;
+		left-= ret;
+	}
+	
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t try_read(int fd, char *buf, int len)
+{
+	char *ptr = buf;
+	int left = len;
+	int ret;
+	
+	while(left)
+	{
+		ret = read(fd, ptr, left);
+		if(ret==-1)
+		{
+			if(errno!=EINTR)
+				return AM_FAILURE;
+			ret = 0;
+		}
+		
+		ptr += ret;
+		left-= ret;
+	}
+	
+	return AM_SUCCESS;
+}
+
+/****************************************************************************
+ * API functions
+ ***************************************************************************/
+
+/**\brief 注册读写sysfs的回调函数
+ * \param[in] fun 回调
+ * \return
+ *	 - AM_SUCCESS 成功
+ *	 - 其他值 错误代码
+ */
+void AM_RegisterRWSysfsFun(AM_Read_Sysfs_Cb RCb, AM_Write_Sysfs_Cb WCb)
+{
+	assert(RCb && WCb);
+
+	if (!rwSysfsCb.readSysfsCb)
+		rwSysfsCb.readSysfsCb = RCb;
+	if (!rwSysfsCb.writeSysfsCb)
+		rwSysfsCb.writeSysfsCb = WCb;
+
+	AM_DEBUG(1, "AM_RegisterRWSysfsFun !!");
+}
+
+/**\brief 卸载注册
+ */
+void AM_UnRegisterRWSysfsFun()
+{
+	if (rwSysfsCb.readSysfsCb)
+		rwSysfsCb.readSysfsCb = NULL;
+	if (rwSysfsCb.writeSysfsCb)
+		rwSysfsCb.writeSysfsCb = NULL;
+}
+
+/**\brief 注册读写prop的回调函数
+ * \param[in] fun 回调
+ * \return
+ *	 - AM_SUCCESS 成功
+ *	 - 其他值 错误代码
+ */
+void AM_RegisterRWPropFun(AM_Read_Prop_Cb RCb, AM_Write_Prop_Cb WCb)
+{
+	assert(RCb && WCb);
+
+	if (!rwPropCb.readPropCb)
+		rwPropCb.readPropCb = RCb;
+	if (!rwPropCb.writePropCb)
+		rwPropCb.writePropCb = WCb;
+
+	AM_DEBUG(1, "AM_RegisterRWSysfsFun !!");
+}
+
+/**\brief 卸载prop注册
+ */
+void AM_UnRegisterRWPropFun()
+{
+	if (rwPropCb.readPropCb)
+		rwPropCb.readPropCb = NULL;
+	if (rwPropCb.writePropCb)
+		rwPropCb.writePropCb = NULL;
+}
+
+/**\brief 向一个文件打印字符串
+ * \param[in] name 文件名
+ * \param[in] cmd 向文件打印的字符串
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码
+ */
+AM_ErrorCode_t AM_FileEcho(const char *name, const char *cmd)
+{
+	int fd, len, ret;
+
+	assert(name && cmd);
+
+	if (rwSysfsCb.writeSysfsCb)
+	{
+		rwSysfsCb.writeSysfsCb(name, cmd);
+		return AM_SUCCESS;
+	}else
+	{
+		am_init_syscontrol_api();
+		if (Write_Sysfs_ptr != NULL)
+		{
+			return Write_Sysfs_ptr(name, (char *)cmd);
+		}
+	}
+
+	fd = open(name, O_WRONLY);
+	if(fd==-1)
+	{
+		AM_DEBUG(1, "cannot open file \"%s\"", name);
+		return AM_FAILURE;
+	}
+	
+	len = strlen(cmd);
+	
+	ret = write(fd, cmd, len);
+	if(ret!=len)
+	{
+		AM_DEBUG(1, "write failed file:\"%s\" cmd:\"%s\" error:\"%s\"", name, cmd, strerror(errno));
+		close(fd);
+		return AM_FAILURE;
+	}
+
+	close(fd);
+
+	return AM_SUCCESS;
+}
+
+/**\brief 读取一个文件中的字符串
+ * \param[in] name 文件名
+ * \param[out] buf 存放字符串的缓冲区
+ * \param len 缓冲区大小
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码
+ */
+AM_ErrorCode_t AM_FileRead(const char *name, char *buf, int len)
+{
+	FILE *fp;
+	char *ret;
+	
+	assert(name && buf);
+
+	if (rwSysfsCb.readSysfsCb)
+	{
+		rwSysfsCb.readSysfsCb(name, buf, len);
+		return AM_SUCCESS;
+	}else
+	{
+		am_init_syscontrol_api();
+		if (ReadNum_Sysfs_ptr != NULL)
+		{
+			return ReadNum_Sysfs_ptr(name,buf,len);
+		}
+	}
+
+
+	fp = fopen(name, "r");
+	if(!fp)
+	{
+		AM_DEBUG(1, "cannot open file \"%s\"", name);
+		return AM_FAILURE;
+	}
+	
+	ret = fgets(buf, len, fp);
+	if(!ret)
+	{
+		AM_DEBUG(1, "read the file:\"%s\" error:\"%s\" failed", name, strerror(errno));
+	}
+	
+	fclose(fp);
+	
+	return ret ? AM_SUCCESS : AM_FAILURE;
+}
+
+
+/**\brief 向一个prop set字符串
+ * \param[in] name 文件名
+ * \param[in] cmd 向propset 的字符串
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码
+ */
+AM_ErrorCode_t AM_PropEcho(const char *name, const char *cmd)
+{
+	int fd, len, ret;
+
+	assert(name && cmd);
+
+	if (rwPropCb.writePropCb)
+	{
+		rwPropCb.writePropCb(name, cmd);
+		return AM_SUCCESS;
+	}
+
+	return AM_SUCCESS;
+}
+
+/**\brief 读取一个prop字符串
+ * \param[in] name prop名
+ * \param[out] buf 存放字符串的缓冲区
+ * \param len 缓冲区大小
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码
+ */
+AM_ErrorCode_t AM_PropRead(const char *name, char *buf, int len)
+{
+	FILE *fp;
+	char *ret;
+
+	assert(name && buf);
+
+	if (rwPropCb.readPropCb)
+	{
+		rwPropCb.readPropCb(name, buf, len);
+		return AM_SUCCESS;
+	}
+	return AM_FAILURE;
+}
+
+/**\brief 创建本地socket服务
+ * \param[in] name 服务名称
+ * \param[out] fd 返回服务器socket
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码
+ */
+AM_ErrorCode_t AM_LocalServer(const char *name, int *fd)
+{
+	struct sockaddr_un addr;
+	int s, ret;
+	
+	assert(name && fd);
+	
+	s = socket(AF_LOCAL, SOCK_STREAM, 0);
+	if(s==-1)
+	{
+		AM_DEBUG(1, "cannot create local socket \"%s\"", strerror(errno));
+		return AM_FAILURE;
+	}
+	
+	addr.sun_family = AF_LOCAL;
+	strncpy(addr.sun_path, name, sizeof(addr.sun_path)-1);
+
+	ret = bind(s, (struct sockaddr*)&addr, SUN_LEN(&addr));
+	if(ret==-1)
+	{
+		AM_DEBUG(1, "bind to \"%s\" failed \"%s\"", name, strerror(errno));
+		close(s);
+		return AM_FAILURE;
+	}
+
+	ret = listen(s, 5);
+	if(ret==-1)
+	{
+		AM_DEBUG(1, "listen failed \"%s\" (%s)", name, strerror(errno));
+		close(s);
+		return AM_FAILURE;
+	}
+
+	*fd = s;
+	return AM_SUCCESS;
+        
+}
+
+/**\brief 通过本地socket连接到服务
+ * \param[in] name 服务名称
+ * \param[out] fd 返回socket
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码
+ */
+AM_ErrorCode_t AM_LocalConnect(const char *name, int *fd)
+{
+	struct sockaddr_un addr;
+	int s, ret;
+	
+	assert(name && fd);
+	
+	s = socket(AF_LOCAL, SOCK_STREAM, 0);
+	if(s==-1)
+	{
+		AM_DEBUG(1, "cannot create local socket \"%s\"", strerror(errno));
+		return AM_FAILURE;
+	}
+	
+	addr.sun_family = AF_LOCAL;
+        strncpy(addr.sun_path, name, sizeof(addr.sun_path)-1);
+        
+        ret = connect(s, (struct sockaddr*)&addr, SUN_LEN(&addr));
+        if(ret==-1)
+        {
+        	AM_DEBUG(1, "connect to \"%s\" failed \"%s\"", name, strerror(errno));
+        	close(s);
+		return AM_FAILURE;
+        }
+        
+        *fd = s;
+        return AM_SUCCESS;
+}
+
+/**\brief 通过本地socket发送命令
+ * \param fd socket
+ * \param[in] cmd 命令字符串
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码
+ */
+AM_ErrorCode_t AM_LocalSendCmd(int fd, const char *cmd)
+{
+	AM_ErrorCode_t ret;
+	int len;
+	
+	assert(cmd);
+	
+	len = strlen(cmd)+1;
+	
+	ret = try_write(fd, (const char*)&len, sizeof(int));
+	if(ret!=AM_SUCCESS)
+	{
+		AM_DEBUG(1, "write local socket failed");
+		return ret;
+	}
+	
+	ret = try_write(fd, cmd, len);
+	if(ret!=AM_SUCCESS)
+	{
+		AM_DEBUG(1, "write local socket failed");
+		return ret;
+	}
+	
+	AM_DEBUG(2, "write cmd: %s", cmd);
+	
+	return AM_SUCCESS;
+}
+
+/**\brief 通过本地socket接收响应字符串
+ * \param fd socket
+ * \param[out] buf 缓冲区
+ * \param len 缓冲区大小
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码
+ */
+AM_ErrorCode_t AM_LocalGetResp(int fd, char *buf, int len)
+{
+	AM_ErrorCode_t ret;
+	int bytes;
+	
+	assert(buf);
+	
+	ret = try_read(fd, (char*)&bytes, sizeof(int));
+	if(ret!=AM_SUCCESS)
+	{
+		AM_DEBUG(1, "read local socket failed");
+		return ret;
+	}
+	
+	if(len<bytes)
+	{
+		AM_DEBUG(1, "respond buffer is too small");
+		return AM_FAILURE;
+	}
+	
+	ret = try_read(fd, buf, bytes);
+	if(ret!=AM_SUCCESS)
+	{
+		AM_DEBUG(1, "read local socket failed");
+		return ret;
+	}
+	
+	return AM_SUCCESS;
+}
+
+/* UTF8 utilities */
+
+/* This parses a UTF8 string one character at a time. It is passed a pointer
+ * to the string and the length of the string. It sets 'value' to the value of
+ * the current character. It returns the number of characters read or a
+ * negative error code:
+ * -1 = string too short
+ * -2 = illegal character
+ * -3 = subsequent characters not of the form 10xxxxxx
+ * -4 = character encoded incorrectly (not minimal length).
+ */
+
+static int UTF8_getc(const unsigned char *str, int len, unsigned long *val)
+{
+	const unsigned char *p;
+	unsigned long value;
+	int ret;
+	if(len <= 0) return 0;
+	p = str;
+
+	/* Check syntax and work out the encoded value (if correct) */
+	if((*p & 0x80) == 0) {
+		value = *p++ & 0x7f;
+		ret = 1;
+	} else if((*p & 0xe0) == 0xc0) {
+		if(len < 2) return -1;
+		if((p[1] & 0xc0) != 0x80) return -3;
+		value = (*p++ & 0x1f) << 6;
+		value |= *p++ & 0x3f;
+		if(value < 0x80) return -4;
+		ret = 2;
+	} else if((*p & 0xf0) == 0xe0) {
+		if(len < 3) return -1;
+		if( ((p[1] & 0xc0) != 0x80)
+		   || ((p[2] & 0xc0) != 0x80) ) return -3;
+		value = (*p++ & 0xf) << 12;
+		value |= (*p++ & 0x3f) << 6;
+		value |= *p++ & 0x3f;
+		if(value < 0x800) return -4;
+		ret = 3;
+	} else if((*p & 0xf8) == 0xf0) {
+		if(len < 4) return -1;
+		if( ((p[1] & 0xc0) != 0x80)
+		   || ((p[2] & 0xc0) != 0x80) 
+		   || ((p[3] & 0xc0) != 0x80) ) return -3;
+		value = ((unsigned long)(*p++ & 0x7)) << 18;
+		value |= (*p++ & 0x3f) << 12;
+		value |= (*p++ & 0x3f) << 6;
+		value |= *p++ & 0x3f;
+		if(value < 0x10000) return -4;
+		ret = 4;
+	} else if((*p & 0xfc) == 0xf8) {
+		if(len < 5) return -1;
+		if( ((p[1] & 0xc0) != 0x80)
+		   || ((p[2] & 0xc0) != 0x80) 
+		   || ((p[3] & 0xc0) != 0x80) 
+		   || ((p[4] & 0xc0) != 0x80) ) return -3;
+		value = ((unsigned long)(*p++ & 0x3)) << 24;
+		value |= ((unsigned long)(*p++ & 0x3f)) << 18;
+		value |= ((unsigned long)(*p++ & 0x3f)) << 12;
+		value |= (*p++ & 0x3f) << 6;
+		value |= *p++ & 0x3f;
+		if(value < 0x200000) return -4;
+		ret = 5;
+	} else if((*p & 0xfe) == 0xfc) {
+		if(len < 6) return -1;
+		if( ((p[1] & 0xc0) != 0x80)
+		   || ((p[2] & 0xc0) != 0x80) 
+		   || ((p[3] & 0xc0) != 0x80) 
+		   || ((p[4] & 0xc0) != 0x80) 
+		   || ((p[5] & 0xc0) != 0x80) ) return -3;
+		value = ((unsigned long)(*p++ & 0x1)) << 30;
+		value |= ((unsigned long)(*p++ & 0x3f)) << 24;
+		value |= ((unsigned long)(*p++ & 0x3f)) << 18;
+		value |= ((unsigned long)(*p++ & 0x3f)) << 12;
+		value |= (*p++ & 0x3f) << 6;
+		value |= *p++ & 0x3f;
+		if(value < 0x4000000) return -4;
+		ret = 6;
+	} else return -2;
+	*val = value;
+	return ret;
+}
+
+static int in_utf8(unsigned long value, void *arg)
+{
+	int *nchar;
+	nchar = arg;
+	(*nchar) += value;
+	return 1;
+}
+
+static int is_ctrl_code(unsigned long v)
+{
+	return ((v >= 0x80) && (v <= 0x9f))
+		|| ((v >= 0xE080) && (v <= 0xE09f));
+}
+
+/* This function traverses a string and passes the value of each character
+ * to an optional function along with a void * argument.
+ */
+
+static int traverse_string(const unsigned char *p, int len,
+		 int (*rfunc)(unsigned long value, void *in), void *arg,char *dest, int *dest_len)
+{
+	unsigned long value;
+	int ret;
+	while(len) {
+
+		ret = UTF8_getc(p, len, &value);
+		if(ret < 0) 
+		{
+			len -- ;
+			p++;
+			continue;
+		}//return -1;
+		else if(is_ctrl_code(value))
+		{//remove the control codes
+			len -= ret;
+			p += ret;
+			continue;
+		}
+		else
+		{        
+			int *pos = arg;
+			if((*pos + ret) > *dest_len)
+				break;
+
+			char *tp = dest+(*pos);
+			memcpy(tp,p,ret);
+			len -= ret;
+			p += ret;			
+		}
+		if(rfunc) {
+			ret = rfunc(ret, arg);
+			if(ret <= 0) return ret;
+		}
+	}
+	return 1;
+}
+
+
+/**\brief 跳过无效UTF8字符
+ * \param[in] src 源字符缓冲区
+ * \param src_len 源字符缓冲区大小
+ * \param[out] dest 目标字符缓冲区
+ * \param[in] dest_len 目标字符缓冲区大小
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码
+ */
+AM_ErrorCode_t AM_Check_UTF8(const char *src, int src_len, char *dest, int *dest_len)
+{
+	assert(src);
+	assert(dest);
+	assert(dest_len);
+
+	int ret;
+	int nchar;
+	nchar = 0;
+	/* This counts the characters and does utf8 syntax checking */
+	ret = traverse_string((unsigned char*)src, src_len, in_utf8, &nchar,dest, dest_len);
+
+	*dest_len = nchar;	
+	return AM_SUCCESS;	
+}
+
+static int am_debug_loglevel = AM_DEBUG_LOGLEVEL_DEFAULT;
+
+void AM_DebugSetLogLevel(int level)
+{
+	am_debug_loglevel = level;
+}
+
+int AM_DebugGetLogLevel()
+{
+	return am_debug_loglevel;
+}
diff --git a/test/am_ca_key_test/inject_record_t5d/am_misc/am_sig_handler.c b/test/am_ca_key_test/inject_record_t5d/am_misc/am_sig_handler.c
new file mode 100644
index 0000000..6fd4483
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_misc/am_sig_handler.c
@@ -0,0 +1,45 @@
+#ifdef _FORTIFY_SOURCE
+#undef _FORTIFY_SOURCE
+#endif
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief pthread 信号注册
+ *
+ * \author Yan Yan <Yan.Yan@amlogic.com>
+ * \date 2018-04-03: create the document
+ ***************************************************************************/
+
+#define AM_DEBUG_LEVEL 5
+
+#include <am_debug.h>
+#include <pthread.h>
+#include <signal.h>
+
+static pthread_once_t once = PTHREAD_ONCE_INIT;
+
+static void sig_handler(int signo)
+{
+	pthread_t tid =pthread_self();
+	AM_DEBUG(AM_DEBUG_LEVEL, "signal handler, tid %ld, signo %d", tid, signo);
+}
+
+static void register_sig_handler()
+{
+	struct sigaction action = {0};
+	action.sa_flags = 0;
+	action.sa_handler = sig_handler;
+	sigaction(SIGALRM, &action, NULL);
+}
+
+void AM_SigHandlerInit()
+{
+	pthread_once(&once, register_sig_handler);
+}
+
diff --git a/test/am_ca_key_test/inject_record_t5d/am_misc/am_thread.c b/test/am_ca_key_test/inject_record_t5d/am_misc/am_thread.c
new file mode 100644
index 0000000..defd72a
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_misc/am_thread.c
@@ -0,0 +1,327 @@
+#ifdef _FORTIFY_SOURCE
+#undef _FORTIFY_SOURCE
+#endif
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief pthread 调试工具
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-10-15: create the document
+ ***************************************************************************/
+
+#define AM_DEBUG_LEVEL 5
+
+#include <am_debug.h>
+#include <am_mem.h>
+#include <pthread.h>
+
+/****************************************************************************
+ * Type define
+ ***************************************************************************/
+
+typedef struct {
+	const char       *file;
+	const char       *func;
+	int               line;
+} AM_ThreadFrame_t;
+
+typedef struct AM_Thread AM_Thread_t;
+struct AM_Thread {
+	AM_Thread_t      *prev;
+	AM_Thread_t      *next;
+	pthread_t         thread;
+	char             *name;
+	void* (*entry)(void*);
+	void             *arg;
+	AM_ThreadFrame_t *frame;
+	int               frame_size;
+	int               frame_top;
+};
+
+/****************************************************************************
+ * Static data
+ ***************************************************************************/
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_once_t  once = PTHREAD_ONCE_INIT;
+static AM_Thread_t    *threads = NULL;
+
+/****************************************************************************
+ * Static functions
+ ***************************************************************************/
+
+static void thread_init(void)
+{
+	AM_Thread_t *th;
+	
+	th = malloc(sizeof(AM_Thread_t));
+	if(!th)
+	{
+		AM_DEBUG(1, "not enough memory");
+		return;
+	}
+	
+	th->thread= pthread_self();
+	th->name  = strdup("main");
+	th->entry = NULL;
+	th->arg   = NULL;
+	th->prev  = NULL;
+	th->next  = NULL;
+	th->frame = NULL;
+	th->frame_size = 0;
+	th->frame_top  = 0;
+	
+	threads = th;
+	
+	AM_DEBUG(1, "Register thread \"main\"");
+}
+
+static void thread_remove(AM_Thread_t *th)
+{
+	if(th->prev)
+		th->prev->next = th->next;
+	else
+		threads = th->next;
+	if(th->next)
+		th->next->prev = th->prev;
+	
+	if(th->name)
+		free(th->name);
+	if(th->frame)
+		free(th->frame);
+	
+	free(th);
+}
+
+static void* thread_entry(void *arg)
+{
+	AM_Thread_t *th = (AM_Thread_t*)arg;
+	void *r;
+	
+	pthread_mutex_lock(&lock);
+	th->thread = pthread_self();
+	pthread_mutex_unlock(&lock);
+	
+	AM_DEBUG(1, "Register thread \"%s\" %p", th->name, (void*)th->thread);
+	
+	r = th->entry(th->arg);
+	
+	pthread_mutex_lock(&lock);
+	thread_remove(th);
+	pthread_mutex_unlock(&lock);
+	
+	return r;
+}
+
+static AM_Thread_t* thread_get(pthread_t t)
+{
+	AM_Thread_t *th;
+	
+	for(th=threads; th; th=th->next)
+	{
+		if(th->thread==t)
+			return th;
+	}
+	
+	return NULL;
+}
+
+/****************************************************************************
+ * API functions
+ ***************************************************************************/
+
+/**\brief 创建一个被AM_THREAD管理的线程
+ * \param[out] thread 返回线程句柄
+ * \param[in] attr 线程属性,等于NULL时使用缺省属性
+ * \param start_routine 线程入口函数
+ * \param[in] arg 线程入口函数的参数
+ * \param[in] name 线程名
+ * \return 成功返回0,失败返回错误代码
+ */
+int AM_pthread_create_name(pthread_t *thread,
+		const pthread_attr_t *attr,
+		void* (*start_routine)(void*),
+		void *arg,
+		const char *name)
+{
+	AM_Thread_t *th;
+	int ret;
+	
+	pthread_once(&once, thread_init);
+	
+	th = malloc(sizeof(AM_Thread_t));
+	if(!th)
+	{
+		AM_DEBUG(1, "not enough memory");
+		return -1;
+	}
+	
+	th->thread= -1;
+	th->name  = name?strdup(name):NULL;
+	th->entry = start_routine;
+	th->arg   = arg;
+	th->prev  = NULL;
+	th->frame = NULL;
+	th->frame_size = 0;
+	th->frame_top  = 0;
+	
+	pthread_mutex_lock(&lock);
+	if(threads)
+		threads->prev = th;
+	th->next = threads;
+	threads = th;
+	pthread_mutex_unlock(&lock);
+	
+	ret = pthread_create(thread, attr, thread_entry, th);
+	if(ret)
+	{
+		AM_DEBUG(1, "create thread failed");
+		pthread_mutex_lock(&lock);
+		thread_remove(th);
+		pthread_mutex_unlock(&lock);
+		
+		return ret;
+	}
+	
+	return 0;
+}
+
+/**\brief 结束当前线程
+ * \param[in] r 返回值
+ */
+void AM_pthread_exit(void *r)
+{
+	AM_Thread_t *th;
+	
+	pthread_once(&once, thread_init);
+	
+	pthread_mutex_lock(&lock);
+	
+	th = thread_get(pthread_self());
+	if(th)
+		thread_remove(th);
+	else
+		AM_DEBUG(1, "thread %p is not registered", (void*)pthread_self());
+		
+	pthread_mutex_unlock(&lock);
+	
+	pthread_exit(r);
+}
+
+/**\brief 记录当前线程进入一个函数
+ * \param[in] file 文件名
+ * \param[in] func 函数名
+ * \param line 行号
+ * \return 成功返回0,失败返回错误代码
+ */
+int AM_pthread_enter(const char *file, const char *func, int line)
+{
+	AM_Thread_t *th;
+	int ret = 0;
+	
+	pthread_once(&once, thread_init);
+	
+	pthread_mutex_lock(&lock);
+	
+	th = thread_get(pthread_self());
+	if(th)
+	{
+		if((th->frame_top+1)>=th->frame_size)
+		{
+			AM_ThreadFrame_t *f;
+			int size = AM_MAX(th->frame_size*2, 16);
+			
+			f = realloc(th->frame, sizeof(AM_ThreadFrame_t)*size);
+			if(!f)
+			{
+				AM_DEBUG(1, "not enough memory");
+				ret = -1;
+				goto error;
+			}
+			
+			th->frame = f;
+			th->frame_size = size;
+		}
+		th->frame[th->frame_top].file = file;
+		th->frame[th->frame_top].func = func;
+		th->frame[th->frame_top].line = line;
+		th->frame_top++;
+	}
+	else
+	{
+		AM_DEBUG(1, "thread %p is not registered", (void*)pthread_self());
+		ret = -1;
+	}
+error:
+	pthread_mutex_unlock(&lock);
+	return ret;
+}
+
+/**\brief 记录当前线程离开一个函数
+ * \param[in] file 文件名
+ * \param[in] func 函数名
+ * \param line 行号
+ * \return 成功返回0,失败返回错误代码
+ */
+int AM_pthread_leave(const char *file, const char *func, int line)
+{
+	AM_Thread_t *th;
+	
+	pthread_once(&once, thread_init);
+	
+	pthread_mutex_lock(&lock);
+	
+	th = thread_get(pthread_self());
+	if(th)
+	{
+		if(!th->frame_top)
+			AM_DEBUG(1, "AM_pthread_enter and AM_pthread_leave mismatch");
+		else
+			th->frame_top--;
+	}
+	else
+	{
+		AM_DEBUG(1, "thread %p is not registered", (void*)pthread_self());
+	}
+		
+	pthread_mutex_unlock(&lock);
+	
+	return 0;
+}
+
+/**\brief 打印当前所有注册线程的状态信息
+ * \return 成功返回0,失败返回错误代码
+ */
+int AM_pthread_dump(void)
+{
+	AM_Thread_t *th;
+	int i, l, n;
+	
+	pthread_once(&once, thread_init);
+	
+	pthread_mutex_lock(&lock);
+	
+	for(th=threads,i=0; th; th=th->next, i++)
+	{
+		if(th->thread==-1)
+			continue;
+		
+		fprintf(stdout, "Thread %d (%p:%s)\n", i, (void*)th->thread, th->name?th->name:"");
+		for(l=th->frame_top-1,n=0; l>=0; l--,n++)
+		{
+			AM_ThreadFrame_t *f = &th->frame[l];
+			fprintf(stdout, "\t<%d> %s line %d [%s]\n", n, f->func?f->func:NULL, f->line, f->file?f->file:NULL);
+		}
+	}
+	
+	pthread_mutex_unlock(&lock);
+	
+	return 0;
+}
+
diff --git a/test/am_ca_key_test/inject_record_t5d/am_tfile/Makefile b/test/am_ca_key_test/inject_record_t5d/am_tfile/Makefile
new file mode 100644
index 0000000..cc20a43
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_tfile/Makefile
@@ -0,0 +1,8 @@
+BASE=../..
+
+include $(BASE)/rule/def.mk
+
+O_TARGET=am_tfile
+am_tfile_SRCS=am_tfile.c
+
+include $(BASE)/rule/rule.mk
diff --git a/test/am_ca_key_test/inject_record_t5d/am_tfile/am_tfile.c b/test/am_ca_key_test/inject_record_t5d/am_tfile/am_tfile.c
new file mode 100644
index 0000000..3dc295d
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_tfile/am_tfile.c
@@ -0,0 +1,1374 @@
+
+#ifdef _FORTIFY_SOURCE
+#undef _FORTIFY_SOURCE
+#endif
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief file functions
+ *
+ ***************************************************************************/
+
+#ifndef ANDROID
+#define _LARGEFILE64_SOURCE
+#endif
+#define AM_DEBUG_LEVEL 5
+
+#include <unistd.h>
+//#include <sys/types.h>
+#ifdef SUPPORT_CAS
+#include <limits.h>
+#include <byteswap.h>
+#endif
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <am_types.h>
+#include <am_debug.h>
+#include <am_mem.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+//#include <dlfcn.h>
+#include "am_misc.h"
+#include "am_evt.h"
+#include "am_time.h"
+#include "am_tfile.h"
+#ifdef SUPPORT_CAS
+#include "am_av.h"
+#endif
+
+#include "list.h"
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+typedef struct {
+	struct list_head head;
+	int time;
+	loff_t start;
+	loff_t end;
+} tfragment_t;
+
+typedef struct {
+	struct list_head list;
+	int wrap;
+	int now;
+	int wstart;
+	int last;
+	AM_TFile_t file;
+} tfile_timer_t;
+
+#ifdef SUPPORT_CAS
+typedef struct
+{
+	struct list_head list;
+	uint64_t start;
+	uint64_t end;
+	uint16_t info_len;
+	uint8_t *info_data;
+} tfile_cas_t;
+
+static tfile_cas_t cas_ctx = {0};
+static cas_info_data[16] = {0};
+static CAS_RecInfo_t cas_rec_info = {
+.blk_size = 0,
+.len = 0,
+.data = cas_info_data
+};
+#define CAS_MAGIC_NUM 0xBEEFBEEF
+#define NODE_IS_REWIND(p) \
+	(p->end <= p->start ? 1 : 0)
+#endif
+/****************************************************************************
+ * Static functions
+ ***************************************************************************/
+
+static int timer_get_total(void *timer)
+{
+	if (!timer)
+		return 0;
+	tfile_timer_t *ptimer = (tfile_timer_t*)timer;
+	tfragment_t *pfirst = list_first_entry(&ptimer->list, tfragment_t, head);
+	tfragment_t *plast = list_entry(ptimer->list.prev, tfragment_t, head);
+
+	AM_DEBUG(3, "[tfile] total [%d, %d - %d]ms [%lld - %lld]B",
+		plast->time - pfirst->time, pfirst->time, plast->time,
+		pfirst->start, plast->start);
+
+	return plast->time - pfirst->time;
+}
+
+static int timer_try_add_fragment(void *timer, loff_t pre_end, loff_t offset, int force)
+{
+	tfile_timer_t *ptimer = (tfile_timer_t*)timer;
+	tfragment_t *plast = NULL;
+	tfragment_t *pnow;
+	int now;
+
+	AM_TIME_GetClock(&now);
+	ptimer->now = now - ptimer->wstart;
+
+	if (!force && (ptimer->now - ptimer->last  < 1000))//fragment size: 1s
+		return 0;
+
+	ptimer->last = ptimer->now;
+
+//	AM_EVT_Signal((long )ptimer->file, AM_TFILE_EVT_END_TIME_CHANGED, (void*)(long)ptimer->now);
+
+	if (!list_empty(&ptimer->list)) {
+		plast = list_entry(ptimer->list.prev, tfragment_t, head);
+	}
+
+	if (plast && (plast->start == offset)) {
+		/*write fail? fragment too large? should not get here!!*/
+		AM_DEBUG(0, "[tfile] FATAL ERROR");
+		return 0;
+	}
+
+	if (plast)
+		plast->end = pre_end;
+
+	pnow = malloc(sizeof(tfragment_t));
+	memset(pnow, 0, sizeof(tfragment_t));
+
+	pnow->time = ptimer->now;
+	pnow->start = offset;
+	pnow->end = 0;
+
+	list_add_tail(&pnow->head, &ptimer->list);
+
+	AM_DEBUG(3, "[tfile] add fragment %p[time:%d start:%lld] force[%d]",
+		pnow, pnow->time, pnow->start, force);
+
+	return 0;
+}
+
+static int timer_try_add_fragment_continuous(void *timer, loff_t offset, int force)
+{
+	return timer_try_add_fragment(timer, offset, offset, force);
+}
+
+//remove earliest fragment, return removed size and next fragment's start
+static loff_t timer_remove_earliest_fragment(void *timer, loff_t *next)
+{
+	tfile_timer_t *ptimer = (tfile_timer_t*)timer;
+	loff_t size = 0;
+
+	if (!list_empty(&ptimer->list))
+	{
+		tfragment_t *pfirst, *pnext;
+
+		pfirst = list_first_entry(&ptimer->list, tfragment_t, head);
+		list_del(&pfirst->head);
+		pnext = list_first_entry(&ptimer->list, tfragment_t, head);
+
+		if (next)
+			*next = pnext->start;
+
+		size = (pfirst->end >= pfirst->start) ? (pfirst->end - pfirst->start) : (ptimer->file->size - pfirst->start);
+
+		AM_DEBUG(3, "[tfile] del fragment %p[time:%d start:%lld end:%lld size:%lld]",
+			pfirst, pfirst->time, pfirst->start, pfirst->end, size);
+
+		free(pfirst);
+
+		ptimer->wrap = 1;
+//		AM_EVT_Signal((long)ptimer->file, AM_TFILE_EVT_START_TIME_CHANGED, (void *)(long)pnext->time);
+
+	}
+	return size;
+}
+
+static int aml_tfile_attach_timer(AM_TFile_t tfile)
+{
+	tfile_timer_t *timer = malloc(sizeof(tfile_timer_t));
+	tfragment_t *frag = malloc(sizeof(tfragment_t));
+	int err = 0;
+
+	if (!timer || !frag) {
+		AM_DEBUG(0, "[tfile] FATAL: no mem for tfile");
+		err = -1;
+		goto end;
+	}
+
+	memset(timer, 0, sizeof(tfile_timer_t));
+	INIT_LIST_HEAD(&timer->list);
+
+	memset(frag, 0, sizeof(tfragment_t));
+
+	pthread_mutex_lock(&tfile->lock);
+	if (!tfile->timer) {
+		AM_TIME_GetClock(&timer->wstart);
+		timer->now = timer->last = 0;
+
+		frag->time = 0;
+		frag->end = 0;
+		frag->start = tfile->write;
+		list_add_tail(&frag->head, &timer->list);
+
+		AM_DEBUG(3, "[tfile] add fragment %p[time:%d start:%lld]",
+				frag, frag->time, frag->start);
+
+		timer->file = tfile;
+		timer->wrap = 0;
+
+		tfile->timer = timer;
+	} else {
+		err = 1;
+	}
+	pthread_mutex_unlock(&tfile->lock);
+
+//	AM_EVT_Signal((long)tfile, AM_TFILE_EVT_START_TIME_CHANGED, (void *)(long)0);
+
+end:
+	if (err) {
+		if (timer)
+			free(timer);
+		if (frag)
+			free(frag);
+	}
+	return (err < 0) ? err : 0;
+}
+
+static int aml_tfile_detach_timer(AM_TFile_t tfile)
+{
+	tfile_timer_t *timer = NULL;
+	struct list_head *pos = NULL, *n = NULL;
+
+	if (!tfile->timer)
+		return 0;
+
+	pthread_mutex_lock(&tfile->lock);
+	timer = tfile->timer;
+	tfile->timer = NULL;
+	pthread_mutex_unlock(&tfile->lock);
+
+	list_for_each_safe(pos, n, &timer->list)
+	{
+		list_del(pos);
+		free(list_entry(pos, tfragment_t, head));
+	}
+	free(timer);
+	return 0;
+}
+
+static int aml_timeshift_data_write(int fd, uint8_t *buf, int size, int *err)
+{
+	int ret;
+	int left = size;
+	uint8_t *p = buf;
+
+	while (left > 0)
+	{
+		ret = write(fd, p, left);
+
+		if (err)
+			*err = errno;
+
+		if (ret == -1)
+		{
+			if (errno != EINTR)
+			{
+				AM_DEBUG(0, "[tfile] write data failed: %s", strerror(errno));
+				break;
+			}
+			ret = 0;
+		}
+
+		left -= ret;
+		p += ret;
+	}
+
+	return (size - left);
+}
+
+static AM_TFile_Sub_t *aml_timeshift_new_subfile(AM_TFile_t tfile)
+{
+	int flags;
+	struct stat st;
+	char fname[1024];
+	AM_Bool_t is_timeshift = tfile->is_timeshift;
+	AM_TFile_Sub_t *sub_file, *ret = NULL;
+
+	if (is_timeshift)
+	{
+		/* create new timeshifting sub files */
+		flags = O_WRONLY | O_CREAT | O_TRUNC;
+	}
+	else
+	{
+		/* gathering all pvr playback sub files */
+		flags = O_WRONLY;
+	}
+
+	sub_file = (AM_TFile_Sub_t *)malloc(sizeof(AM_TFile_Sub_t));
+	if (sub_file == NULL)
+	{
+		AM_DEBUG(0, "[tfile] Cannot write sub file , no memory!\n");
+		return ret;
+	}
+
+	sub_file->next = NULL;
+
+
+	if (tfile->last_sub_index == 0 && !is_timeshift)
+	{
+		/* To be compatible with the old version */
+		sub_file->findex = tfile->last_sub_index++;
+		snprintf(fname, sizeof(fname), "%s", tfile->name);
+	}
+	else
+	{
+		sub_file->findex = tfile->last_sub_index++;
+		snprintf(fname, sizeof(fname), "%s.%d", tfile->name, sub_file->findex);
+	}
+
+	if (!is_timeshift && stat(fname, &st) < 0)
+	{
+		AM_DEBUG(2, "[tfile] sub file '%s': %s", fname, strerror(errno));
+		sub_file->wfd = -1;
+		sub_file->rfd = -1;
+	}
+	else
+	{
+		AM_DEBUG(1, "openning %s\n", fname);
+		sub_file->wfd = open(fname, flags, 0666);
+		sub_file->rfd = open(fname, O_RDONLY, 0666);
+	}
+
+	if (sub_file->wfd < 0 || sub_file->rfd < 0)
+	{
+		AM_DEBUG(0, "Open file failed: %s", strerror(errno));
+		if (is_timeshift)
+		{
+			AM_DEBUG(0, "Cannot open new sub file: %s\n", strerror(errno));
+		}
+		else
+		{
+			/* To be compatible with the old version */
+			if (sub_file->findex == 0)
+			{
+				ret = aml_timeshift_new_subfile(tfile);
+			}
+			else
+			{
+				AM_DEBUG(2, "[tfile] sub files end at index %d", sub_file->findex-1);
+			}
+		}
+
+		if (sub_file->wfd >= 0)
+			close(sub_file->wfd);
+		if (sub_file->rfd >= 0)
+			close(sub_file->rfd);
+
+		free(sub_file);
+	}
+	else
+	{
+		ret = sub_file;
+	}
+
+	return ret;
+}
+
+static ssize_t aml_timeshift_subfile_read(AM_TFile_t tfile, uint8_t *buf, size_t size)
+{
+	ssize_t ret = 0;
+
+	if (tfile->sub_files == NULL)
+	{
+		AM_DEBUG(0, "[tfile] No sub files, cannot read\n");
+		return -1;
+	}
+
+	if (tfile->cur_rsub_file == NULL)
+	{
+		tfile->cur_rsub_file = tfile->sub_files;
+		AM_DEBUG(2, "[tfile] Reading from the start, file index %d", tfile->cur_rsub_file->findex);
+	}
+
+	ret = read(tfile->cur_rsub_file->rfd, buf, size);
+	if (ret == 0)
+	{
+		/* reach the end, automatically turn to next sub file */
+		if (tfile->cur_rsub_file->next != NULL)
+		{
+			tfile->cur_rsub_file = tfile->cur_rsub_file->next;
+			AM_DEBUG(1, "[tfile] Reading from file index %d ...", tfile->cur_rsub_file->findex);
+			lseek64(tfile->cur_rsub_file->rfd, 0, SEEK_SET);
+			ret = aml_timeshift_subfile_read(tfile, buf, size);
+		}
+	}
+
+	return ret;
+}
+
+static ssize_t aml_timeshift_subfile_write(AM_TFile_t tfile, uint8_t *buf, size_t size, int *err)
+{
+	ssize_t ret = 0;
+	loff_t fsize;
+
+	if (tfile->sub_files == NULL)
+	{
+		AM_DEBUG(0, "[tfile] No sub files, cannot write\n");
+		return -1;
+	}
+
+	if (tfile->cur_wsub_file == NULL)
+	{
+		tfile->cur_wsub_file = tfile->sub_files;
+		AM_DEBUG(1, "[tfile] Switching to file index %d for writing...\n",
+			tfile->cur_wsub_file->findex);
+	}
+
+	fsize = lseek64(tfile->cur_wsub_file->wfd, 0, SEEK_CUR);
+	if (fsize >= tfile->sub_file_size)
+	{
+		AM_Bool_t start_new = AM_FALSE;
+
+		if (tfile->cur_wsub_file->next != NULL)
+		{
+			tfile->cur_wsub_file = tfile->cur_wsub_file->next;
+			start_new = AM_TRUE;
+		}
+		else
+		{
+			AM_TFile_Sub_t *sub_file = aml_timeshift_new_subfile(tfile);
+			if (sub_file != NULL)
+			{
+				tfile->cur_wsub_file->next = sub_file;
+				tfile->cur_wsub_file = sub_file;
+				start_new = AM_TRUE;
+			}
+		}
+
+		if (start_new)
+		{
+			AM_DEBUG(1, "[tfile] Switching to file index %d for writing...\n",
+				tfile->cur_wsub_file->findex);
+			lseek64(tfile->cur_wsub_file->wfd, 0, SEEK_SET);
+			ret = aml_timeshift_subfile_write(tfile, buf, size, err);
+		}
+	}
+	else
+	{
+		ret = aml_timeshift_data_write(tfile->cur_wsub_file->wfd, buf, size, err);
+	}
+
+	return ret;
+}
+
+static int aml_timeshift_subfile_close(AM_TFile_t tfile)
+{
+	AM_TFile_Sub_t *sub_file, *next;
+	char fname[1024];
+
+	sub_file = tfile->sub_files;
+	while (sub_file != NULL)
+	{
+		next = sub_file->next;
+		if (sub_file->rfd >= 0)
+		{
+			close(sub_file->rfd);
+		}
+		if (sub_file->wfd >= 0)
+		{
+			close(sub_file->wfd);
+		}
+
+		if (tfile->delete_on_close)
+		{
+			if (sub_file->findex == 0 && !tfile->is_timeshift)
+				snprintf(fname, sizeof(fname), "%s", tfile->name);
+			else
+				snprintf(fname, sizeof(fname), "%s.%d", tfile->name, sub_file->findex);
+			AM_DEBUG(1, "[tfile] unlinking file: %s", fname);
+			unlink(fname);
+		}
+
+		free(sub_file);
+		sub_file = next;
+	}
+
+	return 0;
+}
+
+static int aml_timeshift_subfile_open(AM_TFile_t tfile)
+{
+	int index = 1, flags;
+	char fname[1024];
+	AM_TFile_Sub_t *sub_file, *prev_sub_file, *exist_sub_file;
+	AM_Bool_t is_timeshift = tfile->is_timeshift;
+	loff_t left = is_timeshift ? tfile->size : 1/*just keep the while going*/;
+
+	if (is_timeshift)
+	{
+		tfile->sub_files = aml_timeshift_new_subfile(tfile);
+		if (!tfile->sub_files)
+			return -1;
+	}
+	else
+	{
+		prev_sub_file = NULL;
+		do
+		{
+			sub_file = aml_timeshift_new_subfile(tfile);
+			if (sub_file != NULL)
+			{
+				off64_t size;
+
+				if (prev_sub_file == NULL)
+					tfile->sub_files = sub_file;
+				else
+					prev_sub_file->next = sub_file;
+				prev_sub_file = sub_file;
+
+				size = lseek64(sub_file->rfd, 0, SEEK_END);
+				tfile->sub_file_size = AM_MAX(tfile->sub_file_size, size);
+				tfile->size += size;
+				lseek64(sub_file->rfd, 0, SEEK_SET);
+			}
+		} while (sub_file != NULL);
+	}
+
+	return 0;
+}
+
+static loff_t aml_timeshift_subfile_seek(AM_TFile_t tfile, loff_t offset, AM_Bool_t read)
+{
+	int sub_index = offset/tfile->sub_file_size; /* start from 0 */
+	loff_t sub_offset = offset%tfile->sub_file_size;
+	AM_TFile_Sub_t *sub_file = tfile->sub_files;
+
+	while (sub_file != NULL)
+	{
+		if (sub_file->findex == sub_index)
+			break;
+		sub_file = sub_file->next;
+	}
+
+	if (sub_file != NULL)
+	{
+		AM_DEBUG(1, "[tfile] %c Seek to sub file %d at %lld\n", read?'r':'w', sub_index, sub_offset);
+		if (read)
+		{
+			tfile->cur_rsub_file = sub_file;
+			lseek64(sub_file->rfd, sub_offset, SEEK_SET);
+		}
+		else
+		{
+			tfile->cur_wsub_file = sub_file;
+			lseek64(sub_file->wfd, sub_offset, SEEK_SET);
+		}
+		return offset;
+	}
+
+	return (loff_t)-1;
+}
+
+//duration & size valid in loop mode only now, cause tfile used by timeshifting only, tfile may be used for all recording case in the future
+AM_ErrorCode_t AM_TFile_Open(AM_TFile_t *tfile, const char *file_name, AM_Bool_t loop, int max_duration, loff_t max_size)
+{
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	const loff_t SUB_FILE_SIZE = 1024*1024*1024ll;
+
+	AM_TFileData_t *pfile = malloc(sizeof(AM_TFileData_t));
+	memset(pfile, 0, sizeof(AM_TFileData_t));
+
+	pfile->name = strdup(file_name);
+	pfile->sub_file_size = SUB_FILE_SIZE;
+	pfile->is_timeshift = (strstr(pfile->name, "TimeShifting") != NULL);
+	pfile->loop = loop;
+	pfile->duration = max_duration;
+	if (pfile->is_timeshift)
+		pfile->delete_on_close = 1;
+
+	if (pfile->loop)
+	{
+		pfile->size = (max_size <= 0)? SUB_FILE_SIZE : max_size;
+
+		if (aml_timeshift_subfile_open(pfile) < 0)
+			return AM_FAILURE;
+
+		pfile->avail = 0;
+		pfile->total = 0;
+	}
+	else
+	{
+		if (aml_timeshift_subfile_open(pfile) < 0)
+			return AM_FAILURE;
+
+		pfile->avail = pfile->size;
+		pfile->total = pfile->size;
+		AM_DEBUG(1, "[tfile] total subfiles size %lld", pfile->size);
+	}
+
+	pfile->start = 0;
+	pfile->read = pfile->write = 0;
+
+	pthread_mutex_init(&pfile->lock, NULL);
+	pthread_cond_init(&pfile->cond, NULL);
+
+	pfile->opened = 1;
+
+	*tfile = pfile;
+	return AM_SUCCESS;
+}
+
+AM_ErrorCode_t AM_TFile_Close(AM_TFile_t tfile)
+{
+	if (! tfile->opened)
+	{
+		AM_DEBUG(0, "[tfile] has not opened");
+		return AM_FAILURE;
+	}
+
+	tfile->opened = 0;
+
+	pthread_mutex_lock(&tfile->lock);
+	aml_timeshift_subfile_close(tfile);
+
+	/*remove timeshift file*/
+	if (tfile->name != NULL)
+	{
+		free(tfile->name);
+		tfile->name = NULL;
+	}
+	pthread_mutex_unlock(&tfile->lock);
+
+	aml_tfile_detach_timer(tfile);
+
+	pthread_mutex_destroy(&tfile->lock);
+
+	return AM_SUCCESS;
+}
+
+#ifdef SUPPORT_CAS
+AM_ErrorCode_t AM_TFile_CasOpen(char *path)
+{
+	int fd, ret;
+	uint32_t blk_size;
+	uint16_t info_len;
+	uint64_t pos;
+	tfile_cas_t *pcas = NULL;
+
+	AM_DEBUG(3, "%s in\n", __func__);
+	if (!path) {
+		INIT_LIST_HEAD(&cas_ctx.list);
+		AM_DEBUG(0, "[tfile] cas dat path null");
+		return AM_SUCCESS;
+	}
+	fd = open(path, O_RDONLY);
+	if (fd < 0) {
+		AM_DEBUG(0, "[tfile] open cas file failed");
+		return AM_FAILURE;
+	}
+
+	if ((ret = read(fd, &blk_size, 4)) != 4) {
+		AM_DEBUG(0, "[tfile] read cas block size failed");
+		goto fail;
+	}
+
+	if ((ret = read(fd, &info_len, 2)) != 2) {
+		AM_DEBUG(0, "[tfile] read cas header info len failed");
+		goto fail;
+	}
+
+	cas_rec_info.blk_size = bswap_32(blk_size);
+	cas_rec_info.len =  bswap_16(info_len);
+	if ((ret = read(fd, cas_rec_info.data, cas_rec_info.len)) != cas_rec_info.len) {
+		AM_DEBUG(0, "[tfile] read cas header data failed");
+		goto fail;
+	}
+
+	INIT_LIST_HEAD(&cas_ctx.list);
+	AM_DEBUG(0, "[tfile] cas block size:%d, header info len:%d, seek:%d\n",
+			bswap_32(blk_size), bswap_16(info_len), ret);
+	do {
+		if ((ret = read(fd, &pos, 8)) != 8) {
+			AM_DEBUG(0, "[tfile] read cas pos failed, ret:%d. maybe end of file", ret);
+			close(fd);
+			return AM_SUCCESS;
+		}
+		AM_DEBUG(0, "[tfile] read cas pos:%lld", bswap_64(pos));
+		if ((ret = read(fd, &info_len, 2)) != 2) {
+			AM_DEBUG(0, "[tfile] read cas info len failed");
+			goto fail;
+		}
+
+		info_len = bswap_16(info_len);
+		AM_DEBUG(0, "[tfile] read cas store info len:%d", info_len);
+		if (pos == ULLONG_MAX) {
+			break;
+		}
+		pcas = malloc(sizeof(tfile_cas_t));
+		pcas->info_data = malloc(info_len);
+		pcas->info_len = info_len;
+		pcas->start = bswap_64(pos);
+		if ((ret = read(fd, pcas->info_data, pcas->info_len)) != pcas->info_len) {
+			AM_DEBUG(0, "[tfile] read cas info len failed");
+			goto fail;
+		}
+		AM_DEBUG(0, "[tfile] read cas store info");
+		list_add_tail(&pcas->list, &cas_ctx.list);
+		AM_DEBUG(0, "[tfile] add cas list");
+	} while (1);
+
+	close(fd);
+	return AM_SUCCESS;
+
+fail:
+	if (fd > 0) {
+		close(fd);
+	}
+	return AM_FAILURE;
+}
+AM_ErrorCode_t AM_TFile_CasClose()
+{
+	struct list_head *pos, *q;
+	tfile_cas_t *pcas;
+
+	AM_DEBUG(3, "%s in\n", __func__);
+	list_for_each_safe(pos, q, &cas_ctx.list) {
+		pcas = list_entry(pos, tfile_cas_t, list);
+		list_del(pos);
+		free(pcas->info_data);
+		free(pcas);
+	}
+	return AM_SUCCESS;
+}
+
+AM_ErrorCode_t AM_TFile_CasUpdateStoreInfo(uint32_t len, uint64_t fsize)
+{
+	struct list_head *pos, *q;
+	tfile_cas_t *pfirst, *plast;
+
+	plast = list_entry(cas_ctx.list.prev, tfile_cas_t, list);
+	pfirst = list_first_entry(&cas_ctx.list, tfile_cas_t, list);
+	if (plast->end == CAS_MAGIC_NUM) {
+		//the last node end pos no value
+		plast->end = (plast->start + len) % fsize;
+	} else {
+		//the last node end pos already had value
+		if (plast == pfirst && NODE_IS_REWIND(plast)) {
+			//only 1 node and rewind
+			plast->start = (plast->start + len) % fsize;
+		}
+		plast->end = (plast->end + len) % fsize;
+	}
+
+	AM_DEBUG(2, "%s, first:%lld, %lld, last:%lld-%lld, arg len:%d, fsize:%lld\n", __func__,
+			pfirst->start, pfirst->end, plast->start, plast->end, len, fsize);
+	if (plast == pfirst) {
+		AM_DEBUG(1, "%s, only 1 node\n", __func__);
+		return 0;
+	}
+
+	if((plast->start <= pfirst->start && plast->end > pfirst->start) ||
+			(NODE_IS_REWIND(plast) && plast->end > pfirst->start)) {
+		AM_DEBUG(0, "plast and pfirst has coincide area, pfirst:%lld, plast:%lld\n",
+				pfirst->start, plast->end);
+		pfirst->start = plast->end;
+		if (pfirst->start == pfirst->end) {
+			AM_DEBUG(0, "last node overwrite first node, delete first node\n");
+			list_del(&pfirst->list);
+		}
+	}
+
+	return 0;
+}
+
+AM_ErrorCode_t AM_TFile_CasSetStoreInfo(CAS_StoreInfo_t info)
+{
+	tfile_cas_t *pcas, *plast;
+
+	pcas = malloc(sizeof(tfile_cas_t));
+	pcas->info_data = malloc(info.len);
+	pcas->info_len = info.len;
+	pcas->start = info.pos;
+	pcas->end = CAS_MAGIC_NUM;
+	memcpy(pcas->info_data, info.data, info.len);
+	AM_DEBUG(0, "%s set cas store info, len:%d, pos:%lld", __func__, info.len, info.pos);
+	list_add_tail(&pcas->list, &cas_ctx.list);
+
+	return AM_SUCCESS;
+}
+
+AM_ErrorCode_t AM_TFile_CasGetStoreInfo(uint64_t stream_pos, CAS_StoreInfo_t *info)
+{
+	struct list_head *pos, *q;
+	tfile_cas_t *pcas, *pstart;
+
+	list_for_each_safe(pos, q, &cas_ctx.list) {
+		AM_DEBUG(0, "Get store info loop");
+		pcas = list_entry(pos, tfile_cas_t, list);
+		AM_DEBUG(0, "Get store info %lld->%lld", pcas->start, pcas->end);
+		if (NODE_IS_REWIND(pcas)) {
+			AM_DEBUG(2, "%s, >> %d, pos:%lld, start-end:%lld-%lld\n",
+					__func__, __LINE__, stream_pos, pcas->start, pcas->end);
+			if (stream_pos > pcas->start || stream_pos <= pcas->end) {
+				//seems like can NOT change info->pos value, otherwise vmx report DVR channel already in used 
+				info->pos = 0;//pcas->start;
+				info->len = pcas->info_len;
+				memcpy(info->data, pcas->info_data, pcas->info_len);
+				AM_DEBUG(1, "%s found rewind store info, pos:%lld-%lld, stream_pos:%lld, info_len:%d\n", __func__,
+						pcas->start, pcas->end, stream_pos, pcas->info_len);
+				return 0;
+			}
+		} else {
+			AM_DEBUG(2, "%s, >> %d, pos:%lld, start-end:%lld-%lld\n",
+					__func__, __LINE__, stream_pos, pcas->start, pcas->end);
+			if (stream_pos > pcas->start && stream_pos <= pcas->end) {
+				//seems like can NOT change info->pos value, otherwise vmx report DVR channel already in used 
+				info->pos = 0;//pcas->start;
+				info->len = pcas->info_len;
+				memcpy(info->data, pcas->info_data, pcas->info_len);
+				AM_DEBUG(1, "%s found store info, pos:%lld-%lld, stream_pos:%lld\n", __func__,
+						pcas->start, pcas->end, stream_pos);
+				return 0;
+			}
+		}
+	}
+
+	AM_DEBUG(0, "Get store info failed");
+	return AM_FAILURE;
+}
+
+AM_ErrorCode_t AM_TFile_CasGetRecInfo(CAS_RecInfo_t *info)
+{
+	if (info) {
+		info->blk_size = cas_rec_info.blk_size;
+		info->len = cas_rec_info.len;
+		if (info->data)
+			memcpy(info->data, cas_rec_info.data, info->len);
+		return AM_SUCCESS;
+	}
+	return AM_FAILURE;
+}
+AM_ErrorCode_t AM_TFile_CasDump()
+{
+	struct list_head *pos, *q;
+	tfile_cas_t *pcas;
+	list_for_each_safe(pos, q, &cas_ctx.list) {
+		pcas = list_entry(pos, tfile_cas_t, list);
+		AM_DEBUG(0, "%s, cas info len:%d, pos:%lld", __func__, pcas->info_len, pcas->start);
+	}
+
+	return AM_SUCCESS;
+}
+#endif
+
+ssize_t AM_TFile_Read(AM_TFile_t tfile, uint8_t *buf, size_t size, int timeout)
+{
+	ssize_t ret = -1;
+	size_t todo, split;
+	struct timespec rt;
+
+	if (! tfile->opened)
+	{
+		AM_DEBUG(0, "[tfile] has not opened");
+		return AM_FAILURE;
+	}
+
+	if (! tfile->loop)
+	{
+		ret = aml_timeshift_subfile_read(tfile, buf, size);
+		if (ret > 0)
+		{
+			tfile->avail -= ret;
+			tfile->read += ret;
+			if (tfile->avail < 0)
+				tfile->avail = 0;
+		}
+		return ret;
+	}
+
+	pthread_mutex_lock(&tfile->lock);
+	if (tfile->avail <= 0)
+	{
+		AM_TIME_GetTimeSpecTimeout(timeout, &rt);
+		pthread_cond_timedwait(&tfile->cond, &tfile->lock, &rt);
+	}
+	if (tfile->avail <= 0)
+	{
+		tfile->avail = 0;
+		goto read_done;
+	}
+	todo = (size < tfile->avail) ? size : tfile->avail;
+	size = todo;
+	split = ((tfile->read+size) > tfile->size) ? (tfile->size - tfile->read) : 0;
+	if (split > 0)
+	{
+		/*read -> end*/
+		ret = aml_timeshift_subfile_read(tfile, buf, split);
+		if (ret < 0)
+			goto read_done;
+		if (ret != (ssize_t)split)
+		{
+			tfile->read += ret;
+			goto read_done;
+		}
+
+		tfile->read = 0;
+		todo -= ret;
+		buf += ret;
+	}
+	/*rewind the file*/
+	if (split > 0)
+		aml_timeshift_subfile_seek(tfile, 0, AM_TRUE);
+	ret = aml_timeshift_subfile_read(tfile, buf, todo);
+	if (ret > 0)
+	{
+		todo -= ret;
+		tfile->read += ret;
+		tfile->read %= tfile->size;
+		ret = size - todo;
+	}
+	if (tfile->read == 0) {
+		AM_DEBUG(0, "[tfile] reed is set 0 need to seek 0");
+		aml_timeshift_subfile_seek(tfile, 0, AM_TRUE);
+	}
+read_done:
+	if (ret > 0)
+	{
+		tfile->avail -= ret;
+		if (tfile->avail < 0)
+			tfile->avail = 0;
+	}
+	pthread_mutex_unlock(&tfile->lock);
+	return ret;
+}
+
+ssize_t AM_TFile_Write(AM_TFile_t tfile, uint8_t *buf, size_t size, int *sys_err)
+{
+	ssize_t ret = 0, ret2 = 0;
+	size_t len1 = 0, len2 = 0;
+	loff_t fsize, wpos;
+	int now;
+	size_t size_act = 0;
+	int wrap = 0;
+	int write_fail = 0;
+
+	if (! tfile->opened)
+	{
+		AM_DEBUG(0, "[tfile] has not opened");
+		return AM_FAILURE;
+	}
+
+	if (! tfile->loop)
+	{
+		/* Normal write */
+		ret = aml_timeshift_subfile_write(tfile, buf, size, sys_err);
+		if (ret > 0)
+		{
+			pthread_mutex_lock(&tfile->lock);
+			tfile->size += ret;
+			tfile->write += ret;
+			tfile->total += ret;
+			tfile->avail += ret;
+			pthread_mutex_unlock(&tfile->lock);
+		}
+
+		if (tfile->timer)
+			timer_try_add_fragment_continuous(tfile->timer, tfile->write, 0);
+
+		goto write_done;
+	}
+
+	pthread_mutex_lock(&tfile->lock);
+	fsize = tfile->size;
+	wpos = tfile->write;
+	pthread_mutex_unlock(&tfile->lock);
+
+	/*is the size exceed the file size?*/
+	if (size > fsize)
+	{
+		size = fsize;
+		AM_DEBUG(0, "[tfile] data lost, write size(%zu) > file size(%lld)?", size, fsize);
+	}
+
+	len1 = size;
+	if ((wpos+len1) >= fsize)
+	{
+		len1 = (fsize - wpos);
+		len2 = size - len1;
+		wrap = 1;
+		AM_DEBUG(2, "[tfile] wrap here, len[%d]=len1[%d]+len2[%d]", size, len1, len2);
+	}
+	if (len1 > 0)
+	{
+		/*write -> end*/
+		ret = aml_timeshift_subfile_write(tfile, buf, len1, sys_err);
+		if (ret != (ssize_t)len1)
+			write_fail = 1;
+
+		if (tfile->timer)
+			timer_try_add_fragment(tfile->timer,
+					tfile->write + ret,
+					(wrap && !write_fail)? 0 : tfile->write+ret,
+					(wrap || (write_fail && ret))? 1 : 0);
+
+		if (write_fail) {
+			AM_DEBUG(0, "[tfile] data lost, eof write: try:%d act:%d", len1, ret);
+			goto adjust_pos;
+		}
+	}
+
+	if (len2 > 0)
+	{
+		/*rewind the file*/
+		aml_timeshift_subfile_seek(tfile, 0, AM_FALSE);
+
+		ret2 = aml_timeshift_subfile_write(tfile, buf+len1, len2, sys_err);
+		if (ret2 != (ssize_t)len2)
+			write_fail = 1;
+
+		if (tfile->timer)
+			timer_try_add_fragment_continuous(tfile->timer, ret2, 1);
+
+		if (write_fail) {
+			AM_DEBUG(0, "[tfile] data lost, sof write: try:%d act:%d", len2, ret2);
+			goto adjust_pos;
+		}
+	}
+
+adjust_pos:
+
+	size_act = ret + ret2;
+
+	if (size_act > 0)
+	{
+		pthread_mutex_lock(&tfile->lock);
+
+		int debug = 0;
+		/*now, ret bytes actually written*/
+		off_t rleft = tfile->size - tfile->avail;
+		off_t sleft = tfile->size - tfile->total;
+
+		tfile->write = (tfile->write + size_act) % tfile->size;
+		if (tfile->write == 0) {
+			/*rewind the file*/
+			AM_DEBUG(0, "[tfile] write == 0, need seek write(0)read(%lld)", tfile->read);
+			aml_timeshift_subfile_seek(tfile, 0, AM_FALSE);
+		}
+		//check the start pointer
+		if (size_act > sleft) {
+			if (tfile->timer) {
+				loff_t start;
+				loff_t remove = 0;
+				do {
+					remove += timer_remove_earliest_fragment(tfile->timer, &start);
+					} while(remove < size_act);
+				tfile->start = start;//tfile->write;
+				tfile->total -= remove;
+				//tfile->avail -= remove;
+				AM_DEBUG(3, "[tfile] size:%zu w >> s, s:%lld, t:%lld", size_act, tfile->start, tfile->total);
+				debug = 1;
+			} else {
+				tfile->start = tfile->write;
+				tfile->total -= size_act;
+			}
+		}
+
+		//check the read pointer
+		if (size_act > rleft) {
+			tfile->read = tfile->start;
+			tfile->avail -= size_act - rleft;
+			//AM_DEBUG(3, "ttt size:%zu w >> r, r:%lld, a:%lld",
+			//    size_act, tfile->read, tfile->avail);
+			//debug = 1;
+		}
+
+		if (tfile->avail < tfile->size)
+		{
+			tfile->avail += size_act;
+			if (tfile->avail > tfile->size)
+				tfile->avail = tfile->size;
+			pthread_cond_signal(&tfile->cond);
+		}
+		if (tfile->total < tfile->size)
+		{
+			tfile->total += size_act;
+			if (tfile->total > tfile->size)
+				tfile->total = tfile->size;
+		}
+
+		if (tfile->avail > tfile->total) {
+			tfile->read = tfile->start;
+			tfile->avail = tfile->total;
+		}
+
+		if (debug) {
+			AM_DEBUG(3, "[tfile] size:%zu now -> s:%lld, r:%lld, w:%lld, t:%lld, a:%lld",
+				size_act,
+				tfile->start, tfile->read, tfile->write, tfile->total, tfile->avail);
+
+			if (tfile->timer)
+				timer_get_total(tfile->timer);
+		}
+		pthread_mutex_unlock(&tfile->lock);
+	}
+
+write_done:
+
+#if 1
+	//calc rate and notify rate ready
+	if (ret > 0 && !tfile->rate)
+	{
+		AM_TIME_GetClock(&now);
+		if (! tfile->wlast) {
+			tfile->wtotal = 0;
+			tfile->wlast = now;
+		} else {
+			tfile->wtotal += size;
+			if ((now - tfile->wlast) >= 3000) {
+				/*Calcaulate the rate*/
+				tfile->rate = (tfile->wtotal*1000)/(now - tfile->wlast);
+				AM_DEBUG(1, "[tfile] got rate:%dBps", tfile->rate);
+				if (tfile->rate) {
+					if (tfile->loop) {
+						if (tfile->duration >= 0) {
+							loff_t size = (loff_t)tfile->rate * (loff_t)tfile->duration;
+							if (size < tfile->size) {
+								tfile->size = size;
+								AM_DEBUG(1, "[tfile] file size -> %lld", tfile->size);
+//								AM_EVT_Signal((long)tfile, AM_TFILE_EVT_SIZE_CHANGED, (void*)(long)tfile->size);
+							}
+						} else {
+							int duration = tfile->size / tfile->rate;
+							tfile->duration = duration;
+							AM_DEBUG(1, "[tfile] file duration -> %ds", tfile->duration);
+//							AM_EVT_Signal((long)tfile, AM_TFILE_EVT_DURATION_CHANGED, (void*)(long)tfile->duration);
+						}
+					}
+//					AM_EVT_Signal((long)tfile, AM_TFILE_EVT_RATE_CHANGED, (void*)(long)tfile->rate);
+				} else {
+					tfile->wlast = 0;
+				}
+			}
+		}
+	}
+#endif
+	return ret + ret2;
+}
+
+/**\brief seek到指定的偏移,如越界则返å›?*/
+int AM_TFile_Seek(AM_TFile_t tfile, loff_t offset)
+{
+	int ret = 1;
+	if (! tfile->opened)
+	{
+		AM_DEBUG(0, "[tfile] has not opened");
+		return AM_FAILURE;
+	}
+
+	pthread_mutex_lock(&tfile->lock);
+	if (tfile->size <= 0)
+	{
+		pthread_mutex_unlock(&tfile->lock);
+		return ret;
+	}
+	if (offset > tfile->total)
+		offset = tfile->total - 1;
+	else if (offset < 0)
+		offset = 0;
+	else
+		ret = 0;
+
+	tfile->read = (tfile->start + offset)%tfile->size;
+	tfile->avail = tfile->total - offset;
+	if (tfile->avail > 0)
+		pthread_cond_signal(&tfile->cond);
+
+	aml_timeshift_subfile_seek(tfile, tfile->read, AM_TRUE);
+
+	AM_DEBUG(3, "[tfile] Seek: start %lld, read %lld, write %lld, avail %lld, total %lld",
+				tfile->start, tfile->read, tfile->write, tfile->avail, tfile->total);
+	pthread_mutex_unlock(&tfile->lock);
+	return ret;
+}
+
+loff_t AM_TFile_Tell(AM_TFile_t tfile)
+{
+	loff_t ret = 0;
+	if (! tfile->opened)
+	{
+		AM_DEBUG(0, "[tfile] has not opened");
+		return AM_FAILURE;
+	}
+
+	pthread_mutex_lock(&tfile->lock);
+	ret = tfile->read;
+	pthread_mutex_unlock(&tfile->lock);
+	return ret;
+}
+
+loff_t AM_TFile_GetAvailable(AM_TFile_t tfile)
+{
+	loff_t ret = 0;
+	if (! tfile->opened)
+	{
+		AM_DEBUG(0, "[tfile] has not opened");
+		return AM_FAILURE;
+	}
+
+	pthread_mutex_lock(&tfile->lock);
+	ret = tfile->avail;
+	pthread_mutex_unlock(&tfile->lock);
+	return ret;
+}
+
+int AM_TFile_TimeStart(AM_TFile_t tfile)
+{
+	if (! tfile->opened)
+	{
+		AM_DEBUG(0, "[tfile] has not opened");
+		return AM_FAILURE;
+	}
+
+	return aml_tfile_attach_timer(tfile);
+}
+
+//one node for guard time //need more research, fatal exists
+//#define get_list_start(_ptimer_) ((_ptimer_)->wrap? (_ptimer_)->list.next : &(_ptimer_)->list)
+#define get_list_start(_ptimer_)  (&(_ptimer_)->list)
+
+
+int AM_TFile_TimeSeek(AM_TFile_t tfile, int offset_ms/*offset from time start*/)
+{
+	int ret = -1;
+	if (! tfile->opened)
+	{
+		AM_DEBUG(0, "[tfile] has not opened");
+		return -1;
+	}
+	pthread_mutex_lock(&tfile->lock);
+	if (tfile->timer) {
+		tfile_timer_t *timer = (tfile_timer_t*)tfile->timer;
+		tfragment_t *pstart = list_first_entry(get_list_start(timer), tfragment_t, head);
+		loff_t from = pstart->start;
+		tfragment_t *p;
+		list_for_each_entry(p, get_list_start(timer), head)
+		{
+			if (p->time > offset_ms)
+				break;
+			from = p->start;
+		}
+		tfile->read = from;
+
+		aml_timeshift_subfile_seek(tfile, tfile->read, AM_TRUE);
+        tfile->avail = (tfile->write >= from) ? tfile->write - from : (tfile->size - from) + tfile->write;
+		//tfile->avail = (tfile->write >= pstart->start) ? tfile->write - pstart->start : (tfile->size - pstart->start) + tfile->write;
+		if (tfile->avail > 0)
+			pthread_cond_signal(&tfile->cond);
+
+		AM_DEBUG(3, "[tfile] >>timeseek: pstart: %p[time:%d offset:%lld - %lld]", pstart, pstart->time, pstart->start, pstart->end);
+		AM_DEBUG(3, "[tfile] >>timeseek: got block: next%p[time:%d offset:%lld - %lld]", p, p->time, p->start, p->end);
+		AM_DEBUG(3, "[tfile] >>timeseek: start %lld, read %lld, write %lld, avail %lld, total %lld",
+				tfile->start, tfile->read, tfile->write, tfile->avail, tfile->total);
+		ret = 0;
+	}
+	pthread_mutex_unlock(&tfile->lock);
+	return ret;
+}
+
+int AM_TFile_TimeGetReadNow(AM_TFile_t tfile)
+{
+	int now = 0;
+	if (! tfile->opened)
+	{
+		AM_DEBUG(0, "[tfile] has not opened");
+		return -1;
+	}
+
+	pthread_mutex_lock(&tfile->lock);
+	if (tfile->timer) {
+		loff_t r = tfile->read;
+		tfile_timer_t *timer = (tfile_timer_t*)tfile->timer;
+		tfragment_t *pstart = list_first_entry(get_list_start(timer), tfragment_t, head);
+		tfragment_t *pend = list_entry(timer->list.prev, tfragment_t, head);
+		if (r > pstart->start) {
+			/*
+				| s--i--e |
+				or
+				|       s---i--|
+				|--e           |
+			*/
+			now = pstart->time;
+			tfragment_t *p;
+			list_for_each_entry(p, get_list_start(timer), head)
+			{
+				if (p->start > r)
+					break;
+				now = p->time;
+			}
+		} else if (r < pstart->start) {
+			/*
+				|           s---|
+				|--i-e          |
+			*/
+			now = pend->time;
+			struct list_head *pos;
+			list_for_each_prev(pos, &timer->list)
+			{
+				tfragment_t *p = list_entry(pos, tfragment_t, head);
+				if (p->start <= r) {
+					now = p->time;
+					break;
+				}
+			}
+		} else {
+			now = pstart->time;
+		}
+		AM_DEBUG(3, "[tfile] >>read:\ttime[%d]\toffset[%lld]", now, tfile->read);
+	}
+	pthread_mutex_unlock(&tfile->lock);
+	return now;
+}
+
+int AM_TFile_TimeGetStart(AM_TFile_t tfile)
+{
+	int time = 0;
+	if (!tfile->opened)
+	{
+		AM_DEBUG(0, "[tfile] has not opened");
+		return -1;
+	}
+
+	pthread_mutex_lock(&tfile->lock);
+	if (tfile->timer) {
+		tfile_timer_t *timer = (tfile_timer_t*)tfile->timer;
+		tfragment_t *pstart = list_first_entry(get_list_start(timer), tfragment_t, head);
+		time = pstart->time;
+		AM_DEBUG(3, "[tfile] >>start:\ttime[%d]\toffset[%lld]", pstart->time, pstart->start);
+	}
+	pthread_mutex_unlock(&tfile->lock);
+	return time;
+}
+
+int AM_TFile_TimeGetEnd(AM_TFile_t tfile)
+{
+	int time = 0;
+	if (!tfile->opened)
+	{
+		AM_DEBUG(0, "[tfile] has not opened");
+		return -1;
+	}
+
+	pthread_mutex_lock(&tfile->lock);
+	if (tfile->timer) {
+		tfile_timer_t *timer = (tfile_timer_t*)tfile->timer;
+		tfragment_t *pend = list_entry(timer->list.prev, tfragment_t, head);
+		time = pend->time;
+		AM_DEBUG(3, "[tfile] >>end:\ttime[%d]\toffset[%lld]", pend->time, pend->start);
+	}
+	pthread_mutex_unlock(&tfile->lock);
+	return time;
+}
+
diff --git a/test/am_ca_key_test/inject_record_t5d/am_tfile/list.h b/test/am_ca_key_test/inject_record_t5d/am_tfile/list.h
new file mode 100644
index 0000000..80dab91
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_tfile/list.h
@@ -0,0 +1,734 @@
+/*
+* Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+*
+* This source code is subject to the terms and conditions defined in the
+* file 'LICENSE' which is part of this source code package. *
+* Description:
+*/
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#ifndef container_of
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr:	the pointer to the member.
+ * @type:	the type of the container struct this is embedded in.
+ * @member:	the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({			\
+	const typeof(((type *)0)->member) * __mptr = (ptr);	\
+	(type *)((char *)__mptr - offsetof(type, member)); })
+#endif
+
+#define LIST_POISON1  ((void *) 0x00100100)
+#define LIST_POISON2  ((void *) 0x00200200)
+
+#define prefetch(x) (x)
+
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+	struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+	struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+	list->next = list;
+	list->prev = list;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+#ifndef CONFIG_DEBUG_LIST
+static inline void __list_add(struct list_head *new,
+			      struct list_head *prev,
+			      struct list_head *next)
+{
+	next->prev = new;
+	new->next = next;
+	new->prev = prev;
+	prev->next = new;
+}
+#else
+extern void __list_add(struct list_head *new,
+			      struct list_head *prev,
+			      struct list_head *next);
+#endif
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head, head->next);
+}
+
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+	next->prev = prev;
+	prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty() on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+#ifndef CONFIG_DEBUG_LIST
+static inline void list_del(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+	entry->next = LIST_POISON1;
+	entry->prev = LIST_POISON2;
+}
+#else
+extern void list_del(struct list_head *entry);
+#endif
+
+/**
+ * list_replace - replace old entry by new one
+ * @old : the element to be replaced
+ * @new : the new element to insert
+ *
+ * If @old was empty, it will be overwritten.
+ */
+static inline void list_replace(struct list_head *old,
+				struct list_head *new)
+{
+	new->next = old->next;
+	new->next->prev = new;
+	new->prev = old->prev;
+	new->prev->next = new;
+}
+
+static inline void list_replace_init(struct list_head *old,
+					struct list_head *new)
+{
+	list_replace(old, new);
+	INIT_LIST_HEAD(old);
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+	INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+	__list_del(list->prev, list->next);
+	list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+				  struct list_head *head)
+{
+	__list_del(list->prev, list->next);
+	list_add_tail(list, head);
+}
+
+/**
+ * list_is_last - tests whether @list is the last entry in list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_last(const struct list_head *list,
+				const struct list_head *head)
+{
+	return list->next == head;
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+	return head->next == head;
+}
+
+/**
+ * list_empty_careful - tests whether a list is empty and not being modified
+ * @head: the list to test
+ *
+ * Description:
+ * tests whether a list is empty _and_ checks that no other CPU might be
+ * in the process of modifying either member (next or prev)
+ *
+ * NOTE: using list_empty_careful() without synchronization
+ * can only be safe if the only activity that can happen
+ * to the list entry is list_del_init(). Eg. it cannot be used
+ * if another CPU could re-list_add() it.
+ */
+static inline int list_empty_careful(const struct list_head *head)
+{
+	struct list_head *next = head->next;
+	return (next == head) && (next == head->prev);
+}
+
+/**
+ * list_rotate_left - rotate the list to the left
+ * @head: the head of the list
+ */
+static inline void list_rotate_left(struct list_head *head)
+{
+	struct list_head *first;
+
+	if (!list_empty(head)) {
+		first = head->next;
+		list_move_tail(first, head);
+	}
+}
+
+/**
+ * list_is_singular - tests whether a list has just one entry.
+ * @head: the list to test.
+ */
+static inline int list_is_singular(const struct list_head *head)
+{
+	return !list_empty(head) && (head->next == head->prev);
+}
+
+static inline void __list_cut_position(struct list_head *list,
+		struct list_head *head, struct list_head *entry)
+{
+	struct list_head *new_first = entry->next;
+	list->next = head->next;
+	list->next->prev = list;
+	list->prev = entry;
+	entry->next = list;
+	head->next = new_first;
+	new_first->prev = head;
+}
+
+/**
+ * list_cut_position - cut a list into two
+ * @list: a new list to add all removed entries
+ * @head: a list with entries
+ * @entry: an entry within head, could be the head itself
+ *	and if so we won't cut the list
+ *
+ * This helper moves the initial part of @head, up to and
+ * including @entry, from @head to @list. You should
+ * pass on @entry an element you know is on @head. @list
+ * should be an empty list or a list you do not care about
+ * losing its data.
+ *
+ */
+static inline void list_cut_position(struct list_head *list,
+		struct list_head *head, struct list_head *entry)
+{
+	if (list_empty(head))
+		return;
+	if (list_is_singular(head) &&
+		(head->next != entry && head != entry))
+		return;
+	if (entry == head)
+		INIT_LIST_HEAD(list);
+	else
+		__list_cut_position(list, head, entry);
+}
+
+static inline void __list_splice(const struct list_head *list,
+				 struct list_head *prev,
+				 struct list_head *next)
+{
+	struct list_head *first = list->next;
+	struct list_head *last = list->prev;
+
+	first->prev = prev;
+	prev->next = first;
+
+	last->next = next;
+	next->prev = last;
+}
+
+/**
+ * list_splice - join two lists, this is designed for stacks
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(const struct list_head *list,
+				struct list_head *head)
+{
+	if (!list_empty(list))
+		__list_splice(list, head, head->next);
+}
+
+/**
+ * list_splice_tail - join two lists, each list being a queue
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice_tail(struct list_head *list,
+				struct list_head *head)
+{
+	if (!list_empty(list))
+		__list_splice(list, head->prev, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+				    struct list_head *head)
+{
+	if (!list_empty(list)) {
+		__list_splice(list, head, head->next);
+		INIT_LIST_HEAD(list);
+	}
+}
+
+/**
+ * list_splice_tail_init - join two lists and reinitialise the emptied list
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * Each of the lists is a queue.
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_tail_init(struct list_head *list,
+					 struct list_head *head)
+{
+	if (!list_empty(list)) {
+		__list_splice(list, head->prev, head);
+		INIT_LIST_HEAD(list);
+	}
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:	the &struct list_head pointer.
+ * @type:	the type of the struct this is embedded in.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+	container_of(ptr, type, member)
+
+/**
+ * list_first_entry - get the first element from a list
+ * @ptr:	the list head to take the element from.
+ * @type:	the type of the struct this is embedded in.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_first_entry(ptr, type, member) \
+	list_entry((ptr)->next, type, member)
+
+/**
+ * list_for_each	-	iterate over a list
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @head:	the head for your list.
+ */
+#define list_for_each(pos, head) \
+	for (pos = (head)->next; prefetch(pos->next), pos != (head); \
+			pos = pos->next)
+
+/**
+ * __list_for_each	-	iterate over a list
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @head:	the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code, no prefetching is done.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+	for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev	-	iterate over a list backwards
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @head:	the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+	for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \
+			pos = pos->prev)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @n:		another &struct list_head to use as temporary storage
+ * @head:	the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+	for (pos = (head)->next, n = pos->next; pos != (head); \
+		pos = n, n = pos->next)
+
+/**
+ * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @n:		another &struct list_head to use as temporary storage
+ * @head:	the head for your list.
+ */
+#define list_for_each_prev_safe(pos, n, head) \
+	for (pos = (head)->prev, n = pos->prev; \
+	     prefetch(pos->prev), pos != (head); \
+	     pos = n, n = pos->prev)
+
+/**
+ * list_for_each_entry	-	iterate over list of given type
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member)				\
+	for (pos = list_entry((head)->next, typeof(*pos), member);	\
+	     prefetch(pos->member.next), &pos->member != (head); 	\
+	     pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member)			\
+	for (pos = list_entry((head)->prev, typeof(*pos), member);	\
+	     prefetch(pos->member.prev), &pos->member != (head); 	\
+	     pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
+ * @pos:	the type * to use as a start point
+ * @head:	the head of the list
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Prepares a pos entry for use as a start point in list_for_each_entry_continue().
+ */
+#define list_prepare_entry(pos, head, member) \
+	((pos) ? : list_entry(head, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue - continue iteration over list of given type
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Continue to iterate over list of given type, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue(pos, head, member) 		\
+	for (pos = list_entry(pos->member.next, typeof(*pos), member);	\
+	     prefetch(pos->member.next), &pos->member != (head);	\
+	     pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue_reverse - iterate backwards from the given point
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Start to iterate over list of given type backwards, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue_reverse(pos, head, member)		\
+	for (pos = list_entry(pos->member.prev, typeof(*pos), member);	\
+	     prefetch(pos->member.prev), &pos->member != (head);	\
+	     pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_from - iterate over list of given type from the current point
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing from current position.
+ */
+#define list_for_each_entry_from(pos, head, member) 			\
+	for (; prefetch(pos->member.next), &pos->member != (head);	\
+	     pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos:	the type * to use as a loop cursor.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member)			\
+	for (pos = list_entry((head)->next, typeof(*pos), member),	\
+		n = list_entry(pos->member.next, typeof(*pos), member);	\
+	     &pos->member != (head); 					\
+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_continue - continue list iteration safe against removal
+ * @pos:	the type * to use as a loop cursor.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing after current point,
+ * safe against removal of list entry.
+ */
+#define list_for_each_entry_safe_continue(pos, n, head, member) 		\
+	for (pos = list_entry(pos->member.next, typeof(*pos), member), 		\
+		n = list_entry(pos->member.next, typeof(*pos), member);		\
+	     &pos->member != (head);						\
+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_from - iterate over list from current point safe against removal
+ * @pos:	the type * to use as a loop cursor.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type from current point, safe against
+ * removal of list entry.
+ */
+#define list_for_each_entry_safe_from(pos, n, head, member) 			\
+	for (n = list_entry(pos->member.next, typeof(*pos), member);		\
+	     &pos->member != (head);						\
+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal
+ * @pos:	the type * to use as a loop cursor.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ *
+ * Iterate backwards over list of given type, safe against removal
+ * of list entry.
+ */
+#define list_for_each_entry_safe_reverse(pos, n, head, member)		\
+	for (pos = list_entry((head)->prev, typeof(*pos), member),	\
+		n = list_entry(pos->member.prev, typeof(*pos), member);	\
+	     &pos->member != (head); 					\
+	     pos = n, n = list_entry(n->member.prev, typeof(*n), member))
+
+/*
+ * Double linked lists with a single pointer list head.
+ * Mostly useful for hash tables where the two pointer list head is
+ * too wasteful.
+ * You lose the ability to access the tail in O(1).
+ */
+
+struct hlist_head {
+	struct hlist_node *first;
+};
+
+struct hlist_node {
+	struct hlist_node *next, **pprev;
+};
+
+#define HLIST_HEAD_INIT { .first = NULL }
+#define HLIST_HEAD(name) struct hlist_head name = {  .first = NULL }
+#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
+static inline void INIT_HLIST_NODE(struct hlist_node *h)
+{
+	h->next = NULL;
+	h->pprev = NULL;
+}
+
+static inline int hlist_unhashed(const struct hlist_node *h)
+{
+	return !h->pprev;
+}
+
+static inline int hlist_empty(const struct hlist_head *h)
+{
+	return !h->first;
+}
+
+static inline void __hlist_del(struct hlist_node *n)
+{
+	struct hlist_node *next = n->next;
+	struct hlist_node **pprev = n->pprev;
+	*pprev = next;
+	if (next)
+		next->pprev = pprev;
+}
+
+static inline void hlist_del(struct hlist_node *n)
+{
+	__hlist_del(n);
+	n->next = LIST_POISON1;
+	n->pprev = LIST_POISON2;
+}
+
+static inline void hlist_del_init(struct hlist_node *n)
+{
+	if (!hlist_unhashed(n)) {
+		__hlist_del(n);
+		INIT_HLIST_NODE(n);
+	}
+}
+
+static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
+{
+	struct hlist_node *first = h->first;
+	n->next = first;
+	if (first)
+		first->pprev = &n->next;
+	h->first = n;
+	n->pprev = &h->first;
+}
+
+/* next must be != NULL */
+static inline void hlist_add_before(struct hlist_node *n,
+					struct hlist_node *next)
+{
+	n->pprev = next->pprev;
+	n->next = next;
+	next->pprev = &n->next;
+	*(n->pprev) = n;
+}
+
+static inline void hlist_add_after(struct hlist_node *n,
+					struct hlist_node *next)
+{
+	next->next = n->next;
+	n->next = next;
+	next->pprev = &n->next;
+
+	if(next->next)
+		next->next->pprev  = &next->next;
+}
+
+/*
+ * Move a list from one list head to another. Fixup the pprev
+ * reference of the first entry if it exists.
+ */
+static inline void hlist_move_list(struct hlist_head *old,
+				   struct hlist_head *new)
+{
+	new->first = old->first;
+	if (new->first)
+		new->first->pprev = &new->first;
+	old->first = NULL;
+}
+
+#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
+
+#define hlist_for_each(pos, head) \
+	for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
+	     pos = pos->next)
+
+#define hlist_for_each_safe(pos, n, head) \
+	for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
+	     pos = n)
+
+/**
+ * hlist_for_each_entry	- iterate over list of given type
+ * @tpos:	the type * to use as a loop cursor.
+ * @pos:	the &struct hlist_node to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry(tpos, pos, head, member)			 \
+	for (pos = (head)->first;					 \
+	     pos && ({ prefetch(pos->next); 1;}) &&			 \
+		({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+	     pos = pos->next)
+
+/**
+ * hlist_for_each_entry_continue - iterate over a hlist continuing after current point
+ * @tpos:	the type * to use as a loop cursor.
+ * @pos:	the &struct hlist_node to use as a loop cursor.
+ * @member:	the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_continue(tpos, pos, member)		 \
+	for (pos = (pos)->next;						 \
+	     pos && ({ prefetch(pos->next); 1;}) &&			 \
+		({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+	     pos = pos->next)
+
+/**
+ * hlist_for_each_entry_from - iterate over a hlist continuing from current point
+ * @tpos:	the type * to use as a loop cursor.
+ * @pos:	the &struct hlist_node to use as a loop cursor.
+ * @member:	the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_from(tpos, pos, member)			 \
+	for (; pos && ({ prefetch(pos->next); 1;}) &&			 \
+		({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+	     pos = pos->next)
+
+/**
+ * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @tpos:	the type * to use as a loop cursor.
+ * @pos:	the &struct hlist_node to use as a loop cursor.
+ * @n:		another &struct hlist_node to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_safe(tpos, pos, n, head, member) 		 \
+	for (pos = (head)->first;					 \
+	     pos && ({ n = pos->next; 1; }) && 				 \
+		({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+	     pos = n)
+
+#endif
diff --git a/test/am_ca_key_test/inject_record_t5d/am_time/Makefile b/test/am_ca_key_test/inject_record_t5d/am_time/Makefile
new file mode 100644
index 0000000..cad22f9
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_time/Makefile
@@ -0,0 +1,8 @@
+BASE=../..
+
+include $(BASE)/rule/def.mk
+
+O_TARGET=am_time
+am_time_SRCS=am_time.c
+
+include $(BASE)/rule/rule.mk
diff --git a/test/am_ca_key_test/inject_record_t5d/am_time/am_time.c b/test/am_ca_key_test/inject_record_t5d/am_time/am_time.c
new file mode 100644
index 0000000..56a975e
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_time/am_time.c
@@ -0,0 +1,111 @@
+#ifdef _FORTIFY_SOURCE
+#undef _FORTIFY_SOURCE
+#endif
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief 时钟、时间相关函数
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-05-21: create the document
+ ***************************************************************************/
+
+#define AM_DEBUG_LEVEL 5
+
+#include <am_debug.h>
+#include <am_time.h>
+#include <am_mem.h>
+#include <sys/time.h>
+#include <time.h>
+#include <assert.h>
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+#ifdef ANDROID
+//#undef CLOCK_REALTIME
+//#define CLOCK_REALTIME	CLOCK_MONOTONIC
+#endif
+
+/****************************************************************************
+ * API functions
+ ***************************************************************************/
+
+/**\brief 得到开机到当前系统运行的时间,单位为毫秒
+ * \param[out] clock 返回系统运行时间
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_time.h)
+ */
+AM_ErrorCode_t AM_TIME_GetClock(int *clock)
+{
+	struct timespec ts;
+	int ms;
+	
+	assert(clock);
+	
+	clock_gettime(CLOCK_MONOTONIC, &ts);
+	ms = ts.tv_sec*1000+ts.tv_nsec/1000000;
+	*clock = ms;
+	
+	return AM_SUCCESS;
+}
+
+/**\brief 得到开机到当前系统运行的时间,格式为struct timespec
+ * \param[out] ts 返回当前timespec值
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_time.h)
+ */
+AM_ErrorCode_t AM_TIME_GetTimeSpec(struct timespec *ts)
+{
+	assert(ts);
+	
+	clock_gettime(CLOCK_MONOTONIC, ts);
+	
+	return AM_SUCCESS;
+}
+
+/**\brief 得到若干毫秒后的timespec值
+ * 此函数主要用于pthread_cond_timedwait, sem_timedwait等函数计算超时时间。
+ * \param timeout 以毫秒为单位的超时时间
+ * \param[out] ts 返回timespec值
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_time.h)
+ */
+AM_ErrorCode_t AM_TIME_GetTimeSpecTimeout(int timeout, struct timespec *ts)
+{
+	struct timespec ots;
+	int left, diff;
+	
+	assert(ts);
+	
+	clock_gettime(CLOCK_MONOTONIC, &ots);
+	
+	ts->tv_sec  = ots.tv_sec + timeout/1000;
+	ts->tv_nsec = ots.tv_nsec;
+	
+	left = timeout % 1000;
+	left *= 1000000;
+	diff = 1000000000-ots.tv_nsec;
+
+	if(diff<=left)
+	{
+		ts->tv_sec++;
+		ts->tv_nsec = left-diff;
+	}
+	else
+	{
+		ts->tv_nsec += left;
+	}
+
+	return AM_SUCCESS;
+}
+
diff --git a/test/am_ca_key_test/inject_record_t5d/am_userdata/Makefile b/test/am_ca_key_test/inject_record_t5d/am_userdata/Makefile
new file mode 100644
index 0000000..94c5946
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_userdata/Makefile
@@ -0,0 +1,19 @@
+BASE=../..
+
+include $(BASE)/rule/def.mk
+
+O_TARGET=am_userdata
+am_userdata_SRCS=am_userdata.c
+
+SUBDIRS=
+am_userdata_OBJS=
+
+ifeq ($(EMU_DVR), y)
+	SUBDIRS+=emu
+	am_userdata_OBJS+=emu/emu
+else
+	SUBDIRS+=aml
+	am_userdata_OBJS+=aml/aml
+endif
+
+include $(BASE)/rule/rule.mk
diff --git a/test/am_ca_key_test/inject_record_t5d/am_userdata/am_userdata.c b/test/am_ca_key_test/inject_record_t5d/am_userdata/am_userdata.c
new file mode 100644
index 0000000..ba3e222
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_userdata/am_userdata.c
@@ -0,0 +1,485 @@
+#ifdef _FORTIFY_SOURCE
+#undef _FORTIFY_SOURCE
+#endif
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file am_userdata.c
+ * \brief user data 驱动模块
+ *
+ * \author Xia Lei Peng <leipeng.xia@amlogic.com>
+ * \date 2013-3-13: create the document
+ ***************************************************************************/
+
+#define AM_DEBUG_LEVEL 2
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <poll.h>
+#include <am_debug.h>
+#include "am_userdata_internal.h"
+#include <am_dmx.h>
+#include <am_fend.h>
+#include <am_time.h>
+#include <am_mem.h>
+#include <am_cond.h>
+
+#include "../am_adp_internal.h"
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+#define USERDATA_DEV_COUNT      (1)
+
+
+/****************************************************************************
+ * Static data
+ ***************************************************************************/
+//#define EMU_USERDATA
+
+#ifdef EMU_USERDATA
+extern const AM_USERDATA_Driver_t emu_ud_drv;
+#else
+extern const AM_USERDATA_Driver_t aml_ud_drv;
+#endif
+
+
+static AM_USERDATA_Device_t userdata_devices[USERDATA_DEV_COUNT] =
+{
+#ifdef EMU_USERDATA
+{
+.drv = &emu_ud_drv,
+},
+#else
+{
+.drv = &aml_ud_drv,
+},
+#endif
+};
+
+/****************************************************************************
+ * Static functions
+ ***************************************************************************/
+
+/**\brief 根据设备号取得设备结构指针*/
+static AM_INLINE AM_ErrorCode_t userdata_get_dev(int dev_no, AM_USERDATA_Device_t **dev)
+{
+	if ((dev_no<0) || (dev_no >= USERDATA_DEV_COUNT))
+	{
+		AM_DEBUG(1, "invalid userdata device number %d, must in(%d~%d)", dev_no, 0, USERDATA_DEV_COUNT-1);
+		return AM_USERDATA_ERR_INVALID_DEV_NO;
+	}
+	
+	*dev = &userdata_devices[dev_no];
+	return AM_SUCCESS;
+}
+
+/**\brief 根据设备号取得设备结构并检查设备是否已经打开*/
+static AM_INLINE AM_ErrorCode_t userdata_get_openned_dev(int dev_no, AM_USERDATA_Device_t **dev)
+{
+	AM_TRY(userdata_get_dev(dev_no, dev));
+	
+	if (!(*dev)->open_cnt)
+	{
+		AM_DEBUG(1, "userdata device %d has not been openned", dev_no);
+		return AM_USERDATA_ERR_INVALID_DEV_NO;
+	}
+	
+	return AM_SUCCESS;
+}
+
+static void dump_user_data(const uint8_t *buff, int size)
+{
+	int i;
+	char buf[4096];
+
+	if (size > 1024)
+		size = 1024;
+	for (i=0; i<size; i++)
+	{
+		sprintf(buf+i*3, "%02x ", buff[i]);
+	}
+
+	AM_DEBUG(5, "%s", buf);
+}
+
+int userdata_ring_buf_init(AM_USERDATA_RingBuffer_t *ringbuf, size_t len)
+{
+	ringbuf->pread=ringbuf->pwrite=0;
+	ringbuf->data=(uint8_t*)malloc(len);
+	if (ringbuf->data == NULL)
+		return -1;
+	ringbuf->size=len;
+	ringbuf->error=0;
+	
+	pthread_cond_init(&ringbuf->cond, NULL);
+	
+	return 0;
+}
+
+int userdata_ring_buf_deinit(AM_USERDATA_RingBuffer_t *ringbuf)
+{
+	ringbuf->pread=ringbuf->pwrite=0;
+	if (ringbuf->data != NULL)
+		free(ringbuf->data);
+	ringbuf->size=0;
+	ringbuf->error=0;
+	
+	pthread_cond_destroy(&ringbuf->cond);
+	
+	return 0;
+}
+
+int userdata_ring_buf_empty(AM_USERDATA_RingBuffer_t *ringbuf)
+{
+	return (ringbuf->pread==ringbuf->pwrite);
+}
+
+ssize_t userdata_ring_buf_free(AM_USERDATA_RingBuffer_t *ringbuf)
+{
+	ssize_t free;
+
+	free = ringbuf->pread - ringbuf->pwrite;
+	if (free <= 0)
+		free += ringbuf->size;
+
+	return free-1;
+}
+
+ssize_t userdata_ring_buf_avail(AM_USERDATA_RingBuffer_t *ringbuf)
+{
+	ssize_t avail;
+	
+	avail = ringbuf->pwrite - ringbuf->pread;
+	if (avail < 0)
+		avail += ringbuf->size;
+
+	return avail;
+}
+
+void userdata_ring_buf_read(AM_USERDATA_RingBuffer_t *ringbuf, uint8_t *buf, size_t len)
+{
+	size_t todo = len;
+	size_t split;
+
+	if (ringbuf->data == NULL)
+		return;
+	
+	split = ((ssize_t)(ringbuf->pread + len) > ringbuf->size) ? ringbuf->size - ringbuf->pread : 0;
+	if (split > 0) {
+		memcpy(buf, ringbuf->data+ringbuf->pread, split);
+		buf += split;
+		todo -= split;
+		ringbuf->pread = 0;
+	}
+	
+	memcpy(buf, ringbuf->data+ringbuf->pread, todo);
+
+	ringbuf->pread = (ringbuf->pread + todo) % ringbuf->size;
+}
+
+ssize_t userdata_ring_buf_write(AM_USERDATA_RingBuffer_t *ringbuf, const uint8_t *buf, size_t len)
+{
+	size_t todo = len;
+	size_t split;
+	
+	if (ringbuf->data == NULL)
+		return 0;
+	
+	split = ((ssize_t)(ringbuf->pwrite + len) > ringbuf->size) ? ringbuf->size - ringbuf->pwrite : 0;
+
+	if (split > 0) {
+		memcpy(ringbuf->data+ringbuf->pwrite, buf, split);
+		buf += split;
+		todo -= split;
+		ringbuf->pwrite = 0;
+	}
+	
+	memcpy(ringbuf->data+ringbuf->pwrite, buf, todo);
+	
+	ringbuf->pwrite = (ringbuf->pwrite + todo) % ringbuf->size;
+	
+	if (len > 0)
+		pthread_cond_signal(&ringbuf->cond);
+
+	return len;
+}
+
+static void read_unused_data(AM_USERDATA_RingBuffer_t *ringbuf, size_t len)
+{
+	uint8_t *buf = (uint8_t*)malloc(len);
+	
+	if (buf != NULL)
+	{
+		//AM_DEBUG(1, "read %d bytes unused data", len);
+		userdata_ring_buf_read(ringbuf, buf, len);
+		free(buf);
+	}
+}
+
+static int userdata_package_write(AM_USERDATA_Device_t *dev, const uint8_t *buf, size_t size)
+{
+	int cnt, ret;
+	
+	pthread_mutex_lock(&dev->lock);
+	cnt = userdata_ring_buf_free(&dev->pkg_buf);
+	if (cnt < (int)(size+sizeof(cnt)))
+	{
+		AM_DEBUG(1, "write userdata error: data size to large, %d > %d", size+sizeof(cnt), cnt);
+		ret = 0;
+	}
+	else
+	{
+		cnt = size;
+		userdata_ring_buf_write(&dev->pkg_buf, (uint8_t*)&cnt, sizeof(cnt));
+		userdata_ring_buf_write(&dev->pkg_buf, buf, size);
+		ret = size;
+	}
+	pthread_mutex_unlock(&dev->lock);
+	
+	//AM_DEBUG(3, "write %d bytes\n", ret);
+	dump_user_data(buf, size);
+	return ret;
+}
+
+static int userdata_package_read(AM_USERDATA_Device_t *dev, uint8_t *buf, int size)
+{	
+	int cnt, ud_cnt;
+	
+	ud_cnt = 0;
+	cnt = userdata_ring_buf_avail(&dev->pkg_buf);
+	if (cnt > 4)
+	{
+		userdata_ring_buf_read(&dev->pkg_buf, (uint8_t*)&ud_cnt, sizeof(ud_cnt));
+		cnt = userdata_ring_buf_avail(&dev->pkg_buf);
+		if (cnt < ud_cnt)
+		{
+			/* this case must not happen */
+			//AM_DEBUG(0, "read userdata error: expect %d bytes, but only %d bytes avail", ud_cnt, cnt);
+			cnt = 0;
+			read_unused_data(&dev->pkg_buf, cnt);
+		}
+		else
+		{
+			cnt = 0;
+			if (ud_cnt > size)
+			{
+				//AM_DEBUG(0, "read userdata error: source buffer not enough, bufsize %d , datasize %d", size, ud_cnt);
+				read_unused_data(&dev->pkg_buf, ud_cnt);
+			}
+			else if (ud_cnt > 0)
+			{
+				userdata_ring_buf_read(&dev->pkg_buf, buf, ud_cnt);
+				cnt = ud_cnt;
+			}
+		}
+	}
+	else
+	{
+		//AM_DEBUG(0, "read userdata error: count = %d < 4", cnt);
+		cnt = 0;
+		read_unused_data(&dev->pkg_buf, cnt);
+	}
+	
+	return cnt;
+}
+
+static AM_ErrorCode_t userdata_package_poll(AM_USERDATA_Device_t *dev, int timeout)
+{
+	int rv, ret = AM_SUCCESS, cnt;
+	struct timespec rt;
+	
+	cnt = userdata_ring_buf_avail(&dev->pkg_buf);
+	if (cnt <= 0)
+	{
+		AM_TIME_GetTimeSpecTimeout(timeout, &rt);
+		rv = pthread_cond_timedwait(&dev->pkg_buf.cond, &dev->lock, &rt);
+		if (rv == ETIMEDOUT)
+		{
+			//AM_DEBUG(1, "poll userdata timeout, timeout = %d ms", timeout);
+			ret = AM_FAILURE;
+		}
+		else
+		{
+			cnt = userdata_ring_buf_avail(&dev->pkg_buf);
+			if (cnt <= 0)
+			{
+				AM_DEBUG(1, "poll error, unexpected error");
+				ret = AM_FAILURE;
+			}
+		}
+	}
+	return ret;
+}
+
+/****************************************************************************
+ * API functions
+ ***************************************************************************/
+
+/**\brief 打开USERDATA设备
+ * \param dev_no USERDATA设备号
+ * \param[in] para USERDATA设备开启参数
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_userdata.h)
+ */
+AM_ErrorCode_t AM_USERDATA_Open(int dev_no, const AM_USERDATA_OpenPara_t *para)
+{
+	AM_USERDATA_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	int i;
+	
+	assert(para);
+	
+	AM_TRY(userdata_get_dev(dev_no, &dev));
+	
+	pthread_mutex_lock(&am_gAdpLock);
+	
+	if (dev->open_cnt)
+	{
+		AM_DEBUG(1, "userdata device %d has already been openned", dev_no);
+		dev->open_cnt++;
+		goto final;
+	}
+
+	dev->dev_no = dev_no;
+
+	dev->write_package = userdata_package_write;
+	userdata_ring_buf_init(&dev->pkg_buf, USERDATA_BUF_SIZE);
+	pthread_mutex_init(&dev->lock, NULL);
+	
+	if (dev->drv->open)
+	{
+		ret = dev->drv->open(dev, para);
+	}
+	
+	if (ret == AM_SUCCESS)
+	{
+		dev->open_cnt++;
+	}
+	else
+	{
+		pthread_mutex_destroy(&dev->lock);
+	}
+	
+final:
+	pthread_mutex_unlock(&am_gAdpLock);
+	
+	return ret;
+}
+
+/**\brief 关闭USERDATA设备
+ * \param dev_no USERDATA设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_userdata.h)
+ */
+AM_ErrorCode_t AM_USERDATA_Close(int dev_no)
+{
+	AM_USERDATA_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+	
+	AM_TRY(userdata_get_dev(dev_no, &dev));
+	
+	pthread_mutex_lock(&am_gAdpLock);
+
+	if (dev->open_cnt > 0)
+	{
+		if (dev->open_cnt == 1)
+		{				
+			if (dev->drv->close)
+			{
+				dev->drv->close(dev);
+			}
+
+			pthread_mutex_destroy(&dev->lock);
+			
+			userdata_ring_buf_deinit(&dev->pkg_buf);
+		}
+		dev->open_cnt--;
+	}
+	
+	pthread_mutex_unlock(&am_gAdpLock);
+	
+	return ret;
+}
+
+/**\brief 从USERDATA读取数据
+ * \param dev_no USERDATA设备号
+ * \param	[out] buf 缓冲区
+ * \param size	需要读取的数据长度
+ * \param timeout 读取超时时间 ms
+ * \return
+ *   - 实际读取的字节数
+ */
+int AM_USERDATA_Read(int dev_no, uint8_t *buf, int size, int timeout_ms)
+{
+	AM_USERDATA_Device_t *dev;
+	AM_ErrorCode_t ret;
+	int cnt = -1;
+
+	AM_TRY(userdata_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+	ret = userdata_package_poll(dev, timeout_ms);
+	if (ret == AM_SUCCESS)
+	{
+		cnt = userdata_package_read(dev, buf, size);
+	}
+	pthread_mutex_unlock(&dev->lock);
+
+	return cnt;
+}
+
+AM_ErrorCode_t AM_USERDATA_SetMode(int dev_no, int mode)
+{
+	AM_USERDATA_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	AM_TRY(userdata_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (dev->drv->set_mode)
+		ret = dev->drv->set_mode(dev, mode);
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
+AM_ErrorCode_t AM_USERDATA_GetMode(int dev_no, int *mode)
+{
+	AM_USERDATA_Device_t *dev;
+	AM_ErrorCode_t ret = AM_SUCCESS;
+
+	if (!mode)
+		return AM_USERDATA_ERR_INVALID_ARG;
+
+	AM_TRY(userdata_get_openned_dev(dev_no, &dev));
+
+	pthread_mutex_lock(&dev->lock);
+
+	if (dev->drv->get_mode)
+		ret = dev->drv->get_mode(dev, mode);
+
+	pthread_mutex_unlock(&dev->lock);
+
+	return ret;
+}
+
diff --git a/test/am_ca_key_test/inject_record_t5d/am_userdata/am_userdata_internal.h b/test/am_ca_key_test/inject_record_t5d/am_userdata/am_userdata_internal.h
new file mode 100644
index 0000000..4539e5b
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_userdata/am_userdata_internal.h
@@ -0,0 +1,88 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief USER DATA module
+ *
+ * \author Xia Lei Peng <leipeng.xia@amlogic.com>
+ * \date 2013-3-13: create the document
+ ***************************************************************************/
+
+#ifndef _AM_USERDATA_INTERNAL_H
+#define _AM_USERDATA_INTERNAL_H
+
+#include <am_userdata.h>
+#include <am_util.h>
+#include <am_thread.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+#define USERDATA_BUF_SIZE (5*1024)
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+ 
+/**\brief USERDATA设备*/
+typedef struct AM_USERDATA_Device AM_USERDATA_Device_t;
+
+
+typedef struct
+{
+	uint8_t           *data;
+	ssize_t           size;
+	ssize_t           pread;
+	ssize_t           pwrite;
+	int               error;
+	
+	pthread_cond_t	  cond;
+}AM_USERDATA_RingBuffer_t;
+
+/**\brief USERDATA设备驱动*/
+typedef struct
+{
+	AM_ErrorCode_t (*open)(AM_USERDATA_Device_t *dev, const AM_USERDATA_OpenPara_t *para);
+	AM_ErrorCode_t (*close)(AM_USERDATA_Device_t *dev);
+	AM_ErrorCode_t (*set_mode)(AM_USERDATA_Device_t *dev, int mode);
+	AM_ErrorCode_t (*get_mode)(AM_USERDATA_Device_t *dev, int *mode);
+} AM_USERDATA_Driver_t;
+
+/**\brief USERDATA设备*/
+struct AM_USERDATA_Device
+{
+	int                 dev_no;  /**< 设备号*/
+	const AM_USERDATA_Driver_t *drv;  /**< 设备驱动*/
+	void               *drv_data;/**< 驱动私有数据*/
+	int                 open_cnt;   /**< 设备打开计数*/
+	pthread_mutex_t     lock;    /**< 设备保护互斥体*/
+	AM_USERDATA_RingBuffer_t pkg_buf;
+
+	int (*write_package)(AM_USERDATA_Device_t *dev, const uint8_t *buf, size_t size);
+
+};
+
+
+
+/****************************************************************************
+ * Function prototypes  
+ ***************************************************************************/
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/am_userdata/aml/Makefile b/test/am_ca_key_test/inject_record_t5d/am_userdata/aml/Makefile
new file mode 100644
index 0000000..b7fcded
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_userdata/aml/Makefile
@@ -0,0 +1,8 @@
+BASE=../../..
+
+include $(BASE)/rule/def.mk
+
+O_TARGET=aml
+aml_SRCS=aml.c
+
+include $(BASE)/rule/rule.mk
diff --git a/test/am_ca_key_test/inject_record_t5d/am_userdata/aml/aml.c b/test/am_ca_key_test/inject_record_t5d/am_userdata/aml/aml.c
new file mode 100644
index 0000000..afc9567
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_userdata/aml/aml.c
@@ -0,0 +1,1070 @@
+#ifdef _FORTIFY_SOURCE
+#undef _FORTIFY_SOURCE
+#endif
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief aml user data driver
+ *
+ * \author Xia Lei Peng <leipeng.xia@amlogic.com>
+ * \date 2013-3-13: create the document
+ ***************************************************************************/
+
+#define AM_DEBUG_LEVEL 4
+
+#include <am_debug.h>
+#include <am_mem.h>
+#include "../am_userdata_internal.h"
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <poll.h>
+#include <sys/ioctl.h>
+#include <math.h>
+#include <signal.h>
+#include <strings.h>
+
+#define USERDATA_POLL_TIMEOUT 100
+#define MAX_CC_NUM			64
+#define MAX_CC_DATA_LEN  (1024*5 + 4)
+
+#define IS_H264(p)	((p[0] == 0xb5 && p[3] == 0x47 && p[4] == 0x41 && p[5] == 0x39 && p[6] == 0x34))
+#define IS_DIRECTV(p) ((p[0] == 0xb5 && p[1] == 0x00 && p[2] == 0x2f))
+#define IS_AVS(p)	 ((p[0] == 0x47) && (p[1] == 0x41) && (p[2] == 0x39) && (p[3] == 0x34))
+#define IS_ATSC(p)	((p[0] == 0x47) && (p[1] == 0x41) && (p[2] == 0x39) && (p[3] == 0x34)/* && (p[4] == 0x3)*/)
+#define IS_SCTE(p)  ((p[0]==0x3) && ((p[1]&0x7f) == 1))
+
+#define IS_AFD(p)	((p[0] == 0x44) && (p[1] == 0x54) && (p[2] == 0x47) && (p[3] == 0x31))
+#define IS_H264_AFD(p)	((p[0] == 0xb5) && (p[3] == 0x44) && (p[4] == 0x54) && (p[5] == 0x47) && (p[6] == 0x31))
+
+#define AMSTREAM_IOC_MAGIC  'S'
+#define AMSTREAM_IOC_UD_LENGTH _IOR(AMSTREAM_IOC_MAGIC, 0x54, unsigned long)
+#define AMSTREAM_IOC_UD_POC _IOR(AMSTREAM_IOC_MAGIC, 0x55, int)
+#define AMSTREAM_IOC_UD_FLUSH_USERDATA _IOR(AMSTREAM_IOC_MAGIC, 0x56, int)
+#define AMSTREAM_IOC_UD_BUF_READ _IOR(AMSTREAM_IOC_MAGIC, 0x57, int)
+#define AMSTREAM_IOC_UD_AVAIBLE_VDEC      _IOR(AMSTREAM_IOC_MAGIC, 0x5c, unsigned int)
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+typedef enum {
+	INVALID_TYPE = 0,
+	CC_TYPE_FOR_JUDGE = 10,
+	MPEG_CC_TYPE,
+	H264_CC_TYPE,
+	DIRECTV_CC_TYPE,
+	AVS_CC_TYPE,
+	SCTE_CC_TYPE,
+	AFD_TYPE_FOR_JUDGE = 100,
+	MPEG_AFD_TYPE,
+	H264_AFD_TYPE,
+	USERDATA_TYPE_MAX,
+} userdata_type;
+
+#define IS_AFD_TYPE(p) (p > AFD_TYPE_FOR_JUDGE && p < USERDATA_TYPE_MAX)
+#define IS_CC_TYPE(p) (p > CC_TYPE_FOR_JUDGE && p < AFD_TYPE_FOR_JUDGE)
+typedef enum {
+	/* 0 forbidden */
+	I_TYPE = 1,
+	P_TYPE = 2,
+	B_TYPE = 3,
+	D_TYPE = 4,
+	/* 5 ... 7 reserved */
+} picture_coding_type;
+
+struct userdata_meta_info_t {
+	uint32_t poc_number;
+	/************ flags bit defination ***********
+	bit 0:		//used for mpeg2
+		1, group start
+		0, not group start
+	bit 1-2:	//used for mpeg2
+		0, extension_and_user_data( 0 )
+		1, extension_and_user_data( 1 )
+		2, extension_and_user_data( 2 )
+	bit 3-6:	//video format
+		0,	VFORMAT_MPEG12
+		1,	VFORMAT_MPEG4
+		2,	VFORMAT_H264
+		3,	VFORMAT_MJPEG
+		4,	VFORMAT_REAL
+		5,	VFORMAT_JPEG
+		6,	VFORMAT_VC1
+		7,	VFORMAT_AVS
+		8,	VFORMAT_SW
+		9,	VFORMAT_H264MVC
+		10, VFORMAT_H264_4K2K
+		11, VFORMAT_HEVC
+		12, VFORMAT_H264_ENC
+		13, VFORMAT_JPEG_ENC
+		14, VFORMAT_VP9
+	bit 7-9:	//frame type
+		0, Unknown Frame Type
+		1, I Frame
+		2, B Frame
+		3, P Frame
+		4, D_Type_MPEG2
+	bit 10:  //top_field_first_flag valid
+		0: top_field_first_flag is not valid
+		1: top_field_first_flag is valid
+	bit 11: //top_field_first bit val
+	bit 12-13: //picture_struct, used for H264
+		0: Invalid
+		1: TOP_FIELD_PICTURE
+		2: BOT_FIELD_PICTURE
+		3: FRAME_PICTURE
+	**********************************************/
+	uint32_t flags;
+	uint32_t vpts;			/*video frame pts*/
+	/******************************************
+	0: pts is invalid, please use duration to calcuate
+	1: pts is valid
+	******************************************/
+	uint32_t vpts_valid;
+	/*duration for frame*/
+	uint32_t duration;
+	/* how many records left in queue waiting to be read*/
+	uint32_t records_in_que;
+	unsigned long long priv_data;
+	uint32_t padding_data[4];
+};
+
+
+struct userdata_param_t {
+	uint32_t version;
+	uint32_t instance_id; /*input, 0~9*/
+	uint32_t buf_len; /*input*/
+	uint32_t data_size; /*output*/
+	void* pbuf_addr; /*input*/
+	struct userdata_meta_info_t meta_info; /*output*/
+};
+
+typedef struct AM_CCData_s AM_CCData;
+struct AM_CCData_s {
+	AM_CCData *next;
+	uint8_t   *buf;
+	uint32_t pts;
+	uint32_t duration;
+	int pts_valid;
+	int		size;
+	int		cap;
+	int		poc;
+};
+
+typedef struct {
+	uint32_t picture_structure:16;
+	uint32_t temporal_reference:10;
+	uint32_t picture_coding_type:3;
+	uint32_t reserved:3;
+	uint32_t index:16;
+	uint32_t offset:16;
+	uint8_t  atsc_flag[4];
+	uint8_t  cc_data_start[4];
+} aml_ud_header_t;
+
+typedef struct {
+	pthread_t	   th;
+	int			 fd;
+	int vfmt;
+	AM_Bool_t	   running;
+	AM_CCData	  *cc_list;
+	AM_CCData	  *free_list;
+	int			 cc_num;
+	userdata_type   format;
+	int			 curr_poc;
+	uint32_t curr_pts;
+	uint32_t curr_duration;
+	int scte_enable;
+	int mode;
+} AM_UDDrvData;
+
+#define MOD_ON(__mod, __mask) (__mod & __mask)
+#define MOD_ON_CC(__mod) MOD_ON(__mod, AM_USERDATA_MODE_CC)
+#define MOD_ON_AFD(__mod) MOD_ON(__mod, AM_USERDATA_MODE_AFD)
+
+
+/****************************************************************************
+ * Static data definitions
+ ***************************************************************************/
+
+static AM_ErrorCode_t aml_open(AM_USERDATA_Device_t *dev, const AM_USERDATA_OpenPara_t *para);
+static AM_ErrorCode_t aml_close(AM_USERDATA_Device_t *dev);
+static AM_ErrorCode_t aml_set_mode(AM_USERDATA_Device_t *dev, int mode);
+static AM_ErrorCode_t aml_get_mode(AM_USERDATA_Device_t *dev, int *mode);
+
+const AM_USERDATA_Driver_t aml_ud_drv = {
+.open  = aml_open,
+.close = aml_close,
+.set_mode = aml_set_mode,
+.get_mode = aml_get_mode,
+};
+
+uint32_t am_get_video_pts()
+{
+#define VIDEO_PTS_PATH "/sys/class/tsync/pts_video"
+	char buffer[16] = {0};
+	AM_FileRead(VIDEO_PTS_PATH,buffer,16);
+	return strtoul(buffer, NULL, 16);
+}
+
+static void dump_cc_data(char *who, int poc, uint8_t *buff, int size)
+{
+	int i;
+	char buf[4096];
+
+	if (size > 1024)
+		size = 1024;
+	for (i=0; i<size; i++)
+	{
+		sprintf(buf+i*3, "%02x ", buff[i]);
+	}
+
+	AM_DEBUG(AM_DEBUG_LEVEL, "CC DUMP:who:%s poc: %d :%s", who, poc, buf);
+}
+
+static void aml_free_cc_data (AM_CCData *cc)
+{
+	if (cc->buf)
+		free(cc->buf);
+	free(cc);
+}
+
+static void aml_swap_data(uint8_t *user_data, int ud_size)
+{
+	int swap_blocks, i, j, k, m;
+	unsigned char c_temp;
+
+	/* swap byte order */
+	swap_blocks = ud_size >> 3;
+	for (i = 0; i < swap_blocks; i ++) {
+		j = i << 3;
+		k = j + 7;
+		for (m=0; m<4; m++) {
+			c_temp = user_data[j];
+			user_data[j++] = user_data[k];
+			user_data[k--] = c_temp;
+		}
+	}
+}
+
+static uint8_t scte20_char_map[256];
+
+static uint8_t
+scte20_get_char (uint8_t c)
+{
+	if (scte20_char_map[1] == 0) {
+		int i;
+
+		for (i = 0; i < 256; i ++) {
+			uint8_t v1, v2;
+			int     b;
+
+			v1 = i;
+			v2 = 0;
+
+			for (b = 0; b < 8; b ++) {
+				if (v1 & (1 << b))
+					v2 |= (1 << (7 - b));
+			}
+
+			scte20_char_map[i] = v2;
+		}
+	}
+
+	return scte20_char_map[c];
+}
+
+static userdata_type aml_check_userdata_format (uint8_t *buf, int vfmt, int len)
+{
+	if (len < 8)
+		return INVALID_TYPE;
+	//vfmt:
+	//0 for MPEG
+	//2 for H264
+	//7 for AVS
+
+	if (vfmt == 2)
+	{
+		if (IS_H264(buf))
+		{
+			AM_DEBUG(AM_DEBUG_LEVEL,"CC format is h264_cc_type");
+			return H264_CC_TYPE;
+		}
+		else if (IS_DIRECTV(buf))
+		{
+			AM_DEBUG(AM_DEBUG_LEVEL,"CC format is directv_cc_type");
+			return DIRECTV_CC_TYPE;
+		}
+		else if (IS_H264_AFD(buf))
+		{
+			return H264_AFD_TYPE;
+		}
+	}
+	else if (vfmt == 7)
+	{
+		if (IS_AVS(buf)) {
+			AM_DEBUG(AM_DEBUG_LEVEL,"CC format is avs_cc_type");
+			return AVS_CC_TYPE;
+		}
+	}
+	else if (vfmt == 0)
+	{
+		if (len >= (int)sizeof(aml_ud_header_t))
+		{
+			aml_ud_header_t *hdr = (aml_ud_header_t*)buf;
+
+			if (IS_ATSC(hdr->atsc_flag))
+			{
+				AM_DEBUG(AM_DEBUG_LEVEL,"CC format is mpeg_cc_type");
+				return MPEG_CC_TYPE;
+			}
+			else if (IS_SCTE(hdr->atsc_flag))
+			{
+				AM_DEBUG(AM_DEBUG_LEVEL, "CC format is scte_cc_type");
+				return SCTE_CC_TYPE;
+			}
+			else if (IS_AFD(hdr->atsc_flag))
+			{
+				return MPEG_AFD_TYPE;
+			}
+			else if (IS_H264(buf))
+			{
+				AM_DEBUG(AM_DEBUG_LEVEL,"CC format is h264_cc_type");
+				return H264_CC_TYPE;
+			}
+		}
+	}
+	else
+		AM_DEBUG(AM_DEBUG_LEVEL, "vfmt not handled");
+
+	AM_DEBUG(AM_DEBUG_LEVEL,"CC format is INVALID_TYPE");
+	return INVALID_TYPE;
+}
+
+static void aml_write_userdata(AM_USERDATA_Device_t *dev, uint8_t *buffer, int buffer_len, uint32_t
+	pts, int pts_valid, uint32_t duration)
+{
+	uint32_t *pts_in_buffer;
+	uint8_t userdata_with_pts[MAX_CC_DATA_LEN];
+	AM_UDDrvData *ud = dev->drv_data;
+
+	if (pts_valid == 0)
+		pts = ud->curr_pts + ud->curr_duration;
+
+	pts_in_buffer = (uint32_t *)userdata_with_pts;
+	*pts_in_buffer = pts;
+	memcpy(userdata_with_pts+4, buffer, buffer_len);
+
+	dev->write_package(dev, userdata_with_pts, buffer_len + 4);
+
+	ud->curr_pts = pts;
+	ud->curr_duration = duration;
+}
+
+static void aml_flush_cc_data(AM_USERDATA_Device_t *dev)
+{
+	AM_UDDrvData *ud = dev->drv_data;
+	AM_CCData *cc, *ncc;
+	char  buf[256];
+	char *pp = buf;
+	int   left = sizeof(buf), i, pr;
+
+	for (cc = ud->cc_list; cc; cc = ncc) {
+		ncc = cc->next;
+
+		for (i = 0; i < cc->size; i ++) {
+			pr = snprintf(pp, left, "%02x ", cc->buf[i]);
+			if (pr < left) {
+				pp   += pr;
+				left -= pr;
+			}
+		}
+
+		AM_DEBUG(AM_DEBUG_LEVEL, "cc_write_package decode:%s", buf);
+
+		aml_write_userdata(dev, cc->buf, cc->size, cc->pts, cc->pts_valid, cc->duration);
+
+		cc->next = ud->free_list;
+		ud->free_list = cc;
+	}
+
+	ud->cc_list  = NULL;
+	ud->cc_num   = 0;
+	ud->curr_poc = -1;
+}
+
+static void aml_add_cc_data(AM_USERDATA_Device_t *dev, int poc, int type, uint8_t *p, int len, uint32_t
+	pts, int pts_valid, uint32_t duration)
+{
+	AM_UDDrvData *ud = dev->drv_data;
+	AM_CCData **pcc, *cc;
+	char  buf[256];
+	char *pp = buf;
+	int   left = sizeof(buf), i, pr;
+
+	if (ud->cc_num >= MAX_CC_NUM) {
+#if 0
+		aml_flush_cc_data(dev);
+#else
+		cc = ud->cc_list;
+		//dump_cc_data("add cc ",cc->poc,cc->buf, cc->size);
+		aml_write_userdata(dev, cc->buf, cc->size, cc->pts, cc->pts_valid, cc->duration);
+
+		ud->cc_list = cc->next;
+		cc->next = ud->free_list;
+		ud->free_list = cc;
+		ud->cc_num --;
+#endif
+	}
+
+	for (i = 0; i < len; i ++) {
+		pr = snprintf(pp, left, "%02x ", p[i]);
+		if (pr < left) {
+			pp   += pr;
+			left -= pr;
+		}
+	}
+
+	AM_DEBUG(AM_DEBUG_LEVEL, "CC poc:%d ptype:%d data:%s", poc, type, buf);
+
+	pcc = &ud->cc_list;
+	if (*pcc && poc < ((*pcc)->poc - 30))
+		aml_flush_cc_data(dev);
+
+	while ((cc = *pcc)) {
+		/*if (cc->poc == poc) {
+			aml_flush_cc_data(dev);
+			pcc = &ud->cc_list;
+			break;
+		}*/
+		if (cc->pts == pts)
+		{
+			if (cc->poc > poc)
+				break;
+		}
+		else if (cc->pts > pts) {
+			break;
+		}
+
+		pcc = &cc->next;
+	}
+
+	if (ud->free_list) {
+		cc = ud->free_list;
+		ud->free_list = cc->next;
+	} else {
+		cc = malloc(sizeof(AM_CCData));
+		cc->buf  = NULL;
+		cc->size = 0;
+		cc->cap  = 0;
+		cc->poc  = 0;
+	}
+
+	if (cc->cap < len) {
+		cc->buf = realloc(cc->buf, len);
+		cc->cap = len;
+	}
+
+	memcpy(cc->buf, p, len);
+
+	cc->size = len;
+	cc->poc  = poc;
+	cc->pts = pts;
+	cc->pts_valid = pts_valid;
+	cc->duration = duration;
+	cc->next = *pcc;
+	*pcc = cc;
+
+	ud->cc_num ++;
+}
+
+static void aml_mpeg_userdata_package(AM_USERDATA_Device_t *dev, int poc, int type, uint8_t *p, int
+len, uint32_t pts, int pts_valid, uint32_t duration)
+{
+	AM_UDDrvData *ud = dev->drv_data;
+#if 0
+	int i;
+	char display_buffer[10240];
+	for (i=0;i<len; i++)
+		sprintf(&display_buffer[i*3], " %02x", p[i]);
+	AM_DEBUG(0, "mpeg_process len:%d data:%s", len, display_buffer);
+#endif
+
+	if (len < 5)
+		return;
+
+	if (p[4] != 3)
+		return;
+
+	if (type == I_TYPE)
+		aml_flush_cc_data(dev);
+
+	if (poc == ud->curr_poc + 1) {
+		AM_CCData *cc, **pcc;
+
+		aml_write_userdata(dev, p, len, pts, pts_valid, duration);
+		ud->curr_poc ++;
+
+		pcc = &ud->cc_list;
+		while ((cc = *pcc)) {
+			if (ud->curr_poc + 1 != cc->poc)
+				break;
+
+			aml_write_userdata(dev, cc->buf, cc->size, cc->pts, cc->pts_valid, cc->duration);
+			*pcc = cc->next;
+			ud->curr_poc ++;
+
+			cc->next = ud->free_list;
+			ud->free_list = cc;
+		}
+
+		return;
+	}
+
+	aml_add_cc_data(dev, poc, type, p, len, pts, pts_valid, duration);
+}
+
+static int aml_process_scte_userdata(AM_USERDATA_Device_t *dev, uint8_t *data, int len, struct userdata_meta_info_t* meta_info)
+{
+	int cc_count = 0, cnt, i;
+	int field_num;
+	uint8_t* cc_section;
+	uint8_t cc_data[64] = {0};
+	uint8_t* scte_head;
+	uint8_t* scte_head_search_position;
+	int head_posi = 0;
+	int prio, field, line, cc1, cc2, mark, size, ptype, ref;
+	int write_position, bits = 0, array_position = 0;
+	uint8_t *p;
+	int left = len;
+	int left_bits;
+	uint32_t v;
+	int flags;
+	uint32_t pts;
+	int top_bit_value, top_bit_valid;
+	AM_UDDrvData *ud = dev->drv_data;
+
+#if 0
+	char display_buffer[10240];
+#endif
+
+	flags = meta_info->flags;
+	pts = meta_info->vpts;
+
+	if (ud->scte_enable != 1)
+		return len;
+
+	v = (data[4] << 24) | (data[5] << 16) | (data[6] << 8) | data[7];
+	top_bit_valid = flags & (1<<10);
+	top_bit_value = flags & (1<<11);
+	if (top_bit_valid == 0)
+		top_bit_value = 1;
+
+	ref = (v >> 16) & 0x3ff;
+	ptype = (v >> 26) & 7;
+
+#if 0
+	for (i=0; i<len; i++)
+		sprintf(display_buffer+3*i, " %02x", data[i]);
+	AM_DEBUG(0, "scte buffer type %d ref %d top_bit %d %s", ptype, ref, top_bit_value, display_buffer);
+#endif
+
+	if (ptype == I_TYPE)
+		aml_flush_cc_data(dev);
+
+	scte_head = data;
+	while (head_posi < len)
+	{
+		scte_head_search_position = &scte_head[head_posi];
+		if (IS_SCTE(scte_head_search_position))
+			break;
+		head_posi += 8;
+	}
+
+	if ((len - head_posi) < 8)
+		return len;
+
+	p = &data[head_posi + 2];
+	cc_data[0] = 0x47;
+	cc_data[1] = 0x41;
+	cc_data[2] = 0x39;
+	cc_data[3] = 0x34;
+	cc_data[4] = 0x3;
+
+	left_bits = (len - head_posi) << 3;
+
+#define NST_BITS(v, b, l) (((v) >> (b)) & (0xff >> (8 - (l))))
+#define GET(n, b)\
+	do \
+	{\
+		int off, bs;\
+		if (bits + b > left_bits) goto error;\
+		off = bits >> 3;\
+		bs  = bits & 7;\
+		if (8 - bs >= b) {\
+		  n = NST_BITS(p[off], 8 - bs - b, b);\
+		} else {\
+		  int n1, n2, b1 = 8 - bs, b2 = b- b1;\
+		  n1 = NST_BITS(p[off], 0, b1);\
+		  n2 = NST_BITS(p[off + 1], 8 - b + b1, b - b1);\
+		  n = (n1 << b2) | n2;\
+		}\
+		bits += b;\
+	} while(0)
+
+	GET(cnt, 5);
+	array_position = 7;
+	for (i = 0; i < cnt; i ++) {
+		GET(prio, 2);
+		GET(field, 2);
+		GET(line, 5);
+		GET(cc1, 8);
+		GET(cc2, 8);
+		GET(mark, 1);
+		if (field == 3)
+			field = 1;
+		AM_DEBUG(AM_DEBUG_LEVEL, "loop %d field %d line %d cc1 %x cc2 %x",
+			i, field, line, cc1, cc2);
+		if (field == 1)
+			line = (top_bit_value)?line+10:line+273;
+		else if (field == 2)
+			line = (top_bit_value)?line+273:line+10;
+		else
+			continue;
+
+		if (line == 21)
+		{
+			cc_data[array_position] = 4;
+			cc_data[array_position + 1] = scte20_get_char(cc1);
+			cc_data[array_position + 2] = scte20_get_char(cc2);
+			array_position += 3;
+			cc_count++;
+		}
+		else if (line == 284)
+		{
+			cc_data[array_position] = 4|1;
+			cc_data[array_position + 1] = scte20_get_char(cc1);
+			cc_data[array_position + 2] = scte20_get_char(cc2);
+			array_position += 3;
+			cc_count++;
+		}
+		else
+			continue;
+	}
+	cc_data[5] = 0x40 |cc_count;
+	size = 7 + cc_count*3;
+
+#if 0
+	for (i=0; i<size; i++)
+			sprintf(display_buffer+3*i, " %02x", cc_data[i]);
+		//AM_DEBUG(0, "scte_write_buffer len: %d data: %s", size, display_buffer);
+#endif
+	if (cc_count > 0)
+		aml_add_cc_data(dev, ref, ptype, cc_data, size, pts, meta_info->vpts_valid,
+			meta_info->duration);
+error:
+	return len;
+}
+
+static int aml_process_mpeg_userdata(AM_USERDATA_Device_t *dev, uint8_t *data, int len, struct userdata_meta_info_t* meta_info)
+{
+	AM_UDDrvData *ud = dev->drv_data;
+	uint8_t *pd = data;
+	int left = len;
+	int r = 0;
+	int i;
+	int package_count = 0;
+	int userdata_length;
+	int flag;
+	uint32_t pts;
+
+	flag = meta_info->flags;
+	pts = meta_info->vpts;
+
+	while (left >= (int)sizeof(aml_ud_header_t)) {
+		aml_ud_header_t *hdr = (aml_ud_header_t*)pd;
+		int ref, ptype;
+
+		if (MOD_ON_CC(ud->mode) && IS_ATSC(hdr->atsc_flag) ) {
+			aml_ud_header_t *nhdr;
+			uint8_t *pp, t;
+			uint32_t v;
+			int pl;
+
+			pp = (uint8_t*)&hdr->atsc_flag;
+			pl = 8;
+
+			v = (pd[4] << 24) | (pd[5] << 16) | (pd[6] << 8) | pd[7];
+			ref   = (v >> 16) & 0x3ff;
+			ptype = (v >> 26) & 7;
+
+			/* We read one packet in one time, so treat entire buffer */
+			if (!(flag & (1<<2)))
+				return len;
+
+			userdata_length = len-r-8;
+			aml_mpeg_userdata_package(dev, ref, ptype, pp, userdata_length, pts,
+				meta_info->vpts_valid, meta_info->duration);
+			r = len;
+
+			break;
+		} else if (MOD_ON_AFD(ud->mode) && IS_AFD(hdr->atsc_flag)) {
+			uint8_t *pafd_hdr = (uint8_t*)hdr->atsc_flag;
+			AM_USERDATA_AFD_t afd = *((AM_USERDATA_AFD_t *)(pafd_hdr + 4));
+			afd.reserved = afd.pts = 0;
+			AM_EVT_Signal(dev->dev_no, AM_USERDATA_EVT_AFD, (void*)&afd);
+			pd   += 8;
+			left -= 8;
+			r	+= 8;
+			break;
+		} else {
+			pd   += 8;
+			left -= 8;
+			r	+= 8;
+		}
+	}
+
+	return r;
+}
+
+static void aml_h264_userdata_package(AM_USERDATA_Device_t *dev, int poc, int type, uint8_t *p, int len, uint32_t
+	pts, int pts_valid, uint32_t duration)
+{
+	UNUSED(type);
+	AM_UDDrvData *ud = dev->drv_data;
+	AM_CCData *cc;
+
+	//if (poc == 0)
+		//aml_flush_cc_data(dev);
+
+	aml_add_cc_data(dev, poc, I_TYPE, p, len, pts, pts_valid, duration);
+
+	cc = ud->cc_list;
+	while (cc) {
+		if (am_get_video_pts() > cc->pts)
+		{
+			aml_write_userdata(dev, cc->buf, cc->size, cc->pts, cc->pts_valid, cc->duration);
+
+			ud->curr_poc = cc->poc;
+
+			//If node is chain head, reset chain head
+			if (cc == ud->cc_list)
+			{
+				ud->cc_list = cc->next;
+			}
+			else
+			{
+				//Delete node from chain
+				AM_CCData *cc_tmp = ud->cc_list;
+				while (cc_tmp)
+				{
+					if (cc_tmp->next == cc)
+					{
+						cc_tmp->next = cc->next;
+						break;
+					}
+					else
+						cc_tmp = cc_tmp->next;
+				}
+			}
+
+			cc->next = ud->free_list;
+			ud->free_list = cc;
+			ud->cc_num --;
+
+			cc = ud->cc_list;
+		}
+		else
+		{
+			cc = cc->next;
+		}
+	}
+}
+
+static int aml_process_h264_userdata(AM_USERDATA_Device_t *dev, uint8_t *data, int len, struct userdata_meta_info_t* meta_info)
+{
+	AM_UDDrvData *ud = dev->drv_data;
+	int fd = ud->fd;
+	uint8_t *pd = data;
+	int left = len;
+	int r = 0;
+	int poc;
+	uint32_t pts;
+
+	poc = meta_info->poc_number;
+	pts = meta_info->vpts;
+
+	while (left >= 8) {
+		if (MOD_ON_CC(ud->mode)
+			&& ((IS_H264(pd) || IS_DIRECTV(pd) || IS_AVS(pd)))) {
+			int hdr = (ud->format == H264_CC_TYPE) ? 3 : 0;
+			int pl;
+
+			pd += hdr;
+
+			pl = 8 + (pd[5] & 0x1f) * 3;
+
+			if (pl + hdr > left) {
+				break;
+			}
+
+			//AM_DEBUG(0, "CC poc_number:%x hdr:%d pl:%d", poc, hdr, pl);
+			if (poc == 0) {
+				aml_flush_cc_data(dev);
+			}
+
+			//aml_add_cc_data(dev, poc, I_TYPE, pd, pl, pts, meta_info->vpts_valid,
+			//	meta_info->duration);
+
+			//aml_add_cc_data(dev, poc, I_TYPE, userdata_with_pts, pl+4);
+			aml_h264_userdata_package(dev, poc, I_TYPE, pd, pl, pts, meta_info->vpts_valid,
+				meta_info->duration);
+
+			pd   += pl;
+			left -= pl + hdr;
+			r    += pl + hdr;
+		} else if (MOD_ON_AFD(ud->mode) && IS_H264_AFD(pd)) {
+			AM_USERDATA_AFD_t afd = *((AM_USERDATA_AFD_t*)(pd + 7));
+			afd.reserved = afd.pts = 0;
+			AM_EVT_Signal(dev->dev_no, AM_USERDATA_EVT_AFD, (void*)&afd);
+			pd   += 8;
+			left -= 8;
+			r    += 8;
+			break;
+		} else {
+			pd   += 8;
+			left -= 8;
+			r    += 8;
+		}
+	}
+
+	return r;
+}
+
+static void* aml_userdata_thread (void *arg)
+{
+	AM_USERDATA_Device_t *dev = (AM_USERDATA_Device_t*)arg;
+	AM_UDDrvData *ud = dev->drv_data;
+	int fd = ud->fd;
+	int r, ret, i;
+	struct pollfd pfd;
+	uint8_t data[MAX_CC_DATA_LEN];
+	uint8_t *pd = data;
+#if 0
+	char display_buffer[10*1024];
+#endif
+	int left = 0;
+	int flush = 1;
+	int vdec_ids;
+	int read_vdec_id;
+	struct userdata_param_t user_para_info;
+
+	pfd.events = POLLIN|POLLERR;
+	pfd.fd = fd;
+
+	while (ud->running) {
+		//If scte and mpeg both exist, we need to ignore scte cc data,
+		//so we need to check cc type every time.
+		left = 0;
+
+		ret = poll(&pfd, 1, USERDATA_POLL_TIMEOUT);
+		AM_DEBUG(AM_DEBUG_LEVEL, "userdata after poll ret %d", ret);
+		if (!ud->running)
+			break;
+		if (ret != 1)
+			continue;
+		if (!(pfd.revents & POLLIN))
+			continue;
+
+		//For multi-instances support
+		vdec_ids = 0;
+
+		if (-1 == ioctl(fd, AMSTREAM_IOC_UD_AVAIBLE_VDEC, &vdec_ids)) {
+			AM_DEBUG(AM_DEBUG_LEVEL, "get avaible vdec failed");
+			continue;
+		} else {
+			AM_DEBUG(AM_DEBUG_LEVEL, "get avaible vdec OK: 0x%x\n", vdec_ids);
+		}
+
+		read_vdec_id = ffs(vdec_ids) - 1;
+
+		if (flush) {
+			ioctl(fd, AMSTREAM_IOC_UD_FLUSH_USERDATA, &read_vdec_id);
+			flush = 0;
+			continue;
+		}
+
+		do {
+			if (!ud->running)
+				break;
+
+			if (left < 8) {
+				memset(&user_para_info, 0, sizeof(struct userdata_param_t));
+				user_para_info.pbuf_addr = (void*)(size_t)data;
+				user_para_info.buf_len = sizeof(data);
+				user_para_info.instance_id = read_vdec_id;
+
+				if (-1 == ioctl(fd, AMSTREAM_IOC_UD_BUF_READ, &user_para_info))
+					AM_DEBUG(0, "call AMSTREAM_IOC_UD_BUF_READ failed\n");
+	//			AM_DEBUG(0, "vdec_id %d real_id %d ioctl left data: %d",
+	//			vdec_ids, read_vdec_id, user_para_info.meta_info.records_in_que);
+
+				r = user_para_info.data_size;
+				r = (r > MAX_CC_DATA_LEN) ? MAX_CC_DATA_LEN : r;
+
+				if (r <= 0)
+					continue;
+				aml_swap_data(data + left, r);
+				left += r;
+				pd = data;
+			}
+#if 0
+			for (i=0; i<left; i++)
+				sprintf(&display_buffer[i*3], " %02x", data[i]);
+			AM_DEBUG(0, "fmt %d ud_aml_buffer: %s", ud->vfmt, display_buffer);
+#endif
+			ud->format = INVALID_TYPE;
+			while (ud->format == INVALID_TYPE ||
+							IS_AFD_TYPE(ud->format))
+			{
+				if (left < 8)
+					break;
+
+				ud->format = aml_check_userdata_format(pd, ud->vfmt, left);
+				if (!IS_CC_TYPE(ud->format) &&
+					!IS_AFD_TYPE(ud->format))
+				{
+					pd   += 8;
+					left -= 8;
+				}
+				else
+					break;
+			}
+
+			if ((ud->format == MPEG_CC_TYPE) || (ud->format == MPEG_AFD_TYPE)) {
+				ud->scte_enable = 0;
+				r = aml_process_mpeg_userdata(dev, pd, left, &user_para_info.meta_info);
+			} else if (ud->format == SCTE_CC_TYPE) {
+				if (ud->scte_enable == 1)
+					r = aml_process_scte_userdata(dev, pd, left, &user_para_info.meta_info);
+				else
+					r = left;
+			} else if (ud->format != INVALID_TYPE) {
+				r = aml_process_h264_userdata(dev, pd, left, &user_para_info.meta_info);
+			} else {
+				r = left;
+			}
+
+		if ((data != pd + r) && (r < left)) {
+			memmove(data, pd + r, left - r);
+		}
+
+		left -= r;
+		}while(user_para_info.meta_info.records_in_que > 1 || (left >= 8));
+	}
+	AM_DEBUG(0, "aml userdata thread exit");
+	return NULL;
+}
+
+static AM_ErrorCode_t aml_open(AM_USERDATA_Device_t *dev, const AM_USERDATA_OpenPara_t *para)
+{
+	AM_UDDrvData *ud = malloc(sizeof(AM_UDDrvData));
+	int r;
+
+	if (!ud) {
+		AM_DEBUG(0, "not enough memory");
+		return AM_USERDATA_ERR_NO_MEM;
+	}
+
+	ud->fd = open("/dev/amstream_userdata", O_RDONLY);
+	if (ud->fd == -1) {
+		AM_DEBUG(0, "cannot open userdata device");
+		free(ud);
+		return AM_USERDATA_ERR_CANNOT_OPEN_DEV;
+	}
+	ud->vfmt = para->vfmt;
+	ud->format	= INVALID_TYPE;
+	ud->cc_list   = NULL;
+	ud->free_list = NULL;
+	ud->running   = AM_TRUE;
+	ud->cc_num	= 0;
+	ud->curr_poc  = -1;
+	ud->scte_enable = 1;
+	if (!para->cc_default_stop)
+		ud->mode = AM_USERDATA_MODE_CC;
+
+	r = pthread_create(&ud->th, NULL, aml_userdata_thread, (void*)dev);
+	if (r) {
+		AM_DEBUG(0, "create userdata thread failed");
+		close(ud->fd);
+		free(ud);
+		return AM_USERDATA_ERR_SYS;
+	}
+	AM_SigHandlerInit();
+
+	dev->drv_data = ud;
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t aml_close(AM_USERDATA_Device_t *dev)
+{
+	AM_UDDrvData *ud = dev->drv_data;
+	AM_CCData *cc, *cc_next;
+
+	ud->running = AM_FALSE;
+	pthread_kill(ud->th, SIGALRM);
+	pthread_join(ud->th, NULL);
+	close(ud->fd);
+
+	for (cc = ud->cc_list; cc; cc = cc_next) {
+		cc_next = cc->next;
+		aml_free_cc_data(cc);
+	}
+
+	for (cc = ud->free_list; cc; cc = cc_next) {
+		cc_next = cc->next;
+		aml_free_cc_data(cc);
+	}
+
+
+	free (ud);
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t aml_set_mode(AM_USERDATA_Device_t *dev, int mode)
+{
+	AM_UDDrvData *ud = dev->drv_data;
+
+	if (MOD_ON_CC(mode) != MOD_ON_CC(ud->mode)) {
+		if (MOD_ON_CC(mode)) {
+			ud->mode |= AM_USERDATA_MODE_CC;
+		} else {
+			ud->mode &= ~AM_USERDATA_MODE_CC;
+		}
+	}
+
+	if (MOD_ON_AFD(mode) != MOD_ON_AFD(ud->mode)) {
+		if (MOD_ON_AFD(mode)) {
+			ud->mode |= AM_USERDATA_MODE_AFD;
+		} else {
+			ud->mode &= ~AM_USERDATA_MODE_AFD;
+		}
+	}
+
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t aml_get_mode(AM_USERDATA_Device_t *dev, int *mode)
+{
+	AM_UDDrvData *ud = dev->drv_data;
+	*mode = ud->mode;
+	return AM_SUCCESS;
+}
diff --git a/test/am_ca_key_test/inject_record_t5d/am_userdata/emu/Makefile b/test/am_ca_key_test/inject_record_t5d/am_userdata/emu/Makefile
new file mode 100644
index 0000000..b9a90bb
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_userdata/emu/Makefile
@@ -0,0 +1,8 @@
+BASE=../../..
+
+include $(BASE)/rule/def.mk
+
+O_TARGET=emu
+emu_SRCS=emu.c
+
+include $(BASE)/rule/rule.mk
diff --git a/test/am_ca_key_test/inject_record_t5d/am_userdata/emu/emu.c b/test/am_ca_key_test/inject_record_t5d/am_userdata/emu/emu.c
new file mode 100644
index 0000000..94c7613
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/am_userdata/emu/emu.c
@@ -0,0 +1,1283 @@
+#ifdef _FORTIFY_SOURCE
+#undef _FORTIFY_SOURCE
+#endif
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief  emu user data
+ *
+ * \author Xia Lei Peng <leipeng.xia@amlogic.com>
+ * \date 2010-12-13: create the document
+ ***************************************************************************/
+
+#define AM_DEBUG_LEVEL 2
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <am_debug.h>
+#include "../am_userdata_internal.h"
+#include <am_dvr.h>
+#include <am_dmx.h>
+#include "../../am_adp_internal.h"
+#include <limits.h>
+#include <stddef.h>
+
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+#define likely(expr) (expr)
+#define unlikely(expr) (expr)
+
+
+#define N_ELEMENTS(array) (sizeof (array) / sizeof ((array)[0]))
+#define CLEAR(var) memset (&(var), 0, sizeof (var))
+
+/* FIXME __typeof__ is a GCC extension. */
+#undef SWAP
+#define SWAP(x, y)							\
+do {									\
+	__typeof__ (x) _x = x;						\
+	x = y;								\
+	y = _x;								\
+} while (0)
+
+#undef MIN
+#define MIN(x, y) ({							\
+	__typeof__ (x) _x = (x);					\
+	__typeof__ (y) _y = (y);					\
+	(void)(&_x == &_y); /* warn if types do not match */		\
+	/* return */ (_x < _y) ? _x : _y;				\
+})
+
+#undef MAX
+#define MAX(x, y) ({							\
+	__typeof__ (x) _x = (x);					\
+	__typeof__ (y) _y = (y);					\
+	(void)(&_x == &_y); /* warn if types do not match */		\
+	/* return */ (_x > _y) ? _x : _y;				\
+})
+
+#undef PARENT
+#define PARENT(_ptr, _type, _member) ({					\
+	__typeof__ (&((_type *) 0)->_member) _p = (_ptr);		\
+	(_p != 0) ? (_type *)(((char *) _p) - offsetof (_type,		\
+	  _member)) : (_type *) 0;					\
+})
+
+/****************************************************************************
+ * Static data definitions
+ ***************************************************************************/
+
+static AM_ErrorCode_t emu_open(AM_USERDATA_Device_t *dev, const AM_USERDATA_OpenPara_t *para);
+static AM_ErrorCode_t emu_close(AM_USERDATA_Device_t *dev);
+
+const AM_USERDATA_Driver_t emu_ud_drv = {
+.open  			= emu_open,
+.close 			= emu_close,
+};
+
+
+
+enum start_code {
+	PICTURE_START_CODE = 0x00,
+	/* 0x01 ... 0xAF slice_start_code */
+	/* 0xB0 reserved */
+	/* 0xB1 reserved */
+	USER_DATA_START_CODE = 0xB2,
+	SEQUENCE_HEADER_CODE = 0xB3,
+	SEQUENCE_ERROR_CODE = 0xB4,
+	EXTENSION_START_CODE = 0xB5,
+	/* 0xB6 reserved */
+	SEQUENCE_END_CODE = 0xB7,
+	GROUP_START_CODE = 0xB8,
+	/* 0xB9 ... 0xFF system start codes */
+	PRIVATE_STREAM_1 = 0xBD,
+	PADDING_STREAM = 0xBE,
+	PRIVATE_STREAM_2 = 0xBF,
+	AUDIO_STREAM_0 = 0xC0,
+	AUDIO_STREAM_31 = 0xDF,
+	VIDEO_STREAM_0 = 0xE0,
+	VIDEO_STREAM_15 = 0xEF,
+};
+
+enum extension_start_code_identifier {
+	/* 0x0 reserved */
+	SEQUENCE_EXTENSION_ID = 0x1,
+	SEQUENCE_DISPLAY_EXTENSION_ID = 0x2,
+	QUANT_MATRIX_EXTENSION_ID = 0x3,
+	COPYRIGHT_EXTENSION_ID = 0x4,
+	SEQUENCE_SCALABLE_EXTENSION_ID = 0x5,
+	/* 0x6 reserved */
+	PICTURE_DISPLAY_EXTENSION_ID = 0x7,
+	PICTURE_CODING_EXTENSION_ID = 0x8,
+	PICTURE_SPATIAL_SCALABLE_EXTENSION_ID = 0x9,
+	PICTURE_TEMPORAL_SCALABLE_EXTENSION_ID = 0xA,
+	/* 0xB ... 0xF reserved */
+};
+
+enum picture_coding_type {
+	/* 0 forbidden */
+	I_TYPE = 1,
+	P_TYPE = 2,
+	B_TYPE = 3,
+	D_TYPE = 4,
+	/* 5 ... 7 reserved */
+};
+
+enum picture_structure {
+	/* 0 reserved */
+	TOP_FIELD = 1,
+	BOTTOM_FIELD = 2,
+	FRAME_PICTURE = 3
+};
+
+/* PTSs and DTSs are 33 bits wide. */
+#define TIMESTAMP_MASK (((int64_t) 1 << 33) - 1)
+
+struct packet {
+	/* Offset in bytes from the buffer start. */
+	unsigned int			offset;
+
+	/* Packet and payload size in bytes. */
+	unsigned int			size;
+	unsigned int			payload;
+
+	/* Decoding and presentation time stamp and display duration
+	   of this packet. */
+	int64_t				dts;
+	int64_t				pts;
+	int64_t				duration;
+
+	/* Cut the stream at this packet. */
+	AM_Bool_t			splice;
+
+	/* Data is missing before this packet but the producer will
+	   correct that later. */
+	AM_Bool_t			data_lost;
+};
+
+struct buffer {
+	uint8_t *			base;
+
+	/* Capacity of the buffer in bytes. */
+	unsigned int			capacity;
+
+	/* Offset in bytes from base where the next data will be
+	   stored. */
+	unsigned int			in;
+
+	/* Offset in bytes from base where the next data will be
+	   removed. */ 
+	unsigned int			out;
+};
+
+#define MAX_PACKETS 64
+
+struct pes_buffer {
+	uint8_t *			base;
+
+	/* Capacity of the buffer in bytes. */
+	unsigned int			capacity;
+
+	/* Offset in bytes from base where the next data will be stored. */
+	unsigned int			in;
+
+	/* Information about the packets in the buffer.
+	   packet[0].offset is the offset in bytes from base
+	   where the next data will be removed. */
+	struct packet			packet[MAX_PACKETS];
+
+	/* Number of packets in the packet[] array. packet[0] must not
+	   be removed unless n_packets >= 2. */
+	unsigned int			n_packets;
+};
+
+struct pes_multiplexer {
+	AM_Bool_t			new_file;
+	unsigned int			b_state;
+
+	time_t				minicut_end;
+
+	FILE *				minicut_fp;
+};
+
+struct audio_es_packetizer {
+	/* Test tap. */
+	const char *			option_audio_es_tap_file_name;
+	FILE *				audio_es_tap_fp;
+
+	struct buffer			ac3_buffer;
+	struct pes_buffer		pes_buffer;
+
+	/* Number of bytes we want to examine at pes_buffer.in. */
+	unsigned int			need;
+
+	/* Estimated PTS of the next/current AC3 frame (pts or
+	   pes_packet_pts plus previous frame duration), -1 if no PTS
+	   was received yet. */
+	int64_t				pts;
+
+	/* Next/current AC3 frame is the first received frame. */
+	AM_Bool_t			first_frame;
+
+	/* Data may have been lost between the previous and
+	   next/current AC3 frame. */
+	AM_Bool_t			data_lost;
+
+	uint64_t			pes_audio_bit_rate;
+};
+
+struct video_es_packetizer {
+	struct pes_buffer		pes_buffer;
+	int				sequence_header_offset;
+	unsigned int			packet_filled;
+	uint8_t				pes_packet_header_6;
+	uint64_t			pes_video_bit_rate;
+	AM_Bool_t			aligned;
+};
+
+struct audio_pes_decoder {
+	struct buffer			buffer;
+
+	unsigned int			need;
+	unsigned int			look_ahead;
+};
+
+struct video_recorder {
+	struct audio_pes_decoder	apesd;
+
+	struct video_es_packetizer	vesp;
+
+	struct audio_es_packetizer	aesp;
+
+	struct pes_multiplexer		pm;
+
+	/* TS recorder */
+
+	unsigned int			pat_cc;
+	unsigned int			pmt_cc;
+
+	time_t				minicut_end;
+	FILE *				minicut_fp;
+};
+
+enum received_blocks {
+	RECEIVED_PES_PACKET		= (1 << 0),
+	RECEIVED_PICTURE		= (1 << 1),
+	RECEIVED_PICTURE_EXT		= (1 << 2),
+	RECEIVED_MPEG_CC_DATA		= (1 << 3)
+};
+
+struct video_es_decoder {
+	/* Test tap. */
+	const char *			option_video_es_all_tap_file_name;
+	const char *			option_video_es_tap_file_name;
+
+	FILE *				video_es_tap_fp;
+
+	/* Video elementary stream buffer. */
+	struct buffer			buffer;
+
+	unsigned int			min_bytes_valid;
+
+	/* Number of bytes after buffer.out which have already
+	   been scanned for a start code prefix. */
+	unsigned int			skip;
+
+	/* Last received start code, < 0 if none. If valid
+	   buffer.out points at the first start code prefix
+	   byte. */
+	enum start_code			last_start_code;
+
+	/* The decoding and presentation time stamp of the
+	   current picture. Only the lowest 33 bits are
+	   valid. < 0 if no PTS or DTS was received or the PES
+	   packet header was malformed. */
+	int64_t				pts;
+	int64_t				dts;
+
+	/* For debugging. */
+	uint64_t			n_pictures_received;
+
+	/* Parameters of the current picture. */
+	enum picture_coding_type	picture_coding_type;
+	enum picture_structure		picture_structure;
+	unsigned int			picture_temporal_reference;
+
+	/* Set of the data blocks we received so far. */
+	enum received_blocks		received_blocks;
+
+	/* Describes the contents of the reorder_buffer[]:
+	   Bit 0 - a top field in reorder_buffer[0],
+	   Bit 1 - a bottom field in reorder_buffer[1],
+	   Bit 2 - a frame in reorder_buffer[0]. Only the
+	   combinations 0, 1, 2, 3, 4 are valid. */
+	unsigned int			reorder_pictures;
+
+	/* The PTS (as above) of the data in the reorder_buffer. */
+	int64_t				reorder_pts[2];
+
+	unsigned int			reorder_n_bytes[2];
+
+	/* Buffer to convert picture user data from coded
+	   order to display order, for the top and bottom
+	   field. Maximum size required: 11 + cc_count * 3,
+	   where cc_count = 0 ... 31. */
+	uint8_t				reorder_buffer[2][128];
+};
+
+struct ts_decoder {
+	/* TS PID of the video [0] and audio [1] stream. */
+	unsigned int			pid[2];
+
+	/* Next expected video and audio TS packet continuity
+	   counter. Only the lowest four bits are valid. < 0
+	   if no continuity counter has been received yet. */
+	int				next_ts_cc[2];
+
+	/* One or more TS packets were lost. */
+	AM_Bool_t			data_lost;
+}					tsd;
+
+
+typedef struct
+{
+	int fd;
+	int vpid;
+	AM_Bool_t running;
+	pthread_t thread;
+	struct ts_decoder tsd;
+	struct video_es_decoder vesd;
+
+	AM_USERDATA_Device_t *dev;
+}emu_ud_drv_data_t;
+
+
+/****************************************************************************
+ * Static functions
+ ***************************************************************************/
+
+static int get_vid_pid(emu_ud_drv_data_t *drv_data)
+{
+#if 1
+	if (drv_data->vpid == 0x1fff){
+		int handle;
+	    int size;
+	    char s[1024];
+		char *str;
+
+	    handle = open("/sys/class/amstream/ports", O_RDONLY);
+	    if (handle < 0) {
+	        return -1;
+	    }
+	    size = read(handle, s, sizeof(s));
+	    if (size > 0) {
+	        str = strstr(s, "amstream_mpts");
+			if (str != NULL){
+				str = strstr(str, "Vid:");
+				if (str != NULL){
+					drv_data->vpid = atoi(str+4);
+				}
+			}
+	    }
+	    close(handle);
+	}
+#else
+	//drv_data->vpid = 65;
+	drv_data->vpid = 33;
+#endif
+	return drv_data->vpid;
+}
+
+
+static void
+init_buffer			(struct buffer *	b,
+				 unsigned int		capacity)
+{
+	b->capacity = capacity;
+	b->base = malloc (capacity);
+	b->in = 0;
+	b->out = 0;
+}
+
+static AM_Bool_t
+decode_time_stamp		(int64_t *		ts,
+				 const uint8_t *	buf,
+				 unsigned int		marker)
+{
+	/* ISO 13818-1 Section 2.4.3.6 */
+
+	if (0 != ((marker ^ buf[0]) & 0xF1))
+		return AM_FALSE;
+
+	if (NULL != ts) {
+		unsigned int a, b, c;
+
+		/* marker [4], TS [32..30], marker_bit,
+		   TS [29..15], marker_bit,
+		   TS [14..0], marker_bit */
+		a = (buf[0] >> 1) & 0x7;
+		b = (buf[1] * 256 + buf[2]) >> 1;
+		c = (buf[3] * 256 + buf[4]) >> 1;
+
+		*ts = ((int64_t) a << 30) + (b << 15) + (c << 0);
+	}
+
+	return AM_TRUE;
+}
+
+
+static unsigned int
+mpeg2_crc			(const uint8_t *	buf,
+				 unsigned int		n_bytes)
+{
+	static uint32_t crc_table[256];
+	unsigned int crc;
+	unsigned int i;
+
+	/* ISO 13818-1 Annex B. */
+
+	if (unlikely (0 == crc_table[255])) {
+		const unsigned int poly = 
+			((1 << 26) | (1 << 23) | (1 << 22) | (1 << 16) |
+			 (1 << 12) | (1 << 11) | (1 << 10) | (1 << 8) |
+			 (1 << 7) | (1 << 5) | (1 << 4) | (1 << 2) |
+			 (1 << 1) | 1);
+		unsigned int c, j;
+
+		for (i = 0; i < 256; ++i) {
+			c = i << 24;
+			for (j = 0; j < 8; ++j) {
+				if (c & (1 << 31))
+					c = (c << 1) ^ poly;
+				else
+					c <<= 1;
+			}
+			crc_table[i] = c;
+		}
+		assert (0 != crc_table[255]);
+	}
+
+	crc = -1;
+	for (i = 0; i < n_bytes; ++i)
+		crc = crc_table[(buf[i] ^ (crc >> 24)) & 0xFF] ^ (crc << 8);
+
+	return crc & 0xFFFFFFFFUL;
+}
+
+
+/* Video elementary stream decoder. */
+
+static void
+vesd_reorder_decode_cc_data	(struct video_es_decoder *vd,
+				 const uint8_t *	buf,
+				 unsigned int		n_bytes)
+{
+	emu_ud_drv_data_t *drv_data = PARENT (vd, emu_ud_drv_data_t, vesd);
+	AM_USERDATA_Device_t *dev = drv_data->dev;
+	
+	n_bytes = MIN (n_bytes, (unsigned int)
+		       sizeof (vd->reorder_buffer[0]));
+
+	switch (vd->picture_structure) {
+	case FRAME_PICTURE:
+		AM_DEBUG(4, "FRAME_PICTURE, 0x%02x", vd->reorder_pictures);
+		if (0 != vd->reorder_pictures) {
+			if (vd->reorder_pictures & 5) {
+				/* Top field or top and bottom field. */
+				dev->write_package(dev, 
+						&vd->reorder_buffer[0][4],
+						vd->reorder_n_bytes[0]-4);
+			}
+			if (vd->reorder_pictures & 2) {
+				/* Bottom field. */
+				dev->write_package(dev, 
+						&vd->reorder_buffer[1][4],
+						vd->reorder_n_bytes[1]-4);
+			}
+		}
+
+		memcpy (vd->reorder_buffer[0], buf, n_bytes);
+		vd->reorder_n_bytes[0] = n_bytes;
+		vd->reorder_pts[0] = vd->pts;
+
+		/* We have a frame. */
+		vd->reorder_pictures = 4;
+
+		break;
+
+	case TOP_FIELD:
+		AM_DEBUG(4, "TOP_FIELD, 0x%02x", vd->reorder_pictures);
+		if (vd->reorder_pictures >= 3) {
+			/* Top field or top and bottom field. */
+			dev->write_package(dev, &vd->reorder_buffer[0][4], vd->reorder_n_bytes[0]-4);
+
+			vd->reorder_pictures &= 2;
+		} else if (1 == vd->reorder_pictures) {
+			/* Apparently we missed a bottom field. */
+		}
+
+		memcpy (vd->reorder_buffer[0], buf, n_bytes);
+		vd->reorder_n_bytes[0] = n_bytes;
+		vd->reorder_pts[0] = vd->pts;
+
+		/* We have a top field. */
+		vd->reorder_pictures |= 1;
+
+		break;
+
+	case BOTTOM_FIELD:
+		AM_DEBUG(4, "BOTTOM_FIELD, 0x%02x", vd->reorder_pictures);
+		if (vd->reorder_pictures >= 3) {
+			if (vd->reorder_pictures >= 4) {
+				/* Top and bottom field. */
+				dev->write_package(dev, 
+						&vd->reorder_buffer[0][4],
+						vd->reorder_n_bytes[0]-4);
+			} else {
+				/* Bottom field. */
+				dev->write_package(dev, 
+						&vd->reorder_buffer[1][4],
+						vd->reorder_n_bytes[1]-4);
+			}
+
+			vd->reorder_pictures &= 1;
+		} else if (2 == vd->reorder_pictures) {
+			/* Apparently we missed a top field. */
+		}
+
+		memcpy (vd->reorder_buffer[1], buf, n_bytes);
+		vd->reorder_n_bytes[1] = n_bytes;
+		vd->reorder_pts[1] = vd->pts;
+
+		/* We have a bottom field. */
+		vd->reorder_pictures |= 2;
+
+		break;
+
+	default: /* invalid */
+		break;
+	}
+}
+
+static void
+vesd_user_data			(struct video_es_decoder *vd,
+				 const uint8_t *	buf,
+				 unsigned int		min_bytes_valid)
+{
+	unsigned int ATSC_identifier;
+	unsigned int user_data_type_code;
+	unsigned int cc_count;
+	emu_ud_drv_data_t *drv_data = PARENT (vd, emu_ud_drv_data_t, vesd);
+	AM_USERDATA_Device_t *dev = drv_data->dev;
+
+	/* ATSC A/53 Part 4:2007 Section 6.2.2 */
+
+	if (0 == (vd->received_blocks & RECEIVED_PICTURE)) {
+		/* Either sequence or group user_data, or we missed
+		   the picture_header. */
+		vd->received_blocks &= ~RECEIVED_PES_PACKET;
+		return;
+	}
+
+	/* start_code_prefix [24], start_code [8],
+	   ATSC_identifier [32], user_data_type_code [8] */
+	if (min_bytes_valid < 9)
+		return;
+
+	ATSC_identifier = ((buf[4] << 24) | (buf[5] << 16) |
+			   (buf[6] << 8) | buf[7]);
+	if (0x47413934 != ATSC_identifier)
+		return;
+
+	user_data_type_code = buf[8];
+	if (0x03 != user_data_type_code)
+		return;
+
+	/* ATSC A/53 Part 4:2007 Section 6.2.1: "No more than one
+	   user_data() structure using the same user_data_type_code
+	   [...] shall be present following any given picture
+	   header." */
+	if (vd->received_blocks & RECEIVED_MPEG_CC_DATA) {
+		/* Too much data lost. */
+		return;
+	}
+
+	vd->received_blocks |= RECEIVED_MPEG_CC_DATA;
+
+	/* reserved, process_cc_data_flag, zero_bit, cc_count [5],
+	   reserved [8] */
+	if (min_bytes_valid < 11)
+		return;
+
+	/* one_bit, reserved [4], cc_valid, cc_type [2],
+	   cc_data_1 [8], cc_data_2 [8] */
+	cc_count = buf[9] & 0x1F;
+
+	/* CEA 708-C Section 4.4 permits padding, so we have to see
+	   all cc_data elements. */
+	if (min_bytes_valid < 11 + cc_count * 3)
+		return;
+
+
+	/* CEA 708-C Section 4.4.1.1 */
+
+	switch (vd->picture_coding_type) {
+	case I_TYPE:
+	case P_TYPE:
+		AM_DEBUG(4, "%s, 0x%02x", vd->picture_coding_type==I_TYPE ? "I_TYPE" : "P_TYPE", vd->reorder_pictures);
+		vesd_reorder_decode_cc_data (vd, buf, min_bytes_valid);
+		break;
+
+	case B_TYPE:
+		AM_DEBUG(4, "B_TYPE, 0x%02x", vd->reorder_pictures);
+		/* To prevent a gap in the caption stream we must not
+		   decode B pictures until we have buffered both
+		   fields of the temporally following I or P picture. */
+		if (vd->reorder_pictures < 3) {
+			vd->reorder_pictures = 0;
+			break;
+		}
+
+		/* To do: If a B picture appears to have a higher
+		   temporal_reference than the picture it forward
+		   references we lost that I or P picture. */
+		{
+			dev->write_package(dev,  buf+4,
+					min_bytes_valid-4);
+		}
+
+		break;
+
+	default: /* invalid */
+		break;
+	}
+}
+
+static void
+vesd_extension			(struct video_es_decoder *vd,
+				 const uint8_t *	buf,
+				 unsigned int		min_bytes_valid)
+{
+	enum extension_start_code_identifier extension_start_code_identifier;
+
+	/* extension_start_code [32],
+	   extension_start_code_identifier [4],
+	   f_code [4][4], intra_dc_precision [2],
+	   picture_structure [2], ... */
+	if (min_bytes_valid < 7)
+		return;
+
+	extension_start_code_identifier =
+		(enum extension_start_code_identifier)(buf[4] >> 4);
+	if (PICTURE_CODING_EXTENSION_ID
+	    != extension_start_code_identifier)
+		return;
+
+	vd->picture_structure = (enum picture_structure)(buf[6] & 3);
+
+	vd->received_blocks |= RECEIVED_PICTURE_EXT;
+}
+
+static void
+vesd_picture_header		(struct video_es_decoder *vd,
+				 const uint8_t *	buf,
+				 unsigned int		min_bytes_valid)
+{
+	unsigned int c;
+
+	/* picture_start_code [32],
+	   picture_temporal_reference [10],
+	   picture_coding_type [3], ... */
+	if (min_bytes_valid < 6
+	    || vd->received_blocks != RECEIVED_PES_PACKET) {
+		/* Too much data lost. */
+		vd->received_blocks = 0;
+		return;
+	}
+
+	c = buf[4] * 256 + buf[5];
+	vd->picture_temporal_reference = (c >> 6) & 0x3FF;
+	vd->picture_coding_type = (enum picture_coding_type)((c >> 3) & 7);
+
+	vd->received_blocks = (RECEIVED_PES_PACKET |
+			       RECEIVED_PICTURE);
+
+	++vd->n_pictures_received;
+}
+
+static void
+vesd_pes_packet_header		(struct video_es_decoder *vd,
+				 const uint8_t *	buf,
+				 unsigned int		min_bytes_valid)
+{
+	unsigned int PES_packet_length;
+	unsigned int PTS_DTS_flags;
+	int64_t pts;
+
+
+	vd->pts = -1;
+	vd->dts = -1;
+
+	vd->received_blocks = 0;
+
+	/* packet_start_code_prefix [24], stream_id [8],
+	   PES_packet_length [16],
+
+	   '10', PES_scrambling_control [2], PES_priority,
+	   data_alignment_indicator, copyright, original_or_copy,
+
+	   PTS_DTS_flags [2], ESCR_flag, ES_rate_flag,
+	   DSM_trick_mode_flag, additional_copy_info_flag,
+	   PES_CRC_flag, PES_extension_flag,
+
+	   PES_header_data_length [8] */
+	if (min_bytes_valid < 9)
+		return;
+
+	PES_packet_length = buf[4] * 256 + buf[5];
+	PTS_DTS_flags = (buf[7] & 0xC0) >> 6;
+
+	/* ISO 13818-1 Section 2.4.3.7: In transport streams video PES
+	   packets do not carry data, they only contain the DTS/PTS of
+	   the following picture and PES_packet_length must be
+	   zero. */
+	if (0 != PES_packet_length)
+		return;
+
+	switch (PTS_DTS_flags) {
+	case 0: /* no timestamps */
+		return;
+
+	case 1: /* forbidden */
+		return;
+
+	case 2: /* PTS only */
+		if (min_bytes_valid < 14)
+			return;
+		if (!decode_time_stamp (&vd->pts, &buf[9], 0x21))
+			return;
+		break;
+
+	case 3: /* PTS and DTS */
+		if (min_bytes_valid < 19)
+			return;
+		if (!decode_time_stamp (&pts, &buf[9], 0x31))
+			return;
+		if (!decode_time_stamp (&vd->dts, &buf[14], 0x11))
+			return;
+		vd->pts = pts;
+		break;
+	}
+
+
+	vd->received_blocks = RECEIVED_PES_PACKET;
+}
+
+static void
+vesd_decode_block		(struct video_es_decoder *vd,
+				 unsigned int		start_code,
+				 const uint8_t *	buf,
+				 unsigned int		n_bytes,
+				 unsigned int		min_bytes_valid,
+				 AM_Bool_t		data_lost)
+{
+	UNUSED(n_bytes);
+
+	/* The CEA 608-C and 708-C Close Caption data is encoded in
+	   picture user data fields. ISO 13818-2 requires the start
+	   code sequence 0x00, 0xB5/8, (0xB5?, 0xB2?)*. To properly
+	   convert from coded order to display order we also need the
+	   picture_coding_type and picture_structure fields. */
+
+	if (likely (start_code <= 0xAF)) {
+		if (unlikely (0x00 == start_code) && !data_lost) {
+			vesd_picture_header (vd, buf, min_bytes_valid);
+		} else {
+			/* slice_start_code or data lost in or after
+			   the picture_header. */
+			/* For all we care the picture data is just
+			   useless filler prior to the next PES packet
+			   header, and we need an uninterrupted
+			   sequence from there to the next picture
+			   user_data to ensure the PTS, DTS,
+			   picture_temporal_reference,
+			   picture_coding_type, picture_structure and
+			   cc_data belong together. */
+			vd->received_blocks = 0;
+		}
+	} else if (USER_DATA_START_CODE == start_code) {
+		vesd_user_data (vd, buf, min_bytes_valid);
+	} else if (data_lost) {
+		/* Data lost in or after this block. */
+		vd->received_blocks = 0;
+	} else if (EXTENSION_START_CODE == start_code) {
+		vesd_extension (vd, buf, min_bytes_valid);
+	} else if (start_code >= VIDEO_STREAM_0
+		   && start_code <= VIDEO_STREAM_15) {
+		vesd_pes_packet_header (vd, buf, min_bytes_valid);
+	} else {
+		/* Should be a sequence_header or
+		   group_of_pictures_header. */
+
+		vd->received_blocks &= (1 << 0);
+	}
+}
+
+static unsigned int
+vesd_make_room			(struct video_es_decoder *vd,
+				 unsigned int		required)
+{
+	struct buffer *b;
+	unsigned int capacity;
+	unsigned int in;
+
+	b = &vd->buffer;
+	capacity = b->capacity;
+	in = b->in;
+
+	if (unlikely (in + required > capacity)) {
+		unsigned int consumed;
+		unsigned int unconsumed;
+
+		consumed = b->out;
+		unconsumed = in - consumed;
+		if (required > capacity - unconsumed) {
+			/* XXX make this a recoverable error. */
+			AM_DEBUG(1, "Video ES buffer overflow.\n");
+			return 0;
+		}
+		memmove (b->base, b->base + consumed, unconsumed);
+		in = unconsumed;
+		b->out = 0;
+	}
+
+	return in;
+}
+
+static void
+video_es_decoder		(struct video_es_decoder *vd,
+				 const uint8_t *	buf,
+				 unsigned int		n_bytes,
+				 AM_Bool_t		data_lost)
+{
+	const uint8_t *s;
+	const uint8_t *e;
+	const uint8_t *e_max;
+	unsigned int in;
+
+	/* This code searches for a start code and then decodes the
+	   data between the previous and the current start code. */
+
+	in = vesd_make_room (vd, n_bytes);
+
+	memcpy (vd->buffer.base + in, buf, n_bytes);
+	vd->buffer.in = in + n_bytes;
+
+	s = vd->buffer.base + vd->buffer.out + vd->skip;
+	e = vd->buffer.base + in + n_bytes - 4;
+	e_max = e;
+
+	if (unlikely (data_lost)) {
+		if (vd->min_bytes_valid >= UINT_MAX) {
+			vd->min_bytes_valid =
+				in - vd->buffer.out;
+		}
+
+		/* Data is missing after vd->buffer.base + in, so
+		   we must ignore apparent start codes crossing that
+		   boundary. */
+		e -= n_bytes;
+	}
+
+	for (;;) {
+		const uint8_t *b;
+		enum start_code start_code;
+		unsigned int n_bytes;
+		unsigned int min_bytes_valid;
+
+		for (;;) {
+			if (s >= e) {
+				/* Need more data. */
+
+				if (unlikely (s < e_max)) {
+					/* Skip over the lost data. */
+					s = e + 4;
+					e = e_max;
+					continue;
+				}
+
+				/* In the next iteration skip the
+				   bytes we already scanned. */
+				vd->skip = s - vd->buffer.base
+					- vd->buffer.out;
+
+				return;
+			}
+
+			if (likely (0 != (s[2] & ~1))) {
+				/* Not 000001 or xx0000 or xxxx00. */
+				s += 3;
+			} else if (0 != (s[0] | s[1]) || 1 != s[2]) {
+				++s;
+			} else {
+				break;
+			}
+		}
+
+		b = vd->buffer.base + vd->buffer.out;
+		n_bytes = s - b;
+		min_bytes_valid = n_bytes;
+		data_lost = AM_FALSE;
+
+		if (unlikely (vd->min_bytes_valid < UINT_MAX)) {
+			if (n_bytes < vd->min_bytes_valid) {
+				/* We found a new start code before
+				   the missing data. */
+				vd->min_bytes_valid -= n_bytes;
+			} else {
+				min_bytes_valid = vd->min_bytes_valid;
+				vd->min_bytes_valid = UINT_MAX;
+
+				/* Need a flag in case we lost data just
+				   before the next start code. */
+				data_lost = AM_TRUE;
+			}
+		}
+
+		start_code = vd->last_start_code;
+		if (likely ((int) start_code >= 0)) {
+			vesd_decode_block (vd, start_code, b,
+					   n_bytes, min_bytes_valid,
+					   data_lost);
+		}
+
+		/* Remove the data we just decoded from the
+		   buffer. Remember the position of the new start code
+		   we found, skip it and continue the search. */
+		vd->buffer.out = s - vd->buffer.base;
+		vd->last_start_code = (enum start_code) s[3];
+		s += 4;
+	}
+}
+
+static void
+reset_video_es_decoder		(struct video_es_decoder *vd)
+{
+	vd->buffer.in = 0;
+	vd->buffer.out = 0;
+
+	vd->min_bytes_valid = UINT_MAX;
+	vd->skip = 0;
+	vd->last_start_code = (enum start_code) -1;
+
+	vd->pts = -1;
+	vd->dts = -1;
+	vd->picture_coding_type = (enum picture_coding_type) -1;
+	vd->picture_structure = (enum picture_structure) -1;
+	vd->received_blocks = 0;
+	vd->reorder_pictures = 0;
+}
+
+static void
+init_video_es_decoder		(struct video_es_decoder *vd)
+{
+	CLEAR (*vd);
+
+	init_buffer (&vd->buffer, /* capacity */ 1 << 20);
+	reset_video_es_decoder (vd);
+}
+
+
+static void
+tsd_program			(emu_ud_drv_data_t *drv_data,
+				 const uint8_t		buf[188],
+				 unsigned int		pid,
+				 unsigned int		es_num)
+{
+	UNUSED(pid);
+	unsigned int adaptation_field_control;
+	unsigned int header_length;
+	unsigned int payload_length;
+	AM_Bool_t data_lost;
+
+	adaptation_field_control = (buf[3] & 0x30) >> 4;
+	if (likely (1 == adaptation_field_control)) {
+		header_length = 4;
+	} else if (3 == adaptation_field_control) {
+		unsigned int adaptation_field_length;
+
+		adaptation_field_length = buf[4];
+
+		/* Zero length is used for stuffing. */
+		if (adaptation_field_length > 0) {
+			unsigned int discontinuity_indicator;
+
+			/* ISO 13818-1 Section 2.4.3.5. Also the code
+			   below would be rather upset if
+			   header_length > packet_size. */
+			if (adaptation_field_length > 182) {
+				AM_DEBUG (2, "Invalid TS header ");
+				/* Possibly. */
+				drv_data->tsd.data_lost = AM_TRUE;
+				return;
+			}
+
+			/* ISO 13818-1 Section 2.4.3.5 */
+			discontinuity_indicator = buf[5] & 0x80;
+			if (discontinuity_indicator)
+				drv_data->tsd.next_ts_cc[es_num] = -1;
+		}
+
+		header_length = 5 + adaptation_field_length;
+	} else {
+		/* 0 == adaptation_field_control: invalid;
+		   2 == adaptation_field_control: no payload. */
+		/* ISO 13818-1 Section 2.4.3.3:
+		   continuity_counter shall not increment. */
+		return;
+	}
+
+	payload_length = 188 - header_length;
+
+	data_lost = drv_data->tsd.data_lost;
+
+	if (unlikely (0 != ((drv_data->tsd.next_ts_cc[es_num]
+			     ^ buf[3]) & 0x0F))) {
+		/* Continuity counter mismatch. */
+
+		if (drv_data->tsd.next_ts_cc[es_num] < 0) {
+			/* First TS packet. */
+		} else if (0 == (((drv_data->tsd.next_ts_cc[es_num] - 1)
+				  ^ buf[3]) & 0x0F)) {
+			/* ISO 13818-1 Section 2.4.3.3: Repeated packet. */
+			return;
+		} else {
+			AM_DEBUG (2, "TS continuity error ");
+			data_lost = AM_TRUE;
+		}
+	}
+
+	drv_data->tsd.next_ts_cc[es_num] = buf[3] + 1;
+	drv_data->tsd.data_lost = AM_FALSE;
+
+	if (0 == es_num) {
+		video_es_decoder (&drv_data->vesd, buf + header_length,
+				  payload_length, data_lost);
+	}
+}
+
+static void
+ts_decoder			(emu_ud_drv_data_t *drv_data, const uint8_t		buf[188])
+{
+	unsigned int pid;
+	unsigned int i;
+
+	if (unlikely (buf[1] & 0x80)) {
+		AM_DEBUG(1, "TS transmission error.\n");
+		return;
+	}
+
+	pid = (buf[1] * 256 + buf[2]) & 0x1FFF;
+
+	if (pid == get_vid_pid(drv_data))
+		tsd_program (drv_data, buf, pid, 0);
+}
+
+static void
+init_ts_decoder			(struct ts_decoder *	td)
+{
+	CLEAR (*td);
+
+	memset (&td->next_ts_cc, -1, sizeof (td->next_ts_cc));
+}
+
+static int read_ts_packet(const uint8_t *tsbuf, int tssize, uint8_t buf[188])
+{
+	int p = 0;
+	
+	/*Scan the sync byte*/
+	while(tsbuf[p]!=0x47)
+	{
+		p++;
+		if(p>=tssize)
+		{
+			return tssize;
+		}
+	}
+	
+	if(p!=0)
+		AM_DEBUG(1, "skip %d bytes", p);
+	
+	if ((tssize - p) >= 188)
+	{
+		memcpy(buf, tsbuf+p, 188);
+		p += 188;
+	}
+
+	return p;
+}
+
+#if 1
+static void* dvr_data_thread(void *arg)
+{
+	AM_USERDATA_Device_t *dev = (AM_USERDATA_Device_t*)arg;
+	emu_ud_drv_data_t *drv_data = (emu_ud_drv_data_t*)dev->drv_data;
+	int cnt, left, rp;
+	uint8_t buf[256*1024];
+	uint8_t pkt_buf[188];
+	uint8_t *p;
+	AM_DMX_OpenPara_t dpara;
+	AM_DVR_OpenPara_t para;
+	AM_DVR_StartRecPara_t spara;
+
+	memset(&dpara, 0, sizeof(dpara));
+	AM_DMX_Open(0, &dpara);
+	AM_DVR_Open(0, &para);
+	AM_DVR_SetSource(0, 0);
+	spara.pid_count = 1;
+	spara.pids[0] = get_vid_pid(drv_data);
+	AM_DVR_StartRecord(0, &spara);
+	
+	left = 0;
+	
+	while (drv_data->running)
+	{
+		cnt = AM_DVR_Read(0, buf+left, sizeof(buf)-left, 1000);
+		if (cnt <= 0)
+		{
+			AM_DEBUG(1, "No data available from DVR0");
+			usleep(200*1000);
+			continue;
+		}
+		cnt += left;
+		left = cnt;
+		p = buf;
+		AM_DEBUG(1, "read from DVR return %d bytes", cnt);
+		while (left >= 188)
+		{
+			pkt_buf[0] = 0;
+			//AM_DEBUG(1, "read 188 bytes ts packet");
+			rp = read_ts_packet(p, left, pkt_buf);
+			left -= rp;
+			p += rp;
+			
+			if (pkt_buf[0] == 0x47)
+				ts_decoder(drv_data, pkt_buf);
+		}
+		if (left > 0)
+			memmove(buf, buf+cnt-left, left);
+	}
+
+	AM_DVR_Close(0);
+	AM_DMX_Close(0);
+
+	AM_DEBUG(1, "Data thread for DVR0 now exit");
+
+	return NULL;
+}
+#else
+
+static void* dvr_data_thread(void *arg)
+{
+	AM_USERDATA_Device_t *dev = (AM_USERDATA_Device_t*)arg;
+	emu_ud_drv_data_t *drv_data = (emu_ud_drv_data_t*)dev->drv_data;
+	int cnt, left, rp;
+	uint8_t buf[256*1024];
+	uint8_t pkt_buf[188];
+	uint8_t *p;
+	//int fd = open("/mnt/sda1/DTV_CC_English_Spanish.ts", O_RDONLY);
+	int fd = open("/mnt/sda1/atsc-480i-TV-14.ts", O_RDONLY);
+	uint32_t total = 0;
+
+	if (fd == -1)
+	{
+		AM_DEBUG(1, "cannot open file");
+		return NULL;
+	}
+	
+	left = 0;
+	
+	while (drv_data->running)
+	{
+		cnt = read(fd, buf+left, sizeof(buf)-left);
+		if (cnt <= 0)
+		{
+			AM_DEBUG(1, "No data available from file");
+			usleep(200*1000);
+			lseek(fd, 0, SEEK_SET);
+			continue;
+		}
+		cnt += left;
+		left = cnt;
+		p = buf;
+		AM_DEBUG(1, "read from file return %d bytes", cnt);
+		while (left >= 188)
+		{
+			pkt_buf[0] = 0;
+			//AM_DEBUG(1, "read 188 bytes ts packet");
+			rp = read_ts_packet(p, left, pkt_buf);
+			left -= rp;
+			p += rp;
+			
+			if (pkt_buf[0] == 0x47)
+				ts_decoder(drv_data, pkt_buf);
+
+			total += rp;
+			if (total >= 125000)
+			{
+				usleep(20*1000);
+				total = 0;
+			}
+		}
+		if (left > 0)
+			memmove(buf, buf+cnt-left, left);
+	}
+
+	close(fd);
+
+	return NULL;
+}
+#endif
+
+static AM_ErrorCode_t emu_open(AM_USERDATA_Device_t *dev, const AM_USERDATA_OpenPara_t *para)
+{
+	UNUSED(para);
+	emu_ud_drv_data_t *drv_data = malloc(sizeof(emu_ud_drv_data_t));
+	
+	init_ts_decoder (&drv_data->tsd);
+	init_video_es_decoder (&drv_data->vesd);
+
+	drv_data->running = AM_TRUE;
+	drv_data->dev = dev;
+	drv_data->vpid = 0x1fff;
+	dev->drv_data = (void*)drv_data;
+	pthread_create(&drv_data->thread, NULL, dvr_data_thread, (void*)dev);
+
+	return AM_SUCCESS;
+}
+
+static AM_ErrorCode_t emu_close(AM_USERDATA_Device_t *dev)
+{
+	emu_ud_drv_data_t *drv_data = (emu_ud_drv_data_t*)dev->drv_data;
+
+	pthread_mutex_unlock(&am_gAdpLock);
+	drv_data->running = AM_FALSE;
+	pthread_join(drv_data->thread, NULL);
+	free(drv_data);
+	pthread_mutex_lock(&am_gAdpLock);
+	
+	return AM_SUCCESS;
+}
+
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/LICENSE b/test/am_ca_key_test/inject_record_t5d/include/am_adp/LICENSE
new file mode 100644
index 0000000..d0030e3
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/LICENSE
@@ -0,0 +1,23 @@
+// Copyright (C) 2015 Amlogic, Inc. All rights reserved.
+//
+// All information contained herein is Amlogic confidential.
+//
+// This software is provided to you pursuant to Software License
+// Agreement (SLA) with Amlogic Inc ("Amlogic"). This software may be
+// used only in accordance with the terms of this agreement.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification is strictly prohibited without prior written permission
+// from Amlogic.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/Makefile b/test/am_ca_key_test/inject_record_t5d/include/am_adp/Makefile
new file mode 100644
index 0000000..c107fc4
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/Makefile
@@ -0,0 +1,6 @@
+BASE=../..
+
+include $(BASE)/rule/def.mk
+
+
+include $(BASE)/rule/rule.mk
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_ad.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_ad.h
new file mode 100644
index 0000000..67db89f
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_ad.h
@@ -0,0 +1,108 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief Audio description
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2014-03-04: create the document
+ ***************************************************************************/
+
+
+#ifndef _AM_AD_H
+#define _AM_AD_H
+
+#include "am_types.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+/**\brief AD分析器句柄*/
+typedef void* AM_AD_Handle_t;
+
+/**\brief AD模块错误代码*/
+enum AM_AD_ErrorCode
+{
+	AM_AD_ERROR_BASE=AM_ERROR_BASE(AM_MOD_AD),
+	AM_AD_ERR_INVALID_PARAM,   /**< 参数无效*/
+	AM_AD_ERR_INVALID_HANDLE,  /**< 句柄无效*/
+	AM_AD_ERR_NOT_SUPPORTED,   /**< 不支持的操作*/
+	AM_AD_ERR_OPEN_PES,        /**< 打开PES通道失败*/
+	AM_AD_ERR_SET_BUFFER,      /**< 失置PES 缓冲区失败*/
+	AM_AD_ERR_NO_MEM,                  /**< 空闲内存不足*/
+	AM_AD_ERR_CANNOT_CREATE_THREAD,    /**< 无法创建线程*/
+	AM_AD_ERR_END
+};
+
+/**\brief AD参数*/
+typedef struct
+{
+	int dmx_id; /**< 使用Demux设备的ID*/
+	int pid;    /**< AD 音频的PID*/
+	int fmt;	/**< AD 音频的fmt*/
+}AM_AD_Para_t;
+
+typedef void (*AM_AD_Callback_t) (const uint8_t *data, int len, void *user_data);
+
+/**\brief 创建AD解析句柄
+ * \param[out] handle 返回创建的新句柄
+ * \param[in] para AD解析参数
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_ad.h)
+ */
+extern AM_ErrorCode_t AM_AD_Create(AM_AD_Handle_t *handle, AM_AD_Para_t *para);
+
+/**\brief 释放AD解析句柄
+ * \param handle 要释放的句柄
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_ad.h)
+ */
+extern AM_ErrorCode_t AM_AD_Destroy(AM_AD_Handle_t handle);
+
+/**\brief 开始AD数据解析
+ * \param handle AD句柄
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_ad.h)
+ */
+extern AM_ErrorCode_t AM_AD_Start(AM_AD_Handle_t handle);
+
+/**\brief 停止AD数据解析
+ * \param handle AD句柄
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_ad.h)
+ */
+extern AM_ErrorCode_t AM_AD_Stop(AM_AD_Handle_t handle);
+
+
+/**\brief 设定AD音量
+ * \param handle 要释放的句柄
+ * \param vol 音量0~100
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_ad.h)
+ */
+extern AM_ErrorCode_t AM_AD_SetVolume(AM_AD_Handle_t handle, int vol);
+
+extern AM_ErrorCode_t AM_AD_SetCallback(AM_AD_Handle_t handle, AM_AD_Callback_t cb, void *user);
+#ifdef __cplusplus
+}
+#endif
+
+
+
+#endif
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_aout.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_aout.h
new file mode 100644
index 0000000..8e41d0f
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_aout.h
@@ -0,0 +1,197 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief Audio output control module
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-08-13: create the document
+ ***************************************************************************/
+
+#ifndef _AM_AOUT_H
+#define _AM_AOUT_H
+
+#include "am_types.h"
+#include "am_evt.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+#define AM_AOUT_VOLUME_MIN 0   /**< The minimum volumn value */
+#define AM_AOUT_VOLUME_MAX 100 /**< The maximum volumn value */
+
+/****************************************************************************
+ * Error code definitions
+ ****************************************************************************/
+
+/**\brief Error code of the audio output module */
+enum AM_AOUT_ErrorCode
+{
+	AM_AOUT_ERROR_BASE=AM_ERROR_BASE(AM_MOD_AOUT),
+	AM_AOUT_ERR_INVALID_DEV_NO,          /**< Invalid audio output device number */
+	AM_AOUT_ERR_BUSY,                    /**< The device has already been openned */
+	AM_AOUT_ERR_ILLEGAL_OP,              /**< Illegal operation */
+	AM_AOUT_ERR_INVAL_ARG,               /**< Invalid argument */
+	AM_AOUT_ERR_NOT_ALLOCATED,           /**< The device has not been allocated */
+	AM_AOUT_ERR_CANNOT_CREATE_THREAD,    /**< Cannot create a new thread */
+	AM_AOUT_ERR_CANNOT_OPEN_DEV,         /**< Cannot open the device */
+	AM_AOUT_ERR_CANNOT_OPEN_FILE,        /**< Cannot open the file */
+	AM_AOUT_ERR_NOT_SUPPORTED,           /**< The operation is not supported */
+	AM_AOUT_ERR_NO_MEM,                  /**< Not enough memory */
+	AM_AOUT_ERR_TIMEOUT,                 /**< Timeout*/
+	AM_AOUT_ERR_SYS,                     /**< System error*/
+	AM_AOUT_ERR_END
+};
+
+/****************************************************************************
+ * Event type definitions
+ ****************************************************************************/
+
+/**\brief Event type of the audio output module*/
+enum AM_AOUT_EventType
+{
+	AM_AOUT_EVT_BASE=AM_EVT_TYPE_BASE(AM_MOD_AOUT),
+	AM_AOUT_EVT_VOLUME_CHANGED,          /**< Volumn has been changed,the parameter is the volumn value (int 0~100)*/
+	AM_AOUT_EVT_MUTE_CHANGED,            /**< Mute/Unmute status changed,the parameter is the new mute status (AM_Bool_t)*/
+	AM_AOUT_EVT_OUTPUT_MODE_CHANGED,     /**< Audio output mode changed,the parameter is the new mode (AM_AOUT_OutputMode_t)*/
+	AM_AOUT_EVT_PREGAIN_CHANGED,         /**< Pregain value changed,the parameter is the new pregain value*/
+	AM_AOUT_EVT_PREMUTE_CHANGED,         /**< Premute value changed, the parameter is the new premute value*/
+	AM_AOUT_EVT_END
+};
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+/**\brief Audio output mode*/
+typedef enum
+{
+	AM_AOUT_OUTPUT_STEREO,     /**< Stereo output*/
+	AM_AOUT_OUTPUT_DUAL_LEFT,  /**< Left audio output to dual channel*/
+	AM_AOUT_OUTPUT_DUAL_RIGHT, /**< Right audio output to dual channel*/
+	AM_AOUT_OUTPUT_SWAP        /**< Swap left and right channel*/
+} AM_AOUT_OutputMode_t;
+
+/**\brief Audio output device open parameters*/
+typedef struct
+{
+	int   foo;
+} AM_AOUT_OpenPara_t;
+
+/****************************************************************************
+ * Function prototypes  
+ ***************************************************************************/
+
+/**\brief Open an audio output device
+ * \param dev_no Audio output device number
+ * \param[in] para Audio output device open parameters
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AOUT_Open(int dev_no, const AM_AOUT_OpenPara_t *para);
+
+/**\brief Close the audio output device
+ * \param dev_no Audio output device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AOUT_Close(int dev_no);
+
+/**\brief Set the volumn of the audio output (0~100)
+ * \param dev_no Audio output device number
+ * \param vol Volumn number (0~100)
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AOUT_SetVolume(int dev_no, int vol);
+
+/**\brief Get the current volumn of the audio output
+ * \param dev_no Audio output device number
+ * \param[out] vol Return the volumn value
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AOUT_GetVolume(int dev_no, int *vol);
+
+/**\brief Mute/unmute the audio output
+ * \param dev_no Audio output device number
+ * \param mute AM_TRUE to mute the output, AM_FALSE to unmute the output
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AOUT_SetMute(int dev_no, AM_Bool_t mute);
+
+/**\brief Get the current mute status of the audio
+ * \param dev_no Audio output device number
+ * \param[out] mute Return the mute status
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AOUT_GetMute(int dev_no, AM_Bool_t *mute);
+
+/**\brief Set the audio output mode
+ * \param dev_no Audio output device number
+ * \param mode New audio output mode
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AOUT_SetOutputMode(int dev_no, AM_AOUT_OutputMode_t mode);
+
+/**\brief Get the current audio output mode
+ * \param dev_no Audio output device number
+ * \param[out] mode Return the current audio output mode
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AOUT_GetOutputMode(int dev_no, AM_AOUT_OutputMode_t *mode);
+
+/**\brief Set the audio pregain value
+ * \param dev_no Audio output device number
+ * \param gain Pregain value
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AOUT_SetPreGain(int dev_no, float gain);
+
+/**\brief Get the current audio pregain value
+ * \param dev_no Audio output device number
+ * \param[out] gain Return the audio pregain value
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AOUT_GetPreGain(int dev_no, float *gain);
+
+/**\brief Set premute/preunmute status of the audio
+ * \param dev_no Audio output device number
+ * \param mute AM_TRUE means mute, AM_FALSE means unmute
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AOUT_SetPreMute(int dev_no, AM_Bool_t mute);
+
+/**\brief Get the current premute status of the audio
+ * \param dev_no Audio output device number
+ * \param[out] mute Return the current premute status
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AOUT_GetPreMute(int dev_no, AM_Bool_t *mute);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_aout_internal.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_aout_internal.h
new file mode 100644
index 0000000..831f73c
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_aout_internal.h
@@ -0,0 +1,84 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief 音频输出模块内部头文件
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-08-13: create the document
+ ***************************************************************************/
+
+#ifndef _AM_AOUT_INTERNAL_H
+#define _AM_AOUT_INTERNAL_H
+
+#include <am_aout.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+typedef struct AM_AOUT_Device AM_AOUT_Device_t;
+typedef struct AM_AOUT_Driver AM_AOUT_Driver_t;
+
+/**\brief 音频输出驱动*/
+struct AM_AOUT_Driver
+{
+	AM_ErrorCode_t (*open)(AM_AOUT_Device_t *dev, const AM_AOUT_OpenPara_t *para);
+	AM_ErrorCode_t (*set_volume)(AM_AOUT_Device_t *dev, int vol);
+	AM_ErrorCode_t (*set_mute)(AM_AOUT_Device_t *dev, AM_Bool_t mute);
+	AM_ErrorCode_t (*set_output_mode)(AM_AOUT_Device_t *dev, AM_AOUT_OutputMode_t mode);
+	AM_ErrorCode_t (*close)(AM_AOUT_Device_t *dev);
+	AM_ErrorCode_t (*set_pre_gain)(AM_AOUT_Device_t *dev, float gain);
+	AM_ErrorCode_t (*set_pre_mute)(AM_AOUT_Device_t *dev, AM_Bool_t mute);
+};
+
+/**\brief 音频输出设备*/
+struct AM_AOUT_Device
+{
+	int                     dev_no;    /**< 设备号*/
+	const AM_AOUT_Driver_t *drv;       /**< 音频输出驱动*/
+	void                   *drv_data;  /**< 音频驱动私有数据*/
+	pthread_mutex_t         lock;      /**< 设备数据保护互斥体*/
+	int                     volume;    /**< 当前音量*/
+	AM_Bool_t               mute;      /**< 当前静音状态*/
+	AM_Bool_t               openned;   /**< 设备是否打开*/
+	AM_AOUT_OutputMode_t    mode;      /**< 当前输出模式*/
+	AM_AOUT_OpenPara_t      open_para; /**< 开启参数*/
+	float                   pre_gain;  /**< 当前预增益*/
+	AM_Bool_t               pre_mute;  /**< 当前预静音*/
+};
+
+/****************************************************************************
+ * Function prototypes  
+ ***************************************************************************/
+
+/**\brief 设定音频输出驱动
+ * \param dev_no 音频输出设备号
+ * \param[in] drv 音频输出驱动
+ * \param[in] drv_data 驱动私有数据
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_aout.h)
+ */
+extern AM_ErrorCode_t AM_AOUT_SetDriver(int dev_no, const AM_AOUT_Driver_t *drv, void *drv_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_av.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_av.h
new file mode 100644
index 0000000..0aba7bd
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_av.h
@@ -0,0 +1,1255 @@
+/***************************************************************************
+ * Copyright (C) 2017 Amlogic, Inc. 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.
+ *
+ * Description:
+ */
+/**\file
+ * \brief AV decoder module
+ *
+ * AV decoder device can work in the following modes:
+ *	- play TS stream
+ *	- decode audio ES
+ *	- decode video ES
+ *	- inject AV data to decoder
+ *	- timeshifting play
+ *	- local file playing (not available on android)
+ *	- JPEG hardware decode (not available on android)
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-08-06: create the document
+ ***************************************************************************/
+
+#ifndef _AM_AV_H
+#define _AM_AV_H
+
+#include "am_types.h"
+#include "am_osd.h"
+#include "am_evt.h"
+#include "am_misc.h"
+#include "am_tfile.h"
+#include "am_userdata.h"
+#include "am_crypt.h"
+#include <amports/vformat.h>
+#include <amports/aformat.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+#define AM_AV_VIDEO_CONTRAST_MIN   -1024  /**< The minimum contrast value*/
+#define AM_AV_VIDEO_CONTRAST_MAX   1024   /**< The maximum contrast value*/
+#define AM_AV_VIDEO_SATURATION_MIN -1024  /**< The minimum saturation value*/
+#define AM_AV_VIDEO_SATURATION_MAX 1024   /**< The maximum saturation value*/
+#define AM_AV_VIDEO_BRIGHTNESS_MIN -1024  /**< The minimum brightness value*/
+#define AM_AV_VIDEO_BRIGHTNESS_MAX 1024   /**< The maximum brightness value*/
+
+/****************************************************************************
+ * Error code definitions
+ ****************************************************************************/
+
+/**\brief Error code of the AV decoder module*/
+enum AM_AV_ErrorCode
+{
+	AM_AV_ERROR_BASE=AM_ERROR_BASE(AM_MOD_AV),
+	AM_AV_ERR_INVALID_DEV_NO,          /**< Invalid decoder device number*/
+	AM_AV_ERR_BUSY,                    /**< The device has already been openned*/
+	AM_AV_ERR_ILLEGAL_OP,              /**< Illegal operation*/
+	AM_AV_ERR_INVAL_ARG,               /**< Invalid argument*/
+	AM_AV_ERR_NOT_ALLOCATED,           /**< The device has not been allocated*/
+	AM_AV_ERR_CANNOT_CREATE_THREAD,    /**< Cannot create a new thread*/
+	AM_AV_ERR_CANNOT_OPEN_DEV,         /**< Cannot open the device*/
+	AM_AV_ERR_CANNOT_OPEN_FILE,        /**< Cannot open the file*/
+	AM_AV_ERR_NOT_SUPPORTED,           /**< Not supported*/
+	AM_AV_ERR_NO_MEM,                  /**< Not enough memory*/
+	AM_AV_ERR_TIMEOUT,                 /**< Timeout*/
+	AM_AV_ERR_SYS,                     /**< System error*/
+	AM_AV_ERR_DECODE,                  /**< Decoder error*/
+	AM_AV_ERR_END
+};
+
+/****************************************************************************
+ * Event type definitions
+ ****************************************************************************/
+
+/**\brief Event type of the AV decoder module*/
+enum AM_AV_EventType
+{
+	AM_AV_EVT_BASE=AM_EVT_TYPE_BASE(AM_MOD_AV),
+	AM_AV_EVT_PLAYER_STATE_CHANGED,    /**< File player's state changed, the parameter is the new state(AM_AV_MPState_t)*/
+	AM_AV_EVT_PLAYER_SPEED_CHANGED,    /**< File player's playing speed changed, the parameter is the new speed(0:normal,<0:backward,>0:fast forward)*/
+	AM_AV_EVT_PLAYER_TIME_CHANGED,     /**< File player's current time changed,the parameter is the current time*/
+	AM_AV_EVT_PLAYER_UPDATE_INFO,      /**< Update the current player information*/
+	AM_AV_EVT_VIDEO_WINDOW_CHANGED,    /**< Video window change, the parameter is the new window(AM_AV_VideoWindow_t)*/
+	AM_AV_EVT_VIDEO_CONTRAST_CHANGED,  /**< Video contrast changed,the parameter is the new contrast(int 0~100)*/
+	AM_AV_EVT_VIDEO_SATURATION_CHANGED,/**< Video saturation changed, the parameter is the new saturation(int 0~100)*/
+	AM_AV_EVT_VIDEO_BRIGHTNESS_CHANGED,/**< Video brightness changed, the parameter is the new brightness(int 0~100)*/
+	AM_AV_EVT_VIDEO_ENABLED,           /**< Video layer enabled*/
+	AM_AV_EVT_VIDEO_DISABLED,          /**< Video layer disabled*/
+	AM_AV_EVT_VIDEO_ASPECT_RATIO_CHANGED, /**< Video aspect ratio changed,the parameter is the new aspect ratio(AM_AV_VideoAspectRatio_t)*/
+	AM_AV_EVT_VIDEO_DISPLAY_MODE_CHANGED, /**< Video display mode changed, the parameter is the new display mode(AM_AV_VideoDisplayMode_t)*/
+	AM_AV_EVT_AV_NO_DATA,		   /**< Audio/Video data stopped*/
+	AM_AV_EVT_AV_DATA_RESUME,	/**< After event AM_AV_EVT_AV_NO_DATA,audio/video data resumed*/
+	AM_AV_EVT_VIDEO_ES_END,     /**< Injected video ES data end*/
+	AM_AV_EVT_AUDIO_ES_END,     /**< Injected audio ES data end*/
+	AM_AV_EVT_VIDEO_SCAMBLED,   /**< Video is scrambled*/
+	AM_AV_EVT_AUDIO_SCAMBLED,   /**< Audio is scrambled*/
+	AM_AV_EVT_AUDIO_AC3_NO_LICENCE,     /**< AC3 audio has not licence*/
+	AM_AV_EVT_AUDIO_AC3_LICENCE_RESUME, /**< AC3 audio resumed*/
+	AM_AV_EVT_VIDEO_NOT_SUPPORT,        /**< Video format is not supported*/
+	AM_AV_EVT_VIDEO_AVAILABLE,  /**< Cannot get valid video information*/
+	AM_AV_EVT_AUDIO_CB, /**< Audio function will implement in cb */
+	AM_AV_EVT_VIDEO_RESOLUTION_CHANGED, /**< Video resolution changed, the parameter is the AM_AV_VideoStatus_t with new width&height valid only */
+	AM_AV_EVT_VIDEO_AFD_CHANGED, /**< Video AFD info changed, parameter is AM_USERDATA_AFD_t*/
+	AM_AV_EVT_VIDEO_CROPPING_CHANGED,    /**< Video cropping change, the parameter is the new cropping window(AM_AV_VideoWindow_t)*/
+	AM_AV_EVT_PLAYER_EOF,              /**< Update the current player information*/
+	AM_AV_EVT_END
+};
+
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+/**\cond */
+/**\brief File player's state*/
+typedef enum
+{
+	AM_AV_MP_STATE_UNKNOWN = 0,        /**< Unknown*/
+	AM_AV_MP_STATE_INITING,            /**< Initializing*/
+	AM_AV_MP_STATE_NORMALERROR,        /**< Error occured*/
+	AM_AV_MP_STATE_FATALERROR,         /**< Fatal error occured*/
+	AM_AV_MP_STATE_PARSERED,           /**< The file's header has been parsed*/
+	AM_AV_MP_STATE_STARTED,            /**< Start playing*/
+	AM_AV_MP_STATE_PLAYING,            /**< Playing*/
+	AM_AV_MP_STATE_PAUSED,             /**< Paused*/
+	AM_AV_MP_STATE_CONNECTING,         /**< Connecting to the server*/
+	AM_AV_MP_STATE_CONNECTDONE,        /**< Connected*/
+	AM_AV_MP_STATE_BUFFERING,          /**< Buffering*/
+	AM_AV_MP_STATE_BUFFERINGDONE,      /**< Buffering done*/
+	AM_AV_MP_STATE_SEARCHING,          /**< Set new playing position*/
+	AM_AV_MP_STATE_TRICKPLAY,          /**< Play in trick mode*/
+	AM_AV_MP_STATE_MESSAGE_EOD,        /**< Message begin*/
+	AM_AV_MP_STATE_MESSAGE_BOD,        /**< Message end*/
+	AM_AV_MP_STATE_TRICKTOPLAY,        /**< Trick mode to normal playing mode*/
+	AM_AV_MP_STATE_FINISHED,           /**< File finished*/
+	AM_AV_MP_STATE_STOPED              /**< Palyer stopped*/
+} AM_AV_MPState_t;
+/**\endcond */
+
+/**\brief Video window*/
+typedef struct
+{
+	int x;                               /**< X coordinate of the top left corner*/
+	int y;                               /**< Y coordinate of the top left corner*/
+	int w;                               /**< Width of the window*/
+	int h;                               /**< Height of the window*/
+} AM_AV_VideoWindow_t;
+
+/**\brief TS stream input source*/
+typedef enum
+{
+	AM_AV_TS_SRC_TS0,                    /**< TS input port 0*/
+	AM_AV_TS_SRC_TS1,                    /**< TS input port 1*/
+	AM_AV_TS_SRC_TS2,                    /**< TS input port 2*/
+	AM_AV_TS_SRC_HIU,                    /**< HIU port (file input)*/
+	AM_AV_TS_SRC_HIU1,
+	AM_AV_TS_SRC_DMX0,                   /**< Demux 0*/
+	AM_AV_TS_SRC_DMX1,                   /**< Demux 1*/
+	AM_AV_TS_SRC_DMX2                    /**< Demux 2*/
+} AM_AV_TSSource_t;
+
+#if 0
+typedef enum {
+	AFORMAT_MPEG   = 0,
+	AFORMAT_PCM_S16LE = 1,
+	AFORMAT_AAC   = 2,
+	AFORMAT_AC3   =3,
+	AFORMAT_ALAW = 4,
+	AFORMAT_MULAW = 5,
+	AFORMAT_DTS = 6,
+	AFORMAT_PCM_S16BE = 7,
+	AFORMAT_FLAC = 8,
+	AFORMAT_COOK = 9,
+	AFORMAT_PCM_U8 = 10,
+	AFORMAT_ADPCM = 11,
+	AFORMAT_AMR  = 12,
+	AFORMAT_RAAC  = 13,
+	AFORMAT_WMA  = 14,
+	AFORMAT_WMAPRO    = 15,
+	AFORMAT_PCM_BLURAY	= 16,
+	AFORMAT_ALAC  = 17,
+	AFORMAT_VORBIS    = 18,
+	AFORMAT_AAC_LATM   = 19,
+	AFORMAT_UNSUPPORT = 20,
+	AFORMAT_MAX    = 21
+} AM_AV_AFormat_t;
+#else
+/**
+ * Audio format
+ *
+ * detail definition in "linux/amlogic/amports/aformat.h"
+ */
+typedef enum aformat_e AM_AV_AFormat_t;
+#endif
+
+#if 0
+typedef enum
+{
+	VFORMAT_MPEG12 = 0,
+	VFORMAT_MPEG4,
+	VFORMAT_H264,
+	VFORMAT_MJPEG,
+	VFORMAT_REAL,
+	VFORMAT_JPEG,
+	VFORMAT_VC1,
+	VFORMAT_AVS,
+	VFORMAT_YUV,    // Use SW decoder
+	VFORMAT_H264MVC,
+	VFORMAT_MAX
+} AM_AV_VFormat_t;
+#else
+/**
+ * Video format
+ *
+ * detail definition in "linux/amlogic/amports/vformat.h"
+ */
+typedef enum vformat_e AM_AV_VFormat_t;
+#endif
+
+/**\brief AV stream package format*/
+typedef enum
+{
+	PFORMAT_ES = 0, /**< ES stream*/
+	PFORMAT_PS,     /**< PS stream*/
+	PFORMAT_TS,     /**< TS stream*/
+	PFORMAT_REAL    /**< REAL file*/
+} AM_AV_PFormat_t;
+
+/**\brief Video aspect ratio*/
+typedef enum
+{
+	AM_AV_VIDEO_ASPECT_AUTO,      /**< Automatic*/
+	AM_AV_VIDEO_ASPECT_4_3,       /**< 4:3*/
+	AM_AV_VIDEO_ASPECT_16_9       /**< 16:9*/
+} AM_AV_VideoAspectRatio_t;
+
+/**\brief Video aspect ratio match mode*/
+typedef enum
+{
+	AM_AV_VIDEO_ASPECT_MATCH_IGNORE,     /**< Ignoring orignal aspect ratio*/
+	AM_AV_VIDEO_ASPECT_MATCH_LETTER_BOX, /**< Letter box match mode*/
+	AM_AV_VIDEO_ASPECT_MATCH_PAN_SCAN,   /**< Pan scan match mode*/
+	AM_AV_VIDEO_ASPECT_MATCH_COMBINED    /**< Combined letter box/pan scan match mode*/
+} AM_AV_VideoAspectMatchMode_t;
+
+/**\brief Video display mode*/
+typedef enum
+{
+	AM_AV_VIDEO_DISPLAY_NORMAL,     /**< Normal display mode*/
+	AM_AV_VIDEO_DISPLAY_FULL_SCREEN /**< Full screaan display mode*/
+} AM_AV_VideoDisplayMode_t;
+
+/**\cond */
+/**\brief Freescale parameter*/
+typedef enum
+{
+	AM_AV_FREE_SCALE_DISABLE,     /**< Disable freescale*/
+	AM_AV_FREE_SCALE_ENABLE       /**< Enable freescale*/
+} AM_AV_FreeScalePara_t;
+
+/**\brief Deinterlace parameter*/
+typedef enum
+{
+	AM_AV_DEINTERLACE_DISABLE,    /**< Disable deinterlace*/
+	AM_AV_DEINTERLACE_ENABLE      /**< Enable deinterlace*/
+} AM_AV_DeinterlacePara_t;
+
+/**\brief PPMGR parameter*/
+typedef enum
+{
+	AM_AV_PPMGR_DISABLE,          /**< Disable PPMGR*/
+	AM_AV_PPMGR_ENABLE,           /**< Enable PPMGR*/
+	/*以下为3D模式设置*/
+	AM_AV_PPMGR_MODE3D_DISABLE,
+	AM_AV_PPMGR_MODE3D_AUTO,
+	AM_AV_PPMGR_MODE3D_2D_TO_3D,
+	AM_AV_PPMGR_MODE3D_LR,
+	AM_AV_PPMGR_MODE3D_BT,
+	AM_AV_PPMGR_MODE3D_OFF_LR_SWITCH,
+	AM_AV_PPMGR_MODE3D_ON_LR_SWITCH,
+	AM_AV_PPMGR_MODE3D_FIELD_DEPTH,
+	AM_AV_PPMGR_MODE3D_OFF_3D_TO_2D,
+	AM_AV_PPMGR_MODE3D_L_3D_TO_2D,
+	AM_AV_PPMGR_MODE3D_R_3D_TO_2D,
+	AM_AV_PPMGR_MODE3D_OFF_LR_SWITCH_BT,
+	AM_AV_PPMGR_MODE3D_ON_LR_SWITCH_BT,
+	AM_AV_PPMGR_MODE3D_OFF_3D_TO_2D_BT,
+	AM_AV_PPMGR_MODE3D_L_3D_TO_2D_BT,
+	AM_AV_PPMGR_MODE3D_R_3D_TO_2D_BT,
+	AM_AV_PPMGR_MODE3D_MAX,
+} AM_AV_PPMGRPara_t;
+/**\endcond */
+
+/**\brief AV decoder device open parameters*/
+typedef struct
+{
+	int      vout_dev_no;         /**< Video output device number*/
+	int      afd_enable;          /**< enable AFD*/
+} AM_AV_OpenPara_t;
+
+/**\brief Media file information*/
+typedef struct
+{
+	uint64_t size;                /**< File size in bytes*/
+	int      duration;            /**< Total duration in seconds*/
+} AM_AV_FileInfo_t;
+
+/**\brief File playing status*/
+typedef struct
+{
+	int      duration;            /**< Total duration in seconds.*/
+	int      position;            /**< Current time*/
+} AM_AV_PlayStatus_t;
+
+/**\brief JPEG file properties*/
+typedef struct
+{
+	int      width;               /**< JPEG image width*/
+	int      height;              /**< JPEG image height*/
+	int      comp_num;            /**< Color number*/
+} AM_AV_JPEGInfo_t;
+
+/**\brief JPEG rotation parameter*/
+typedef enum
+{
+	AM_AV_JPEG_CLKWISE_0    = 0,  /**< Normal*/
+	AM_AV_JPEG_CLKWISE_90   = 1,  /**< Rotate 90 degrees clockwise*/
+	AM_AV_JPEG_CLKWISE_180  = 2,  /**< Rotate 180 degrees clockwise*/
+	AM_AV_JPEG_CLKWISE_270  = 3   /**< Rotate 270 degrees clockwise*/
+} AM_AV_JPEGAngle_t;
+
+/**\brief JPEG decoder options*/
+typedef enum
+{
+	AM_AV_JPEG_OPT_THUMBNAIL_ONLY     = 1, /**< Decode in thumbnail only mode*/
+	AM_AV_JPEG_OPT_THUMBNAIL_PREFERED = 2, /**< Decode in thumbnail prefered mode*/
+	AM_AV_JPEG_OPT_FULLRANGE          = 4  /**< Normal*/
+} AM_AV_JPEGOption_t;
+
+/**\brief Image surface parameters (used in JPEG decoder)*/
+typedef struct
+{
+	int    width;                 /**< Image width, <=0 means use orignal size*/
+	int    height;                /**< Image height, <=0 means use orignal size*/
+	AM_AV_JPEGAngle_t  angle;     /**< JPEG image ratation parameter*/
+	AM_AV_JPEGOption_t option;    /**< JPEG decoder options*/
+} AM_AV_SurfacePara_t;
+
+/**\brief Decoder injection data type*/
+typedef enum
+{
+	AM_AV_INJECT_AUDIO,           /**< Audio data*/
+	AM_AV_INJECT_VIDEO,           /**< Video data*/
+	AM_AV_INJECT_MULTIPLEX        /**< Multiplexed data*/
+} AM_AV_InjectType_t;
+
+typedef enum
+{
+	AM_AV_NO_DRM,
+	AM_AV_DRM_WITH_SECURE_INPUT_BUFFER, /**< Use for HLS, input buffer is clear and protected*/
+	AM_AV_DRM_WITH_NORMAL_INPUT_BUFFER  /**< Use for IPTV, input buffer is normal and scramble*/
+} AM_AV_DrmMode_t;
+
+/**\brief Decoder injection parameters*/
+typedef struct
+{
+	AM_AV_AFormat_t  aud_fmt;     /**< Audio format*/
+	AM_AV_VFormat_t  vid_fmt;     /**< Video format*/
+	AM_AV_PFormat_t  pkg_fmt;     /**< Package format*/
+	int              sub_type;    /**< Subtitle type.*/
+	int              aud_id;      /**< Audio ID, -1 means no audio data*/
+	int              vid_id;      /**< Video ID, -1 means no video data*/
+	int              sub_id;      /**< Subtitle ID, -i means no subtitle data*/
+	int              channel;     /**< Audio channel number (used in playing audio PCM data)*/
+	int              sample_rate; /**< Audio sample rate (used in playing audio PCM data)*/
+	int              data_width;  /**< Audio data width (used in playing audio PCM data)*/
+} AM_AV_InjectPara_t;
+
+/**\brief Video decoder status*/
+typedef struct
+{
+	AM_AV_VFormat_t  vid_fmt;     /**< Video format*/
+	int              src_w;       /**< Video source width*/
+	int              src_h;       /**< Video source height*/
+	int              fps;         /**< Frames per second*/
+	char             interlaced;  /**< Is interlaced ? */
+	int              frames;      /**< Decoded frames number*/
+	int              vb_size;     /**< Video buffer size*/
+	int              vb_data;     /**< Data size in the video buffer*/
+	int              vb_free;     /**< Free size in the video buffer*/
+	AM_AV_VideoAspectRatio_t vid_ratio; /**< Video source aspect ratio*/
+}AM_AV_VideoStatus_t;
+
+/**\brief Audio decoder status*/
+typedef struct
+{
+	AM_AV_AFormat_t  aud_fmt;     		/**< Audio format*/
+	int              sample_rate; 		/**< Sample rate*/
+	int              resolution;  		/**< Data width (8/16bits)*/
+	int              channels;    		/**< Channel number*/
+	unsigned int     frames;      		/**< Decoded frames number*/
+	int              ab_size;     		/**< Audio buffer size*/
+	int              ab_data;     		/**< Data size in the audio buffer*/
+	int              ab_free;     		/**< Free size in the audio buffer*/
+	AM_AV_AFormat_t  aud_fmt_orig;     	/**< original audio format*/
+	int              sample_rate_orig; 	/**< original sample rate*/
+	int              resolution_orig;  	/**< original resolution*/
+	int              channels_orig;    	/**< original channel number*/
+	int              lfepresent;       	/**< low frequency effects present*/
+	int              lfepresent_orig;  	/**< original low frequency effects present*/
+
+}AM_AV_AudioStatus_t;
+
+/**\brief Timeshifting play mode*/
+typedef enum
+{
+	AM_AV_TIMESHIFT_MODE_TIMESHIFTING, /**< Normal timeshifting mode*/
+	AM_AV_TIMESHIFT_MODE_PLAYBACK      /**< PVR playback mode*/
+}AM_AV_TimeshiftMode_t;
+
+/**\brief Timeshifting media information*/
+typedef struct
+{
+	int duration;              /**< Duration in seconds*/
+	char program_name[16];     /**< Program name*/
+	
+	int vid_pid; /**< Video PID*/
+	int vid_fmt; /**< Video format*/
+
+	int aud_cnt; /**< Audio number*/
+	struct
+	{
+		int pid; /**< Audio PID*/
+		int fmt; /**< Audio format*/
+		char lang[4]; /**< Lanuguage descripton*/
+	}audios[8]; /**< Audio information array*/
+
+	int sub_cnt; /**< Subtitle number*/
+	struct
+	{
+		int pid;  /**< Subtitle PID*/
+		int type; /**< Subtitle type*/
+		int composition_page; /**< DVB subtitle's composition page*/
+		int ancillary_page;   /**< DVB subtitle's ancillary page*/
+		int magzine_no; /**< Teletext subtitle's magzine number*/
+		int page_no;  /**< Teletext subtitle's page number*/
+		char lang[4]; /**< Language description*/
+	}subtitles[8]; /**< Subtitle information array*/
+
+	int ttx_cnt; /**< Teletext number*/
+	struct
+	{
+		int pid; /**< Teletext PID*/
+		int magzine_no; /**< Teletext magzine number*/
+		int page_no;    /**< Teletext page number*/
+		char lang[4];   /**< Teletext language description*/
+	}teletexts[8]; /**< Teletext information array*/
+}AM_AV_TimeshiftMediaInfo_t;
+
+/**\brief Timeshift playing parameters*/
+typedef struct
+{
+	int              dmx_id;      /**< Demux device index used*/
+	char             file_path[256];     /**< File path*/
+	
+	AM_AV_TimeshiftMode_t mode;   /**< Playing mode*/
+	AM_AV_TimeshiftMediaInfo_t media_info; /**< Media information*/
+
+	AM_TFile_t tfile;
+	int offset_ms;
+	AM_Bool_t start_paused;
+#ifdef SUPPORT_CAS
+	int  secure_enable;			/*Use for cas PVR/TimeShift playback*/
+	uint8_t *secure_buffer;	/*Use for sotre cas decrypt pvr data**/
+	char cas_file_path[256];/*Store Cas info file*/
+	AM_CAS_decrypt dec_cb;
+	uint32_t cb_param;
+#endif
+} AM_AV_TimeshiftPara_t;
+
+/**\brief Timeshift lpaying information*/
+typedef struct
+{
+	int                   current_time; /**< Current time in seconds*/
+	int                   full_time;    /**< Total length in seconds*/
+	int                   status;       /**< Status*/
+}AM_AV_TimeshiftInfo_t;
+
+/**\brief Player information*/
+typedef struct player_info
+{
+	char *name;
+	int last_sta;
+	int status;		   /*stop,pause	*/
+	int full_time;	   /*Seconds	*/
+	int current_time;  /*Seconds	*/
+	int current_ms;	/*ms*/
+	int last_time;		
+	int error_no;  
+	int start_time;
+	int pts_video;
+	int pts_pcrscr;
+	int current_pts;
+	long curtime_old_time;    
+	unsigned int video_error_cnt;
+	unsigned int audio_error_cnt;
+	float audio_bufferlevel;
+	float video_bufferlevel;
+}player_info_t;
+
+/****************************************************************************
+ * Function prototypes  
+ ***************************************************************************/
+
+/**\brief Open an AV decoder device
+ * \param dev_no AV decoder device number
+ * \param[in] para Device open parameters
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_Open(int dev_no, const AM_AV_OpenPara_t *para);
+
+/**\brief Close an AV decoder device
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_Close(int dev_no);
+
+/**\brief Set the decoder's TS input source
+ * \param dev_no AV decoder device number
+ * \param src TS input source
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetTSSource(int dev_no, AM_AV_TSSource_t src);
+
+/**\brief Start TS stream playing with PCR parameter
+ * \param dev_no AV decoder device number
+ * \param vpid Video PID
+ * \param apid Audio PID
+ * \param pcrpid PCR PID
+ * \param vfmt Video format
+ * \param afmt Audio format
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StartTSWithPCR(int dev_no, uint16_t vpid, uint16_t apid, uint16_t pcrpid, AM_AV_VFormat_t vfmt, AM_AV_AFormat_t afmt);
+
+/**\brief Start TS stream playing
+ * \param dev_no AV decoder device number
+ * \param vpid Video PID
+ * \param apid Audio PID
+ * \param vfmt Video format
+ * \param afmt Audio format
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StartTS(int dev_no, uint16_t vpid, uint16_t apid, AM_AV_VFormat_t vfmt, AM_AV_AFormat_t afmt);
+
+
+/**\brief Stop TS stream playing
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StopTS(int dev_no);
+
+/**\brief Start a media file playing
+ * \param dev_no AV decoder device number
+ * \param[in] fname Filename
+ * \param loop If play in loop mode.
+ * \param pos Start position in seconds
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StartFile(int dev_no, const char *fname, AM_Bool_t loop, int pos);
+
+/**\brief Switch to file play mode but do not start
+ * \param dev_no AV decoder device number
+ * \param[in] fname Filename
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_AddFile(int dev_no, const char *fname);
+
+/**\brief Start play the file. Invoke after AM_AV_AddFile
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StartCurrFile(int dev_no);
+
+/**\brief Start file playing
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StopFile(int dev_no);
+
+/**\brief Pause the file playing
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_PauseFile(int dev_no);
+
+/**\brief Resume the file playing
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_ResumeFile(int dev_no);
+
+/**\brief Set the current file playing position
+ * \param dev_no AV decoder device number
+ * \param pos Playing position in seconds
+ * \param start Start directly or pause on the position
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SeekFile(int dev_no, int pos, AM_Bool_t start);
+
+/**\brief Fast forward the file
+ * \param dev_no AV decoder device number
+ * \param speed Playing speed (0 means normal)
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_FastForwardFile(int dev_no, int speed);
+
+/**\brief Fast backward the file
+ * \param dev_no AV decoder device number
+ * \param speed Playing speed
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_FastBackwardFile(int dev_no, int speed);
+
+/**\brief Get the current playing file's information
+ * \param dev_no AV decoder device number
+ * \param[out] info Return the file's information
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetCurrFileInfo(int dev_no, AM_AV_FileInfo_t *info);
+
+/**\brief Get the current player status
+ * \param dev_no AV decoder device number
+ * \param[out] status Return the current player status
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetPlayStatus(int dev_no, AM_AV_PlayStatus_t *status);
+
+/**\brief Get the JPEG image file's information
+ * \param dev_no AV decoder device number
+ * \param[in] fname JPEG file name
+ * \param[out] info Return the image's information
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetJPEGInfo(int dev_no, const char *fname, AM_AV_JPEGInfo_t *info);
+
+/**\brief Get the JPEG image data's information
+ * \param dev_no AV decoder device number
+ * \param[in] data JPEG image data buffer
+ * \param len JPEG data length in bytes
+ * \param[out] info Return the image's information
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetJPEGDataInfo(int dev_no, const uint8_t *data, int len, AM_AV_JPEGInfo_t *info);
+
+/**\brief Decode the JPEG image file
+ * \param dev_no AV decoder device number
+ * \param[in] fname JPEG filename
+ * \param[in] para JPEG output parameters
+ * \param[out] surf Return the JPEG image
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_DecodeJPEG(int dev_no, const char *fname, const AM_AV_SurfacePara_t *para, AM_OSD_Surface_t **surf);
+
+/**\brief Decode the JPEG data
+ * \param dev_no AV decoder device number
+ * \param[in] data JPEG data buffer
+ * \param len JPEG data length in bytes
+ * \param[in] para JPEG output parameters
+ * \param[out] surf Return the JPEG image
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_DacodeJPEGData(int dev_no, const uint8_t *data, int len, const AM_AV_SurfacePara_t *para, AM_OSD_Surface_t **surf);
+
+/**\brief Decode video ES data from a file
+ * \param dev_no AV decoder device number
+ * \param format Video format
+ * \param[in] fname ES filename
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StartVideoES(int dev_no, AM_AV_VFormat_t format, const char *fname);
+
+/**\brief Decode video ES data from a buffer
+ * \param dev_no AV decoder device number
+ * \param format Video format
+ * \param[in] data Video ES buffer
+ * \param len Video data length in bytes
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StartVideoESData(int dev_no, AM_AV_VFormat_t format, const uint8_t *data, int len);
+
+/**\brief Stop video ES data decoding
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StopVideoES(int dev_no);
+
+/**\brief Start audio ES data decoding from a file
+ * \param dev_no AV decoder device number
+ * \param format Audio format
+ * \param[in] fname Audio ES filename
+ * \param times Playing times, <=0 means loop forever
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StartAudioES(int dev_no, AM_AV_AFormat_t format, const char *fname, int times);
+
+/**\brief Start audio ES data decoding from a buffer
+ * \param dev_no AV decoder device number
+ * \param format Audio format
+ * \param[in] data Audio ES buffer
+ * \param len Audio data length in bytes
+ * \param times Playing times, <=0 means loop forever
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StartAudioESData(int dev_no, AM_AV_AFormat_t format, const uint8_t *data, int len, int times);
+
+/**\brief Stop audio ES decoding
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StopAudioES(int dev_no);
+
+/**\brief Enable/diable decoder's DRM mode
+ * \param dev_no AV decoder device number
+ * \param[in] enable enable or disable DRM mode
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetDRMMode(int dev_no, AM_AV_DrmMode_t drm_mode);
+
+/**\brief Start AV data injection playing mode
+ * \param dev_no AV decoder device number
+ * \param[in] para Injection parameters
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StartInject(int dev_no, const AM_AV_InjectPara_t *para);
+
+/**\brief In injection mode, inject AV data to decoder
+ * \param dev_no AV decoder device number
+ * \param type Input data type
+ * \param[in] data AV data buffer
+ * \param[in,out] size Input the data length, and return the injected data length
+ * \param timeout Timeout in milliseconds
+ * The function will wait until the decoder's input buffer has enough space to receive the AV data.
+ * >0 the function will return immediately to this time.
+ * <0 means waiting forever.
+ * =0 means return immediately.
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_InjectData(int dev_no, AM_AV_InjectType_t type, uint8_t *data, int *size, int timeout);
+
+/**\brief Pause the decoder in injection mode
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_PauseInject(int dev_no);
+
+/**\brief Resume the decoder in injection mode
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_ResumeInject(int dev_no);
+
+/**\brief In injection mode, change the video
+ * \param dev_no AV decoder device number
+ * \param vid Video PID
+ * \param vfmt Video format
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetInjectVideo(int dev_no, int vid, AM_AV_VFormat_t vfmt);
+
+/**\brief In injection mode, change the audio
+ * \param dev_no AV decoder device number
+ * \param aid Audio PID
+ * \param afmt Audio format
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetInjectAudio(int dev_no, int aid, AM_AV_AFormat_t afmt);
+
+/**\brief In injection mode, change the subtitle
+ * \param dev_no AV decoder device number
+ * \param sid Subtitle's PID
+ * \param stype The subtitle's type.
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetInjectSubtitle(int dev_no, int sid, int stype);
+
+/**\brief Stop the injection mode
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StopInject(int dev_no);
+
+/**\brief Set the video window
+ * \param dev_no AV decoder device number
+ * \param x X coordinate of the top left corner
+ * \param y Y coordinate of the top left corner
+ * \param w Window width
+ * \param h Window height
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetVideoWindow(int dev_no, int x, int y, int w, int h);
+
+/**\brief Set the video cropping
+ * \param dev_no AV decoder device number
+ * \param Voffset0 vertical crop of the top left corner
+ * \param Hoffset0 horizontal crop of the top left corner
+ * \param Voffset1 vertical crop of the bottom right corner
+ * \param Hoffset1 horizontal crop of the bottom right corner
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetVideoCropping(int dev_no, int Voffset0, int Hoffset0, int Voffset1, int Hoffset1);
+
+/**\brief Get the video window
+ * \param dev_no AV decoder device number
+ * \param[out] x Return x coordinate of the top left corner
+ * \param[out] y Return y coordinate of the top left corner
+ * \param[out] w Return the window width
+ * \param[out] h Return the window height
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetVideoWindow(int dev_no, int *x, int *y, int *w, int *h);
+
+/**\brief Set the video contrast (0~100)
+ * \param dev_no AV decoder device number
+ * \param val New contrast value
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetVideoContrast(int dev_no, int val);
+
+/**\brief Get the current video contrast value
+ * \param dev_no AV decoder device number
+ * \param[out] val Return the current video contrast value
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetVideoContrast(int dev_no, int *val);
+
+/**\brief Set the video saturation value (0~100)
+ * \param dev_no AV decoder device number
+ * \param val The new video saturation value
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetVideoSaturation(int dev_no, int val);
+
+/**\brief Get the current video saturation value
+ * \param dev_no AV decoder device number
+ * \param[out] val Return the saturation value
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetVideoSaturation(int dev_no, int *val);
+
+/**\brief Set the video brightness value (0~100)
+ * \param dev_no AV decoder device number
+ * \param val New video brightness value
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetVideoBrightness(int dev_no, int val);
+
+/**\brief Get the current video brightness value
+ * \param dev_no AV decoder device number
+ * \param[out] val Return the current video brightness value
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetVideoBrightness(int dev_no, int *val);
+
+/**\brief Enable the video layer
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_EnableVideo(int dev_no);
+
+/**\brief Disable the video layer
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_DisableVideo(int dev_no);
+
+/**\brief Set the video aspect ratio
+ * \param dev_no AV decoder device number
+ * \param ratio New aspect ratio value
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetVideoAspectRatio(int dev_no, AM_AV_VideoAspectRatio_t ratio);
+
+/**\brief Get the video aspect ratio
+ * \param dev_no AV decoder device number
+ * \param[out] ratio Return the video aspect ratio
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetVideoAspectRatio(int dev_no, AM_AV_VideoAspectRatio_t *ratio);
+
+/**\brief Set the video aspect ratio match mode
+ * \param dev_no AV decoder device number
+ * \param mode New match mode
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetVideoAspectMatchMode(int dev_no, AM_AV_VideoAspectMatchMode_t mode);
+
+/**\brief Get the video aspect ratio match mode
+ * \param dev_no AV decoder device number
+ * \param[out] mode Return the current match mode
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetVideoAspectMatchMode(int dev_no, AM_AV_VideoAspectMatchMode_t *mode);
+
+/**\brief Set the video layer disabled automatically when video stopped
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_EnableVideoBlackout(int dev_no);
+
+/**\brief Set the video layer do not disabled when video stopped
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_DisableVideoBlackout(int dev_no);
+
+/**\brief Set the video display mode
+ * \param dev_no AV decoder device number
+ * \param mode New display mode
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetVideoDisplayMode(int dev_no, AM_AV_VideoDisplayMode_t mode);
+
+/**\brief Get the current video display mode
+ * \param dev_no AV decoder device number
+ * \param[out] mode Return the current display mode
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetVideoDisplayMode(int dev_no, AM_AV_VideoDisplayMode_t *mode);
+
+/**\brief Clear the video layer
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_ClearVideoBuffer(int dev_no);
+
+/**\brief Get the video frame data (after video stopped)
+ *
+ * This function is not available on android.
+ * \param dev_no AV decoder device number
+ * \param[in] para Surface create parameters
+ * \param[out] s Return the video frame
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetVideoFrame(int dev_no, const AM_AV_SurfacePara_t *para, AM_OSD_Surface_t **s);
+
+/**\brief Get the current video decoder's status
+ * \param dev_no AV decoder device number
+ * \param[out] status Return the current video decoder's status
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetVideoStatus(int dev_no, AM_AV_VideoStatus_t *status);
+
+/**\brief Get the current audio decoder's status
+ * \param dev_no AV decoder device number
+ * \param[out] status Return the current audio decoder's status
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetAudioStatus(int dev_no, AM_AV_AudioStatus_t *status);
+
+
+/**\brief Start the timeshifting mode
+ * \param dev_no AV decoder device number
+ * \param[in] para Timeshifting parameters
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StartTimeshift(int dev_no, const AM_AV_TimeshiftPara_t *para);
+
+/**\brief In timeshifting mode, write AV data to decoder
+ * \param dev_no AV decoder device number
+ * \param[in] data Injected data buffer
+ * \param size Data length in the buffer
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_TimeshiftFillData(int dev_no, uint8_t *data, int size);
+
+/**\brief Stop timeshifting mode
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_StopTimeshift(int dev_no);
+
+/**\brief Start playing in timeshifting mode
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_PlayTimeshift(int dev_no);
+
+/**\brief Pause playing in timeshifting mode
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_PauseTimeshift(int dev_no);
+
+/**\brief Resume playing in timeshifting mode
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_ResumeTimeshift(int dev_no);
+
+/**\brief Set the current playing position in timeshifting mode
+ * \param dev_no AV decoder device number
+ * \param pos New position in seconds
+ * \param start Start playing directly after seek
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SeekTimeshift(int dev_no, int pos, AM_Bool_t start);
+
+/**\brief Fast forward playing in timeshifting mode
+ * \param dev_no AV decoder device number
+ * \param speed Playing speed
+ * 0 means normal speed.
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_FastForwardTimeshift(int dev_no, int speed);
+
+/**\brief Fast backward playing in timeshifting mode
+ * \param dev_no AV decoder device number
+ * \param speed Playing speed
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_FastBackwardTimeshift(int dev_no, int speed);
+
+/**\brief Switch audio in timeshifting mode
+ * \param dev_no AV decoder device number
+ * \param apid The new audio PID
+ * \param afmt The new audio format
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SwitchTimeshiftAudio(int dev_no, int apid, int afmt);
+
+/**\brief Get the current timeshifting play information
+ * \param dev_no AV decoder device number
+ * \param [out] info Return the timeshifting information
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetTimeshiftInfo(int dev_no, AM_AV_TimeshiftInfo_t *info);
+
+/**\brief Get the current timeshifting play information
+ * \param dev_no AV decoder device number
+ * \param [out] tfile the tfile used for timeshift
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetTimeshiftTFile(int dev_no, AM_TFile_t *tfile);
+
+/**\cond */
+/**\brief Set video path parameters
+ * \param dev_no AV decoder device number
+ * \param fs free scale parameter
+ * \param di deinterlace parameter
+ * \param pp PPMGR parameter
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetVPathPara(int dev_no, AM_AV_FreeScalePara_t fs, AM_AV_DeinterlacePara_t di, AM_AV_PPMGRPara_t pp);
+/**\endcond */
+
+/**\brief Switch audio in TS playing mode
+ * \param dev_no AV decoder device number
+ * \param apid New audio PID
+ * \param afmt New audio format
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SwitchTSAudio(int dev_no, uint16_t apid, AM_AV_AFormat_t afmt);
+
+/**
+ * Reset the audio decoder
+ * \param dev_no AV decoder device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_ResetAudioDecoder(int dev_no);
+
+
+/**\brief Used to set /sys/module/amvdec_h264/parameters/error_recovery_mode to choose display mosaic or not
+ * \param dev_no AV decoder device number
+ * \param error_recovery_mode : 0 ,skip mosaic and reset vdec,2 skip mosaic ,3 display mosaic
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetVdecErrorRecoveryMode(int dev_no, uint8_t error_recovery_mode);
+
+/**
+ * Set audio description output in TS playing mode
+ * \param dev_no AV decoder device number
+ * \param enable 1 to enable AD output, 0 to disable AD output
+ * \param apid AD audio PID
+ * \param afmt AD audio format
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetAudioAd(int dev_no, int enable, uint16_t apid, AM_AV_AFormat_t afmt);
+
+typedef struct _AUDIO_PARMS_
+{
+	int cmd;
+	int param1;
+	int param2;
+}AudioParms;
+
+#if 0
+typedef struct _AUDIO_STATUS_
+{
+	int sample_rate_orig;
+	int channels_orig;
+	int lfepresent_orig;
+	int channels;
+	int sample_rate;
+}AudioStatus;
+#endif
+
+#define ADEC_START_DECODE 		1
+#define ADEC_PAUSE_DECODE 		2
+#define ADEC_RESUME_DECODE 		3
+#define ADEC_STOP_DECODE  		4
+#define ADEC_SET_DECODE_AD 		5
+#define ADEC_SET_VOLUME 		6
+#define ADEC_SET_MUTE			7
+#define ADEC_SET_OUTPUT_MODE 	8
+#define ADEC_SET_PRE_GAIN		9
+#define ADEC_SET_PRE_MUTE 		10
+#define ADEC_GET_STATUS			11
+
+typedef void (*AM_AV_Audio_CB_t)(int event_type, AudioParms* parm, void *user_data);
+
+extern AM_ErrorCode_t AM_AV_SetAudioCallback(int dev_no,AM_AV_Audio_CB_t cb,void *user_data);
+
+/**
+ * brief Get current video pts
+ * \param dev_no AV decoder device number
+ * \param[out] Return the 33-bit pts value
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetVideoPts(int dev_no, uint64_t *pts);
+
+/**
+ * brief Get current audio pts
+ * \param dev_no AV decoder device number
+ * \param[out] Return the 33-bit pts value
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_GetAudioPts(int dev_no, uint64_t *pts);
+
+/**
+ * brief Set Crypt operators
+ * \param dev_no AV decoder device number
+ * \param ops Crypt ops
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_SetCryptOps(int dev_no, AM_Crypt_Ops_t *ops);
+
+/**
+ * brief Set Crypt operators
+ * \param dev_no AV decoder device number
+ * \param value Fendend Status
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_AV_setFEStatus(int dev_no,int value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_ci.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_ci.h
new file mode 100644
index 0000000..b58c6a2
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_ci.h
@@ -0,0 +1,329 @@
+/***************************************************************************
+ * Copyright (C) 2017 Amlogic, Inc. 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.
+ *
+ * Description:
+ */
+/**\file
+ * \brief am ci module
+ *
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-08-06: create the document
+ ***************************************************************************/
+
+#ifndef _AM_CI_H_
+#define _AM_CI_H_
+
+#include "am_caman.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/**\brief Error code of the ci module*/
+enum AM_CI_ErrorCode
+{
+	AM_CI_ERROR_BASE=AM_ERROR_BASE(AM_MOD_CI),
+	AM_CI_ERROR_INVALID_DEV_NO, 							/**< Invalid device number*/
+	AM_CI_ERROR_BAD_PARAM,										/**< Invalid parameter*/
+	AM_CI_ERROR_NOT_OPEN,											/**< The device is not yet open */
+	AM_CI_ERROR_NOT_START,										/**< The device is already start*/
+	AM_CI_ERROR_ALREADY_OPEN,									/**< The device is not yet open*/
+	AM_CI_ERROR_ALREADY_START,								/**< The device is already start*/
+	AM_CI_ERROR_CANNOT_CREATE_THREAD,					/**< Cannot creat thread*/
+	AM_CI_ERROR_USED_BY_CAMAN,								/**< CAMAN error */
+	AM_CI_ERROR_PROTOCOL,											/**< Protocol error*/
+	AM_CI_ERROR_BAD_PMT,											/**< PMT is bad error*/
+	AM_CI_ERROR_MAX_DEV,											/**< already open max device,need close other device*/
+	AM_CI_ERROR_BAD_CAM,											/**< Cam card is bad*/
+	AM_CI_ERROR_UNAVAILABLE,									/**< ci unavailable error*/
+	AM_CI_ERROR_UNKOWN,												/**< Unkown error*/
+};
+/**\brief callback id of the ci module*/
+enum AM_CI_CBID
+{
+	CBID_AI_CALLBACK,											/**< ai callback ID*/
+	CBID_CA_INFO_CALLBACK ,								/**< ca info callback ID*/
+	CBID_MMI_CLOSE_CALLBACK ,							/**< mmi close callback ID*/
+	CBID_MMI_DISPLAY_CONTROL_CALLBACK ,		/**< mmi display control callback ID*/
+	CBID_MMI_ENQ_CALLBACK ,								/**< mmi enquiry callback ID*/
+	CBID_MMI_MENU_CALLBACK ,							/**< mmi menu callback ID*/
+	CBID_MMI_LIST_CALLBACK ,							/**< mmi list callback ID*/
+};
+/**\brief mmi answer id */
+enum AM_CI_MMI_ANSWER_ID
+{
+	AM_CI_MMI_ANSW_CANCEL = 0x00,	/**< mmi cancel*/
+	AM_CI_MMI_ANSW_ANSWER = 0x01, /**< mmi answer*/
+};
+/**\brief close mmi cmd id */
+enum AM_CI_MMI_CLOSE_MMI_CMD_ID
+{
+	AM_CI_MMI_CLOSE_MMI_CMD_ID_IMMEDIATE = 0x00, /**< send mmi close cmd immediately*/
+	AM_CI_MMI_CLOSE_MMI_CMD_ID_DELAY = 0x01,		 /**< send mmi close cmd delay*/
+};
+/**\brief ca pmt list management */
+enum AM_CI_CA_LIST_MANAGEMENT
+{
+	AM_CI_CA_LIST_MANAGEMENT_MORE =    0x00,	/**< has more pmt*/
+	AM_CI_CA_LIST_MANAGEMENT_FIRST =   0x01,	/**< the first one pmt*/
+	AM_CI_CA_LIST_MANAGEMENT_LAST =    0x02,	/**< the last one pmt*/
+	AM_CI_CA_LIST_MANAGEMENT_ONLY =    0x03,	/**< only for single ca pmt*/
+	AM_CI_CA_LIST_MANAGEMENT_ADD =     0x04,	/**< add for already existing programme */
+	AM_CI_CA_LIST_MANAGEMENT_UPDATE =  0x05,	/**< update means that ca pmt already existing,is sent again*/
+};
+/**\brief ca pmt cmd id */
+enum AM_CI_CA_PMT_CMD_ID
+{
+	AM_CI_CA_PMT_CMD_ID_OK_DESCRAMBLING =  0x01,	/**< application can start descrambling*/
+	AM_CI_CA_PMT_CMD_ID_OK_MMI =           0x02,	/**< application can send mmi dialogue but shall not satrt descrambling*/
+	AM_CI_CA_PMT_CMD_ID_QUERY =            0x03,	/**< host expect to receive ca pmt reply,the application is not allowen to start des and mmi dialogue*/
+	AM_CI_CA_PMT_CMD_ID_NOT_SELECTED =     0x04,	/**< host no longer requires that ca applition to descramble the service*/
+};
+/**\brief CI handle type*/
+typedef void* AM_CI_Handle_t;
+/**\brief CI open  parameter*/
+typedef struct
+{
+	int foo;
+} AM_CI_OpenPara_t;
+/**\brief ci mmi text info struct*/
+typedef struct  {
+	uint8_t *text;			/**< mmi text content*/
+	uint32_t text_size;	/**< mmi text content length*/
+} app_mmi_text_t;
+/**\brief ci application info callback
+ * \param[in] arg callback used private data
+ * \param[in] slot_id ci slot id
+ * \param[in] session_number	ci session number
+ * \param[in] application_type	application type
+ * \param[in] application_manufacturer application manufacturer
+ * \param[in] menu_string_length	menu string length
+ * \param[in] menu_string menu string
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+typedef int (*ai_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
+			     uint8_t application_type, uint16_t application_manufacturer,
+			     uint16_t manufacturer_code, uint8_t menu_string_length,
+			     uint8_t *menu_string);
+/**\brief ci info callback
+ * \param[in] arg callback used private data
+ * \param[in] slot_id ci slot id
+ * \param[in] session_number	ci session number
+ * \param[in] ca_id_count	ca id count number
+ * \param[in] ca_ids ca id array
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+typedef int (*ca_info_callback)(void *arg, uint8_t slot_id, uint16_t session_number, uint32_t ca_id_count, uint16_t *ca_ids);
+/**\brief mmi close callback
+ * \param[in] arg callback used private data
+ * \param[in] slot_id ci slot id
+ * \param[in] session_number	ci session number
+ * \param[in] cmd_id	see AM_CI_MMI_CLOSE_MMI_CMD_ID
+ * \param[in] delay delay time
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+typedef int (*mmi_close_callback)(void *arg, uint8_t slot_id, uint16_t session_number, uint8_t cmd_id, uint8_t delay);
+/**\brief mmi display control callback
+ * \param[in] arg callback used private data
+ * \param[in] slot_id ci slot id
+ * \param[in] session_number	ci session number
+ * \param[in] cmd_id	see MMI_DISPLAY_CONTROL_CMD_ID* in en50221_app_mmi.h
+ * \param[in] mmi_mode see MMI_MODE_* in en50221_app_mmi.h
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+typedef int (*mmi_display_control_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
+					      uint8_t cmd_id, uint8_t mmi_mode);
+/**\brief mmi enq callback
+ * \param[in] arg callback used private data
+ * \param[in] slot_id ci slot id
+ * \param[in] session_number	ci session number
+ * \param[in] blind_answer	set to 1 menus that user input has not to be displayed
+ * \param[in] expected_answer_length expected length,if set to FF if unkown
+ * \param[in] text	input text string
+ * \param[in] text_size input text length
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+typedef int (*mmi_enq_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
+				  uint8_t blind_answer, uint8_t expected_answer_length,
+				  uint8_t *text, uint32_t text_size);
+/**\brief mmi menu callback
+ * \param[in] arg callback used private data
+ * \param[in] slot_id ci slot id
+ * \param[in] session_number	ci session number
+ * \param[in] title	menu title string
+ * \param[in] sub_title menu subtitle string
+ * \param[in] bottom	menu bottom string
+ * \param[in] item_count menu list item count
+ * \param[in] items menu items string
+ * \param[in] item_raw_length menu item raw string length
+ * \param[in] items_raw menu item raw string
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+typedef int (*mmi_menu_callback)(void *arg, uint8_t slot_id, uint16_t session_number,
+				   app_mmi_text_t *title,
+				   app_mmi_text_t *sub_title,
+				   app_mmi_text_t *bottom,
+				   uint32_t item_count, app_mmi_text_t *items,
+				   uint32_t item_raw_length, uint8_t *items_raw);
+
+/**\brief ca callback struct */
+typedef struct {
+	union{
+		ai_callback ai_cb;																		/**< ai callback*/
+		ca_info_callback ca_info_cb;													/**< ca info callback*/
+		mmi_close_callback mmi_close_cb;											/**< mmi close callback*/
+		mmi_display_control_callback mmi_display_control_cb;	/**< mmi display callback*/
+		mmi_enq_callback mmi_enq_cb;													/**< mmi enq callback*/
+		mmi_menu_callback mmi_menu_cb;												/**< mmi menu callback*/
+		mmi_menu_callback mmi_list_cb;												/**< mmi list callback*/
+	}u;
+}AM_CI_CB_t;
+/**\brief Open ci device
+ * \param [in] dev_no ci device number
+ * \param [in] slot_no Serviceid
+ * \param [in] para ci open parameter
+ * \param [out] handle ci open handle
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_CI_Open(int dev_no, int slot_no, const AM_CI_OpenPara_t *para, AM_CI_Handle_t *handle);
+/**\brief Close ci device
+ * \param [in] handle ci opened handle
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_CI_Close(AM_CI_Handle_t handle);
+/**\brief start ci
+ * \param [in] handle ci opened handle
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_CI_Start(AM_CI_Handle_t handle);
+/**\brief stop ci
+ * \param [in] handle ci opened handle
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_CI_Stop(AM_CI_Handle_t handle);
+
+/*set callbacks before start() or you may miss callbacks*/
+/**\brief set ci callback
+ * \param [in] handle ci opened handle
+ * \param [in] cbid callback id,see AM_CI_CBID enum
+ * \param [in] cb ci callback function
+ * \param [in] arg ci callback private data
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_CI_SetCallback(AM_CI_Handle_t handle, int cbid, AM_CI_CB_t *cb, void *arg);
+
+/**\brief seen pmt to cam card
+ * \param [in] handle ci opened handle
+ * \param [in] capmt pmt data buffer
+ * \param [in] size pmt buffer length
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_CI_App_ca_pmt(AM_CI_Handle_t handle, unsigned char *capmt, unsigned int size);
+/**\brief ci enter menu
+ * \param [in] handle ci opened handle
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_CI_App_ai_entermenu(AM_CI_Handle_t handle);
+/*answer_id see:AM_CI_MMI_ANSWER_ID*/
+
+/**\brief ci mmi answer
+ * \param [in] handle ci opened handle
+ * \param [in] answer_id ci answer id
+ * \param [in] answer ci answer string
+ * \param [in] size ci answer size
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_CI_App_mmi_answ(AM_CI_Handle_t handle, int answer_id, char *answer, int size);
+/**\brief ci mmi slect menu
+ * \param [in] handle ci opened handle
+ * \param [in] select ci selected menu item index
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_CI_App_mmi_menu_answ(AM_CI_Handle_t handle, int select);
+/**\brief ci mmi close
+ * \param [in] handle ci opened handle
+ * \param [in] cmd_id mmi close cmd id,see AM_CI_MMI_CLOSE_MMI_CMD_ID
+ * \param [in] delay delay time
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_CI_App_mmi_close(AM_CI_Handle_t handle, int cmd_id, int delay);
+
+/*infomations enquired will be repled in the callback*/
+
+/**\brief ci enquie ca info
+ * \param [in] handle ci opened handle
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_CI_App_ca_info_enq(AM_CI_Handle_t handle);
+/**\brief ci enquie ai
+ * \param [in] handle ci opened handle
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_CI_App_ai_enquiry(AM_CI_Handle_t handle);
+
+/*user need to free the generated capmt with free() in the end */
+/**\brief ci generate ca pmt
+ * \param [in] pmt CA modue recivered pmt
+ * \param [in] pmt_size pmt length
+ * \param [out] capmt generated ca pmt
+ * \param [out] capmt_size capmt length
+ * \param [in] ca_list_management see AM_CI_CA_LIST_MANAGEMENT
+ * \param [in] ca_pmt_cmd_id see AM_CI_CA_PMT_CMD_ID
+ * \param [in] moveca Whether to delete ca descriptors
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_CI_GenerateCAPMT(unsigned char *pmt, unsigned int pmt_size,
+											unsigned char **capmt, unsigned int *capmt_size,
+											int ca_list_management, int ca_pmt_cmd_id,
+											int moveca);
+/**\brief ci match ca by caid
+ * \param [in] handle ci opened handle
+ * \param [in] caid CA id
+ * \param [out] match 1:match 0: unmatch.
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_CI_MatchCAID(AM_CI_Handle_t handle, unsigned int caid, int *match);
+/**\brief ci get ca by handle
+ * \param [in] handle ci opened handle
+ * \param [out] ca AM_CA_t pointer of pointer
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_CI_CAMAN_getCA(AM_CI_Handle_t handle, AM_CA_t **ca);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif/*_AM_CI_H_*/
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_cond.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_cond.h
new file mode 100644
index 0000000..7071d68
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_cond.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+ * Copyright (C) 2017 Amlogic, Inc. 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.
+ *
+ * Description:
+ */
+/**\file
+ * \brief Condition variable.
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2017-11-07: create the document
+ ***************************************************************************/
+
+#ifndef _AM_COND_H
+#define _AM_COND_H
+
+#include "am_types.h"
+#include <pthread.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define pthread_cond_init(c, a)\
+	({\
+		pthread_condattr_t attr;\
+		pthread_condattr_t *pattr;\
+		int r;\
+		if (a) {\
+			pattr = a;\
+		} else {\
+			pattr = &attr;\
+			pthread_condattr_init(pattr);\
+		}\
+		pthread_condattr_setclock(pattr, CLOCK_MONOTONIC);\
+		r = pthread_cond_init(c, pattr);\
+		if (pattr == &attr) {\
+			pthread_condattr_destroy(pattr);\
+		}\
+		r;\
+	 })
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_config.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_config.h
new file mode 100644
index 0000000..5ecc369
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_config.h
@@ -0,0 +1,37 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+
+ */
+/**\file
+ * \brief aml config
+ * \author hualing.chen <hualing.chen@amlogic.com>
+ * \date 2017-04-25: create the document
+ ***************************************************************************/
+
+#ifndef _AM_CONFIG_H
+#define _AM_CONFIG_H
+
+#ifndef CONFIG_AMLOGIC_DVB_COMPAT
+/**\brief int value: 1*/
+#define CONFIG_AMLOGIC_DVB_COMPAT       (1)
+#endif
+
+#ifndef __DVB_CORE__
+/**\brief int value: 1*/
+#define __DVB_CORE__       (1)
+#endif
+
+#include <linux/dvb/frontend.h>
+
+typedef struct atv_status_s atv_status_t;
+typedef struct tuner_param_s tuner_param_t;
+//typedef enum fe_ofdm_mode fe_ofdm_mode_t;
+
+#define fe_ofdm_mode_t enum fe_ofdm_mode
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_crypt.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_crypt.h
new file mode 100644
index 0000000..d8f5ef5
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_crypt.h
@@ -0,0 +1,55 @@
+/***************************************************************************
+ * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ ***************************************************************************/
+
+#ifndef _AM_CRYPT_H
+#define _AM_CRYPT_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+/****************************************************************************
+ * Error code definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+/**\brief */
+typedef struct
+{
+	void *(*open)();
+	int   (*close)(void *cryptor);
+	void  (*crypt)(void *cryptor,
+		uint8_t *dst, uint8_t *src, int len,
+		int decrypt);
+} AM_Crypt_Ops_t;
+
+#define CRYPT_SET(_ops_) ((_ops_) && (_ops_)->crypt)
+
+/****************************************************************************
+ * Function prototypes
+ ***************************************************************************/
+
+void *AM_CRYPT_des_open(const uint8_t *key, int key_bits);
+
+int AM_CRYPT_des_close(void *cryptor);
+
+void AM_CRYPT_des_crypt(void* cryptor, uint8_t* dst, const uint8_t *src, int len, uint8_t *iv, int decrypt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_debug.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_debug.h
new file mode 100644
index 0000000..cd1ab71
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_debug.h
@@ -0,0 +1,99 @@
+/***************************************************************************
+ * Copyright (C) 2017 Amlogic, Inc. 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.
+ *
+ * Description:
+ */
+/**\file
+ * \brief DEBUG 信息输出设置
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-05-12: create the document
+ ***************************************************************************/
+
+#ifndef _AM_DEBUG_H
+#define _AM_DEBUG_H
+
+#include "am_util.h"
+#include <stdio.h>
+#include "am_misc.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+#ifndef AM_DEBUG_LEVEL
+#define AM_DEBUG_LEVEL 500
+#endif
+
+#define AM_DEBUG_LOGLEVEL_DEFAULT 1
+
+#define AM_DEBUG_WITH_FILE_LINE
+#ifdef AM_DEBUG_WITH_FILE_LINE
+#define AM_DEBUG_FILE_LINE fprintf(stderr, "(\"%s\" %d)", __FILE__, __LINE__);
+#else
+#define AM_DEBUG_FILE_LINE
+#endif
+
+/**\brief 输出调试信息
+ *如果_level小于等于文件中定义的宏AM_DEBUG_LEVEL,则输出调试信息。
+ */
+#ifndef ANDROID
+#define AM_DEBUG(_level,_fmt...) \
+	AM_MACRO_BEGIN\
+	if ((_level)<=(AM_DEBUG_LEVEL))\
+	{\
+		fprintf(stderr, "AM_DEBUG:");\
+		AM_DEBUG_FILE_LINE\
+		fprintf(stderr, _fmt);\
+		fprintf(stderr, "\n");\
+	}\
+	AM_MACRO_END
+#else
+#if 0
+#include <android/log.h>
+#ifndef TAG_EXT
+#define TAG_EXT
+#endif
+#endif
+
+#define log_print(...) printf
+#define AM_DEBUG(_level,_fmt...) \
+	AM_MACRO_BEGIN\
+	if (1)\
+	{\
+		log_print(_fmt);\
+	}\
+	AM_MACRO_END
+#endif
+/****************************************************************************
+ * Error code definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+/****************************************************************************
+ * Function prototypes  
+ ***************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_dmx.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_dmx.h
new file mode 100644
index 0000000..7deee60
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_dmx.h
@@ -0,0 +1,240 @@
+/***************************************************************************
+ * Copyright (C) 2017 Amlogic, Inc. 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.
+ *
+ * Description:
+ */
+/**\file
+ * \brief Demux module
+ *
+ * Basic data strucutres definition in "linux/dvb/dmx.h"
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-05-21: create the document
+ ***************************************************************************/
+
+#ifndef _AM_DMX_H
+#define _AM_DMX_H
+
+#include "am_types.h"
+/*add for config define for linux dvb *.h*/
+#include "am_config.h"
+#include <linux/dvb/dmx.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+/****************************************************************************
+ * Error code definitions
+ ****************************************************************************/
+
+/**\brief Error code of the demux module*/
+enum AM_DMX_ErrorCode
+{
+	AM_DMX_ERROR_BASE=AM_ERROR_BASE(AM_MOD_DMX),
+	AM_DMX_ERR_INVALID_DEV_NO,          /**< Invalid device number*/
+	AM_DMX_ERR_INVALID_ID,              /**< Invalid filer handle*/
+	AM_DMX_ERR_BUSY,                    /**< The device has already been openned*/
+	AM_DMX_ERR_NOT_ALLOCATED,           /**< The device has not been allocated*/
+	AM_DMX_ERR_CANNOT_CREATE_THREAD,    /**< Cannot create new thread*/
+	AM_DMX_ERR_CANNOT_OPEN_DEV,         /**< Cannot open device*/
+	AM_DMX_ERR_NOT_SUPPORTED,           /**< Not supported*/
+	AM_DMX_ERR_NO_FREE_FILTER,          /**< No free filter*/
+	AM_DMX_ERR_NO_MEM,                  /**< Not enough memory*/
+	AM_DMX_ERR_TIMEOUT,                 /**< Timeout*/
+	AM_DMX_ERR_SYS,                     /**< System error*/
+	AM_DMX_ERR_NO_DATA,                 /**< No data received*/
+	AM_DMX_ERR_END
+};
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+/**\brief Input source of the demux*/
+typedef enum
+{
+	AM_DMX_SRC_TS0,                    /**< TS input port 0*/
+	AM_DMX_SRC_TS1,                    /**< TS input port 1*/
+	AM_DMX_SRC_TS2,                    /**< TS input port 2*/
+	AM_DMX_SRC_TS3,                    /**< TS input port 3*/
+	AM_DMX_SRC_HIU,                     /**< HIU input (memory)*/
+	AM_DMX_SRC_HIU1,
+	AM_DMX_SRC_TS4,
+	AM_DMX_SRC_TS5,
+	AM_DMX_SRC_TS6,
+	AM_DMX_SRC_TS7,
+	AM_DMX_SRC_DMA0,
+	AM_DMX_SRC_DMA1,
+	AM_DMX_SRC_DMA2,
+	AM_DMX_SRC_DMA3,
+	AM_DMX_SRC_DMA4,
+	AM_DMX_SRC_DMA5,
+	AM_DMX_SRC_DMA6,
+	AM_DMX_SRC_DMA7,
+} AM_DMX_Source_t;
+
+/**\brief Demux device open parameters*/
+typedef struct
+{
+	AM_Bool_t use_sw_filter;           /**< M_TURE to use DVR software filters.*/
+	int       dvr_fifo_no;             /**< Async fifo number if use software filters.*/
+	int       dvr_buf_size;            /**< Async fifo buffer size if use software filters.*/
+} AM_DMX_OpenPara_t;
+
+/**\brief Filter received data callback function
+ * \a fandle is the filter's handle.
+ * \a data is the received data buffer pointer.
+ * \a len is the data length.
+ * If \a data == null, means timeout.
+ */
+typedef void (*AM_DMX_DataCb) (int dev_no, int fhandle, const uint8_t *data, int len, void *user_data);
+
+
+/****************************************************************************
+ * Function prototypes  
+ ***************************************************************************/
+
+/**\brief Open a demux device
+ * \param dev_no Demux device number
+ * \param[in] para Demux device's open parameters
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DMX_Open(int dev_no, const AM_DMX_OpenPara_t *para);
+
+/**\brief Close a demux device
+ * \param dev_no Demux device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DMX_Close(int dev_no);
+
+/**\brief Allocate a filter
+ * \param dev_no Demux device number
+ * \param[out] fhandle Return the allocated filter's handle
+ * \retval AM_SUCCESS On success
+ * \return Error Code
+ */
+extern AM_ErrorCode_t AM_DMX_AllocateFilter(int dev_no, int *fhandle);
+
+/**\brief Set a section filter's parameters
+ * \param dev_no Demux device number
+ * \param fhandle Filter handle
+ * \param[in] params Section filter's parameters
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DMX_SetSecFilter(int dev_no, int fhandle, const struct dmx_sct_filter_params *params);
+
+/**\brief Set a PES filter's parameters
+ * \param dev_no Demux device number
+ * \param fhandle Filter handle
+ * \param[in] params PES filter's parameters
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DMX_SetPesFilter(int dev_no, int fhandle, const struct dmx_pes_filter_params *params);
+
+/**\brief Release an unused filter
+ * \param dev_no Demux device number
+ * \param fhandle Filter handle
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DMX_FreeFilter(int dev_no, int fhandle);
+
+/**\brief Start filtering
+ * \param dev_no Demux device number
+ * \param fhandle Filter handle
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DMX_StartFilter(int dev_no, int fhandle);
+
+/**\brief Stop filtering
+ * \param dev_no Demux device number
+ * \param fhandle Filter handle
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DMX_StopFilter(int dev_no, int fhandle);
+
+/**\brief Set the ring queue buffer size of a filter
+ * \param dev_no Demux device number
+ * \param fhandle Filter handle
+ * \param size Ring queue buffer size in bytes
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DMX_SetBufferSize(int dev_no, int fhandle, int size);
+
+/**\brief Get a filter's data callback function
+ * \param dev_no Demux device number
+ * \param fhandle Filter handle
+ * \param[out] cb Return the data callback function of the filter
+ * \param[out] data Return the user defined parameter of the callback function
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DMX_GetCallback(int dev_no, int fhandle, AM_DMX_DataCb *cb, void **data);
+
+/**\brief Set a filter's data callback function
+ * \param dev_no Demux device number
+ * \param fhandle Filter handle
+ * \param[in] cb New data callback function
+ * \param[in] data User defined parameter of the callback function
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DMX_SetCallback(int dev_no, int fhandle, AM_DMX_DataCb cb, void *data);
+
+/**\brief Set the demux's input source
+ * \param dev_no Demux device number
+ * \param src Input source
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DMX_SetSource(int dev_no, AM_DMX_Source_t src);
+
+/**\cond */
+/**\brief Sync the demux data
+ * \param dev_no Demux device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DMX_Sync(int dev_no);
+/**\endcond */
+
+/**
+ * Get the scramble status of the AV channels in the demux
+ * \param dev_no Demux device number
+ * \param[out] dev_status Return the AV channels's scramble status.
+ * dev_status[0] is the video status, dev_status[1] is the audio status.
+ * AM_TRUE means the channel is scrambled, AM_FALSE means the channel is not scrambled.
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DMX_GetScrambleStatus(int dev_no, AM_Bool_t dev_status[2]);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_dsc.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_dsc.h
new file mode 100644
index 0000000..a7b8a6c
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_dsc.h
@@ -0,0 +1,206 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief Descrambler device module
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-08-06: create the document
+ ***************************************************************************/
+
+#ifndef _AM_DSC_H
+#define _AM_DSC_H
+
+#include "am_types.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+/* For sec os mode */
+#define DSC_SEC_CaLib 	"libam_sec_dsc.so"
+#define KL_SEC_Lib 		"libam_kl_api.so"
+
+/****************************************************************************
+ * Error code definitions
+ ****************************************************************************/
+
+/**\brief Error code of the descrambler module*/
+enum AM_DSC_ErrorCode
+{
+	AM_DSC_ERROR_BASE=AM_ERROR_BASE(AM_MOD_DSC),
+	AM_DSC_ERR_INVALID_DEV_NO,          /**< Invalid device number*/
+	AM_DSC_ERR_BUSY,                    /**< The device is busy*/
+	AM_DSC_ERR_NOT_ALLOCATED,           /**< The device has not been allocated*/
+	AM_DSC_ERR_CANNOT_OPEN_DEV,         /**< Cannot open the device*/
+	AM_DSC_ERR_NOT_SUPPORTED,           /**< Not supported*/
+	AM_DSC_ERR_NO_FREE_CHAN,            /**< No free channel left*/
+	AM_DSC_ERR_NO_MEM,                  /**< Not enough memory*/
+	AM_DSC_ERR_SYS,                     /**< System error*/
+	AM_DSC_ERR_INVALID_ID,              /**< Invalid channel index*/
+	AM_DSC_ERR_END
+};
+
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+/**\brief Descrambler device open parameters*/
+typedef struct
+{
+	int  foo;
+} AM_DSC_OpenPara_t;
+
+/**\brief Work enviorment, tee/kernel */
+typedef enum _work_mode_e{
+	DSC_MODE_NORMAL,
+	DSC_MODE_SEC,
+	DSC_MODE_MAX
+}AM_DSC_WorkMode_e;
+
+/**\brief Parity */
+typedef enum _key_parity{
+	DSC_KEY_ODD,
+	DSC_KEY_EVEN
+}AM_DSC_KeyParity_e;
+
+/**\brief Video encrypt algoritm */
+typedef enum {
+	CW_ALGO_AES = 0,
+	CW_ALGO_DVBCSA = 1,
+	CW_ALGO_MAX = 2,
+} CW_ALGO_T;
+
+typedef enum {
+	DSC_DSC_CBC = 1,
+	DSC_DSC_ECB,
+	DSC_DSC_IDSA
+}AM_DSC_MODE_t;
+
+/**\brief CW key type */
+typedef enum {
+	AM_DSC_KEY_TYPE_EVEN = 0,        /**< DVB-CSA even control word*/
+	AM_DSC_KEY_TYPE_ODD = 1,         /**< DVB-CSA odd control word*/
+	AM_DSC_KEY_TYPE_AES_EVEN = 2,    /**< AES even control word*/
+	AM_DSC_KEY_TYPE_AES_ODD = 3,     /**< AES odd control word*/
+	AM_DSC_KEY_TYPE_AES_IV_EVEN = 4, /**< AES-CBC even control word's IV data*/
+	AM_DSC_KEY_TYPE_AES_IV_ODD = 5,  /**< AES-CBC odd control word's IV data*/
+	AM_DSC_KEY_TYPE_DES_EVEN = 6,    /**< DES even control word*/
+	AM_DSC_KEY_TYPE_DES_ODD = 7,     /**< DES odd control word*/
+	AM_DSC_KEY_TYPE_SM4_EVEN = 8,	 /**< SM4 even key */
+	AM_DSC_KEY_TYPE_SM4_ODD = 9,	 /**< SM4 odd key */
+	AM_DSC_KEY_TYPE_SM4_EVEN_IV = 10,/**< SM4-CBC iv even key */
+	AM_DSC_KEY_TYPE_SM4_ODD_IV = 11, /**< SM4-CBC iv odd key */
+	AM_DSC_KEY_FROM_KL = (1<<7)      /**< Read the control word from hardware keyladder*/
+} AM_DSC_KeyType_t;
+
+/**\brief Input source of the descrambler*/
+typedef enum {
+	AM_DSC_SRC_DMX0,         /**< Demux device 0*/
+	AM_DSC_SRC_DMX1,         /**< Demux device 1*/
+	AM_DSC_SRC_DMX2,         /**< Demux device 2*/
+	AM_DSC_SRC_BYPASS        /**< Bypass TS data*/
+} AM_DSC_Source_t;
+
+typedef AM_ErrorCode_t (*AM_KL_SEC_GetKeys_t)(int index, int level, unsigned char keys[6][16]);
+
+
+/****************************************************************************
+ * Function prototypes
+ ***************************************************************************/
+
+/**\brief Open a descrambler device
+ * \param dev_no Descrambler device number
+ * \param[in] para Device open paramaters
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DSC_Open(int dev_no, const AM_DSC_OpenPara_t *para);
+
+/**\brief Allocate a new descrambler channel
+ * \param dev_no Descrambler device number
+ * \param[out] chan_id Return the new channel's index
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DSC_AllocateChannel(int dev_no, int *chan_id);
+
+/**\brief Set the descrambler channel's PID value
+ * \param dev_no Descrambler device number
+ * \param chan_id Descrambler channel's index
+ * \param pid PID value
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DSC_SetChannelPID(int dev_no, int chan_id, uint16_t pid);
+
+/**\brief Set the control word to the descrambler channel
+ * \param dev_no Descrambler device number
+ * \param chan_id Descrambler channel's index
+ * \param type Control word's type
+ * \param[in] key Control word
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DSC_SetKey(int dev_no, int chan_id, AM_DSC_KeyType_t type, const uint8_t *key);
+
+/**\brief Release an unused descrambler channel
+ * \param dev_no Descrambler device number
+ * \param chan_id Descrambler channel's index to be released
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DSC_FreeChannel(int dev_no, int chan_id);
+
+/**\brief Close the descrambler device
+ * \param dev_no Descrambler device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DSC_Close(int dev_no);
+
+/**\brief Set the input source of the descrambler device
+ * \param dev_no Descrambler device number
+ * \param src Input source
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DSC_SetSource(int dev_no, AM_DSC_Source_t src);
+
+/**\brief Set the output of descrambler device
+ * \param dev_no Descrambler device number
+ * \param src destination demux
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DSC_SetOutput(int dev_no, int dst);
+
+/**\brief Set descrambler mode
+ * \param dev_no Descrambler device number
+ * \param mode
+ * \ typedef enum {
+	DSC_DSC_CBC = 1,
+	DSC_DSC_ECB,
+	DSC_DSC_IDSA
+ * \	}AM_DSC_MODE_t
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DSC_SetMode(int dev_no, int chan_id, int mode);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_dsc_type.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_dsc_type.h
new file mode 100644
index 0000000..c95023f
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_dsc_type.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
+ *
+ * All information contained herein is Amlogic confidential.
+ *
+ * This software is provided to you pursuant to Software License
+ * Agreement (SLA) with Amlogic Inc ("Amlogic"). This software may be
+ * used only in accordance with the terms of this agreement.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification is strictly prohibited without prior written permission
+ * from Amlogic.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __AM_DSC_TYPE__H__
+#define __AM_DSC_TYPE__H__
+typedef enum {
+	AM_DSC_KEY_TYPE_EVEN = 0,        /**< DVB-CSA even key */
+	AM_DSC_KEY_TYPE_ODD = 1,         /**< DVB-CSA odd key */
+	AM_DSC_KEY_TYPE_AES_EVEN = 2,    /**< AES even key */
+	AM_DSC_KEY_TYPE_AES_ODD = 3,     /**< AES odd key */
+	AM_DSC_KEY_TYPE_AES_IV_EVEN = 4, /**< AES-CBC iv even key */
+	AM_DSC_KEY_TYPE_AES_IV_ODD = 5,  /**< AES-CBC iv odd key */
+	AM_DSC_KEY_TYPE_DES_EVEN = 6,    /**< DES even key */
+	AM_DSC_KEY_TYPE_DES_ODD = 7,     /**< DES odd key */
+	AM_DSC_KEY_TYPE_SM4_EVEN = 8,	 /**< SM4 even key */
+	AM_DSC_KEY_TYPE_SM4_ODD = 9,	 /**< SM4 odd key */
+	AM_DSC_KEY_TYPE_SM4_EVEN_IV = 10,/**< SM4-CBC iv even key */
+	AM_DSC_KEY_TYPE_SM4_ODD_IV = 11, /**< SM4-CBC iv odd key */
+	AM_DSC_KEY_FROM_KL = (1<<7)      /**< Key from keyladder flag */
+} AM_DSC_KeyType_t;
+#endif
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_dvr.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_dvr.h
new file mode 100644
index 0000000..cf5a3f3
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_dvr.h
@@ -0,0 +1,148 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief DVR module
+ *
+ * DVR module use asyncfifo to record TS stream from a demux.
+ * Each demux has a corresponding DVR device.
+ *
+ * \author Xia Lei Peng <leipeng.xia@amlogic.com>
+ * \date 2010-12-13: create the document
+ ***************************************************************************/
+
+#ifndef _AM_DVR_H
+#define _AM_DVR_H
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <am_types.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+#define AM_DVR_MAX_PID_COUNT  (32)
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+/**\brief DVR module's error code*/
+enum AM_DVR_ErrorCode
+{
+	AM_DVR_ERROR_BASE=AM_ERROR_BASE(AM_MOD_DVR),
+	AM_DVR_ERR_INVALID_ARG,			/**< Invalid argument*/
+	AM_DVR_ERR_INVALID_DEV_NO,		/**< Invalid decide number*/
+	AM_DVR_ERR_BUSY,                        /**< The device has already been openned*/
+	AM_DVR_ERR_NOT_ALLOCATED,           /**< The device has not been allocated*/
+	AM_DVR_ERR_CANNOT_CREATE_THREAD,    /**< Cannot create a new thread*/
+	AM_DVR_ERR_CANNOT_OPEN_DEV,         /**< Cannot open the device*/
+	AM_DVR_ERR_NOT_SUPPORTED,           /**< Not supported*/
+	AM_DVR_ERR_NO_MEM,                  /**< Not enough memory*/
+	AM_DVR_ERR_TIMEOUT,                 /**< Timeout*/
+	AM_DVR_ERR_SYS,                     /**< System error*/
+	AM_DVR_ERR_NO_DATA,                 /**< No data received*/
+	AM_DVR_ERR_CANNOT_OPEN_OUTFILE,		/**< Cannot open the output file*/
+	AM_DVR_ERR_TOO_MANY_STREAMS,		/**< PID number is too big*/
+	AM_DVR_ERR_STREAM_ALREADY_ADD,		/**< The elementary stream has already been added*/
+	AM_DVR_ERR_END
+};
+
+
+/**\brief DVR device open parameters*/
+typedef struct
+{
+	int    foo;	
+} AM_DVR_OpenPara_t;
+
+/**\brief Recording parameters*/
+typedef struct
+{
+	int		pid_count; /**< PID number*/
+	int		pids[AM_DVR_MAX_PID_COUNT]; /**< PID array*/
+} AM_DVR_StartRecPara_t;
+
+/**\brief DVR recording source*/
+typedef enum
+{
+	AM_DVR_SRC_ASYNC_FIFO0, /**< asyncfifo 0*/
+	AM_DVR_SRC_ASYNC_FIFO1, /**< asyncfifo 1*/
+	AM_DVR_SRC_ASYNC_FIFO2, /**< asyncfifo 2*/
+}AM_DVR_Source_t;
+
+/****************************************************************************
+ * Function prototypes  
+ ***************************************************************************/
+
+/**\brief Open a DVR device
+ * \param dev_no DVR device number
+ * \param[in] para DVR device open parameters
+ * \retval AM_SUCCESS On succes
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DVR_Open(int dev_no, const AM_DVR_OpenPara_t *para);
+
+/**\brief Close an unused DVR device
+ * \param dev_no DVR device number
+ * \retval AM_SUCCESS On succes
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DVR_Close(int dev_no);
+
+/**\brief Set the DVR device's ring queue buffer size.
+ * \param dev_no DVR device number
+ * \param size Ring queue buffer size
+ * \retval AM_SUCCESS On succes
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DVR_SetBufferSize(int dev_no, int size);
+
+/**\brief Start recording
+ * \param dev_no DVR device number
+ * \param [in] para Recording parameters
+ * \retval AM_SUCCESS On succes
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DVR_StartRecord(int dev_no, const AM_DVR_StartRecPara_t *para);
+
+/**\brief Stop recording
+ * \param dev_no DVR device number
+ * \retval AM_SUCCESS On succes
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DVR_StopRecord(int dev_no);
+
+/**\brief Set the DVR input source
+ * \param dev_no DVR device number
+ * \param	src DVR input source
+ * \retval AM_SUCCESS On succes
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_DVR_SetSource(int dev_no, AM_DVR_Source_t src);
+
+/**\brief Read TS data from a DVR device
+ * \param dev_no DVR device number
+ * \param[out] buf TS output buffer
+ * \param size	The buffer size in bytes
+ * \param timeout_ms Timeout in milliseconds
+ * \return Read data size in bytes
+ */
+extern int AM_DVR_Read(int dev_no, uint8_t *buf, int size, int timeout_ms);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_evt.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_evt.h
new file mode 100644
index 0000000..4cf42c4
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_evt.h
@@ -0,0 +1,99 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief Driver event module
+ *
+ * Event is driver asyncronized message callback mechanism.
+ * User can register multiply callback functions in one event.
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-09-10: create the document
+ ***************************************************************************/
+
+#ifndef _AM_EVT_H
+#define _AM_EVT_H
+
+#include "am_types.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+#define AM_EVT_TYPE_BASE(no)    ((no)<<24)
+
+/****************************************************************************
+ * Error code definitions
+ ****************************************************************************/
+
+/**\brief Error code of the event module*/
+enum AM_EVT_ErrorCode
+{
+	AM_EVT_ERROR_BASE=AM_ERROR_BASE(AM_MOD_EVT),
+	AM_EVT_ERR_NO_MEM,                  /**< Not enough memory*/
+	AM_EVT_ERR_NOT_SUBSCRIBED,          /**< The event is not subscribed*/
+	AM_EVT_ERR_END
+};
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+/**\brief Event callback function
+ * \a dev_no The device number.
+ * \a event_type The event type.
+ * \a param The event callback's parameter.
+ * \a data User defined data registered when event subscribed.
+ */
+typedef void (*AM_EVT_Callback_t)(long dev_no, int event_type, void *param, void *data);
+
+/****************************************************************************
+ * Function prototypes  
+ ***************************************************************************/
+
+/**\brief Subscribe an event
+ * \param dev_no Device number generated the event
+ * \param event_type Event type
+ * \param cb Callback function's pointer
+ * \param data User defined parameter of the callback function
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_EVT_Subscribe(long dev_no, int event_type, AM_EVT_Callback_t cb, void *data);
+
+/**\brief Unsubscribe an event
+ * \param dev_no Device number generated the event
+ * \param event_type Event type
+ * \param cb Callback function's pointer
+ * \param data User defined parameter of the callback function
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_EVT_Unsubscribe(long dev_no, int event_type, AM_EVT_Callback_t cb, void *data);
+
+/**\brief Signal an event occured
+ * \param dev_no The device number generate the event
+ * \param event_type Event type
+ * \param[in] param Parameter of the event
+ */
+extern AM_ErrorCode_t AM_EVT_Signal(long dev_no, int event_type, void *param);
+
+extern AM_ErrorCode_t AM_EVT_Init();
+extern AM_ErrorCode_t AM_EVT_Destory();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_fend.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_fend.h
new file mode 100644
index 0000000..14f5653
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_fend.h
@@ -0,0 +1,472 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief DVB Frontend Module
+ *
+ * Basic data structures definition in "linux/dvb/frontend.h"
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-06-07: create the document
+ ***************************************************************************/
+
+#ifndef _AM_FEND_H
+#define _AM_FEND_H
+
+#include "am_types.h"
+#include "am_evt.h"
+#include "am_dmx.h"
+/*add for config define for linux dvb *.h*/
+#include "am_config.h"
+#include <linux/dvb/frontend.h>
+
+// #ifdef FE_SET_FRONTEND
+// #undef FE_SET_FRONTEND
+// #define FE_SET_FRONTEND FE_SET_FRONTEND_EX
+// #endif
+
+// #ifdef FE_GET_FRONTEND
+// #undef FE_GET_FRONTEND
+// #define FE_GET_FRONTEND FE_GET_FRONTEND_EX
+// #endif
+
+//#define dvb_frontend_parameters dvb_frontend_parameters_ex
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+/****************************************************************************
+ * Error code definitions
+ ****************************************************************************/
+
+/**\brief Error code of the fend module*/
+enum AM_FEND_ErrorCode
+{
+	AM_FEND_ERROR_BASE=AM_ERROR_BASE(AM_MOD_FEND),
+	AM_FEND_ERR_NO_MEM,                   /**< Not enough memory*/
+	AM_FEND_ERR_BUSY,                     /**< The device has already been openned*/
+	AM_FEND_ERR_INVALID_DEV_NO,           /**< Invalid device numbe*/
+	AM_FEND_ERR_NOT_OPENNED,              /**< The device not open*/
+	AM_FEND_ERR_CANNOT_CREATE_THREAD,     /**< Cannot create new thread*/
+	AM_FEND_ERR_NOT_SUPPORTED,            /**< Not supported*/
+	AM_FEND_ERR_CANNOT_OPEN,              /**< Cannot open device*/
+	AM_FEND_ERR_TIMEOUT,                  /**< Timeout*/
+	AM_FEND_ERR_INVOKE_IN_CB,             /**< Invoke in callback function*/
+	AM_FEND_ERR_IO,                       /**< IO error*/
+	AM_FEND_ERR_BLINDSCAN, 				  /**< Blindscan error*/
+	AM_FEND_ERR_BLINDSCAN_INRUNNING, 	  /**< In Blindscan*/
+	AM_FEND_ERR_END
+};
+
+/****************************************************************************
+ * Event type definitions
+ ****************************************************************************/
+
+/**\brief DVB frontend event type*/
+enum AM_FEND_EventType
+{
+	AM_FEND_EVT_BASE=AM_EVT_TYPE_BASE(AM_MOD_FEND),
+	AM_FEND_EVT_STATUS_CHANGED,    /**< Frontend status changed, argument's type: struct dvb_frontend_event*/
+	AM_FEND_EVT_ROTOR_MOVING,    /**< Rotor moving*/
+	AM_FEND_EVT_ROTOR_STOP,    /**< Rotor stop*/
+	AM_FEND_EVT_SHORT_CIRCUIT, /**< Frontend circuit*/
+	AM_FEND_EVT_SHORT_CIRCUIT_REPAIR, /**< Frontend circuit repair*/
+	AM_VLFEND_EVT_STATUS_CHANGED,
+	AM_FEND_EVT_END
+};
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+/**\brief frontend open parameter*/
+typedef struct
+{
+	int mode;
+	#define FE_AUTO (-1)    /**< Do not care the mode*/
+	#define FE_UNKNOWN (-2) /**< Set mode to unknown, something like reset*/
+} AM_FEND_OpenPara_t;
+
+/**\brief frontend callback function*/
+typedef void (*AM_FEND_Callback_t) (int dev_no, struct dvb_frontend_event *evt, void *user_data);
+
+/**\brief Frontend blindscan status*/
+typedef enum
+{
+	AM_FEND_BLIND_START,			/**< Blindscan start*/
+	AM_FEND_BLIND_UPDATEPROCESS,	/**< Blindscan update process*/
+	AM_FEND_BLIND_UPDATETP			/**< Blindscan update transport program*/
+} AM_FEND_BlindStatus_t;
+
+/**\brief Blindscan event*/
+typedef struct
+{
+	AM_FEND_BlindStatus_t    status; /**< Blindscan status*/
+	union
+	{
+		unsigned int freq;
+		unsigned int process;
+	};
+} AM_FEND_BlindEvent_t;
+
+/**\brief Blindscan callback function*/
+typedef void (*AM_FEND_BlindCallback_t) (int dev_no, AM_FEND_BlindEvent_t *evt, void *user_data);
+
+
+/****************************************************************************
+ * Function prototypes  
+ ***************************************************************************/
+
+/**\brief open a frontend device
+ * \param dev_no frontend device number
+ * \param[in] para frontend's device open parameters
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Open(int dev_no, const AM_FEND_OpenPara_t *para);
+
+/**\brief close a frontend device
+ * \param dev_no frontend device number
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_OpenEx(int dev_no, const AM_FEND_OpenPara_t *para, int *fe_fd);
+extern AM_ErrorCode_t AM_FEND_Close(int dev_no);
+extern AM_ErrorCode_t AM_FEND_CloseEx(int dev_no, AM_Bool_t reset);
+
+
+/**\brief set frontend deivce mode
+ * \param dev_no frontend device number
+ * \param mode frontend demod mode
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_SetMode(int dev_no, int mode);
+
+/**\brief get frontend device infomation
+ * \param dev_no frontend device number
+ * \param[out] info return frontend infomation struct
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_GetInfo(int dev_no, struct dvb_frontend_info *info);
+
+/**\brief get a frontend device's ts source
+ * \param dev_no frontend device number
+ * \param[out] src retrun device's ts source
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_GetTSSource(int dev_no, AM_DMX_Source_t *src);
+
+/**\brief set frontend parameter
+ * \param dev_no frontend device number
+ * \param[in] para frontend parameter
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_SetPara(int dev_no, const struct dvb_frontend_parameters *para);
+
+/**
+ * \brief set frontend property
+ * \param dev_no frontend device number
+ * \param[in] prop frontend device property
+ * \return
+ *   - AM_SUCCESS onSuccess
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_SetProp(int dev_no, const struct dtv_properties *prop);
+
+/**\brief get frontend parameter
+ * \param dev_no frontend device number
+ * \param[out] para return frontend parameter
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_GetPara(int dev_no, struct dvb_frontend_parameters *para);
+
+/**
+ * \brief get frontend property
+ * \param dev_no frontend device number
+ * \param[out] prop return frontend device property
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_GetProp(int dev_no, struct dtv_properties *prop);
+
+/**\brief get frontend lock status
+ * \param dev_no frontend device number
+ * \param[out] status return frontend lock status
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_GetStatus(int dev_no, fe_status_t *status);
+
+/**\brief get frontend device's SNR
+ * \param dev_no frontend device number
+ * \param[out] snr return SNR
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_GetSNR(int dev_no, int *snr);
+
+/**\brief get frontend device's BER
+ * \param dev_no frontend device number
+ * \param[out] ber return frontend's BER
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_GetBER(int dev_no, int *ber);
+
+/**\brief get frontend device's signal strength
+ * \param dev_no frontend device number
+ * \param[out] strength return signal strength
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_GetStrength(int dev_no, int *strength);
+
+/**\brief get frontend device's callback function
+ * \param dev_no frontend device number
+ * \param[out] cb return callback function
+ * \param[out] user_data callback function's parameters
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_GetCallback(int dev_no, AM_FEND_Callback_t *cb, void **user_data);
+
+/**\brief register the frontend callback function
+ * \param dev_no frontend device function
+ * \param[in] cb callback function
+ * \param[in] user_data callback function's parameter
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_SetCallback(int dev_no, AM_FEND_Callback_t cb, void *user_data);
+
+/**\brief enable or disable frontend callback
+ * \param dev_no frontend device number
+ * \param[in] enable_cb enable or disable
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_SetActionCallback(int dev_no, AM_Bool_t enable_cb);
+
+/**\brief try to lock frontend and wait lock status
+ * \param dev_no device frontend number
+ * \param[in] para frontend parameters
+ * \param[out] status return frontend lock status
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Lock(int dev_no, const struct dvb_frontend_parameters *para, fe_status_t *status);
+
+/**\brief set frontend thread delay time
+ * \param dev_no frontend device number
+ * \param delay time value in millisecond,  0 means no time interval and frontend thread will stop
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_SetThreadDelay(int dev_no, int delay);
+
+/**\brief reset digital satellite equipment control
+ * \param dev_no frontend device number
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_DiseqcResetOverload(int dev_no); 
+
+/**\brief send digital satellite command
+ * \param dev_no frontend device number
+ * \param[in] cmd control command
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_DiseqcSendMasterCmd(int dev_no, struct dvb_diseqc_master_cmd* cmd); 
+
+/**\brief recv digital satellite command's reply
+ * \param dev_no frontend device number
+ * \param[out] reply digital satellite's reply
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_DiseqcRecvSlaveReply(int dev_no, struct dvb_diseqc_slave_reply* reply); 
+
+/**\brief sent command to control tone burst
+ * \param dev_no frontend device number
+ * \param minicmd tone burst command
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_DiseqcSendBurst(int dev_no, fe_sec_mini_cmd_t minicmd); 
+
+/**\brief set tone mode
+ * \param dev_no frontend device number
+ * \param tone device tone mode
+ * \return
+ *   - AM_SUCCESS On Success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_SetTone(int dev_no, fe_sec_tone_mode_t tone); 
+
+/**\brief set device voltage
+ * \param dev_no frontend device number
+ * \param voltage device voltage
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_SetVoltage(int dev_no, fe_sec_voltage_t voltage); 
+
+/**\brief enable device High Lnb Voltage
+ * \param dev_no frontend device number
+ * \param arg 0 means disable, !=0 means enable
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_EnableHighLnbVoltage(int dev_no, long arg);                          
+                                                                           
+/**\brief start satellite blind scan
+ * \param dev_no frontend device number
+ * \param[in] cb blind scan callback function
+ * \param[in] user_data callback function parameter
+ * \param start_freq start frequency unit HZ
+ * \param stop_freq stop frequency unit HZ
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_BlindScan(int dev_no, AM_FEND_BlindCallback_t cb, void *user_data, unsigned int start_freq, unsigned int stop_freq);
+
+/**\brief exit blind scan
+ * \param dev_no frontend device number
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_BlindExit(int dev_no); 
+
+/**\brief get blind scan process
+ * \param dev_no frontend device number
+ * \param[out] process blind scan process 0-100
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_BlindGetProcess(int dev_no, unsigned int *process);
+
+/**\brief 卫星盲扫信息
+ * \param dev_no 前端设备号
+ * \param[in out] para in 盲扫频点信息缓存区大小,out 盲扫频点个数
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_fend.h)
+ */
+AM_ErrorCode_t AM_FEND_BlindGetTPCount(int dev_no, unsigned int *count);
+
+
+/**\brief get blind scan TP infomation
+ * \param dev_no frontend device number
+ * \param[out] para blindscan parameters
+ * \param[out] count parameters's count
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_BlindGetTPInfo(int dev_no, struct dvb_frontend_parameters *para, unsigned int count);
+
+/**\brief try to tune
+ *\param dev_no frontend device number
+ *\param freq frequency unit Hz
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_FineTune(int dev_no, unsigned int freq);
+
+/**\brief set CVBS AMP OUT
+ *\param dev_no frontend device number
+ *\param amp AMP
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_SetCvbsAmpOut(int dev_no, unsigned int amp);
+
+/**\brief get atv status
+ *\param dev_no frontend device number
+ *\param[out] atv_status return atv status struct
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+AM_ErrorCode_t AM_FEND_GetAtvStatus(int dev_no,  atv_status_t *atv_status);
+
+/**\brief try to set AFC
+ *\param dev_no frontend device number
+ *\param afc AFC
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+AM_ErrorCode_t AM_FEND_SetAfc(int dev_no, unsigned int afc);
+
+
+/**\brief try to set sub sys
+ *\param dev_no frontend device number
+ *\param sub_sys fend type,T or T2,C-A C-B OR C-A
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+AM_ErrorCode_t AM_FEND_SetSubSystem(int dev_no, unsigned int sub_sys);
+
+
+/**\brief try to get sub sys
+ *\param dev_no frontend device number
+ *\param sub_sys fend type,use to indentify T or T2,C-A C-B OR C-C
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+AM_ErrorCode_t AM_FEND_GetSubSystem(int dev_no, unsigned int *sub_sys);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_fend_diseqc_cmd.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_fend_diseqc_cmd.h
new file mode 100644
index 0000000..eca6a99
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_fend_diseqc_cmd.h
@@ -0,0 +1,428 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief Diseqc protocol command
+ *
+ * \author jiang zhongming <zhongming.jiang@amlogic.com>
+ * \date 2012-03-20: create the document
+ ***************************************************************************/
+
+#ifndef _AM_FEND_DISEQC_CMD_H
+#define _AM_FEND_DISEQC_CMD_H
+
+#include "am_types.h"
+#include "am_evt.h"
+/*add for config define for linux dvb *.h*/
+#include <am_config.h>
+#include <linux/dvb/frontend.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+/****************************************************************************
+ * Error code definitions
+ ****************************************************************************/
+
+/**\brief Diseqc error code*/
+enum AM_FEND_DISEQCCMD_ErrorCode
+{
+	AM_FEND_DISEQCCMD_ERROR_BASE=AM_ERROR_BASE(AM_MOD_FEND_DISEQCCMD),
+	AM_FEND_DISEQCCMD_ERR_END
+};
+
+/****************************************************************************
+ * Event type definitions
+ ****************************************************************************/
+
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+/**\brief DVB-S/S2 frontend switch input type*/
+typedef enum AM_FEND_SWITCHINPUT
+{
+	AM_FEND_SWITCH1INPUTA,
+	AM_FEND_SWITCH2INPUTA, 
+	AM_FEND_SWITCH3INPUTA,
+	AM_FEND_SWITCH4INPUTA,
+	AM_FEND_SWITCH1INPUTB,
+	AM_FEND_SWITCH2INPUTB,
+	AM_FEND_SWITCH3INPUTB,
+	AM_FEND_SWITCH4INPUTB	
+}AM_FEND_Switchinput_t; 
+
+/**\brief DVB-S/S2 frontend polraisation*/
+typedef enum AM_FEND_POLARISATION
+{
+	AM_FEND_POLARISATION_H,
+	AM_FEND_POLARISATION_V,
+	AM_FEND_POLARISATION_NOSET
+}AM_FEND_Polarisation_t; 
+
+/**\brief DVB-S/S2 frontend local oscillator frequency*/
+typedef enum AM_FEND_LOCALOSCILLATORFREQ
+{
+	AM_FEND_LOCALOSCILLATORFREQ_L,
+	AM_FEND_LOCALOSCILLATORFREQ_H,
+	AM_FEND_LOCALOSCILLATORFREQ_NOSET
+}AM_FEND_Localoscollatorfreq_t;
+
+/**\brief 22Khz parameter, match AM_SEC_22khz_Signal*/
+typedef enum {	AM_FEND_ON=0, AM_FEND_OFF=1 }AM_FEND_22khz_Signal; // 22 Khz
+
+/**\brief voltage parameter, match AM_SEC_Voltage_Mode*/
+typedef enum {	AM_FEND_13V=0, AM_FEND_18V=1 }AM_FEND_Voltage_Mode; // 13/18 V
+
+/**\brief DVB-S/S2 Frontend LOCAL OSCILLATOR FREQ TABLE*/
+typedef enum AM_FEND_LOT
+{
+	AM_FEND_LOT_STANDARD_NONE = 0x00,
+	AM_FEND_LOT_STANDARD_UNKNOWN,
+	AM_FEND_LOT_STANDARD_9750MHZ,
+	AM_FEND_LOT_STANDARD_10000MHZ,
+	AM_FEND_LOT_STANDARD_10600MHZ,
+	AM_FEND_LOT_STANDARD_10750MHZ,
+	AM_FEND_LOT_STANDARD_11000MHZ,
+	AM_FEND_LOT_STANDARD_11250MHZ,	
+	AM_FEND_LOT_STANDARD_11475MHZ,
+	AM_FEND_LOT_STANDARD_20250MHZ,
+	AM_FEND_LOT_STANDARD_5150MHZ,	
+	AM_FEND_LOT_STANDARD_1585MHZ,
+	AM_FEND_LOT_STANDARD_13850MHZ,
+	AM_FEND_LOT_WIDEBAND_NONE = 0x10,
+	AM_FEND_LOT_WIDEBAND_10000MHZ,
+	AM_FEND_LOT_WIDEBAND_10200MHZ,
+	AM_FEND_LOT_WIDEBAND_13250MHZ,
+	AM_FEND_LOT_WIDEBAND_13450MHZ
+}AM_FEND_LOT_t;
+                
+/**\brief DVB-S/S2 Frontend RF type*/
+typedef enum AM_FEND_RFType
+{
+	AM_FEND_RFTYPE_STANDARD,
+	AM_FEND_RFTYPE_WIDEBAND
+}AM_FEND_RFType_t;
+                
+
+/****************************************************************************
+ * Function prototypes  
+ ***************************************************************************/
+
+/**\brief reset Diseqc micro controller(Diseqc1.0 M*R)
+ * \param dev_no frontend device number
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_ResetDiseqcMicro(int dev_no);
+
+/**\brief standby the switch Diseqc(Diseqc1.0 R)
+ * \param dev_no frontend device number
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_StandbySwitch(int dev_no);
+
+/**\brief poweron the switch Diseqc(Diseqc1.0 R)
+ * \param dev_no frontend device number
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_PoweronSwitch(int dev_no);
+
+/**\brief Set Low Local Oscillator Freq(Diseqc1.0 R)
+ * \param dev_no frontend device number
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_SetLo(int dev_no);
+
+/**\brief set polarisation(Diseqc1.0 R)
+ * \param dev_no forntend device number
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_SetVR(int dev_no); 
+
+/**\brief choose satellite A (Diseqc1.0 R)
+ * \param dev_no frontend device number
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_SetSatellitePositionA(int dev_no); 
+
+/**\brief choose Switch Option A (Diseqc1.0 R)
+ * \param dev_no frontend device number
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_SetSwitchOptionA(int dev_no);
+
+/**\brief set High Local Oscillator Frequency(Diseqc1.0 R)
+ * \param dev_no frontend device number
+ * \return
+ *   - AM_SUCCESS On Success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_SetHi(int dev_no);
+
+/**\brief set horizontal polarisation(Diseqc1.0 R)
+ * \param dev_no frontend device number
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_SetHL(int dev_no);
+
+/**\brief set satellite B (Diseqc1.0 R)
+ * \param dev_no frontend device number
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_SetSatellitePositionB(int dev_no); 
+
+/**\brief set Switch Option B (Diseqc1.0 R)
+ * \param dev_no frontend device number
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_SetSwitchOptionB(int dev_no); 
+
+/**\brief set Switch input (Diseqc1.1 R)
+ * \param dev_no frontend device number
+ * \param switch_input switch input parameter
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_SetSwitchInput(int dev_no, AM_FEND_Switchinput_t switch_input);
+
+/**\brief set LNB1-LNB4/polarisation/local oscillator (Diseqc1.0 M)
+ * \param dev_no frontend device number
+ * \param lnbport LNB1-LNB4/LNBPort:AA=0, AB=1, BA=2, BB=3, SENDNO=4
+ * \param polarisation H/V
+ * \param local_oscillator_freq H/L
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_SetLNBPort4(int dev_no, int lnbport, 
+			AM_FEND_Polarisation_t polarisation,
+			AM_FEND_Localoscollatorfreq_t local_oscillator_freq);
+                                                                 
+/**\brief set LNB Port LNB1-LNB16 (Diseqc1.1 M)
+ * \param dev_no frontend device number
+ * \param lnbport LNB1-LNB16,LNBPort In 0xF0 .. 0xFF
+ * \param polarisation H/V
+ * \param local_oscillator_freq H/L
+ * \return
+ *   - AM_SUCCESS On Success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_SetLNBPort16(int dev_no, int lnbport,
+			AM_FEND_Polarisation_t polarisation,
+			AM_FEND_Localoscollatorfreq_t local_oscillator_freq);
+                                                                  
+/**\brief set channel frequency (Diseqc1.1 M)
+ * \param dev_no frontend device number
+ * \param freq unit KHZ 
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_SetChannelFreq(int dev_no, int freq);
+
+/**\brief set ositioner halt (Diseqc1.2 M)
+ * \param dev_no frontend device number
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_SetPositionerHalt(int dev_no);
+
+/**\brief enable positioner limit (Diseqc1.2 M)
+ * \param dev_no frontend deivce number
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_EnablePositionerLimit(int dev_no);
+																  
+/**\brief disable positioner limit (Diseqc1.2 M)
+ * \param dev_no frontend device number
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_DisablePositionerLimit(int dev_no);
+
+/**\brief enable positioner limit and store east limit (Diseqc1.2 M)
+ * \param dev_no frontend device number
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_SetPositionerELimit(int dev_no);
+
+/**\brief enable positioner limit and store west limit(Diseqc1.2 M)
+ * \param dev_no frontend device number
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_SetPositionerWLimit(int dev_no);
+
+/**\brief set positioner to go to east (Diseqc1.2 M)
+ * \param dev_no frontend device number
+ * \param unit 00 continuously 01-7F(unit second, e.g 01-one second 02-two second) 80-FF (unit step,e.g FF-one step FE-two step)
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_PositionerGoE(int dev_no, unsigned char unit);
+
+/**\brief set positioner to go to west (Diseqc1.2 M)
+ * \param dev_no frontend device number
+ * \param unit 00 continuously 01-7F(unit second, e.g 01-one second 02-two second) 80-FF (unit step,e.g FF-one step FE-two step)
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_PositionerGoW(int dev_no, unsigned char unit);
+
+/**\brief store position (Diseqc1.2 M)
+ * \param dev_no frontend device number
+ * \param position (e.g 1,2...)0 for reference.  actually it's not store ?
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_StorePosition(int dev_no, unsigned char position);
+
+/**\brief set positioner to last position (Diseqc1.2 M)
+ * \param dev_no frontend device number
+ * \param position (e.g 1,2...) 0 for reference
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_GotoPositioner(int dev_no, unsigned char position); 
+
+/**\brief position satellite with angular (longitude/latitude)
+ * \param dev_no frontend device number
+ * \param local_longitude
+ * \param local_latitude
+ * \param satellite_longitude
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_GotoxxAngularPositioner(int dev_no, double local_longitude, double local_latitude, double satellite_longitude);
+
+/**\brief position satellite with angular (USALS(another name Diseqc1.3) Diseqc extention)
+ * \param dev_no frontend device number
+ * \param local_longitude
+ * \param local_latitude
+ * \param satellite_longitude
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_GotoAngularPositioner(int dev_no, double local_longitude, double local_latitude, double satellite_longitude);
+                                                                       
+/**\brief set ODU channel (Diseqc extention)
+ * \param dev_no frontend device number
+ * \param ub_number user band number(0-7)
+ * \param inputbank_number input bank number (0-7)
+ * \param transponder_freq unit KHZ
+ * \param oscillator_freq unit KHZ
+ * \param ub_freq unit KHZ    
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_SetODUChannel(int dev_no, unsigned char ub_number, unsigned char inputbank_number,
+																int transponder_freq, int oscillator_freq, int ub_freq);
+       
+/**\brief set ODU UB to power off (Diseqc extention)
+ * \param dev_no frontend device numner
+ * \param ub_number user band number(0-7)  
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_SetODUPowerOff(int dev_no, unsigned char ub_number); 
+
+/**\brief set ODU UB to signal on (Diseqc extention)
+ * \param dev_no frontend device number
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_SetODUUbxSignalOn(int dev_no);
+                                                                 
+/**\brief set ODU config(Diseqc extention)
+ * \param dev_no frontend device number
+ * \param ub_number user band number(0-7)
+ * \param satellite_position_count
+ * \param input_bank_count input bank count
+ * \param rf_type frontend rf type
+ * \param ub_count user band count
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_SetODUConfig(int dev_no, unsigned char ub_number, 
+																unsigned char satellite_position_count,
+																unsigned char input_bank_count,
+																AM_FEND_RFType_t rf_type,
+																unsigned char ub_count);
+                                                                  
+/**\brief se ODU local oscillator (Diseqc extention)
+ * \param dev_no frontend device number
+ * \param ub_number user band number(0-7)    
+ * \param lot parameter in local oscillator table
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_FEND_Diseqccmd_SetODULoFreq(int dev_no, unsigned char ub_number, AM_FEND_LOT_t lot);                                                                  
+                                                                               
+
+/**\brief produce satellite angular (USALS(another name Diseqc1.3) Diseqc extention)
+ * \param dev_no frontend device number
+ * \param local_longitude
+ * \param local_latitude
+ * \param satellite_longitude
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern int AM_ProduceAngularPositioner(int dev_no, double local_longitude, double local_latitude, double satellite_longitude);
+																		
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_iconv.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_iconv.h
new file mode 100644
index 0000000..58b2c70
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_iconv.h
@@ -0,0 +1,183 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief iconv
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2012-08-10: create the document
+ ***************************************************************************/
+
+#ifndef _AM_ICONV_H
+#define _AM_ICONV_H
+
+#include "am_types.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#ifdef ANDROID
+#include <malloc.h>
+#include <unicode/ucnv.h>
+#include <unicode/putil.h>
+#include <unicode/uclean.h>
+#include <android/log.h>
+#include <dlfcn.h>
+#include <assert.h>
+#include <errno.h>
+#include "am_util.h"
+
+typedef struct {
+	UConverter *target;
+	UConverter *source;
+} AM_IConv_t;
+
+typedef AM_IConv_t* iconv_t;
+
+extern UConverter* (*am_ucnv_open_ptr)(const char *converterName, UErrorCode *err);
+extern void (*am_ucnv_close_ptr)(UConverter * converter);
+extern void (*am_ucnv_convertEx_ptr)(UConverter *targetCnv, UConverter *sourceCnv,
+		char **target, const char *targetLimit,
+		const char **source, const char *sourceLimit,
+		UChar *pivotStart, UChar **pivotSource,
+		UChar **pivotTarget, const UChar *pivotLimit,
+		UBool reset, UBool flush,
+		UErrorCode *pErrorCode);
+
+extern void am_ucnv_dlink(void);
+
+
+#ifdef USE_VENDOR_ICU
+extern void am_first_action(void);
+#define am_ucnv_open(conv, err)\
+	({\
+        UConverter *ret;\
+        am_first_action();\
+        ret = ucnv_open(conv, err);\
+        ret;\
+	 })
+#define am_ucnv_close(conv)\
+	AM_MACRO_BEGIN\
+		am_first_action();\
+		ucnv_close(conv);\
+	AM_MACRO_END
+#define am_ucnv_convertEx(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13)\
+	AM_MACRO_BEGIN\
+		am_first_action();\
+		ucnv_convertEx(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13);\
+	AM_MACRO_END
+#else
+#define am_ucnv_open(conv, err)\
+	({\
+	 	UConverter *ret;\
+		if(!am_ucnv_open_ptr)\
+	 		am_ucnv_dlink();\
+	 	ret = am_ucnv_open_ptr(conv, err);\
+	 	ret;\
+	 })
+#define am_ucnv_close(conv)\
+	AM_MACRO_BEGIN\
+		if(!am_ucnv_close_ptr)\
+	 		am_ucnv_dlink();\
+		am_ucnv_close_ptr(conv);\
+	AM_MACRO_END
+#define am_ucnv_convertEx(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13)\
+	AM_MACRO_BEGIN\
+		if(!am_ucnv_convertEx_ptr)\
+	 		am_ucnv_dlink();\
+		am_ucnv_convertEx_ptr(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13);\
+	AM_MACRO_END
+#endif
+
+static inline iconv_t
+iconv_open(const char *tocode, const char *fromcode)
+{
+	iconv_t cd = NULL;
+	UErrorCode err1 = U_ZERO_ERROR, err2 = U_ZERO_ERROR;
+
+	cd = (iconv_t)malloc(sizeof(AM_IConv_t));
+	if(!cd)
+		goto error;
+	
+	cd->target = (UConverter *)am_ucnv_open(tocode, &err1);
+	cd->source = (UConverter *)am_ucnv_open(fromcode, &err2);
+	if((!U_SUCCESS(err1)) || (!U_SUCCESS(err2)))
+		goto error;
+	
+	return cd;
+error:
+	if(cd)
+	{
+		if(U_SUCCESS(err1))
+			am_ucnv_close(cd->target);
+		else
+			errno = err1;//use errno for error code export
+		if(U_SUCCESS(err2))
+			am_ucnv_close(cd->source);
+		else
+			errno = err2;//use errno for error code export
+		free(cd);
+	}
+
+	return (iconv_t)-1;
+}
+
+static inline int
+iconv_close(iconv_t cd)
+{
+	if(!cd)
+		return 0;
+	
+	am_ucnv_close(cd->target);
+	am_ucnv_close(cd->source);
+	free(cd);
+
+	return 0;
+}
+
+static inline size_t
+iconv(iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
+{
+	UErrorCode err = U_ZERO_ERROR;
+	const char *sbegin, *send;
+	char *tbegin, *tend;
+
+	if(!cd)
+		return -1;
+
+	sbegin = *inbuf;
+	send   = sbegin + *inbytesleft;
+	tbegin = *outbuf;
+	tend   = tbegin + *outbytesleft;
+
+	am_ucnv_convertEx(cd->target, cd->source, &tbegin, tend, &sbegin, send,
+			NULL, NULL, NULL, NULL, FALSE, TRUE, &err);
+	if(!U_SUCCESS(err)) {
+		errno = err;//use errno for error code export
+		return -1;
+	}
+	
+	*inbuf  = (char*)sbegin;
+	*inbytesleft  = send - sbegin;
+	*outbuf = tbegin;
+	*outbytesleft = tend - tbegin;
+	return 0;
+}
+
+#else /*!defined(ANDROID)*/
+#include <iconv.h>
+#endif /*ANDROID*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_inp.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_inp.h
new file mode 100644
index 0000000..15a208b
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_inp.h
@@ -0,0 +1,198 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief 输入设备模块
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-05-19: create the document
+ ***************************************************************************/
+
+#ifndef _AM_INP_H
+#define _AM_INP_H
+
+#include "am_types.h"
+#include <linux/input.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+/****************************************************************************
+ * Error code definitions
+ ****************************************************************************/
+
+/**\brief 输入模块错误代码*/
+enum AM_INP_ErrorCode
+{
+	AM_INP_ERROR_BASE=AM_ERROR_BASE(AM_MOD_INP),
+	AM_INP_ERR_INVALID_DEV_NO,           /**< 无效的设备号*/
+	AM_INP_ERR_BUSY,                     /**< 设备已经打开*/
+	AM_INP_ERR_NOT_OPENNED,              /**< 设备还没有打开*/
+	AM_INP_ERR_CANNOT_OPEN_DEV,          /**< 打开设备失败*/
+	AM_INP_ERR_CANNOT_CREATE_THREAD,     /**< 无法创建线程*/
+	AM_INP_ERR_TIMEOUT,                  /**< 等待输入事件超时*/
+	AM_INP_ERR_NOT_SUPPORTED,            /**< 设备不支持此功能*/
+	AM_INP_ERR_READ_FAILED,              /**< 读取设备文件出错*/
+	AM_INP_ERR_UNKNOWN_KEY,              /**< 无效按键*/
+	AM_INP_ERR_END
+};
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+/**\brief 输入设备开启参数*/
+typedef struct
+{
+	AM_Bool_t    enable_thread;          /**< 始能输入事件检测线程*/
+} AM_INP_OpenPara_t;
+
+/**\brief 按键名*/
+typedef enum
+{
+	AM_INP_KEY_UNKNOWN,
+	AM_INP_KEY_UP,                       /**< 上*/
+	AM_INP_KEY_DOWN,                     /**< 下*/
+	AM_INP_KEY_LEFT,                     /**< 左*/
+	AM_INP_KEY_RIGHT,                    /**< 右*/
+	AM_INP_KEY_PGUP,                     /**< 上翻页*/
+	AM_INP_KEY_PGDOWN,                   /**< 下翻页*/
+	AM_INP_KEY_0,                        /**< 数字0*/
+	AM_INP_KEY_1,                        /**< 数字1*/
+	AM_INP_KEY_2,                        /**< 数字2*/
+	AM_INP_KEY_3,                        /**< 数字3*/
+	AM_INP_KEY_4,                        /**< 数字4*/
+	AM_INP_KEY_5,                        /**< 数字5*/
+	AM_INP_KEY_6,                        /**< 数字6*/
+	AM_INP_KEY_7,                        /**< 数字7*/
+	AM_INP_KEY_8,                        /**< 数字8*/
+	AM_INP_KEY_9,                        /**< 数字9*/
+	AM_INP_KEY_MUTE,                     /**< 静音*/
+	AM_INP_KEY_VOLUP,                    /**< 音量+*/
+	AM_INP_KEY_VOLDOWN,                  /**< 音量-*/
+	AM_INP_KEY_CHUP,                     /**< 频道+*/
+	AM_INP_KEY_CHDOWN,                   /**< 频道-*/
+	AM_INP_KEY_OK,                       /**< 确定*/
+	AM_INP_KEY_CANCEL,                   /**< 取消*/
+	AM_INP_KEY_MENU,                     /**< 菜单*/
+	AM_INP_KEY_EXIT,                     /**< 退出*/
+	AM_INP_KEY_BACK,                     /**< 返回*/
+	AM_INP_KEY_PLAY,                     /**< 播放*/
+	AM_INP_KEY_PAUSE,                    /**< 暂停*/
+	AM_INP_KEY_STOP,                     /**< 停止*/
+	AM_INP_KEY_REC,                      /**< 图像*/
+	AM_INP_KEY_SKIP,                     /**< 跳至下一个*/
+	AM_INP_KEY_REWIND,                   /**< 重新播放当前*/
+	AM_INP_KEY_POWER,                    /**< 电源*/
+	AM_INP_KEY_RED,                      /**< 红*/
+	AM_INP_KEY_YELLOW,                   /**< 黄*/
+	AM_INP_KEY_BLUE,                     /**< 蓝*/
+	AM_INP_KEY_GREEN,                    /**< 绿*/
+	AM_INP_KEY_COUNT
+} AM_INP_Key_t;
+
+/**\brief 键值映射表*/
+typedef struct
+{
+	int codes[AM_INP_KEY_COUNT];         /**< 存放每个按键的键码值*/
+} AM_INP_KeyMap_t;
+
+/**\brief 输入设备回调函数*/
+typedef void (*AM_INP_EventCb_t) (int dev_no, struct input_event *evt, void *user_data);
+
+/****************************************************************************
+ * Function prototypes  
+ ***************************************************************************/
+
+/**\brief 打开一个输入设备
+ * \param dev_no 输入设备号
+ * \param[in] para 设备开启参数
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_inp.h)
+ */
+extern AM_ErrorCode_t AM_INP_Open(int dev_no, const AM_INP_OpenPara_t *para);
+
+/**\brief 关闭一个输入设备
+ * \param dev_no 输入设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_inp.h)
+ */
+extern AM_ErrorCode_t AM_INP_Close(int dev_no);
+
+/**\brief 使能输入设备,之后输入设备产生的输入事件可以被读取
+ * \param dev_no 输入设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_inp.h)
+ */
+extern AM_ErrorCode_t AM_INP_Enable(int dev_no);
+
+/**\brief 禁止输入设备,禁止之后,设备不会返回输入事件
+ * \param dev_no 输入设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_inp.h)
+ */
+extern AM_ErrorCode_t AM_INP_Disable(int dev_no);
+
+/**\brief 等待一个输入事件
+ *挂起调用线程直到输入设备产生一个输入事件。如果超过超时时间没有事件,返回AM_INP_ERR_TIMEOUT。
+ * \param dev_no 输入设备号
+ * \param[out] evt 返回输入事件
+ * \param timeout 以毫秒为单位的超时时间,<0表示永远等待,=0表示检查后不等待立即返回
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_inp.h)
+ */
+extern AM_ErrorCode_t AM_INP_WaitEvent(int dev_no, struct input_event *evt, int timeout);
+
+/**\brief 向输入设备注册一个事件回调函数
+ *输入设备将创建一个线程,检查输入输入事件,如果有输入事件,线程调用回调函数。
+ *如果回调函数为NULL,表示取消回调函数,输入设备将结束事件检测线程。
+ * \param dev_no 输入设备号
+ * \param[in] cb 新注册的回调函数
+ * \param[in] user_data 回调函数的用户参数
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_inp.h)
+ */
+extern AM_ErrorCode_t AM_INP_SetCallback(int dev_no, AM_INP_EventCb_t cb, void *user_data);
+
+/**\brief 取得输入设备已经注册事件回调函数及参数
+ * \param dev_no 输入设备号
+ * \param[out] cb 返回回调函数指针
+ * \param[out] user_data 返回回调函数的用户参数
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_inp.h)
+ */
+extern AM_ErrorCode_t AM_INP_GetCallback(int dev_no, AM_INP_EventCb_t *cb, void **user_data);
+
+/**\brief 设定输入设备的键码映射表
+ * \param dev_no 输入设备号
+ * \param[in] map 新的键码映射表,如果为NULL表示不使用映射表,直接返回键值
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_inp.h)
+ */
+extern AM_ErrorCode_t AM_INP_SetKeyMap(int dev_no, const AM_INP_KeyMap_t *map);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_kl.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_kl.h
new file mode 100644
index 0000000..6e8d445
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_kl.h
@@ -0,0 +1,89 @@
+/*
+* Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+*
+* This source code is subject to the terms and conditions defined in the
+* file 'LICENSE' which is part of this source code package. *
+* Description:
+*/
+#ifndef MESON_AM_KL
+#define MESON_AM_KL
+#include <linux/types.h>
+#define MESON_KL_DEV "/dev/keyladder"
+#define MESON_KL_NUM 0
+#define MESON_KL_LEVEL 3
+#define MESON_KL_IOC_MAGIC 'k'
+#define MESON_KL_RUN              _IOW(MESON_KL_IOC_MAGIC, 13, \
+	int)
+#define MESON_KL_CR               _IOWR(MESON_KL_IOC_MAGIC, 14, \
+	struct meson_kl_cr_args)
+
+struct meson_kl_config{
+	unsigned char ekey5[16];
+	unsigned char ekey4[16];
+	unsigned char ekey3[16];
+	unsigned char ekey2[16];
+	unsigned char ekey1[16];
+	unsigned char ecw[16];
+	int kl_levels;
+};
+
+enum meson_kl_dest {
+	MESON_KL_DEST_OUTPUT_DNONCE,
+	MESON_KL_DEST_DESCRAMBLER_EVEN,
+	MESON_KL_DEST_DESCRAMBLER_ODD,
+	MESON_KL_DEST_CRYPTO_THREAD0,
+	MESON_KL_DEST_CRYPTO_THREAD1,
+	MESON_KL_DEST_CRYPTO_THREAD2,
+	MESON_KL_DEST_CRYPTO_THREAD3,
+};
+
+struct meson_kl_run_args {
+	__u32 dest;
+	__u8 kl_num;
+	__u8 kl_levels;
+	__u8 __padding[6];
+	__u8 keys[7][16];
+};
+
+struct meson_kl_cr_args {
+	__u8 kl_num;
+	__u8 __padding[7];
+	/* in: challenge-nonce, out:response-dnonce */
+	__u8 cr[16];
+	/* ekn-1 (e.g. ek2 for 3-key ladder) */
+	__u8 ekn1[16];
+};
+/* keyladder_init
+ * open keyladder device
+ *  ret:
+ *  	Success:	AM_SUCCESS
+ *           Failure:	AM_FAILURE
+ */
+int AM_KL_KeyladderInit();
+/* keyladder_release
+ * release keyladder device
+ */
+void AM_KL_KeyladderRelease();
+/*  set_keyladder:
+ *  Currently support 3 levels keyladder, use this function
+ *  	to set kl regs, the cw will set to descrambler automatically.
+ *  key2:  for 3 levels kl, it means ekn1
+ *  key1:  ekn2
+ *  ecw:    ecw
+ *  ret:
+ *  	Success:	AM_SUCCESS
+ *           Failure:	AM_FAILURE
+ */
+int AM_KL_SetKeyladder(struct meson_kl_config *kl_config);
+/*  set_keyladder:
+ *  Currently support 3 levels keyladder, use this function
+ *  	to set kl regs, the cw will set to descrambler automatically.
+ *  key2:  for 3 levels kl, it means ekn1
+ *  nounce: it is used for challenge
+ *  dnounce: response of cr
+ *  ret:
+ *  	Success:	AM_SUCCESS
+ *           Failure:	AM_FAILURE
+ */
+int AM_KL_SetKeyladderCr(unsigned char key2[16], unsigned nounce[16], unsigned dnounce[16]);
+#endif  //end define MESON_AM_KL
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_mem.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_mem.h
new file mode 100644
index 0000000..be91002
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_mem.h
@@ -0,0 +1,162 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief 内存分配
+ *封装动态内存分配函数,支持memwatch内存检查
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-05-12: create the document
+ ***************************************************************************/
+
+#ifndef _AM_MEM_H
+#define _AM_MEM_H
+
+#include <string.h>
+#include "am_util.h"
+#include <memwatch.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+#ifdef AM_DEBUG
+#define AM_MEM_ERROR_DEBUG(_s)        AM_DEBUG(1, "cannot allocate %d bytes memory", _s)
+#else
+#define AM_MEM_ERROR_DEBUG(_s)
+#endif
+
+/**\brief 内存缓冲区分配*/
+#define AM_MEM_Alloc(_size) \
+	({\
+	void *_ptr = malloc(_size);\
+	if (!_ptr) {\
+		AM_MEM_ERROR_DEBUG(_size);\
+	}\
+	_ptr;\
+	})
+
+/**\brief 重新设定缓冲区大小*/
+#define AM_MEM_Realloc(_old,_size) \
+	({\
+	void *_ptr=realloc(_old,_size);\
+	if (!_ptr) {\
+		AM_MEM_ERROR_DEBUG(_size);\
+	}\
+	_ptr;\
+	})
+
+/**\brief 内存缓冲区释放*/
+#define AM_MEM_Free(_ptr) \
+	AM_MACRO_BEGIN\
+	if (_ptr) free(_ptr);\
+	AM_MACRO_END
+
+/**\brief 分配内存并复制字符串*/
+#define AM_MEM_Strdup(_str) \
+	({\
+	void *_ptr = strdup(_str);\
+	if (!_ptr) {\
+		AM_MEM_ERROR_DEBUG(strlen(_str));\
+	}\
+	_ptr;\
+	})
+
+/**\brief 分配内存并将缓冲区清0*/
+#define AM_MEM_Alloc0(_size) \
+	({\
+	void *_ptr = AM_MEM_Alloc((_size));\
+	if(_ptr) memset(_ptr, 0, (_size));\
+	_ptr;\
+	})
+
+/**\brief 根据类型_type的大小分配内存*/
+#define AM_MEM_ALLOC_TYPE(_type)       AM_MEM_Alloc(sizeof(_type))
+
+/**\brief 分配_n个类型_type大小的内存*/
+#define AM_MEM_ALLOC_TYPEN(_type,_n)   AM_MEM_Alloc(sizeof(_type)*(_n))
+
+/**\brief 根据类型_type的大小分配内存,并清0*/
+#define AM_MEM_ALLOC_TYPE0(_type)      AM_MEM_Alloc0(sizeof(_type))
+
+/**\brief 分配_n个类型_type大小的内存,并清0*/
+#define AM_MEM_ALLOC_TYPEN0(_type,_n)  AM_MEM_Alloc0(sizeof(_type)*(_n))
+
+/**\brief 从内存池分配一个缓冲区并清0*/
+#define AM_MEM_PoolAlloc0(_pool,_size) \
+	({\
+	void *_ptr = AM_MEM_PoolAlloc(_pool,_size);\
+	if(_ptr) memset(_ptr, 0, _size);\
+	_ptr;\
+	})
+
+/**\brief 根据类型_type的大小从内存池分配内存*/
+#define AM_MEM_POOL_ALLOC_TYPE(_pool,_type)       AM_MEM_PoolAlloc(_pool,sizeof(_type))
+
+/**\brief 从内存池分配_n个类型_type大小的内存*/
+#define AM_MEM_POOL_ALLOC_TYPEN(_pool,_type,_n)   AM_MEM_PoolAlloc(_pool,sizeof(_type)*(_n))
+
+/**\brief 根据类型_type的大小从内存池分配内存,并清0*/
+#define AM_MEM_POOL_ALLOC_TYPE0(_pool,_type)      AM_MEM_PoolAlloc0(_pool,sizeof(_type))
+
+/**\brief 从内存池分配_n个类型_type大小的内存,并清0*/
+#define AM_MEM_POOL_ALLOC_TYPEN0(_pool,_type,_n)  AM_MEM_PoolAlloc0(_pool,sizeof(_type)*(_n))
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+/**\brief 内存缓冲池
+ *内存缓冲池在多次分配但统一释放的情况下提高分配效率。
+ *内存缓冲池每次调用malloc分配一个较大的内存,此后所有的小内存块直接在缓冲池内分配。
+ */
+typedef struct
+{
+	int        pool_size;   /**< 每次分配的内存大小*/
+	void      *pools;       /**< 内存块链表*/
+} AM_MEM_Pool_t;
+
+/****************************************************************************
+ * Function prototypes  
+ ***************************************************************************/
+
+/**\brief 初始化一个缓冲池
+ * \param[out] pool 需要初始化的缓冲池结构
+ * \param pool_size 每次调用系统分配函数分配的内存大小
+ */
+extern void AM_MEM_PoolInit(AM_MEM_Pool_t *pool, int pool_size);
+
+/**\brief 从缓冲池分配内存
+ * \param[in,out] pool 缓冲池指针
+ * \param size 要分配的内存大小
+ * \return
+ *   - 返回分配内存的指针
+ *   - 如果分配失败返回NULL
+ */
+extern void* AM_MEM_PoolAlloc(AM_MEM_Pool_t *pool, int size);
+
+/**\brief 将缓冲池内全部以分配的内存标记,但不调用系统free()
+ * \param[in,out] pool 缓冲池指针
+ */
+extern void AM_MEM_PoolClear(AM_MEM_Pool_t *pool);
+
+/**\brief 将缓冲池内全部以分配的内存标记,调用系统free()释放全部资源
+ * \param[in,out] pool 缓冲池指针
+ */
+extern void AM_MEM_PoolFree(AM_MEM_Pool_t *pool);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_misc.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_misc.h
new file mode 100644
index 0000000..36fc603
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_misc.h
@@ -0,0 +1,200 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief Misc tools
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-08-05: create the document
+ ***************************************************************************/
+
+#ifndef _AM_MISC_H
+#define _AM_MISC_H
+
+#include "am_types.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+/****************************************************************************
+ * API function prototypes  
+ ***************************************************************************/
+/**\brief 读sysfs
+ *  name 文件名
+ *  buf  存放字符串的缓冲区
+ *  len  缓冲区大小
+ */
+typedef void (*AM_Read_Sysfs_Cb)(const char *name, char *buf, int len);
+
+/**\brief 写sysfs
+ *  name 文件名
+ *  cmd  向文件打印的字符串
+ */
+typedef void (*AM_Write_Sysfs_Cb)(const char *name, const char *cmd);
+
+
+/**\brief 注册读写sysfs的回调函数
+ * \param[in] fun 回调
+ * \return
+ *	 - AM_SUCCESS 成功
+ *	 - 其他值 错误代码
+ */
+extern void AM_RegisterRWSysfsFun(AM_Read_Sysfs_Cb RCb, AM_Write_Sysfs_Cb WCb);
+
+/**\brief 卸载注册
+ */
+extern void AM_UnRegisterRWSysfsFun();
+
+/**\brief 读prop
+ *  name 文件名
+ *  buf  存放字符串的缓冲区
+ *  len  缓冲区大小
+ */
+typedef void (*AM_Read_Prop_Cb)(const char *name, char *buf, int len);
+
+/**\brief 写prop
+ *  name 文件名
+ *  cmd  向文件打印的字符串
+ */
+typedef void (*AM_Write_Prop_Cb)(const char *name, const char *cmd);
+
+
+/**\brief 注册读写sysfs的回调函数
+ * \param[in] fun 回调
+ * \return
+ *	 - AM_SUCCESS 成功
+ *	 - 其他值 错误代码
+ */
+extern void AM_RegisterRWPropFun(AM_Read_Prop_Cb RCb, AM_Write_Prop_Cb WCb);
+
+/**\brief 卸载注册
+ */
+extern void AM_UnRegisterRWPropFun();
+
+
+/**\brief 向一个Prop set字符串
+ * \param[in] name Prop名
+ * \param[in] cmd 向Prop set的字符串
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码
+ */
+extern AM_ErrorCode_t AM_PropEcho(const char *name, const char *cmd);
+
+/**\brief 读取一个Prop的字符串
+ * \param[in] name Prop名
+ * \param[out] buf 存放字符串的缓冲区
+ * \param len 缓冲区大小
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码
+ */
+extern AM_ErrorCode_t AM_PropRead(const char *name, char *buf, int len);
+
+/**\brief 向一个文件打印字符串
+ * \param[in] name 文件名
+ * \param[in] cmd 向文件打印的字符串
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码
+ */
+extern AM_ErrorCode_t AM_FileEcho(const char *name, const char *cmd);
+
+/**\brief 读取一个文件中的字符串
+ * \param[in] name 文件名
+ * \param[out] buf 存放字符串的缓冲区
+ * \param len 缓冲区大小
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码
+ */
+extern AM_ErrorCode_t AM_FileRead(const char *name, char *buf, int len);
+
+/**\brief 创建本地socket服务
+ * \param[in] name 服务名称
+ * \param[out] fd 返回服务器socket
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码
+ */
+extern AM_ErrorCode_t AM_LocalServer(const char *name, int *fd);
+
+/**\brief 通过本地socket连接到服务
+ * \param[in] name 服务名称
+ * \param[out] fd 返回socket
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码
+ */
+extern AM_ErrorCode_t AM_LocalConnect(const char *name, int *fd);
+
+/**\brief 通过本地socket发送命令
+ * \param fd socket
+ * \param[in] cmd 命令字符串
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码
+ */
+extern AM_ErrorCode_t AM_LocalSendCmd(int fd, const char *cmd);
+
+/**\brief 通过本地socket接收响应字符串
+ * \param fd socket
+ * \param[out] buf 缓冲区
+ * \param len 缓冲区大小
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码
+ */
+extern AM_ErrorCode_t AM_LocalGetResp(int fd, char *buf, int len);
+
+/**\brief 跳过无效UTF8字符
+ * \param[in] src 源字符缓冲区
+ * \param src_len 源字符缓冲区大小
+ * \param[out] dest 目标字符缓冲区
+ * \param[in] dest_len 目标字符缓冲区大小
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码
+ */
+extern AM_ErrorCode_t AM_Check_UTF8(const char *src, int src_len, char *dest, int *dest_len);
+
+/**\brief Set the log level of debug print
+ * \param[in] level
+ */
+extern void AM_DebugSetLogLevel(int level);
+
+/**\brief Get the log level of debug print
+ * \return
+ *   - current log level
+ */
+extern int AM_DebugGetLogLevel();
+
+/**\brief Make sure signal is declared only once in one process
+ * \return
+ *   None
+ */
+void AM_SigHandlerInit();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_net.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_net.h
new file mode 100644
index 0000000..56df61d
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_net.h
@@ -0,0 +1,166 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief 网络管理模块
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-11-19: create the document
+ ***************************************************************************/
+
+#ifndef _AM_NET_H
+#define _AM_NET_H
+
+#include "am_types.h"
+#include <arpa/inet.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+/**\brief 网络管理模块错误代码*/
+enum AM_NET_ErrorCode
+{
+	AM_NET_ERROR_BASE=AM_ERROR_BASE(AM_MOD_NET),
+	AM_NET_ERR_INVALID_DEV_NO,          /**< 设备号无效*/
+	AM_NET_ERR_BUSY,                    /**< 设备已经被打开*/
+	AM_NET_ERR_INVAL_ARG,               /**< 无效的参数*/
+	AM_NET_ERR_NOT_SUPPORTED,           /**< 不支持的操作*/
+	AM_NET_ERR_NO_MEM,                  /**< 空闲内存不足*/
+	AM_NET_ERR_END
+};
+
+
+/**\brief IP地址*/
+typedef struct in_addr AM_NET_IPAddr_t;
+
+/**\brief 网络参数设置选项, 对应AM_NET_Para_t中的参数,为1时表示设置对应参数*/
+enum AM_NET_SetParaMask
+{
+	AM_NET_SP_DHCP	= 0x1,
+	AM_NET_SP_IP	= 0x2,
+	AM_NET_SP_MASK	= 0x4,
+	AM_NET_SP_GW	= 0x8,
+	AM_NET_SP_DNS1	= 0x10,
+	AM_NET_SP_DNS2	= 0x20,
+	AM_NET_SP_DNS3	= 0x40,
+	AM_NET_SP_DNS4	= 0x80,
+	AM_NET_SP_ALL 	= AM_NET_SP_DHCP | AM_NET_SP_IP | AM_NET_SP_MASK | AM_NET_SP_GW | 
+					  AM_NET_SP_DNS1 | AM_NET_SP_DNS2 | AM_NET_SP_DNS3 | AM_NET_SP_DNS4
+};
+
+/**\brief 网卡状态*/
+typedef enum
+{
+	AM_NET_STATUS_UNLINKED,    /**< 网络断开*/
+	AM_NET_STATUS_LINKED       /**< 已经连接到网络*/
+} AM_NET_Status_t;
+
+/**\brief MAC地址*/
+typedef struct
+{
+	uint8_t      mac[6];       /**< MAC地址*/
+} AM_NET_HWAddr_t;
+
+/**\brief 网络参数*/
+typedef struct
+{
+	AM_Bool_t        dynamic;  /**< 是否使用DHCP*/
+	AM_NET_IPAddr_t  ip;       /**< IP地址*/
+	AM_NET_IPAddr_t  mask;     /**< 子网掩码*/
+	AM_NET_IPAddr_t  gw;       /**< 网关地址*/
+	AM_NET_IPAddr_t  dns1;     /**< DNS服务器1*/
+	AM_NET_IPAddr_t  dns2;     /**< DNS服务器2*/
+	AM_NET_IPAddr_t  dns3;     /**< DNS服务器1*/
+	AM_NET_IPAddr_t  dns4;     /**< DNS服务器2*/
+} AM_NET_Para_t;
+
+/****************************************************************************
+ * Function prototypes  
+ ***************************************************************************/
+
+/**\brief 打开网络设备
+ * \param dev_no 网络设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_net.h)
+ */
+extern AM_ErrorCode_t AM_NET_Open(int dev_no);
+
+/**\brief 获取网络连接状态
+ * \param dev_no 网络设备号
+ * \param [out] status 连接状态
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_net.h)
+ */
+extern AM_ErrorCode_t AM_NET_GetStatus(int dev_no, AM_NET_Status_t *status);
+
+/**\brief 获取MAC地址
+ * \param dev_no 网络设备号
+ * \param [out] addr 返回的MAC地址
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_net.h)
+ */
+extern AM_ErrorCode_t AM_NET_GetHWAddr(int dev_no, AM_NET_HWAddr_t *addr);
+
+/**\brief 设置MAC地址
+ * \param dev_no 网络设备号
+ * \param [in] addr MAC地址
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_net.h)
+ */
+extern AM_ErrorCode_t AM_NET_SetHWAddr(int dev_no, const AM_NET_HWAddr_t *addr);
+
+/**\brief 获取网络参数
+ * \param dev_no 网络设备号
+ * \param [out] para 返回的网络参数
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_net.h)
+ */
+extern AM_ErrorCode_t AM_NET_GetPara(int dev_no, AM_NET_Para_t *para);
+
+/**\brief 设置网络参数
+ * \param dev_no 网络设备号
+ * \param mask 设置掩码,见AM_NET_SetParaMask
+ * \param [in] para 网络参数
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_net.h)
+ */
+extern AM_ErrorCode_t AM_NET_SetPara(int dev_no, int mask, AM_NET_Para_t *para);
+
+
+/**\brief 关闭网络设备
+ * \param dev_no 网络设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_net.h)
+ */
+extern AM_ErrorCode_t AM_NET_Close(int dev_no);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_osd.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_osd.h
new file mode 100644
index 0000000..e60e06a
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_osd.h
@@ -0,0 +1,482 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief OSD驱动
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-07-18: create the document
+ ***************************************************************************/
+
+#ifndef _AM_OSD_H
+#define _AM_OSD_H
+
+#include "am_types.h"
+#include "am_evt.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+/****************************************************************************
+ * Error code definitions
+ ****************************************************************************/
+
+/**\brief OSD模块错误代码*/
+enum AM_OSD_ErrorCode
+{
+	AM_OSD_ERROR_BASE=AM_ERROR_BASE(AM_MOD_OSD),
+	AM_OSD_ERR_NO_MEM,                   /**< 内存不足*/
+	AM_OSD_ERR_BUSY,                     /**< 设备已经打开*/
+	AM_OSD_ERR_INVALID_DEV_NO,           /**< 无效的设备号*/
+	AM_OSD_ERR_NOT_OPENNED,              /**< 设备还没有打开*/
+	AM_OSD_ERR_CANNOT_CREATE_THREAD,     /**< 无法创建线程*/
+	AM_OSD_ERR_NOT_SUPPORTED,            /**< 设备不支持此功能*/
+	AM_OSD_ERR_CANNOT_OPEN,              /**< 无法打开设备*/
+	AM_OSD_ERR_ILLEGAL_PIXEL,            /**< 无效的像素值*/
+	AM_OSD_ERR_SYS,                      /**< 系统错误*/
+	AM_OSD_ERR_END
+};
+
+/****************************************************************************
+ * Event type definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+/**\brief 图形模式类型*/
+typedef enum
+{
+	AM_OSD_FMT_PALETTE_256,      /**< 256色调色板模式*/
+	AM_OSD_FMT_COLOR_ARGB_4444,  /**< 真彩a:4 r:4 g:4 b:4*/
+	AM_OSD_FMT_COLOR_BGRA_4444,  /**< 真彩b:4 g:4 r:4 a:4*/
+	AM_OSD_FMT_COLOR_ARGB_1555,  /**< 真彩a:1 r:5 g:5 b:5*/
+	AM_OSD_FMT_COLOR_BGRA_5551,  /**< 真彩b:5 g:5 r:5 a:1*/
+	AM_OSD_FMT_COLOR_RGB_565,    /**< 真彩r:5 g:6 b:5*/
+	AM_OSD_FMT_COLOR_BGR_565,    /**< 真彩b:5 g:6 r:5*/
+	AM_OSD_FMT_COLOR_RGB_888,    /**< 真彩r:8 g:8 b:8*/
+	AM_OSD_FMT_COLOR_BGR_888,    /**< 真彩b:8 g:8 r:8*/
+	AM_OSD_FMT_COLOR_ARGB_8888,  /**< 真彩a:8 r:8 g:8 b:8*/
+	AM_OSD_FMT_COLOR_BGRA_8888,  /**< 真彩a:8 r:8 g:8 b:8*/
+	AM_OSD_FMT_COLOR_RGBA_8888,  /**< 真彩a:8 r:8 g:8 b:8*/
+	AM_OSD_FMT_COLOR_ABGR_8888,  /**< 真彩a:8 r:8 g:8 b:8*/
+	AM_OSD_FMT_YUV_420,          /**< YUV4:2:0模式*/
+	AM_OSD_FMT_YUV_422,          /**< YUV4:2:2模式*/
+	AM_OSD_FMT_YUV_444,          /**< YUV4:4:4模式*/
+	AM_OSD_FMT_COUNT
+} AM_OSD_PixelFormatType_t;
+
+/**\brief 真彩a:4 r:4 g:4 b:4*/
+#define AM_OSD_FMT_COLOR_4444    AM_OSD_FMT_COLOR_BGRA_4444
+/**\brief 真彩a:1 r:5 g:5 b:5*/
+#define AM_OSD_FMT_COLOR_1555    AM_OSD_FMT_COLOR_BGRA_5551
+/**\brief 真彩r:5 g:6 b:5*/
+#define AM_OSD_FMT_COLOR_565     AM_OSD_FMT_COLOR_BGR_565
+/**\brief 真彩r:8 g:8 b:8*/
+#define AM_OSD_FMT_COLOR_888     AM_OSD_FMT_COLOR_RGB_888
+/**\brief 真彩a:8 r:8 g:8 b:8*/
+#define AM_OSD_FMT_COLOR_8888    AM_OSD_FMT_COLOR_BGRA_8888
+
+/**\brief 图形模式是否为调色板方式*/
+#define AM_OSD_PIXEL_FORMAT_TYPE_IS_PALETTE(t)    ((t)<=AM_OSD_FMT_PALETTE_256)
+
+/**\brief 图形模式是否为YUV模式*/
+#define AM_OSD_PIXEL_FORMAT_TYPE_IS_YUV(t)        ((t)>=AM_OSD_FMT_YUV_420)
+
+/**\brief 颜色*/
+typedef struct
+{
+	uint8_t r; /**< 红*/
+	uint8_t g; /**< 绿*/
+	uint8_t b; /**< 蓝*/
+	uint8_t a; /**< alpah*/
+} AM_OSD_Color_t;
+
+/**\brief 调色板*/
+typedef struct
+{
+	int             color_count; /**< 调色板中的颜色数*/
+	AM_OSD_Color_t *colors;      /**< 颜色缓冲区*/
+} AM_OSD_Palette_t;
+ 
+/**\brief 图形模式*/
+typedef struct
+{
+	AM_OSD_PixelFormatType_t type;            /**< 显示模式类型*/
+	int                      bits_per_pixel;  /**< 每个像素占用的位数*/
+	int                      bytes_per_pixel; /**< 每个像素占用的字节数*/
+	int                      planes;          /**< 像素缓冲区数目*/
+	uint32_t                 a_mask;          /**< 像素中alpha值掩码*/
+	uint32_t                 r_mask;          /**< 像素中红色值掩码*/
+	uint32_t                 g_mask;          /**< 像素中绿色值掩码*/
+	uint32_t                 b_mask;          /**< 像素中蓝色值掩码*/
+	uint8_t                  a_offset;        /**< 像素中alpha值的偏移*/
+	uint8_t                  r_offset;        /**< 像素中红色值的偏移*/
+	uint8_t                  g_offset;        /**< 像素中绿色值的偏移*/
+	uint8_t                  b_offset;        /**< 像素中蓝色值的偏移*/
+	uint8_t                  a_shift;         /**< 像素中alpha值移位(255最大)*/
+	uint8_t                  r_shift;         /**< 像素中红色值的移位(255最大)*/
+	uint8_t                  g_shift;         /**< 像素中绿色值的移位(255最大)*/
+	uint8_t                  b_shift;         /**< 像素中蓝色值的移位(255最大)*/
+	AM_OSD_Palette_t         palette;         /**< 调色板*/
+} AM_OSD_PixelFormat_t;
+
+/**\brief OSD设备开启参数*/
+typedef struct
+{
+	AM_OSD_PixelFormatType_t format;          /**< 显示模式*/
+	int                      width;           /**< 宽度像素数*/
+	int                      height;          /**< 高度像素数*/
+	int                      output_width;    /**< 视频输出宽度*/
+	int                      output_height;   /**< 视频输出高度*/
+	AM_Bool_t                enable_double_buffer; /**< 是否支持双缓冲*/
+	int                      vout_dev_no;     /**< OSD对应的视频输出设备ID*/
+} AM_OSD_OpenPara_t;
+
+/**\brief 矩形*/
+typedef struct
+{
+	int x;  /**< X坐标*/
+	int y;  /**< Y坐标*/
+	int w;  /**< 宽度*/
+	int h;  /**< 高度*/
+} AM_OSD_Rect_t;
+
+/**\brief 绘图表面*/
+typedef struct
+{
+	uint32_t   flags;       /**< 绘图表面功能标志*/
+	AM_OSD_PixelFormat_t    *format; /**< 图形模式*/
+	AM_OSD_Rect_t            clip;   /**< 剪切区域*/
+	int        width;       /**< 宽度*/
+	int        height;      /**< 高度*/
+	int        pitch;       /**< 每行所占字节数*/
+	uint32_t   color_key;   /**< Color key值*/
+	uint8_t    alpha;       /**< 全局Alpha值*/
+	uint8_t   *buffer;      /**< 像素缓冲区*/
+	void      *drv_data;    /**< 驱动私有数据*/
+	void      *hw_data;     /**< 硬件绘图相关数据*/
+} AM_OSD_Surface_t;
+
+/**\brief Blit操作模式*/
+typedef enum
+{
+	AM_OSD_BLIT_OP_CLEAR,         /**< =0*/
+	AM_OSD_BLIT_OP_COPY,          /**< =s*/
+	AM_OSD_BLIT_OP_NOOP,          /**< =d*/
+	AM_OSD_BLIT_OP_SET,           /**< =1*/
+	AM_OSD_BLIT_OP_COPY_INVERT,   /**< =~s*/
+	AM_OSD_BLIT_OP_INVERT,        /**< =~d*/
+	AM_OSD_BLIT_OP_AND_REVERSE,   /**< =s&~d*/
+	AM_OSD_BLIT_OP_OR_REVERSE,    /**< =s|~d*/
+	AM_OSD_BLIT_OP_AND,           /**< =s&d*/
+	AM_OSD_BLIT_OP_OR,            /**< =s|d*/
+	AM_OSD_BLIT_OP_NAND,          /**< =~(s&d)*/
+	AM_OSD_BLIT_OP_NOR,           /**< =~(s|d)*/
+	AM_OSD_BLIT_OP_XOR,           /**< =s^d*/
+	AM_OSD_BLIT_OP_EQUIV,         /**< =~(s^d)*/
+	AM_OSD_BLIT_OP_AND_INVERTED,  /**< =~s&d*/
+	AM_OSD_BLIT_OP_OR_INVERTED    /**< =~s|d*/
+} AM_OSD_BlitMode_t;
+
+/**\brief Blit 操作参数*/
+typedef struct
+{
+	AM_Bool_t  enable_alpha;       /**< 是否进行alpha blending*/
+	AM_Bool_t  enable_global_alpha;/**< 是否使用全局alpha值*/
+	AM_Bool_t  enable_key;   /**< 是否支持color key*/
+	AM_Bool_t  enable_op;    /**< 是否设置Blit模式*/
+	uint32_t   key;          /**< Color Key值*/
+	uint8_t    alpha;        /**< 全局Alpha值*/
+	AM_OSD_BlitMode_t op;    /**< Blit模式*/
+} AM_OSD_BlitPara_t;
+
+/**\brief 绘图表面支持硬件加速*/
+#define AM_OSD_SURFACE_FL_HW     (1)
+
+/**\brief 绘图表面支持openGL*/
+#define AM_OSD_SURFACE_FL_OPENGL (2)
+
+/**\brief 绘图表面为OSD*/
+#define AM_OSD_SURFACE_FL_OSD    (4)
+
+/**\brief 绘图表面为OSD的双缓冲*/
+#define AM_OSD_SURFACE_FL_DBUF   (8)
+
+/**\brief 外部分配的缓冲区,AM_OSD_DestroySurface时不释放*/
+#define AM_OSD_SURFACE_FL_EXTERNAL  (16)
+
+/**\brief Surface中的Format结构是私有的。当Surface释放时,释放Format结构内存*/
+#define AM_OSD_SURFACE_FL_PRIV_FMT  (32)
+
+/**\brief Surface的图像中color key为透明色的键值*/
+#define AM_OSD_SURFACE_FL_COLOR_KEY (64)
+
+/**\brief Surface的图像中包含Alpha值*/
+#define AM_OSD_SURFACE_FL_ALPHA     (128)
+
+/**\brief Surface的图像中包含全局Alpha值*/
+#define AM_OSD_SURFACE_FL_GLOBAL_ALPHA    (256)
+
+/**\brief 图像以32x32方式存储*/
+#define AM_OSD_SURFACE_FL_CANVAS_32X32    (512)
+
+/**\brief 图像以64x64方式存储*/
+#define AM_OSD_SURFACE_FL_CANVAS_64X64    (1024)
+
+/****************************************************************************
+ * Function prototypes  
+ ***************************************************************************/
+
+/**\brief 初始化OSD模块(不打开OSD设备,只初始化相关资源)
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_osd.h)
+ */
+extern AM_ErrorCode_t AM_OSD_Init(void);
+
+/**\brief 释放OSD模块
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_osd.h)
+ */
+extern AM_ErrorCode_t AM_OSD_Quit(void);
+
+/**\brief 打开一个OSD设备
+ * \param dev_no OSD设备号
+ * \param[in] para 设备开启参数
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_osd.h)
+ */
+extern AM_ErrorCode_t AM_OSD_Open(int dev_no, AM_OSD_OpenPara_t *para);
+
+/**\brief 关闭一个OSD设备
+ * \param dev_no OSD设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_osd.h)
+ */
+extern AM_ErrorCode_t AM_OSD_Close(int dev_no);
+
+/**\brief 取得OSD设备的绘图表面
+ * \param dev_no OSD设备号
+ * \param[out] s 返回OSD绘图表面
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_osd.h)
+ */
+extern AM_ErrorCode_t AM_OSD_GetSurface(int dev_no, AM_OSD_Surface_t **s);
+
+/**\brief 取得OSD设备的显示绘图表面,如果OSD没有使用双缓冲,则返回的Surface和AM_OSD_GetSurface的返回值相同
+ * \param dev_no OSD设备号
+ * \param[out] s 返回OSD绘图表面
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_osd.h)
+ */
+extern AM_ErrorCode_t AM_OSD_GetDisplaySurface(int dev_no, AM_OSD_Surface_t **s);
+
+/**\brief 显示OSD层
+ * \param dev_no OSD设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_osd.h)
+ */
+extern AM_ErrorCode_t AM_OSD_Enable(int dev_no);
+
+/**\brief 不显示OSD层
+ * \param dev_no OSD设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_osd.h)
+ */
+extern AM_ErrorCode_t AM_OSD_Disable(int dev_no);
+
+/**\brief 双缓冲模式下,将缓冲区中的数据显示到OSD中
+ * \param dev_no OSD设备号
+ * \param[in] rect 要刷新的区域,NULL表示整个OSD
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_osd.h)
+ */
+extern AM_ErrorCode_t AM_OSD_Update(int dev_no, AM_OSD_Rect_t *rect);
+
+/**\brief 设定OSD的全局Alpha值
+ * \param dev_no OSD设备号
+ * \param alpha Alpha值(0~255)
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_osd.h)
+ */
+extern AM_ErrorCode_t AM_OSD_SetGlobalAlpha(int dev_no, uint8_t alpha);
+
+/**\brief 取得图形模式相关参数
+ * \param type 图形模式类型
+ * \param[out] fmt 返回图形模式相关参数的指针
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_osd.h)
+ */
+extern AM_ErrorCode_t AM_OSD_GetFormatPara(AM_OSD_PixelFormatType_t type, AM_OSD_PixelFormat_t **fmt);
+
+/**\brief 将颜色映射为像素值
+ * \param[in] fmt 图形模式 
+ * \param[in] col 颜色值
+ * \param[out] pix 返回映射的像素值 
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_osd.h)
+ */
+extern AM_ErrorCode_t AM_OSD_MapColor(AM_OSD_PixelFormat_t *fmt, AM_OSD_Color_t *col, uint32_t *pix);
+
+/**\brief 将像素映射为颜色
+ * \param[in] fmt 图形模式 
+ * \param[in] pix 像素值
+ * \param[out] col 返回映射的颜色值 
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_osd.h)
+ */
+extern AM_ErrorCode_t AM_OSD_MapPixel(AM_OSD_PixelFormat_t *fmt, uint32_t pix, AM_OSD_Color_t *col);
+
+/**\brief 创建一个绘图表面
+ * \param type 图形模式 
+ * \param w 绘图表面宽度
+ * \param h 绘图表面高度
+ * \param flags 绘图表面的属性标志
+ * \param[out] s 返回创建的绘图表面
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_osd.h)
+ */
+extern AM_ErrorCode_t AM_OSD_CreateSurface(AM_OSD_PixelFormatType_t type, int w, int h, uint32_t flags, AM_OSD_Surface_t **s);
+
+/**\brief 从一个缓冲区创建一个绘图表面
+ * \param type 图形模式 
+ * \param w 绘图表面宽度
+ * \param h 绘图表面高度
+ * \param pitch 两行之间的字节数
+ * \param buffer 缓冲区指针
+ * \param flags 绘图表面的属性标志
+ * \param[out] s 返回创建的绘图表面
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_osd.h)
+ */
+extern AM_ErrorCode_t AM_OSD_CreateSurfaceFromBuffer(AM_OSD_PixelFormatType_t type, int w, int h, int pitch,
+		uint8_t *buffer, uint32_t flags, AM_OSD_Surface_t **s);
+
+/**\brief 销毁一个绘图表面
+ * \param[in,out] s 要销毁的绘图表面 
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_osd.h)
+ */
+extern AM_ErrorCode_t AM_OSD_DestroySurface(AM_OSD_Surface_t *s);
+
+/**\brief 设定绘图剪切区,绘图只对剪切区内部的像素生效
+ * \param[in] surf 绘图表面
+ * \param[in] clip 剪切区矩形,NULL表示取消剪切区
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_osd.h)
+ */
+extern AM_ErrorCode_t AM_OSD_SetClip(AM_OSD_Surface_t *surf, AM_OSD_Rect_t *clip);
+
+/**\brief 设定调色板,此操作只对调色板模式的表面有效
+ * \param[in] surf 绘图表面
+ * \param[in] pal 设定颜色数组
+ * \param start 要设定的调色板起始项
+ * \param count 要设定的颜色数目
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_osd.h)
+ */
+extern AM_ErrorCode_t AM_OSD_SetPalette(AM_OSD_Surface_t *surf, AM_OSD_Color_t *pal, int start, int count);
+
+/**\brief 在绘图表面上画点
+ * \param[in] surf 绘图表面
+ * \param x 点的X坐标
+ * \param y 点的Y坐标
+ * \param pix 点的像素值
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_osd.h)
+ */
+extern AM_ErrorCode_t AM_OSD_DrawPixel(AM_OSD_Surface_t *surf, int x, int y, uint32_t pix);
+
+/**\brief 在绘图表面上画水平线
+ * \param[in] surf 绘图表面
+ * \param x 左顶点的X坐标
+ * \param y 左顶点的Y坐标
+ * \param w 水平线宽度
+ * \param pix 直线的像素值
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_osd.h)
+ */
+extern AM_ErrorCode_t AM_OSD_DrawHLine(AM_OSD_Surface_t *surf, int x, int y, int w, uint32_t pix);
+
+/**\brief 在绘图表面上画垂直线
+ * \param[in] surf 绘图表面
+ * \param x 上顶点的X坐标
+ * \param y 上顶点的Y坐标
+ * \param h 垂直线高度
+ * \param pix 直线的像素值
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_osd.h)
+ */
+extern AM_ErrorCode_t AM_OSD_DrawVLine(AM_OSD_Surface_t *surf, int x, int y, int h, uint32_t pix);
+
+/**\brief 在绘图表面上画矩形
+ * \param[in] surf 绘图表面
+ * \param[in] rect 矩形区 
+ * \param pix 矩形边的像素值
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_osd.h)
+ */
+extern AM_ErrorCode_t AM_OSD_DrawRect(AM_OSD_Surface_t *surf, AM_OSD_Rect_t *rect, uint32_t pix);
+
+/**\brief 在绘图表面上画填充矩形
+ * \param[in] surf 绘图表面
+ * \param[in] rect 矩形区 
+ * \param pix 填充像素值
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_osd.h)
+ */
+extern AM_ErrorCode_t AM_OSD_DrawFilledRect(AM_OSD_Surface_t *surf, AM_OSD_Rect_t *rect, uint32_t pix);
+
+/**\brief Blit操作
+ * \param[in] src 源绘图表面
+ * \param[in] sr 源矩形区 
+ * \param[in] dst 目标绘图表面
+ * \param[in] dr 目标矩形区
+ * \param[in] para Blit参数,如果para==NULL,将根据src的flags标志设定参数
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_osd.h)
+ */
+extern AM_ErrorCode_t AM_OSD_Blit(AM_OSD_Surface_t *src, AM_OSD_Rect_t *sr, AM_OSD_Surface_t *dst, AM_OSD_Rect_t *dr, const AM_OSD_BlitPara_t *para);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_pes.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_pes.h
new file mode 100644
index 0000000..9389de9
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_pes.h
@@ -0,0 +1,97 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief PES packet parser module
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2012-08-01: create the document
+ ***************************************************************************/
+
+
+#ifndef _AM_PES_H
+#define _AM_PES_H
+
+#include "am_types.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+
+/**\brief PES parser module's error code*/
+enum AM_PES_ErrorCode
+{
+	AM_PES_ERROR_BASE=AM_ERROR_BASE(AM_MOD_PES),
+	AM_PES_ERR_INVALID_PARAM,   /**< Invalid parameter*/
+	AM_PES_ERR_INVALID_HANDLE,  /**< Invalid handle*/
+	AM_PES_ERR_NO_MEM,          /**< Not enough memory*/
+	AM_PES_ERR_END
+};
+
+/**\brief PES parser handle*/
+typedef void* AM_PES_Handle_t;
+
+/**\brief PES packet callback function
+ * \a handle The PES parser's handle.
+ * \a buf The PES packet.
+ * \a size The packet size in bytes.
+ */
+typedef void (*AM_PES_PacketCb_t)(AM_PES_Handle_t handle, uint8_t *buf, int size);
+
+/**\brief PES parser's parameters*/
+typedef struct
+{
+	AM_PES_PacketCb_t packet;       /**< PES packet callback function*/
+	AM_Bool_t         payload_only; /**< Only read PES payload*/
+	void             *user_data;    /**< User dafined data*/
+	int				  afmt;			/**< audio fmt*/
+}AM_PES_Para_t;
+
+/**\brief Create a new PES parser
+ * \param[out] handle Return the new PES parser's handle
+ * \param[in] para PES parser's parameters
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+AM_ErrorCode_t AM_PES_Create(AM_PES_Handle_t *handle, AM_PES_Para_t *para);
+
+/**\brief Release an unused PES parser
+ * \param handle The PES parser's handle
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+AM_ErrorCode_t AM_PES_Destroy(AM_PES_Handle_t handle);
+
+/**\brief Parse the PES data
+ * \param handle PES parser's handle
+ * \param[in] buf PES data's buffer
+ * \param size Data in the buffer
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+AM_ErrorCode_t AM_PES_Decode(AM_PES_Handle_t handle, uint8_t *buf, int size);
+
+/**\brief Get the user defined data of the PES parser
+ * \param handle PES parser's handle
+ * \return The user defined data
+ */
+void*          AM_PES_GetUserData(AM_PES_Handle_t handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+#endif
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_queue.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_queue.h
new file mode 100644
index 0000000..601316a
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_queue.h
@@ -0,0 +1,69 @@
+#ifndef QUEUE_H
+#define QUEUE_H
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+
+enum enqueue_result {
+  ENQUEUE_RESULT_SUCCESS,
+  ENQUEUE_RESULT_FULL,
+};
+
+enum dequeue_result {
+  DEQUEUE_RESULT_SUCCESS,
+  DEQUEUE_RESULT_EMPTY,
+};
+
+#define ARRAY_LENGTH(A) (sizeof(A)/sizeof((A)[0]))
+
+#define QUEUE_DECLARATION(NAME, ITEM_TYPE, NUM_ITEMS)                                   \
+struct NAME {                                                                           \
+  uint16_t read_idx;                                                                    \
+  uint16_t write_idx;                                                                   \
+  ITEM_TYPE items[NUM_ITEMS];                                                           \
+};                                                                                      \
+void NAME ## _init(struct NAME * p_queue);                                              \
+enum enqueue_result NAME ##_enqueue(struct NAME * p_queue, ITEM_TYPE * p_new_item);     \
+enum dequeue_result NAME ##_dequeue(struct NAME * p_queue, ITEM_TYPE * p_item_out);     \
+bool NAME ##_is_empty(struct NAME * p_queue);
+
+#define QUEUE_DEFINITION(NAME, ITEM_TYPE)                                               \
+void NAME ## _init(struct NAME * p_queue)                                               \
+{                                                                                       \
+  p_queue->read_idx = 0;                                                                \
+  p_queue->write_idx = 0;                                                               \
+}                                                                                       \
+                                                                                        \
+enum enqueue_result NAME ##_enqueue(struct NAME  * p_queue, ITEM_TYPE * p_new_item) {   \
+  uint16_t elements_in = p_queue->write_idx - p_queue->read_idx;                        \
+                                                                                        \
+  size_t const capacity = ARRAY_LENGTH(p_queue->items);                                 \
+  if (elements_in == capacity) {                                                        \
+    return ENQUEUE_RESULT_FULL;                                                         \
+  }                                                                                     \
+                                                                                        \
+  uint16_t i = (p_queue->write_idx)++ & (capacity - 1);                                 \
+  p_queue->items[i] = *p_new_item;                                                      \
+  return ENQUEUE_RESULT_SUCCESS;                                                        \
+}                                                                                       \
+                                                                                        \
+enum dequeue_result NAME ##_dequeue(struct NAME * p_queue, ITEM_TYPE * p_item_out) {    \
+  uint16_t elements_in = p_queue->write_idx - p_queue->read_idx;                        \
+  size_t const capacity = ARRAY_LENGTH(p_queue->items);                                 \
+                                                                                        \
+  if(elements_in == 0) {                                                                \
+    return DEQUEUE_RESULT_EMPTY;                                                        \
+  }                                                                                     \
+                                                                                        \
+  uint16_t i = (p_queue->read_idx)++ & (capacity - 1);                                  \
+  *p_item_out = p_queue->items[i];                                                      \
+                                                                                        \
+  return DEQUEUE_RESULT_SUCCESS;                                                        \
+}                                                                                       \
+                                                                                        \
+bool NAME ##_is_empty(struct NAME * p_queue) {                                          \
+  return ((p_queue->write_idx - p_queue->read_idx) == 0);                               \
+}
+
+
+#endif
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_smc.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_smc.h
new file mode 100644
index 0000000..1a545b2
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_smc.h
@@ -0,0 +1,289 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief smart card communication module
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-06-29: create the document
+ ***************************************************************************/
+
+#ifndef _AM_SMC_H
+#define _AM_SMC_H
+
+#include "am_types.h"
+#include "am_evt.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+#define AM_SMC_MAX_ATR_LEN    (33)
+
+/****************************************************************************
+ * Error code definitions
+ ****************************************************************************/
+/**\brief Error code of the Smart card module*/
+enum AM_SMC_ErrorCode
+{
+	AM_SMC_ERROR_BASE=AM_ERROR_BASE(AM_MOD_SMC),
+	AM_SMC_ERR_INVALID_DEV_NO,           /**< Invalid device number*/
+	AM_SMC_ERR_BUSY,                     /**< The device has already been openned*/
+	AM_SMC_ERR_NOT_OPENNED,              /**< The device is not yet open*/
+	AM_SMC_ERR_CANNOT_OPEN_DEV,          /**< Failed to open device*/
+	AM_SMC_ERR_CANNOT_CREATE_THREAD,     /**< Creating device failure*/
+	AM_SMC_ERR_TIMEOUT,                  /**< Timeout*/
+	AM_SMC_ERR_NOT_SUPPORTED,            /**< The device does not support this function*/
+	AM_SMC_ERR_IO,                       /**< Device input or output errors*/
+	AM_SMC_ERR_BUF_TOO_SMALL,            /**< Buffer too small*/
+	AM_SMC_ERR_NO_CARD,                  /**< Smart card not inserted*/
+	AM_SMC_ERR_END
+};
+
+/****************************************************************************
+ * Event type definitions
+ ****************************************************************************/
+
+/**\brief Event type of Smart card module*/
+enum AM_SMC_EventType
+{
+	AM_SMC_EVT_BASE=AM_EVT_TYPE_BASE(AM_MOD_SMC),
+	AM_SMC_EVT_CARD_IN,                  /**< Smart card insert*/
+	AM_SMC_EVT_CARD_OUT,                 /**< Smart card pull out*/
+	AM_SMC_EVT_END
+};
+
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+/**\brief Smart card device enable parameter*/
+typedef struct
+{
+	int  enable_thread;                  /**< check the thread of check smart card status is enable*/
+} AM_SMC_OpenPara_t;
+
+/**\brief Insert Status type of smart card */
+typedef enum
+{
+	AM_SMC_CARD_OUT, /**< Smart card pull out*/
+	AM_SMC_CARD_IN   /**< Smart card insert*/
+} AM_SMC_CardStatus_t;
+
+/**\brief Smart card status callback*/
+typedef void (*AM_SMC_StatusCb_t) (int dev_no, AM_SMC_CardStatus_t status, void *data);
+
+/** brief Smart card device parameter*/
+typedef struct
+{
+	int     f;                 /**<Clock frequency conversion coefficient*/
+	int     d;                 /**<baud rate coefficient*/
+	int     n;                 /**<the N parameter is used to provide extra guard time between characters.*/
+	int     bwi;               /**<The BWI is used to define the Block Wait Time*/
+	int     cwi;               /**<The CWT is defined as the wait time between characters*/
+	int     bgt;               /**<Block Guard Time*/
+	int     freq;              /**<clock frequency*/
+	int     recv_invert;       /**<1:invert the data bits (excluding the parity) during receiving*/
+	int     recv_lsb_msb;      /**<1:Swap MSBits / Lsbits during receiving*/
+	int     recv_no_parity;    /**<Ignore parity,This is useful during debug*/
+	int     recv_parity;			 /**< 1:Invert Parity during receiving*/
+	int     xmit_invert;       /**<1:invert the data bits (excluding the parity)*/
+	int     xmit_lsb_msb;      /**<1:Swap MSBits / LSbits*/
+	int     xmit_retries;      /**<Number of attempts to make sending a character.*/
+	int     xmit_repeat_dis;   /**<Set this bit to 1 to disable character repeats when an error is detected.*/
+	int     xmit_parity;			 /**<1:Invert Parity*/
+}AM_SMC_Param_t;
+
+/****************************************************************************
+ * Function prototypes  
+ ***************************************************************************/
+
+/**\brief Open smart card device
+ * \param dev_no Smart card device number
+ * \param[in] para Smart card device open parameter
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_SMC_Open(int dev_no, const AM_SMC_OpenPara_t *para);
+
+/**\brief Close smart cart device
+ * \param dev_no Smart card device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_SMC_Close(int dev_no);
+
+/**\brief Get smart card insert status
+ * \param dev_no Smart card device number
+ * \param[out] status inert status of smart card device
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_SMC_GetCardStatus(int dev_no, AM_SMC_CardStatus_t *status);
+
+/**\brief Reset smart card
+ * \param dev_no Smart card device number
+ * \param[out] atr Smart card attribute data
+ * \param[in,out] len input attribute len,out the actual attribute length
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_SMC_Reset(int dev_no, uint8_t *atr, int *len);
+
+/**\brief Read data from Smart card device
+ * Read data directly from the smart card device,
+ * The thread that calls the function will block,
+ * Until the expiration of the expected number of data read
+ * Or timeout.
+ * \param dev_no Smart card device number
+ * \param[out] data Read data buffer
+ * \param[in] len want read Data length
+ * \param timeout Read timeout in milliseconds, <0 said the permanent wait.
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_SMC_Read(int dev_no, uint8_t *data, int len, int timeout);
+
+/**\brief write data to smard card device
+ * Write data to the smart card device,
+ * The thread that calls the function will block,
+ * Until the expiration of the expected number of data write
+ * Or timeout.
+ * \param dev_no Smart card device number
+ * \param[in] data Write data buffer
+ * \param[in] len want write Data length
+ * \param timeout Write timeout in milliseconds, <0 said the permanent wait.
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_SMC_Write(int dev_no, const uint8_t *data, int len, int timeout);
+
+/**\brief Read data from Smart card device
+ * Read data directly from the smart card device,
+ * The thread that calls the function will block,
+ * Until the expiration of the expected number of data read
+ * Or timeout.
+  * \param dev_no Smart card device number
+ * \param[out] data Read data buffer
+ * \param[out] act_len Actual read data length
+ * \param[in] len len want read Data length
+ * \param timeout Read timeout in milliseconds, <0 said the permanent wait.
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_SMC_ReadEx(int dev_no, uint8_t *data, int *act_len, int len, int timeout);
+
+/**\brief write data to smard card device
+ * Write data to the smart card device,
+ * The thread that calls the function will block,
+ * Until the expiration of the expected number of data write
+ * Or timeout.
+ * \param dev_no Smart card device number
+ * \param[in] data Write data buffer
+ * \param[out] act_len Actual Write data length
+ * \param[in] len len want write Data length
+ * \param timeout Write timeout in milliseconds, <0 said the permanent wait.
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_SMC_WriteEx(int dev_no, const uint8_t *data, int *act_len, int len, int timeout);
+
+/**\brief Transmit data by T0 protocol
+ * \param dev_no Smart card device number
+ * \param[in] send send data buffer
+ * \param[in] slen send data length
+ * \param[out] recv Receive data buffer
+ * \param[out] rlen Receive data length
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_SMC_TransferT0(int dev_no, const uint8_t *send, int slen, uint8_t *recv, int *rlen);
+
+/**\brief Transmit data by T1 protocol
+ * \param dev_no Smart card device number
+ * \param[in] send send data buffer
+ * \param[in] slen send data length
+ * \param[out] recv Receive data buffer
+ * \param[out] rlen Receive data length
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_SMC_TransferT1(int dev_no, const uint8_t *send, int slen, uint8_t *recv, int *rlen);
+
+/**\brief Transmit data by T14 protocol
+ * \param dev_no Smart card device number
+ * \param[in] send send data buffer
+ * \param[in] slen send data length
+ * \param[out] recv Receive data buffer
+ * \param[out] rlen Receive data length
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_SMC_TransferT14(int dev_no, const uint8_t *send, int slen, uint8_t *recv, int *rlen);
+
+/**\brief Get callback function of the smart card status
+ * \param dev_no Smart card device number
+ * \param[out] cb The pointer of callback function
+ * \param[out] data user data
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_SMC_GetCallback(int dev_no, AM_SMC_StatusCb_t *cb, void **data);
+
+/**\brief Set callback function of the smart card status
+ * \param dev_no Smart card device number
+ * \param[in] cb The pointer of callback function
+ * \param[in] data user data
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_SMC_SetCallback(int dev_no, AM_SMC_StatusCb_t cb, void *data);
+
+/**\brief Activate smart card device
+ * \param dev_no Smart card device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_SMC_Active(int dev_no);
+
+/**\brief Deactivate smart card device
+ * \param dev_no Smart card device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_SMC_Deactive(int dev_no);
+
+/**\brief Get smart card parameters
+ * \param dev_no Smart card device number
+ * \param[out] para smart card parameters
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_SMC_GetParam(int dev_no, AM_SMC_Param_t *para);
+
+/**\brief Set smart card parameters
+ * \param dev_no Smart card device number
+ * \param[in] para smart card parameters
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_SMC_SetParam(int dev_no, const AM_SMC_Param_t *para);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_tfile.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_tfile.h
new file mode 100644
index 0000000..4a88cb2
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_tfile.h
@@ -0,0 +1,211 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief file tools
+ *
+ * \author
+ * \date
+ ***************************************************************************/
+
+#ifndef _AM_TFILE_H
+#define _AM_TFILE_H
+
+#include "am_types.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+enum AM_TFile_EventType
+{
+	AM_TFILE_EVT_BASE=AM_EVT_TYPE_BASE(AM_MOD_TFILE),
+	AM_TFILE_EVT_RATE_CHANGED,
+	AM_TFILE_EVT_SIZE_CHANGED,
+	AM_TFILE_EVT_START_TIME_CHANGED,
+	AM_TFILE_EVT_END_TIME_CHANGED,
+	AM_TFILE_EVT_DURATION_CHANGED,
+	AM_TFILE_EVT_END
+};
+
+typedef struct AM_TFileData_s AM_TFileData_t;
+typedef struct AM_TFile_Sub_s AM_TFile_Sub_t;
+
+typedef AM_TFileData_t * AM_TFile_t;
+
+struct AM_TFile_Sub_s
+{
+	int rfd;
+	int wfd;
+	int findex;
+	loff_t size;
+	struct AM_TFile_Sub_s *next;
+};
+
+/**\brief Timeshift File*/
+struct AM_TFileData_s
+{
+	int		opened;	/**< open flag*/
+	loff_t	size;	/**< size of the file*/
+	loff_t	avail;	/**< avail data*/
+	loff_t	total;	/**< total written*/
+	loff_t	start;	/**< start offset*/
+	loff_t	read;	/**< read offset*/
+	loff_t	write;	/**< write offset*/
+	pthread_mutex_t lock;	/*r/w lock*/
+	pthread_cond_t		cond;
+	AM_Bool_t	loop;	/*loop mode*/
+	AM_Bool_t	is_timeshift;
+	char	*name;	/*name*/
+	int		duration;
+
+	/*statistics*/
+	loff_t	rtotal;
+	int		rlast; /**< the latest time read*/
+	int		rrate;
+	loff_t	wtotal;
+	int		wlast;/**< the latest time write*/
+	int		rate;
+
+	/* sub files control */
+	int last_sub_index;
+	loff_t sub_file_size;
+	AM_TFile_Sub_t *sub_files;
+	AM_TFile_Sub_t *cur_rsub_file;
+	AM_TFile_Sub_t *cur_wsub_file;
+
+	void *timer;
+
+	int delete_on_close;
+};
+
+#ifdef SUPPORT_CAS
+//#define BUF_NORMAL 0
+//#define BUF_SECURE 1
+typedef struct
+{
+	uint32_t blk_size;
+	uint16_t len;
+	uint8_t *data;
+} CAS_RecInfo_t;
+typedef struct
+{
+	uint64_t pos;
+	uint16_t len;
+	uint8_t *data;
+} CAS_StoreInfo_t;
+typedef struct
+{
+	uint8_t 				*buf_in;
+	uint8_t					*buf_out;
+	uint32_t				buf_len;
+	uint32_t				buf_type;
+	CAS_RecInfo_t 	rec_info;
+	CAS_StoreInfo_t store_info;
+} AM_CAS_CryptPara_t;
+typedef int (*AM_CAS_decrypt) (AM_CAS_CryptPara_t *crypto_inf, uint32_t param);
+typedef int (*AM_CAS_encrypt) (AM_CAS_CryptPara_t *crypto_inf, uint32_t param);
+#endif
+
+/****************************************************************************
+ * API function prototypes
+ ***************************************************************************/
+
+/**\brief Open a TFile
+ * \param[out] tfile tfile handler
+ * \param[in] file_name name of the tfile
+ * \param[in] loop
+ * \param[in] duration
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_TFile_Open(AM_TFile_t *tfile, const char *file_name, AM_Bool_t loop, int duration_max, loff_t size_max);
+
+/**\brief Close a TFile
+ * \param[in] tfile handler of the TFile
+ * \retval AM_SUCCESS on success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_TFile_Close(AM_TFile_t tfile);
+
+/**\brief Read from a TFile
+ * \param[in] tfile tfile handler
+ * \param[in] buf read data will be stored
+ * \param[in] size the length to read
+ * \param[in] timeout in ms
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern ssize_t AM_TFile_Read(AM_TFile_t tfile, uint8_t *buf, size_t size, int timeout);
+
+/**\brief Write to a TFile
+ * \param[out] tfile tfile handler
+ * \param[in] buf data to be written
+ * \param[in] size length to write
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern ssize_t AM_TFile_Write(AM_TFile_t tfile, uint8_t *buf, size_t size, int *sys_err);
+
+/**\brief Seek a TFile
+ * \param[out] tfile tfile handler
+ * \param[in] offset the offset to seek
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern int AM_TFile_Seek(AM_TFile_t tfile, loff_t offset);
+
+extern loff_t AM_TFile_Tell(AM_TFile_t tfile);
+
+extern int AM_TFile_TimeStart(AM_TFile_t tfile);
+
+extern int AM_TFile_TimeSeek(AM_TFile_t tfile, int offset_ms);
+
+extern int AM_TFile_TimeGetReadNow(AM_TFile_t tfile);
+
+extern int AM_TFile_TimeGetStart(AM_TFile_t tfile);
+
+extern int AM_TFile_TimeGetEnd(AM_TFile_t tfile);
+
+extern loff_t AM_TFile_GetAvailable(AM_TFile_t tfile);
+
+#ifdef SUPPORT_CAS
+extern int AM_TFile_CasOpen(char *path);
+
+extern int AM_TFile_Close(AM_TFile_t tfile);
+
+extern int AM_TFile_CasOpen(char *path);
+
+extern int AM_TFile_CasClose();
+
+extern int AM_TFile_CasUpdateStoreInfo(uint32_t len, uint64_t fsize);
+
+extern int AM_TFile_CasSetStoreInfo(CAS_StoreInfo_t info);
+
+extern int AM_TFile_CasGetStoreInfo(uint64_t stream_pos, CAS_StoreInfo_t *info);
+
+extern int AM_TFile_CasGetRecInfo(CAS_RecInfo_t *info);
+
+extern int AM_TFile_CasDump();
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_thread.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_thread.h
new file mode 100644
index 0000000..4479b3a
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_thread.h
@@ -0,0 +1,118 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief pthread 调试工具
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-10-15: create the document
+ ***************************************************************************/
+
+#ifndef _AM_THREAD_H
+#define _AM_THREAD_H
+
+#include <pthread.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+/*打开宏使能线程检测*/
+//#define AM_THREAD_ENABLE
+
+#ifdef AM_THREAD_ENABLE
+
+/**\brief 替换pthread_create()函数,创建一个被AM_THREAD管理的线程*/
+#define pthread_create(t,a,s,p)            AM_pthread_create_name(t,a,s,p,"no name")
+
+/**\brief 创建一个被AM_THREAD管理的线程并注册一个线程名*/
+#define pthread_create_name(t,a,s,p,n)     AM_pthread_create_name(t,a,s,p,n)
+
+/**\brief 结束当前线程*/
+#define pthread_exit(r)                    AM_pthread_exit(r)
+
+/**\brief 当进入一个函数的时候,AM_THREAD记录当前线程状态*/
+#define AM_THREAD_ENTER()                  AM_pthread_enter(__FILE__,__FUNCTION__,__LINE__)
+
+/**\brief 当退出一个函数的时候,AM_THREAD记录当前线程状态*/
+#define AM_THREAD_LEAVE()                  AM_pthread_leave(__FILE__,__FUNCTION__,__LINE__)
+
+/**\brief AM_THREAD_ENTER()和AM_THREAD_LEAVE()对中间包括函数中的各个语句*/
+#define AM_THREAD_FUNC(do)\
+	AM_THREAD_ENTER();\
+	{do;}\
+	AM_THREAD_LEAVE();
+
+#else /*AM_THREAD_ENABLE*/
+
+#define pthread_create_name(t,a,s,p,n)     pthread_create(t,a,s,p)
+#define AM_THREAD_ENTER()
+#define AM_THREAD_LEAVE()
+#define AM_THREAD_FUNC(do)                 do
+#define AM_pthread_dump()
+#endif /*AM_THREAD_ENABLE*/
+
+/****************************************************************************
+ * Function prototypes  
+ ***************************************************************************/
+
+#ifdef AM_THREAD_ENABLE
+
+/**\brief 创建一个被AM_THREAD管理的线程
+ * \param[out] thread 返回线程句柄
+ * \param[in] attr 线程属性,等于NULL时使用缺省属性
+ * \param start_routine 线程入口函数
+ * \param[in] arg 线程入口函数的参数
+ * \param[in] name 线程名
+ * \return 成功返回0,失败返回错误代码
+ */
+int AM_pthread_create_name(pthread_t *thread,
+		const pthread_attr_t *attr,
+		void* (*start_routine)(void*),
+		void *arg,
+		const char *name);
+
+/**\brief 结束当前线程
+ * \param[in] r 返回值
+ */
+void AM_pthread_exit(void *r);
+
+/**\brief 记录当前线程进入一个函数
+ * \param[in] file 文件名
+ * \param[in] func 函数名
+ * \param line 行号
+ * \return 成功返回0,失败返回错误代码
+ */
+int AM_pthread_enter(const char *file, const char *func, int line);
+
+/**\brief 记录当前线程离开一个函数
+ * \param[in] file 文件名
+ * \param[in] func 函数名
+ * \param line 行号
+ * \return 成功返回0,失败返回错误代码
+ */
+int AM_pthread_leave(const char *file, const char *func, int line);
+
+/**\brief 打印当前所有注册线程的状态信息
+ * \return 成功返回0,失败返回错误代码
+ */
+int AM_pthread_dump(void);
+
+#endif /*AM_THREAD_ENABLE*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_time.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_time.h
new file mode 100644
index 0000000..065be58
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_time.h
@@ -0,0 +1,79 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief 时钟、时间相关函数
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-05-21: create the document
+ ***************************************************************************/
+
+#ifndef _AM_TIME_H
+#define _AM_TIME_H
+
+#include "am_types.h"
+#include <time.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+#ifdef ANDROID
+/*extern int  __pthread_cond_timedwait(pthread_cond_t*, 
+                                     pthread_mutex_t*,
+                                     const struct timespec*, 
+                                     clockid_t);
+#define pthread_cond_timedwait(c, m, a) __pthread_cond_timedwait(c, m, a, CLOCK_MONOTONIC);
+*/
+#endif
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+
+/****************************************************************************
+ * Function prototypes  
+ ***************************************************************************/
+
+/**\brief 得到开机到当前系统运行的时间,单位为毫秒
+ * \param[out] clock 返回系统运行时间
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_time.h)
+ */
+extern AM_ErrorCode_t AM_TIME_GetClock(int *clock);
+
+/**\brief 得到开机到当前系统运行的时间,格式为struct timespec
+ * \param[out] ts 返回当前timespec值
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_time.h)
+ */
+extern AM_ErrorCode_t AM_TIME_GetTimeSpec(struct timespec *ts);
+
+/**\brief 得到若干毫秒后的timespec值
+ * 此函数主要用于pthread_cond_timedwait, sem_timedwait等函数计算超时时间。
+ * \param timeout 以毫秒为单位的超时时间
+ * \param[out] ts 返回timespec值
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_time.h)
+ */
+extern AM_ErrorCode_t AM_TIME_GetTimeSpecTimeout(int timeout, struct timespec *ts);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_types.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_types.h
new file mode 100644
index 0000000..f6c44e6
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_types.h
@@ -0,0 +1,118 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief Basic datatypes
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-05-19: create the document
+ ***************************************************************************/
+
+#ifndef _AM_TYPES_H
+#define _AM_TYPES_H
+
+#include <stdint.h>
+#include "pthread.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+/*****************************************************************************
+* Global Definitions
+*****************************************************************************/
+
+/**\brief Boolean value*/
+typedef uint8_t        AM_Bool_t;
+
+
+/**\brief Error code of the function result,
+ * Low 24 bits store the error number.
+ * High 8 bits store the module's index.
+ */
+typedef int            AM_ErrorCode_t;
+
+/**\brief The module's index */
+enum AM_MOD_ID
+{
+	AM_MOD_EVT,    /**< Event module*/
+	AM_MOD_DMX,    /**< Demux module*/
+	AM_MOD_DVR,    /**< DVR module*/
+	AM_MOD_NET,    /**< Network manager module*/
+	AM_MOD_OSD,    /**< OSD module*/
+	AM_MOD_AV,     /**< AV decoder module*/
+	AM_MOD_AOUT,   /**< Audio output device module*/
+	AM_MOD_VOUT,   /**< Video output device module*/
+	AM_MOD_SMC,    /**< Smartcard module*/
+	AM_MOD_INP,    /**< Input device module*/
+	AM_MOD_FEND,   /**< DVB frontend device module*/
+	AM_MOD_DSC,    /**< Descrambler device module*/
+	AM_MOD_CFG,    /**< Configure file manager module*/
+	AM_MOD_SI,     /**< SI decoder module*/
+	AM_MOD_SCAN,   /**< Channel scanner module*/
+	AM_MOD_EPG,    /**< EPG scanner module*/
+	AM_MOD_IMG,    /**< Image loader module*/
+	AM_MOD_FONT,   /**< Font manager module*/
+	AM_MOD_DB,     /**< Database module*/
+	AM_MOD_GUI,    /**< GUI module*/
+	AM_MOD_REC,    /**< Recorder module*/
+	AM_MOD_TV,     /**< TV manager module*/
+	AM_MOD_SUB,    /**< Subtitle module*/
+	AM_MOD_SUB2,   /**< Subtitle(version 2) module*/
+	AM_MOD_TT,     /**< Teletext module*/
+	AM_MOD_TT2,    /**< Teletext(version 2) module*/
+	AM_MOD_FEND_DISEQCCMD,/**< Diseqc command module*/
+	AM_MOD_FENDCTRL, /**< DVB frontend high level control module*/
+	AM_MOD_PES,    /**< PES parser module*/
+	AM_MOD_CAMAN,  /**< CA manager module*/
+	AM_MOD_CI,     /**< DVB-CI module*/
+	AM_MOD_USERDATA, /**< MPEG user data reader device module*/
+	AM_MOD_CC,     /**< Close caption module*/
+	AM_MOD_AD,     /**< Audio description module*/
+	AM_MOD_UPD,    /**< Uploader module*/
+	AM_MOD_TFILE, /*File wrapper module*/
+	AM_MOD_SCTE27,
+	AM_MOD_MAX
+};
+
+/**\brief Get the error code base of each module
+ * \param _mod The module's index
+ */
+#define AM_ERROR_BASE(_mod)    ((_mod)<<24)
+
+#ifndef AM_SUCCESS
+/**\brief Function result: Success*/
+#define AM_SUCCESS     (0)
+#endif
+
+#ifndef AM_FAILURE
+/**\brief Function result: Unknown error*/
+#define AM_FAILURE     (-1)
+#endif
+
+#ifndef AM_TRUE
+/**\brief Boolean value: true*/
+#define AM_TRUE        (1)
+#endif
+
+#ifndef AM_FALSE
+/**\brief Boolean value: false*/
+#define AM_FALSE       (0)
+#endif
+
+#ifndef UNUSED
+#define UNUSED(x) (void)(x)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_userdata.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_userdata.h
new file mode 100644
index 0000000..6aca4e5
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_userdata.h
@@ -0,0 +1,119 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+ /**\file am_userdata.h
+ * \brief MPEG user data device module
+ *
+ * \author Xia Lei Peng <leipeng.xia@amlogic.com>
+ * \date 2013-3-13: create the document
+ ***************************************************************************/
+
+#ifndef _AM_USERDATA_H
+#define _AM_USERDATA_H
+
+#include <unistd.h>
+#include <sys/types.h>
+#include "am_types.h"
+#include "am_evt.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+/**\brief Error code of the user data module*/
+enum AM_USERDATA_ErrorCode
+{
+	AM_USERDATA_ERROR_BASE=AM_ERROR_BASE(AM_MOD_USERDATA),
+	AM_USERDATA_ERR_INVALID_ARG,             /**< Invalid argument*/
+	AM_USERDATA_ERR_INVALID_DEV_NO,          /**< Invalid device number*/
+	AM_USERDATA_ERR_BUSY,                    /**< The device is busy*/
+	AM_USERDATA_ERR_CANNOT_OPEN_DEV,         /**< Cannot open the device*/
+	AM_USERDATA_ERR_NOT_SUPPORTED,           /**< Not supported*/
+	AM_USERDATA_ERR_NO_MEM,                  /**< Not enough memory*/
+	AM_USERDATA_ERR_TIMEOUT,                 /**< Timeout*/
+	AM_USERDATA_ERR_SYS,                     /**< System error*/
+	AM_USERDATA_ERR_END
+};
+
+enum AM_USERDATA_EventType
+{
+	AM_USERDATA_EVT_BASE = AM_EVT_TYPE_BASE(AM_MOD_USERDATA),
+	AM_USERDATA_EVT_AFD,
+};
+
+enum AM_USERDATA_Mode
+{
+	AM_USERDATA_MODE_CC = 0x1,
+	AM_USERDATA_MODE_AFD = 0x2,
+};
+
+/**\brief MPEG user data device open parameters*/
+typedef struct
+{
+	int    foo;
+	int vfmt;
+	int cc_default_stop;
+} AM_USERDATA_OpenPara_t;
+
+typedef struct
+{
+	uint8_t         :6;
+	uint8_t  af_flag:1;
+	uint8_t         :1;
+	uint8_t  af     :4;
+	uint8_t         :4;
+	uint16_t reserved;
+	uint32_t pts;
+} AM_USERDATA_AFD_t;
+
+/****************************************************************************
+ * Function prototypes
+ ***************************************************************************/
+
+/**\brief Open the MPEG user data device
+ * \param dev_no Device number
+ * \param[in] para Device open parameters
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_USERDATA_Open(int dev_no, const AM_USERDATA_OpenPara_t *para);
+
+/**\brief Close the MPEG user data device
+ * \param dev_no Device number
+ * \retval AM_SUCCESS On success
+ * \return Error code
+ */
+extern AM_ErrorCode_t AM_USERDATA_Close(int dev_no);
+
+/**\brief Read MPEG user data from the device
+ * \param dev_no Device number
+ * \param[out] buf Output buffer to store the user data
+ * \param size	Buffer length in bytes
+ * \param timeout_ms Timeout time in milliseconds
+ * \return Read data length in bytes
+ */
+extern int AM_USERDATA_Read(int dev_no, uint8_t *buf, int size, int timeout_ms);
+
+extern AM_ErrorCode_t AM_USERDATA_SetMode(int dev_no, int mode);
+extern AM_ErrorCode_t AM_USERDATA_GetMode(int dev_no, int *mode);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_util.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_util.h
new file mode 100644
index 0000000..9209dd7
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_util.h
@@ -0,0 +1,129 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief 一些常用宏和辅助函数
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-05-12: create the document
+ ***************************************************************************/
+
+#ifndef _AM_UTIL_H
+#define _AM_UTIL_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+/**\brief 函数inline属性*/
+#define AM_INLINE        inline
+
+/**\brief 计算数值_a和_b中的最大值*/
+#define AM_MAX(_a,_b)    ((_a)>(_b)?(_a):(_b))
+
+/**\brief 计算数值_a和_b中的最小值*/
+#define AM_MIN(_a,_b)    ((_a)<(_b)?(_a):(_b))
+
+/**\brief 计算数值_a的绝对值*/
+#define AM_ABS(_a)       ((_a)>0?(_a):-(_a))
+
+/**\brief 计算数值a与b差值的绝对值*/
+#define AM_ABSSUB(a,b) ((a>=b)?(a-b):(b-a))
+
+/**\brief 添加在命令行式宏定义的开头
+ * 一些宏需要完成一系列语句,为了使这些语句形成一个整体不被打断,需要用
+ * AM_MACRO_BEGIN和AM_MACRO_END将这些语句括起来。如:
+ * \code
+ * #define CHECK(_n)    \
+ *    AM_MACRO_BEGIN \
+ *    if ((_n)>0) printf(">0"); \
+ *    else if ((n)<0) printf("<0"); \
+ *    else printf("=0"); \
+ *    AM_MACRO_END
+ * \endcode
+ */
+#define AM_MACRO_BEGIN   do {
+
+/**\brief 添加在命令行式定义的末尾*/
+#define AM_MACRO_END     } while(0)
+
+/**\brief 计算数组常数的元素数*/
+#define AM_ARRAY_SIZE(_a)    (sizeof(_a)/sizeof((_a)[0]))
+
+/**\brief 检查如果返回值是否错误,返回错误代码给调用函数*/
+#define AM_TRY(_func) \
+	AM_MACRO_BEGIN\
+	AM_ErrorCode_t _ret;\
+	if ((_ret=(_func))!=AM_SUCCESS)\
+		return _ret;\
+	AM_MACRO_END
+
+/**\brief 检查返回值是否错误,如果错误,跳转到final标号。注意:函数中必须定义"AM_ErrorCode_t ret"和标号"final"*/
+#define AM_TRY_FINAL(_func)\
+	AM_MACRO_BEGIN\
+	if ((ret=(_func))!=AM_SUCCESS)\
+		goto final;\
+	AM_MACRO_END
+
+/**\brief 开始解析一个被指定字符隔开的字符串*/
+#define AM_TOKEN_PARSE_BEGIN(_str, _delim, _token) \
+	{\
+	char *_strb =  strdup(_str);\
+	if (_strb) {\
+		_token = strtok(_strb, _delim);\
+		while (_token != NULL) {
+	
+#define AM_TOKEN_PARSE_END(_str, _delim, _token) \
+		_token = strtok(NULL, _delim);\
+		}\
+		free(_strb);\
+	}\
+	}
+	
+
+/**\brief 从一个被指定字符隔开的字符串中取指定位置的值,int类型,如未找到指定位置,则使用默认值_default代替*/
+#define AM_TOKEN_VALUE_INT(_str, _delim, _index, _default) \
+	({\
+		char *token;\
+		char *_strbak = strdup(_str);\
+		int counter = 0;\
+		int val = _default;\
+		if (_strbak != NULL) {\
+			AM_TOKEN_PARSE_BEGIN(_strbak, _delim, token)\
+				if (counter == (_index)) {\
+					val = atoi(token);\
+					break;\
+				}\
+				counter++;\
+			AM_TOKEN_PARSE_END(_strbak, _delim, token)\
+			free(_strbak);\
+		}\
+		val;\
+	})
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+
+/****************************************************************************
+ * Function prototypes  
+ ***************************************************************************/
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_vlfend.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_vlfend.h
new file mode 100644
index 0000000..01d42f5
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_vlfend.h
@@ -0,0 +1,194 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief DVB Frontend Module
+ *
+ * Basic data structures definition in "linux/dvb/frontend.h"
+ *
+ * \author nengwen.chen <nengwen.chen@amlogic.com>
+ * \date 2018-04-16: create the document
+ ***************************************************************************/
+
+#ifndef _AM_VFFEND_H_
+#define _AM_VFFEND_H_
+
+#include "am_types.h"
+#include "am_evt.h"
+#include "am_dmx.h"
+/*add for config define for linux dvb *.h*/
+#include <am_config.h>
+#include <linux/dvb/frontend.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define VLFEND_FL_RUN_CB        (1)
+#define VLFEND_FL_LOCK          (2)
+
+/****************************************************************************
+ * Function prototypes
+ ***************************************************************************/
+
+/**\brief open a frontend device
+ * \param dev_no frontend device number
+ * \param[in] para frontend's device open parameters
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_VLFEND_Open(int dev_no, const AM_FEND_OpenPara_t *para);
+
+/**\brief close a frontend device
+ * \param dev_no frontend device number
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_VLFEND_Close(int dev_no);
+extern AM_ErrorCode_t AM_VLFEND_CloseEx(int dev_no, AM_Bool_t reset);
+
+
+/**\brief set frontend deivce mode
+ * \param dev_no frontend device number
+ * \param mode frontend demod mode
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_VLFEND_SetMode(int dev_no, int mode);
+
+/**\brief set frontend parameter
+ * \param dev_no frontend device number
+ * \param[in] para frontend parameter
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_VLFEND_SetPara(int dev_no, const struct dvb_frontend_parameters *para);
+
+/**\brief get frontend parameter
+ * \param dev_no frontend device number
+ * \param[out] para return frontend parameter
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_VLFEND_GetPara(int dev_no, struct dvb_frontend_parameters *para);
+
+/**
+ * \brief set frontend property
+ * \param dev_no frontend device number
+ * \param[in] prop frontend device property
+ * \return
+ *   - AM_SUCCESS onSuccess
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_VLFEND_SetProp(int dev_no, const struct dtv_properties *prop);
+
+/**
+ * \brief get frontend property
+ * \param dev_no frontend device number
+ * \param[out] prop return frontend device property
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_VLFEND_GetProp(int dev_no, struct dtv_properties *prop);
+
+/**\brief get frontend lock status
+ * \param dev_no frontend device number
+ * \param[out] status return frontend lock status
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_VLFEND_GetStatus(int dev_no, fe_status_t *status);
+
+/**\brief get frontend frequency afc
+ * \param dev_no frontend device number
+ * \param[out] status return frontend frequency afc
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_VLFEND_GetAFC(int dev_no, int *afc);
+
+/**\brief get frontend device's callback function
+ * \param dev_no frontend device number
+ * \param[out] cb return callback function
+ * \param[out] user_data callback function's parameters
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_VLFEND_GetCallback(int dev_no, AM_FEND_Callback_t *cb, void **user_data);
+
+/**\brief register the frontend callback function
+ * \param dev_no frontend device function
+ * \param[in] cb callback function
+ * \param[in] user_data callback function's parameter
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_VLFEND_SetCallback(int dev_no, AM_FEND_Callback_t cb, void *user_data);
+
+/**\brief enable or disable frontend callback
+ * \param dev_no frontend device number
+ * \param[in] enable_cb enable or disable
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_VLFEND_SetActionCallback(int dev_no, AM_Bool_t enable_cb);
+
+/**\brief try to lock frontend and wait lock status
+ * \param dev_no device frontend number
+ * \param[in] para frontend parameters
+ * \param[out] status return frontend lock status
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_VLFEND_Lock(int dev_no, const struct dvb_frontend_parameters *para, fe_status_t *status);
+
+/**\brief set frontend thread delay time
+ * \param dev_no frontend device number
+ * \param delay time value in millisecond,  0 means no time interval and frontend thread will stop
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_VLFEND_SetThreadDelay(int dev_no, int delay);
+
+/**\brief get frontend atv tune status
+ * \param dev_no frontend device number
+ * \param atv_status tune status value
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_VLFEND_GetAtvStatus(int dev_no, atv_status_t *atv_status);
+
+/**\brief start frontend detect standard
+ * \param dev_no frontend device number
+ * \return
+ *   - AM_SUCCESS On success
+ *   - or error code
+ */
+extern AM_ErrorCode_t AM_VLFEND_DetectStandard(int dev_no);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_vout.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_vout.h
new file mode 100644
index 0000000..91e885c
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/am_vout.h
@@ -0,0 +1,149 @@
+/***************************************************************************
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+/**\file
+ * \brief 视频输出模块
+ *
+ * \author Gong Ke <ke.gong@amlogic.com>
+ * \date 2010-08-13: create the document
+ ***************************************************************************/
+
+#ifndef _AM_VOUT_H
+#define _AM_VOUT_H
+
+#include "am_types.h"
+#include "am_evt.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Macro definitions
+ ***************************************************************************/
+
+/****************************************************************************
+ * Error code definitions
+ ****************************************************************************/
+
+/**\brief 视频输出模块错误代码*/
+enum AM_VOUT_ErrorCode
+{
+	AM_VOUT_ERROR_BASE=AM_ERROR_BASE(AM_MOD_VOUT),
+	AM_VOUT_ERR_INVALID_DEV_NO,          /**< 设备号无效*/
+	AM_VOUT_ERR_BUSY,                    /**< 设备已经被打开*/
+	AM_VOUT_ERR_ILLEGAL_OP,              /**< 无效的操作*/
+	AM_VOUT_ERR_INVAL_ARG,               /**< 无效的参数*/
+	AM_VOUT_ERR_NOT_ALLOCATED,           /**< 设备没有分配*/
+	AM_VOUT_ERR_CANNOT_CREATE_THREAD,    /**< 无法创建线程*/
+	AM_VOUT_ERR_CANNOT_OPEN_DEV,         /**< 无法打开设备*/
+	AM_VOUT_ERR_CANNOT_OPEN_FILE,        /**< 无法打开文件*/
+	AM_VOUT_ERR_NOT_SUPPORTED,           /**< 不支持的操作*/
+	AM_VOUT_ERR_NO_MEM,                  /**< 空闲内存不足*/
+	AM_VOUT_ERR_TIMEOUT,                 /**< 等待设备数据超时*/
+	AM_VOUT_ERR_SYS,                     /**< 系统操作错误*/
+	AM_VOUT_ERR_END
+};
+
+/**\brief 视频输出模块事件类型*/
+enum AM_VOUT_EventType
+{
+	AM_VOUT_EVT_BASE=AM_EVT_TYPE_BASE(AM_MOD_SMC),
+	AM_VOUT_EVT_FORMAT_CHANGED,          /**< 输出模式改变,参数为AM_VOUT_Format_t*/
+	AM_VOUT_EVT_ENABLE,                  /**< 开始视频信号输出*/
+	AM_VOUT_EVT_DISABLE,                 /**< 停止视频信号输出*/
+	AM_VOUT_EVT_END
+};
+
+/****************************************************************************
+ * Type definitions
+ ***************************************************************************/
+
+/**\brief 视频输出模式*/
+typedef enum
+{
+	AM_VOUT_FORMAT_UNKNOWN,              /**< 未知的模式*/
+	AM_VOUT_FORMAT_576CVBS,              /**< PAL制CVBS输出*/
+	AM_VOUT_FORMAT_480CVBS,              /**< NTSC制CVBS输出*/
+	AM_VOUT_FORMAT_576I,                 /**< 576I*/
+	AM_VOUT_FORMAT_576P,                 /**< 576P*/
+	AM_VOUT_FORMAT_480I,                 /**< 480I*/
+	AM_VOUT_FORMAT_480P,                 /**< 480P*/
+	AM_VOUT_FORMAT_720P,                 /**< 720P*/
+	AM_VOUT_FORMAT_1080I,                /**< 1080I*/
+	AM_VOUT_FORMAT_1080P,                /**< 1080P*/
+} AM_VOUT_Format_t;
+
+/**\brief 视频输出设备开启参数*/
+typedef struct
+{
+	int    foo;
+} AM_VOUT_OpenPara_t;
+
+/****************************************************************************
+ * Function prototypes  
+ ***************************************************************************/
+
+/**\brief 打开视频输出设备
+ * \param dev_no 视频输出设备号
+ * \param[in] para 视频输出设备开启参数
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_vout.h)
+ */
+extern AM_ErrorCode_t AM_VOUT_Open(int dev_no, const AM_VOUT_OpenPara_t *para);
+
+/**\brief 关闭视频输出设备
+ * \param dev_no 视频输出设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_vout.h)
+ */
+extern AM_ErrorCode_t AM_VOUT_Close(int dev_no);
+
+/**\brief 设定输出模式
+ * \param dev_no 视频输出设备号
+ * \param fmt 视频输出模式
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_vout.h)
+ */
+extern AM_ErrorCode_t AM_VOUT_SetFormat(int dev_no, AM_VOUT_Format_t fmt);
+
+/**\brief 取得当前输出模式
+ * \param dev_no 视频输出设备号
+ * \param[out] fmt 返回当前视频输出模式
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_vout.h)
+ */
+extern AM_ErrorCode_t AM_VOUT_GetFormat(int dev_no, AM_VOUT_Format_t *fmt);
+
+/**\brief 使能视频信号输出
+ * \param dev_no 视频输出设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_vout.h)
+ */
+extern AM_ErrorCode_t AM_VOUT_Enable(int dev_no);
+
+/**\brief 停止视频信号输出
+ * \param dev_no 视频输出设备号
+ * \return
+ *   - AM_SUCCESS 成功
+ *   - 其他值 错误代码(见am_vout.h)
+ */
+extern AM_ErrorCode_t AM_VOUT_Disable(int dev_no);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/codec_type.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/codec_type.h
new file mode 100644
index 0000000..25ce908
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/codec_type.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+ *
+ * This source code is subject to the terms and conditions defined in the
+ * file 'LICENSE' which is part of this source code package.
+ *
+ * Description:
+ */
+
+
+/**
+* @file codec_type.h
+* @brief  Definitions of codec type and structures
+* 
+* @version 1.0.0
+* @date 2011-02-24
+*/
+/* Copyright (C) 2007-2011, Amlogic Inc.
+* All right reserved
+*
+*/
+#ifndef CODEC_TYPE_H_
+#define CODEC_TYPE_H_
+
+#include "amports/amstream.h"
+#include "amports/vformat.h"
+#include "amports/aformat.h"
+//#include "ppmgr/ppmgr.h"
+#include <stdlib.h>
+
+typedef int CODEC_HANDLE;
+
+typedef enum {
+    STREAM_TYPE_UNKNOW,
+    STREAM_TYPE_ES_VIDEO,
+    STREAM_TYPE_ES_AUDIO,
+    STREAM_TYPE_ES_SUB,
+    STREAM_TYPE_PS,
+    STREAM_TYPE_TS,
+    STREAM_TYPE_RM,
+} stream_type_t;
+
+typedef struct {
+    unsigned int    format;  ///< video format, such as H264, MPEG2...
+    unsigned int    width;   ///< video source width
+    unsigned int    height;  ///< video source height
+    unsigned int    rate;    ///< video source frame duration
+    unsigned int    extra;   ///< extra data information of video stream
+    unsigned int    status;  ///< status of video stream
+    unsigned int    ratio;   ///< aspect ratio of video source
+    void *          param;   ///< other parameters for video decoder
+    unsigned long long    ratio64;   ///< aspect ratio of video source
+} dec_sysinfo_t;
+
+typedef struct {
+    int valid;               ///< audio extradata valid(1) or invalid(0), set by dsp
+    int sample_rate;         ///< audio stream sample rate
+    int channels;            ///< audio stream channels
+    int bitrate;             ///< audio stream bit rate
+    int codec_id;            ///< codec format id
+    int block_align;         ///< audio block align from ffmpeg
+    int extradata_size;      ///< extra data size
+    char extradata[AUDIO_EXTRA_DATA_SIZE];;   ///< extra data information for decoder
+} audio_info_t;
+
+typedef struct {
+    int valid;               ///< audio extradata valid(1) or invalid(0), set by dsp
+    int sample_rate;         ///< audio stream sample rate
+    int channels;            ///< audio stream channels
+    int bitrate;             ///< audio stream bit rate
+    int codec_id;            ///< codec format id
+    int block_align;         ///< audio block align from ffmpeg
+    int extradata_size;      ///< extra data size
+    char extradata[512];;   ///< extra data information for decoder
+} Asf_audio_info_t;
+
+typedef struct {
+    CODEC_HANDLE handle;        ///< codec device handler
+    CODEC_HANDLE cntl_handle;   ///< video control device handler
+    CODEC_HANDLE sub_handle;    ///< subtile device handler
+    CODEC_HANDLE audio_utils_handle;  ///< audio utils handler
+    stream_type_t stream_type;  ///< stream type(es, ps, rm, ts)
+unsigned int has_video:
+    1;                          ///< stream has video(1) or not(0)
+unsigned int  has_audio:
+    1;                          ///< stream has audio(1) or not(0)
+unsigned int has_sub:
+    1;                          ///< stream has subtitle(1) or not(0)
+unsigned int noblock:
+    1;                          ///< codec device is NONBLOCK(1) or not(0)
+unsigned int dv_enable:
+	1;							///< videois dv data.
+
+    int video_type;             ///< stream video type(H264, VC1...)
+    int audio_type;             ///< stream audio type(PCM, WMA...)
+    int sub_type;               ///< stream subtitle type(TXT, SSA...)
+    int video_pid;              ///< stream video pid
+    int audio_pid;              ///< stream audio pid
+    int sub_pid;                ///< stream subtitle pid
+    int audio_channels;         ///< stream audio channel number
+    int audio_samplerate;       ///< steram audio sample rate
+    int vbuf_size;              ///< video buffer size of codec device
+    int abuf_size;              ///< audio buffer size of codec device
+    dec_sysinfo_t am_sysinfo;   ///< system information for video
+    audio_info_t audio_info;    ///< audio information pass to audiodsp
+    int packet_size;            ///< data size per packet
+    int avsync_threshold;    ///<for adec in ms>
+    void * adec_priv;          ///<for adec>
+    void * amsub_priv;          // <for amsub>
+    int SessionID;
+    int dspdec_not_supported;//check some profile that audiodsp decoder can not support,we switch to arm decoder
+    int switch_audio_flag;      //<switch audio flag switching(1) else(0)
+    int automute_flag;
+    char *sub_filename;
+    int associate_dec_supported;//support associate or not
+    int mixing_level;
+    unsigned int drmmode;
+} codec_para_t;
+
+typedef struct {
+    signed char id;
+    unsigned char width;
+    unsigned char height;
+    unsigned char type;
+} subtitle_info_t;
+#define MAX_SUB_NUM         (32)
+
+#define IS_VALID_PID(t)     (t>=0 && t<=0x1fff)
+#define IS_VALID_STREAM(t)  (t>0 && t<=0x1fff)
+#define IS_VALID_ATYPE(t)   (t>=0 && t<AFORMAT_MAX)
+#define IS_VALID_VTYPE(t)   (t>=0 && t<VFORMAT_MAX)
+
+//pass to arm audio decoder
+typedef struct {
+    int sample_rate;         ///< audio stream sample rate
+    int channels;            ///< audio stream channels
+    int format;            ///< codec format id
+    int bitrate;
+    int block_align;
+    int codec_id;         //original codecid corespingding to ffmepg
+    int handle;        ///< codec device handler
+    int extradata_size;      ///< extra data size
+    char extradata[AUDIO_EXTRA_DATA_SIZE];
+    int SessionID;
+    int dspdec_not_supported;//check some profile that audiodsp decoder can not support,we switch to arm decoder
+    int droppcm_flag;               // drop pcm flag, if switch audio (1)
+    int automute;
+    unsigned int has_video;
+    int associate_dec_supported;//support associate or not
+    int mixing_level;
+} arm_audio_info;
+
+
+typedef struct {
+    int sub_type;
+    int sub_pid;
+    int stream_type;  // to judge sub how to get data
+    char *sub_filename;
+    unsigned int curr_timeMs; //for idx+sub
+    unsigned int next_pts; //for idx+sub
+
+    unsigned int pts;
+    unsigned int m_delay;
+    unsigned short sub_start_x;
+    unsigned short sub_start_y;
+    unsigned short sub_width;
+    unsigned short sub_height;
+    char * odata;    // point to decoder data
+    unsigned buffer_size;
+} amsub_info_t;
+
+//audio decoder type, default arc
+#define AUDIO_ARC_DECODER 0
+#define AUDIO_ARM_DECODER 1
+#define AUDIO_FFMPEG_DECODER 2
+#define AUDIO_ARMWFD_DECODER  3
+
+int codec_set_drmmode(codec_para_t *pcodec, unsigned int setval);
+int codec_get_video_checkin_bitrate(codec_para_t *pcodec, int *bitrate);
+int codec_get_audio_checkin_bitrate(codec_para_t *pcodec, int *bitrate);
+int codec_set_skip_bytes(codec_para_t* pcodec, unsigned int bytes);
+int codec_get_dsp_apts(codec_para_t* pcodec, unsigned int * apts);
+int codec_get_pcm_level(codec_para_t* pcodec, unsigned int* level);
+#endif
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/freesat.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/freesat.h
new file mode 100644
index 0000000..026632d
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/freesat.h
@@ -0,0 +1,15 @@
+/*
+* Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+*
+* This source code is subject to the terms and conditions defined in the
+* file 'LICENSE' which is part of this source code package. *
+* Description:
+*/
+#ifndef FREESAT_H
+#define FREESAT_H
+
+#include <sys/types.h>
+
+char *freesat_huffman_decode(const unsigned char *compressed, size_t size);
+
+#endif
\ No newline at end of file
diff --git a/test/am_ca_key_test/inject_record_t5d/include/am_adp/memwatch.h b/test/am_ca_key_test/inject_record_t5d/include/am_adp/memwatch.h
new file mode 100644
index 0000000..d63fd76
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/am_adp/memwatch.h
@@ -0,0 +1,707 @@
+/*
+** MEMWATCH.H
+** Nonintrusive ANSI C memory leak / overwrite detection
+** Copyright (C) 1992-2002 Johan Lindh
+** All rights reserved.
+** Version 2.71
+**
+************************************************************************
+**
+** PURPOSE:
+**
+**  MEMWATCH has been written to allow guys and gals that like to
+**  program in C a public-domain memory error control product.
+**  I hope you'll find it's as advanced as most commercial packages.
+**  The idea is that you use it during the development phase and
+**  then remove the MEMWATCH define to produce your final product.
+**  MEMWATCH is distributed in source code form in order to allow
+**  you to compile it for your platform with your own compiler.
+**  It's aim is to be 100% ANSI C, but some compilers are more stingy
+**  than others. If it doesn't compile without warnings, please mail
+**  me the configuration of operating system and compiler you are using
+**  along with a description of how to modify the source, and the version
+**  number of MEMWATCH that you are using.
+**
+************************************************************************
+
+	This file is part of MEMWATCH.
+
+    MEMWATCH 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.
+
+    MEMWATCH 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 MEMWATCH; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+************************************************************************
+**
+** REVISION HISTORY:
+**
+** 920810 JLI   [1.00]
+** 920830 JLI   [1.10 double-free detection]
+** 920912 JLI   [1.15 mwPuts, mwGrab/Drop, mwLimit]
+** 921022 JLI   [1.20 ASSERT and VERIFY]
+** 921105 JLI   [1.30 C++ support and TRACE]
+** 921116 JLI   [1.40 mwSetOutFunc]
+** 930215 JLI   [1.50 modified ASSERT/VERIFY]
+** 930327 JLI   [1.51 better auto-init & PC-lint support]
+** 930506 JLI   [1.55 MemWatch class, improved C++ support]
+** 930507 JLI   [1.60 mwTest & CHECK()]
+** 930809 JLI   [1.65 Abort/Retry/Ignore]
+** 930820 JLI   [1.70 data dump when unfreed]
+** 931016 JLI   [1.72 modified C++ new/delete handling]
+** 931108 JLI   [1.77 mwSetAssertAction() & some small changes]
+** 940110 JLI   [1.80 no-mans-land alloc/checking]
+** 940328 JLI   [2.00 version 2.0 rewrite]
+**              Improved NML (no-mans-land) support.
+**              Improved performance (especially for free()ing!).
+**              Support for 'read-only' buffers (checksums)
+**              ^^ NOTE: I never did this... maybe I should?
+**              FBI (free'd block info) tagged before freed blocks
+**              Exporting of the mwCounter variable
+**              mwBreakOut() localizes debugger support
+**              Allocation statistics (global, per-module, per-line)
+**              Self-repair ability with relinking
+** 950913 JLI   [2.10 improved garbage handling]
+** 951201 JLI   [2.11 improved auto-free in emergencies]
+** 960125 JLI   [X.01 implemented auto-checking using mwAutoCheck()]
+** 960514 JLI   [2.12 undefining of existing macros]
+** 960515 JLI   [2.13 possibility to use default new() & delete()]
+** 960516 JLI   [2.20 suppression of file flushing on unfreed msgs]
+** 960516 JLI   [2.21 better support for using MEMWATCH with DLL's]
+** 960710 JLI   [X.02 multiple logs and mwFlushNow()]
+** 960801 JLI   [2.22 merged X.01 version with current]
+** 960805 JLI   [2.30 mwIsXXXXAddr() to avoid unneeded GP's]
+** 960805 JLI   [2.31 merged X.02 version with current]
+** 961002 JLI   [2.32 support for realloc() + fixed STDERR bug]
+** 961222 JLI   [2.40 added mwMark() & mwUnmark()]
+** 970101 JLI   [2.41 added over/underflow checking after failed ASSERT/VERIFY]
+** 970113 JLI   [2.42 added support for PC-Lint 7.00g]
+** 970207 JLI   [2.43 added support for strdup()]
+** 970209 JLI   [2.44 changed default filename to lowercase]
+** 970405 JLI   [2.45 fixed bug related with atexit() and some C++ compilers]
+** 970723 JLI   [2.46 added MW_ARI_NULLREAD flag]
+** 970813 JLI   [2.47 stabilized marker handling]
+** 980317 JLI   [2.48 ripped out C++ support; wasn't working good anyway]
+** 980318 JLI   [2.50 improved self-repair facilities & SIGSEGV support]
+** 980417 JLI	[2.51 more checks for invalid addresses]
+** 980512 JLI	[2.52 moved MW_ARI_NULLREAD to occur before aborting]
+** 990112 JLI	[2.53 added check for empty heap to mwIsOwned]
+** 990217 JLI	[2.55 improved the emergency repairs diagnostics and NML]
+** 990224 JLI	[2.56 changed ordering of members in structures]
+** 990303 JLI	[2.57 first maybe-fixit-for-hpux test]
+** 990516 JLI	[2.58 added 'static' to the definition of mwAutoInit]
+** 990517 JLI	[2.59 fixed some high-sensitivity warnings]
+** 990610 JLI	[2.60 fixed some more high-sensitivity warnings]
+** 990715 JLI	[2.61 changed TRACE/ASSERT/VERIFY macro names]
+** 991001 JLI	[2.62 added CHECK_BUFFER() and mwTestBuffer()]
+** 991007 JLI	[2.63 first shot at a 64-bit compatible version]
+** 991009 JLI	[2.64 undef's strdup() if defined, mwStrdup made const]
+** 000704 JLI	[2.65 added some more detection for 64-bits]
+** 010502 JLI   [2.66 incorporated some user fixes]
+**              [mwRelink() could print out garbage pointer (thanks mac@phobos.ca)]
+**				[added array destructor for C++ (thanks rdasilva@connecttel.com)]
+**				[added mutex support (thanks rdasilva@connecttel.com)]
+** 010531 JLI	[2.67 fix: mwMutexXXX() was declared even if MW_HAVE_MUTEX was not defined]
+** 010619 JLI	[2.68 fix: mwRealloc() could leave the mutex locked]
+** 020918 JLI	[2.69 changed to GPL, added C++ array allocation by Howard Cohen]
+** 030212 JLI	[2.70 mwMalloc() bug for very large allocations (4GB on 32bits)]
+** 030520 JLI	[2.71 added ULONG_LONG_MAX as a 64-bit detector (thanks Sami Salonen)]
+**
+** To use, simply include 'MEMWATCH.H' as a header file,
+** and add MEMWATCH.C to your list of files, and define the macro
+** 'MEMWATCH'. If this is not defined, MEMWATCH will disable itself.
+**
+** To call the standard C malloc / realloc / calloc / free; use mwMalloc_(),
+** mwCalloc_() and mwFree_(). Note that mwFree_() will correctly
+** free both malloc()'d memory as well as mwMalloc()'d.
+**
+** 980317: C++ support has been disabled.
+**         The code remains, but is not compiled.
+**
+**         For use with C++, which allows use of inlining in header files
+**         and class specific new/delete, you must also define 'new' as
+**         'mwNew' and 'delete' as 'mwDelete'. Do this *after* you include
+**         C++ header files from libraries, otherwise you can mess up their
+**         class definitions. If you don't define these, the C++ allocations
+**         will not have source file and line number information. Also note,
+**         most C++ class libraries implement their own C++ memory management,
+**         and don't allow anyone to override them. MFC belongs to this crew.
+**         In these cases, the only thing to do is to use MEMWATCH_NOCPP.
+**
+** You can capture output from MEMWATCH using mwSetOutFunc().
+** Just give it the adress of a "void myOutFunc(int c)" function,
+** and all characters to be output will be redirected there.
+**
+** A failing ASSERT() or VERIFY() will normally always abort your
+** program. This can be changed using mwSetAriFunc(). Give it a
+** pointer to a "int myAriFunc(const char *)" function. Your function
+** must ask the user whether to Abort, Retry or Ignore the trap.
+** Return 2 to Abort, 1 to Retry or 0 to Ignore. Beware retry; it
+** causes the expression to be evaluated again! MEMWATCH has a
+** default ARI handler. It's disabled by default, but you can enable
+** it by calling 'mwDefaultAri()'. Note that this will STILL abort
+** your program unless you define MEMWATCH_STDIO to allow MEMWATCH
+** to use the standard C I/O streams. Also, setting the ARI function
+** will cause MEMWATCH *NOT* to write the ARI error to stderr. The
+** error string is passed to the ARI function instead, as the
+** 'const char *' parameter.
+**
+** You can disable MEMWATCH's ASSERT/VERIFY and/or TRACE implementations.
+** This can be useful if you're using a debug terminal or smart debugger.
+** Disable them by defining MW_NOASSERT, MW_NOVERIFY or MW_NOTRACE.
+**
+** MEMWATCH fills all allocated memory with the byte 0xFE, so if
+** you're looking at erroneous data which are all 0xFE:s, the
+** data probably was not initialized by you. The exception is
+** calloc(), which will fill with zero's. All freed buffers are
+** zapped with 0xFD. If this is what you look at, you're using
+** data that has been freed. If this is the case, be aware that
+** MEMWATCH places a 'free'd block info' structure immediately
+** before the freed data. This block contains info about where
+** the block was freed. The information is in readable text,
+** in the format "FBI<counter>filename(line)", for example:
+** "FBI<267>test.c(12)". Using FBI's slows down free(), so it's
+** disabled by default. Use mwFreeBufferInfo(1) to enable it.
+**
+** To aid in tracking down wild pointer writes, MEMWATCH can perform
+** no-mans-land allocations. No-mans-land will contain the byte 0xFC.
+** MEMWATCH will, when this is enabled, convert recently free'd memory
+** into NML allocations.
+**
+** MEMWATCH protects it's own data buffers with checksums. If you
+** get an internal error, it means you're overwriting wildly,
+** or using an uninitialized pointer.
+**
+************************************************************************
+**
+** Note when compiling with Microsoft C:
+**  -   MSC ignores fflush() by default. This is overridden, so that
+**      the disk log will always be current.
+**
+** This utility has been tested with:
+**  PC-lint 7.0k, passed as 100% ANSI C compatible
+**  Microsoft Visual C++ on Win16 and Win32
+**  Microsoft C on DOS
+**  SAS C on an Amiga 500
+**  Gnu C on a PC running Red Hat Linux
+**  ...and using an (to me) unknown compiler on an Atari machine.
+**
+************************************************************************
+**
+** Format of error messages in MEMWATCH.LOG:
+**  message: <sequence-number> filename(linenumber), information
+**
+** Errors caught by MemWatch, when they are detected, and any
+** actions taken besides writing to the log file MEMWATCH.LOG:
+**
+**  Double-freeing:
+**      A pointer that was recently freed and has not since been
+**      reused was freed again. The place where the previous free()
+**      was executed is displayed.
+**      Detect: delete or free() using the offending pointer.
+**      Action: The delete or free() is cancelled, execution continues.
+**  Underflow:
+**      You have written just ahead of the allocated memory.
+**      The size and place of the allocation is displayed.
+**      Detect: delete or free() of the damaged buffer.
+**      Action: The buffer is freed, but there may be secondary damage.
+**  Overflow:
+**      Like underflow, but you've written after the end of the buffer.
+**      Detect: see Underflow.
+**      Action: see Underflow.
+**  WILD free:
+**      An unrecognized pointer was passed to delete or free().
+**      The pointer may have been returned from a library function;
+**      in that case, use mwFree_() to force free() of it.
+**      Also, this may be a double-free, but the previous free was
+**      too long ago, causing MEMWATCH to 'forget' it.
+**      Detect: delete or free() of the offending pointer.
+**      Action: The delete or free() is cancelled, execution continues.
+**  NULL free:
+**      It's unclear to me whether or not freeing of NULL pointers
+**      is legal in ANSI C, therefore a warning is written to the log file,
+**      but the error counter remains the same. This is legal using C++,
+**      so the warning does not appear with delete.
+**      Detect: When you free(NULL).
+**      Action: The free() is cancelled.
+**  Failed:
+**      A request to allocate memory failed. If the allocation is
+**      small, this may be due to memory depletion, but is more likely
+**      to be memory fragmentation problems. The amount of memory
+**      allocated so far is displayed also.
+**      Detect: When you new, malloc(), realloc() or calloc() memory.
+**      Action: NULL is returned.
+**  Realloc:
+**      A request to re-allocate a memory buffer failed for reasons
+**      other than out-of-memory. The specific reason is shown.
+**      Detect: When you realloc()
+**      Action: realloc() is cancelled, NULL is returned
+**  Limit fail:
+**      A request to allocate memory failed since it would violate
+**      the limit set using mwLimit(). mwLimit() is used to stress-test
+**      your code under simulated low memory conditions.
+**      Detect: At new, malloc(), realloc() or calloc().
+**      Action: NULL is returned.
+**  Assert trap:
+**      An ASSERT() failed. The ASSERT() macro works like C's assert()
+**      macro/function, except that it's interactive. See your C manual.
+**      Detect: On the ASSERT().
+**      Action: Program ends with an advisory message to stderr, OR
+**              Program writes the ASSERT to the log and continues, OR
+**              Program asks Abort/Retry/Ignore? and takes that action.
+**  Verify trap:
+**      A VERIFY() failed. The VERIFY() macro works like ASSERT(),
+**      but if MEMWATCH is not defined, it still evaluates the
+**      expression, but it does not act upon the result.
+**      Detect: On the VERIFY().
+**      Action: Program ends with an advisory message to stderr, OR
+**              Program writes the VERIFY to the log and continues, OR
+**              Program asks Abort/Retry/Ignore? and takes that action.
+**  Wild pointer:
+**      A no-mans-land buffer has been written into. MEMWATCH can
+**      allocate and distribute chunks of memory solely for the
+**      purpose of trying to catch random writes into memory.
+**      Detect: Always on CHECK(), but can be detected in several places.
+**      Action: The error is logged, and if an ARI handler is installed,
+**              it is executed, otherwise, execution continues.
+**  Unfreed:
+**      A memory buffer you allocated has not been freed.
+**      You are informed where it was allocated, and whether any
+**      over or underflow has occured. MemWatch also displays up to
+**      16 bytes of the data, as much as it can, in hex and text.
+**      Detect: When MemWatch terminates.
+**      Action: The buffer is freed.
+**  Check:
+**      An error was detected during a CHECK() operation.
+**      The associated pointer is displayed along with
+**      the file and line where the CHECK() was executed.
+**      Followed immediately by a normal error message.
+**      Detect: When you CHECK()
+**      Action: Depends on the error
+**  Relink:
+**      After a MEMWATCH internal control block has been trashed,
+**      MEMWATCH tries to repair the damage. If successful, program
+**      execution will continue instead of aborting. Some information
+**      about the block may be gone permanently, though.
+**      Detect: N/A
+**      Action: Relink successful: program continues.
+**              Relink fails: program aborts.
+**  Internal:
+**      An internal error is flagged by MEMWATCH when it's control
+**      structures have been damaged. You are likely using an uninitialized
+**      pointer somewhere in your program, or are zapping memory all over.
+**      The message may give you additional diagnostic information.
+**      If possible, MEMWATCH will recover and continue execution.
+**      Detect: Various actions.
+**      Action: Whatever is needed
+**  Mark:
+**      The program terminated without umarking all marked pointers. Marking
+**      can be used to track resources other than memory. mwMark(pointer,text,...)
+**      when the resource is allocated, and mwUnmark(pointer) when it's freed.
+**      The 'text' is displayed for still marked pointers when the program
+**      ends.
+**      Detect: When MemWatch terminates.
+**      Action: The error is logged.
+**
+**
+************************************************************************
+**
+**  The author may be reached by e-mail at the address below. If you
+**  mail me about source code changes in MEMWATCH, remember to include
+**  MW's version number.
+**
+**      Johan Lindh
+**      johan@linkdata.se
+**
+** The latest version of MEMWATCH may be downloaded from
+** http://www.linkdata.se/
+*/
+
+#ifndef __MEMWATCH_H
+#define __MEMWATCH_H
+
+/* Make sure that malloc(), realloc(), calloc() and free() are declared. */
+/*lint -save -e537 */
+#include <stdlib.h>
+/*lint -restore */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+** Constants used
+**  All MEMWATCH constants start with the prefix MW_, followed by
+**  a short mnemonic which indicates where the constant is used,
+**  followed by a descriptive text about it.
+*/
+
+#define MW_ARI_NULLREAD 0x10    /* Null read (to start debugger) */
+#define MW_ARI_ABORT    0x04    /* ARI handler says: abort program! */
+#define MW_ARI_RETRY    0x02    /* ARI handler says: retry action! */
+#define MW_ARI_IGNORE   0x01    /* ARI handler says: ignore error! */
+
+#define MW_VAL_NEW      0xFE    /* value in newly allocated memory */
+#define MW_VAL_DEL      0xFD    /* value in newly deleted memory */
+#define MW_VAL_NML      0xFC    /* value in no-mans-land */
+#define MW_VAL_GRB      0xFB    /* value in grabbed memory */
+
+#define MW_TEST_ALL     0xFFFF  /* perform all tests */
+#define MW_TEST_CHAIN   0x0001  /* walk the heap chain */
+#define MW_TEST_ALLOC   0x0002  /* test allocations & NML guards */
+#define MW_TEST_NML     0x0004  /* test all-NML areas for modifications */
+
+#define MW_NML_NONE     0       /* no NML */
+#define MW_NML_FREE     1       /* turn FREE'd memory into NML */
+#define MW_NML_ALL      2       /* all unused memory is NML */
+#define MW_NML_DEFAULT  0       /* the default NML setting */
+
+#define MW_STAT_GLOBAL  0       /* only global statistics collected */
+#define MW_STAT_MODULE  1       /* collect statistics on a module basis */
+#define MW_STAT_LINE    2       /* collect statistics on a line basis */
+#define MW_STAT_DEFAULT 0       /* the default statistics setting */
+
+/*
+** MemWatch internal constants
+**  You may change these and recompile MemWatch to change the limits
+**  of some parameters. Respect the recommended minimums!
+*/
+#define MW_TRACE_BUFFER 2048    /* (min 160) size of TRACE()'s output buffer */
+#define MW_FREE_LIST    64      /* (min 4) number of free()'s to track */
+
+/*
+** Exported variables
+**  In case you have to remove the 'const' keyword because your compiler
+**  doesn't support it, be aware that changing the values may cause
+**  unpredictable behaviour.
+**  - mwCounter contains the current action count. You can use this to
+**      place breakpoints using a debugger, if you want.
+*/
+#ifndef __MEMWATCH_C
+extern const unsigned long mwCounter;
+#endif
+
+/*
+** System functions
+**  Normally, it is not nessecary to call any of these. MEMWATCH will
+**  automatically initialize itself on the first MEMWATCH function call,
+**  and set up a call to mwAbort() using atexit(). Some C++ implementations
+**  run the atexit() chain before the program has terminated, so you
+**  may have to use mwInit() or the MemWatch C++ class to get good
+**  behaviour.
+**  - mwInit() can be called to disable the atexit() usage. If mwInit()
+**      is called directly, you must call mwTerm() to end MemWatch, or
+**      mwAbort().
+**  - mwTerm() is usually not nessecary to call; but if called, it will
+**      call mwAbort() if it finds that it is cancelling the 'topmost'
+**      mwInit() call.
+**  - mwAbort() cleans up after MEMWATCH, reports unfreed buffers, etc.
+*/
+void  mwInit( void );
+void  mwTerm( void );
+void  mwAbort( void );
+
+/*
+** Setup functions
+**  These functions control the operation of MEMWATCH's protective features.
+**  - mwFlushNow() causes MEMWATCH to flush it's buffers.
+**  - mwDoFlush() controls whether MEMWATCH flushes the disk buffers after
+**      writes. The default is smart flushing: MEMWATCH will not flush buffers
+**      explicitly until memory errors are detected. Then, all writes are
+**      flushed until program end or mwDoFlush(0) is called.
+**  - mwLimit() sets the allocation limit, an arbitrary limit on how much
+**      memory your program may allocate in bytes. Used to stress-test app.
+**      Also, in virtual-memory or multitasking environs, puts a limit on
+**      how much MW_NML_ALL can eat up.
+**  - mwGrab() grabs up X kilobytes of memory. Allocates actual memory,
+**      can be used to stress test app & OS both.
+**  - mwDrop() drops X kilobytes of grabbed memory.
+**  - mwNoMansLand() sets the behaviour of the NML logic. See the
+**      MW_NML_xxx for more information. The default is MW_NML_DEFAULT.
+**  - mwStatistics() sets the behaviour of the statistics collector. See
+**      the MW_STAT_xxx defines for more information. Default MW_STAT_DEFAULT.
+**  - mwFreeBufferInfo() enables or disables the tagging of free'd buffers
+**      with freeing information. This information is written in text form,
+**      using sprintf(), so it's pretty slow. Disabled by default.
+**  - mwAutoCheck() performs a CHECK() operation whenever a MemWatch function
+**      is used. Slows down performance, of course.
+**  - mwCalcCheck() calculates checksums for all data buffers. Slow!
+**  - mwDumpCheck() logs buffers where stored & calc'd checksums differ. Slow!!
+**  - mwMark() sets a generic marker. Returns the pointer given.
+**  - mwUnmark() removes a generic marker. If, at the end of execution, some
+**      markers are still in existence, these will be reported as leakage.
+**      returns the pointer given.
+*/
+void        mwFlushNow( void );
+void        mwDoFlush( int onoff );
+void        mwLimit( long bytes );
+unsigned    mwGrab( unsigned kilobytes );
+unsigned    mwDrop( unsigned kilobytes );
+void        mwNoMansLand( int mw_nml_level );
+void        mwStatistics( int level );
+void        mwFreeBufferInfo( int onoff );
+void        mwAutoCheck( int onoff );
+void        mwCalcCheck( void );
+void        mwDumpCheck( void );
+void *      mwMark( void *p, const char *description, const char *file, unsigned line );
+void *      mwUnmark( void *p, const char *file, unsigned line );
+
+/*
+** Testing/verification/tracing
+**  All of these macros except VERIFY() evaluates to a null statement
+**  if MEMWATCH is not defined during compilation.
+**  - mwIsReadAddr() checks a memory area for read privilige.
+**  - mwIsSafeAddr() checks a memory area for both read & write privilige.
+**      This function and mwIsReadAddr() is highly system-specific and
+**      may not be implemented. If this is the case, they will default
+**      to returning nonzero for any non-NULL pointer.
+**  - CHECK() does a complete memory integrity test. Slow!
+**  - CHECK_THIS() checks only selected components.
+**  - CHECK_BUFFER() checks the indicated buffer for errors.
+**  - mwASSERT() or ASSERT() If the expression evaluates to nonzero, execution continues.
+**      Otherwise, the ARI handler is called, if present. If not present,
+**      the default ARI action is taken (set with mwSetAriAction()).
+**      ASSERT() can be disabled by defining MW_NOASSERT.
+**  - mwVERIFY() or VERIFY() works just like ASSERT(), but when compiling without
+**      MEMWATCH the macro evaluates to the expression.
+**      VERIFY() can be disabled by defining MW_NOVERIFY.
+**  - mwTRACE() or TRACE() writes some text and data to the log. Use like printf().
+**      TRACE() can be disabled by defining MW_NOTRACE.
+*/
+int   mwIsReadAddr( const void *p, unsigned len );
+int   mwIsSafeAddr( void *p, unsigned len );
+int   mwTest( const char *file, int line, int mw_test_flags );
+int   mwTestBuffer( const char *file, int line, void *p );
+int   mwAssert( int, const char*, const char*, int );
+int   mwVerify( int, const char*, const char*, int );
+
+/*
+** User I/O functions
+**  - mwTrace() works like printf(), but dumps output either to the
+**      function specified with mwSetOutFunc(), or the log file.
+**  - mwPuts() works like puts(), dumps output like mwTrace().
+**  - mwSetOutFunc() allows you to give the adress of a function
+**      where all user output will go. (exeption: see mwSetAriFunc)
+**      Specifying NULL will direct output to the log file.
+**  - mwSetAriFunc() gives MEMWATCH the adress of a function to call
+**      when an 'Abort, Retry, Ignore' question is called for. The
+**      actual error message is NOT printed when you've set this adress,
+**      but instead it is passed as an argument. If you call with NULL
+**      for an argument, the ARI handler is disabled again. When the
+**      handler is disabled, MEMWATCH will automatically take the
+**      action specified by mwSetAriAction().
+**  - mwSetAriAction() sets the default ARI return value MEMWATCH should
+**      use if no ARI handler is specified. Defaults to MW_ARI_ABORT.
+**  - mwAriHandler() is an ANSI ARI handler you can use if you like. It
+**      dumps output to stderr, and expects input from stdin.
+**  - mwBreakOut() is called in certain cases when MEMWATCH feels it would
+**      be nice to break into a debugger. If you feel like MEMWATCH, place
+**      an execution breakpoint on this function.
+*/
+void  mwTrace( const char* format_string, ... );
+void  mwPuts( const char* text );
+void  mwSetOutFunc( void (*func)(int) );
+void  mwSetAriFunc( int (*func)(const char*) );
+void  mwSetAriAction( int mw_ari_value );
+int   mwAriHandler( const char* cause );
+void  mwBreakOut( const char* cause );
+
+/*
+** Allocation/deallocation functions
+**  These functions are the ones actually to perform allocations
+**  when running MEMWATCH, for both C and C++ calls.
+**  - mwMalloc() debugging allocator
+**  - mwMalloc_() always resolves to a clean call of malloc()
+**  - mwRealloc() debugging re-allocator
+**  - mwRealloc_() always resolves to a clean call of realloc()
+**  - mwCalloc() debugging allocator, fills with zeros
+**  - mwCalloc_() always resolves to a clean call of calloc()
+**  - mwFree() debugging free. Can only free memory which has
+**      been allocated by MEMWATCH.
+**  - mwFree_() resolves to a) normal free() or b) debugging free.
+**      Can free memory allocated by MEMWATCH and malloc() both.
+**      Does not generate any runtime errors.
+*/
+void* mwMalloc( size_t, const char*, int );
+void* mwMalloc_( size_t );
+void* mwRealloc( void *, size_t, const char*, int );
+void* mwRealloc_( void *, size_t );
+void* mwCalloc( size_t, size_t, const char*, int );
+void* mwCalloc_( size_t, size_t );
+void  mwFree( void*, const char*, int );
+void  mwFree_( void* );
+char* mwStrdup( const char *, const char*, int );
+
+/*
+** Enable/disable precompiler block
+**  This block of defines and if(n)defs make sure that references
+**  to MEMWATCH is completely removed from the code if the MEMWATCH
+**  manifest constant is not defined.
+*/
+#ifndef __MEMWATCH_C
+#ifdef MEMWATCH
+
+#define mwASSERT(exp)   while(mwAssert((int)(exp),#exp,__FILE__,__LINE__))
+#ifndef MW_NOASSERT
+#ifndef ASSERT
+#define ASSERT          mwASSERT
+#endif /* !ASSERT */
+#endif /* !MW_NOASSERT */
+#define mwVERIFY(exp)   while(mwVerify((int)(exp),#exp,__FILE__,__LINE__))
+#ifndef MW_NOVERIFY
+#ifndef VERIFY
+#define VERIFY          mwVERIFY
+#endif /* !VERIFY */
+#endif /* !MW_NOVERIFY */
+#define mwTRACE         mwTrace
+#ifndef MW_NOTRACE
+#ifndef TRACE
+#define TRACE           mwTRACE
+#endif /* !TRACE */
+#endif /* !MW_NOTRACE */
+
+/* some compilers use a define and not a function */
+/* for strdup(). */
+#ifdef strdup
+#undef strdup
+#endif
+
+#define malloc(n)       mwMalloc(n,__FILE__,__LINE__)
+#define strdup(p)       mwStrdup(p,__FILE__,__LINE__)
+#define realloc(p,n)    mwRealloc(p,n,__FILE__,__LINE__)
+#define calloc(n,m)     mwCalloc(n,m,__FILE__,__LINE__)
+#define free(p)         mwFree(p,__FILE__,__LINE__)
+#define CHECK()         mwTest(__FILE__,__LINE__,MW_TEST_ALL)
+#define CHECK_THIS(n)   mwTest(__FILE__,__LINE__,n)
+#define CHECK_BUFFER(b) mwTestBuffer(__FILE__,__LINE__,b)
+#define MARK(p)         mwMark(p,#p,__FILE__,__LINE__)
+#define UNMARK(p)       mwUnmark(p,__FILE__,__LINE__)
+
+#else /* MEMWATCH */
+
+#define mwASSERT(exp)
+#ifndef MW_NOASSERT
+#ifndef ASSERT
+#define ASSERT          mwASSERT
+#endif /* !ASSERT */
+#endif /* !MW_NOASSERT */
+
+#define mwVERIFY(exp)    exp
+#ifndef MW_NOVERIFY
+#ifndef VERIFY
+#define VERIFY          mwVERIFY
+#endif /* !VERIFY */
+#endif /* !MW_NOVERIFY */
+
+/*lint -esym(773,mwTRACE) */
+#define mwTRACE         /*lint -save -e506 */ 1?(void)0:mwDummyTraceFunction /*lint -restore */
+#ifndef MW_NOTRACE
+#ifndef TRACE
+/*lint -esym(773,TRACE) */
+#define TRACE           mwTRACE
+#endif /* !TRACE */
+#endif /* !MW_NOTRACE */
+
+extern void mwDummyTraceFunction(const char *,...);
+/*lint -save -e652 */
+#define mwDoFlush(n)
+#define mwPuts(s)
+#define mwInit()
+#define mwGrab(n)
+#define mwDrop(n)
+#define mwLimit(n)
+#define mwTest(f,l)
+#define mwSetOutFunc(f)
+#define mwSetAriFunc(f)
+#define mwDefaultAri()
+#define mwNomansland()
+#define mwStatistics(f)
+#define mwMark(p,t,f,n)     (p)
+#define mwUnmark(p,f,n)     (p)
+#define mwMalloc(n,f,l)     malloc(n)
+#define mwStrdup(p,f,l)     strdup(p)
+#define mwRealloc(p,n,f,l)  realloc(p,n)
+#define mwCalloc(n,m,f,l)   calloc(n,m)
+#define mwFree(p)           free(p)
+#define mwMalloc_(n)        malloc(n)
+#define mwRealloc_(p,n)     realloc(p,n)
+#define mwCalloc_(n,m)      calloc(n,m)
+#define mwFree_(p)          free(p)
+#define mwAssert(e,es,f,l)
+#define mwVerify(e,es,f,l)  (e)
+#define mwTrace             mwDummyTrace
+#define mwTestBuffer(f,l,b) (0)
+#define CHECK()
+#define CHECK_THIS(n)
+#define CHECK_BUFFER(b)
+#define MARK(p)             (p)
+#define UNMARK(p)           (p)
+/*lint -restore */
+
+#endif /* MEMWATCH */
+#endif /* !__MEMWATCH_C */
+
+#ifdef __cplusplus
+    }
+#endif
+
+#if 0 /* 980317: disabled C++ */
+
+/*
+** C++ support section
+**  Implements the C++ support. Please note that in order to avoid
+**  messing up library classes, C++ support is disabled by default.
+**  You must NOT enable it until AFTER the inclusion of all header
+**  files belonging to code that are not compiled with MEMWATCH, and
+**  possibly for some that are! The reason for this is that a C++
+**  class may implement it's own new() function, and the preprocessor
+**  would substitute this crucial declaration for MEMWATCH new().
+**  You can forcibly deny C++ support by defining MEMWATCH_NOCPP.
+**  To enble C++ support, you must be compiling C++, MEMWATCH must
+**  be defined, MEMWATCH_NOCPP must not be defined, and finally,
+**  you must define 'new' to be 'mwNew', and 'delete' to be 'mwDelete'.
+**  Unlike C, C++ code can begin executing *way* before main(), for
+**  example if a global variable is created. For this reason, you can
+**  declare a global variable of the class 'MemWatch'. If this is
+**  is the first variable created, it will then check ALL C++ allocations
+**  and deallocations. Unfortunately, this evaluation order is not
+**  guaranteed by C++, though the compilers I've tried evaluates them
+**  in the order encountered.
+*/
+#ifdef __cplusplus
+#ifndef __MEMWATCH_C
+#ifdef MEMWATCH
+#ifndef MEMWATCH_NOCPP
+extern int mwNCur;
+extern const char *mwNFile;
+extern int mwNLine;
+class MemWatch {
+public:
+    MemWatch();
+    ~MemWatch();
+    };
+void * operator new(size_t);
+void * operator new(size_t,const char *,int);
+void * operator new[] (size_t,const char *,int);	// hjc 07/16/02
+void operator delete(void *);
+#define mwNew new(__FILE__,__LINE__)
+#define mwDelete (mwNCur=1,mwNFile=__FILE__,mwNLine=__LINE__),delete
+#endif /* MEMWATCH_NOCPP */
+#endif /* MEMWATCH */
+#endif /* !__MEMWATCH_C */
+#endif /* __cplusplus */
+
+#endif /* 980317: disabled C++ */
+
+#endif /* __MEMWATCH_H */
+
+/* EOF MEMWATCH.H */
diff --git a/test/am_ca_key_test/inject_record_t5d/include/ndk/include/.malloc.h.swp b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/.malloc.h.swp
new file mode 100755
index 0000000..dbe466d
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/.malloc.h.swp
Binary files differ
diff --git a/test/am_ca_key_test/inject_record_t5d/include/ndk/include/amdsc.h b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/amdsc.h
new file mode 100644
index 0000000..3a36f26
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/amdsc.h
@@ -0,0 +1,33 @@
+/*
+* Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+*
+* This source code is subject to the terms and conditions defined in the
+* file 'LICENSE' which is part of this source code package. *
+* Description:
+*/
+#ifndef _AMDSC_H
+#define _AMDSC_H
+
+#include <linux/types.h>
+
+enum am_dsc_key_type_t {
+	AM_DSC_EVEN_KEY = 0,
+	AM_DSC_ODD_KEY = 1,
+	AM_DSC_EVEN_KEY_AES = 2,
+	AM_DSC_ODD_KEY_AES = 3,
+	AM_DSC_EVEN_KEY_AES_IV = 4,
+	AM_DSC_ODD_KEY_AES_IV = 5,
+	AM_DSC_FROM_KL_KEY = (1<<7)
+};
+struct am_dsc_key {
+	enum am_dsc_key_type_t    type;
+	__u8                 key[16];
+};
+
+#define AMDSC_IOC_MAGIC  'D'
+
+#define AMDSC_IOC_SET_PID      _IO(AMDSC_IOC_MAGIC, 0x00)
+#define AMDSC_IOC_SET_KEY      _IOW(AMDSC_IOC_MAGIC, 0x01, int)
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/ndk/include/amsmc.h b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/amsmc.h
new file mode 100644
index 0000000..85bfcea
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/amsmc.h
@@ -0,0 +1,65 @@
+/*
+ * AMLOGIC Smart card driver.
+ *
+ * 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 named License,
+ * or 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef _AMSMC_H
+#define _AMSMC_H
+
+#include <asm/types.h>
+
+#define AMSMC_MAX_ATR_LEN    33
+
+enum {
+	AMSMC_CARDOUT = 0,
+	AMSMC_CARDIN = 1
+};
+
+struct am_smc_atr {
+	char    atr[AMSMC_MAX_ATR_LEN];
+	int     atr_len;
+};
+
+struct am_smc_param {
+	int     f;
+	int     d;
+	int     n;
+	int     bwi;
+	int     cwi;
+	int     bgt;
+	int     freq;
+	int     recv_invert;
+	int     recv_lsb_msb;
+	int     recv_no_parity;
+	int     recv_parity;
+	int     xmit_invert;
+	int     xmit_lsb_msb;
+	int     xmit_retries;
+	int     xmit_repeat_dis;
+	int     xmit_parity;
+};
+
+#define AMSMC_IOC_MAGIC  'C'
+
+#define AMSMC_IOC_RESET        _IOR(AMSMC_IOC_MAGIC, 0x00, struct am_smc_atr)
+#define AMSMC_IOC_GET_STATUS   _IOR(AMSMC_IOC_MAGIC, 0x01, int)
+#define AMSMC_IOC_ACTIVE       _IO(AMSMC_IOC_MAGIC, 0x02)
+#define AMSMC_IOC_DEACTIVE     _IO(AMSMC_IOC_MAGIC, 0x03)
+#define AMSMC_IOC_GET_PARAM    _IOR(AMSMC_IOC_MAGIC, 0x04, struct am_smc_param)
+#define AMSMC_IOC_SET_PARAM    _IOW(AMSMC_IOC_MAGIC, 0x05, struct am_smc_param)
+
+#endif
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/aformat.h b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/aformat.h
new file mode 100644
index 0000000..d6d3555
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/aformat.h
@@ -0,0 +1,55 @@
+/*
+ * AMLOGIC Audio/Video streaming port driver.
+ *
+ * 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 named License,
+ * or 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Author:  Tim Yao <timyao@amlogic.com>
+ *
+ */
+
+#ifndef AFORMAT_H
+#define AFORMAT_H
+
+enum aformat_e {
+    AFORMAT_MPEG   = 0,
+    AFORMAT_PCM_S16LE = 1,
+    AFORMAT_AAC   = 2,
+    AFORMAT_AC3   =3,
+    AFORMAT_ALAW = 4,
+    AFORMAT_MULAW = 5,
+    AFORMAT_DTS = 6,
+    AFORMAT_PCM_S16BE = 7,
+    AFORMAT_FLAC = 8,
+    AFORMAT_COOK = 9,
+    AFORMAT_PCM_U8 = 10,
+    AFORMAT_ADPCM = 11,
+    AFORMAT_AMR  = 12,
+    AFORMAT_RAAC  = 13,
+    AFORMAT_WMA  = 14,
+    AFORMAT_WMAPRO    = 15,
+    AFORMAT_PCM_BLURAY	= 16,
+    AFORMAT_ALAC  = 17,
+    AFORMAT_VORBIS    = 18,
+    AFORMAT_AAC_LATM   = 19,
+    AFORMAT_APE   = 20,
+    AFORMAT_EAC3   = 21,
+    AFORMAT_PCM_WIFIDISPLAY = 22,
+    AFORMAT_DRA    = 23,
+    AFORMAT_UNSUPPORT = 24,
+    AFORMAT_MAX    = 25
+};
+
+#endif /* AFORMAT_H */
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/amstream.h b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/amstream.h
new file mode 100644
index 0000000..d607224
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/amstream.h
@@ -0,0 +1,954 @@
+/*
+ * include/linux/amlogic/media/utils/amstream.h
+ *
+ * Copyright (C) 2016 Amlogic, Inc. 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.
+ *
+*/
+#ifndef AMSTREAM_H
+#define AMSTREAM_H
+
+/* #include <linux/interrupt.h> */
+//#include <linux/amlogic/media/utils/vformat.h>
+//#include <linux/amlogic/media/utils/aformat.h>
+#include <amports/vformat.h>
+#include <amports/aformat.h>
+#define u32 unsigned int
+#define u64 unsigned int
+#define u16 unsigned short
+#define bool int
+
+#ifdef __KERNEL__
+#define PORT_FLAG_IN_USE    0x0001
+#define PORT_FLAG_VFORMAT   0x0002
+#define PORT_FLAG_AFORMAT   0x0004
+#define PORT_FLAG_FORMAT    (PORT_FLAG_VFORMAT | PORT_FLAG_AFORMAT)
+#define PORT_FLAG_VID       0x0008
+#define PORT_FLAG_AID       0x0010
+#define PORT_FLAG_SID       0x0020
+#define PORT_FLAG_UD        0x0040
+#define PORT_FLAG_DRM       0x0080
+#define PORT_FLAG_ID        (PORT_FLAG_VID | \
+		PORT_FLAG_AID | PORT_FLAG_SID | PORT_FLAG_UD)
+#define PORT_FLAG_INITED    0x100
+
+#define PORT_TYPE_VIDEO         0x01
+#define PORT_TYPE_AUDIO         0x02
+#define PORT_TYPE_MPTS          0x04
+#define PORT_TYPE_MPPS          0x08
+#define PORT_TYPE_ES            0x10
+#define PORT_TYPE_RM            0x20
+#define PORT_TYPE_SUB           0x40
+#define PORT_TYPE_SUB_RD        0x80
+#define PORT_TYPE_HEVC          0x100
+#define PORT_TYPE_USERDATA      0x200
+#define PORT_TYPE_FRAME         0x400
+#define PORT_TYPE_DECODER_SCHED 0x800
+#define PORT_TYPE_DUALDEC       0x1000
+#endif
+
+#define _A_M  'S'
+#define AMSTREAM_IOC_VB_START   _IOW((_A_M), 0x00, int)
+#define AMSTREAM_IOC_VB_SIZE    _IOW((_A_M), 0x01, int)
+#define AMSTREAM_IOC_AB_START   _IOW((_A_M), 0x02, int)
+#define AMSTREAM_IOC_AB_SIZE    _IOW((_A_M), 0x03, int)
+#define AMSTREAM_IOC_VFORMAT    _IOW((_A_M), 0x04, int)
+#define AMSTREAM_IOC_AFORMAT    _IOW((_A_M), 0x05, int)
+#define AMSTREAM_IOC_VID        _IOW((_A_M), 0x06, int)
+#define AMSTREAM_IOC_AID        _IOW((_A_M), 0x07, int)
+#define AMSTREAM_IOC_VB_STATUS  _IOR((_A_M), 0x08, int)
+#define AMSTREAM_IOC_AB_STATUS  _IOR((_A_M), 0x09, int)
+#define AMSTREAM_IOC_SYSINFO    _IOW((_A_M), 0x0a, int)
+#define AMSTREAM_IOC_ACHANNEL   _IOW((_A_M), 0x0b, int)
+#define AMSTREAM_IOC_SAMPLERATE _IOW((_A_M), 0x0c, int)
+#define AMSTREAM_IOC_DATAWIDTH  _IOW((_A_M), 0x0d, int)
+#define AMSTREAM_IOC_TSTAMP     _IOW((_A_M), 0x0e, int)
+#define AMSTREAM_IOC_VDECSTAT   _IOR((_A_M), 0x0f, int)
+#define AMSTREAM_IOC_ADECSTAT   _IOR((_A_M), 0x10, int)
+
+#define AMSTREAM_IOC_PORT_INIT   _IO((_A_M), 0x11)
+#define AMSTREAM_IOC_TRICKMODE  _IOW((_A_M), 0x12, int)
+
+#define AMSTREAM_IOC_AUDIO_INFO	_IOW((_A_M), 0x13, int)
+#define AMSTREAM_IOC_TRICK_STAT  _IOR((_A_M), 0x14, int)
+#define AMSTREAM_IOC_AUDIO_RESET _IO((_A_M), 0x15)
+#define AMSTREAM_IOC_SID         _IOW((_A_M), 0x16, int)
+#define AMSTREAM_IOC_VPAUSE      _IOW((_A_M), 0x17, int)
+#define AMSTREAM_IOC_AVTHRESH   _IOW((_A_M), 0x18, int)
+#define AMSTREAM_IOC_SYNCTHRESH _IOW((_A_M), 0x19, int)
+#define AMSTREAM_IOC_SUB_RESET   _IOW((_A_M), 0x1a, int)
+#define AMSTREAM_IOC_SUB_LENGTH  _IOR((_A_M), 0x1b, int)
+#define AMSTREAM_IOC_SET_DEC_RESET _IOW((_A_M), 0x1c, int)
+#define AMSTREAM_IOC_TS_SKIPBYTE _IOW((_A_M), 0x1d, int)
+#define AMSTREAM_IOC_SUB_TYPE    _IOW((_A_M), 0x1e, int)
+#define AMSTREAM_IOC_CLEAR_VIDEO _IOW((_A_M), 0x1f, int)
+
+#define AMSTREAM_IOC_VDECINFO _IOR((_A_M), 0x20, int)
+#define AMSTREAM_IOC_GLOBAL_GET_VIDEO_OUTPUT  _IOR((_A_M), 0x21, int)
+#define AMSTREAM_IOC_GLOBAL_SET_VIDEO_OUTPUT  _IOW((_A_M), 0x22, int)
+#define AMSTREAM_IOC_GET_VIDEO_LAYER1_ON  _IOR((_A_M), 0x23, int)
+/*video pip IOCTL command list*/
+#define AMSTREAM_IOC_CLEAR_VIDEOPIP _IOW((_A_M), 0x24, int)
+#define AMSTREAM_IOC_CLEAR_PIP_VBUF _IO((_A_M), 0x25)
+
+#define AMSTREAM_IOC_GET_DISPLAYPATH  _IOW((_A_M), 0x26, int)
+#define AMSTREAM_IOC_SET_DISPLAYPATH  _IOW((_A_M), 0x27, int)
+
+#define AMSTREAM_IOC_GET_PIP_DISPLAYPATH  _IOW((_A_M), 0x28, int)
+#define AMSTREAM_IOC_SET_PIP_DISPLAYPATH  _IOW((_A_M), 0x29, int)
+
+#define AMSTREAM_IOC_GLOBAL_GET_VIDEOPIP_OUTPUT  _IOR((_A_M), 0x2b, int)
+#define AMSTREAM_IOC_GLOBAL_SET_VIDEOPIP_OUTPUT  _IOW((_A_M), 0x2c, int)
+#define AMSTREAM_IOC_GET_VIDEOPIP_DISABLE  _IOR((_A_M), 0x2d, int)
+#define AMSTREAM_IOC_SET_VIDEOPIP_DISABLE  _IOW((_A_M), 0x2e, int)
+#define AMSTREAM_IOC_GET_VIDEOPIP_AXIS   _IOR((_A_M), 0x2f, int)
+#define AMSTREAM_IOC_SET_VIDEOPIP_AXIS   _IOW((_A_M), 0x30, int)
+#define AMSTREAM_IOC_GET_VIDEOPIP_CROP   _IOR((_A_M), 0x31, int)
+#define AMSTREAM_IOC_SET_VIDEOPIP_CROP   _IOW((_A_M), 0x32, int)
+#define AMSTREAM_IOC_GET_PIP_SCREEN_MODE _IOR((_A_M), 0x33, int)
+#define AMSTREAM_IOC_SET_PIP_SCREEN_MODE _IOW((_A_M), 0x34, int)
+#define AMSTREAM_IOC_GET_PIP_ZORDER  _IOW((_A_M), 0x35, unsigned int)
+#define AMSTREAM_IOC_SET_PIP_ZORDER  _IOW((_A_M), 0x36, unsigned int)
+
+#define AMSTREAM_IOC_GET_ZORDER  _IOW((_A_M), 0x37, unsigned int)
+#define AMSTREAM_IOC_SET_ZORDER  _IOW((_A_M), 0x38, unsigned int)
+
+#define AMSTREAM_IOC_QUERY_LAYER  _IOW((_A_M), 0x39, unsigned int)
+#define AMSTREAM_IOC_ALLOC_LAYER  _IOW((_A_M), 0x3a, unsigned int)
+#define AMSTREAM_IOC_FREE_LAYER  _IOW((_A_M), 0x3b, unsigned int)
+
+/* VPP.3D IOCTL command list^M */
+#define  AMSTREAM_IOC_SET_3D_TYPE  _IOW((_A_M), 0x3c, unsigned int)
+#define  AMSTREAM_IOC_GET_3D_TYPE  _IOW((_A_M), 0x3d, unsigned int)
+#define  AMSTREAM_IOC_GET_SOURCE_VIDEO_3D_TYPE  _IOW((_A_M), 0x3e, unsigned int)
+
+#define AMSTREAM_IOC_APTS             _IOR((_A_M), 0x40, int)
+#define AMSTREAM_IOC_VPTS             _IOR((_A_M), 0x41, int)
+#define AMSTREAM_IOC_PCRSCR           _IOR((_A_M), 0x42, int)
+#define AMSTREAM_IOC_SYNCENABLE      _IOW((_A_M), 0x43, int)
+#define AMSTREAM_IOC_GET_SYNC_ADISCON  _IOR((_A_M), 0x44, int)
+#define AMSTREAM_IOC_SET_SYNC_ADISCON  _IOW((_A_M), 0x45, int)
+#define AMSTREAM_IOC_GET_SYNC_VDISCON  _IOR((_A_M), 0x46, int)
+#define AMSTREAM_IOC_SET_SYNC_VDISCON  _IOW((_A_M), 0x47, int)
+#define AMSTREAM_IOC_GET_VIDEO_DISABLE  _IOR((_A_M), 0x48, int)
+#define AMSTREAM_IOC_SET_VIDEO_DISABLE  _IOW((_A_M), 0x49, int)
+#define AMSTREAM_IOC_SET_PCRSCR       _IOW((_A_M), 0x4a, int)
+#define AMSTREAM_IOC_GET_VIDEO_AXIS   _IOR((_A_M), 0x4b, int)
+#define AMSTREAM_IOC_SET_VIDEO_AXIS   _IOW((_A_M), 0x4c, int)
+#define AMSTREAM_IOC_GET_VIDEO_CROP   _IOR((_A_M), 0x4d, int)
+#define AMSTREAM_IOC_SET_VIDEO_CROP   _IOW((_A_M), 0x4e, int)
+#define AMSTREAM_IOC_PCRID        _IOW((_A_M), 0x4f, int)
+
+#define AMSTREAM_IOC_SUB_NUM	_IOR((_A_M), 0x50, int)
+#define AMSTREAM_IOC_SUB_INFO	_IOR((_A_M), 0x51, int)
+#define AMSTREAM_IOC_GET_BLACKOUT_POLICY   _IOR((_A_M), 0x52, int)
+#define AMSTREAM_IOC_SET_BLACKOUT_POLICY   _IOW((_A_M), 0x53, int)
+#define AMSTREAM_IOC_UD_LENGTH _IOR((_A_M), 0x54, int)
+#define AMSTREAM_IOC_UD_POC _IOR((_A_M), 0x55, int)
+#define AMSTREAM_IOC_UD_FLUSH_USERDATA _IOR((_A_M), 0x56, int)
+
+#define AMSTREAM_IOC_UD_BUF_READ _IOR((_A_M), 0x57, int)
+
+#define AMSTREAM_IOC_GET_SCREEN_MODE _IOR((_A_M), 0x58, int)
+#define AMSTREAM_IOC_SET_SCREEN_MODE _IOW((_A_M), 0x59, int)
+#define AMSTREAM_IOC_GET_VIDEO_DISCONTINUE_REPORT _IOR((_A_M), 0x5a, int)
+#define AMSTREAM_IOC_SET_VIDEO_DISCONTINUE_REPORT _IOW((_A_M), 0x5b, int)
+
+#define AMSTREAM_IOC_UD_AVAILABLE_VDEC      _IOR((_A_M), 0x5c, unsigned int)
+#define AMSTREAM_IOC_GET_VDEC_ID			_IOR((_A_M), 0x5d, int)
+
+/*
+ * #define AMSTREAM_IOC_UD_BUF_STATUS _IOR((_A_M),
+ * 0x5c, struct userdata_buf_state_t)
+ */
+
+#define AMSTREAM_IOC_VF_STATUS  _IOR((_A_M), 0x60, int)
+
+#define AMSTREAM_IOC_GET_BLACKOUT_PIP_POLICY   _IOR((_A_M), 0x62, int)
+#define AMSTREAM_IOC_SET_BLACKOUT_PIP_POLICY   _IOW((_A_M), 0x63, int)
+
+#define AMSTREAM_IOC_CLEAR_VBUF _IO((_A_M), 0x80)
+
+#define AMSTREAM_IOC_APTS_LOOKUP    _IOR((_A_M), 0x81, int)
+#define GET_FIRST_APTS_FLAG    _IOR((_A_M), 0x82, int)
+#define AMSTREAM_IOC_GET_SYNC_ADISCON_DIFF  _IOR((_A_M), 0x83, int)
+#define AMSTREAM_IOC_GET_SYNC_VDISCON_DIFF  _IOR((_A_M), 0x84, int)
+#define AMSTREAM_IOC_SET_SYNC_ADISCON_DIFF  _IOW((_A_M), 0x85, int)
+#define AMSTREAM_IOC_SET_SYNC_VDISCON_DIFF  _IOW((_A_M), 0x86, int)
+#define AMSTREAM_IOC_GET_FREERUN_MODE  _IOR((_A_M), 0x87, int)
+#define AMSTREAM_IOC_SET_FREERUN_MODE  _IOW((_A_M), 0x88, int)
+#define AMSTREAM_IOC_SET_VSYNC_UPINT   _IOW((_A_M), 0x89, int)
+#define AMSTREAM_IOC_GET_VSYNC_SLOW_FACTOR   _IOW((_A_M), 0x8a, int)
+#define AMSTREAM_IOC_SET_VSYNC_SLOW_FACTOR   _IOW((_A_M), 0x8b, int)
+#define AMSTREAM_IOC_GET_FIRST_FRAME_LATENCY _IOR((_A_M), 0x8c, int)
+#define AMSTREAM_IOC_CLEAR_FIRST_FRAME_LATENCY _IOR((_A_M), 0x8d, int)
+#define AMSTREAM_IOC_SET_DEMUX  _IOW((_A_M), 0x90, int)
+#define AMSTREAM_IOC_SET_DRMMODE _IOW((_A_M), 0x91, int)
+#define AMSTREAM_IOC_TSTAMP_uS64 _IOW((_A_M), 0x95, int)
+
+#define AMSTREAM_IOC_SET_VIDEO_DELAY_LIMIT_MS _IOW((_A_M), 0xa0, int)
+#define AMSTREAM_IOC_GET_VIDEO_DELAY_LIMIT_MS _IOR((_A_M), 0xa1, int)
+#define AMSTREAM_IOC_SET_AUDIO_DELAY_LIMIT_MS _IOW((_A_M), 0xa2, int)
+#define AMSTREAM_IOC_GET_AUDIO_DELAY_LIMIT_MS _IOR((_A_M), 0xa3, int)
+#define AMSTREAM_IOC_GET_AUDIO_CUR_DELAY_MS _IOR((_A_M), 0xa4, int)
+#define AMSTREAM_IOC_GET_VIDEO_CUR_DELAY_MS _IOR((_A_M), 0xa5, int)
+#define AMSTREAM_IOC_GET_AUDIO_AVG_BITRATE_BPS _IOR((_A_M), 0xa6, int)
+#define AMSTREAM_IOC_GET_VIDEO_AVG_BITRATE_BPS _IOR((_A_M), 0xa7, int)
+#define AMSTREAM_IOC_SET_APTS  _IOW((_A_M), 0xa8, int)
+#define AMSTREAM_IOC_GET_LAST_CHECKIN_APTS _IOR((_A_M), 0xa9, int)
+#define AMSTREAM_IOC_GET_LAST_CHECKIN_VPTS _IOR((_A_M), 0xaa, int)
+#define AMSTREAM_IOC_GET_LAST_CHECKOUT_APTS _IOR((_A_M), 0xab, int)
+#define AMSTREAM_IOC_GET_LAST_CHECKOUT_VPTS _IOR((_A_M), 0xac, int)
+
+/* subtitle.c get/set subtitle info */
+#define AMSTREAM_IOC_GET_SUBTITLE_INFO _IOR((_A_M), 0xad, int)
+#define AMSTREAM_IOC_SET_SUBTITLE_INFO _IOW((_A_M), 0xae, int)
+#define AMSTREAM_IOC_SET_OMX_VPTS _IOW((_A_M), 0xaf, int)
+#define AMSTREAM_IOC_GET_OMX_VPTS _IOW((_A_M), 0xb0, int)
+#define AMSTREAM_IOC_GET_OMX_VERSION _IOW((_A_M), 0xb1, int)
+#define AMSTREAM_IOC_GET_OMX_INFO    _IOR((_A_M), 0xb2, unsigned int)
+#define AMSTREAM_IOC_SET_HDR_INFO    _IOW((_A_M), 0xb3, int)
+#define AMSTREAM_IOC_GET_VIDEO_LATENCY _IOW((_A_M), 0xb4, int)
+#define AMSTREAM_IOC_SET_TUNNEL_MODE _IOR(_A_M, 0xbd, unsigned int)
+#define AMSTREAM_IOC_GET_FIRST_FRAME_TOGGLED _IOR(_A_M, 0xbe, unsigned int)
+#define AMSTREAM_IOC_SET_VIDEOPEEK   _IOW(_A_M, 0xbf, unsigned int)
+#define AMSTREAM_IOC_SET_NO_VIDEO_STOP _IOW(_A_M, 0xf5, unsigned int)
+
+#define AMSTREAM_IOC_GET_TRICK_VPTS _IOR((_A_M), 0xf0, int)
+#define AMSTREAM_IOC_DISABLE_SLOW_SYNC _IOW((_A_M), 0xf1, int)
+
+#define AMSTREAM_IOC_GET_AUDIO_CHECKIN_BITRATE_BPS _IOR((_A_M), 0xf2, int)
+#define AMSTREAM_IOC_GET_VIDEO_CHECKIN_BITRATE_BPS _IOR((_A_M), 0xf3, int)
+#define AMSTREAM_IOC_VDEC_RESET _IO((_A_M), 0xf4)
+#define AMSTREAM_IOC_GET_VERSION _IOR((_A_M), 0xc0, int)
+#define AMSTREAM_IOC_GET _IOWR((_A_M), 0xc1, struct am_ioctl_parm)
+#define AMSTREAM_IOC_SET _IOW((_A_M), 0xc2, struct am_ioctl_parm)
+#define AMSTREAM_IOC_GET_EX _IOWR((_A_M), 0xc3, struct am_ioctl_parm_ex)
+#define AMSTREAM_IOC_SET_EX _IOW((_A_M), 0xc4, struct am_ioctl_parm_ex)
+#define AMSTREAM_IOC_GET_PTR _IOWR((_A_M), 0xc5, struct am_ioctl_parm_ptr)
+#define AMSTREAM_IOC_SET_PTR _IOW((_A_M), 0xc6, struct am_ioctl_parm_ptr)
+#define AMSTREAM_IOC_GET_AVINFO _IOR((_A_M), 0xc7, struct av_param_info_t)
+#define AMSTREAM_IOC_GET_QOSINFO _IOR((_A_M), 0xc8, struct av_param_qosinfo_t)
+#define AMSTREAM_IOC_SET_CRC _IOW((_A_M), 0xc9, struct usr_crc_info_t)
+#define AMSTREAM_IOC_GET_CRC_CMP_RESULT _IOWR((_A_M), 0xca, int)
+#define AMSTREAM_IOC_GET_MVDECINFO _IOR((_A_M), 0xcb, int)
+#define AMSTREAM_IOC_SET_SPEED_MULT _IOW((_A_M), 0xcd, int)
+#define AMSTREAM_IOC_GET_SPEED_MULT _IOR((_A_M), 0xce, int)
+
+
+#define TRICKMODE_NONE       0x00
+#define TRICKMODE_I          0x01
+#define TRICKMODE_FFFB       0x02
+
+#define TRICK_STAT_DONE     0x01
+#define TRICK_STAT_WAIT     0x00
+
+#define AUDIO_EXTRA_DATA_SIZE   (4096)
+#define MAX_SUB_NUM		32
+
+enum VIDEO_DEC_TYPE {
+	VIDEO_DEC_FORMAT_UNKNOWN,
+	VIDEO_DEC_FORMAT_MPEG4_3,
+
+	VIDEO_DEC_FORMAT_MPEG4_4,
+	VIDEO_DEC_FORMAT_MPEG4_5,
+
+	VIDEO_DEC_FORMAT_H264,
+
+	VIDEO_DEC_FORMAT_MJPEG,
+	VIDEO_DEC_FORMAT_MP4,
+	VIDEO_DEC_FORMAT_H263,
+
+	VIDEO_DEC_FORMAT_REAL_8,
+	VIDEO_DEC_FORMAT_REAL_9,
+
+	VIDEO_DEC_FORMAT_WMV3,
+
+	VIDEO_DEC_FORMAT_WVC1,
+	VIDEO_DEC_FORMAT_SW,
+        VIDEO_DEC_FORMAT_AVS,
+        VIDEO_DEC_FORMAT_H264_4K2K,
+        VIDEO_DEC_FORMAT_HEVC,
+	VIDEO_DEC_FORMAT_MAX
+};
+
+enum FRAME_BASE_VIDEO_PATH {
+	FRAME_BASE_PATH_IONVIDEO = 0,
+	FRAME_BASE_PATH_AMLVIDEO_AMVIDEO,
+	FRAME_BASE_PATH_AMLVIDEO1_AMVIDEO2,
+	FRAME_BASE_PATH_DI_AMVIDEO,
+	FRAME_BASE_PATH_AMVIDEO,
+	FRAME_BASE_PATH_AMVIDEO2,
+	FRAME_BASE_PATH_V4L_VIDEO,
+	FRAME_BASE_PATH_TUNNEL_MODE,
+	FRAME_BASE_PATH_V4L_OSD,
+	FRAME_BASE_PATH_DI_V4LVIDEO,
+	FRAME_BASE_PATH_PIP_TUNNEL_MODE,
+	FRAME_BASE_PATH_V4LVIDEO,
+	FRAME_BASE_PATH_DTV_TUNNEL_MODE,
+	FRAME_BASE_PATH_AMLVIDEO_FENCE,
+	FRAME_BASE_PATH_MAX
+};
+
+struct buf_status {
+
+	int size;
+
+	int data_len;
+
+	int free_len;
+
+	unsigned int read_pointer;
+
+	unsigned int write_pointer;
+};
+
+/*struct vdec_status.status*/
+#define STAT_TIMER_INIT     0x01
+#define STAT_MC_LOAD        0x02
+#define STAT_ISR_REG        0x04
+#define STAT_VF_HOOK        0x08
+#define STAT_TIMER_ARM      0x10
+#define STAT_VDEC_RUN       0x20
+
+/*struct vdec_status.status on error*/
+
+#define PARSER_FATAL_ERROR              (0x10<<16)
+#define DECODER_ERROR_VLC_DECODE_TBL    (0x20<<16)
+#define PARSER_ERROR_WRONG_HEAD_VER     (0x40<<16)
+#define PARSER_ERROR_WRONG_PACKAGE_SIZE (0x80<<16)
+#define DECODER_FATAL_ERROR_SIZE_OVERFLOW     (0x100<<16)
+#define DECODER_FATAL_ERROR_UNKNOWN             (0x200<<16)
+#define DECODER_FATAL_ERROR_NO_MEM		(0x400<<16)
+
+#define DECODER_ERROR_MASK	(0xffff<<16)
+/* The total slot number for fifo_buf */
+#define NUM_FRAME_VDEC  128  //This must be 2^n
+#define QOS_FRAME_NUM 8
+
+
+enum E_ASPECT_RATIO {
+	ASPECT_RATIO_4_3,
+	ASPECT_RATIO_16_9,
+	ASPECT_UNDEFINED = 255
+};
+
+struct vdec_status {
+	unsigned int width;
+	unsigned int height;
+	unsigned int fps;
+	unsigned int error_count;
+	unsigned int status;
+	enum E_ASPECT_RATIO euAspectRatio;
+};
+
+struct vdec_info {
+	char vdec_name[16];
+	u32 ver;
+	u32 frame_width;
+	u32 frame_height;
+	u32 frame_rate;
+	union {
+		u32 bit_rate;
+		/* Effective in h265,vp9,avs2 multi-instance */
+		u32 bit_depth_luma;
+	};
+	u32 frame_dur;
+	union {
+		u32 frame_data;
+		/* Effective in h265,vp9,avs2 multi-instance */
+		u32 bit_depth_chroma;
+	};
+	u32 error_count;
+	u32 status;
+	u32 frame_count;
+	u32 error_frame_count;
+	u32 drop_frame_count;
+	u64 total_data;
+	union {
+		u32 samp_cnt;
+		/* Effective in h265,vp9,avs2 multi-instance */
+		u32 double_write_mode;
+	};
+	u32 offset;
+	u32 ratio_control;
+	char reserved[0];
+	unsigned int i_decoded_frames;/*i frames decoded*/
+	unsigned int i_lost_frames;/*i frames can not be decoded*/
+	unsigned int i_concealed_frames;/*i frames decoded but have some error*/
+	unsigned int p_decoded_frames;
+	unsigned int p_lost_frames;
+	unsigned int p_concealed_frames;
+	unsigned int b_decoded_frames;
+	unsigned int b_lost_frames;
+	unsigned int b_concealed_frames;
+	char endipb_line[0];
+};
+
+struct adec_status {
+	unsigned int channels;
+	unsigned int sample_rate;
+	unsigned int resolution;
+	unsigned int error_count;
+	unsigned int status;
+};
+
+struct am_io_param {
+	union {
+		int data;
+		int id;		/* get bufstatus? or others */
+	};
+	int len;		/* buffer size; */
+
+	union {
+
+		char buf[1];
+
+		struct buf_status status;
+
+		struct vdec_status vstatus;
+		struct adec_status astatus;
+	};
+};
+
+struct am_io_info {
+	union {
+		int data;
+		int id;
+	};
+	int len;
+	union {
+		char buf[1];
+		struct vdec_info vinfo;
+	};
+};
+
+struct audio_info {
+
+	int valid;
+
+	int sample_rate;
+
+	int channels;
+
+	int bitrate;
+
+	int codec_id;
+
+	int block_align;
+
+	int extradata_size;
+
+	char extradata[AUDIO_EXTRA_DATA_SIZE];
+};
+
+struct dec_sysinfo {
+
+	unsigned int format;
+
+	unsigned int width;
+
+	unsigned int height;
+
+	unsigned int rate;
+
+	unsigned int extra;
+
+	unsigned int status;
+
+	unsigned int ratio;
+
+	void *param;
+
+	unsigned long long ratio64;
+};
+
+struct subtitle_info {
+
+	unsigned char id;
+
+	unsigned char width;
+
+	unsigned char height;
+
+	unsigned char type;
+};
+
+struct codec_profile_t {
+
+	char *name;		/* video codec short name */
+	char *profile;		/* Attributes,separated by commas */
+};
+
+struct userdata_poc_info_t {
+
+	unsigned int poc_info;
+	unsigned int poc_number;
+	/*
+	 * bit 0:
+	 *	1, group start
+	 *	0, not group start
+	 * bit 1-2:
+	 *	0, extension_and_user_data( 0 )
+	 *	1, extension_and_user_data( 1 )
+	 *	2, extension_and_user_data( 2 )
+	 */
+	unsigned int flags;
+	unsigned int vpts;
+	unsigned int vpts_valid;
+	unsigned int duration;
+};
+
+struct userdata_meta_info_t {
+	uint32_t poc_number;
+	/************ flags bit defination ***********/
+	/*
+	 * bit 0:		//used for mpeg2
+	 *	1, group start
+	 *	0, not group start
+	 * bit 1-2:	//used for mpeg2
+	 *	0, extension_and_user_data( 0 )
+	 *	1, extension_and_user_data( 1 )
+	 *	2, extension_and_user_data( 2 )
+	 * bit 3-6:	//video format
+	 *	0,	VFORMAT_MPEG12
+	 *	1,	VFORMAT_MPEG4
+	 *	2,	VFORMAT_H264
+	 *	3,	VFORMAT_MJPEG
+	 *	4,	VFORMAT_REAL
+	 *	5,	VFORMAT_JPEG
+	 *	6,	VFORMAT_VC1
+	 *	7,	VFORMAT_AVS
+	 *	8,	VFORMAT_SW
+	 *	9,	VFORMAT_H264MVC
+	 *	10, VFORMAT_H264_4K2K
+	 *	11, VFORMAT_HEVC
+	 *	12, VFORMAT_H264_ENC
+	 *	13, VFORMAT_JPEG_ENC
+	 *	14, VFORMAT_VP9
+	 * bit 7-9:	//frame type
+	 *	0, Unknown Frame Type
+	 *	1, I Frame
+	 *	2, B Frame
+	 *	3, P Frame
+	 *	4, D_Type_MPEG2
+	 * bit 10:  //top_field_first_flag valid
+	 *	0: top_field_first_flag is not valid
+	 *	1: top_field_first_flag is valid
+	 * bit 11: //top_field_first bit val
+	 */
+	uint32_t flags;
+	uint32_t vpts;			/*video frame pts*/
+	/*
+	 * 0: pts is invalid, please use duration to calcuate
+	 * 1: pts is valid
+	 */
+	uint32_t vpts_valid;
+	/*duration for frame*/
+	uint32_t duration;
+	/* how many records left in queue waiting to be read*/
+	uint32_t records_in_que;
+	unsigned long long priv_data;
+	uint32_t padding_data[4];
+};
+
+struct userdata_param_t {
+	uint32_t version;
+	uint32_t instance_id; /*input, 0~9*/
+	uint32_t buf_len; /*input*/
+	uint32_t data_size; /*output*/
+	void *pbuf_addr; /*input*/
+	struct userdata_meta_info_t meta_info; /*output*/
+};
+
+struct usr_crc_info_t {
+	u32 id;
+	u32 pic_num;
+	u32 y_crc;
+	u32 uv_crc;
+};
+
+/*******************************************************************
+* 0x100~~0x1FF : set cmd
+* 0x200~~0x2FF : set ex cmd
+* 0x300~~0x3FF : set ptr cmd
+* 0x400~~0x7FF : set reserved cmd
+* 0x800~~0x8FF : get cmd
+* 0x900~~0x9FF : get ex cmd
+* 0xA00~~0xAFF : get ptr cmd
+* 0xBFF~~0xFFF : get reserved cmd
+* 0xX00~~0xX5F : amstream cmd(X: cmd type)
+* 0xX60~~0xXAF : video cmd(X: cmd type)
+* 0xXAF~~0xXFF : reserved cmd(X: cmd type)
+******************************************************************
+*/
+
+/*  amstream set cmd */
+#define AMSTREAM_SET_VB_START 0x101
+#define AMSTREAM_SET_VB_SIZE 0x102
+#define AMSTREAM_SET_AB_START 0x103
+#define AMSTREAM_SET_AB_SIZE 0x104
+#define AMSTREAM_SET_VFORMAT 0x105
+#define AMSTREAM_SET_AFORMAT 0x106
+#define AMSTREAM_SET_VID 0x107
+#define AMSTREAM_SET_AID 0x108
+#define AMSTREAM_SET_SID 0x109
+#define AMSTREAM_SET_PCRID 0x10A
+#define AMSTREAM_SET_ACHANNEL 0x10B
+#define AMSTREAM_SET_SAMPLERATE 0x10C
+#define AMSTREAM_SET_DATAWIDTH 0x10D
+#define AMSTREAM_SET_TSTAMP 0x10E
+#define AMSTREAM_SET_TSTAMP_US64 0x10F
+#define AMSTREAM_SET_APTS 0x110
+#define AMSTREAM_PORT_INIT 0x111
+#define AMSTREAM_SET_TRICKMODE 0x112	/* amstream,video */
+#define AMSTREAM_AUDIO_RESET 0x013
+#define AMSTREAM_SUB_RESET 0x114
+#define AMSTREAM_DEC_RESET 0x115
+#define AMSTREAM_SET_TS_SKIPBYTE 0x116
+#define AMSTREAM_SET_SUB_TYPE 0x117
+#define AMSTREAM_SET_PCRSCR 0x118
+#define AMSTREAM_SET_DEMUX 0x119
+#define AMSTREAM_SET_VIDEO_DELAY_LIMIT_MS 0x11A
+#define AMSTREAM_SET_AUDIO_DELAY_LIMIT_MS 0x11B
+#define AMSTREAM_SET_DRMMODE 0x11C
+
+/*  video set   cmd */
+#define AMSTREAM_SET_OMX_VPTS 0x160
+#define AMSTREAM_SET_VPAUSE 0x161
+#define AMSTREAM_SET_AVTHRESH 0x162
+#define AMSTREAM_SET_SYNCTHRESH 0x163
+#define AMSTREAM_SET_SYNCENABLE 0x164
+#define AMSTREAM_SET_SYNC_ADISCON 0x165
+#define AMSTREAM_SET_SYNC_VDISCON 0x166
+#define AMSTREAM_SET_SYNC_ADISCON_DIFF 0x167
+#define AMSTREAM_SET_SYNC_VDISCON_DIFF 0x168
+#define AMSTREAM_SET_VIDEO_DISABLE 0x169
+#define AMSTREAM_SET_VIDEO_DISCONTINUE_REPORT 0x16A
+#define AMSTREAM_SET_SCREEN_MODE 0x16B
+#define AMSTREAM_SET_BLACKOUT_POLICY 0x16C
+#define AMSTREAM_CLEAR_VBUF 0x16D
+#define AMSTREAM_SET_CLEAR_VIDEO 0x16E
+#define AMSTREAM_SET_FREERUN_MODE 0x16F
+#define AMSTREAM_SET_DISABLE_SLOW_SYNC 0x170
+#define AMSTREAM_SET_3D_TYPE 0x171
+#define AMSTREAM_SET_VSYNC_UPINT 0x172
+#define AMSTREAM_SET_VSYNC_SLOW_FACTOR 0x173
+#define AMSTREAM_SET_FRAME_BASE_PATH 0x174
+#define AMSTREAM_SET_EOS 0x175
+#define AMSTREAM_SET_RECEIVE_ID 0x176
+#define AMSTREAM_SET_IS_RESET 0x177
+#define AMSTREAM_SET_NO_POWERDOWN   0x178
+#define AMSTREAM_SET_DV_META_WITH_EL 0x179
+
+
+/*  video set ex cmd */
+#define AMSTREAM_SET_EX_VIDEO_AXIS 0x260
+#define AMSTREAM_SET_EX_VIDEO_CROP 0x261
+
+/*  amstream set ptr cmd */
+#define AMSTREAM_SET_PTR_AUDIO_INFO 0x300
+#define AMSTREAM_SET_PTR_CONFIGS 0x301
+
+/*  amstream get cmd */
+#define AMSTREAM_GET_SUB_LENGTH 0x800
+#define AMSTREAM_GET_UD_LENGTH 0x801
+#define AMSTREAM_GET_APTS_LOOKUP 0x802
+#define AMSTREAM_GET_FIRST_APTS_FLAG 0x803
+#define AMSTREAM_GET_APTS 0x804
+#define AMSTREAM_GET_VPTS 0x805
+#define AMSTREAM_GET_PCRSCR 0x806
+#define AMSTREAM_GET_LAST_CHECKIN_APTS 0x807
+#define AMSTREAM_GET_LAST_CHECKIN_VPTS 0x808
+#define AMSTREAM_GET_LAST_CHECKOUT_APTS 0x809
+#define AMSTREAM_GET_LAST_CHECKOUT_VPTS 0x80A
+#define AMSTREAM_GET_SUB_NUM 0x80B
+#define AMSTREAM_GET_VIDEO_DELAY_LIMIT_MS 0x80C
+#define AMSTREAM_GET_AUDIO_DELAY_LIMIT_MS 0x80D
+#define AMSTREAM_GET_AUDIO_CUR_DELAY_MS 0x80E
+#define AMSTREAM_GET_VIDEO_CUR_DELAY_MS 0x80F
+#define AMSTREAM_GET_AUDIO_AVG_BITRATE_BPS 0x810
+#define AMSTREAM_GET_VIDEO_AVG_BITRATE_BPS 0x811
+#define AMSTREAM_GET_ION_ID 0x812
+#define AMSTREAM_GET_NEED_MORE_DATA 0x813
+#define AMSTREAM_GET_FREED_HANDLE 0x814
+/*  video get cmd */
+#define AMSTREAM_GET_OMX_VPTS 0x860
+#define AMSTREAM_GET_TRICK_STAT 0x861
+#define AMSTREAM_GET_TRICK_VPTS 0x862
+#define AMSTREAM_GET_SYNC_ADISCON 0x863
+#define AMSTREAM_GET_SYNC_VDISCON 0x864
+#define AMSTREAM_GET_SYNC_ADISCON_DIFF 0x865
+#define AMSTREAM_GET_SYNC_VDISCON_DIFF 0x866
+#define AMSTREAM_GET_VIDEO_DISABLE 0x867
+#define AMSTREAM_GET_VIDEO_DISCONTINUE_REPORT 0x868
+#define AMSTREAM_GET_SCREEN_MODE 0x869
+#define AMSTREAM_GET_BLACKOUT_POLICY 0x86A
+#define AMSTREAM_GET_FREERUN_MODE 0x86B
+#define AMSTREAM_GET_3D_TYPE 0x86C
+#define AMSTREAM_GET_VSYNC_SLOW_FACTOR 0x86D
+
+/*  amstream get ex cmd */
+#define AMSTREAM_GET_EX_VB_STATUS 0x900
+#define AMSTREAM_GET_EX_AB_STATUS 0x901
+#define AMSTREAM_GET_EX_VDECSTAT 0x902
+#define AMSTREAM_GET_EX_ADECSTAT 0x903
+#define AMSTREAM_GET_EX_UD_POC 0x904
+#define AMSTREAM_GET_EX_SB_STATUS 0x906
+/*  video get ex cmd */
+#define AMSTREAM_GET_EX_VF_STATUS 0x960
+#define AMSTREAM_GET_EX_VIDEO_AXIS 0x961
+#define AMSTREAM_GET_EX_VIDEO_CROP 0x962
+
+/*  amstream get ptr cmd */
+#define AMSTREAM_GET_PTR_SUB_INFO 0xA00
+
+#define AMSTREAM_IOC_VERSION_FIRST 2
+#define AMSTREAM_IOC_VERSION_SECOND 0
+
+struct am_ioctl_parm {
+	union {
+		u32 data_32;
+		u64 data_64;
+		enum vformat_e data_vformat;
+		enum aformat_e data_aformat;
+		enum FRAME_BASE_VIDEO_PATH frame_base_video_path;
+		char data[8];
+	};
+	u32 cmd;
+	char reserved[4];
+};
+
+struct am_ioctl_parm_ex {
+	union {
+		struct buf_status status;
+		struct vdec_status vstatus;
+		struct adec_status astatus;
+
+		struct userdata_poc_info_t data_userdata_info;
+		char data[24];
+
+	};
+	u32 cmd;
+	char reserved[4];
+};
+
+struct am_ioctl_parm_ptr {
+	union {
+		struct audio_info *pdata_audio_info;
+		struct subtitle_info *pdata_sub_info;
+		void *pointer;
+		char data[8];
+	};
+	u32 cmd;
+	u32 len; /*char reserved[4]; */
+};
+
+struct vframe_qos_s {
+	u32 num;
+	u32 type;
+	u32 size;
+	u32 pts;
+	int max_qp;
+	int avg_qp;
+	int min_qp;
+	int max_skip;
+	int avg_skip;
+	int min_skip;
+	int max_mv;
+	int min_mv;
+	int avg_mv;
+	int decode_buffer;//For padding currently
+} /*vframe_qos */;
+
+
+struct vframe_comm_s {
+	int vdec_id;
+	char vdec_name[16];
+	u32 vdec_type;
+};
+
+
+struct vframe_counter_s {
+	struct vframe_qos_s qos;
+	u32  decode_time_cost;/*us*/
+	u32 frame_width;
+	u32 frame_height;
+	u32 frame_rate;
+	union {
+		u32 bit_rate;
+		/* Effective in h265,vp9,avs2 multi-instance */
+		u32 bit_depth_luma;
+	};
+	u32 frame_dur;
+	union {
+		u32 frame_data;
+		/* Effective in h265,vp9,avs2 multi-instance */
+		u32 bit_depth_chroma;
+	};
+	u32 error_count;
+	u32 status;
+	u32 frame_count;
+	u32 error_frame_count;
+	u32 drop_frame_count;
+	u64 total_data;//this member must be 8 bytes alignment
+	union {
+		u32 samp_cnt;
+		/* Effective in h265,vp9,avs2 multi-instance */
+		u32 double_write_mode;
+	};
+	u32 offset;
+	u32 ratio_control;
+	u32 vf_type;
+	u32 signal_type;
+	u32 pts;
+	u64 pts_us64;
+};
+
+struct vdec_frames_s {
+	u64 hw_decode_start;
+	u64 hw_decode_time;
+	u32 frame_size;
+	u32 rd;
+	u32 wr;
+	struct vframe_comm_s comm;
+	struct vframe_counter_s fifo_buf[NUM_FRAME_VDEC];
+};
+
+enum FRAME_FORMAT {
+	FRAME_FORMAT_UNKNOWN,
+	FRAME_FORMAT_PROGRESS,
+	FRAME_FORMAT_INTERLACE,
+};
+
+struct av_info_t {
+	/*auido info*/
+	int sample_rate;
+	int channels;
+	int aformat_type;
+	unsigned int apts;
+	unsigned int apts_err;
+	/*video info*/
+	unsigned int width;
+	unsigned int height;
+	unsigned int dec_error_count;
+	unsigned int first_pic_coming;
+	unsigned int fps;
+	unsigned int current_fps;
+	unsigned int vpts;
+	unsigned int vpts_err;
+	unsigned int ts_error;
+	unsigned int first_vpts;
+	int vformat_type;
+	enum FRAME_FORMAT frame_format;
+	unsigned int toggle_frame_count;/*toggle frame count*/
+	unsigned int dec_err_frame_count;/*vdec error frame count*/
+	unsigned int dec_frame_count;/*vdec frame count*/
+	unsigned int dec_drop_frame_count;/*drop frame num*/
+	int tsync_mode;
+	unsigned int dec_video_bps;//video bitrate
+};
+
+struct av_param_info_t {
+	struct av_info_t av_info;
+};
+struct av_param_qosinfo_t {
+	struct vframe_qos_s vframe_qos[QOS_FRAME_NUM];
+};
+
+
+/*This is a versioning structure, the key member is the struct_size.
+ *In the 1st version it is not used,but will have its role in fureture.
+ *https://bytes.com/topic/c/answers/811125-struct-versioning
+ */
+struct av_param_mvdec_t {
+	int vdec_id;
+
+	/*This member is used for versioning this structure.
+	 *When passed from userspace, its value must be
+	 *sizeof(struct av_param_mvdec_t)
+	 */
+	int struct_size;
+
+	int slots;
+
+	struct vframe_comm_s comm;
+	struct vframe_counter_s minfo[QOS_FRAME_NUM];
+};
+
+#define SUPPORT_VDEC_NUM	(64)
+int vcodec_profile_register(const struct codec_profile_t *vdec_profile);
+ssize_t vcodec_profile_read(char *buf);
+bool is_support_profile(char *name);
+#ifdef __KERNEL__
+#include <linux/interrupt.h>
+
+/*TS demux operation interface*/
+struct tsdemux_ops {
+
+	int (*reset)(void);
+
+	int (*set_reset_flag)(void);
+
+	int (*request_irq)(irq_handler_t handler, void *data);
+
+	int (*free_irq)(void);
+
+	int (*set_vid)(int vpid);
+
+	int (*set_aid)(int apid);
+
+	int (*set_sid)(int spid);
+
+	int (*set_pcrid)(int pcrpid);
+
+	int (*set_skipbyte)(int skipbyte);
+
+	int (*set_demux)(int dev);
+};
+
+void tsdemux_set_ops(struct tsdemux_ops *ops);
+int tsdemux_set_reset_flag(void);
+int amports_switch_gate(const char *name, int enable);
+
+void set_adec_func(int (*adec_func)(struct adec_status *));
+void wakeup_sub_poll(void);
+void init_userdata_fifo(void);
+void reset_userdata_fifo(int bInit);
+int wakeup_userdata_poll(struct userdata_poc_info_t poc,
+			int wp, unsigned long start_phyaddr,
+			int buf_size, int data_length);
+int get_sub_type(void);
+
+#endif				/**/
+
+struct tcon_gamma_table_s {
+
+	u16 data[256];
+} /*tcon_gamma_table_t */;
+
+struct tcon_rgb_ogo_s {
+
+	unsigned int en;
+
+	int r_pre_offset;	/* s11.0, range -1024~+1023, default is 0 */
+	int g_pre_offset;	/* s11.0, range -1024~+1023, default is 0 */
+	int b_pre_offset;	/* s11.0, range -1024~+1023, default is 0 */
+	unsigned int r_gain;   /* u1.10, range 0~2047, default is 1024 (1.0x) */
+	unsigned int g_gain;   /* u1.10, range 0~2047, default is 1024 (1.0x) */
+	unsigned int b_gain;   /* u1.10, range 0~2047, default is 1024 (1.0x) */
+	int r_post_offset;	/* s11.0, range -1024~+1023, default is 0 */
+	int g_post_offset;	/* s11.0, range -1024~+1023, default is 0 */
+	int b_post_offset;	/* s11.0, range -1024~+1023, default is 0 */
+} /*tcon_rgb_ogo_t */;
+
+#endif /* AMSTREAM_H */
diff --git a/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/canvas.h b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/canvas.h
new file mode 100644
index 0000000..c937d41
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/canvas.h
@@ -0,0 +1,60 @@
+/*
+ * AMLOGIC Canvas management driver.
+ *
+ * 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 named License,
+ * or 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Author:  Tim Yao <timyao@amlogic.com>
+ *
+ */
+
+#ifndef CANVAS_H
+#define CANVAS_H
+
+#include <linux/types.h>
+#include <linux/kobject.h>
+
+typedef struct {
+    struct kobject kobj;
+    ulong addr;
+    u32 width;
+    u32 height;
+    u32 wrap;
+    u32 blkmode;
+} canvas_t;
+
+#define OSD1_CANVAS_INDEX 0x40
+#define OSD2_CANVAS_INDEX 0x43
+#define ALLOC_CANVAS_INDEX  0x46
+
+#define GE2D_MAX_CANVAS_INDEX   0x5f
+
+#define DISPLAY_CANVAS_BASE_INDEX   0x60
+#define DISPLAY_CANVAS_MAX_INDEX    0x62 
+
+#define DEINTERLACE_CANVAS_BASE_INDEX	0x63
+#define DEINTERLACE_CANVAS_MAX_INDEX	0x6a
+
+extern void canvas_config(u32 index, ulong addr, u32 width,
+                          u32 height, u32 wrap, u32 blkmode);
+
+extern void canvas_read(u32 index, canvas_t *p);
+
+extern void canvas_copy(unsigned src, unsigned dst);
+
+extern void canvas_update_addr(u32 index, u32 addr);
+
+extern unsigned int canvas_get_addr(u32 index);
+
+#endif /* CANVAS_H */
diff --git a/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/cm.h b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/cm.h
new file mode 100644
index 0000000..3405656
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/cm.h
@@ -0,0 +1,169 @@
+/*

+ * Color Management

+ *

+ * Author: Lin Xu <lin.xu@amlogic.com>

+ *         Bobby Yang <bo.yang@amlogic.com>

+ *

+ * Copyright (C) 2010 Amlogic Inc.

+ *

+ * This program is free software; you can redistribute it and/or modify

+ * it under the terms of the GNU General Public License version 2 as

+ * published by the Free Software Foundation.

+ */

+

+

+#ifndef _TVOUT_CM_H

+#define _TVOUT_CM_H

+

+// ***************************************************************************

+// *** enum definitions *********************************************

+// ***************************************************************************

+

+typedef enum cm_region_idx_e {

+    CM_REGION_IDX_0 = 0,

+    CM_REGION_IDX_1,

+    CM_REGION_IDX_2,

+    CM_REGION_IDX_3,

+    CM_REGION_IDX_4,

+    CM_REGION_IDX_5,

+    CM_REGION_IDX_6,

+    CM_REGION_IDX_7,

+} cm_region_idx_t;

+

+typedef enum cm_sat_shape_e {

+    CM_SAT_SHAPE_RIGHT_BIGGEST = 0,

+    CM_SAT_SHAPE_LEFT_BIGGEST,

+} cm_sat_shape_t;

+

+typedef enum cm_hue_shape_e {

+    CM_HUE_SHAPE_LEFT_MORE = 0,

+    CM_HUE_SHAPE_RIGHT_MORE,

+} cm_hue_shape_t;

+

+typedef enum cm_demo_pos_e {

+    CM_DEMO_POS_TOP = 0,

+    CM_DEMO_POS_BOTTOM,

+    CM_DEMO_POS_LEFT,

+    CM_DEMO_POS_RIGHT,

+} cm_demo_pos_t;

+

+typedef enum cm_sat_sel_e {

+    CM_SAT_SEL_U2_V2 = 0,

+    CM_SAT_SEL_UV_MAX,

+} cm_sat_sel_t;

+

+typedef enum cm_csc_e {

+    CM_CSC_601 = 0,

+    CM_CSC_709,

+    CM_CSC_FULL_601,

+    CM_CSC_FULL_709,

+} cm_csc_t;

+

+// ***************************************************************************

+// *** struct definitions *********************************************

+// ***************************************************************************

+

+typedef struct cm_region_s {

+    enum cm_region_idx_e region_idx;

+    // sym

+    unsigned char       sym_en;

+    // sat - top

+    unsigned char       sat_en;

+    unsigned char       sat_central_en;

+    enum cm_sat_shape_e sat_shape;

+    unsigned char       sat_gain;

+    unsigned char       sat_inc;

+    // sat - lum

+    unsigned char       sat_lum_h_slope;

+    unsigned char       sat_lum_l_slope;

+    unsigned char       sat_lum_h;

+    unsigned char       sat_lum_l;

+    // sat - sat

+    unsigned char       sat_sat_h_slope;

+    unsigned char       sat_sat_l_slope;

+    unsigned char       sat_sat_h;

+    unsigned char       sat_sat_l;

+    // hue - top

+    unsigned char       hue_en;

+    unsigned char       hue_central_en;

+    enum cm_hue_shape_e hue_shape;

+    unsigned char       hue_gain;

+    unsigned char       hue_clockwise;

+    unsigned char       hue_shf_ran;

+    ushort              hue_shf_sta;

+    // hue - lum

+    unsigned char       hue_lum_h_slope;

+    unsigned char       hue_lum_l_slope;

+    unsigned char       hue_lum_h;

+    unsigned char       hue_lum_l;

+    // hue - sat

+    unsigned char       hue_sat_h_slope;

+    unsigned char       hue_sat_l_slope;

+    unsigned char       hue_sat_h;

+    unsigned char       hue_sat_l;

+} cm_region_t;

+

+typedef struct cm_top_s {

+    unsigned char       chroma_en;

+    enum cm_sat_sel_e   sat_sel;

+    unsigned char       uv_adj_en;

+    unsigned char       rgb_to_hue_en;

+    enum cm_csc_e       csc_sel;

+} cm_top_t;

+

+typedef struct cm_cbar_s {

+    unsigned char en;

+    unsigned char wid;

+    unsigned char cr;

+    unsigned char cb;

+    unsigned char y;

+} cm_cbar_t;

+typedef struct cm_demo_s {

+    unsigned char       en;

+    enum cm_demo_pos_e  pos;

+    unsigned char       hlight_adj;

+    ushort              wid;

+    struct cm_cbar_s   cbar;

+} cm_demo_t;

+

+typedef struct cm_regmap_s {

+    ulong reg[50];

+} cm_regmap_t;

+

+#if defined(CONFIG_AM_VECM)

+typedef enum reg_bus_type_e {

+    REG_TYPE_PHY = 0,

+    REG_TYPE_CBUS,

+    REG_TYPE_APB,

+    REG_TYPE_AXI,

+    REG_TYPE_AHB,

+    REG_TYPE_MPEG,

+    REG_TYPE_INDEX_VPPCHROMA,

+    REG_TYPE_INDEX_GAMMA,

+    VALUE_TYPE_CONTRAST_BRIGHTNESS,

+    REG_TYPE_INDEX_VPP_COEF,

+    REG_TYPE_MAX,

+} reg_bus_type_t;

+

+/* Register table structure */

+typedef struct am_reg_s {

+    unsigned int type; //32-bits; 0: CBUS; 1: APB BUS...

+    unsigned int addr; //32-bits; Register address

+    unsigned int mask; //32-bits; Valid bits

+    unsigned int  val; //32-bits; Register Value

+} am_reg_t;

+

+#ifdef AMVIDEO_REG_TABLE_DYNAMIC

+typedef struct am_regs_s {

+    unsigned int    length; // Length of total am_reg

+    struct am_reg_s *am_reg;

+} am_regs_t;

+#else

+typedef struct am_regs_s {

+    unsigned int    length; // Length of total am_reg

+    struct am_reg_s am_reg[512];

+} am_regs_t;

+#endif

+#endif

+

+#endif  // _TVOUT_CM_H

diff --git a/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/jpegdec.h b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/jpegdec.h
new file mode 100644
index 0000000..7387d9f
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/jpegdec.h
@@ -0,0 +1,93 @@
+/*

+ * AMLOGIC HW Jpeg decoder driver.

+ *

+ * 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 named License,

+ * or 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA

+ *

+ * Author:  Tim Yao <timyao@amlogic.com>

+ *

+ */

+

+#ifndef JPEGDEC_H

+#define JPEGDEC_H

+

+#define JPEGDEC_IOC_MAGIC  'J'

+

+#define JPEGDEC_IOC_INFOCONFIG	_IOW(JPEGDEC_IOC_MAGIC, 0x00, unsigned int)

+#define JPEGDEC_IOC_DECCONFIG	_IOW(JPEGDEC_IOC_MAGIC, 0x01, unsigned int)

+#define JPEGDEC_IOC_INFO		_IOW(JPEGDEC_IOC_MAGIC, 0x02, unsigned int)

+#define JPEGDEC_IOC_STAT		_IOW(JPEGDEC_IOC_MAGIC, 0x03, unsigned int)

+#define JPEGDEC_G_MEM_INFO		_IOW(JPEGDEC_IOC_MAGIC, 0x04, unsigned int)

+

+#define JPEGDEC_OPT_THUMBNAIL_ONLY		0x01

+#define JPEGDEC_OPT_THUMBNAIL_PREFERED	0x02

+#define JPEGDEC_OPT_FULLRANGE			0x04

+#define JPEGDEC_OPT_SRC_CROP			0x08

+

+#define JPEGINFO_TYPE_PROGRESSIVE		0x01

+#define JPEGINFO_TYPE_MULTISCAN			0x02

+#define JPEGINFO_TYPE_GRAYSCALE			0x04

+

+#define JPEGDEC_STAT_WAIT_DATA			0x01

+#define JPEGDEC_STAT_WAIT_INFOCONFIG	0x02

+#define JPEGDEC_STAT_WAIT_DECCONFIG		0x04

+#define JPEGDEC_STAT_ERROR				0x08

+#define JPEGDEC_STAT_UNSUPPORT			0x10

+#define JPEGDEC_STAT_INFO_READY			0x20

+#define JPEGDEC_STAT_DONE				0x40

+

+typedef enum {

+	CLKWISE_0    = 0,

+	CLKWISE_90   = 1,

+	CLKWISE_180  = 2,

+	CLKWISE_270  = 3,

+} jpegdec_angle_t;

+

+typedef struct {

+	unsigned long	addr_y;

+	unsigned long	addr_u;

+	unsigned long	addr_v;

+	unsigned 		canvas_width;

+

+	unsigned		opt;

+

+	unsigned		src_crop_x;

+	unsigned		src_crop_y;

+	unsigned		src_crop_w;

+	unsigned		src_crop_h;

+	

+	unsigned		dec_x;

+	unsigned		dec_y;

+	unsigned		dec_w;

+	unsigned		dec_h;	

+	jpegdec_angle_t	angle;

+} jpegdec_config_t;

+

+typedef struct {

+	unsigned width;

+	unsigned height;

+	unsigned comp_num;

+	unsigned type;

+} jpegdec_info_t;

+

+typedef struct {

+	jpegdec_angle_t	angle;

+	unsigned	dec_w;

+	unsigned	dec_h;

+	unsigned canv_addr;

+	unsigned canv_len;

+}  jpegdec_mem_info_t;

+

+#endif /* JPEGDEC_H */

+

diff --git a/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/ptsserv.h b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/ptsserv.h
new file mode 100644
index 0000000..847e4f9
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/ptsserv.h
@@ -0,0 +1,52 @@
+/*
+ * AMLOGIC PTS Manager Driver.
+ *
+ * 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 named License,
+ * or 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Author:  Tim Yao <timyao@amlogic.com>
+ *
+ */
+
+#ifndef PTSSERV_H
+#define PTSSERV_H
+
+enum {
+    PTS_TYPE_VIDEO = 0,
+    PTS_TYPE_AUDIO = 1,
+    PTS_TYPE_MAX   = 2
+};
+
+#define apts_checkin(x) pts_checkin(PTS_TYPE_AUDIO, (x))
+#define vpts_checkin(x) pts_checkin(PTS_TYPE_VIDEO, (x))
+
+extern int pts_checkin(u8 type, u32 val);
+
+extern int pts_checkin_wrptr(u8 type, u32 ptr, u32 val);
+
+extern int pts_checkin_offset(u8 type, u32 offset, u32 val);
+
+extern int pts_lookup(u8 type, u32 *val, u32 pts_margin);
+
+extern int pts_lookup_offset(u8 type, u32 offset, u32 *val, u32 pts_margin);
+
+extern int pts_set_resolution(u8 type, u32 level);
+
+extern int pts_set_rec_size(u8 type, u32 val);
+
+extern int pts_start(u8 type);
+
+extern int pts_stop(u8 type);
+
+#endif /* PTSSERV_H */
diff --git a/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/timestamp.h b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/timestamp.h
new file mode 100644
index 0000000..5b1930d
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/timestamp.h
@@ -0,0 +1,45 @@
+/*
+ * AMLOGIC PTS Manager Driver.
+ *
+ * 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 named License,
+ * or 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Author:  Tim Yao <timyao@amlogic.com>
+ *
+ */
+
+#ifndef TIMESTAMP_H
+#define TIMESTAMP_H
+
+extern u32 timestamp_vpts_get(void);
+
+extern void timestamp_vpts_set(u32 pts);
+
+extern void timestamp_vpts_inc(s32 val);
+
+extern u32 timestamp_apts_get(void);
+
+extern void timestamp_apts_set(u32 pts);
+
+extern void timestamp_apts_inc(s32 val);
+
+extern u32 timestamp_pcrscr_get(void);
+
+extern void timestamp_pcrscr_set(u32 pts);
+
+extern void timestamp_pcrscr_inc(s32 val);
+
+extern void timestamp_pcrscr_enable(u32 enable);
+
+#endif /* TIMESTAMP_H */
diff --git a/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/tsync.h b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/tsync.h
new file mode 100644
index 0000000..f8e341a
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/tsync.h
@@ -0,0 +1,77 @@
+/*
+ * AMLOGIC PTS Manager Driver.
+ *
+ * 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 named License,
+ * or 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Author:  Tim Yao <timyao@amlogic.com>
+ *
+ */
+
+#ifndef TSYNC_H
+#define TSYNC_H
+
+#define TIME_UNIT90K    (90000)
+#define VIDEO_HOLD_THRESHOLD        (TIME_UNIT90K * 3)
+#define AV_DISCONTINUE_THREDHOLD    (TIME_UNIT90K * 30)
+
+typedef enum {
+    VIDEO_START,
+    VIDEO_PAUSE,
+    VIDEO_STOP,
+    VIDEO_TSTAMP_DISCONTINUITY,
+    AUDIO_START,
+    AUDIO_PAUSE,
+    AUDIO_RESUME,
+    AUDIO_STOP,
+    AUDIO_TSTAMP_DISCONTINUITY
+} avevent_t;
+
+typedef enum {
+    TSYNC_MODE_VMASTER,
+    TSYNC_MODE_AMASTER,
+} tsync_mode_t;
+
+enum tysnc_func_type_e {
+	TSYNC_PCRSCR_VALID,
+	TSYNC_PCRSCR_GET,
+	TSYNC_FIRST_PCRSCR_GET,
+	TSYNC_PCRAUDIO_VALID,
+	TSYNC_PCRVIDEO_VALID,
+	TSYNC_BUF_BY_BYTE,
+	TSYNC_STBUF_LEVEL,
+	TSYNC_STBUF_SPACE,
+	TSYNC_STBUF_SIZE,
+	TSYNC_FUNC_TYPE_MAX,
+};
+
+extern void tsync_avevent(avevent_t event, u32 param);
+
+extern void tsync_audio_break(int audio_break);
+
+extern void tsync_trick_mode(int trick_mode);
+
+extern void tsync_set_avthresh(unsigned int av_thresh);
+
+extern void tsync_set_syncthresh(unsigned int sync_thresh);
+
+extern void tsync_set_dec_reset(void);
+
+static inline u32 tsync_vpts_discontinuity_margin(void)
+{
+    return AV_DISCONTINUE_THREDHOLD;
+}
+extern int register_tync_func(enum tysnc_func_type_e ntype, void *pfunc);
+
+#endif /* TSYNC_H */
diff --git a/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/ve.h b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/ve.h
new file mode 100644
index 0000000..2f57cea
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/ve.h
@@ -0,0 +1,184 @@
+/*

+ * Video Enhancement

+ *

+ * Author: Lin Xu <lin.xu@amlogic.com>

+ *         Bobby Yang <bo.yang@amlogic.com>

+ *

+ * Copyright (C) 2010 Amlogic Inc.

+ *

+ * This program is free software; you can redistribute it and/or modify

+ * it under the terms of the GNU General Public License version 2 as

+ * published by the Free Software Foundation.

+ */

+

+#ifndef __VE_H

+#define __VE_H

+

+// ***************************************************************************

+// *** enum definitions *********************************************

+// ***************************************************************************

+

+typedef enum ve_demo_pos_e {

+  VE_DEMO_POS_TOP = 0,

+  VE_DEMO_POS_BOTTOM,

+  VE_DEMO_POS_LEFT,

+  VE_DEMO_POS_RIGHT,

+} ve_demo_pos_t;

+

+typedef enum ve_dnlp_rt_e {

+	VE_DNLP_RT_0S = 0,

+	VE_DNLP_RT_1S = 6,

+    VE_DNLP_RT_2S,

+    VE_DNLP_RT_4S,

+    VE_DNLP_RT_8S,

+    VE_DNLP_RT_16S,

+    VE_DNLP_RT_32S,

+    VE_DNLP_RT_64S,

+    VE_DNLP_RT_FREEZE,

+} ve_dnlp_rt_t;

+

+// ***************************************************************************

+// *** struct definitions *********************************************

+// ***************************************************************************

+

+typedef struct ve_bext_s {

+    unsigned char en;

+    unsigned char start;

+    unsigned char slope1;

+    unsigned char midpt;

+    unsigned char slope2;

+} ve_bext_t;

+#if defined(CONFIG_AM_VECM)

+typedef struct ve_dnlp_s {

+    unsigned int      en;

+    unsigned int rt;    //       0 ~ 255,

+    unsigned int rl;    //       0 ~  15, 1.0000x ~ 1.9375x, step 0.0625x

+    unsigned int black; //       0 ~  16, weak ~ strong

+    unsigned int white; //       0 ~  16, weak ~ strong

+} ve_dnlp_t;

+#else

+typedef struct ve_dnlp_s {

+    unsigned char en;

+    enum  ve_dnlp_rt_e rt;

+    unsigned char gamma[64];

+} ve_dnlp_t;

+#endif

+typedef struct ve_hsvs_s {

+    unsigned char en;

+    unsigned char peak_gain_h1;

+    unsigned char peak_gain_h2;

+    unsigned char peak_gain_h3;

+    unsigned char peak_gain_h4;

+    unsigned char peak_gain_h5;

+    unsigned char peak_gain_v1;

+    unsigned char peak_gain_v2;

+    unsigned char peak_gain_v3;

+    unsigned char peak_gain_v4;

+    unsigned char peak_gain_v5;

+    unsigned char peak_gain_v6;

+    unsigned char hpeak_slope1;

+    unsigned char hpeak_slope2;

+    unsigned char hpeak_thr1;

+    unsigned char hpeak_thr2;

+    unsigned char hpeak_nlp_cor_thr;

+    unsigned char hpeak_nlp_gain_pos;

+    unsigned char hpeak_nlp_gain_neg;

+    unsigned char vpeak_slope1;

+    unsigned char vpeak_slope2;

+    unsigned char vpeak_thr1;

+    unsigned char vpeak_thr2;

+    unsigned char vpeak_nlp_cor_thr;

+    unsigned char vpeak_nlp_gain_pos;

+    unsigned char vpeak_nlp_gain_neg;

+    unsigned char speak_slope1;

+    unsigned char speak_slope2;

+    unsigned char speak_thr1;

+    unsigned char speak_thr2;

+    unsigned char speak_nlp_cor_thr;

+    unsigned char speak_nlp_gain_pos;

+    unsigned char speak_nlp_gain_neg;

+    unsigned char peak_cor_gain;

+    unsigned char peak_cor_thr_l;

+    unsigned char peak_cor_thr_h;

+    unsigned char vlti_step;

+    unsigned char vlti_step2;

+    unsigned char vlti_thr;

+    unsigned char vlti_gain_pos;

+    unsigned char vlti_gain_neg;

+    unsigned char vlti_blend_factor;

+    unsigned char hlti_step;

+    unsigned char hlti_thr;

+    unsigned char hlti_gain_pos;

+    unsigned char hlti_gain_neg;

+    unsigned char hlti_blend_factor;

+    unsigned char vlimit_coef_h;

+    unsigned char vlimit_coef_l;

+    unsigned char hlimit_coef_h;

+    unsigned char hlimit_coef_l;

+    unsigned char cti_444_422_en;

+    unsigned char cti_422_444_en;

+    unsigned char cti_blend_factor;

+    unsigned char vcti_buf_en;

+    unsigned char vcti_buf_mode_c5l;

+    unsigned char vcti_filter;

+    unsigned char hcti_step;

+    unsigned char hcti_step2;

+    unsigned char hcti_thr;

+    unsigned char hcti_gain;

+    unsigned char hcti_mode_median;

+} ve_hsvs_t;

+

+typedef struct ve_ccor_s {

+    unsigned char en;

+    unsigned char slope;

+    unsigned char thr;

+} ve_ccor_t;

+

+typedef struct ve_benh_s {

+    unsigned char en;

+    unsigned char cb_inc;

+    unsigned char cr_inc;

+    unsigned char gain_cr;

+    unsigned char gain_cb4cr;

+    unsigned char luma_h;

+    unsigned char err_crp;

+    unsigned char err_crn;

+    unsigned char err_cbp;

+    unsigned char err_cbn;

+} ve_benh_t;

+

+typedef struct ve_cbar_s {

+    unsigned char en;

+    unsigned char wid;

+    unsigned char cr;

+    unsigned char cb;

+    unsigned char y;

+} ve_cbar_t;

+typedef struct ve_demo_s {

+    unsigned char bext;

+    unsigned char dnlp;

+    unsigned char hsvs;

+    unsigned char ccor;

+    unsigned char benh;

+    enum  ve_demo_pos_e  pos;

+    unsigned long wid;

+    struct ve_cbar_s   cbar;

+} ve_demo_t;

+

+typedef struct vdo_meas_s {

+    //...

+} vdo_meas_t;

+

+typedef struct ve_regmap_s {

+    unsigned long reg[43];

+} ve_regmap_t;

+

+// ***************************************************************************

+// *** MACRO definitions **********

+// ***************************************************************************

+

+// ***************************************************************************

+// *** FUNCTION definitions **********

+// ***************************************************************************

+

+#endif  // _VE_H

diff --git a/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/vformat.h b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/vformat.h
new file mode 100644
index 0000000..c0afc41
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/vformat.h
@@ -0,0 +1,45 @@
+/*
+ * AMLOGIC Audio/Video streaming port driver.
+ *
+ * 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 named License,
+ * or 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Author:  Tim Yao <timyao@amlogic.com>
+ *
+ */
+
+#ifndef VFORMAT_H
+#define VFORMAT_H
+
+enum vformat_e {
+    VFORMAT_MPEG12 = 0,
+    VFORMAT_MPEG4,
+    VFORMAT_H264,
+    VFORMAT_MJPEG,
+    VFORMAT_REAL,
+    VFORMAT_JPEG,
+    VFORMAT_VC1,
+    VFORMAT_AVS,
+    VFORMAT_YUV,    // Use SW decoder
+    VFORMAT_H264MVC,
+    VFORMAT_H264_4K2K,
+    VFORMAT_HEVC,
+    VFORMAT_H264_ENC,
+    VFORMAT_JPEG_ENC,
+    VFORMAT_VP9,
+    VFORMAT_AVS2,
+    VFORMAT_MAX
+};
+
+#endif /* VFORMAT_H */
diff --git a/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/vframe.h b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/vframe.h
new file mode 100644
index 0000000..4dcbac2
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/vframe.h
@@ -0,0 +1,123 @@
+/*
+ * AMLOGIC Audio/Video streaming port driver.
+ *
+ * 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 named License,
+ * or 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Author:  Tim Yao <timyao@amlogic.com>
+ *
+ */
+
+#ifndef VFRAME_H
+#define VFRAME_H
+
+#include <linux/types.h>
+
+
+#define VIDTYPE_PROGRESSIVE             0x0
+#define VIDTYPE_INTERLACE_TOP           0x1
+#define VIDTYPE_INTERLACE_BOTTOM        0x3
+#define VIDTYPE_TYPEMASK                0x7
+#define VIDTYPE_INTERLACE               0x1
+#define VIDTYPE_INTERLACE_FIRST         0x8
+#define VIDTYPE_PULLDOWN                0x10
+#define VIDTYPE_VIU_422                 0x800
+#define VIDTYPE_VIU_FIELD               0x1000
+#define VIDTYPE_VIU_SINGLE_PLANE        0x2000
+#define VIDTYPE_VIU_444                 0x4000
+
+#define DISP_RATIO_FORCECONFIG          0x80000000
+#define DISP_RATIO_CTRL_MASK            0x00000003
+#define DISP_RATIO_NO_KEEPRATIO         0x00000000
+#define DISP_RATIO_KEEPRATIO            0x00000001
+
+#define DISP_RATIO_ASPECT_RATIO_MASK    0x0003ff00
+#define DISP_RATIO_ASPECT_RATIO_BIT     8
+#define DISP_RATIO_ASPECT_RATIO_MAX     0x3ff
+
+
+
+
+/*
+ * If pixel_sum[21:0] == 0, then all Histogram information are invalid
+ */
+typedef struct vframe_hist_s
+{
+    unsigned int   luma_sum;
+    unsigned int   chroma_sum;
+    unsigned int   pixel_sum;  // [31:30] POW [21:0] PIXEL_SUM
+    unsigned char  luma_max;
+    unsigned char  luma_min;
+    unsigned short gamma[64];
+} vframe_hist_t;
+
+
+/*
+ * If bottom == 0 or right == 0, then all Blackbar information are invalid
+ */
+typedef struct vframe_bbar_s
+{
+    unsigned short top;
+    unsigned short bottom;
+    unsigned short left;
+    unsigned short right;
+} vfame_bbar_t;
+
+
+/*
+ * If vsin == 0, then all Measurement information are invalid
+ */
+typedef struct vframe_meas_s
+{
+    float          frin;      // Frame Rate of Video Input in the unit of Hz
+} vframe_meas_t;
+
+
+/* vframe properties */
+typedef struct vframe_prop_s
+{
+    struct vframe_hist_s hist;
+    struct vframe_bbar_s bbar;
+    struct vframe_meas_s meas;
+} vframe_prop_t;
+
+typedef struct vframe_s {
+    u32 index;
+    u32 type;
+    u32 type_backup;
+    u32 blend_mode;
+    u32 duration;
+    u32 duration_pulldown;
+    u32 pts;
+
+    u32 canvas0Addr;
+    u32 canvas1Addr;
+
+    u32 bufWidth;
+    u32 width;
+    u32 height;
+    u32 ratio_control;
+
+#if 1
+    /* vframe properties */
+    struct vframe_prop_s prop;
+#endif
+} vframe_t;
+
+#if 0
+struct vframe_prop_s * vdin_get_vframe_prop(u32 index);
+#endif
+
+#endif /* VFRAME_H */
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/vframe_provider.h b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/vframe_provider.h
new file mode 100644
index 0000000..c861fef
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/amports/vframe_provider.h
@@ -0,0 +1,40 @@
+/*
+ * AMLOGIC Audio/Video streaming port driver.
+ *
+ * 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 named License,
+ * or 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
+ *
+ * Author:  Tim Yao <timyao@amlogic.com>
+ *
+ */
+
+#ifndef VFRAME_PROVIDER_H
+#define VFRAME_PROVIDER_H
+
+#include <linux/amports/vframe.h>
+
+typedef struct vframe_provider_s {
+    vframe_t * (*peek)(void);
+    vframe_t * (*get )(void);
+    void       (*put )(vframe_t *);
+} vframe_provider_t;
+
+void vf_reg_provider(const vframe_provider_t *p);
+void vf_unreg_provider(void);
+void vf_light_unreg_provider(void);
+unsigned int get_post_canvas(void);
+unsigned int vf_keep_current(void);
+
+#endif /* VFRAME_PROVIDER_H */
+
diff --git a/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/dvb/Kbuild b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/dvb/Kbuild
new file mode 100644
index 0000000..d40942c
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/dvb/Kbuild
@@ -0,0 +1,9 @@
+# UAPI Header export list
+header-y += audio.h
+header-y += ca.h
+header-y += dmx.h
+header-y += frontend.h
+header-y += net.h
+header-y += osd.h
+header-y += version.h
+header-y += video.h
diff --git a/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/dvb/aml_demod.h b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/dvb/aml_demod.h
new file mode 100644
index 0000000..673a716
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/dvb/aml_demod.h
@@ -0,0 +1,221 @@
+/*
+* Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+*
+* This source code is subject to the terms and conditions defined in the
+* file 'LICENSE' which is part of this source code package. *
+* Description:
+*/
+#ifndef AML_DEMOD_H
+#define AML_DEMOD_H
+#ifndef CONFIG_AM_DEMOD_FPGA_VER
+#define CONFIG_AM_DEMOD_FPGA_VER
+#endif				/*CONFIG_AM_DEMOD_FPGA_VER */
+
+/*#include <linux/types.h>*/
+#define u8_t u8
+#define u16_t u16
+#define u32_t u32
+#define u64_t u64
+
+struct aml_demod_i2c {
+	u8_t tuner;		/*type */
+	u8_t addr;		/*slave addr */
+	u32_t scl_oe;
+	u32_t scl_out;
+	u32_t scl_in;
+	u8_t scl_bit;
+	u32_t sda_oe;
+	u32_t sda_out;
+	u32_t sda_in;
+	u8_t sda_bit;
+	u8_t udelay;		/*us */
+	u8_t retries;
+	u8_t debug;		/*1:debug */
+	u8_t tmp;		/*spare */
+	u8_t i2c_id;
+	void *i2c_priv;
+};
+
+struct aml_tuner_sys {
+	u8_t mode;
+	u8_t amp;
+	u8_t if_agc_speed;
+	u32_t ch_freq;
+	u32_t if_freq;
+	u32_t rssi;
+	u32_t delay;
+	u8_t bandwith;
+};
+
+struct aml_demod_sys {
+	u8_t clk_en;		/* 1:on */
+	u8_t clk_src;		/*2 bits */
+	u8_t clk_div;		/*7 bits */
+	u8_t pll_n;		/*5 bits */
+	u16_t pll_m;		/*9 bits */
+	u8_t pll_od;		/*7 bits */
+	u8_t pll_sys_xd;	/*5 bits */
+	u8_t pll_adc_xd;	/*5 bits */
+	u8_t agc_sel;		/*pin mux */
+	u8_t adc_en;		/*1:on */
+	u8_t debug;		/*1:debug */
+	u32_t i2c;		/*pointer */
+	u32_t adc_clk;
+	u32_t demod_clk;
+};
+
+struct aml_demod_sts {
+	u32_t ch_sts;
+	u32_t freq_off;		/*Hz */
+	u32_t ch_pow;
+	u32_t ch_snr;
+	u32_t ch_ber;
+	u32_t ch_per;
+	u32_t symb_rate;
+	u32_t dat0;
+	u32_t dat1;
+};
+
+struct aml_demod_sta {
+	u8_t clk_en;		/*on/off */
+	u8_t adc_en;		/*on/off */
+	u32_t clk_freq;		/*kHz */
+	u32_t adc_freq;		/*kHz */
+	u8_t dvb_mode;		/*dvb-t/c mode */
+	u8_t ch_mode;		/* 16,32,..,256QAM or 2K,4K,8K */
+	u8_t agc_mode;		/*if, rf or both. */
+	u8_t tuner;		/*type */
+	u32_t ch_freq;		/*kHz */
+	u16_t ch_if;		/*kHz */
+	u16_t ch_bw;		/*kHz */
+	u16_t symb_rate;	/*kHz */
+	u8_t debug;
+	u8_t tmp;
+	u32_t sts;		/*pointer */
+	u8_t spectrum;
+};
+
+struct aml_demod_dvbc {
+	u8_t mode;
+	u8_t tmp;
+	u16_t symb_rate;
+	u32_t ch_freq;
+	u32_t dat0;
+	u32_t dat1;
+};
+
+struct aml_demod_dvbt {
+	u8_t bw;
+	u8_t sr;
+	u8_t ifreq;
+	u8_t agc_mode;
+	u32_t ch_freq;
+	u32_t dat0;
+	u32_t dat1;
+	u32_t layer;
+
+};
+
+struct aml_demod_dtmb {
+	u8_t bw;
+	u8_t sr;
+	u8_t ifreq;
+	u8_t agc_mode;
+	u32_t ch_freq;
+	u32_t dat0;
+	u32_t dat1;
+	u32_t mode;
+
+};
+
+struct aml_demod_atsc {
+	u8_t bw;
+	u8_t sr;
+	u8_t ifreq;
+	u8_t agc_mode;
+	u32_t ch_freq;
+	u32_t dat0;
+	u32_t dat1;
+	u32_t mode;
+
+};
+
+struct aml_demod_mem {
+	u32_t addr;
+	u32_t dat;
+
+};
+
+struct aml_cap_data {
+	u32_t cap_addr;
+	u32_t cap_size;
+	u32_t cap_afifo;
+	char  *cap_dev_name;
+};
+
+struct aml_demod_reg {
+	u8_t mode;
+	u8_t rw;		/* 0: read, 1: write. */
+	u32_t addr;
+	u32_t val;
+/*	u32_t val_high;*/
+};
+
+struct aml_demod_regs {
+	u8_t mode;
+	u8_t rw;		/* 0: read, 1: write. */
+	u32_t addr;
+	u32_t addr_len;
+	u32_t n;
+	u32_t vals[1];		/*[mode i2c]: write:n*u32_t, read:n*u8_t */
+};
+struct fpga_m1_sdio {
+	unsigned long addr;
+	unsigned long byte_count;
+	unsigned char *data_buf;
+};
+
+#define AML_DEMOD_SET_SYS        _IOW('D',  0, struct aml_demod_sys)
+#define AML_DEMOD_GET_SYS        _IOR('D',  1, struct aml_demod_sys)
+#define AML_DEMOD_TEST           _IOR('D',  2, u32_t)
+#define AML_DEMOD_TURN_ON        _IOR('D',  3, u32_t)
+#define AML_DEMOD_TURN_OFF       _IOR('D',  4, u32_t)
+#define AML_DEMOD_SET_TUNER      _IOW('D',  5, struct aml_tuner_sys)
+#define AML_DEMOD_GET_RSSI       _IOR('D',  6, struct aml_tuner_sys)
+
+#define AML_DEMOD_DVBC_SET_CH    _IOW('D', 10, struct aml_demod_dvbc)
+#define AML_DEMOD_DVBC_GET_CH    _IOR('D', 11, struct aml_demod_dvbc)
+#define AML_DEMOD_DVBC_TEST      _IOR('D', 12, u32_t)
+
+#define AML_DEMOD_DVBT_SET_CH    _IOW('D', 20, struct aml_demod_dvbt)
+#define AML_DEMOD_DVBT_GET_CH    _IOR('D', 21, struct aml_demod_dvbt)
+#define AML_DEMOD_DVBT_TEST      _IOR('D', 22, u32_t)
+
+#define AML_DEMOD_DTMB_SET_CH    _IOW('D', 50, struct aml_demod_dtmb)
+#define AML_DEMOD_DTMB_GET_CH    _IOR('D', 51, struct aml_demod_dtmb)
+#define AML_DEMOD_DTMB_TEST      _IOR('D', 52, u32_t)
+
+#define AML_DEMOD_ATSC_SET_CH    _IOW('D', 60, struct aml_demod_atsc)
+#define AML_DEMOD_ATSC_GET_CH    _IOR('D', 61, struct aml_demod_atsc)
+#define AML_DEMOD_ATSC_TEST      _IOR('D', 62, u32_t)
+#define AML_DEMOD_ATSC_IRQ       _IOR('D', 63, u32_t)
+
+#define AML_DEMOD_RESET_MEM		  _IOR('D', 70, u32_t)
+#define	AML_DEMOD_READ_MEM		  _IOR('D', 71, u32_t)
+#define AML_DEMOD_SET_MEM		  _IOR('D', 72, struct aml_demod_mem)
+
+#define AML_DEMOD_SET_REG        _IOW('D', 30, struct aml_demod_reg)
+#define AML_DEMOD_GET_REG        _IOR('D', 31, struct aml_demod_reg)
+/* #define AML_DEMOD_SET_REGS        _IOW('D', 32, struct aml_demod_regs)*/
+/*#define AML_DEMOD_GET_REGS        _IOR('D', 33, struct aml_demod_regs)*/
+#define FPGA2M1_SDIO_WR_DDR      _IOW('D', 40, struct fpga_m1_sdio)
+#define FPGA2M1_SDIO_RD_DDR      _IOR('D', 41, struct fpga_m1_sdio)
+#define FPGA2M1_SDIO_INIT        _IO('D', 42)
+#define FPGA2M1_SDIO_EXIT        _IO('D', 43)
+
+int read_memory_to_file(struct aml_cap_data *cap);
+int read_reg(int addr);
+void wait_capture(int cap_cur_addr, int depth_MB, int start);
+int cap_adc_data(struct aml_cap_data *cap);
+
+#endif				/* AML_DEMOD_H */
diff --git a/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/dvb/audio.h b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/dvb/audio.h
new file mode 100644
index 0000000..d47bccd
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/dvb/audio.h
@@ -0,0 +1,135 @@
+/*
+ * audio.h
+ *
+ * Copyright (C) 2000 Ralph  Metzler <ralph@convergence.de>
+ *                  & Marcus Metzler <marcus@convergence.de>
+ *                    for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Lesser Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * 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 Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#ifndef _DVBAUDIO_H_
+#define _DVBAUDIO_H_
+
+#include <linux/types.h>
+
+typedef enum {
+	AUDIO_SOURCE_DEMUX, /* Select the demux as the main source */
+	AUDIO_SOURCE_MEMORY /* Select internal memory as the main source */
+} audio_stream_source_t;
+
+
+typedef enum {
+	AUDIO_STOPPED,      /* Device is stopped */
+	AUDIO_PLAYING,      /* Device is currently playing */
+	AUDIO_PAUSED        /* Device is paused */
+} audio_play_state_t;
+
+
+typedef enum {
+	AUDIO_STEREO,
+	AUDIO_MONO_LEFT,
+	AUDIO_MONO_RIGHT,
+	AUDIO_MONO,
+	AUDIO_STEREO_SWAPPED
+} audio_channel_select_t;
+
+
+typedef struct audio_mixer {
+	unsigned int volume_left;
+	unsigned int volume_right;
+  // what else do we need? bass, pass-through, ...
+} audio_mixer_t;
+
+
+typedef struct audio_status {
+	int                    AV_sync_state;  /* sync audio and video? */
+	int                    mute_state;     /* audio is muted */
+	audio_play_state_t     play_state;     /* current playback state */
+	audio_stream_source_t  stream_source;  /* current stream source */
+	audio_channel_select_t channel_select; /* currently selected channel */
+	int                    bypass_mode;    /* pass on audio data to */
+	audio_mixer_t	       mixer_state;    /* current mixer state */
+} audio_status_t;                              /* separate decoder hardware */
+
+
+typedef
+struct audio_karaoke {  /* if Vocal1 or Vocal2 are non-zero, they get mixed  */
+	int vocal1;    /* into left and right t at 70% each */
+	int vocal2;    /* if both, Vocal1 and Vocal2 are non-zero, Vocal1 gets*/
+	int melody;    /* mixed into the left channel and */
+		       /* Vocal2 into the right channel at 100% each. */
+		       /* if Melody is non-zero, the melody channel gets mixed*/
+} audio_karaoke_t;     /* into left and right  */
+
+
+typedef __u16 audio_attributes_t;
+/*   bits: descr. */
+/*   15-13 audio coding mode (0=ac3, 2=mpeg1, 3=mpeg2ext, 4=LPCM, 6=DTS, */
+/*   12    multichannel extension */
+/*   11-10 audio type (0=not spec, 1=language included) */
+/*    9- 8 audio application mode (0=not spec, 1=karaoke, 2=surround) */
+/*    7- 6 Quantization / DRC (mpeg audio: 1=DRC exists)(lpcm: 0=16bit,  */
+/*    5- 4 Sample frequency fs (0=48kHz, 1=96kHz) */
+/*    2- 0 number of audio channels (n+1 channels) */
+
+
+/* for GET_CAPABILITIES and SET_FORMAT, the latter should only set one bit */
+#define AUDIO_CAP_DTS    1
+#define AUDIO_CAP_LPCM   2
+#define AUDIO_CAP_MP1    4
+#define AUDIO_CAP_MP2    8
+#define AUDIO_CAP_MP3   16
+#define AUDIO_CAP_AAC   32
+#define AUDIO_CAP_OGG   64
+#define AUDIO_CAP_SDDS 128
+#define AUDIO_CAP_AC3  256
+
+#define AUDIO_STOP                 _IO('o', 1)
+#define AUDIO_PLAY                 _IO('o', 2)
+#define AUDIO_PAUSE                _IO('o', 3)
+#define AUDIO_CONTINUE             _IO('o', 4)
+#define AUDIO_SELECT_SOURCE        _IO('o', 5)
+#define AUDIO_SET_MUTE             _IO('o', 6)
+#define AUDIO_SET_AV_SYNC          _IO('o', 7)
+#define AUDIO_SET_BYPASS_MODE      _IO('o', 8)
+#define AUDIO_CHANNEL_SELECT       _IO('o', 9)
+#define AUDIO_GET_STATUS           _IOR('o', 10, audio_status_t)
+
+#define AUDIO_GET_CAPABILITIES     _IOR('o', 11, unsigned int)
+#define AUDIO_CLEAR_BUFFER         _IO('o',  12)
+#define AUDIO_SET_ID               _IO('o', 13)
+#define AUDIO_SET_MIXER            _IOW('o', 14, audio_mixer_t)
+#define AUDIO_SET_STREAMTYPE       _IO('o', 15)
+#define AUDIO_SET_EXT_ID           _IO('o', 16)
+#define AUDIO_SET_ATTRIBUTES       _IOW('o', 17, audio_attributes_t)
+#define AUDIO_SET_KARAOKE          _IOW('o', 18, audio_karaoke_t)
+
+/**
+ * AUDIO_GET_PTS
+ *
+ * Read the 33 bit presentation time stamp as defined
+ * in ITU T-REC-H.222.0 / ISO/IEC 13818-1.
+ *
+ * The PTS should belong to the currently played
+ * frame if possible, but may also be a value close to it
+ * like the PTS of the last decoded frame or the last PTS
+ * extracted by the PES parser.
+ */
+#define AUDIO_GET_PTS              _IOR('o', 19, __u64)
+#define AUDIO_BILINGUAL_CHANNEL_SELECT _IO('o', 20)
+
+#endif /* _DVBAUDIO_H_ */
diff --git a/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/dvb/ca.h b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/dvb/ca.h
new file mode 100644
index 0000000..69ef406
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/dvb/ca.h
@@ -0,0 +1,130 @@
+/*
+ * ca.h
+ *
+ * Copyright (C) 2000 Ralph  Metzler <ralph@convergence.de>
+ *                  & Marcus Metzler <marcus@convergence.de>
+ *                    for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Lesser Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * 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 Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#ifndef _DVBCA_H_
+#define _DVBCA_H_
+
+/* slot interface types and info */
+
+typedef struct ca_slot_info {
+	int num;               /* slot number */
+
+	int type;              /* CA interface this slot supports */
+#define CA_CI            1     /* CI high level interface */
+#define CA_CI_LINK       2     /* CI link layer level interface */
+#define CA_CI_PHYS       4     /* CI physical layer level interface */
+#define CA_DESCR         8     /* built-in descrambler */
+#define CA_SC          128     /* simple smart card interface */
+
+	unsigned int flags;
+#define CA_CI_MODULE_PRESENT 1 /* module (or card) inserted */
+#define CA_CI_MODULE_READY   2
+} ca_slot_info_t;
+
+
+/* descrambler types and info */
+
+typedef struct ca_descr_info {
+	unsigned int num;          /* number of available descramblers (keys) */
+	unsigned int type;         /* type of supported scrambling system */
+#define CA_ECD           1
+#define CA_NDS           2
+#define CA_DSS           4
+} ca_descr_info_t;
+
+typedef struct ca_caps {
+	unsigned int slot_num;     /* total number of CA card and module slots */
+	unsigned int slot_type;    /* OR of all supported types */
+	unsigned int descr_num;    /* total number of descrambler slots (keys) */
+	unsigned int descr_type;   /* OR of all supported types */
+} ca_caps_t;
+
+/* a message to/from a CI-CAM */
+typedef struct ca_msg {
+	unsigned int index;
+	unsigned int type;
+	unsigned int length;
+	unsigned char msg[256];
+} ca_msg_t;
+
+typedef struct ca_descr {
+	unsigned int index;
+	unsigned int parity;	/* 0 == even, 1 == odd */
+	unsigned char cw[8];
+} ca_descr_t;
+
+#ifdef CONFIG_AMLOGIC_DVB_COMPAT
+
+/* CW type. */
+enum ca_cw_type {
+	CA_CW_DVB_CSA_EVEN,
+	CA_CW_DVB_CSA_ODD,
+	CA_CW_AES_EVEN,
+	CA_CW_AES_ODD,
+	CA_CW_AES_EVEN_IV,
+	CA_CW_AES_ODD_IV,
+	CA_CW_DES_EVEN,
+	CA_CW_DES_ODD,
+	CA_CW_SM4_EVEN,
+	CA_CW_SM4_ODD,
+	CA_CW_SM4_EVEN_IV,
+	CA_CW_SM4_ODD_IV,
+	CA_CW_TYPE_MAX
+};
+
+enum ca_dsc_mode {
+	CA_DSC_CBC = 1,
+	CA_DSC_ECB,
+	CA_DSC_IDSA
+};
+
+struct ca_descr_ex {
+	unsigned int index;
+	enum ca_cw_type type;
+	enum ca_dsc_mode mode;
+	int          flags;
+#define CA_CW_FROM_KL 1
+	unsigned char cw[16];
+};
+
+#endif /*CONFIG_AMLOGIC_DVB_COMPAT*/
+
+typedef struct ca_pid {
+	unsigned int pid;
+	int index;		/* -1 == disable*/
+} ca_pid_t;
+
+#define CA_RESET          _IO('o', 128)
+#define CA_GET_CAP        _IOR('o', 129, ca_caps_t)
+#define CA_GET_SLOT_INFO  _IOR('o', 130, ca_slot_info_t)
+#define CA_GET_DESCR_INFO _IOR('o', 131, ca_descr_info_t)
+#define CA_GET_MSG        _IOR('o', 132, ca_msg_t)
+#define CA_SEND_MSG       _IOW('o', 133, ca_msg_t)
+#define CA_SET_DESCR      _IOW('o', 134, ca_descr_t)
+#define CA_SET_PID        _IOW('o', 135, ca_pid_t)
+
+#ifdef CONFIG_AMLOGIC_DVB_COMPAT
+#define CA_SET_DESCR_EX   _IOW('o', 200, struct ca_descr_ex)
+#endif
+
+#endif
diff --git a/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/dvb/dmx.h b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/dvb/dmx.h
new file mode 100644
index 0000000..1c03fe5
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/dvb/dmx.h
@@ -0,0 +1,165 @@
+/*
+ * dmx.h
+ *
+ * Copyright (C) 2000 Marcus Metzler <marcus@convergence.de>
+ *                  & Ralph  Metzler <ralph@convergence.de>
+ *                    for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * 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 Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#ifndef _UAPI_DVBDMX_H_
+#define _UAPI_DVBDMX_H_
+
+#include <linux/types.h>
+#ifndef __KERNEL__
+#include <time.h>
+#endif
+
+
+#define DMX_FILTER_SIZE 16
+
+enum dmx_output
+{
+	DMX_OUT_DECODER, /* Streaming directly to decoder. */
+	DMX_OUT_TAP,     /* Output going to a memory buffer */
+			 /* (to be retrieved via the read command).*/
+	DMX_OUT_TS_TAP,  /* Output multiplexed into a new TS  */
+			 /* (to be retrieved by reading from the */
+			 /* logical DVR device).                 */
+	DMX_OUT_TSDEMUX_TAP /* Like TS_TAP but retrieved from the DMX device */
+};
+
+typedef enum dmx_output dmx_output_t;
+
+typedef enum dmx_input
+{
+	DMX_IN_FRONTEND, /* Input from a front-end device.  */
+	DMX_IN_DVR       /* Input from the logical DVR device.  */
+} dmx_input_t;
+
+
+typedef enum dmx_ts_pes
+{
+	DMX_PES_AUDIO0,
+	DMX_PES_VIDEO0,
+	DMX_PES_TELETEXT0,
+	DMX_PES_SUBTITLE0,
+	DMX_PES_PCR0,
+
+	DMX_PES_AUDIO1,
+	DMX_PES_VIDEO1,
+	DMX_PES_TELETEXT1,
+	DMX_PES_SUBTITLE1,
+	DMX_PES_PCR1,
+
+	DMX_PES_AUDIO2,
+	DMX_PES_VIDEO2,
+	DMX_PES_TELETEXT2,
+	DMX_PES_SUBTITLE2,
+	DMX_PES_PCR2,
+
+	DMX_PES_AUDIO3,
+	DMX_PES_VIDEO3,
+	DMX_PES_TELETEXT3,
+	DMX_PES_SUBTITLE3,
+	DMX_PES_PCR3,
+
+	DMX_PES_OTHER
+} dmx_pes_type_t;
+
+#define DMX_PES_AUDIO    DMX_PES_AUDIO0
+#define DMX_PES_VIDEO    DMX_PES_VIDEO0
+#define DMX_PES_TELETEXT DMX_PES_TELETEXT0
+#define DMX_PES_SUBTITLE DMX_PES_SUBTITLE0
+#define DMX_PES_PCR      DMX_PES_PCR0
+
+
+typedef struct dmx_filter
+{
+	__u8  filter[DMX_FILTER_SIZE];
+	__u8  mask[DMX_FILTER_SIZE];
+	__u8  mode[DMX_FILTER_SIZE];
+} dmx_filter_t;
+
+
+struct dmx_sct_filter_params
+{
+	__u16          pid;
+	dmx_filter_t   filter;
+	__u32          timeout;
+	__u32          flags;
+#define DMX_CHECK_CRC       1
+#define DMX_ONESHOT         2
+#define DMX_IMMEDIATE_START 4
+#define DMX_KERNEL_CLIENT   0x8000
+
+#ifdef CONFIG_AMLOGIC_DVB_COMPAT
+#define DMX_USE_SWFILTER    0x100
+#endif
+};
+
+
+struct dmx_pes_filter_params
+{
+	__u16          pid;
+	dmx_input_t    input;
+	dmx_output_t   output;
+	dmx_pes_type_t pes_type;
+	__u32          flags;
+};
+
+typedef struct dmx_caps {
+	__u32 caps;
+	int num_decoders;
+} dmx_caps_t;
+
+typedef enum dmx_source {
+	DMX_SOURCE_FRONT0 = 0,
+	DMX_SOURCE_FRONT1,
+	DMX_SOURCE_FRONT2,
+	DMX_SOURCE_FRONT3,
+	DMX_SOURCE_DVR0   = 16,
+	DMX_SOURCE_DVR1,
+	DMX_SOURCE_DVR2,
+	DMX_SOURCE_DVR3,
+
+#ifdef CONFIG_AMLOGIC_DVB_COMPAT
+	DMX_SOURCE_FRONT0_OFFSET = 100,
+	DMX_SOURCE_FRONT1_OFFSET,
+	DMX_SOURCE_FRONT2_OFFSET
+#endif
+} dmx_source_t;
+
+struct dmx_stc {
+	unsigned int num;	/* input : which STC? 0..N */
+	unsigned int base;	/* output: divisor for stc to get 90 kHz clock */
+	__u64 stc;		/* output: stc in 'base'*90 kHz units */
+};
+
+#define DMX_START                _IO('o', 41)
+#define DMX_STOP                 _IO('o', 42)
+#define DMX_SET_FILTER           _IOW('o', 43, struct dmx_sct_filter_params)
+#define DMX_SET_PES_FILTER       _IOW('o', 44, struct dmx_pes_filter_params)
+#define DMX_SET_BUFFER_SIZE      _IO('o', 45)
+#define DMX_GET_PES_PIDS         _IOR('o', 47, __u16[5])
+#define DMX_GET_CAPS             _IOR('o', 48, dmx_caps_t)
+#define DMX_SET_SOURCE           _IOW('o', 49, dmx_source_t)
+#define DMX_GET_STC              _IOWR('o', 50, struct dmx_stc)
+#define DMX_ADD_PID              _IOW('o', 51, __u16)
+#define DMX_REMOVE_PID           _IOW('o', 52, __u16)
+
+#endif /* _UAPI_DVBDMX_H_ */
diff --git a/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/dvb/frontend.h b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/dvb/frontend.h
new file mode 100644
index 0000000..96a954f
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/dvb/frontend.h
@@ -0,0 +1,836 @@
+/*
+ * frontend.h
+ *
+ * Copyright (C) 2000 Marcus Metzler <marcus@convergence.de>
+ *		    Ralph  Metzler <ralph@convergence.de>
+ *		    Holger Waechtler <holger@convergence.de>
+ *		    Andre Draszik <ad@convergence.de>
+ *		    for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * 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 Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#ifndef _DVBFRONTEND_H_
+#define _DVBFRONTEND_H_
+
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+enum fe_type {
+	FE_QPSK,
+	FE_QAM,
+	FE_OFDM,
+	FE_ATSC,
+	FE_ANALOG,
+	FE_DTMB,
+	FE_ISDBT
+};
+
+enum fe_caps {
+	FE_IS_STUPID			= 0,
+	FE_CAN_INVERSION_AUTO	= 0x1,
+	FE_CAN_FEC_1_2			= 0x2,
+	FE_CAN_FEC_2_3			= 0x4,
+	FE_CAN_FEC_3_4			= 0x8,
+	FE_CAN_FEC_4_5			= 0x10,
+	FE_CAN_FEC_5_6			= 0x20,
+	FE_CAN_FEC_6_7			= 0x40,
+	FE_CAN_FEC_7_8			= 0x80,
+	FE_CAN_FEC_8_9			= 0x100,
+	FE_CAN_FEC_AUTO			= 0x200,
+	FE_CAN_QPSK				= 0x400,
+	FE_CAN_QAM_16			= 0x800,
+	FE_CAN_QAM_32			= 0x1000,
+	FE_CAN_QAM_64			= 0x2000,
+	FE_CAN_QAM_128			= 0x4000,
+	FE_CAN_QAM_256			= 0x8000,
+	FE_CAN_QAM_AUTO			= 0x10000,
+	FE_CAN_TRANSMISSION_MODE_AUTO	= 0x20000,
+	FE_CAN_BANDWIDTH_AUTO		= 0x40000,
+	FE_CAN_GUARD_INTERVAL_AUTO	= 0x80000,
+	FE_CAN_HIERARCHY_AUTO		= 0x100000,
+	FE_CAN_8VSB			= 0x200000,
+	FE_CAN_16VSB			= 0x400000,
+/* We need more bitspace for newer APIs, indicate this. */
+	FE_HAS_EXTENDED_CAPS	= 0x800000,
+	FE_CAN_MULTISTREAM		= 0x4000000,  /* frontend supports multistream filtering */
+	FE_CAN_TURBO_FEC		= 0x8000000,  /* frontend supports "turbo fec modulation" */
+/* frontend supports "2nd generation modulation" (DVB-S2) */
+	FE_CAN_2G_MODULATION	= 0x10000000,
+	FE_NEEDS_BENDING		= 0x20000000, /* not supported anymore, don't use (frontend requires frequency bending) */
+	FE_CAN_RECOVER			= 0x40000000, /* frontend can recover from a cable unplug automatically */
+	FE_CAN_MUTE_TS			= 0x80000000  /* frontend can stop spurious TS data output */
+};
+#define FE_CAN_3_LAYER FE_CAN_MULTISTREAM
+
+struct dvb_frontend_info {
+	char       name[128];
+	enum fe_type type;	/* DEPRECATED. Use DTV_ENUM_DELSYS instead */
+	__u32      frequency_min;
+	__u32      frequency_max;
+	__u32      frequency_stepsize;
+	__u32      frequency_tolerance;
+	__u32      symbol_rate_min;
+	__u32      symbol_rate_max;
+	__u32      symbol_rate_tolerance;	/* ppm */
+	__u32      notifier_delay;		/* DEPRECATED */
+	enum fe_caps caps;
+};
+
+
+/**
+ *  Check out the DiSEqC bus spec available on http://www.eutelsat.org/ for
+ *  the meaning of this struct...
+ */
+struct dvb_diseqc_master_cmd {
+	__u8 msg [6];	/*  { framing, address, command, data [3] } */
+	__u8 msg_len;	/*  valid values are 3...6  */
+};
+
+struct dvb_diseqc_slave_reply {
+	__u8 msg [4];	/*  { framing, data [3] } */
+	__u8 msg_len;	/*  valid values are 0...4, 0 means no msg  */
+	int  timeout;	/*  return from ioctl after timeout ms with */
+};			/*  errorcode when no message was received  */
+
+enum fe_sec_voltage {
+	SEC_VOLTAGE_13,
+	SEC_VOLTAGE_18,
+	SEC_VOLTAGE_OFF,
+	SEC_VOLTAGE_ON     /*for ISDBT antenna control*/
+};
+
+enum fe_sec_tone_mode {
+	SEC_TONE_ON,
+	SEC_TONE_OFF
+};
+
+enum fe_sec_mini_cmd {
+	SEC_MINI_A,
+	SEC_MINI_B
+};
+
+/**
+ * enum fe_status - enumerates the possible frontend status
+ * @FE_HAS_SIGNAL:	found something above the noise level
+ * @FE_HAS_CARRIER:	found a DVB signal
+ * @FE_HAS_VITERBI:	FEC is stable
+ * @FE_HAS_SYNC:	found sync bytes
+ * @FE_HAS_LOCK:	everything's working
+ * @FE_TIMEDOUT:	no lock within the last ~2 seconds
+ * @FE_REINIT:		frontend was reinitialized, application is recommended
+ *			to reset DiSEqC, tone and parameters
+ */
+enum fe_status {
+	FE_HAS_SIGNAL	= 0x01,   /* found something above the noise level */
+	FE_HAS_CARRIER	= 0x02,   /* found a DVB signal  */
+	FE_HAS_VITERBI	= 0x04,   /* FEC is stable  */
+	FE_HAS_SYNC	= 0x08,   /* found sync bytes  */
+	FE_HAS_LOCK	= 0x10,   /* everything's working... */
+	FE_TIMEDOUT	= 0x20,   /* no lock within the last ~2 seconds */
+	FE_REINIT	= 0x40,    /* frontend was reinitialized,  */
+	BLINDSCAN_NONEDO = 0x80, /* not blind scan  */
+	BLINDSCAN_UPDATESTARTFREQ = 0x100, /* blind scan update start freq  */
+	BLINDSCAN_UPDATEPROCESS = 0x200, /* blind scan update process  */
+	BLINDSCAN_UPDATERESULTFREQ = 0x400/* blind scan update result  */
+}; /* application is recommended to reset */
+/* DiSEqC, tone and parameters */
+
+enum fe_spectral_inversion {
+	INVERSION_OFF,
+	INVERSION_ON,
+	INVERSION_AUTO
+};
+
+enum fe_code_rate {
+	FEC_NONE = 0,
+	FEC_1_2,
+	FEC_2_3,
+	FEC_3_4,
+	FEC_4_5,
+	FEC_5_6,
+	FEC_6_7,
+	FEC_7_8,
+	FEC_8_9,
+	FEC_AUTO,
+	FEC_3_5,
+	FEC_9_10,
+	FEC_2_5,
+};
+
+enum fe_modulation {
+	QPSK,
+	QAM_16,
+	QAM_32,
+	QAM_64,
+	QAM_128,
+	QAM_256,
+	QAM_AUTO,
+	VSB_8,
+	VSB_16,
+	PSK_8,
+	APSK_16,
+	APSK_32,
+	DQPSK,
+	QAM_4_NR,
+};
+
+enum fe_transmit_mode {
+	TRANSMISSION_MODE_2K,
+	TRANSMISSION_MODE_8K,
+	TRANSMISSION_MODE_AUTO,
+	TRANSMISSION_MODE_4K,
+	TRANSMISSION_MODE_1K,
+	TRANSMISSION_MODE_16K,
+	TRANSMISSION_MODE_32K,
+	TRANSMISSION_MODE_C1,
+	TRANSMISSION_MODE_C3780,
+};
+
+enum fe_guard_interval {
+	GUARD_INTERVAL_1_32,
+	GUARD_INTERVAL_1_16,
+	GUARD_INTERVAL_1_8,
+	GUARD_INTERVAL_1_4,
+	GUARD_INTERVAL_AUTO,
+	GUARD_INTERVAL_1_128,
+	GUARD_INTERVAL_19_128,
+	GUARD_INTERVAL_19_256,
+	GUARD_INTERVAL_PN420,
+	GUARD_INTERVAL_PN595,
+	GUARD_INTERVAL_PN945,
+};
+
+enum fe_hierarchy {
+	HIERARCHY_NONE,
+	HIERARCHY_1,
+	HIERARCHY_2,
+	HIERARCHY_4,
+	HIERARCHY_AUTO
+};
+
+enum fe_interleaving {
+	INTERLEAVING_NONE,
+	INTERLEAVING_AUTO,
+	INTERLEAVING_240,
+	INTERLEAVING_720,
+};
+
+#ifdef CONFIG_AMLOGIC_DVB_COMPAT
+struct fe_blind_scan_parameters {
+	/* minimum tuner frequency in kHz */
+	__u32 min_frequency;
+	/* maximum tuner frequency in kHz */
+	__u32 max_frequency;
+	/* minimum symbol rate in sym/sec */
+	__u32 min_symbol_rate;
+	/* maximum symbol rate in sym/sec */
+	__u32 max_symbol_rate;
+	/* search range in kHz. freq -/+freqRange will be searched */
+	__u32 frequency_range;
+	/* tuner step frequency in kHz */
+	__u32 frequency_step;
+	/* blindscan event timeout */
+	__s32 timeout;
+};
+#endif
+
+/* S2API Commands */
+#define DTV_UNDEFINED		0
+#define DTV_TUNE		1
+#define DTV_CLEAR		2
+#define DTV_FREQUENCY		3
+#define DTV_MODULATION		4
+#define DTV_BANDWIDTH_HZ	5
+#define DTV_INVERSION		6
+#define DTV_DISEQC_MASTER	7
+#define DTV_SYMBOL_RATE		8
+#define DTV_INNER_FEC		9
+#define DTV_VOLTAGE		10
+#define DTV_TONE		11
+#define DTV_PILOT		12
+#define DTV_ROLLOFF		13
+#define DTV_DISEQC_SLAVE_REPLY	14
+
+/* Basic enumeration set for querying unlimited capabilities */
+#define DTV_FE_CAPABILITY_COUNT	15
+#define DTV_FE_CAPABILITY	16
+#define DTV_DELIVERY_SYSTEM	17
+
+/* ISDB-T and ISDB-Tsb */
+#define DTV_ISDBT_PARTIAL_RECEPTION	18
+#define DTV_ISDBT_SOUND_BROADCASTING	19
+
+#define DTV_ISDBT_SB_SUBCHANNEL_ID	20
+#define DTV_ISDBT_SB_SEGMENT_IDX	21
+#define DTV_ISDBT_SB_SEGMENT_COUNT	22
+
+#define DTV_ISDBT_LAYERA_FEC			23
+#define DTV_ISDBT_LAYERA_MODULATION		24
+#define DTV_ISDBT_LAYERA_SEGMENT_COUNT		25
+#define DTV_ISDBT_LAYERA_TIME_INTERLEAVING	26
+
+#define DTV_ISDBT_LAYERB_FEC			27
+#define DTV_ISDBT_LAYERB_MODULATION		28
+#define DTV_ISDBT_LAYERB_SEGMENT_COUNT		29
+#define DTV_ISDBT_LAYERB_TIME_INTERLEAVING	30
+
+#define DTV_ISDBT_LAYERC_FEC			31
+#define DTV_ISDBT_LAYERC_MODULATION		32
+#define DTV_ISDBT_LAYERC_SEGMENT_COUNT		33
+#define DTV_ISDBT_LAYERC_TIME_INTERLEAVING	34
+
+#define DTV_API_VERSION		35
+
+#define DTV_CODE_RATE_HP	36
+#define DTV_CODE_RATE_LP	37
+#define DTV_GUARD_INTERVAL	38
+#define DTV_TRANSMISSION_MODE	39
+#define DTV_HIERARCHY		40
+
+#define DTV_ISDBT_LAYER_ENABLED	41
+
+#define DTV_STREAM_ID		42
+#define DTV_ISDBS_TS_ID_LEGACY	DTV_STREAM_ID
+#define DTV_DVBT2_PLP_ID_LEGACY	43
+
+#define DTV_ENUM_DELSYS		44
+
+#define DTV_DVBT2_PLP_ID    DTV_DVBT2_PLP_ID_LEGACY
+
+/* ATSC-MH */
+#define DTV_ATSCMH_FIC_VER		45
+#define DTV_ATSCMH_PARADE_ID		46
+#define DTV_ATSCMH_NOG			47
+#define DTV_ATSCMH_TNOG			48
+#define DTV_ATSCMH_SGN			49
+#define DTV_ATSCMH_PRC			50
+#define DTV_ATSCMH_RS_FRAME_MODE	51
+#define DTV_ATSCMH_RS_FRAME_ENSEMBLE	52
+#define DTV_ATSCMH_RS_CODE_MODE_PRI	53
+#define DTV_ATSCMH_RS_CODE_MODE_SEC	54
+#define DTV_ATSCMH_SCCC_BLOCK_MODE	55
+#define DTV_ATSCMH_SCCC_CODE_MODE_A	56
+#define DTV_ATSCMH_SCCC_CODE_MODE_B	57
+#define DTV_ATSCMH_SCCC_CODE_MODE_C	58
+#define DTV_ATSCMH_SCCC_CODE_MODE_D	59
+
+#define DTV_INTERLEAVING			60
+#define DTV_LNA					61
+
+/* Quality parameters */
+#define DTV_STAT_SIGNAL_STRENGTH	62
+#define DTV_STAT_CNR			63
+#define DTV_STAT_PRE_ERROR_BIT_COUNT	64
+#define DTV_STAT_PRE_TOTAL_BIT_COUNT	65
+#define DTV_STAT_POST_ERROR_BIT_COUNT	66
+#define DTV_STAT_POST_TOTAL_BIT_COUNT	67
+#define DTV_STAT_ERROR_BLOCK_COUNT	68
+#define DTV_STAT_TOTAL_BLOCK_COUNT	69
+
+#ifdef CONFIG_AMLOGIC_DVB_COMPAT
+
+/* Get tne TS input of the frontend */
+#define DTV_TS_INPUT                    70
+/* Blind scan */
+#define DTV_START_BLIND_SCAN            71
+#define DTV_CANCEL_BLIND_SCAN           72
+#define DTV_BLIND_SCAN_MIN_FRE          73
+#define DTV_BLIND_SCAN_MAX_FRE          74
+#define DTV_BLIND_SCAN_MIN_SRATE        75
+#define DTV_BLIND_SCAN_MAX_SRATE        76
+#define DTV_BLIND_SCAN_FRE_RANGE        77
+#define DTV_BLIND_SCAN_FRE_STEP         78
+#define DTV_BLIND_SCAN_TIMEOUT          79
+/* Blind scan end*/
+#define DTV_DELIVERY_SUB_SYSTEM			80
+#define DTV_MAX_COMMAND		DTV_DELIVERY_SUB_SYSTEM
+
+#else  /*!defined(CONFIG_AMLOGIC_DVB_COMPAT)*/
+
+#define DTV_MAX_COMMAND		DTV_STAT_TOTAL_BLOCK_COUNT
+
+#endif /*CONFIG_AMLOGIC_DVB_COMPAT*/
+
+
+enum fe_pilot {
+	PILOT_ON,
+	PILOT_OFF,
+	PILOT_AUTO,
+};
+
+enum fe_rolloff {
+	ROLLOFF_35, /* Implied value in DVB-S, default for DVB-S2 */
+	ROLLOFF_20,
+	ROLLOFF_25,
+	ROLLOFF_AUTO,
+};
+
+enum fe_delivery_system {
+	SYS_UNDEFINED,
+	SYS_DVBC_ANNEX_A,
+	SYS_DVBC_ANNEX_B,
+	SYS_DVBT,
+	SYS_DSS,
+	SYS_DVBS,
+	SYS_DVBS2,
+	SYS_DVBH,
+	SYS_ISDBT,
+	SYS_ISDBS,
+	SYS_ISDBC,
+	SYS_ATSC,
+	SYS_ATSCMH,
+	SYS_DTMB,
+	SYS_CMMB,
+	SYS_DAB,
+	SYS_DVBT2,
+	SYS_TURBO,
+	SYS_DVBC_ANNEX_C,
+	SYS_ANALOG
+};
+
+/* backward compatibility */
+#define SYS_DVBC_ANNEX_AC	SYS_DVBC_ANNEX_A
+#define SYS_DMBTH SYS_DTMB /* DMB-TH is legacy name, use DTMB instead */
+
+/* ATSC-MH */
+
+enum atscmh_sccc_block_mode {
+	ATSCMH_SCCC_BLK_SEP      = 0,
+	ATSCMH_SCCC_BLK_COMB     = 1,
+	ATSCMH_SCCC_BLK_RES      = 2,
+};
+
+enum atscmh_sccc_code_mode {
+	ATSCMH_SCCC_CODE_HLF     = 0,
+	ATSCMH_SCCC_CODE_QTR     = 1,
+	ATSCMH_SCCC_CODE_RES     = 2,
+};
+
+enum atscmh_rs_frame_ensemble {
+	ATSCMH_RSFRAME_ENS_PRI   = 0,
+	ATSCMH_RSFRAME_ENS_SEC   = 1,
+};
+
+enum atscmh_rs_frame_mode {
+	ATSCMH_RSFRAME_PRI_ONLY  = 0,
+	ATSCMH_RSFRAME_PRI_SEC   = 1,
+	ATSCMH_RSFRAME_RES       = 2,
+};
+
+enum atscmh_rs_code_mode {
+	ATSCMH_RSCODE_211_187    = 0,
+	ATSCMH_RSCODE_223_187    = 1,
+	ATSCMH_RSCODE_235_187    = 2,
+	ATSCMH_RSCODE_RES        = 3,
+};
+
+#define NO_STREAM_ID_FILTER	(~0U)
+#define LNA_AUTO                (~0U)
+
+struct dtv_cmds_h {
+	char	*name;		/* A display name for debugging purposes */
+
+	__u32	cmd;		/* A unique ID */
+
+	/* Flags */
+	__u32	set:1;		/* Either a set or get property */
+	__u32	buffer:1;	/* Does this property use the buffer? */
+	__u32	reserved:30;	/* Align */
+};
+
+/**
+ * Scale types for the quality parameters.
+ * @FE_SCALE_NOT_AVAILABLE: That QoS measure is not available. That
+ *			    could indicate a temporary or a permanent
+ *			    condition.
+ * @FE_SCALE_DECIBEL: The scale is measured in 0.001 dB steps, typically
+ *		  used on signal measures.
+ * @FE_SCALE_RELATIVE: The scale is a relative percentual measure,
+ *			ranging from 0 (0%) to 0xffff (100%).
+ * @FE_SCALE_COUNTER: The scale counts the occurrence of an event, like
+ *			bit error, block error, lapsed time.
+ */
+enum fecap_scale_params {
+	FE_SCALE_NOT_AVAILABLE = 0,
+	FE_SCALE_DECIBEL,
+	FE_SCALE_RELATIVE,
+	FE_SCALE_COUNTER
+};
+
+/**
+ * struct dtv_stats - Used for reading a DTV status property
+ *
+ * @value:	value of the measure. Should range from 0 to 0xffff;
+ * @scale:	Filled with enum fecap_scale_params - the scale
+ *		in usage for that parameter
+ *
+ * For most delivery systems, this will return a single value for each
+ * parameter.
+ * It should be noticed, however, that new OFDM delivery systems like
+ * ISDB can use different modulation types for each group of carriers.
+ * On such standards, up to 8 groups of statistics can be provided, one
+ * for each carrier group (called "layer" on ISDB).
+ * In order to be consistent with other delivery systems, the first
+ * value refers to the entire set of carriers ("global").
+ * dtv_status:scale should use the value FE_SCALE_NOT_AVAILABLE when
+ * the value for the entire group of carriers or from one specific layer
+ * is not provided by the hardware.
+ * st.len should be filled with the latest filled status + 1.
+ *
+ * In other words, for ISDB, those values should be filled like:
+ *	u.st.stat.svalue[0] = global statistics;
+ *	u.st.stat.scale[0] = FE_SCALE_DECIBEL;
+ *	u.st.stat.value[1] = layer A statistics;
+ *	u.st.stat.scale[1] = FE_SCALE_NOT_AVAILABLE (if not available);
+ *	u.st.stat.svalue[2] = layer B statistics;
+ *	u.st.stat.scale[2] = FE_SCALE_DECIBEL;
+ *	u.st.stat.svalue[3] = layer C statistics;
+ *	u.st.stat.scale[3] = FE_SCALE_DECIBEL;
+ *	u.st.len = 4;
+ */
+struct dtv_stats {
+	__u8 scale;	/* enum fecap_scale_params type */
+	union {
+		__u64 uvalue;	/* for counters and relative scales */
+		__s64 svalue;	/* for 0.001 dB measures */
+	};
+} __attribute__ ((packed));
+
+
+#define MAX_DTV_STATS   4
+
+struct dtv_fe_stats {
+	__u8 len;
+	struct dtv_stats stat[MAX_DTV_STATS];
+} __attribute__ ((packed));
+
+struct dtv_property {
+	__u32 cmd;
+	__u32 reserved[3];
+	union {
+		__u32 data;
+		struct dtv_fe_stats st;
+		struct {
+			__u8 data[32];
+			__u32 len;
+			__u32 reserved1[3];
+			void *reserved2;
+		} buffer;
+#if 0
+		struct {
+			__u8 data[32];
+			__u32 len;
+			__u32 reserved1[3];
+			__u64 reserved;
+		} reserved;
+#endif
+	} u;
+	int result;
+} __attribute__ ((packed));
+
+/* num of properties cannot exceed DTV_IOCTL_MAX_MSGS per ioctl */
+#define DTV_IOCTL_MAX_MSGS 64
+
+struct dtv_properties {
+	__u32 num;
+#if 0 && defined(CONFIG_AMLOGIC_DVB_COMPAT)
+	union {
+		struct dtv_property *props;
+		__u64                reserved;
+	};
+#else
+	struct dtv_property *props;
+#endif
+};
+
+#if defined(__DVB_CORE__) || !defined (__KERNEL__)
+
+/*
+ * DEPRECATED: The DVBv3 ioctls, structs and enums should not be used on
+ * newer programs, as it doesn't support the second generation of digital
+ * TV standards, nor supports newer delivery systems.
+ */
+
+enum fe_bandwidth {
+	BANDWIDTH_8_MHZ,
+	BANDWIDTH_7_MHZ,
+	BANDWIDTH_6_MHZ,
+	BANDWIDTH_AUTO,
+	BANDWIDTH_5_MHZ,
+	BANDWIDTH_10_MHZ,
+	BANDWIDTH_1_712_MHZ,
+};
+
+/* This is needed for legacy userspace support */
+typedef enum fe_sec_voltage fe_sec_voltage_t;
+typedef enum fe_caps fe_caps_t;
+typedef enum fe_type fe_type_t;
+typedef enum fe_sec_tone_mode fe_sec_tone_mode_t;
+typedef enum fe_sec_mini_cmd fe_sec_mini_cmd_t;
+typedef enum fe_status fe_status_t;
+typedef enum fe_spectral_inversion fe_spectral_inversion_t;
+typedef enum fe_code_rate fe_code_rate_t;
+typedef enum fe_modulation fe_modulation_t;
+typedef enum fe_transmit_mode fe_transmit_mode_t;
+typedef enum fe_bandwidth fe_bandwidth_t;
+typedef enum fe_guard_interval fe_guard_interval_t;
+typedef enum fe_hierarchy fe_hierarchy_t;
+typedef enum fe_pilot fe_pilot_t;
+typedef enum fe_rolloff fe_rolloff_t;
+
+typedef enum fe_delivery_system fe_delivery_system_t;
+
+enum fe_ofdm_mode {
+	OFDM_DVBT,
+	OFDM_DVBT2,
+};
+struct dvb_qpsk_parameters {
+	__u32		symbol_rate;  /* symbol rate in Symbols per second */
+	fe_code_rate_t	fec_inner;    /* forward error correction (see above) */
+};
+
+struct dvb_qam_parameters {
+	__u32		symbol_rate; /* symbol rate in Symbols per second */
+	fe_code_rate_t	fec_inner;   /* forward error correction (see above) */
+	fe_modulation_t	modulation;  /* modulation type (see above) */
+};
+
+struct dvb_vsb_parameters {
+	fe_modulation_t	modulation;  /* modulation type (see above) */
+};
+
+struct dvb_ofdm_parameters {
+	fe_bandwidth_t      bandwidth;
+	fe_code_rate_t      code_rate_HP;  /* high priority stream code rate */
+	fe_code_rate_t      code_rate_LP;  /* low priority stream code rate */
+	fe_modulation_t     constellation; /* modulation type (see above) */
+	fe_transmit_mode_t  transmission_mode;
+	fe_guard_interval_t guard_interval;
+	fe_hierarchy_t      hierarchy_information;
+};
+#define ANALOG_FLAG_ENABLE_AFC                 0X00000001
+#define  ANALOG_FLAG_MANUL_SCAN                0x00000011
+struct dvb_analog_parameters {
+	/*V4L2_TUNER_MODE_MONO,V4L2_TUNER_MODE_STEREO,*/
+	/*V4L2_TUNER_MODE_LANG2,V4L2_TUNER_MODE_SAP,*/
+	/*V4L2_TUNER_MODE_LANG1,V4L2_TUNER_MODE_LANG1_LANG2 */
+	unsigned int audmode;
+	unsigned int soundsys;	/*A2,BTSC,EIAJ,NICAM */
+	v4l2_std_id std;
+	unsigned int flag;
+	unsigned int afc_range;
+};
+
+struct dvb_frontend_parameters_orig {
+	/* (absolute) frequency in Hz for DVB-C/DVB-T/ATSC */
+	__u32 frequency;
+	/* intermediate frequency in kHz for DVB-S */
+	fe_spectral_inversion_t inversion;
+	union {
+		struct dvb_qpsk_parameters qpsk;	/* DVB-S */
+		struct dvb_qam_parameters  qam;		/* DVB-C */
+		struct dvb_ofdm_parameters ofdm;	/* DVB-T */
+		struct dvb_vsb_parameters vsb;		/* ATSC */
+	} u;
+};
+
+#ifdef CONFIG_AMLOGIC_DVB_COMPAT
+
+struct dvb_frontend_parameters {
+	__u32 frequency;  /* (absolute) frequency in Hz for DVB-C/DVB-T/ATSC */
+			  /* intermediate frequency in kHz for DVB-S */
+	fe_spectral_inversion_t inversion;
+	union {
+		struct dvb_qpsk_parameters qpsk;	/* DVB-S */
+		struct dvb_qam_parameters  qam;		/* DVB-C */
+		struct dvb_ofdm_parameters ofdm;	/* DVB-T */
+		struct dvb_vsb_parameters vsb;		/* ATSC */
+		struct dvb_analog_parameters analog;
+		/* Add extenstion data here */
+	} u;
+};
+
+/*
+static char dvb_check_frontend_parameters_size[
+	(sizeof(struct dvb_frontend_parameters_ex)
+	== sizeof(struct dvb_frontend_parameters)) ? 1 : -1]
+	__attribute__((__unused__));*/
+
+#endif /*CONFIG_AMLOGIC_DVB_COMPAT*/
+
+struct dvb_frontend_event_orig {
+	fe_status_t status;
+	struct dvb_frontend_parameters_orig parameters;
+};
+
+struct dvb_frontend_event {
+	fe_status_t status;
+	struct dvb_frontend_parameters parameters;
+};
+/* Satellite blind scan event */
+struct dvbsx_blindscanevent {
+	enum fe_status status;
+	union {
+		/* The percentage completion of the*/
+		/*blind scan procedure. A value of*/
+		/*100 indicates that the blind scan*/
+		/*is finished. */
+		__u16 m_uiprogress;
+		/*The start scan frequency in units of kHz.*/
+		/*The minimum value depends on the tuner*/
+		/*specification.*/
+		__u32 m_uistartfreq_khz;
+		/* Blind scan channel info. */
+		struct dvb_frontend_parameters parameters;
+	} u;
+};
+#endif
+
+#define FE_SET_PROPERTY		   _IOW('o', 82, struct dtv_properties)
+#define FE_GET_PROPERTY		   _IOR('o', 83, struct dtv_properties)
+/*for atv*/
+struct tuner_status_s {
+	unsigned int frequency;
+	unsigned int rssi;
+	unsigned char mode;/*dtv:0 or atv:1*/
+	unsigned char tuner_locked;/*notlocked:0,locked:1*/
+	union {
+		void *ressrved;
+		__u64 reserved1;
+	};
+};
+
+
+struct atv_status_s {
+	unsigned char atv_lock;/*notlocked:0,locked 1*/
+	v4l2_std_id	  std;
+	unsigned int  audmode;
+	int  snr;
+	int  afc;
+	union {
+		void *resrvred;
+		__u64 reserved1;
+	};
+};
+
+struct sound_status_s {
+	unsigned short sound_sys;/*A2DK/A2BG/NICAM BG/NICAM DK/BTSC/EIAJ*/
+	unsigned short sound_mode;/*SETERO/DUAL/MONO/SAP*/
+	union {
+		void *resrvred;
+		__u64 reserved1;
+	};
+};
+
+
+enum tuner_param_cmd_e {
+	TUNER_CMD_AUDIO_MUTE = 0x0000,
+	TUNER_CMD_AUDIO_ON,
+	TUNER_CMD_TUNER_POWER_ON,
+	TUNER_CMD_TUNER_POWER_DOWN,
+	TUNER_CMD_SET_VOLUME,
+	TUNER_CMD_SET_LEAP_SETP_SIZE,
+	TUNER_CMD_GET_MONO_MODE,
+	TUNER_CMD_SET_BEST_LOCK_RANGE,
+	TUNER_CMD_GET_BEST_LOCK_RANGE,
+	TUNER_CMD_SET_CVBS_AMP_OUT,
+	TUNER_CMD_GET_CVBS_AMP_OUT,
+	TUNER_CMD_NULL,
+};
+
+
+/*parameter for set param box*/
+struct tuner_param_s {
+	enum tuner_param_cmd_e cmd;
+	unsigned int      parm;
+	unsigned int	resvred;
+};
+
+
+enum fe_layer {
+	Layer_A_B_C,
+	Layer_A,
+	Layer_B,
+	Layer_C,
+};
+
+// typedef struct dvb_analog_parameters dvb_analog_parameters_t;
+// typedef struct tuner_status_s tuner_status_t;
+// typedef struct atv_status_s atv_status_t;
+// typedef struct sound_status_s sound_status_t;
+// typedef enum tuner_param_cmd_e tuner_param_cmd_t;
+// typedef struct tuner_param_s tuner_param_t;
+// typedef enum fe_layer fe_layer_t;
+// typedef enum fe_ofdm_mode fe_ofdm_mode_t;
+
+
+/* Satellite blind scan settings */
+struct dvbsx_blindscanpara {
+	__u32 minfrequency;			/* minimum tuner frequency in kHz */
+	__u32 maxfrequency;			/* maximum tuner frequency in kHz */
+	__u32 minSymbolRate;		/* minimum symbol rate in sym/sec */
+	__u32 maxSymbolRate;		/* maximum symbol rate in sym/sec */
+	__u32 frequencyRange;		/* search range in kHz. freq -/+freqRange will be searched */
+	__u32 frequencyStep;			/* tuner step frequency in kHz */
+	__s32 timeout;				/* blindscan event timeout*/
+};
+
+/**
+ * When set, this flag will disable any zigzagging or other "normal" tuning
+ * behaviour. Additionally, there will be no automatic monitoring of the lock
+ * status, and hence no frontend events will be generated. If a frontend device
+ * is closed, this flag will be automatically turned off when the device is
+ * reopened read-write.
+ */
+#define FE_TUNE_MODE_ONESHOT 0x01
+
+#define FE_GET_INFO		   _IOR('o', 61, struct dvb_frontend_info)
+
+#define FE_DISEQC_RESET_OVERLOAD   _IO('o', 62)
+#define FE_DISEQC_SEND_MASTER_CMD  _IOW('o', 63, struct dvb_diseqc_master_cmd)
+#define FE_DISEQC_RECV_SLAVE_REPLY _IOR('o', 64, struct dvb_diseqc_slave_reply)
+#define FE_DISEQC_SEND_BURST       _IO('o', 65)  /* fe_sec_mini_cmd_t */
+
+#define FE_SET_TONE		   _IO('o', 66)  /* fe_sec_tone_mode_t */
+#define FE_SET_VOLTAGE		   _IO('o', 67)  /* fe_sec_voltage_t */
+#define FE_ENABLE_HIGH_LNB_VOLTAGE _IO('o', 68)  /* int */
+
+#define FE_READ_STATUS		   _IOR('o', 69, fe_status_t)
+#define FE_READ_BER		   _IOR('o', 70, __u32)
+#define FE_READ_SIGNAL_STRENGTH    _IOR('o', 71, __u16)
+#define FE_READ_SNR		   _IOR('o', 72, __u16)
+#define FE_READ_UNCORRECTED_BLOCKS _IOR('o', 73, __u32)
+
+#define FE_SET_FRONTEND		   _IOW('o', 76, struct dvb_frontend_parameters_orig)
+#define FE_GET_FRONTEND		   _IOR('o', 77, struct dvb_frontend_parameters_orig)
+#define FE_SET_FRONTEND_TUNE_MODE  _IO('o', 81) /* unsigned int */
+#define FE_GET_EVENT		   _IOR('o', 78, struct dvb_frontend_event_orig)
+
+#define FE_DISHNETWORK_SEND_LEGACY_CMD _IO('o', 80) /* unsigned int */
+
+/*need del this ioctl, used set PROPERTY instead*/
+#define FE_SET_DELAY               _IO('o', 100)
+#define FE_READ_AFC                _IOR('o', 91, __u32)
+#define FE_FINE_TUNE               _IOW('o', 92, __u32)
+#define FE_READ_TUNER_STATUS       _IOR('o', 93, struct tuner_status_s)
+#define FE_READ_ANALOG_STATUS      _IOR('o', 94, struct atv_status_s)
+#define FE_READ_SD_STATUS          _IOR('o', 95, struct sound_status_s)
+/*set & get the tuner parameters only atv*/
+#define FE_SET_PARAM_BOX           _IOWR('o', 97, struct tuner_param_s)
+#define FE_SET_AFC                 _IOW('o', 98, __u32)
+
+#endif /*_DVBFRONTEND_H_*/
diff --git a/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/dvb/net.h b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/dvb/net.h
new file mode 100644
index 0000000..f451e7e
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/dvb/net.h
@@ -0,0 +1,52 @@
+/*
+ * net.h
+ *
+ * Copyright (C) 2000 Marcus Metzler <marcus@convergence.de>
+ *                  & Ralph  Metzler <ralph@convergence.de>
+ *                    for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * 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 Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#ifndef _DVBNET_H_
+#define _DVBNET_H_
+
+#include <linux/types.h>
+
+struct dvb_net_if {
+	__u16 pid;
+	__u16 if_num;
+	__u8  feedtype;
+#define DVB_NET_FEEDTYPE_MPE 0	/* multi protocol encapsulation */
+#define DVB_NET_FEEDTYPE_ULE 1	/* ultra lightweight encapsulation */
+};
+
+
+#define NET_ADD_IF    _IOWR('o', 52, struct dvb_net_if)
+#define NET_REMOVE_IF _IO('o', 53)
+#define NET_GET_IF    _IOWR('o', 54, struct dvb_net_if)
+
+
+/* binary compatibility cruft: */
+struct __dvb_net_if_old {
+	__u16 pid;
+	__u16 if_num;
+};
+#define __NET_ADD_IF_OLD _IOWR('o', 52, struct __dvb_net_if_old)
+#define __NET_GET_IF_OLD _IOWR('o', 54, struct __dvb_net_if_old)
+
+
+#endif /*_DVBNET_H_*/
diff --git a/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/dvb/osd.h b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/dvb/osd.h
new file mode 100644
index 0000000..880e684
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/dvb/osd.h
@@ -0,0 +1,144 @@
+/*
+ * osd.h
+ *
+ * Copyright (C) 2001 Ralph  Metzler <ralph@convergence.de>
+ *                  & Marcus Metzler <marcus@convergence.de>
+ *                    for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Lesser Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * 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 Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#ifndef _DVBOSD_H_
+#define _DVBOSD_H_
+
+#include <linux/compiler.h>
+
+typedef enum {
+  // All functions return -2 on "not open"
+  OSD_Close=1,    // ()
+  // Disables OSD and releases the buffers
+  // returns 0 on success
+  OSD_Open,       // (x0,y0,x1,y1,BitPerPixel[2/4/8](color&0x0F),mix[0..15](color&0xF0))
+  // Opens OSD with this size and bit depth
+  // returns 0 on success, -1 on DRAM allocation error, -2 on "already open"
+  OSD_Show,       // ()
+  // enables OSD mode
+  // returns 0 on success
+  OSD_Hide,       // ()
+  // disables OSD mode
+  // returns 0 on success
+  OSD_Clear,      // ()
+  // Sets all pixel to color 0
+  // returns 0 on success
+  OSD_Fill,       // (color)
+  // Sets all pixel to color <col>
+  // returns 0 on success
+  OSD_SetColor,   // (color,R{x0},G{y0},B{x1},opacity{y1})
+  // set palette entry <num> to <r,g,b>, <mix> and <trans> apply
+  // R,G,B: 0..255
+  // R=Red, G=Green, B=Blue
+  // opacity=0:      pixel opacity 0% (only video pixel shows)
+  // opacity=1..254: pixel opacity as specified in header
+  // opacity=255:    pixel opacity 100% (only OSD pixel shows)
+  // returns 0 on success, -1 on error
+  OSD_SetPalette, // (firstcolor{color},lastcolor{x0},data)
+  // Set a number of entries in the palette
+  // sets the entries "firstcolor" through "lastcolor" from the array "data"
+  // data has 4 byte for each color:
+  // R,G,B, and a opacity value: 0->transparent, 1..254->mix, 255->pixel
+  OSD_SetTrans,   // (transparency{color})
+  // Sets transparency of mixed pixel (0..15)
+  // returns 0 on success
+  OSD_SetPixel,   // (x0,y0,color)
+  // sets pixel <x>,<y> to color number <col>
+  // returns 0 on success, -1 on error
+  OSD_GetPixel,   // (x0,y0)
+  // returns color number of pixel <x>,<y>,  or -1
+  OSD_SetRow,     // (x0,y0,x1,data)
+  // fills pixels x0,y through  x1,y with the content of data[]
+  // returns 0 on success, -1 on clipping all pixel (no pixel drawn)
+  OSD_SetBlock,   // (x0,y0,x1,y1,increment{color},data)
+  // fills pixels x0,y0 through  x1,y1 with the content of data[]
+  // inc contains the width of one line in the data block,
+  // inc<=0 uses blockwidth as linewidth
+  // returns 0 on success, -1 on clipping all pixel
+  OSD_FillRow,    // (x0,y0,x1,color)
+  // fills pixels x0,y through  x1,y with the color <col>
+  // returns 0 on success, -1 on clipping all pixel
+  OSD_FillBlock,  // (x0,y0,x1,y1,color)
+  // fills pixels x0,y0 through  x1,y1 with the color <col>
+  // returns 0 on success, -1 on clipping all pixel
+  OSD_Line,       // (x0,y0,x1,y1,color)
+  // draw a line from x0,y0 to x1,y1 with the color <col>
+  // returns 0 on success
+  OSD_Query,      // (x0,y0,x1,y1,xasp{color}}), yasp=11
+  // fills parameters with the picture dimensions and the pixel aspect ratio
+  // returns 0 on success
+  OSD_Test,       // ()
+  // draws a test picture. for debugging purposes only
+  // returns 0 on success
+// TODO: remove "test" in final version
+  OSD_Text,       // (x0,y0,size,color,text)
+  OSD_SetWindow, //  (x0) set window with number 0<x0<8 as current
+  OSD_MoveWindow, //  move current window to (x0, y0)
+  OSD_OpenRaw,	// Open other types of OSD windows
+} OSD_Command;
+
+typedef struct osd_cmd_s {
+	OSD_Command cmd;
+	int x0;
+	int y0;
+	int x1;
+	int y1;
+	int color;
+	void __user *data;
+} osd_cmd_t;
+
+/* OSD_OpenRaw: set 'color' to desired window type */
+typedef enum {
+	OSD_BITMAP1,           /* 1 bit bitmap */
+	OSD_BITMAP2,           /* 2 bit bitmap */
+	OSD_BITMAP4,           /* 4 bit bitmap */
+	OSD_BITMAP8,           /* 8 bit bitmap */
+	OSD_BITMAP1HR,         /* 1 Bit bitmap half resolution */
+	OSD_BITMAP2HR,         /* 2 bit bitmap half resolution */
+	OSD_BITMAP4HR,         /* 4 bit bitmap half resolution */
+	OSD_BITMAP8HR,         /* 8 bit bitmap half resolution */
+	OSD_YCRCB422,          /* 4:2:2 YCRCB Graphic Display */
+	OSD_YCRCB444,          /* 4:4:4 YCRCB Graphic Display */
+	OSD_YCRCB444HR,        /* 4:4:4 YCRCB graphic half resolution */
+	OSD_VIDEOTSIZE,        /* True Size Normal MPEG Video Display */
+	OSD_VIDEOHSIZE,        /* MPEG Video Display Half Resolution */
+	OSD_VIDEOQSIZE,        /* MPEG Video Display Quarter Resolution */
+	OSD_VIDEODSIZE,        /* MPEG Video Display Double Resolution */
+	OSD_VIDEOTHSIZE,       /* True Size MPEG Video Display Half Resolution */
+	OSD_VIDEOTQSIZE,       /* True Size MPEG Video Display Quarter Resolution*/
+	OSD_VIDEOTDSIZE,       /* True Size MPEG Video Display Double Resolution */
+	OSD_VIDEONSIZE,        /* Full Size MPEG Video Display */
+	OSD_CURSOR             /* Cursor */
+} osd_raw_window_t;
+
+typedef struct osd_cap_s {
+	int  cmd;
+#define OSD_CAP_MEMSIZE         1  /* memory size */
+	long val;
+} osd_cap_t;
+
+
+#define OSD_SEND_CMD            _IOW('o', 160, osd_cmd_t)
+#define OSD_GET_CAPABILITY      _IOR('o', 161, osd_cap_t)
+
+#endif
diff --git a/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/dvb/version.h b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/dvb/version.h
new file mode 100644
index 0000000..e53e2ad
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/dvb/version.h
@@ -0,0 +1,29 @@
+/*
+ * version.h
+ *
+ * Copyright (C) 2000 Holger Waechtler <holger@convergence.de>
+ *                    for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * 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 Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#ifndef _DVBVERSION_H_
+#define _DVBVERSION_H_
+
+#define DVB_API_VERSION 5
+#define DVB_API_VERSION_MINOR 10
+
+#endif /*_DVBVERSION_H_*/
diff --git a/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/dvb/video.h b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/dvb/video.h
new file mode 100644
index 0000000..c5782fb
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/linux/dvb/video.h
@@ -0,0 +1,275 @@
+/*
+ * video.h
+ *
+ * Copyright (C) 2000 Marcus Metzler <marcus@convergence.de>
+ *                  & Ralph  Metzler <ralph@convergence.de>
+ *                    for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * 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 Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#ifndef _UAPI_DVBVIDEO_H_
+#define _UAPI_DVBVIDEO_H_
+
+#include <linux/types.h>
+#ifndef __KERNEL__
+#include <stdint.h>
+#include <time.h>
+#endif
+
+typedef enum {
+	VIDEO_FORMAT_4_3,     /* Select 4:3 format */
+	VIDEO_FORMAT_16_9,    /* Select 16:9 format. */
+	VIDEO_FORMAT_221_1    /* 2.21:1 */
+} video_format_t;
+
+
+typedef enum {
+	 VIDEO_SYSTEM_PAL,
+	 VIDEO_SYSTEM_NTSC,
+	 VIDEO_SYSTEM_PALN,
+	 VIDEO_SYSTEM_PALNc,
+	 VIDEO_SYSTEM_PALM,
+	 VIDEO_SYSTEM_NTSC60,
+	 VIDEO_SYSTEM_PAL60,
+	 VIDEO_SYSTEM_PALM60
+} video_system_t;
+
+
+typedef enum {
+	VIDEO_PAN_SCAN,       /* use pan and scan format */
+	VIDEO_LETTER_BOX,     /* use letterbox format */
+	VIDEO_CENTER_CUT_OUT  /* use center cut out format */
+} video_displayformat_t;
+
+typedef struct {
+	int w;
+	int h;
+	video_format_t aspect_ratio;
+} video_size_t;
+
+typedef enum {
+	VIDEO_SOURCE_DEMUX, /* Select the demux as the main source */
+	VIDEO_SOURCE_MEMORY /* If this source is selected, the stream
+			       comes from the user through the write
+			       system call */
+} video_stream_source_t;
+
+
+typedef enum {
+	VIDEO_STOPPED, /* Video is stopped */
+	VIDEO_PLAYING, /* Video is currently playing */
+	VIDEO_FREEZED  /* Video is freezed */
+} video_play_state_t;
+
+
+/* Decoder commands */
+#define VIDEO_CMD_PLAY        (0)
+#define VIDEO_CMD_STOP        (1)
+#define VIDEO_CMD_FREEZE      (2)
+#define VIDEO_CMD_CONTINUE    (3)
+
+/* Flags for VIDEO_CMD_FREEZE */
+#define VIDEO_CMD_FREEZE_TO_BLACK     	(1 << 0)
+
+/* Flags for VIDEO_CMD_STOP */
+#define VIDEO_CMD_STOP_TO_BLACK      	(1 << 0)
+#define VIDEO_CMD_STOP_IMMEDIATELY     	(1 << 1)
+
+/* Play input formats: */
+/* The decoder has no special format requirements */
+#define VIDEO_PLAY_FMT_NONE         (0)
+/* The decoder requires full GOPs */
+#define VIDEO_PLAY_FMT_GOP          (1)
+
+/* The structure must be zeroed before use by the application
+   This ensures it can be extended safely in the future. */
+struct video_command {
+	__u32 cmd;
+	__u32 flags;
+	union {
+		struct {
+			__u64 pts;
+		} stop;
+
+		struct {
+			/* 0 or 1000 specifies normal speed,
+			   1 specifies forward single stepping,
+			   -1 specifies backward single stepping,
+			   >1: playback at speed/1000 of the normal speed,
+			   <-1: reverse playback at (-speed/1000) of the normal speed. */
+			__s32 speed;
+			__u32 format;
+		} play;
+
+		struct {
+			__u32 data[16];
+		} raw;
+	};
+};
+
+/* FIELD_UNKNOWN can be used if the hardware does not know whether
+   the Vsync is for an odd, even or progressive (i.e. non-interlaced)
+   field. */
+#define VIDEO_VSYNC_FIELD_UNKNOWN  	(0)
+#define VIDEO_VSYNC_FIELD_ODD 		(1)
+#define VIDEO_VSYNC_FIELD_EVEN		(2)
+#define VIDEO_VSYNC_FIELD_PROGRESSIVE	(3)
+
+struct video_event {
+	__s32 type;
+#define VIDEO_EVENT_SIZE_CHANGED	1
+#define VIDEO_EVENT_FRAME_RATE_CHANGED	2
+#define VIDEO_EVENT_DECODER_STOPPED 	3
+#define VIDEO_EVENT_VSYNC 		4
+	__kernel_time_t timestamp;
+	union {
+		video_size_t size;
+		unsigned int frame_rate;	/* in frames per 1000sec */
+		unsigned char vsync_field;	/* unknown/odd/even/progressive */
+	} u;
+};
+
+
+struct video_status {
+	int                   video_blank;   /* blank video on freeze? */
+	video_play_state_t    play_state;    /* current state of playback */
+	video_stream_source_t stream_source; /* current source (demux/memory) */
+	video_format_t        video_format;  /* current aspect ratio of stream*/
+	video_displayformat_t display_format;/* selected cropping mode */
+};
+
+
+struct video_still_picture {
+	char __user *iFrame;        /* pointer to a single iframe in memory */
+	__s32 size;
+};
+
+
+typedef
+struct video_highlight {
+	int     active;      /*    1=show highlight, 0=hide highlight */
+	__u8    contrast1;   /*    7- 4  Pattern pixel contrast */
+			     /*    3- 0  Background pixel contrast */
+	__u8    contrast2;   /*    7- 4  Emphasis pixel-2 contrast */
+			     /*    3- 0  Emphasis pixel-1 contrast */
+	__u8    color1;      /*    7- 4  Pattern pixel color */
+			     /*    3- 0  Background pixel color */
+	__u8    color2;      /*    7- 4  Emphasis pixel-2 color */
+			     /*    3- 0  Emphasis pixel-1 color */
+	__u32    ypos;       /*   23-22  auto action mode */
+			     /*   21-12  start y */
+			     /*    9- 0  end y */
+	__u32    xpos;       /*   23-22  button color number */
+			     /*   21-12  start x */
+			     /*    9- 0  end x */
+} video_highlight_t;
+
+
+typedef struct video_spu {
+	int active;
+	int stream_id;
+} video_spu_t;
+
+
+typedef struct video_spu_palette {      /* SPU Palette information */
+	int length;
+	__u8 __user *palette;
+} video_spu_palette_t;
+
+
+typedef struct video_navi_pack {
+	int length;          /* 0 ... 1024 */
+	__u8 data[1024];
+} video_navi_pack_t;
+
+
+typedef __u16 video_attributes_t;
+/*   bits: descr. */
+/*   15-14 Video compression mode (0=MPEG-1, 1=MPEG-2) */
+/*   13-12 TV system (0=525/60, 1=625/50) */
+/*   11-10 Aspect ratio (0=4:3, 3=16:9) */
+/*    9- 8 permitted display mode on 4:3 monitor (0=both, 1=only pan-sca */
+/*    7    line 21-1 data present in GOP (1=yes, 0=no) */
+/*    6    line 21-2 data present in GOP (1=yes, 0=no) */
+/*    5- 3 source resolution (0=720x480/576, 1=704x480/576, 2=352x480/57 */
+/*    2    source letterboxed (1=yes, 0=no) */
+/*    0    film/camera mode (0=
+ *camera, 1=film (625/50 only)) */
+
+
+/* bit definitions for capabilities: */
+/* can the hardware decode MPEG1 and/or MPEG2? */
+#define VIDEO_CAP_MPEG1   1
+#define VIDEO_CAP_MPEG2   2
+/* can you send a system and/or program stream to video device?
+   (you still have to open the video and the audio device but only
+    send the stream to the video device) */
+#define VIDEO_CAP_SYS     4
+#define VIDEO_CAP_PROG    8
+/* can the driver also handle SPU, NAVI and CSS encoded data?
+   (CSS API is not present yet) */
+#define VIDEO_CAP_SPU    16
+#define VIDEO_CAP_NAVI   32
+#define VIDEO_CAP_CSS    64
+
+
+#define VIDEO_STOP                 _IO('o', 21)
+#define VIDEO_PLAY                 _IO('o', 22)
+#define VIDEO_FREEZE               _IO('o', 23)
+#define VIDEO_CONTINUE             _IO('o', 24)
+#define VIDEO_SELECT_SOURCE        _IO('o', 25)
+#define VIDEO_SET_BLANK            _IO('o', 26)
+#define VIDEO_GET_STATUS           _IOR('o', 27, struct video_status)
+#define VIDEO_GET_EVENT            _IOR('o', 28, struct video_event)
+#define VIDEO_SET_DISPLAY_FORMAT   _IO('o', 29)
+#define VIDEO_STILLPICTURE         _IOW('o', 30, struct video_still_picture)
+#define VIDEO_FAST_FORWARD         _IO('o', 31)
+#define VIDEO_SLOWMOTION           _IO('o', 32)
+#define VIDEO_GET_CAPABILITIES     _IOR('o', 33, unsigned int)
+#define VIDEO_CLEAR_BUFFER         _IO('o',  34)
+#define VIDEO_SET_ID               _IO('o', 35)
+#define VIDEO_SET_STREAMTYPE       _IO('o', 36)
+#define VIDEO_SET_FORMAT           _IO('o', 37)
+#define VIDEO_SET_SYSTEM           _IO('o', 38)
+#define VIDEO_SET_HIGHLIGHT        _IOW('o', 39, video_highlight_t)
+#define VIDEO_SET_SPU              _IOW('o', 50, video_spu_t)
+#define VIDEO_SET_SPU_PALETTE      _IOW('o', 51, video_spu_palette_t)
+#define VIDEO_GET_NAVI             _IOR('o', 52, video_navi_pack_t)
+#define VIDEO_SET_ATTRIBUTES       _IO('o', 53)
+#define VIDEO_GET_SIZE             _IOR('o', 55, video_size_t)
+#define VIDEO_GET_FRAME_RATE       _IOR('o', 56, unsigned int)
+
+/**
+ * VIDEO_GET_PTS
+ *
+ * Read the 33 bit presentation time stamp as defined
+ * in ITU T-REC-H.222.0 / ISO/IEC 13818-1.
+ *
+ * The PTS should belong to the currently played
+ * frame if possible, but may also be a value close to it
+ * like the PTS of the last decoded frame or the last PTS
+ * extracted by the PES parser.
+ */
+#define VIDEO_GET_PTS              _IOR('o', 57, __u64)
+
+/* Read the number of displayed frames since the decoder was started */
+#define VIDEO_GET_FRAME_COUNT  	   _IOR('o', 58, __u64)
+
+#define VIDEO_COMMAND     	   _IOWR('o', 59, struct video_command)
+#define VIDEO_TRY_COMMAND 	   _IOWR('o', 60, struct video_command)
+
+#endif /* _UAPI_DVBVIDEO_H_ */
diff --git a/test/am_ca_key_test/inject_record_t5d/include/ndk/include/tvin_vbi.h b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/tvin_vbi.h
new file mode 100644
index 0000000..e9cd6cd
--- /dev/null
+++ b/test/am_ca_key_test/inject_record_t5d/include/ndk/include/tvin_vbi.h
@@ -0,0 +1,238 @@
+/*******************************************************************
+* Copyright (c) 2014 Amlogic, Inc. All rights reserved.
+*
+* This source code is subject to the terms and conditions defined in the
+* file 'LICENSE' which is part of this source code package.
+*
+*  File name: tvin_vbi.h
+*  Description: IO function, structure,
+enum, used in TVIN vbi sub-module processing
+*  VBI in M6TV IC only support CC format
+*******************************************************************/
+
+#ifndef TVIN_VBI_H_
+#define TVIN_VBI_H_
+
+#include <linux/types.h>
+
+/* *************************************************** */
+/* *** macro definitions ********************************************* */
+/* ****************************************************** */
+/* defines for vbi spec */
+/* vbi type id */
+#define VBI_ID_CC                  0
+#define VBI_ID_TT                  3
+#define VBI_ID_WSS625              4
+#define VBI_ID_WSSJ                5
+#define VBI_ID_VPS                 6
+#define MAX_PACKET_TYPE            VBI_ID_VPS
+
+/* vbi package data bytes */
+#define VBI_PCNT_USCC              2
+#define VBI_PCNT_WSS625            2
+#define VBI_PCNT_WSSJ              3
+#define VBI_PCNT_VPS               8
+
+/* teletext package data bytes */
+#define VBI_PCNT_TT_625A           37
+#define VBI_PCNT_TT_625B           42
+#define VBI_PCNT_TT_625C           33
+#define VBI_PCNT_TT_625D           34
+#define VBI_PCNT_TT_525B           34
+#define VBI_PCNT_TT_525C           33
+#define VBI_PCNT_TT_525D           34
+
+/* Teletext system type */
+#define VBI_SYS_TT_625A            0
+#define VBI_SYS_TT_625B            1
+#define VBI_SYS_TT_625C            2
+#define VBI_SYS_TT_625D            3
+#define VBI_SYS_TT_525B            5
+#define VBI_SYS_TT_525C            6
+#define VBI_SYS_TT_525D            7
+
+
+/* vbi data type setting */
+#define VBI_DATA_TYPE_NULL         0x00
+#define VBI_DATA_TYPE_USCC         0x11
+#define VBI_DATA_TYPE_EUROCC       0x22
+#define VBI_DATA_TYPE_VPS          0x33
+#define VBI_DATA_TYPE_TT_625A      0x55
+#define VBI_DATA_TYPE_TT_625B      0x66
+#define VBI_DATA_TYPE_TT_625C      0x77
+#define VBI_DATA_TYPE_TT_625D      0x88
+#define VBI_DATA_TYPE_TT_525B      0x99
+#define VBI_DATA_TYPE_TT_525C      0xaa
+#define VBI_DATA_TYPE_TT_525D      0xbb
+#define VBI_DATA_TYPE_WSS625       0xcc
+#define VBI_DATA_TYPE_WSSJ         0xdd
+
+/* vbi start line: unit is hcount value */
+#define VBI_START_CC		0x54
+#define VBI_START_WSS		0x54
+#define VBI_START_TT		0x82
+#define VBI_START_VPS		0x82
+
+
+/* vbi start code,TT start code is programmable by software,
+but our ic use the programmable value as reverse!!
+so wo should use the reverse value */
+#define VBI_START_CODE_USCC         0x01
+#define VBI_START_CODE_EUROCC       0x01
+#define VBI_START_CODE_VPS          0x8a99
+#define VBI_START_CODE_TT_625A      0xe7
+#define VBI_START_CODE_TT_625A_REVERSE      0xe7
+#define VBI_START_CODE_TT_625B      0xe4
+#define VBI_START_CODE_TT_625B_REVERSE      0x27
+#define VBI_START_CODE_TT_625C      0xe7
+#define VBI_START_CODE_TT_625C_REVERSE      0xe7
+#define VBI_START_CODE_TT_625D      0xe5
+#define VBI_START_CODE_TT_625D_REVERSE      0xa7
+#define VBI_START_CODE_TT_525B      0xe4
+#define VBI_START_CODE_TT_525B_REVERSE      0x27
+#define VBI_START_CODE_TT_525C      0xe7
+#define VBI_START_CODE_TT_525C_REVERSE      0xe7
+#define VBI_START_CODE_TT_525D      0xe5
+#define VBI_START_CODE_TT_525D_REVERSE      0xa7
+#define VBI_START_CODE_WSS625       0x1e3c1f
+#define VBI_START_CODE_WSSJ         0x02
+
+/*
+DTO calculation method:
+For WSSJ:
+DTO_Value = output_sampling_rate/(3.579545)*(2^11)
+For WSS625
+DTO_Value = output_sampling_rate*3/10 * (2^11)
+For CLOSE CAPTION
+DTO_Value = output_sampling_rate/(4*vbi_data_rate) * (2^11)
+Otherwise
+DTO_Value = input_sampling_rate/(2*vbi_data_rate) * (2^11)
+!!!Note: DTO_Value should be round!!!
+output_sampling_rate = 13.5M;
+input_sampling_rate= 24M;
+vbi_data_rate reference to vbi document.
+*/
+#define VBI_DTO_USCC		0x35a0
+#define VBI_DTO_EURCC		0x3600
+#define VBI_DTO_TT625A		0x0f7a
+#define VBI_DTO_TT625B		0x0dd6
+#define VBI_DTO_TT625C		0x10be
+#define VBI_DTO_TT625D		0x1103
+#define VBI_DTO_TT525B		0x10c3
+#define VBI_DTO_TT525C		0x10c3
+#define VBI_DTO_TT525D		0x10c3
+#define VBI_DTO_WSS625		0x2066
+#define VBI_DTO_WSSJ		0x1e2c
+#define VBI_DTO_VPS		0x1333
+
+
+#define VBI_LINE_MIN               6
+#define VBI_LINE_MAX               25
+
+enum vbi_package_type_e {
+	VBI_PACKAGE_CC1 = 1,
+	VBI_PACKAGE_CC2 = 2,
+	VBI_PACKAGE_CC3 = 4,
+	VBI_PACKAGE_CC4 = 8,
+	VBI_PACKAGE_TT1 = 16,
+	VBI_PACKAGE_TT2 = 32,
+	VBI_PACKAGE_TT3 = 64,
+	VBI_PACKAGE_TT4 = 128,
+	VBI_PACKAGE_XDS = 256
+};
+
+#define VBI_PACKAGE_FILTER_MAX     3
+
+#define VBI_IOC_MAGIC 'X'
+
+#define VBI_IOC_CC_EN              _IO(VBI_IOC_MAGIC, 0x01)
+#define VBI_IOC_CC_DISABLE         _IO(VBI_IOC_MAGIC, 0x02)
+#define VBI_IOC_SET_TYPE           _IOW(VBI_IOC_MAGIC, 0x03, int)
+#define VBI_IOC_S_BUF_SIZE         _IOW(VBI_IOC_MAGIC, 0x04, int)
+#define VBI_IOC_START              _IO(VBI_IOC_MAGIC, 0x05)
+#define VBI_IOC_STOP               _IO(VBI_IOC_MAGIC, 0x06)
+
+
+#define VBI_MEM_SIZE               0x80000
+/* 0x8000   // 32768 hw address with 8bit not 64bit */
+/* #define VBI_SLICED_MAX            64
+// 32768 hw address with 8bit not 64bit */
+/* before m6tvd vbi_write_burst_byte = 8;
+*  after g9tv vbi_write_burst_byte = 16*/
+#define VBI_WRITE_BURST_BYTE        16
+
+/* debug defines */
+#define VBI_CC_SUPPORT
+#define VBI_TT_SUPPORT
+#define VBI_WSS_SUPPORT
+#define VBI_VPS_SUPPORT
+
+#define VBI_DATA_TYPE_LEN          16
+#define VBI_DATA_TYPE_MASK         0xf0000
+
+#define VBI_PAC_TYPE_LEN           0
+#define VBI_PAC_TYPE_MASK          0x0ffff
+
+#define VBI_PAC_CC_FIELD_LEN       4
+#define VBI_PAC_CC_FIELD_MASK      0xf0
+#define VBI_PAC_CC_FIELD1          0
+#define VBI_PAC_CC_FIELD2          1
+
+/* vbi_slicer type */
+enum vbi_slicer_e {
+	VBI_TYPE_NULL = 0,
+	VBI_TYPE_USCC = 0x00001,
+	VBI_TYPE_EUROCC = 0x00020,
+	VBI_TYPE_VPS = 0x00040,
+	/* Germany, Austria and Switzerland. */
+	VBI_TYPE_TT_625A = 0x00080,
+	VBI_TYPE_TT_625B  = 0x00100,
+	VBI_TYPE_TT_625C = 0x00200,
+	VBI_TYPE_TT_625D  = 0x00400,
+	VBI_TYPE_TT_525B  = 0x00800,
+	VBI_TYPE_TT_525C = 0x01000,
+	VBI_TYPE_TT_525D  = 0x02000,
+	VBI_TYPE_WSS625 = 0x04000,
+	VBI_TYPE_WSSJ = 0x08000
+};
+
+#define VBI_DEFAULT_BUFFER_SIZE 8192 /*set default buffer size--8KByte*/
+#define VBI_DEFAULT_BUFFER_PACKEGE_NUM 100 /* default buffer size */
+
+/* ********************
+********************* */
+/* *** enum definitions ********************************************* */
+/* ****************************
+***************** */
+
+enum field_id_e {
+	VBI_FIELD_1 = 0,
+	VBI_FIELD_2 = 1,
+};
+
+enum vbi_state_e {
+	VBI_STATE_FREE      = 0,
+	VBI_STATE_ALLOCATED = 1,
+	VBI_STATE_SET       = 2,
+	VBI_STATE_GO        = 3,
+	VBI_STATE_DONE      = 4,
+	VBI_STATE_TIMEDOUT  = 5
+} vbi_state_t;
+
+/* ********************
+************************** */
+/* *** structure definitions *************
+******* */
+/* *******************************
+***************** */
+
+struct vbi_data_s {
+	unsigned int vbi_type:8;
+	unsigned int field_id:8;
+	unsigned int tt_sys:8;/*tt*/
+	unsigned int nbytes:16;
+	unsigned int line_num:16;
+	unsigned char b[42];         /* 42 for TT-625B */
+};
+
+#endif /* TVIN_VBI_H_ */