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(¶m,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, ¶m) == -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(¶m,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, ¶m) == -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 = ¶.ves;
+ dev->vid_player.para.need_free = AM_FALSE;
+ } else if(mode & AV_PLAY_TS) {
+ p = ¶.ts;
+ } else if(mode & AV_PLAY_FILE) {
+ AM_AV_PlayStatus_t status;
+
+ p = ¶.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 = ¶.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, ¶);
+ 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, ¶);
+ 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, ¶);
+ 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, ¶);
+ }
+ }
+
+ 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, ¶);
+
+ if (ret == AM_SUCCESS)
+ av_stop(dev, AV_GET_JPEG_INFO);
+
+ pthread_mutex_unlock(&dev->lock);
+
+ if (ret != AM_SUCCESS)
+ av_free_data_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(¶);
+
+ 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, ¶);
+ if (ret == AM_SUCCESS) {
+ dev->curr_para.ves = para;
+ }
+
+ pthread_mutex_unlock(&dev->lock);
+
+ if (ret != AM_SUCCESS)
+ av_free_data_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, ¶);
+ if (ret == AM_SUCCESS) {
+ dev->curr_para.ves = para;
+ }
+
+ pthread_mutex_unlock(&dev->lock);
+
+ if (ret != AM_SUCCESS)
+ av_free_data_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, ¶);
+ if (ret == AM_SUCCESS) {
+ dev->curr_para.aes = para;
+ }
+
+ pthread_mutex_unlock(&dev->lock);
+
+ if (ret != AM_SUCCESS)
+ av_free_data_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, ¶);
+ if (ret == AM_SUCCESS) {
+ dev->curr_para.aes = para;
+ }
+
+ pthread_mutex_unlock(&dev->lock);
+
+ if (ret != AM_SUCCESS)
+ av_free_data_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, ¶);
+ }
+ }
+
+ 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, ¶);
+ }
+ }
+
+ 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(¶m, 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)¶m) == -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(¶m, 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, ¶m);
+ 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, ¶->sample_rate_orig, ¶->channels_orig, ¶->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(¶, 0, sizeof(para));
+ para.vfmt = vfmt;
+ para.cc_default_stop = 1;
+
+ err = AM_USERDATA_Open(afd_dev, ¶);
+ 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, &layer_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, ¶);
+ 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(¶, 0, sizeof(para));
+ AM_TRY(AM_DMX_Open(DMX_DEV_NO, ¶));
+ 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, ¶);
+ 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_ */