| #include <stdio.h> |
| #include <unistd.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <errno.h> |
| #include "dvr_types.h" |
| #include "segment.h" |
| |
| #define MAX_SEGMENT_FD_COUNT (128) |
| #define MAX_SEGMENT_PATH_SIZE (DVR_MAX_LOCATION_SIZE + 32) |
| #define MAX_PTS_THRESHOLD (10*1000) |
| #define PCR_RECORD_INTERVAL_MS (300) |
| #define PTS_DISCONTINUED_DEVIATION (40) |
| #define PTS_HEAD_DEVIATION (40) |
| #define PCR_JUMP_DUR (5000) |
| |
| #define IDX_FILE_SYNC_TIME (10)//10*PCR_RECORD_INTERVAL_MS |
| #define TS_FILE_SYNC_TIME (9)//9*PCR_RECORD_INTERVAL_MS |
| |
| |
| /**\brief Segment context*/ |
| typedef struct { |
| int ts_fd; /**< Segment ts file fd*/ |
| FILE *index_fp; /**< Time index file fd*/ |
| FILE *dat_fp; /**< Information file fd*/ |
| FILE *all_dat_fp; /**< Information file fd*/ |
| FILE *ongoing_fp; /**< Ongoing file fd, used to verify timeshift mode*/ |
| uint64_t first_pts; /**< First pts value, use for write mode*/ |
| uint64_t last_pts; /**< Last input pts value, use for write mode*/ |
| uint64_t last_record_pts; /**< Last record pts value, use for write mode*/ |
| uint64_t cur_time; /**< Current time save in index file */ |
| uint64_t segment_id; /**< Current segment ID */ |
| char location[MAX_SEGMENT_PATH_SIZE]; /**< Current time save in index file */ |
| loff_t first_offset; |
| loff_t last_offset; |
| loff_t last_record_offset; |
| float avg_rate; |
| int time; |
| DVR_Bool_t force_sysclock; /**< If ture, force to use system clock as PVR index time source. If false, libdvr can determine index time source based on actual situation*/ |
| } Segment_Context_t; |
| |
| /**\brief Segment file type*/ |
| typedef enum { |
| SEGMENT_FILE_TYPE_TS, /**< Used for store TS data*/ |
| SEGMENT_FILE_TYPE_INDEX, /**< Used for store index data*/ |
| SEGMENT_FILE_TYPE_DAT, /**< Used for store information data, such as duration etc*/ |
| SEGMENT_FILE_TYPE_ONGOING, /**< Used for store information data, such as duration etc*/ |
| SEGMENT_FILE_TYPE_ALL_DATA, /**< Used for store all information data*/ |
| } Segment_FileType_t; |
| |
| static void segment_get_fname(char fname[MAX_SEGMENT_PATH_SIZE], |
| const char location[DVR_MAX_LOCATION_SIZE], |
| uint64_t segment_id, |
| Segment_FileType_t type) |
| { |
| int offset; |
| |
| offset = strlen(location); |
| DVR_ASSERT(offset < DVR_MAX_LOCATION_SIZE); |
| |
| memset(fname, 0, MAX_SEGMENT_PATH_SIZE); |
| strncpy(fname, location, offset); |
| |
| if (type != SEGMENT_FILE_TYPE_ALL_DATA) { |
| strncpy(fname + offset, "-", 2); |
| offset += 1; |
| sprintf(fname + offset, "%04llu", segment_id); |
| offset += strlen(fname + offset); |
| } |
| |
| if (type == SEGMENT_FILE_TYPE_TS) |
| strncpy(fname + offset, ".ts", 4); |
| else if (type == SEGMENT_FILE_TYPE_INDEX) |
| strncpy(fname + offset, ".idx", 5); |
| else if (type == SEGMENT_FILE_TYPE_DAT) |
| strncpy(fname + offset, ".dat", 5); |
| else if (type == SEGMENT_FILE_TYPE_ONGOING) |
| strncpy(fname + offset, ".going", 7); |
| else if (type == SEGMENT_FILE_TYPE_ALL_DATA) |
| strncpy(fname + offset, ".dat", 5); |
| |
| } |
| |
| static void segment_get_dirname(char dir_name[MAX_SEGMENT_PATH_SIZE], |
| const char location[DVR_MAX_LOCATION_SIZE]) |
| { |
| char *p; |
| int i; |
| int found = 0; |
| |
| for (i = 0; i < (int)strlen(location); i++) { |
| if (location[i] == '/') { |
| p = (char *)location + i; |
| found = 1; |
| } |
| } |
| if (found) |
| memcpy(dir_name, location, p - location); |
| } |
| |
| int segment_open(Segment_OpenParams_t *params, Segment_Handle_t *p_handle) |
| { |
| Segment_Context_t *p_ctx; |
| char ts_fname[MAX_SEGMENT_PATH_SIZE]; |
| char index_fname[MAX_SEGMENT_PATH_SIZE]; |
| char dat_fname[MAX_SEGMENT_PATH_SIZE]; |
| char all_dat_fname[MAX_SEGMENT_PATH_SIZE]; |
| char dir_name[MAX_SEGMENT_PATH_SIZE]; |
| char going_name[MAX_SEGMENT_PATH_SIZE]; |
| int ret = 0; |
| |
| DVR_RETURN_IF_FALSE(params); |
| DVR_RETURN_IF_FALSE(p_handle); |
| |
| //DVR_INFO("%s, location:%s, id:%llu", __func__, params->location, params->segment_id); |
| |
| p_ctx = (void*)malloc(sizeof(Segment_Context_t)); |
| DVR_RETURN_IF_FALSE(p_ctx); |
| memset(p_ctx, 0, sizeof(Segment_Context_t)); |
| |
| memset(ts_fname, 0, sizeof(ts_fname)); |
| segment_get_fname(ts_fname, params->location, params->segment_id, SEGMENT_FILE_TYPE_TS); |
| |
| memset(index_fname, 0, sizeof(index_fname)); |
| segment_get_fname(index_fname, params->location, params->segment_id, SEGMENT_FILE_TYPE_INDEX); |
| |
| memset(dat_fname, 0, sizeof(dat_fname)); |
| segment_get_fname(dat_fname, params->location, params->segment_id, SEGMENT_FILE_TYPE_DAT); |
| |
| memset(all_dat_fname, 0, sizeof(all_dat_fname)); |
| segment_get_fname(all_dat_fname, params->location, params->segment_id, SEGMENT_FILE_TYPE_ALL_DATA); |
| |
| |
| memset(going_name, 0, sizeof(going_name)); |
| segment_get_fname(going_name, params->location, params->segment_id, SEGMENT_FILE_TYPE_ONGOING); |
| |
| memset(dir_name, 0, sizeof(dir_name)); |
| segment_get_dirname(dir_name, params->location); |
| |
| ret = mkdir(dir_name, 0770); |
| if (ret == -1) { |
| DVR_WARN("mkdir of %s returns %d due to errno:%d,%s", |
| dir_name,ret,errno,strerror(errno)); |
| } |
| if (access(dir_name, F_OK) == -1) { |
| DVR_ERROR("%s dir %s does not exist", __func__, dir_name); |
| free(p_ctx); |
| return DVR_FAILURE; |
| } |
| |
| if (params->mode == SEGMENT_MODE_READ) { |
| p_ctx->ts_fd = open(ts_fname, O_RDONLY); |
| p_ctx->index_fp = fopen(index_fname, "r"); |
| p_ctx->dat_fp = fopen(dat_fname, "r"); |
| p_ctx->ongoing_fp = NULL; |
| p_ctx->all_dat_fp = fopen(all_dat_fname, "r"); |
| } else if (params->mode == SEGMENT_MODE_WRITE) { |
| p_ctx->ts_fd = open(ts_fname, O_CREAT | O_RDWR | O_TRUNC, 0644); |
| p_ctx->index_fp = fopen(index_fname, "w+"); |
| p_ctx->dat_fp = fopen(dat_fname, "w+"); |
| p_ctx->all_dat_fp = fopen(all_dat_fname, "a+"); |
| DVR_INFO("%s dir %s is opened", __func__, all_dat_fname); |
| p_ctx->ongoing_fp = fopen(going_name, "w+"); |
| p_ctx->first_pts = ULLONG_MAX; |
| p_ctx->last_pts = ULLONG_MAX; |
| p_ctx->last_record_pts = ULLONG_MAX; |
| p_ctx->avg_rate = 0.0; |
| } else { |
| DVR_INFO("%s, unknown mode use default", __func__); |
| p_ctx->ts_fd = open(ts_fname, O_RDONLY); |
| p_ctx->index_fp = fopen(index_fname, "r"); |
| p_ctx->dat_fp = fopen(dat_fname, "r"); |
| p_ctx->all_dat_fp = fopen(all_dat_fname, "r"); |
| p_ctx->ongoing_fp = NULL; |
| } |
| |
| if (p_ctx->ts_fd == -1 || !p_ctx->index_fp || !p_ctx->dat_fp) { |
| DVR_INFO("%s open file failed [%s, %s, %s], reason:%s", __func__, |
| ts_fname, index_fname, dat_fname, strerror(errno)); |
| if (p_ctx->ts_fd != -1) |
| close(p_ctx->ts_fd); |
| if (p_ctx->index_fp) |
| fclose(p_ctx->index_fp); |
| if (p_ctx->dat_fp) |
| fclose(p_ctx->dat_fp); |
| if (p_ctx->all_dat_fp) |
| fclose(p_ctx->all_dat_fp); |
| if (p_ctx->ongoing_fp) |
| fclose(p_ctx->ongoing_fp); |
| free(p_ctx); |
| *p_handle = NULL; |
| return DVR_FAILURE; |
| } |
| p_ctx->segment_id = params->segment_id; |
| strncpy(p_ctx->location, params->location, strlen(params->location)+1); |
| p_ctx->force_sysclock = params->force_sysclock; |
| |
| //DVR_INFO("%s, open file success p_ctx->location [%s]", __func__, p_ctx->location, params->mode); |
| *p_handle = (Segment_Handle_t)p_ctx; |
| return DVR_SUCCESS; |
| } |
| |
| int segment_close(Segment_Handle_t handle) |
| { |
| Segment_Context_t *p_ctx; |
| |
| p_ctx = (void *)handle; |
| DVR_RETURN_IF_FALSE(p_ctx); |
| |
| if (p_ctx->ts_fd != -1) { |
| close(p_ctx->ts_fd); |
| } |
| |
| if (p_ctx->index_fp) { |
| fclose(p_ctx->index_fp); |
| } |
| |
| if (p_ctx->dat_fp) { |
| fclose(p_ctx->dat_fp); |
| } |
| if (p_ctx->all_dat_fp) { |
| fclose(p_ctx->all_dat_fp); |
| } |
| if (p_ctx->ongoing_fp != NULL) { |
| fclose(p_ctx->ongoing_fp); |
| char going_name[MAX_SEGMENT_PATH_SIZE]; |
| memset(going_name, 0, sizeof(going_name)); |
| segment_get_fname(going_name, p_ctx->location, p_ctx->segment_id, SEGMENT_FILE_TYPE_ONGOING); |
| DVR_INFO("segment close del [%s]", going_name); |
| unlink(going_name); |
| } |
| |
| free(p_ctx); |
| return 0; |
| } |
| |
| ssize_t segment_read(Segment_Handle_t handle, void *buf, size_t count) |
| { |
| Segment_Context_t *p_ctx; |
| ssize_t len; |
| p_ctx = (Segment_Context_t *)handle; |
| DVR_RETURN_IF_FALSE(p_ctx); |
| DVR_RETURN_IF_FALSE(buf); |
| DVR_RETURN_IF_FALSE(p_ctx->ts_fd != -1); |
| len = read(p_ctx->ts_fd, buf, count); |
| return len; |
| } |
| |
| ssize_t segment_write(Segment_Handle_t handle, void *buf, size_t count) |
| { |
| Segment_Context_t *p_ctx; |
| ssize_t len; |
| p_ctx = (Segment_Context_t *)handle; |
| DVR_RETURN_IF_FALSE(p_ctx); |
| DVR_RETURN_IF_FALSE(buf); |
| DVR_RETURN_IF_FALSE(p_ctx->ts_fd != -1); |
| len = write(p_ctx->ts_fd, buf, count); |
| /*remove the fsync, use /proc to control the data writeback*/ |
| //if (p_ctx->time % TS_FILE_SYNC_TIME == 0) |
| // fsync(p_ctx->ts_fd); |
| return len; |
| } |
| |
| int segment_update_pts_force(Segment_Handle_t handle, uint64_t pts, loff_t offset) |
| { |
| Segment_Context_t *p_ctx; |
| char buf[256]; |
| int record_diff = 0; |
| |
| p_ctx = (Segment_Context_t *)handle; |
| DVR_RETURN_IF_FALSE(p_ctx); |
| DVR_RETURN_IF_FALSE(p_ctx->index_fp); |
| |
| if (p_ctx->first_pts == ULLONG_MAX) { |
| DVR_INFO("%s first pcr:%llu", __func__, pts); |
| p_ctx->first_pts = pts; |
| p_ctx->first_offset = offset; |
| } |
| memset(buf, 0, sizeof(buf)); |
| if (p_ctx->last_pts == ULLONG_MAX) { |
| /*Last pts is init value*/ |
| sprintf(buf, "{time=%llu, offset=%lld}", pts - p_ctx->first_pts, offset); |
| p_ctx->cur_time = pts - p_ctx->first_pts; |
| DVR_INFO("%s force pcr:%llu -1", __func__, pts); |
| } else { |
| /*Last pts has valid value*/ |
| int diff = pts - p_ctx->last_pts; |
| if ((diff > MAX_PTS_THRESHOLD) || (diff < 0)) { |
| /*Current pts has a transition*/ |
| DVR_INFO("[%s]force update Current pts has a transition, [%llu, %llu, %llu]",__func__, |
| p_ctx->first_pts, p_ctx->last_pts, pts); |
| sprintf(buf, "\n{time=%llu, offset=%lld}", p_ctx->cur_time, offset); |
| } else { |
| /*This is a normal pts, record it*/ |
| //check if this pcr is transition.if true,add 200ms |
| //other case normal. |
| p_ctx->cur_time += diff; |
| DVR_INFO("%s force pcr:%llu -1 diff [%d]", __func__, pts, diff); |
| sprintf(buf, "\n{time=%llu, offset=%lld}", p_ctx->cur_time, offset); |
| } |
| } |
| |
| record_diff = pts - p_ctx->last_record_pts; |
| if (strlen(buf) > 0) { |
| DVR_INFO("%s force pcr:%llu buf:%s", __func__, pts, buf); |
| fputs(buf, p_ctx->index_fp); |
| fflush(p_ctx->index_fp); |
| //fsync(fileno(p_ctx->index_fp)); |
| p_ctx->last_record_pts = pts; |
| } |
| p_ctx->last_pts = pts; |
| return DVR_SUCCESS; |
| } |
| |
| int segment_update_pts(Segment_Handle_t handle, uint64_t pts, loff_t offset) |
| { |
| Segment_Context_t *p_ctx; |
| char buf[256]; |
| int record_diff = 0; |
| |
| p_ctx = (Segment_Context_t *)handle; |
| DVR_RETURN_IF_FALSE(p_ctx); |
| DVR_RETURN_IF_FALSE(p_ctx->index_fp); |
| |
| if (p_ctx->first_pts == ULLONG_MAX) { |
| DVR_INFO("%s first pcr:%llu", __func__, pts); |
| p_ctx->first_pts = pts; |
| //p_ctx->cur_time = p_ctx->cur_time + PTS_HEAD_DEVIATION; |
| } |
| memset(buf, 0, sizeof(buf)); |
| if (p_ctx->last_pts == ULLONG_MAX) { |
| /*Last pts is init value*/ |
| sprintf(buf, "{time=%llu, offset=%lld}", pts - p_ctx->first_pts, offset); |
| p_ctx->cur_time = pts - p_ctx->first_pts; |
| } else { |
| if (!p_ctx->force_sysclock) { |
| /* if force_sysclock is off, we follow old manner. Please refer to |
| * SWPL-75327*/ |
| /*Last pts has valid value*/ |
| int diff = pts - p_ctx->last_pts; |
| if ((diff > MAX_PTS_THRESHOLD) || (diff < 0)) { |
| /*Current pts has a transition*/ |
| DVR_INFO("Current pts has a transition, [%llu, %llu, %llu]", |
| p_ctx->first_pts, p_ctx->last_pts, pts); |
| p_ctx->last_record_pts = pts; |
| //p_ctx->cur_time = p_ctx->cur_time + PTS_DISCONTINUED_DEVIATION; |
| } else { |
| /*This is a normal pts, record it*/ |
| loff_t off_diff = offset - p_ctx->last_offset; |
| float rate = (float) (off_diff) / (float)(diff); |
| if (p_ctx->avg_rate == 0.0) { |
| p_ctx->avg_rate = (float) offset / (float)(p_ctx->cur_time + diff); |
| } |
| if (diff >= PCR_JUMP_DUR) { |
| DVR_INFO("PTS TRANSITION ERROR last pcr[%llu]pts[%llu]pcr diff[%d]off[%llu]off_diff[%llu]rate[%f]avg rate[%f]4*rate[%d]av_diff[%d]",p_ctx->last_pts, pts, diff, offset,off_diff, rate, p_ctx->avg_rate, (int)(rate * 4), (int)(off_diff / p_ctx->avg_rate)); |
| if (p_ctx->avg_rate != 0 && (int)(p_ctx->avg_rate) >= (int)(rate * 4)) { |
| diff = off_diff / p_ctx->avg_rate; |
| p_ctx->cur_time += diff; |
| } else { |
| p_ctx->cur_time += diff; |
| } |
| } else { |
| p_ctx->cur_time += diff; |
| } |
| } |
| } else { |
| /* if force_sysclock is on, we simply calculate cur_time based on system |
| * time. Please refer to SWPL-75327*/ |
| p_ctx->cur_time = pts - p_ctx->first_pts; |
| } |
| sprintf(buf, "\n{time=%llu, offset=%lld}", p_ctx->cur_time, offset); |
| } |
| |
| record_diff = pts - p_ctx->last_record_pts; |
| if (strlen(buf) > 0 && |
| (record_diff > PCR_RECORD_INTERVAL_MS || p_ctx->last_record_pts == ULLONG_MAX)){ |
| fputs(buf, p_ctx->index_fp); |
| fflush(p_ctx->index_fp); |
| p_ctx->time++; |
| //flush idx file 3s |
| //if ((p_ctx->time > 0 && p_ctx->time % IDX_FILE_SYNC_TIME == 0)) |
| // fsync(fileno(p_ctx->index_fp)); |
| if (p_ctx->time > IDX_FILE_SYNC_TIME) |
| p_ctx->time = 0; |
| p_ctx->last_record_pts = pts; |
| p_ctx->last_record_offset = offset; |
| if (p_ctx->cur_time > 0) |
| p_ctx->avg_rate = (float) offset / (float)p_ctx->cur_time; |
| } |
| p_ctx->last_pts = pts; |
| p_ctx->last_offset = offset; |
| return DVR_SUCCESS; |
| } |
| |
| loff_t segment_seek(Segment_Handle_t handle, uint64_t time, int block_size) |
| { |
| Segment_Context_t *p_ctx; |
| char buf[256]; |
| char value[256]; |
| uint64_t pts = 0L; |
| loff_t offset = 0; |
| char *p1, *p2; |
| int ret = 0; |
| |
| DVR_INFO("into seek time=%llu, offset=%lld time--%llu\n", pts, offset, time); |
| |
| p_ctx = (Segment_Context_t *)handle; |
| DVR_RETURN_IF_FALSE(p_ctx); |
| DVR_RETURN_IF_FALSE(p_ctx->index_fp); |
| DVR_RETURN_IF_FALSE(p_ctx->ts_fd != -1); |
| |
| if (time == 0) { |
| offset = 0; |
| DVR_INFO("seek time=%llu, offset=%lld time--%llu\n", pts, offset, time); |
| DVR_RETURN_IF_FALSE(lseek(p_ctx->ts_fd, offset, SEEK_SET) != -1); |
| return offset; |
| } |
| |
| memset(buf, 0, sizeof(buf)); |
| ret = fseek(p_ctx->index_fp, 0, SEEK_SET); |
| DVR_RETURN_IF_FALSE(ret != -1); |
| int line = 0; |
| while (fgets(buf, sizeof(buf), p_ctx->index_fp) != NULL) { |
| line++; |
| memset(value, 0, sizeof(value)); |
| if ((p1 = strstr(buf, "time="))) { |
| p1 += 5; |
| if ((p2 = strstr(buf, ","))) { |
| memcpy(value, p1, p2 - p1); |
| } |
| pts = strtoull(value, NULL, 10); |
| } |
| |
| memset(value, 0, sizeof(value)); |
| if ((p1 = strstr(buf, "offset="))) { |
| p1 += 7; |
| if ((p2 = strstr(buf, "}"))) { |
| memcpy(value, p1, p2 - p1); |
| } |
| offset = strtoull(value, NULL, 10); |
| } |
| if (0) |
| { |
| DVR_INFO("seek buf[%s]", buf); |
| DVR_INFO("seek time=%llu, offset=%lld\n", pts, offset); |
| } |
| memset(buf, 0, sizeof(buf)); |
| if (time <= pts) { |
| if (block_size > 0) { |
| offset = offset - offset%block_size; |
| } |
| //DVR_INFO("seek time=%llu, offset=%lld time--%llu line %d\n", pts, offset, time, line); |
| DVR_RETURN_IF_FALSE(lseek(p_ctx->ts_fd, offset, SEEK_SET) != -1); |
| return offset; |
| } |
| } |
| if (time > pts) { |
| if (block_size > 0) { |
| offset = offset - offset%block_size; |
| } |
| DVR_INFO("seek time=%llu, offset=%lld time--%llu line %d end\n", pts, offset, time, line); |
| DVR_RETURN_IF_FALSE(lseek(p_ctx->ts_fd, offset, SEEK_SET) != -1); |
| return offset; |
| } |
| DVR_INFO("seek error line [%d]", line); |
| return DVR_FAILURE; |
| } |
| |
| loff_t segment_tell_position(Segment_Handle_t handle) |
| { |
| Segment_Context_t *p_ctx; |
| loff_t pos; |
| p_ctx = (Segment_Context_t *)handle; |
| DVR_RETURN_IF_FALSE(p_ctx); |
| DVR_RETURN_IF_FALSE(p_ctx->ts_fd != -1); |
| pos = lseek(p_ctx->ts_fd, 0, SEEK_CUR); |
| return pos; |
| } |
| |
| loff_t segment_tell_position_time(Segment_Handle_t handle, loff_t position) |
| { |
| Segment_Context_t *p_ctx; |
| char buf[256]; |
| char value[256]; |
| uint64_t ret = 0L; |
| uint64_t pts = 0L; |
| uint64_t pts_p = 0L; |
| loff_t offset = 0; |
| loff_t offset_p = 0; |
| char *p1, *p2; |
| int ret2 = 0; |
| |
| p_ctx = (Segment_Context_t *)handle; |
| DVR_RETURN_IF_FALSE(p_ctx); |
| DVR_RETURN_IF_FALSE(p_ctx->index_fp); |
| DVR_RETURN_IF_FALSE(p_ctx->ts_fd); |
| |
| memset(buf, 0, sizeof(buf)); |
| ret2 = fseek(p_ctx->index_fp, 0, SEEK_SET); |
| DVR_RETURN_IF_FALSE(ret2 != -1); |
| DVR_RETURN_IF_FALSE(position != -1); |
| |
| while (fgets(buf, sizeof(buf), p_ctx->index_fp) != NULL) { |
| memset(value, 0, sizeof(value)); |
| if ((p1 = strstr(buf, "time="))) { |
| p1 += 5; |
| if ((p2 = strstr(buf, ","))) { |
| memcpy(value, p1, p2 - p1); |
| } |
| pts = strtoull(value, NULL, 10); |
| } |
| |
| memset(value, 0, sizeof(value)); |
| if ((p1 = strstr(buf, "offset="))) { |
| p1 += 7; |
| if ((p2 = strstr(buf, "}"))) { |
| memcpy(value, p1, p2 - p1); |
| } |
| offset = strtoull(value, NULL, 10); |
| } |
| |
| memset(buf, 0, sizeof(buf)); |
| //DVR_INFO("tell cur time=%llu, offset=%lld, position=%lld\n", pts, offset, position); |
| if (position <= offset |
| &&position >= offset_p |
| && offset - offset_p > 0) { |
| // Tainted data issue originating from fgets seem false positive, so we |
| // just suppress it here. |
| // coverity[tainted_data] |
| ret = pts_p + (pts - pts_p) * (position - offset_p) / (offset - offset_p); |
| //DVR_INFO("tell cur time=%llu, pts_p = %llu, offset=%lld, position=%lld offset_p+%lld\n", pts, pts_p, offset, position, offset_p); |
| return ret; |
| } |
| offset_p = offset; |
| pts_p = pts; |
| } |
| //DVR_INFO("tell cur time=%llu, offset=%lld, position=%lld\n", pts, offset, position); |
| return pts; |
| } |
| |
| |
| loff_t segment_tell_current_time(Segment_Handle_t handle) |
| { |
| Segment_Context_t *p_ctx; |
| char buf[256]; |
| char value[256]; |
| uint64_t pts = 0L; |
| loff_t offset = 0, position = 0; |
| char *p1, *p2; |
| int ret = 0; |
| |
| p_ctx = (Segment_Context_t *)handle; |
| DVR_RETURN_IF_FALSE(p_ctx); |
| DVR_RETURN_IF_FALSE(p_ctx->index_fp); |
| DVR_RETURN_IF_FALSE(p_ctx->ts_fd); |
| |
| memset(buf, 0, sizeof(buf)); |
| ret = fseek(p_ctx->index_fp, 0, SEEK_SET); |
| DVR_RETURN_IF_FALSE(ret != -1); |
| position = lseek(p_ctx->ts_fd, 0, SEEK_CUR); |
| DVR_RETURN_IF_FALSE(position != -1); |
| |
| while (fgets(buf, sizeof(buf), p_ctx->index_fp) != NULL) { |
| memset(value, 0, sizeof(value)); |
| if ((p1 = strstr(buf, "time="))) { |
| p1 += 5; |
| if ((p2 = strstr(buf, ","))) { |
| memcpy(value, p1, p2 - p1); |
| } |
| pts = strtoull(value, NULL, 10); |
| } |
| |
| memset(value, 0, sizeof(value)); |
| if ((p1 = strstr(buf, "offset="))) { |
| p1 += 7; |
| if ((p2 = strstr(buf, "}"))) { |
| memcpy(value, p1, p2 - p1); |
| } |
| offset = strtoull(value, NULL, 10); |
| } |
| |
| memset(buf, 0, sizeof(buf)); |
| //DVR_INFO("tell cur time=%llu, offset=%lld, position=%lld\n", pts, offset, position); |
| if (position <= offset) { |
| return pts; |
| } |
| } |
| //DVR_INFO("tell cur time=%llu, offset=%lld, position=%lld\n", pts, offset, position); |
| return pts; |
| } |
| |
| loff_t segment_tell_total_time(Segment_Handle_t handle) |
| { |
| Segment_Context_t *p_ctx; |
| char buf[256]; |
| char last_buf[256]; |
| char value[256]; |
| uint64_t pts = ULLONG_MAX; |
| loff_t offset = 0, position = 0; |
| char *p1, *p2; |
| int line = 0; |
| int ret = 0; |
| |
| p_ctx = (Segment_Context_t *)handle; |
| DVR_RETURN_IF_FALSE(p_ctx); |
| DVR_RETURN_IF_FALSE(p_ctx->index_fp); |
| DVR_RETURN_IF_FALSE(p_ctx->ts_fd); |
| |
| memset(buf, 0, sizeof(buf)); |
| memset(last_buf, 0, sizeof(last_buf)); |
| position = lseek(p_ctx->ts_fd, 0, SEEK_CUR); |
| DVR_RETURN_IF_FALSE(position != -1); |
| |
| // if unable to seek from end, it is necessary to seek to file beginning position. |
| if (fseek(p_ctx->index_fp, -1000L, SEEK_END) == -1) { |
| ret = fseek(p_ctx->index_fp, 0L, SEEK_SET); |
| DVR_RETURN_IF_FALSE(ret != -1); |
| } |
| /* Save last line buffer */ |
| while (fgets(buf, sizeof(buf), p_ctx->index_fp) != NULL) { |
| if (strlen(buf) <= 0) { |
| DVR_INFO("read index buf is len 0"); |
| continue; |
| } |
| memset(last_buf, 0, sizeof(last_buf)); |
| memcpy(last_buf, buf, strlen(buf)); |
| memset(buf, 0, sizeof(buf)); |
| line++; |
| } |
| |
| /* Extract time value */ |
| memset(value, 0, sizeof(value)); |
| if ((p1 = strstr(last_buf, "time="))) { |
| p1 += 5; |
| if ((p2 = strstr(last_buf, ","))) { |
| memcpy(value, p1, p2 - p1); |
| } |
| pts = strtoull(value, NULL, 10); |
| } |
| |
| memset(value, 0, sizeof(value)); |
| if ((p1 = strstr(last_buf, "offset="))) { |
| p1 += 7; |
| if ((p2 = strstr(last_buf, "}"))) { |
| memcpy(value, p1, p2 - p1); |
| } |
| offset = strtoull(value, NULL, 10); |
| } |
| //if (line < 2) |
| //DVR_INFO("totle time=%llu, offset=%lld, position=%lld, line:%d\n", pts, offset, position, line); |
| return (pts == ULLONG_MAX ? DVR_FAILURE : pts); |
| } |
| |
| /* Should consider the case of cut power, todo... */ |
| int segment_store_info(Segment_Handle_t handle, Segment_StoreInfo_t *p_info) |
| { |
| Segment_Context_t *p_ctx; |
| char buf[256]; |
| uint32_t i; |
| int ret = 0; |
| |
| p_ctx = (Segment_Context_t *)handle; |
| DVR_RETURN_IF_FALSE(p_ctx); |
| DVR_RETURN_IF_FALSE(p_ctx->dat_fp); |
| DVR_RETURN_IF_FALSE(p_info); |
| // seek to 0 to rewrite info |
| ret = fseek(p_ctx->dat_fp, 0, SEEK_SET); |
| DVR_RETURN_IF_FALSE(ret != -1); |
| |
| /*Save segment id*/ |
| memset(buf, 0, sizeof(buf)); |
| sprintf(buf, "id=%lld\n", p_info->id); |
| fputs(buf, p_ctx->dat_fp); |
| |
| /*Save number of pids*/ |
| memset(buf, 0, sizeof(buf)); |
| sprintf(buf, "nb_pids=%d\n", p_info->nb_pids); |
| fputs(buf, p_ctx->dat_fp); |
| |
| /*Save pid information*/ |
| for (i = 0; i < p_info->nb_pids; i++) { |
| memset(buf, 0, sizeof(buf)); |
| sprintf(buf, "{pid=%d, type=%d}\n", p_info->pids[i].pid, p_info->pids[i].type); |
| fputs(buf, p_ctx->dat_fp); |
| } |
| |
| /*Save segment duration*/ |
| memset(buf, 0, sizeof(buf)); |
| sprintf(buf, "duration=%ld\n", p_info->duration); |
| fputs(buf, p_ctx->dat_fp); |
| |
| /*Save segment size*/ |
| memset(buf, 0, sizeof(buf)); |
| sprintf(buf, "size=%zu\n", p_info->size); |
| fputs(buf, p_ctx->dat_fp); |
| |
| /*Save number of packets*/ |
| memset(buf, 0, sizeof(buf)); |
| sprintf(buf, "nb_packets=%d\n", p_info->nb_packets); |
| fputs(buf, p_ctx->dat_fp); |
| |
| fflush(p_ctx->dat_fp); |
| //fsync(fileno(p_ctx->dat_fp)); |
| return DVR_SUCCESS; |
| } |
| |
| /* Should consider the case of cut power, todo... */ |
| int segment_store_allInfo(Segment_Handle_t handle, Segment_StoreInfo_t *p_info) |
| { |
| Segment_Context_t *p_ctx; |
| char buf[256]; |
| uint32_t i; |
| int ret = 0; |
| |
| p_ctx = (Segment_Context_t *)handle; |
| DVR_RETURN_IF_FALSE(p_ctx); |
| DVR_RETURN_IF_FALSE(p_ctx->all_dat_fp); |
| DVR_RETURN_IF_FALSE(p_info); |
| |
| //seek to end to append info |
| ret = fseek(p_ctx->all_dat_fp, 0, SEEK_END); |
| DVR_RETURN_IF_FALSE(ret != -1); |
| |
| /*Save segment id*/ |
| memset(buf, 0, sizeof(buf)); |
| sprintf(buf, "id=%lld\n", p_info->id); |
| fputs(buf, p_ctx->all_dat_fp); |
| |
| /*Save number of pids*/ |
| memset(buf, 0, sizeof(buf)); |
| sprintf(buf, "nb_pids=%d\n", p_info->nb_pids); |
| fputs(buf, p_ctx->all_dat_fp); |
| |
| /*Save pid information*/ |
| for (i = 0; i < p_info->nb_pids; i++) { |
| memset(buf, 0, sizeof(buf)); |
| sprintf(buf, "{pid=%d, type=%d}\n", p_info->pids[i].pid, p_info->pids[i].type); |
| fputs(buf, p_ctx->all_dat_fp); |
| } |
| |
| /*Save segment duration*/ |
| memset(buf, 0, sizeof(buf)); |
| sprintf(buf, "duration=%ld\n", p_info->duration); |
| fputs(buf, p_ctx->all_dat_fp); |
| |
| /*Save segment size*/ |
| memset(buf, 0, sizeof(buf)); |
| sprintf(buf, "size=%zu\n", p_info->size); |
| fputs(buf, p_ctx->all_dat_fp); |
| |
| /*Save number of packets*/ |
| memset(buf, 0, sizeof(buf)); |
| sprintf(buf, "nb_packets=%d\n", p_info->nb_packets); |
| fputs(buf, p_ctx->all_dat_fp); |
| |
| fflush(p_ctx->all_dat_fp); |
| //fsync(fileno(p_ctx->all_dat_fp)); |
| return DVR_SUCCESS; |
| } |
| |
| /* Should consider the case of cut power, todo... */ |
| int segment_load_info(Segment_Handle_t handle, Segment_StoreInfo_t *p_info) |
| { |
| Segment_Context_t *p_ctx; |
| uint32_t i; |
| char buf[256]; |
| char value[256]; |
| char *p1, *p2; |
| |
| p_ctx = (Segment_Context_t *)handle; |
| DVR_RETURN_IF_FALSE(p_ctx); |
| DVR_RETURN_IF_FALSE(p_info); |
| |
| /*Load segment id*/ |
| p1 = fgets(buf, sizeof(buf), p_ctx->dat_fp); |
| DVR_RETURN_IF_FALSE(p1); |
| p1 = strstr(buf, "id="); |
| DVR_RETURN_IF_FALSE(p1); |
| p_info->id = strtoull(p1 + 3, NULL, 10); |
| |
| /*Save number of pids*/ |
| p1 = fgets(buf, sizeof(buf), p_ctx->dat_fp); |
| DVR_RETURN_IF_FALSE(p1); |
| p1 = strstr(buf, "nb_pids="); |
| DVR_RETURN_IF_FALSE(p1); |
| p_info->nb_pids = strtoul(p1 + 8, NULL, 10); |
| |
| /*Save pid information*/ |
| |
| // Tainted data issue originating from fgets seem false positive, so we |
| // just suppress it here. |
| // coverity[tainted_data] |
| for (i = 0; i < p_info->nb_pids; i++) { |
| p1 = fgets(buf, sizeof(buf), p_ctx->dat_fp); |
| DVR_RETURN_IF_FALSE(p1); |
| memset(value, 0, sizeof(value)); |
| if ((p1 = strstr(buf, "pid="))) { |
| DVR_RETURN_IF_FALSE(p1); |
| p1 += 4; |
| if ((p2 = strstr(buf, ","))) { |
| DVR_RETURN_IF_FALSE(p2); |
| memcpy(value, p1, p2 - p1); |
| } |
| p_info->pids[i].pid = strtoull(value, NULL, 10); |
| } |
| |
| memset(value, 0, sizeof(value)); |
| if ((p1 = strstr(buf, "type="))) { |
| DVR_RETURN_IF_FALSE(p1); |
| p1 += 5; |
| if ((p2 = strstr(buf, "}"))) { |
| DVR_RETURN_IF_FALSE(p2); |
| memcpy(value, p1, p2 - p1); |
| } |
| p_info->pids[i].type = strtoull(value, NULL, 10); |
| } |
| } |
| |
| /*Save segment duration*/ |
| p1 = fgets(buf, sizeof(buf), p_ctx->dat_fp); |
| DVR_RETURN_IF_FALSE(p1); |
| p1 = strstr(buf, "duration="); |
| DVR_RETURN_IF_FALSE(p1); |
| p_info->duration = strtoull(p1 + 9, NULL, 10); |
| //DVR_INFO("load info p_info->duration:%lld", p_info->duration); |
| |
| /*Save segment size*/ |
| p1 = fgets(buf, sizeof(buf), p_ctx->dat_fp); |
| DVR_RETURN_IF_FALSE(p1); |
| p1 = strstr(buf, "size="); |
| DVR_RETURN_IF_FALSE(p1); |
| p_info->size = strtoull(p1 + 5, NULL, 10); |
| |
| /*Save number of packets*/ |
| p1 = fgets(buf, sizeof(buf), p_ctx->dat_fp); |
| DVR_RETURN_IF_FALSE(p1); |
| p1 = strstr(buf, "nb_packets="); |
| DVR_RETURN_IF_FALSE(p1); |
| p_info->nb_packets = strtoull(p1 + 11, NULL, 10); |
| |
| return DVR_SUCCESS; |
| } |
| |
| /* Should consider the case of cut power, todo... */ |
| int segment_load_allInfo(Segment_Handle_t handle, struct list_head *list) |
| { |
| Segment_Context_t *p_ctx; |
| uint32_t i; |
| char buf[256]; |
| char value[256]; |
| char *p1, *p2; |
| |
| p_ctx = (Segment_Context_t *)handle; |
| DVR_RETURN_IF_FALSE(p_ctx); |
| DVR_RETURN_IF_FALSE(list); |
| if (p_ctx->all_dat_fp == NULL) { |
| DVR_INFO("all dat file not open\n"); |
| return DVR_FAILURE; |
| } |
| //first get |
| p1 = fgets(buf, sizeof(buf), p_ctx->all_dat_fp); |
| DVR_RETURN_IF_FALSE(p1); |
| |
| do { |
| |
| DVR_RecordSegmentInfo_t *p_info; |
| |
| p_info = malloc(sizeof(DVR_RecordSegmentInfo_t)); |
| DVR_RETURN_IF_FALSE(p_info); |
| memset(p_info, 0, sizeof(DVR_RecordSegmentInfo_t)); |
| |
| list_add_tail(p_info, list); |
| |
| /*Load segment id*/ |
| DVR_RETURN_IF_FALSE(p1); |
| p1 = strstr(buf, "id="); |
| DVR_RETURN_IF_FALSE(p1); |
| p_info->id = strtoull(p1 + 3, NULL, 10); |
| |
| /*Save number of pids*/ |
| p1 = fgets(buf, sizeof(buf), p_ctx->all_dat_fp); |
| DVR_RETURN_IF_FALSE(p1); |
| p1 = strstr(buf, "nb_pids="); |
| DVR_RETURN_IF_FALSE(p1); |
| p_info->nb_pids = strtoull(p1 + 8, NULL, 10); |
| |
| /*Save pid information*/ |
| // Tainted data issue originating from fgets seem false positive, so we |
| // just suppress it here. |
| // coverity[tainted_data] |
| for (i = 0; i < p_info->nb_pids; i++) { |
| p1 = fgets(buf, sizeof(buf), p_ctx->all_dat_fp); |
| DVR_RETURN_IF_FALSE(p1); |
| memset(value, 0, sizeof(value)); |
| if ((p1 = strstr(buf, "pid="))) { |
| DVR_RETURN_IF_FALSE(p1); |
| p1 += 4; |
| if ((p2 = strstr(buf, ","))) { |
| DVR_RETURN_IF_FALSE(p2); |
| memcpy(value, p1, p2 - p1); |
| } |
| p_info->pids[i].pid = strtoull(value, NULL, 10); |
| } |
| |
| memset(value, 0, sizeof(value)); |
| if ((p1 = strstr(buf, "type="))) { |
| DVR_RETURN_IF_FALSE(p1); |
| p1 += 5; |
| if ((p2 = strstr(buf, "}"))) { |
| DVR_RETURN_IF_FALSE(p2); |
| memcpy(value, p1, p2 - p1); |
| } |
| p_info->pids[i].type = strtoull(value, NULL, 10); |
| } |
| } |
| |
| /*Save segment duration*/ |
| p1 = fgets(buf, sizeof(buf), p_ctx->all_dat_fp); |
| DVR_RETURN_IF_FALSE(p1); |
| p1 = strstr(buf, "duration="); |
| DVR_RETURN_IF_FALSE(p1); |
| p_info->duration = strtoull(p1 + 9, NULL, 10); |
| //DVR_INFO("load info p_info->duration:%lld", p_info->duration); |
| |
| /*Save segment size*/ |
| p1 = fgets(buf, sizeof(buf), p_ctx->all_dat_fp); |
| DVR_RETURN_IF_FALSE(p1); |
| p1 = strstr(buf, "size="); |
| DVR_RETURN_IF_FALSE(p1); |
| p_info->size = strtoull(p1 + 5, NULL, 10); |
| |
| /*Save number of packets*/ |
| p1 = fgets(buf, sizeof(buf), p_ctx->all_dat_fp); |
| DVR_RETURN_IF_FALSE(p1); |
| p1 = strstr(buf, "nb_packets="); |
| DVR_RETURN_IF_FALSE(p1); |
| p_info->nb_packets = strtoull(p1 + 11, NULL, 10); |
| //if reach end,exit loop |
| p1 = fgets(buf, sizeof(buf), p_ctx->all_dat_fp); |
| } while (p1); |
| |
| return DVR_SUCCESS; |
| } |
| |
| int segment_delete(const char *location, uint64_t segment_id) |
| { |
| char fname[MAX_SEGMENT_PATH_SIZE]; |
| int ret; |
| |
| DVR_RETURN_IF_FALSE(location); |
| |
| /*delete ts file*/ |
| memset(fname, 0, sizeof(fname)); |
| segment_get_fname(fname, location, segment_id, SEGMENT_FILE_TYPE_TS); |
| ret = unlink(fname); |
| DVR_ERROR("%s, [%s] return:%s", __func__, fname, strerror(errno)); |
| DVR_RETURN_IF_FALSE(ret == 0); |
| |
| /*delete index file*/ |
| memset(fname, 0, sizeof(fname)); |
| segment_get_fname(fname, location, segment_id, SEGMENT_FILE_TYPE_INDEX); |
| unlink(fname); |
| DVR_ERROR("%s, [%s] return:%s", __func__, fname, strerror(errno)); |
| DVR_RETURN_IF_FALSE(ret == 0); |
| |
| /*delete store information file*/ |
| memset(fname, 0, sizeof(fname)); |
| segment_get_fname(fname, location, segment_id, SEGMENT_FILE_TYPE_DAT); |
| unlink(fname); |
| DVR_ERROR("%s, [%s] return:%s", __func__, fname, strerror(errno)); |
| DVR_RETURN_IF_FALSE(ret == 0); |
| |
| return DVR_SUCCESS; |
| } |
| |
| int segment_ongoing(Segment_Handle_t handle) |
| { |
| Segment_Context_t *p_ctx; |
| p_ctx = (Segment_Context_t *)handle; |
| struct stat mstat; |
| |
| char going_name[MAX_SEGMENT_PATH_SIZE]; |
| memset(going_name, 0, sizeof(going_name)); |
| segment_get_fname(going_name, p_ctx->location, p_ctx->segment_id, SEGMENT_FILE_TYPE_ONGOING); |
| int ret = stat(going_name, &mstat); |
| DVR_INFO("segment check ongoing [%s] ret [%d]", going_name, ret); |
| if (ret != 0) { |
| return DVR_FAILURE; |
| } |
| return DVR_SUCCESS; |
| } |
| |
| loff_t segment_dump_pts(Segment_Handle_t handle) |
| { |
| Segment_Context_t *p_ctx; |
| char buf[256]; |
| char value[256]; |
| uint64_t pts = 0; |
| loff_t offset = 0; |
| char *p1, *p2; |
| int ret = 0; |
| |
| p_ctx = (Segment_Context_t *)handle; |
| DVR_RETURN_IF_FALSE(p_ctx); |
| DVR_RETURN_IF_FALSE(p_ctx->index_fp); |
| DVR_RETURN_IF_FALSE(p_ctx->ts_fd != -1); |
| |
| memset(buf, 0, sizeof(buf)); |
| ret = fseek(p_ctx->index_fp, 0, SEEK_SET); |
| DVR_RETURN_IF_FALSE(ret != -1); |
| |
| printf("start gets pts\n"); |
| while (fgets(buf, sizeof(buf), p_ctx->index_fp) != NULL) { |
| printf("buf[%s]\n", buf); |
| memset(value, 0, sizeof(value)); |
| if ((p1 = strstr(buf, "time="))) { |
| p1 += 5; |
| if ((p2 = strstr(buf, ","))) { |
| memcpy(value, p1, p2 - p1); |
| } |
| pts = strtoull(value, NULL, 10); |
| } |
| |
| memset(value, 0, sizeof(value)); |
| if ((p1 = strstr(buf, "offset="))) { |
| p1 += 7; |
| if ((p2 = strstr(buf, "}"))) { |
| memcpy(value, p1, p2 - p1); |
| } |
| offset = strtoull(value, NULL, 10); |
| } |
| |
| memset(buf, 0, sizeof(buf)); |
| printf("pts=%llu, offset=%lld\n", pts, offset); |
| } |
| |
| return 0; |
| } |
| |
| off_t segment_get_cur_segment_size(Segment_Handle_t handle) |
| { |
| Segment_Context_t *p_ctx = (Segment_Context_t *)handle; |
| DVR_RETURN_IF_FALSE(p_ctx); |
| DVR_RETURN_IF_FALSE(p_ctx->ts_fd != -1); |
| struct stat sb; |
| int ret=fstat(p_ctx->ts_fd,&sb); |
| if (ret<0) { |
| return -1; |
| } |
| return sb.st_size; |
| } |
| |
| uint64_t segment_get_cur_segment_id(Segment_Handle_t handle) |
| { |
| Segment_Context_t *p_ctx = (Segment_Context_t *)handle; |
| DVR_RETURN_IF_FALSE(p_ctx); |
| return p_ctx->segment_id; |
| } |
| |