dvr: implement clear pullvod record [1/1]

PD#SWPL-18817

Problem:
New feature

Solution:
implement clear pullvod record and
add PCR time index

Verify:
Android Q + AC214

Change-Id: Ib16a7990bd901d82132e72ac18792763e4226ba3
Signed-off-by: pengfei.liu <pengfei.liu@amlogic.com>
diff --git a/src/dvr_record.c b/src/dvr_record.c
index 7a32fbf..7360d3f 100644
--- a/src/dvr_record.c
+++ b/src/dvr_record.c
@@ -10,6 +10,22 @@
 #include "segment.h"
 
 #define MAX_DVR_RECORD_SESSION_COUNT 2
+
+/**\brief DVR index file type*/
+typedef enum {
+  DVR_INDEX_TYPE_PCR,                                                   /**< DVR index file use pcr*/
+  DVR_INDEX_TYPE_LOCAL_CLOCK,                                           /**< DVR index file use local clock*/
+  DVR_INDEX_TYPE_INVALID                                                 /**< DVR index file type invalid type*/
+} DVR_IndexType_t;
+
+/**\brief DVR VOD context*/
+typedef struct {
+  pthread_mutex_t                 mutex;                                /**< VOD mutex lock*/
+  pthread_cond_t                  cond;                                 /**< VOD condition*/
+  void                            *buffer;                              /**< VOD buffer*/
+  uint32_t                        buf_len;                              /**< VOD buffer len*/
+} DVR_VodContext_t;
+
 /**\brief DVR record context*/
 typedef struct {
   pthread_t                       thread;                               /**< DVR thread handle*/
@@ -22,6 +38,8 @@
   size_t                          notification_size;                    /**< DVR record nogification size*/
   DVR_RecordEventFunction_t       event_notify_fn;                      /**< DVR record event notify function*/
   void                            *event_userdata;                      /**< DVR record event userdata*/
+  //DVR_VodContext_t                vod;                                  /**< DVR record vod context*/
+  int                             is_vod;                               /**< Indicate current mode is VOD record mode*/
 } DVR_RecordContext_t;
 
 static DVR_RecordContext_t record_ctx[MAX_DVR_RECORD_SESSION_COUNT] = {
@@ -33,17 +51,106 @@
   }
 };
 
+//#define USE_TEST_DATA
+#ifdef USE_TEST_DATA
+static int test_data_read(uint8_t *buf, int len)
+{
+  int i;
+  for (i = 0; i < len; i++) {
+    buf[i] = i % 0xff;
+  }
+  usleep(50*1000);
+  return len;
+}
+#endif
+
+static int record_save_pcr(DVR_RecordContext_t *p_ctx, uint8_t *buf, loff_t pos)
+{
+  uint8_t *p = buf;
+  int len;
+  uint8_t afc;
+  uint64_t pcr = 0;
+  int has_pcr = 0;
+  int pid;
+  int adp_field_len;
+
+  pid = ((p[1] & 0x1f) << 8) | p[2];
+  if (pid == 0x1fff)
+    return has_pcr;
+
+  //scramble = p[3] >> 6;
+  //cc = p[3] & 0x0f;
+  afc = (p[3] >> 4) & 0x03;
+
+  p += 4;
+  len = 184;
+
+  if (afc & 2) {
+    adp_field_len = p[0];
+    /* Skip adaptation len */
+    p++;
+    len--;
+    /* Parse pcr field, see 13818 spec table I-2-6,adaptation_field */
+    if (p[0] & 0x10 && len >= 6) {
+    /* get pcr value,pcr is 33bit value */
+    pcr = (((uint64_t)(p[1])) << 25)
+        | (((uint64_t)p[2]) << 17)
+        | (((uint64_t)(p[3])) << 9)
+        | (((uint64_t)p[4]) << 1)
+        | ((((uint64_t)p[5]) & 0x80) >> 7);
+      has_pcr = 1;
+    }
+
+    p += adp_field_len;
+    len -= adp_field_len;
+
+    if (len < 0) {
+      DVR_DEBUG(1, "parser pcr: illegal adaptation field length");
+      return 0;
+    }
+  }
+
+  if (has_pcr) {
+    segment_update_pts(p_ctx->segment_handle, pcr/90, pos);
+  }
+  return has_pcr;
+}
+
+static int record_do_pcr_index(DVR_RecordContext_t *p_ctx, uint8_t *buf, int len)
+{
+  uint8_t *p = buf;
+  int left = len;
+  loff_t pos;
+  int has_pcr = 0;
+
+  pos = segment_tell_position(p_ctx->segment_handle);
+  while (left >= 188) {
+    if (*p == 0x47) {
+      has_pcr |= record_save_pcr(p_ctx, p, pos);
+      p += 188;
+      left -= 188;
+      pos += 188;
+    } else {
+      p++;
+      left --;
+      pos++;
+    }
+  }
+  return has_pcr;
+}
+
 void *record_thread(void *arg)
 {
   DVR_RecordContext_t *p_ctx = (DVR_RecordContext_t *)arg;
   ssize_t len;
   uint8_t *buf;
   int block_size = 256*1024;
-  off_t pos = 0;
-  uint64_t pts = 0;
+  loff_t pos = 0;
   int ret;
   struct timespec start_ts, end_ts;
   DVR_RecordStatus_t record_status;
+  int has_pcr;
+  int index_type = DVR_INDEX_TYPE_INVALID;
 
   buf = (uint8_t *)malloc(block_size);
   if (!buf) {
@@ -53,33 +160,59 @@
 
   clock_gettime(CLOCK_MONOTONIC, &start_ts);
   while (p_ctx->state == DVR_RECORD_STATE_STARTED) {
+    /* data from dmx, normal dvr case */
+#ifdef USE_TEST_DATA
+    len = test_data_read(buf, block_size);
+#else
     len = record_device_read(p_ctx->dev_handle, buf, block_size, 1000);
+#endif
     if (len == DVR_FAILURE) {
       usleep(10*1000);
       continue;
     }
-#if 0
-    ret = sw_dmx_extract_pcr(buf, len, &pts, &pos);
-    if (ret == DVR_FAILURE) {
-      get_local_pts(&pts);
+    /* got data from device, record it */
+    pos = segment_tell_position(p_ctx->segment_handle);
+    has_pcr = record_do_pcr_index(p_ctx, buf, len);
+    if (has_pcr == 0 && index_type == DVR_INDEX_TYPE_INVALID) {
+      clock_gettime(CLOCK_MONOTONIC, &end_ts);
+      if ((end_ts.tv_sec*1000 + end_ts.tv_nsec/1000000) -
+          (start_ts.tv_sec*1000 + start_ts.tv_nsec/1000000) > 40) {
+        /* PCR interval threshlod > 40 ms*/
+        DVR_DEBUG(1, "%s use local clock time index", __func__);
+        index_type = DVR_INDEX_TYPE_LOCAL_CLOCK;
+      }
+    } else if (has_pcr && index_type == DVR_INDEX_TYPE_INVALID){
+      DVR_DEBUG(1, "%s use pcr time index", __func__);
+      index_type = DVR_INDEX_TYPE_PCR;
     }
-#endif
-    pos += segment_tell_position(p_ctx->segment_handle);
-    ret = segment_update_pts(p_ctx->segment_handle, pts, pos);
     ret = segment_write(p_ctx->segment_handle, buf, len);
+
+    /* Update segment info */
     p_ctx->segment_info.size += len;
+    /*Duration need use pcr to calculate, todo...*/
+    if (index_type == DVR_INDEX_TYPE_PCR) {
+      p_ctx->segment_info.duration = segment_tell_time(p_ctx->segment_handle);
+    } else if (index_type == DVR_INDEX_TYPE_LOCAL_CLOCK) {
+      clock_gettime(CLOCK_MONOTONIC, &end_ts);
+      p_ctx->segment_info.duration = (end_ts.tv_sec*1000 + end_ts.tv_nsec/1000000) -
+        (start_ts.tv_sec*1000 + start_ts.tv_nsec/1000000);
+      segment_update_pts(p_ctx->segment_handle, p_ctx->segment_info.duration, pos);
+    } else {
+      DVR_DEBUG(1, "%s can NOT do time index", __func__);
+    }
+    p_ctx->segment_info.nb_packets = p_ctx->segment_info.size/188;
 
     /*Event notification*/
     if (p_ctx->notification_size &&
         p_ctx->event_notify_fn &&
-        !(p_ctx->segment_info.size % p_ctx->notification_size)) {
+        !(p_ctx->segment_info.size % p_ctx->notification_size) &&
+        p_ctx->segment_info.duration > 0) {
       memset(&record_status, 0, sizeof(record_status));
-      clock_gettime(CLOCK_MONOTONIC, &end_ts);
+      //clock_gettime(CLOCK_MONOTONIC, &end_ts);
 
       record_status.state = p_ctx->state;
       record_status.info.id = p_ctx->segment_info.id;
-      record_status.info.duration = (end_ts.tv_sec*1000 + end_ts.tv_nsec/1000000) -
-        (start_ts.tv_sec*1000 + start_ts.tv_nsec/1000000);
+      record_status.info.duration = p_ctx->segment_info.duration;
       record_status.info.size = p_ctx->segment_info.size;
       record_status.info.nb_packets = p_ctx->segment_info.size/188;
       p_ctx->event_notify_fn(DVR_RECORD_EVENT_STATUS, &record_status, p_ctx->event_userdata);
@@ -88,11 +221,6 @@
     }
   }
 
-  clock_gettime(CLOCK_MONOTONIC, &end_ts);
-  /*Duration need use pcr to calculate, todo...*/
-  p_ctx->segment_info.duration = (end_ts.tv_sec*1000 + end_ts.tv_nsec/1000000) -
-    (start_ts.tv_sec*1000 + start_ts.tv_nsec/1000000);
-  p_ctx->segment_info.nb_packets = p_ctx->segment_info.size/188;
   free((void *)buf);
   DVR_DEBUG(1, "exit %s", __func__);
   return NULL;
@@ -130,13 +258,20 @@
 #endif
 
   memset((void *)&dev_open_params, 0, sizeof(dev_open_params));
-  dev_open_params.dmx_dev_id = params->dmx_dev_id;
-  dev_open_params.buf_size = 256*1024;
+  if (params->data_from_memory) {
+    /* data from memory, VOD case */
+    p_ctx->is_vod = 1;
+  } else {
+    p_ctx->is_vod = 0;
+    /* data from dmx, normal dvr case */
+    dev_open_params.dmx_dev_id = params->dmx_dev_id;
+    dev_open_params.buf_size = 256*1024;
 
-  ret = record_device_open(&p_ctx->dev_handle, &dev_open_params);
-  if (ret != DVR_SUCCESS) {
-    DVR_DEBUG(1, "%s, open record devices failed", __func__);
-    return DVR_FAILURE;
+    ret = record_device_open(&p_ctx->dev_handle, &dev_open_params);
+    if (ret != DVR_SUCCESS) {
+      DVR_DEBUG(1, "%s, open record devices failed", __func__);
+      return DVR_FAILURE;
+    }
   }
 
   p_ctx->state = DVR_RECORD_STATE_OPENED;
@@ -161,9 +296,13 @@
   DVR_DEBUG(1, "%s , current state:%d", __func__, p_ctx->state);
   DVR_RETURN_IF_FALSE(p_ctx->state != DVR_RECORD_STATE_CLOSED);
 
-  ret = record_device_close(p_ctx->dev_handle);
-  if (ret != DVR_SUCCESS) {
-    DVR_DEBUG(1, "%s, failed", __func__);
+  if (p_ctx->is_vod) {
+    ret = DVR_SUCCESS;
+  } else {
+    ret = record_device_close(p_ctx->dev_handle);
+    if (ret != DVR_SUCCESS) {
+      DVR_DEBUG(1, "%s, failed", __func__);
+    }
   }
 
   p_ctx->state = DVR_RECORD_STATE_CLOSED;
@@ -220,15 +359,19 @@
     memcpy(p_ctx->segment_info.pids, params->segment.pids, params->segment.nb_pids*sizeof(DVR_StreamPid_t));
   }
 
-  for (i = 0; i < params->segment.nb_pids; i++) {
-    ret = record_device_add_pid(p_ctx->dev_handle, params->segment.pids[i].pid);
+  if (!p_ctx->is_vod) {
+    /* normal dvr case */
+    for (i = 0; i < params->segment.nb_pids; i++) {
+      ret = record_device_add_pid(p_ctx->dev_handle, params->segment.pids[i].pid);
+      DVR_RETURN_IF_FALSE(ret == DVR_SUCCESS);
+    }
+    ret = record_device_start(p_ctx->dev_handle);
     DVR_RETURN_IF_FALSE(ret == DVR_SUCCESS);
   }
 
-  ret = record_device_start(p_ctx->dev_handle);
-  DVR_RETURN_IF_FALSE(ret == DVR_SUCCESS);
   p_ctx->state = DVR_RECORD_STATE_STARTED;
-  pthread_create(&p_ctx->thread, NULL, record_thread, p_ctx);
+  if (!p_ctx->is_vod)
+    pthread_create(&p_ctx->thread, NULL, record_thread, p_ctx);
 
   return DVR_SUCCESS;
 }
@@ -252,6 +395,7 @@
   //DVR_RETURN_IF_FALSE(p_ctx->state != DVR_RECORD_STATE_CLOSED);
   DVR_RETURN_IF_FALSE(params);
   DVR_RETURN_IF_FALSE(p_info);
+  DVR_RETURN_IF_FALSE(!p_ctx->is_vod);
 
   /*Stop the on going record segment*/
   //ret = record_device_stop(p_ctx->dev_handle);
@@ -340,11 +484,17 @@
   DVR_RETURN_IF_FALSE(p_ctx->state != DVR_RECORD_STATE_CLOSED);
   DVR_RETURN_IF_FALSE(p_info);
 
-  ret = record_device_stop(p_ctx->dev_handle);
-  DVR_RETURN_IF_FALSE(ret == DVR_SUCCESS);
-
   p_ctx->state = DVR_RECORD_STATE_STOPPED;
-  pthread_join(p_ctx->thread, NULL);
+  if (p_ctx->is_vod) {
+    p_ctx->segment_info.duration = segment_tell_time(p_ctx->segment_handle);
+    p_ctx->segment_info.duration = 10*1000; //debug, should delete it
+  } else {
+    ret = record_device_stop(p_ctx->dev_handle);
+    DVR_RETURN_IF_FALSE(ret == DVR_SUCCESS);
+    //p_ctx->state = DVR_RECORD_STATE_STOPPED;
+    pthread_join(p_ctx->thread, NULL);
+  }
+
 
   /*Update segment info*/
   memcpy(p_info, &p_ctx->segment_info, sizeof(p_ctx->segment_info));
@@ -364,6 +514,7 @@
 {
   DVR_RecordContext_t *p_ctx;
   uint32_t i;
+  int ret;
 
   p_ctx = (DVR_RecordContext_t *)handle;
   for (i = 0; i < MAX_DVR_RECORD_SESSION_COUNT; i++) {
@@ -374,6 +525,64 @@
   DVR_RETURN_IF_FALSE(params);
   DVR_RETURN_IF_FALSE(p_resume_size);
 
-  DVR_DEBUG(1, "%s , current state:%d", __func__, p_ctx->state);
+  DVR_DEBUG(1, "%s , current state:%d, resume size:%lld", __func__, p_ctx->state, *p_resume_size);
+  ret = dvr_record_start_segment(handle, params);
+  DVR_RETURN_IF_FALSE(ret == DVR_SUCCESS);
+
+  p_ctx->segment_info.size = *p_resume_size;
+
+  return DVR_SUCCESS;
+}
+
+int dvr_record_get_status(DVR_RecordHandle_t handle, DVR_RecordStatus_t *p_status)
+{
+  DVR_RecordContext_t *p_ctx;
+  int i;
+
+  p_ctx = (DVR_RecordContext_t *)handle;
+  for (i = 0; i < MAX_DVR_RECORD_SESSION_COUNT; i++) {
+    if (p_ctx == &record_ctx[i])
+      break;
+  }
+  DVR_RETURN_IF_FALSE(p_ctx == &record_ctx[i]);
+  DVR_RETURN_IF_FALSE(p_status);
+
+  //lock
+  p_status->state = p_ctx->state;
+  p_status->info.id = p_ctx->segment_info.id;
+  p_status->info.duration = p_ctx->segment_info.duration;
+  p_status->info.size = p_ctx->segment_info.size;
+  p_status->info.nb_packets = p_ctx->segment_info.size/188;
+
+  return DVR_SUCCESS;
+}
+
+int dvr_record_write(DVR_RecordHandle_t handle, void *buffer, uint32_t len)
+{
+  DVR_RecordContext_t *p_ctx;
+  uint32_t i;
+  off_t pos = 0;
+  int ret;
+  int has_pcr;
+
+  p_ctx = (DVR_RecordContext_t *)handle;
+  for (i = 0; i < MAX_DVR_RECORD_SESSION_COUNT; i++) {
+    if (p_ctx == &record_ctx[i])
+      break;
+  }
+  DVR_RETURN_IF_FALSE(p_ctx == &record_ctx[i]);
+  DVR_RETURN_IF_FALSE(buffer);
+  DVR_RETURN_IF_FALSE(len);
+
+  pos = segment_tell_position(p_ctx->segment_handle);
+  has_pcr = record_do_pcr_index(p_ctx, buffer, len);
+  if (has_pcr == 0) {
+    /* Pull VOD record shoud use PCR time index */
+    DVR_DEBUG(1, "%s has no pcr, can NOT do time index", __func__);
+  }
+  ret = segment_write(p_ctx->segment_handle, buffer, len);
+  p_ctx->segment_info.size += len;
+  p_ctx->segment_info.nb_packets = p_ctx->segment_info.size/188;
+
   return DVR_SUCCESS;
 }
diff --git a/src/record_device.c b/src/record_device.c
index b5f33e1..c9af2b7 100644
--- a/src/record_device.c
+++ b/src/record_device.c
@@ -125,9 +125,9 @@
       break;
   }
   DVR_RETURN_IF_FALSE(p_ctx == &record_ctx[i]);
-  DVR_RETURN_IF_FALSE(p_ctx->state != RECORD_DEVICE_STATE_CLOSED);
 
   pthread_mutex_lock(&p_ctx->lock);
+  DVR_RETURN_IF_FALSE_WITH_UNLOCK(p_ctx->state != RECORD_DEVICE_STATE_CLOSED, &p_ctx->lock);
   close(p_ctx->fd);
   p_ctx->state = RECORD_DEVICE_STATE_CLOSED;
   pthread_mutex_unlock(&p_ctx->lock);
@@ -145,22 +145,21 @@
 
   p_ctx = (Record_DeviceContext_t *)handle;
   DVR_RETURN_IF_FALSE(p_ctx);
+  DVR_RETURN_IF_FALSE(pid != DVR_INVALID_PID);
   for (i = 0; i < MAX_RECORD_DEVICE_COUNT; i++) {
     if (p_ctx == &record_ctx[i])
       break;
   }
   DVR_RETURN_IF_FALSE(p_ctx == &record_ctx[i]);
 
-  DVR_RETURN_IF_FALSE(p_ctx->state != RECORD_DEVICE_STATE_CLOSED);
-  DVR_RETURN_IF_FALSE(pid != DVR_INVALID_PID);
-
+  pthread_mutex_lock(&p_ctx->lock);
+  DVR_RETURN_IF_FALSE_WITH_UNLOCK(p_ctx->state != RECORD_DEVICE_STATE_CLOSED, &p_ctx->lock);
   for (i = 0; i < DVR_MAX_RECORD_PIDS_COUNT; i++) {
     if (p_ctx->streams[i].pid == DVR_INVALID_PID)
       break;
   }
-  DVR_RETURN_IF_FALSE(p_ctx->streams[i].pid == DVR_INVALID_PID);
+  DVR_RETURN_IF_FALSE_WITH_UNLOCK(p_ctx->streams[i].pid == DVR_INVALID_PID, &p_ctx->lock);
 
-  pthread_mutex_lock(&p_ctx->lock);
   p_ctx->streams[i].pid = pid;
 	snprintf(dev_name, sizeof(dev_name), "/dev/dvb0.demux%d", p_ctx->dmx_dev_id);
   fd = open(dev_name, O_RDWR);
@@ -205,24 +204,23 @@
 
   p_ctx = (Record_DeviceContext_t *)handle;
   DVR_RETURN_IF_FALSE(p_ctx);
+  DVR_RETURN_IF_FALSE(pid != DVR_INVALID_PID);
   for (i = 0; i < MAX_RECORD_DEVICE_COUNT; i++) {
     if (p_ctx == &record_ctx[i])
       break;
   }
   DVR_RETURN_IF_FALSE(p_ctx == &record_ctx[i]);
 
-  DVR_RETURN_IF_FALSE(p_ctx->state != RECORD_DEVICE_STATE_CLOSED);
-  DVR_RETURN_IF_FALSE(pid != DVR_INVALID_PID);
-
+  pthread_mutex_lock(&p_ctx->lock);
+  DVR_RETURN_IF_FALSE_WITH_UNLOCK(p_ctx->state != RECORD_DEVICE_STATE_CLOSED, &p_ctx->lock);
   for (i = 0; i < DVR_MAX_RECORD_PIDS_COUNT; i++) {
     if (p_ctx->streams[i].pid == pid)
       break;
   }
-  DVR_RETURN_IF_FALSE(p_ctx->streams[i].pid == pid);
+  DVR_RETURN_IF_FALSE_WITH_UNLOCK(p_ctx->streams[i].pid == pid, &p_ctx->lock);
 
-  pthread_mutex_lock(&p_ctx->lock);
   fd = p_ctx->streams[i].fid;
-  DVR_RETURN_IF_FALSE(fd != -1);
+  DVR_RETURN_IF_FALSE_WITH_UNLOCK(fd != -1, &p_ctx->lock);
 
   if (p_ctx->streams[i].is_start == DVR_TRUE) {
     ret = ioctl(fd, DMX_STOP, 0);
@@ -257,13 +255,14 @@
   }
   DVR_RETURN_IF_FALSE(p_ctx == &record_ctx[i]);
 
+  pthread_mutex_lock(&p_ctx->lock);
   if (p_ctx->state != RECORD_DEVICE_STATE_OPENED &&
       p_ctx->state != RECORD_DEVICE_STATE_STOPPED) {
+    pthread_mutex_unlock(&p_ctx->lock);
     DVR_DEBUG(1, "%s, %d, wrong state:%d", __func__, __LINE__,p_ctx->state);
     return DVR_FAILURE;
   }
 
-  pthread_mutex_lock(&p_ctx->lock);
   for (i = 0; i < DVR_MAX_RECORD_PIDS_COUNT; i++) {
     if (p_ctx->streams[i].fid != -1 &&
         p_ctx->streams[i].pid != DVR_INVALID_PID &&
@@ -310,12 +309,13 @@
   }
   DVR_RETURN_IF_FALSE(p_ctx == &record_ctx[i]);
 
+  pthread_mutex_lock(&p_ctx->lock);
   if (p_ctx->state != RECORD_DEVICE_STATE_STARTED) {
     DVR_DEBUG(1, "%s, %d, wrong state:%d", __func__, __LINE__,p_ctx->state);
+    pthread_mutex_unlock(&p_ctx->lock);
     return DVR_FAILURE;
   }
 
-  pthread_mutex_lock(&p_ctx->lock);
   for (i = 0; i < DVR_MAX_RECORD_PIDS_COUNT; i++) {
     if (p_ctx->streams[i].fid != -1 &&
         p_ctx->streams[i].pid != DVR_INVALID_PID &&
diff --git a/src/segment.c b/src/segment.c
index 8503472..9bf4c12 100644
--- a/src/segment.c
+++ b/src/segment.c
@@ -19,6 +19,7 @@
   FILE            *dat_fp;                            /**< Information file fd*/
   uint64_t        first_pts;                          /**< First pts value, use for write mode*/
   uint64_t        last_pts;                           /**< Last pts value, use for write mode*/
+  uint64_t        cur_time;                           /**< Current time save in index file */
 } Segment_Context_t;
 
 /**\brief Segment file type*/
@@ -187,20 +188,24 @@
   DVR_RETURN_IF_FALSE(p_ctx->index_fp);
 
   if (p_ctx->first_pts == ULLONG_MAX) {
+    DVR_DEBUG(1, "%s first pcr:%llu", __func__, pts);
     p_ctx->first_pts = pts;
   }
   memset(buf, 0, sizeof(buf));
   if (p_ctx->last_pts == ULLONG_MAX) {
     /*Last pts is init value*/
     sprintf(buf, "{time=%llu, offset=%lld}\n", pts - p_ctx->first_pts, offset);
+    p_ctx->cur_time = pts - p_ctx->first_pts;
   } else {
     /*Last pts has valid value*/
     if (pts - p_ctx->last_pts > MAX_PTS_THRESHOLD) {
       /*Current pts has a transition*/
-      sprintf(buf, "{time=%llu, offset=%lld}\n", p_ctx->last_pts - p_ctx->first_pts, offset);
+      DVR_DEBUG(1, "Current pts has a transition, [%llu, %llu, %llu]",
+          p_ctx->first_pts, p_ctx->last_pts, pts);
     } else {
       /*This is a normal pts, record it*/
-      sprintf(buf, "{time=%llu, offset=%lld}\n", pts - p_ctx->first_pts, offset);
+      p_ctx->cur_time += (pts - p_ctx->last_pts);
+      sprintf(buf, "{time=%llu, offset=%lld}\n", p_ctx->cur_time, offset);
     }
   }
 
@@ -309,7 +314,7 @@
     }
 
     memset(buf, 0, sizeof(buf));
-    DVR_DEBUG(1, "time=%llu, offset=%lld, position=%lld\n", pts, offset, position);
+    //DVR_DEBUG(1, "time=%llu, offset=%lld, position=%lld\n", pts, offset, position);
     if (position < offset) {
       return pts;
     }
@@ -318,6 +323,7 @@
   return DVR_FAILURE;
 }
 
+/* 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;
@@ -366,6 +372,7 @@
   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;