FuJuntang
2022-07-06 e5cff5a3ef373a5090f45cd1dfb0b85d9c851d5d
Add video recorder and playback support.
11个文件已修改
5个文件已添加
1540 ■■■■ 已修改文件
Makefile 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
comm/proto_comm.c 146 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
comm/proto_comm.h 46 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
comm/proto_dbg.h 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
service/av_demux/av_demux.c 810 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
service/av_demux/av_demux.h 100 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
service/av_demux/video_conv.sh 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
service/capabilities/capa.c 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
service/ptz/ptz.c 164 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
service/ptz/ptz.h 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/Makefile.inc 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/av_test/Makefile 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/av_test/av_test.c 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/probe_test/Makefile 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/ptz_test/Makefile 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
test/ptz_test/ptz_test.c 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
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     " $@; 
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, "//");
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);
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
service/av_demux/av_demux.c
New file
@@ -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;
}
service/av_demux/av_demux.h
New file
@@ -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
service/av_demux/video_conv.sh
New file
@@ -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}
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;
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;
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
}
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
test/av_test/Makefile
New file
@@ -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)
test/av_test/av_test.c
New file
@@ -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;
}
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)
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)
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);