#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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; }