From e5cff5a3ef373a5090f45cd1dfb0b85d9c851d5d Mon Sep 17 00:00:00 2001 From: FuJuntang <strongtiger_001@163.com> Date: 星期三, 06 七月 2022 10:04:09 +0800 Subject: [PATCH] Add video recorder and playback support. --- service/ptz/ptz.c | 164 ++--- service/capabilities/capa.c | 43 + test/av_test/av_test.c | 66 ++ service/av_demux/video_conv.sh | 58 ++ service/ptz/ptz.h | 24 Makefile | 11 test/probe_test/Makefile | 5 service/av_demux/av_demux.h | 100 +++ comm/proto_comm.c | 146 +++- service/av_demux/av_demux.c | 810 +++++++++++++++++++++++++++++++ test/ptz_test/ptz_test.c | 2 comm/proto_dbg.h | 3 test/av_test/Makefile | 52 ++ test/Makefile.inc | 5 comm/proto_comm.h | 46 + test/ptz_test/Makefile | 5 16 files changed, 1,373 insertions(+), 167 deletions(-) diff --git a/Makefile b/Makefile index 593f2b1..a9a81be 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,8 @@ RM := rm CFLAGS += -c -Wall -DWITH_DOM -DWITH_NONAMESPACES -DWITH_OPENSSL +CFLAGS += -DPROTOBUF_USS_DLLS +CFLAGS += -fPIC -Wunused-function SOURCES_CORE += \ core/soapC.c \ @@ -25,7 +27,8 @@ service/probe/probe.c \ service/deviceinfo/dev_info.c \ service/capabilities/capa.c \ - service/ptz/ptz.c + service/ptz/ptz.c \ + service/av_demux/av_demux.c SOURCES_COMM += \ comm/proto_dbg.c \ @@ -35,6 +38,7 @@ OBJECTS_ONVIF_SRVS := $(patsubst %.c,$(TEMPDIR)%.o,$(filter %.c, $(SOURCES_SRVS))) OBJECTS_ONVIF_COMM := $(patsubst %.c,$(TEMPDIR)%.o,$(filter %.c, $(SOURCES_COMM))) +FFMPEG_DIR = thirdparty/ffmpeg OPENSSL_DIR = thirdparty/openssl TARGET_LIB = libonvif_std.so @@ -42,18 +46,21 @@ INCLUDE += -Icore/ \ -Icomm/ \ -Iservice \ + -I$(FFMPEG_DIR)/include \ -I$(OPENSSL_DIR)/include CFLAGS += $(INCLUDE) CFLAGS += -Wno-unused +LDFLAGS += -L$(FFMPEG_DIR)/lib LDFLAGS += -L$(OPENSSL_DIR)/lib +LDFLAGS += -Lthirdparty LDLIBS += -lavcodec -lavdevice -lavfilter -lavformat \ -lavutil -lswresample -lswscale LDLIBS += -lcrypto -lssl -lpthread -ldl -lrt -lm CFLAGS += -fPIC -DIRS_TEST = test/probe_test test/ptz_test +DIRS_TEST = test/probe_test test/ptz_test test/av_test %.o: $(SOURCES_CORE)/%.cpp $(SOURCES_SRVS)/%.cpp $(SOURCES_COMM)/%.cpp @echo " CPP " $@; diff --git a/comm/proto_comm.c b/comm/proto_comm.c index df226ca..21c3c26 100644 --- a/comm/proto_comm.c +++ b/comm/proto_comm.c @@ -1,73 +1,131 @@ - #include <stdio.h> #include <stdlib.h> #include <assert.h> +#include <time.h> +#include <signal.h> + #include "proto_comm.h" #include "proto_dbg.h" +int timer_init(timer_t *timer_index, void (*timer_handler)(union sigval para)) { + struct sigevent event; + timer_t timer; + int ret; + + memset(&event, 0x00, sizeof(event)); + event.sigev_value.sival_int = ENABLE; + event.sigev_value.sival_ptr = NULL; + event.sigev_notify = SIGEV_THREAD; + event.sigev_notify_function = timer_handler; + + ret = timer_create(CLOCK_REALTIME, &event, &timer); + if (ret) { + return -1; + } + + if (timer_index != NULL) { + *timer_index = timer; + } + + return 0; +} + +int timer_start(timer_t timer_index, int sec) { + int ret; + struct itimerspec ts; + + ts.it_interval.tv_sec = 0; + ts.it_interval.tv_nsec = 0; + ts.it_value.tv_sec = sec; + ts.it_value.tv_nsec = 0; + ret = timer_settime(timer_index, 0, &ts, NULL); + if (ret) { + return -1; + } + + return ret; +} + +int timer_stop(timer_t timer_index) { + + int ret = timer_start(timer_index, 0); + + return ret; +} + +int timer_destroy(timer_t timer_index) { + int ret; + + ret = timer_delete(timer_index); + + return ret; +} + void soap_perror(struct soap *soap, const char *str) { - if (NULL == str) { - SOAP_DBGERR("[soap] error: %d, %s, %s\n", soap->error, *soap_faultcode(soap), *soap_faultstring(soap)); - } else { - SOAP_DBGERR("[soap] %s error: %d, %s, %s\n", str, soap->error, *soap_faultcode(soap), *soap_faultstring(soap)); - } - return; + if (NULL == str) { + SOAP_DBGERR("[soap] error: %d, %s, %s\n", soap->error, *soap_faultcode(soap), *soap_faultstring(soap)); + } else { + SOAP_DBGERR("[soap] %s error: %d, %s, %s\n", str, soap->error, *soap_faultcode(soap), *soap_faultstring(soap)); + } + + return; } void* proto_soap_malloc(struct soap *soap, unsigned int n) { - void *p = NULL; + void *p = NULL; - if (n > 0) { - p = soap_malloc(soap, n); - SOAP_ASSERT(NULL != p); - memset(p, 0x00 ,n); - } - return p; + if (n > 0) { + p = soap_malloc(soap, n); + SOAP_ASSERT(NULL != p); + memset(p, 0x00 ,n); + } + + return p; } struct soap *proto_soap_new(int timeout) { - struct soap *soap = NULL; // soap环境变量 + struct soap *soap = NULL; - SOAP_ASSERT(NULL != (soap = soap_new())); + SOAP_ASSERT(NULL != (soap = soap_new())); - soap_set_namespaces(soap, namespaces); // 设置soap的namespaces - soap->recv_timeout = timeout; - soap->send_timeout = timeout; - soap->connect_timeout = timeout; + soap_set_namespaces(soap, namespaces); + soap->recv_timeout = timeout; + soap->send_timeout = timeout; + soap->connect_timeout = timeout; #if defined(__linux__) || defined(__linux) - soap->socket_flags = MSG_NOSIGNAL; + soap->socket_flags = MSG_NOSIGNAL; #endif - soap_set_mode(soap, SOAP_C_UTFSTRING); + soap_set_mode(soap, SOAP_C_UTFSTRING); - return soap; + return soap; } void proto_soap_delete(struct soap *soap) { - soap_destroy(soap); // remove deserialized class instances (C++ only) - soap_end(soap); // Clean up deserialized data (except class instances) and temporary data - soap_done(soap); // Reset, close communications, and remove callbacks - soap_free(soap); // Reset and deallocate the context created with soap_new or soap_copy + soap_destroy(soap); // remove deserialized class instances (C++ only) + soap_end(soap); // Clean up deserialized data (except class instances) and temporary data + soap_done(soap); // Reset, close communications, and remove callbacks + soap_free(soap); // Reset and deallocate the context created with soap_new or soap_copy } int proto_SetAuthInfo(struct soap *soap, const char *username, const char *password) { - int result = 0; + int result = 0; - SOAP_ASSERT(NULL != username); - SOAP_ASSERT(NULL != password); + SOAP_ASSERT(NULL != username); + SOAP_ASSERT(NULL != password); - result = soap_wsse_add_UsernameTokenDigest(soap, NULL, username, password); - SOAP_CHECK_ERROR(result, soap, "add_UsernameTokenDigest"); + result = soap_wsse_add_UsernameTokenDigest(soap, NULL, username, password); + SOAP_CHECK_ERROR(result, soap, "add_UsernameTokenDigest"); EXIT: - return result; + return result; } float para_check(float data) @@ -85,11 +143,6 @@ return ret; } -/************************************************************************ - *初始化soap描述消息头 - - *在本函数内部通过proto_soap_malloc分配的内存,将在proto_soap_delete中被释放 -************************************************************************/ void proto_init_header(struct soap *soap) { struct SOAP_ENV__Header *header = NULL; @@ -109,27 +162,22 @@ return; } -/************************************************************************ - *初始化探测设备的范围和类型 - - *在本函数内部通过proto_soap_malloc分配的内存,将在proto_soap_delete中被释放 -************************************************************************/ void proto_init_ProbeType(struct soap *soap, struct wsdd__ProbeType *probe) { - struct wsdd__ScopesType *scope = NULL; // 用于描述查找哪类的Web服务 + struct wsdd__ScopesType *scope = NULL; SOAP_ASSERT(NULL != soap); SOAP_ASSERT(NULL != probe); scope = (struct wsdd__ScopesType *)proto_soap_malloc(soap, sizeof(struct wsdd__ScopesType)); - soap_default_wsdd__ScopesType(soap, scope); // 设置寻找设备的范围 + soap_default_wsdd__ScopesType(soap, scope); scope->__item = (char*)proto_soap_malloc(soap, strlen(SOAP_ITEM) + 1); strcpy(scope->__item, SOAP_ITEM); memset(probe, 0x00, sizeof(struct wsdd__ProbeType)); soap_default_wsdd__ProbeType(soap, probe); probe->Scopes = scope; - probe->Types = (char*)proto_soap_malloc(soap, strlen(SOAP_TYPES) + 1); // 设置寻找设备的类型 + probe->Types = (char*)proto_soap_malloc(soap, strlen(SOAP_TYPES) + 1); strcpy(probe->Types, SOAP_TYPES); return; @@ -139,7 +187,7 @@ *rtsp://100.100.100.140:554/av0_0 *rtsp://username:password@100.100.100.140:554/av0_0 ************************************************************************/ -int make_uri_withauth(char *src_uri, char *username, char *password, char *dest_uri, unsigned int size_dest_uri) +int bridge_uri(char *src_uri, const char *username, const char *password, char *dest_uri, unsigned int size_dest_uri) { int result = 0; unsigned int needBufSize = 0; @@ -150,14 +198,14 @@ SOAP_ASSERT(NULL != dest_uri); memset(dest_uri, 0x00, size_dest_uri); - needBufSize = strlen(src_uri) + strlen(username) + strlen(password) + 3; // 检查缓存是否足够,包括‘:’和‘@’和字符串结束符 + needBufSize = strlen(src_uri) + strlen(username) + strlen(password) + 3; //check buf size with character ‘:’ and ‘@' if (size_dest_uri < needBufSize) { SOAP_DBGERR("dest uri buf size is not enough.\n"); result = -1; goto EXIT; } - if (0 == strlen(username) && 0 == strlen(password)) { // 生成新的uri地址 + if (0 == strlen(username) && 0 == strlen(password)) { strcpy(dest_uri, src_uri); } else { char *p = strstr(src_uri, "//"); diff --git a/comm/proto_comm.h b/comm/proto_comm.h index 9ca7239..97f3a0b 100644 --- a/comm/proto_comm.h +++ b/comm/proto_comm.h @@ -8,6 +8,9 @@ #include <stdio.h> #include <stdlib.h> #include <assert.h> +#include <time.h> +#include <signal.h> + #include "soapH.h" #include "soapStub.h" #include "wsaapi.h" @@ -24,6 +27,10 @@ #define min(a,b) (((a) < (b)) ? (a) : (b)) #endif +#define WT_TIME 5 +#define STOP_WT_TIME 3 +#define WT_MAX_TIME (60 * 20) + #define SOAP_ASSERT assert #define SOAP_DBGERR printf @@ -33,27 +40,46 @@ #define SOAP_DBGLOG #endif +#define USERNAME "On_admin" +#define PASSWORD "a12345678" + #define SOAP_TO "urn:schemas-xmlsoap-org:ws:2005:04:discovery" #define SOAP_ACTION "http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe" #define SOAP_MCAST_ADDR "soap.udp://239.255.255.250:3702" -#define SOAP_ITEM "" // 寻找的设备范围 -#define SOAP_TYPES "dn:NetworkVideoTransmitter" // 寻找的设备类型 +#define SOAP_ITEM "" +#define SOAP_TYPES "dn:NetworkVideoTransmitter" //device type + +#define ADDR_PREFIX "http://" +#define ADDR_LAST "/" + +#define NAME_BRIDGE "_" +#define NAME_DOT "." +#define NAME_MID "-" #define SOAP_SOCK_TIMEOUT (10) //sec + +#define TRUE 1 +#define FALSE 0 + +#define ENABLE 0 +#define DISABLE 1 #define PARA_MIN (-1) #define PARA_MAX (1) -#define PROTO_ADDRESS_SIZE (128) // URI地址长度 -#define PROTO_TOKEN_SIZE (65) // token长度 +#define PROTO_ADDRESS_SIZE (128) +#define PROTO_TOKEN_SIZE (65) //token size +#define PTOTO_ADDRESS_ADD (65) -/* 视频编码器配置信息 */ +#define MAX_BUF_SIZE 600 + +/*video encoder configurations */ struct tagVideoEncoderConfiguration { - char token[PROTO_TOKEN_SIZE]; // 唯一标识该视频编码器的令牌字符串 - int Width; // 分辨率 + char token[PROTO_TOKEN_SIZE]; //video token + int Width; //resolution int Height; }; @@ -78,6 +104,10 @@ } \ } while (0) +int timer_init(timer_t *timer_index, void (*timer_handler)(union sigval para)); +int timer_start(timer_t timer_index, int sec); +int timer_stop(timer_t timer_index); +int timer_destroy(timer_t timer_index); void soap_perror(struct soap *soap, const char *str); void * proto_soap_malloc(struct soap *soap, unsigned int n); @@ -89,7 +119,7 @@ void proto_init_ProbeType(struct soap *soap, struct wsdd__ProbeType *probe); float para_check(float data); -int make_uri_withauth(char *src_uri, char *username, char *password, char *dest_uri, unsigned int size_dest_uri); +int bridge_uri(char *src_uri, const char *username, const char *password, char *dest_uri, unsigned int size_dest_uri); int soap_wsse_add_UsernameTokenDigest(struct soap *soap, const char *id, const char *username, const char *password); int proto_GetDeviceInformation(const char *DeviceXAddr, const char *username, const char *passwd); diff --git a/comm/proto_dbg.h b/comm/proto_dbg.h index 5858a5f..f001b86 100644 --- a/comm/proto_dbg.h +++ b/comm/proto_dbg.h @@ -22,7 +22,6 @@ }; #ifdef PROTO_DEBUG - void dump__wsdd__ProbeMatches(struct __wsdd__ProbeMatches *rep); void dump__GetPresetsResponse(struct _tptz__GetPresetsResponse *rep); void dump_tds__GetCapabilitiesResponse(struct _tds__GetCapabilitiesResponse *rep); @@ -44,7 +43,6 @@ void dump_trt__GetVideoEncoderConfigurationOptionsResponse(struct _trt__GetVideoEncoderConfigurationOptionsResponse *rep); void log_level_val(unsigned int level, const char *prestr, enum LOG_TYPE type, const void *val); #else - #define dump__wsdd__ProbeMatches #define dump_tds__GetCapabilitiesResponse #define dump_tds__GetDeviceInformationResponse @@ -63,6 +61,7 @@ #define dump_trt__GetVideoEncoderConfigurationsResponse #define dump_trt__GetCompatibleVideoEncoderConfigurationsResponse #define dump_trt__GetVideoEncoderConfigurationOptionsResponse +#define log_level_val #endif diff --git a/service/av_demux/av_demux.c b/service/av_demux/av_demux.c new file mode 100644 index 0000000..99dbf2c --- /dev/null +++ b/service/av_demux/av_demux.c @@ -0,0 +1,810 @@ +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <errno.h> +#include <sys/types.h> +#include <unistd.h> +#include <signal.h> +#include <sys/wait.h> +#include <time.h> +#include <sys/vfs.h> +#include <stdint.h> +#include <sys/stat.h> +#include <signal.h> +#include <sys/types.h> +#include <dirent.h> + +#include "libavcodec/avcodec.h" +#include "libavdevice/avdevice.h" +#include "libavformat/avformat.h" +#include "libavfilter/avfilter.h" +#include "libavutil/avutil.h" +#include "libswscale/swscale.h" +#include "libavutil/pixdesc.h" + +#include "probe/probe.h" +#include "av_demux/av_demux.h" +#include "proto_comm.h" +#include "proto_dbg.h" + +static AVDevs *gAVDevs = NULL; + +static int data_cmp(char *s1, char *s2, char *dlim); + +/*signal process interrupt handler*/ +static void handler(int sig) +{ + sync(); +} + +void av_timer_handler(union sigval para) +{ + gAVDevs->slice_stat = FALSE; +} + +/*parse the location to get the right direction*/ +static int get_dir_with_key(char *dir_path, char *name, char *key, char *buf, int length) { + DIR *pDir; + char *ptr; + char temp = 0; + char found = FALSE; + struct dirent * entry; + char parse_buf[MAX_BUF_SIZE] = { 0x00 }; + + pDir = opendir(dir_path); + if ( + pDir == NULL) { + SOAP_DBGERR("the path(%s) can not be opened!\n", dir_path); + + return -1; + } + + while((entry = readdir(pDir)) != NULL) { + + if (entry->d_type & DT_DIR) { + + if ((strcmp(entry->d_name, ".") != 0) && (strcmp(entry->d_name, "..") != 0)) { + + ptr = strstr(entry->d_name, NAME_BRIDGE); + + if ((ptr != NULL) && (strcmp(ptr + 1, name) == 0)) { + + if (data_cmp(entry->d_name, key, NAME_MID) <= 0) { + + found = TRUE; + if (temp == 0) { + memcpy(parse_buf, entry->d_name, sizeof(parse_buf)); + + temp = 1; + + } else { + + if (data_cmp(parse_buf, entry->d_name, NAME_MID) < 0) { + memset(parse_buf, 0x00, sizeof(parse_buf)); + memcpy(parse_buf, entry->d_name, sizeof(parse_buf)); + } + } + } + } + } + } + } + + closedir(pDir); + + if (found == TRUE) { + memcpy(buf, dir_path, length - 1); + memcpy(buf + strlen(buf), "/", length - strlen(buf) - 1); + memcpy(buf + strlen(buf), parse_buf, length - strlen(buf) - 1); + } else { + buf[0] = 0; + } + + return found; +} + +int playback_get_key(playback_key set, char *buf, int length) { + int ret; + char parse_buf[MAX_BUF_SIZE] = { 0x00 }; + char buf_temp[MAX_BUF_SIZE] = { 0x00 }; + + if ((set.name == NULL) || (set.date == NULL) || (set.time == NULL)) { + SOAP_DBGERR("invalid playbeck key set parameters!\n"); + + return 0; + } + + ret = get_dir_with_key(VIDEO_PUT_DIR, set.name, set.date, parse_buf, sizeof(parse_buf)); + if (ret > 0) { + ret = get_file_with_key(parse_buf, set.time, buf_temp, sizeof(buf_temp), 0); + if (ret > 0) { + memcpy(buf, buf_temp, length); + } + } + + return ret; +} + +static int get_dir_oldest(char *dir_path, char *buf, int length) { + DIR *pDir; + char temp = 0; + int found = FALSE; + struct dirent * entry; + char parse_buf[MAX_BUF_SIZE] = { 0x00 }; + + pDir = opendir(dir_path); + if ( + pDir == NULL) { + SOAP_DBGERR("the path(%s) can not be opened!\n", dir_path); + + return -1; + } + + while((entry = readdir(pDir)) != NULL) { + + if (entry->d_type & DT_DIR) { + + if ((strcmp(entry->d_name, ".") != 0) && (strcmp(entry->d_name, "..") != 0)) { + + found = TRUE; + if (temp == 0) { + memcpy(parse_buf, entry->d_name, sizeof(parse_buf)); + + temp = 1; + + } else { + + if (data_cmp(parse_buf, entry->d_name, NAME_MID) > 0) { + memset(parse_buf, 0x00, sizeof(parse_buf)); + memcpy(parse_buf, entry->d_name, sizeof(parse_buf)); + } + } + } + } + } + + closedir(pDir); + + if (found == TRUE) { + memcpy(buf, dir_path, length); + memcpy(buf + strlen(buf), "/", length - strlen(buf) - 1); + memcpy(buf + strlen(buf), parse_buf, length - strlen(buf) - 1); + + return 0; + } + + buf[0] = 0x00; + + return -1; +} + +/*parse the location to get the right file. +* flag - include the key itself or not +*/ +static int get_file_with_key(char *dir_path, char *key, char *buf, int length, int flag) { + DIR *pDir; + char temp = 0; + char found = FALSE; + char found_flag = FALSE; + struct dirent * entry; + char parse_buf[MAX_BUF_SIZE] = { 0x00 }; + + pDir = opendir(dir_path); + if (pDir == NULL) { + SOAP_DBGERR("the path(%s) can not be opened!\n", dir_path); + + return -1; + } + + while((entry = readdir(pDir)) != NULL) { + + if (entry->d_type & DT_REG) { + + if ((key != NULL) && (data_cmp(key, entry->d_name, NAME_MID) >= 0)) { + + if ((flag == 1) && (data_cmp(key, entry->d_name, NAME_MID) > 0)) { + found = TRUE; + } else if (flag == 0) { + found = TRUE; + } + } else if (key == NULL) { + found = TRUE; + } + + if (found == TRUE) { + + found_flag = TRUE; + + if (temp == 0) { + memcpy(parse_buf, entry->d_name, sizeof(parse_buf)); + + temp = 1; + + } else { + + if (data_cmp(parse_buf, entry->d_name, NAME_MID) < 0) { + memset(parse_buf, 0x00, sizeof(parse_buf)); + memcpy(parse_buf, entry->d_name, sizeof(parse_buf)); + } + } + + found = FALSE; + } + } + } + + closedir(pDir); + + if (found_flag == TRUE) { + memcpy(buf, dir_path, length - 1); + memcpy(buf + strlen(buf), "/", length - strlen(buf) - 1); + memcpy(buf + strlen(buf), parse_buf, length - strlen(buf) - 1); + } else { + buf[0] = 0; + } + + return found_flag; +} + +/*compare the string between s1 and s2*/ +static int data_cmp(char *s1, char *s2, char *dlim) +{ + int data1; + int data2; + char *ptr1; + char *ptr2; + + data1 = atoi(s1); + data2 = atoi(s2); + if (data1 > data2) + return 1; + + if (data1 < data2) + return -1; + + ptr1 = strstr(s1, dlim); + ptr2 = strstr(s2, dlim); + data1 = atoi(ptr1 + 1); + data2 = atoi(ptr2 + 1); + if (data1 > data2) + return 1; + + if (data1 < data2) + return -1; + + ptr1 = strstr(ptr1 + 1, dlim); + ptr2 = strstr(ptr2 + 1, dlim); + data1 = atoi(ptr1 + 1); + data2 = atoi(ptr2 + 1); + if (data1 > data2) + return 1; + + if (data1 < data2) + return -1; + + return 0; +} + +/*av stream capture task*/ +static void *task_av_capture(void *arg) +{ + struct timespec time_exp; + + time_exp.tv_sec = WT_TIME; + time_exp.tv_nsec = 0; + //int data = *(int *)arg; + + pthread_detach(pthread_self()); + + while(1) { + sem_timedwait(&(gAVDevs->sem_cap), &time_exp); + + while(gAVDevs->run_stat == TRUE) { + + av_start_cap(gAVDevs); + + gAVDevs->slice_stat = TRUE; + + } + + if (gAVDevs->dev_stat == DISABLE) { + + gAVDevs->proc_stat = DISABLE; + + } + } + + return 0; +} + +/*monitor the disk usage*/ +static void *task_disk_mon(void *arg) +{ + int ret; + uint64_t blocksize; + uint64_t totalsize; + uint64_t availableDisk; + struct statfs diskInfo; + char buf[MAX_BUF_SIZE] = { 0x00 }; + char buf_cmd[MAX_BUF_SIZE] = { 0x00 }; + + pthread_detach(pthread_self()); + + while(1) { + statfs(VIDEO_PUT_DIR, &diskInfo); + + blocksize = diskInfo.f_bsize; + totalsize = blocksize * diskInfo.f_blocks; + availableDisk = diskInfo.f_bavail * blocksize; + + while ((availableDisk * 1.0 / totalsize) < DISK_FREE_THRES) { + ret = get_dir_oldest(VIDEO_PUT_DIR, buf, sizeof(buf)); + if (ret == 0) { + memcpy(buf_cmd, "rm -rf ", sizeof(buf_cmd)); + snprintf(buf_cmd + strlen(buf_cmd), sizeof(buf_cmd) - strlen(buf_cmd) - 1, "rm -rf %s", buf); + system(buf_cmd); + sleep(WT_TIME); + + statfs(VIDEO_PUT_DIR, &diskInfo); + + blocksize = diskInfo.f_bsize; + totalsize = blocksize * diskInfo.f_blocks; + availableDisk = diskInfo.f_bavail * blocksize; + + memset(buf, 0x00, sizeof(buf)); + memset(buf_cmd, 0x00, sizeof(buf_cmd)); + } else { + + break; + } + } + + sleep(WT_MAX_TIME); + } + + return NULL; +} + +/*initialize the stream data channel*/ +int proto_AVInit(void) { + + int ret; + int flag; + pthread_t tid; + struct stat stat_buf; + + if (stat(VIDEO_CONF_DATA, &stat_buf) != 0) { + SOAP_DBGERR("The video configuration(%s) is not existed! Please put it firstly!\n", VIDEO_CONF_DATA); + + return -1; + } + + ret = chmod(VIDEO_CONF_DATA, 0777); + if (ret < 0) { + SOAP_DBGERR("parse the configuration error: %s\n", strerror(errno)); + + return -1; + } + + ret = DiscoverDevice(cb_av_probe); + if (ret <= 0) { + return -1; + } + + ret = pthread_create(&tid, NULL, task_av_capture, &flag); + if (ret) { + return -1; + } + + ret = pthread_create(&tid, NULL, task_disk_mon, &flag); + if (ret) { + return -1; + } + + return 0; +} + +void proto_AVStart(AVDevs *DevData) { + + DevData->slice_stat = TRUE; + + DevData->run_stat = TRUE; + + sem_post(&(DevData->sem_cap)); + +} + +static int av_start_cap(AVDevs *DevData) { + int ret; + pid_t pid; + char data_buf[MAX_BUF_SIZE] = { 0x00 }; + char temp_buf[MAX_BUF_SIZE] = { 0x00 }; + char data_buf_temp[MAX_BUF_SIZE] = { 0x00 }; + char buf[MAX_BUF_SIZE] = { 0x00 }; + + signal(SIGINT, handler); + + pid = fork(); + if (pid < 0) { + SOAP_DBGERR("AV start failure: fork failed!\n"); + + return -1; + + } + + if (pid > 0) { + + timer_start(gAVDevs->timer_id, gAVDevs->timer_sec); + + while((gAVDevs->run_stat == TRUE) && (gAVDevs->slice_stat == TRUE)) { + sleep(1); + } + timer_stop(gAVDevs->timer_id); + + kill(pid, SIGINT); + + wait(NULL); + + sync(); + + if ((gAVDevs->work_mode == PAUSE) && (gAVDevs->pause_enable == FALSE)) { + + gAVDevs->pause_enable = TRUE; + + } else if ((gAVDevs->work_mode == PAUSE) && (gAVDevs->pause_enable == TRUE)) { + + system_date_get(data_buf_temp, sizeof(data_buf_temp)); + + ret = get_dir_with_key(VIDEO_PUT_DIR, gAVDevs->ip, data_buf_temp, data_buf, sizeof(data_buf)); + if (ret > 0) { + + memcpy(temp_buf, data_buf, sizeof(temp_buf) - 1); + memset(data_buf, 0x00, sizeof(data_buf)); + get_file_with_key(temp_buf, NULL, data_buf, sizeof(data_buf), 0); + + memset(data_buf_temp, 0x00, sizeof(data_buf_temp)); + get_file_with_key(temp_buf, data_buf, data_buf_temp, sizeof(data_buf_temp), 1); + + snprintf(buf, sizeof(buf) - 1, "%s", VIDEO_CONF_DATA); + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf) - 1, "%s %s", data_buf_temp, data_buf); + system(buf); + } + + gAVDevs->work_mode = NORMAL; + + gAVDevs->pause_enable = FALSE; + } + + } else { + + ret = video_file_create(data_buf, sizeof(data_buf)); + if (ret < 0) { + return 0; + } + + ret = execl(FFMPEG_BIN_DIR, "ffmpeg", "-f", "rtsp", "-rtsp_transport", "tcp", "-i", gAVDevs->uri_data, "-vcodec", "copy", "-y", data_buf, (char *)NULL); + if (ret < 0) { + SOAP_DBGERR("ffmpeg stuffs are not available: %s\n", strerror(errno)); + SOAP_DBGERR("please check and confirm it had already been installed correctly!\n"); + } + + } + + return 0; +} + +void proto_AVStop(AVDevs *DevData, enum wr_mode mode) { + + DevData->run_stat = FALSE; + + DevData->work_mode = mode; +} + +static int video_file_create(char *data_buf, int length) { + + int ret; + int len; + struct stat stat_buf; + char buf[MAX_BUF_SIZE] = { 0x00 }; + + struct tm tloc; + time_t now; + time(&now); + localtime_r(&now, &tloc); + + if (stat(VIDEO_PUT_DIR, &stat_buf) != 0) { + memcpy(buf, "mkdir -p ", sizeof(buf)); + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf) - 1, "%s", VIDEO_PUT_DIR); + system(buf); + } + + memset(buf, 0x00, sizeof(buf)); + len = MAX_BUF_SIZE - 1; + snprintf(buf, len, "%s", VIDEO_PUT_DIR); + len = (MAX_BUF_SIZE - 1) >= strlen(buf) ? MAX_BUF_SIZE - 1 - strlen(buf) : 0; + snprintf(buf + strlen(buf), len, "/%d-", tloc.tm_year + 1900); + len = (MAX_BUF_SIZE - 1) >= strlen(buf) ? MAX_BUF_SIZE - 1 - strlen(buf) : 0; + snprintf(buf + strlen(buf), len, "%d-", tloc.tm_mon + 1); + len = (MAX_BUF_SIZE - 1) >= strlen(buf) ? MAX_BUF_SIZE - 1 - strlen(buf) : 0; + snprintf(buf + strlen(buf), len, "%d", tloc.tm_mday); + len = (MAX_BUF_SIZE - 1) >= strlen(buf) ? MAX_BUF_SIZE - 1 - strlen(buf) : 0; + snprintf(buf + strlen(buf), len, "_%s", gAVDevs->ip); + + if (stat(buf, &stat_buf) != 0) { + + ret = mkdir(buf, 0777); + if (ret < 0) { + SOAP_DBGERR("the video put dir create failure: %s\n", strerror(errno)); + + return -1; + } + } + + time(&now); + localtime_r(&now, &tloc); + len = (MAX_BUF_SIZE - 1) >= strlen(buf) ? MAX_BUF_SIZE - 1 - strlen(buf) : 0; + snprintf(buf + strlen(buf), len, "/%d-", tloc.tm_hour); + len = (MAX_BUF_SIZE - 1) >= strlen(buf) ? MAX_BUF_SIZE - 1 - strlen(buf) : 0; + snprintf(buf + strlen(buf), len, "%d-", tloc.tm_min); + len = (MAX_BUF_SIZE - 1) >= strlen(buf) ? MAX_BUF_SIZE - 1 - strlen(buf) : 0; + snprintf(buf + strlen(buf), len, "%d.mp4", tloc.tm_sec); + + memcpy(data_buf, buf, length); + + return 0; +} + +static void system_date_get(char *buf, int len) +{ + struct tm tloc; + time_t now; + time(&now); + localtime_r(&now, &tloc); + + sprintf(buf, "%d", tloc.tm_year + 1900); + sprintf(buf + strlen(buf), "-%d", tloc.tm_mon + 1); + sprintf(buf + strlen(buf), "-%d", tloc.tm_mday); + + return; +} + +static void cb_av_probe(char *DeviceXAddr) +{ + int ret; + int len; + char *pos_s, *pos_e; + + if (gAVDevs == NULL) { + + gAVDevs = malloc(sizeof(AVDevs)); + + SOAP_ASSERT(gAVDevs != NULL); + + memset(gAVDevs, 0x00, sizeof(AVDevs)); + + pos_s = strstr(DeviceXAddr, ADDR_PREFIX); + pos_e = strstr(DeviceXAddr + strlen(ADDR_PREFIX), ADDR_LAST); + len = pos_e - DeviceXAddr - strlen(ADDR_PREFIX); + memcpy(gAVDevs->ip, DeviceXAddr + strlen(ADDR_PREFIX), len); + + gAVDevs->timer_sec = VIDEO_DURATION; + + gAVDevs->dev_stat = ENABLE; + gAVDevs->run_stat = FALSE; + + ret = sem_init(&(gAVDevs->sem_cap), 0, 0); + SOAP_ASSERT(ret == 0); + + timer_init(&(gAVDevs->timer_id), av_timer_handler); + } + + /*Get the device capabilities*/ + proto_GetCapabilities(DeviceXAddr, &(gAVDevs->capa), USERNAME, PASSWORD); + + /*Parse the stream configurations*/ + proto_GetProfiles(gAVDevs->capa.MediaXAddr, &(gAVDevs->profiles), USERNAME, PASSWORD); + + proto_GetStreamUri(gAVDevs->capa.MediaXAddr, gAVDevs->profiles->token, gAVDevs->uri, sizeof(gAVDevs->uri), USERNAME, PASSWORD); + + bridge_uri(gAVDevs->uri, USERNAME, PASSWORD, gAVDevs->uri_data, sizeof(gAVDevs->uri_data)); + +} + +AVDevs *proto_AVGethandle(void) +{ + return gAVDevs; +} + +void proto_AVClose(void) +{ + if (gAVDevs != NULL) { + + if (gAVDevs->dev_stat == ENABLE) { + proto_AVStop(gAVDevs, NORMAL); + } + + gAVDevs->dev_stat = DISABLE; + + while(gAVDevs->proc_stat != DISABLE) { + sleep(2); + } + + sem_destroy(&(gAVDevs->sem_cap)); + + timer_destroy(gAVDevs->timer_id); + + free(gAVDevs->profiles); + + free(gAVDevs); + + gAVDevs = NULL; + } +} + +/*get the video and audio packet*/ +void get_stream(AVDevs *DevData) +{ + unsigned int i; + int ret; + int video_st_index = -1; + int audio_st_index = -1; + AVFormatContext *ifmt_ctx = NULL; + AVPacket pkt; + AVStream *st = NULL; + char errbuf[64]; + + /*Open the input file for reading*/ + if ((ret = avformat_open_input(&ifmt_ctx, DevData->uri_data, 0, NULL)) < 0) { + SOAP_DBGERR("Could not open input file '%s' (error '%s')\n", DevData->uri_data, av_make_error_string(errbuf, sizeof(errbuf), ret)); + + goto EXIT; + } + + /*Get information on the input file (number of streams etc.))*/ + if ((ret = avformat_find_stream_info(ifmt_ctx, NULL)) < 0) { + SOAP_DBGERR("Could not open find stream info (error '%s')\n", av_make_error_string(errbuf, sizeof(errbuf), ret)); + + goto EXIT; + } + + for (i = 0; i < ifmt_ctx->nb_streams; i++) { + av_dump_format(ifmt_ctx, i, DevData->uri_data, 0); + } + + /*find video stream index*/ + for (i = 0; i < ifmt_ctx->nb_streams; i++) { + + st = ifmt_ctx->streams[i]; + + switch(st->codec->codec_type) { + + case AVMEDIA_TYPE_AUDIO: + audio_st_index = i; + + break; + + case AVMEDIA_TYPE_VIDEO: + video_st_index = i; + + break; + + default: + break; + } + } + + if (-1 == video_st_index) { + SOAP_DBGERR("No H.264 video stream in the input file\n"); + + goto EXIT; + } + + /*initialize packet*/ + av_init_packet(&pkt); + pkt.data = NULL; + pkt.size = 0; + + while (1) { + do { + + ret = av_read_frame(ifmt_ctx, &pkt); + + } while (ret == AVERROR(EAGAIN)); + + if (ret < 0) { + SOAP_DBGERR("Could not read frame (error '%s')\n", av_make_error_string(errbuf, sizeof(errbuf), ret)); + + break; + } + + /*video frame*/ + if (pkt.stream_index == video_st_index) { + + SOAP_DBGERR("Video Packet size = %d\n", pkt.size); + + } else if(pkt.stream_index == audio_st_index) { + /*audio frame*/ + SOAP_DBGERR("Audio Packet size = %d\n", pkt.size); + + } else { + + SOAP_DBGERR("Unknow Packet size = %d\n", pkt.size); + + } + + av_packet_unref(&pkt); + } + +EXIT: + + if (NULL != ifmt_ctx) { + + avformat_close_input(&ifmt_ctx); + + ifmt_ctx = NULL; + } + + return ; +} + +/*Get the device service stream address*/ +int proto_GetStreamUri(const char *MediaXAddr, char *ProfileToken, char *uri, unsigned int sizeuri, const char *username, const char *passwd) +{ + + int result = 0; + struct soap *soap = NULL; + struct tt__StreamSetup ttStreamSetup; + struct tt__Transport ttTransport; + struct _trt__GetStreamUri req; + struct _trt__GetStreamUriResponse rep; + + SOAP_ASSERT(NULL != MediaXAddr); + SOAP_ASSERT(NULL != uri); + + memset(uri, 0x00, sizeuri); + + SOAP_ASSERT(NULL != (soap = proto_soap_new(SOAP_SOCK_TIMEOUT))); + + memset(&req, 0x00, sizeof(req)); + memset(&rep, 0x00, sizeof(rep)); + memset(&ttStreamSetup, 0x00, sizeof(ttStreamSetup)); + memset(&ttTransport, 0x00, sizeof(ttTransport)); + + ttStreamSetup.Stream = tt__StreamType__RTP_Unicast; + ttStreamSetup.Transport = &ttTransport; + ttStreamSetup.Transport->Protocol = tt__TransportProtocol__RTSP; + ttStreamSetup.Transport->Tunnel = NULL; + req.StreamSetup = &ttStreamSetup; + req.ProfileToken = ProfileToken; + + proto_SetAuthInfo(soap, username, passwd); + result = soap_call___trt__GetStreamUri(soap, MediaXAddr, NULL, &req, &rep); + SOAP_CHECK_ERROR(result, soap, "GetServices"); + + dump_trt__GetStreamUriResponse(&rep); + + result = -1; + if (NULL != rep.MediaUri) { + if (NULL != rep.MediaUri->Uri) { + if (sizeuri > strlen(rep.MediaUri->Uri)) { + + strcpy(uri, rep.MediaUri->Uri); + + result = 0; + } else { + SOAP_DBGERR("Not enough cache!\n"); + } + } + } + +EXIT: + + if (NULL != soap) { + proto_soap_delete(soap); + } + + return result; + +} + + diff --git a/service/av_demux/av_demux.h b/service/av_demux/av_demux.h new file mode 100644 index 0000000..e8de362 --- /dev/null +++ b/service/av_demux/av_demux.h @@ -0,0 +1,100 @@ +#ifndef __SRV_AV_DEMUX_H__ +#define __SRV_AV_DEMUX_H__ + +#include <semaphore.h> +#include <pthread.h> + +#include "capabilities/capa.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define VIDEO_PUT_DIR "/home/Work/Log_repo/video_log" +#define VIDEO_CONF_DATA "/usr/bin/video_conv.sh" +#define FFMPEG_BIN_DIR "/home/Work/Sources_temp/ffmpeg_sources/host/bin/ffmpeg" + +#define VIDEO_DURATION (5 * 60) //sec + +#define KB (1024.0) +#define MB (KB * 1024.0) +#define GB (MB * 1024.0) +#define DISK_FREE_THRES (0.05) + +/*the player work mode status*/ +enum wr_mode { + NORMAL, + PAUSE, +}; + +/*playback mode set key*/ +typedef struct _playback_key { + + /*format: 192.168.1.101*/ + char name[PTOTO_ADDRESS_ADD]; + + /*format: 2022-6-28*/ + char date[PTOTO_ADDRESS_ADD]; + + /*format: 21-32-19*/ + char time[PTOTO_ADDRESS_ADD]; + +} playback_key; + +/*the operational handle*/ +typedef struct _AVDevs { + + /*the devices capabilities*/ + struct tagCapabilities capa; + + /*the profies for each servies*/ + struct tagProfile *profiles; + + timer_t timer_id; + int timer_sec; + + sem_t sem_cap; + + volatile char run_stat; + volatile char slice_stat; + + char ip[PROTO_ADDRESS_SIZE]; + + char uri[PROTO_ADDRESS_SIZE + PTOTO_ADDRESS_ADD]; + char uri_data[PROTO_ADDRESS_SIZE + PTOTO_ADDRESS_ADD]; + + /*the device work stat*/ + char dev_stat; + + /*the process work stat*/ + char proc_stat; + + /*the stat record for pause work mode*/ + char pause_enable; + char pause_prev_loc[MAX_BUF_SIZE]; + char pause_cur_loc[MAX_BUF_SIZE]; + + enum wr_mode work_mode; + +} AVDevs; + +int proto_AVInit(void); +void proto_AVStart(AVDevs *DevData); +void proto_AVStop(AVDevs *DevData, enum wr_mode mode); +void proto_AVClose(void); +AVDevs *proto_AVGethandle(void); +void get_stream(AVDevs *DevData); +int playback_get_key(playback_key set, char *buf, int length); + +static int get_dir_with_key(char *dir_path, char *name, char *key, char *buf, int length); +static int get_file_with_key(char *dir_path, char *key, char *buf, int length, int flag); +static int get_dir_oldest(char *dir_path, char *buf, int length); + +static void cb_av_probe(char *DeviceXAddr); +static int video_file_create(char *buf, int len); +static int av_start_cap(AVDevs *DevData); + +static void system_date_get(char *buf, int len); + +#endif + diff --git a/service/av_demux/video_conv.sh b/service/av_demux/video_conv.sh new file mode 100644 index 0000000..f822601 --- /dev/null +++ b/service/av_demux/video_conv.sh @@ -0,0 +1,58 @@ +#!/bin/sh + +exist_file() +{ + if [ -e "$1" ] + then + return 1 + else + return 2 + fi +} + +if [ $# != 2 ] ; then +echo "USAGE: $0 media_src1 media_src2" +exit 1; +fi + +arg1=`basename $1` + +arg2=`basename $2` + +mainN1=${arg1%%.*} +mainE=${arg1#*.} +mainN2=${arg2%%.*} + +dirname=`dirname $1` + +exist_file $1 +value=$? + +if [ $value -eq 2 ] +then + echo "No source media ${arg1} found in the directory! Put it here firstly!\n" + exit +fi + +exist_file $2 +value=$? + +if [ $value -eq 2 ] +then + echo "No source media ${arg2} found in the directory! Put it here firstly!\n" + exit +fi + +output1=${mainN1}.ts +output2=${mainN2}.ts + +ffmpeg -i $1 -vcodec copy -acodec copy -vbsf h264_mp4toannexb ${output1} +ffmpeg -i $2 -vcodec copy -acodec copy -vbsf h264_mp4toannexb ${output2} +ffmpeg -i "concat:${output1}|${output2}" -acodec copy -vcodec copy -absf aac_adtstoasc ${mainN1}.${mainE} + +rm -rf ${output1} +rm -rf ${output2} +rm -rf $1 +mv ${mainN1}.${mainE} ${dirname} + + diff --git a/service/capabilities/capa.c b/service/capabilities/capa.c index fd2033f..6fc0847 100644 --- a/service/capabilities/capa.c +++ b/service/capabilities/capa.c @@ -87,6 +87,49 @@ return rep.__sizeProfiles; } +int proto_GetVideoSource(const char *DeviceXAddr, char *buf, int len, const char *username, const char *passwd) { + int result = 0; + struct soap *soap = NULL; + struct _trt__GetVideoSources *getVideoSources; + struct _trt__GetVideoSourcesResponse *getVideoSourcesRes; + + SOAP_ASSERT(NULL != DeviceXAddr); + SOAP_ASSERT(NULL != buf); + SOAP_ASSERT(NULL != (soap = proto_soap_new(SOAP_SOCK_TIMEOUT))); + + getVideoSources = soap_new__trt__GetVideoSources(soap, 1); + getVideoSourcesRes = soap_new__trt__GetVideoSourcesResponse(soap, 1); + + proto_SetAuthInfo(soap, username, passwd); + + result = soap_call___trt__GetVideoSources(soap, DeviceXAddr, NULL, getVideoSources, getVideoSourcesRes); + SOAP_CHECK_ERROR(result, soap, "GetVideoSourc"); + + if (getVideoSourcesRes->__sizeVideoSources <= 0) { + + result = SOAP_NO_DATA; + SOAP_CHECK_ERROR(result, soap, "GetVideoSourc"); + + } else { + + for (int i = 0; i < getVideoSourcesRes->__sizeVideoSources; i++) { + + log_level_val(0, "get video source token: ", log_str, getVideoSourcesRes->VideoSources[i].token); + + if (i == 0) { + strncpy(buf, getVideoSourcesRes->VideoSources[i].token, len); + } + } + } + +EXIT: + if (NULL != soap) { + proto_soap_delete(soap); + } + + return result; +} + int proto_GetCapabilities(const char *DeviceXAddr, struct tagCapabilities *capa, const char *username, const char *passwd) { int result = 0; diff --git a/service/ptz/ptz.c b/service/ptz/ptz.c index c7991f0..5921a42 100644 --- a/service/ptz/ptz.c +++ b/service/ptz/ptz.c @@ -2,6 +2,7 @@ #include <stdlib.h> #include <unistd.h> #include <semaphore.h> +#include <string.h> #include <pthread.h> #include <signal.h> #include <errno.h> @@ -22,9 +23,9 @@ int ret; SOAP_ASSERT(DevData != NULL); - SOAP_ASSERT(DevData->profilesToken != NULL); + SOAP_ASSERT(DevData->profiles != NULL); - ret = DevData->profilesToken->venc.Width; + ret = DevData->profiles->venc.Width; return ret; } @@ -35,14 +36,17 @@ int ret; SOAP_ASSERT(DevData != NULL); - SOAP_ASSERT(DevData->profilesToken != NULL); + SOAP_ASSERT(DevData->profiles != NULL); - ret = DevData->profilesToken->venc.Height; + ret = DevData->profiles->venc.Height; return ret; } static void cb_probe(char *DeviceXAddr) { + + int len; + char *pos_s, *pos_e; if (gPtzDevs == NULL) { @@ -51,10 +55,15 @@ SOAP_ASSERT(gPtzDevs != NULL); memset(gPtzDevs, 0x00, sizeof(PtzDevs)); + + pos_s = strstr(DeviceXAddr, ADDR_PREFIX); + pos_e = strstr(DeviceXAddr + strlen(ADDR_PREFIX), ADDR_LAST); + len = pos_e - DeviceXAddr - strlen(ADDR_PREFIX); + memcpy(gPtzDevs->ip, DeviceXAddr + strlen(ADDR_PREFIX), len); } proto_GetCapabilities(DeviceXAddr, &(gPtzDevs->capa), USERNAME, PASSWORD); - proto_GetProfiles(gPtzDevs->capa.MediaXAddr, &(gPtzDevs->profilesToken), USERNAME, PASSWORD); + proto_GetProfiles(gPtzDevs->capa.MediaXAddr, &(gPtzDevs->profiles), USERNAME, PASSWORD); } @@ -76,7 +85,7 @@ ret = sem_init(&(gPtzDevs->sem_tour), 0, 0); SOAP_ASSERT(ret == 0); - timer_init(&(gPtzDevs->timer_id)); + timer_init(&(gPtzDevs->timer_id), ptz_timer_handler); gPtzDevs->dev_stat = DISABLE; pthread_mutex_init(&(gPtzDevs->node_mutex), NULL); @@ -93,7 +102,7 @@ timer_destroy(gPtzDevs->timer_id); - free(gPtzDevs->profilesToken); + free(gPtzDevs->profiles); free(gPtzDevs); @@ -194,70 +203,20 @@ } /*the timer process heandler*/ -static void timer_handler(union sigval para) { +void ptz_timer_handler(union sigval para) { if (gPtzDevs != NULL) { + + pthread_mutex_lock(&(gPtzDevs->node_mutex)); gPtzDevs->wt_stat = DISABLE; pthread_cond_signal(&(gPtzDevs->cond)); + + pthread_mutex_unlock(&(gPtzDevs->node_mutex)); } return; -} - -static int timer_init(timer_t *timer_index) { - struct sigevent event; - timer_t timer; - int ret; - - memset(&event, 0x00, sizeof(event)); - event.sigev_value.sival_int = ENABLE; - event.sigev_value.sival_ptr = NULL; - event.sigev_notify = SIGEV_THREAD; - event.sigev_notify_function = timer_handler; - - ret = timer_create(CLOCK_REALTIME, &event, &timer); - if (ret) { - return -1; - } - - if (timer_index != NULL) { - *timer_index = timer; - } - - return 0; -} - -static int timer_start(timer_t timer_index, int sec) { - int ret; - struct itimerspec ts; - - ts.it_interval.tv_sec = 0; - ts.it_interval.tv_nsec = 0; - ts.it_value.tv_sec = sec; - ts.it_value.tv_nsec = 0; - ret = timer_settime(timer_index, 0, &ts, NULL); - if (ret) { - return -1; - } - - return ret; -} - -static int timer_stop(timer_t timer_index) { - - int ret = timer_start(timer_index, 0); - - return ret; -} - -static int timer_destroy(timer_t timer_index) { - int ret; - - ret = timer_delete(timer_index); - - return ret; } /*initialize the PTZ*/ @@ -355,7 +314,7 @@ struct _tptz__GetStatusResponse *getStatusResponse = NULL; SOAP_ASSERT(DevData != NULL); - SOAP_ASSERT(NULL != DevData->profilesToken); + SOAP_ASSERT(NULL != DevData->profiles); SOAP_ASSERT(NULL != (soap = proto_soap_new(SOAP_SOCK_TIMEOUT))); getStatus = soap_new__tptz__GetStatus(soap, 1); @@ -364,7 +323,7 @@ strncpy(PTZXAddr, DevData->capa.PTZXAddr, PROTO_ADDRESS_SIZE); proto_SetAuthInfo(soap, username, passwd); - getStatus->ProfileToken = DevData->profilesToken->token; + getStatus->ProfileToken = DevData->profiles->token; result = soap_call___tptz__GetStatus(soap, PTZXAddr, NULL, getStatus, getStatusResponse); SOAP_CHECK_ERROR(result, soap, "proto_PTZ_GetStatus"); @@ -614,7 +573,7 @@ char PTZXAddr[PROTO_ADDRESS_SIZE] = { 0x00 }; SOAP_ASSERT(DevData != NULL); - SOAP_ASSERT(NULL != DevData->profilesToken); + SOAP_ASSERT(NULL != DevData->profiles); SOAP_ASSERT(NULL != (soap = proto_soap_new(SOAP_SOCK_TIMEOUT))); proto_PTZ_GetStatus(DevData, &pos_get, username, passwd); @@ -628,7 +587,7 @@ strncpy(PTZXAddr, DevData->capa.PTZXAddr, PROTO_ADDRESS_SIZE); proto_SetAuthInfo(soap, username, passwd); - absMove->ProfileToken = DevData->profilesToken->token; + absMove->ProfileToken = DevData->profiles->token; absMove->Position = soap_new_tt__PTZVector(soap, 1); absMove->Position->PanTilt = soap_new_tt__Vector2D(soap, 1); @@ -660,7 +619,7 @@ enum xsd__boolean xsd_false = xsd__boolean__false_; SOAP_ASSERT(DevData != NULL); - SOAP_ASSERT(NULL != DevData->profilesToken); + SOAP_ASSERT(NULL != DevData->profiles); SOAP_ASSERT(NULL != (soap = proto_soap_new(SOAP_SOCK_TIMEOUT))); struct _tptz__Stop *tptzStop = soap_new__tptz__Stop(soap, 1); @@ -668,7 +627,7 @@ strncpy(PTZXAddr, DevData->capa.PTZXAddr, PROTO_ADDRESS_SIZE); proto_SetAuthInfo(soap, username, passwd); - tptzStop->ProfileToken = DevData->profilesToken->token; + tptzStop->ProfileToken = DevData->profiles->token; tptzStop->PanTilt = &xsd_true; tptzStop->Zoom = &xsd_false; @@ -693,7 +652,7 @@ char PTZXAddr[PROTO_ADDRESS_SIZE] = { 0x00 }; SOAP_ASSERT(DevData != NULL); - SOAP_ASSERT(NULL != DevData->profilesToken); + SOAP_ASSERT(NULL != DevData->profiles); SOAP_ASSERT(NULL != (soap = proto_soap_new(SOAP_SOCK_TIMEOUT))); struct _tptz__ContinuousMove* contMove = soap_new__tptz__ContinuousMove(soap, 1); @@ -705,7 +664,7 @@ strncpy(PTZXAddr, DevData->capa.PTZXAddr, PROTO_ADDRESS_SIZE); proto_SetAuthInfo(soap, username, passwd); - contMove->ProfileToken = DevData->profilesToken->token; + contMove->ProfileToken = DevData->profiles->token; contMove->Velocity = soap_new_tt__PTZSpeed(soap, 1); memset(contMove->Velocity, 0x00, sizeof(struct tt__PTZSpeed)); contMove->Velocity->PanTilt = soap_new_tt__Vector2D(soap, 1); @@ -863,7 +822,7 @@ char PTZXAddr[PROTO_ADDRESS_SIZE] = { 0x00 }; SOAP_ASSERT(DevData != NULL); - SOAP_ASSERT(NULL != DevData->profilesToken); + SOAP_ASSERT(NULL != DevData->profiles); SOAP_ASSERT(NULL != (soap = proto_soap_new(SOAP_SOCK_TIMEOUT))); pos_p = para_check(pos_p); @@ -875,7 +834,7 @@ strncpy(PTZXAddr, DevData->capa.PTZXAddr, PROTO_ADDRESS_SIZE); proto_SetAuthInfo(soap, username, passwd); - relMove->ProfileToken = DevData->profilesToken->token; + relMove->ProfileToken = DevData->profiles->token; relMove->Translation = (struct tt__PTZVector *)soap_malloc(soap, sizeof(struct tt__PTZVector)); memset(relMove->Translation, 0x00, sizeof(struct tt__PTZVector)); relMove->Translation->PanTilt = soap_new_tt__Vector2D(soap, 1); @@ -953,7 +912,7 @@ } /*set the focus-on functionality*/ -int proto_PTZ_ImagingSet(PtzDevs *DevData, float speed, const char *username, const char *passwd) { +int proto_PTZ_ImagingSet(PtzDevs *DevData, enum PTZCMD cmd, float speed, const char *username, const char *passwd) { int result = 0; float speed_val; struct soap *soap = NULL; @@ -961,34 +920,61 @@ struct tt__ContinuousFocus *stContFocus = NULL; struct _timg__Move *stMoveReq = NULL; struct _timg__MoveResponse *stMoveRes = NULL; + struct _timg__Stop *stStopReq = NULL; + struct _timg__StopResponse *stStopRes = NULL; SOAP_ASSERT(NULL != DevData); - SOAP_ASSERT(NULL != DevData->profilesToken); + SOAP_ASSERT(NULL != DevData->profiles); SOAP_ASSERT(NULL != (soap = proto_soap_new(SOAP_SOCK_TIMEOUT))); stFocusMove = soap_new_tt__FocusMove(soap, 1); stContFocus = soap_new_tt__ContinuousFocus(soap, 1); - - proto_SetAuthInfo(soap, username, passwd); - + stMoveReq = soap_new__timg__Move(soap, 1); stMoveRes = soap_new__timg__MoveResponse(soap, 1); + + stStopReq = soap_new__timg__Stop(soap, 1); + stStopRes = soap_new__timg__StopResponse(soap, 1); memset(stMoveReq, 0x00, sizeof(struct _timg__Move)); memset(stMoveRes, 0x00, sizeof(struct _timg__MoveResponse)); - speed_val = pos_res_z(speed); + memset(stStopReq, 0x00, sizeof(struct _timg__Stop)); + memset(stStopRes, 0x00, sizeof(struct _timg__StopResponse)); - stContFocus->Speed = speed_val; + stMoveReq->Focus = stFocusMove; + stMoveReq->Focus->Continuous = stContFocus; + + stMoveReq->VideoSourceToken = DevData->profiles->videoCfg.sourceToken; + stStopReq->VideoSourceToken = DevData->profiles->videoCfg.sourceToken; + + proto_SetAuthInfo(soap, username, passwd); + + speed_val = pos_res_z(speed); + switch(cmd) { + case PTZ_CMD_FOCUS_IN: + stContFocus->Speed = speed_val; + + break; + + case PTZ_CMD_FOCUS_OUT: + stContFocus->Speed = speed_val * (-1); + + break; + + default: + result = soap_call___timg__Stop(soap, DevData->capa.MediaXAddr, NULL, stStopReq, stStopRes); + SOAP_CHECK_ERROR(result, soap, "proto_PTZ_ImagingSet"); + + break; + } + stFocusMove->Continuous = stContFocus; stFocusMove->Absolute = NULL; stFocusMove->Relative = NULL; - stMoveReq->Focus = stFocusMove; - stMoveReq->VideoSourceToken = DevData->profilesToken->videoCfg.token; - - result = soap_call___timg__Move(soap, DevData->profilesToken->token, NULL, stMoveReq, stMoveRes); - SOAP_CHECK_ERROR(result, soap, "proto_PTZ_FocusSet"); + result = soap_call___timg__Move(soap, DevData->capa.MediaXAddr, NULL, stMoveReq, stMoveRes); + SOAP_CHECK_ERROR(result, soap, "proto_PTZ_ImagingSet"); EXIT: if (NULL != soap) { @@ -1007,7 +993,7 @@ char PTZXAddr[PROTO_ADDRESS_SIZE] = { 0x00 }; SOAP_ASSERT(DevData != NULL); - SOAP_ASSERT(NULL != DevData->profilesToken); + SOAP_ASSERT(NULL != DevData->profiles); SOAP_ASSERT(NULL != (soap = proto_soap_new(SOAP_SOCK_TIMEOUT))); strncpy(PTZXAddr, DevData->capa.PTZXAddr, PROTO_ADDRESS_SIZE); @@ -1020,7 +1006,7 @@ memset(setPreset, 0x00, sizeof(struct _tptz__SetPreset)); memset(setPresetRes, 0x00, sizeof(struct _tptz__SetPresetResponse)); - setPreset->ProfileToken = DevData->profilesToken->token; + setPreset->ProfileToken = DevData->profiles->token; if (posName != NULL) { setPreset->PresetName = (char *)posName; } @@ -1039,7 +1025,7 @@ memset(getPresets, 0x00, sizeof(struct _tptz__GetPresets)); memset(getPresetsRes, 0x00, sizeof(struct _tptz__GetPresetsResponse)); - getPresets->ProfileToken = DevData->profilesToken->token; + getPresets->ProfileToken = DevData->profiles->token; result = soap_call___tptz__GetPresets(soap, PTZXAddr, NULL, getPresets, getPresetsRes); SOAP_CHECK_ERROR(result, soap, "proto_PTZPreset"); @@ -1055,7 +1041,7 @@ memset(gotoPreset, 0x00, sizeof(struct _tptz__GotoPreset)); memset(gotoPresetRes, 0x00, sizeof(struct _tptz__GotoPresetResponse)); - gotoPreset->ProfileToken = DevData->profilesToken->token; + gotoPreset->ProfileToken = DevData->profiles->token; if (posToken != NULL) { sprintf(buf, "%d", *posToken); @@ -1072,7 +1058,7 @@ memset(rmPreset, 0x00, sizeof(struct _tptz__RemovePreset)); memset(rmPresetRes, 0x00, sizeof(struct _tptz__RemovePresetResponse)); - rmPreset->ProfileToken = DevData->profilesToken->token; + rmPreset->ProfileToken = DevData->profiles->token; if (posToken != NULL) { sprintf(buf, "%d", *posToken); rmPreset->PresetToken = buf; diff --git a/service/ptz/ptz.h b/service/ptz/ptz.h index 37e0894..6071030 100644 --- a/service/ptz/ptz.h +++ b/service/ptz/ptz.h @@ -10,9 +10,6 @@ #include "capabilities/capa.h" -#define USERNAME "On_admin" -#define PASSWORD "a12345678" - #define HK_IDS_2DE 1 #if defined(HK_IDS_2DE) @@ -44,9 +41,6 @@ #define MIN_TOUR_TIME 15 #define MIN_TOUR_POS 2 -#define WT_TIME 5 -#define STOP_WT_TIME 3 - #define MAX_IMG_SCALE 0.5 #define PI 3.14159 @@ -60,9 +54,6 @@ #define COEF_FV_A 0.953 #define COEF_FV_B 0.598 #define COEF_FV_C 0.166 - -#define ENABLE 0 -#define DISABLE 1 /*PTZ working stat*/ enum PTZStat { @@ -95,6 +86,9 @@ PTZ_CMD_RIGHTDOWN, PTZ_CMD_ZOOM_IN, PTZ_CMD_ZOOM_OUT, + PTZ_CMD_FOCUS_IN, + PTZ_CMD_FOCUS_OUT, + PTZ_CMD_FOCUS_STOP, }; /*the tradditional preset control command*/ @@ -143,7 +137,7 @@ struct tagCapabilities capa; - struct tagProfile *profilesToken; + struct tagProfile *profiles; PresetToure_node *posNode; int posNode_count; @@ -166,6 +160,8 @@ /*the touring process work stat*/ char proc_stat; + + char ip[PROTO_ADDRESS_SIZE]; enum tourType tour_type; @@ -199,7 +195,7 @@ int proto_PTZPreset(PtzDevs *DevData, const char *posName, enum PreSetCMD cmd, \ int *posToken, const char *username, const char *passwd); -int proto_PTZ_ImagingSet(PtzDevs *DevData, float speed, const char *username, const char *passwd); +int proto_PTZ_ImagingSet(PtzDevs *DevData, enum PTZCMD cmd, float speed, const char *username, const char *passwd); static void *task_preset_touring(void *arg); float proto_PTZZoom_get(PtzDevs *DevData, int x0, int y0, int x1, int y1); @@ -209,11 +205,7 @@ void proto_PTZWaitStopped(PtzDevs *DevData, const char *username, const char *passwd); void proto_PTZPreset_tour_stop(PtzDevs *DevData); -static void timer_handler(union sigval para); -static int timer_init(timer_t *timer_index); -static int timer_start(timer_t timer_index, int sec); -static int timer_stop(timer_t timer_index); -static int timer_destroy(timer_t timer_index); +static void ptz_timer_handler(union sigval para); #ifdef __cplusplus } diff --git a/test/Makefile.inc b/test/Makefile.inc index e9c20a2..75bb0e3 100644 --- a/test/Makefile.inc +++ b/test/Makefile.inc @@ -27,15 +27,20 @@ OBJECTS_ONVIF := $(patsubst %.c,$(TEMPDIR)%.o,$(filter %.c, $(SOURCES_CORE))) OBJECTS_COMM := $(patsubst %.c,$(TEMPDIR)%.o,$(filter %.c, $(SOURCES_COMM))) +FFMPEG_DIR = ../../thirdparty/ffmpeg OPENSSL_DIR = ../../thirdparty/openssl # INCLUDE += -I../../core/ \ -I../../comm/ \ + -I$(FFMPEG_DIR)/include \ -I$(OPENSSL_DIR)/include CFLAGS += $(INCLUDE) +LDFLAGS += -L$(FFMPEG_DIR)/lib LDFLAGS += -L$(OPENSSL_DIR)/lib +LDLIBS += -lavcodec -lavdevice -lavfilter -lavformat \ + -lavutil -lswresample -lswscale LDLIBS += -lcrypto -lssl -lpthread -ldl %.o: %.cpp diff --git a/test/av_test/Makefile b/test/av_test/Makefile new file mode 100644 index 0000000..33ba199 --- /dev/null +++ b/test/av_test/Makefile @@ -0,0 +1,52 @@ +CC := gcc +CPP := g++ +LD := ld +AR := ar +STRIP := strip +RM := rm + +PROGRAM = av_stream_test + +SOURCES += av_test.c + +CFLAGS += -Wall -DWITH_DOM -DWITH_NONAMESPACES -DWITH_OPENSSL -Wno-unused + +OBJECTS := $(patsubst %.c,$(TEMPDIR)%.o,$(filter %.c, $(SOURCES))) + +%.o: %.cpp + @echo " CPP " $@; + @$(CPP) $(CFLAGS) -c -o $@ $< + +%.o: %.c + @echo " CC " $@; + @$(CC) $(CFLAGS) -c -o $@ $< + +FFMPEG_DIR = ../../thirdparty/ffmpeg +OPENSSL_DIR = ../../thirdparty/openss + +LDFLAGS += -L$(FFMPEG_DIR)/lib +LDFLAGS += -L$(OPENSSL_DIR)/lib +LDFLAGS += -L../../ +LDLIBS += -lonvif_std +LDLIBS += -lavcodec -lavdevice -lavfilter -lavformat \ + -lavutil -lswresample -lswscale +LDLIBS += -lcrypto -lssl -lpthread -ldl -lrt +LDLIBS += -lprotobuf -lprotobuf-lite + +INCLUDE += -I../../core/ \ + -I../../comm/ \ + -I../../service \ + -I$(FFMPEG_DIR)/include \ + -I$(OPENSSL_DIR)/include +CFLAGS += $(INCLUDE) + +all: $(OBJECTS) + $(CC) -o $(PROGRAM) $(OBJECTS) $(LDFLAGS) $(LDLIBS) $(CFLAGS) + +clean: + $(RM) -f $(OBJECTS) + $(RM) -f $(PROGRAM) + +allclean: clean + $(RM) -f $(OBJECTS_ONVIF) + diff --git a/test/av_test/av_test.c b/test/av_test/av_test.c new file mode 100644 index 0000000..7f4e660 --- /dev/null +++ b/test/av_test/av_test.c @@ -0,0 +1,66 @@ +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> + +#include "PTZBinding.nsmap" +#include "av_demux/av_demux.h" + +int main(int argc, char **argv) +{ + int ret; + char parse_buf[MAX_BUF_SIZE] = { 0x00 }; + playback_key data_set = {"192.168.1.101", "2022-7-3", "21-52-16"}; + AVDevs *handle = NULL; + + ret = proto_AVInit(); + if (ret < 0) { + printf("AV stream initialization failure!\n"); + + return 0; + } + + printf("start the av stream:\n"); + handle = proto_AVGethandle(); + proto_AVStart(handle); + + sleep(5 * 60 * 2); + + printf("stop the av stream now:\n"); + proto_AVStop(handle, NORMAL); + + sleep(3); + + printf("re-start the AV now:\n"); + proto_AVStart(handle); + + sleep(120); + + printf("pause the av stream now:\n"); + proto_AVStop(handle, PAUSE); + + sleep(20); + + printf("resume the av:\n"); + proto_AVStart(handle); + + sleep(200); + + printf("stop the av"); + proto_AVStop(handle, NORMAL); + + sleep(3); + + ret = playback_get_key(data_set, parse_buf, sizeof(parse_buf)); + if (ret > 0) { + printf("found the playback file: %s\n", parse_buf); + } else { + printf("the playback file is not existed!\n"); + } + + sleep(3000); + printf("now exit the process:\n"); + proto_AVClose(); + + return 0; +} + diff --git a/test/probe_test/Makefile b/test/probe_test/Makefile index a9ba811..4b8a57b 100644 --- a/test/probe_test/Makefile +++ b/test/probe_test/Makefile @@ -19,16 +19,21 @@ @echo " CC " $@; @$(CC) $(CFLAGS) -c -o $@ $< +FFMPEG_DIR = ../../thirdparty/ffmpeg OPENSSL_DIR = ../../thirdparty/openss +LDFLAGS += -L$(FFMPEG_DIR)/lib LDFLAGS += -L$(OPENSSL_DIR)/lib LDFLAGS += -L../../ LDLIBS += -lonvif_std +LDLIBS += -lavcodec -lavdevice -lavfilter -lavformat \ + -lavutil -lswresample -lswscale LDLIBS += -lcrypto -lssl -lpthread -ldl -lm -lrt INCLUDE += -I../../core/ \ -I../../comm/ \ -I../../service \ + -I$(FFMPEG_DIR)/include \ -I$(OPENSSL_DIR)/include CFLAGS += $(INCLUDE) diff --git a/test/ptz_test/Makefile b/test/ptz_test/Makefile index 0eb8ec3..8328d26 100644 --- a/test/ptz_test/Makefile +++ b/test/ptz_test/Makefile @@ -21,16 +21,21 @@ @echo " CC " $@; @$(CC) $(CFLAGS) -c -o $@ $< +FFMPEG_DIR = ../../thirdparty/ffmpeg OPENSSL_DIR = ../../thirdparty/openss +LDFLAGS += -L$(FFMPEG_DIR)/lib LDFLAGS += -L$(OPENSSL_DIR)/lib LDFLAGS += -L../../ LDLIBS += -lonvif_std +LDLIBS += -lavcodec -lavdevice -lavfilter -lavformat \ + -lavutil -lswresample -lswscale LDLIBS += -lcrypto -lssl -lpthread -ldl -lm -lrt INCLUDE += -I../../core/ \ -I../../comm/ \ -I../../service \ + -I$(FFMPEG_DIR)/include \ -I$(OPENSSL_DIR)/include CFLAGS += $(INCLUDE) diff --git a/test/ptz_test/ptz_test.c b/test/ptz_test/ptz_test.c index 02d924d..bcc04f5 100644 --- a/test/ptz_test/ptz_test.c +++ b/test/ptz_test/ptz_test.c @@ -13,7 +13,6 @@ { int ret; PosCur pos_get; - float data; int preset0, preset1, preset2; float pval, tval, zval; float speed_p, speed_t, speed_z; @@ -131,6 +130,7 @@ * secondly, zoom in the object that is describled with left-up and right-down pixel; * finally, restore the image as original size; */ + float data; proto_PTZ_GetStatus(handle, &pos_get, USERNAME, PASSWORD); proto_PTZGetPT(handle, 0, 0, &pval, &tval, USERNAME, PASSWORD); proto_PTZSet(handle, pval, tval, pos_get.z, USERNAME, PASSWORD); -- Gitblit v1.8.0