/*
 * Output packet
 */
static int _timeshift_read
  ( timeshift_t *ts, timeshift_file_t **cur_file, off_t *cur_off, int *fd,
    streaming_message_t **sm, int *wait )
{
  if (*cur_file) {

    /* Open file */
    if (*fd == -1) {
      tvhtrace("timeshift", "ts %d open file %s",
               ts->id, (*cur_file)->path);
      *fd = open((*cur_file)->path, O_RDONLY);
    }
    tvhtrace("timeshift", "ts %d seek to %"PRIoff_t, ts->id, *cur_off);
    lseek(*fd, *cur_off, SEEK_SET);

    /* Read msg */
    ssize_t r = _read_msg(*fd, sm);
    if (r < 0) {
      streaming_message_t *e = streaming_msg_create_code(SMT_STOP, SM_CODE_UNDEFINED_ERROR);
      streaming_target_deliver2(ts->output, e);
      tvhlog(LOG_ERR, "timeshift", "ts %d could not read buffer", ts->id);
      return -1;
    }
    tvhtrace("timeshift", "ts %d read msg %p (%"PRIssize_t")",
             ts->id, *sm, r);

    /* Incomplete */
    if (r == 0) {
      lseek(*fd, *cur_off, SEEK_SET);
      return 0;
    }

    /* Update */
    *cur_off += r;

    /* Special case - EOF */
    if (r == sizeof(size_t) || *cur_off > (*cur_file)->size) {
      close(*fd);
      *fd       = -1;
      pthread_mutex_lock(&ts->rdwr_mutex);
      *cur_file = timeshift_filemgr_next(*cur_file, NULL, 0);
      pthread_mutex_unlock(&ts->rdwr_mutex);
      *cur_off  = 0; // reset
      *wait     = 0;

    /* Check SMT_START index */
    } else {
      streaming_message_t *ssm = _timeshift_find_sstart(*cur_file, (*sm)->sm_time);
      if (ssm && ssm->sm_data != ts->smt_start) {
        streaming_target_deliver2(ts->output, streaming_msg_clone(ssm));
        if (ts->smt_start)
          streaming_start_unref(ts->smt_start);
        ts->smt_start = ssm->sm_data;
        atomic_add(&ts->smt_start->ss_refcount, 1);
      }
    }
  }
  return 0;
}
Beispiel #2
0
static timeshift_index_iframe_t *_timeshift_first_frame
  ( timeshift_t *ts )
{ 
  int end;
  timeshift_index_iframe_t *tsi = NULL;
  timeshift_file_t *tsf = timeshift_filemgr_oldest(ts);
  while (tsf && !tsi) {
    if (!(tsi = TAILQ_FIRST(&tsf->iframes))) {
      tsf = timeshift_filemgr_next(tsf, &end, 0);
    }
  }
  if (tsf)
    tsf->refcount--;
  return tsi;
}
/*
 * Output packet
 */
static int _timeshift_read
  ( timeshift_t *ts, timeshift_seek_t *seek,
    streaming_message_t **sm, int *wait )
{
  timeshift_file_t *tsf = seek->file;
  ssize_t r;
  off_t off = 0;

  *sm = NULL;

  if (tsf) {

    /* Open file */
    if (tsf->rfd < 0 && !tsf->ram) {
      tsf->rfd = tvh_open(tsf->path, O_RDONLY, 0);
      tvhtrace(LS_TIMESHIFT, "ts %d open file %s (fd %i)", ts->id, tsf->path, tsf->rfd);
      if (tsf->rfd < 0)
        return -1;
    }
    if (tsf->rfd >= 0)
      if ((off = lseek(tsf->rfd, tsf->roff, SEEK_SET)) != tsf->roff)
        tvherror(LS_TIMESHIFT, "ts %d seek to %s failed (off %"PRId64" != %"PRId64"): %s",
                 ts->id, tsf->path, (int64_t)tsf->roff, (int64_t)off, strerror(errno));

    /* Read msg */
    r = _read_msg(tsf, -1, sm);
    if (r < 0) {
      streaming_message_t *e = streaming_msg_create_code(SMT_STOP, SM_CODE_UNDEFINED_ERROR);
      streaming_target_deliver2(ts->output, e);
      tvhtrace(LS_TIMESHIFT, "ts %d seek to %jd (woff %jd) (fd %i)", ts->id, (intmax_t)off, (intmax_t)tsf->woff, tsf->rfd);
      tvherror(LS_TIMESHIFT, "ts %d could not read buffer", ts->id);
      return -1;
    }
    tvhtrace(LS_TIMESHIFT, "ts %d seek to %jd (fd %i) read msg %p/%"PRId64" (%"PRId64")",
             ts->id, (intmax_t)off, tsf->rfd, *sm, *sm ? (*sm)->sm_time : -1, (int64_t)r);

    /* Special case - EOF */
    if (r <= sizeof(size_t) || tsf->roff > tsf->size || *sm == NULL) {
      timeshift_file_get(seek->file); /* _read_close decreases file reference */
      _read_close(seek);
      _seek_set_file(seek, timeshift_filemgr_next(tsf, NULL, 0), 0);
      *wait     = 0;
      tvhtrace(LS_TIMESHIFT, "ts %d eof, seek->file %p (prev %p)", ts->id, seek->file, tsf);
      timeshift_filemgr_dump(ts);
    }
  }
  return 0;
}
static int64_t _timeshift_first_time
  ( timeshift_t *ts, int *active )
{ 
  int64_t ret = 0;
  int end;
  timeshift_index_iframe_t *tsi = NULL;
  timeshift_file_t *tsf = timeshift_filemgr_oldest(ts);
  while (tsf && !tsi) {
    if (!(tsi = TAILQ_FIRST(&tsf->iframes)))
      tsf = timeshift_filemgr_next(tsf, &end, 0);
  }
  if (tsi) {
    *active = 1;
    ret = tsi->time;
  }
  timeshift_file_put(tsf);
  return ret;
}
Beispiel #5
0
/*
 * Output packet
 */
static int _timeshift_read
  ( timeshift_t *ts, timeshift_file_t **cur_file,
    streaming_message_t **sm, int *wait )
{
  timeshift_file_t *tsf = *cur_file;
  ssize_t r;
  off_t off, ooff;

  if (tsf) {

    /* Open file */
    if (tsf->rfd < 0 && !tsf->ram) {
      tsf->rfd = open(tsf->path, O_RDONLY);
      tvhtrace("timeshift", "ts %d open file %s (fd %i)", ts->id, tsf->path, tsf->rfd);
      if (tsf->rfd < 0)
        return -1;
    }
    if (tsf->rfd >= 0)
      if ((off = lseek(tsf->rfd, tsf->roff, SEEK_SET)) != tsf->roff)
        tvherror("timeshift", "ts %d seek to %s failed (off %"PRId64" != %"PRId64"): %s",
                 ts->id, tsf->path, (int64_t)tsf->roff, (int64_t)off, strerror(errno));

    /* Read msg */
    ooff = tsf->roff;
    r = _read_msg(tsf, -1, sm);
    if (r < 0) {
      streaming_message_t *e = streaming_msg_create_code(SMT_STOP, SM_CODE_UNDEFINED_ERROR);
      streaming_target_deliver2(ts->output, e);
      tvhtrace("timeshift", "ts %d seek to %jd (fd %i)", ts->id, (intmax_t)tsf->roff, tsf->rfd);
      tvhlog(LOG_ERR, "timeshift", "ts %d could not read buffer", ts->id);
      return -1;
    }
    tvhtrace("timeshift", "ts %d seek to %jd (fd %i) read msg %p (%"PRId64")", ts->id, (intmax_t)tsf->roff, tsf->rfd, *sm, (int64_t)r);

    /* Incomplete */
    if (r == 0) {
      if (tsf->rfd >= 0) {
        tvhtrace("timeshift", "ts %d seek to %jd (fd %i) (incomplete)", ts->id, (intmax_t)tsf->roff, tsf->rfd);
        if ((off = lseek(tsf->rfd, ooff, SEEK_SET)) != ooff)
          tvherror("timeshift", "seek to %s failed (off %"PRId64" != %"PRId64"): %s",
                   tsf->path, (int64_t)ooff, (int64_t)off, strerror(errno));
      }
      tsf->roff = ooff;
      return 0;
    }

    /* Special case - EOF */
    if (r == sizeof(size_t) || tsf->roff > tsf->size) {
      if (tsf->rfd >= 0)
        close(tsf->rfd);
      tsf->rfd  = -1;
      pthread_mutex_lock(&ts->rdwr_mutex);
      *cur_file = timeshift_filemgr_next(tsf, NULL, 0);
      pthread_mutex_unlock(&ts->rdwr_mutex);
      tsf->roff = 0; // reset
      *wait     = 0;

    /* Check SMT_START index */
    } else {
      streaming_message_t *ssm = _timeshift_find_sstart(*cur_file, (*sm)->sm_time);
      if (ssm && ssm->sm_data != ts->smt_start) {
        streaming_target_deliver2(ts->output, streaming_msg_clone(ssm));
        if (ts->smt_start)
          streaming_start_unref(ts->smt_start);
        ts->smt_start = ssm->sm_data;
        atomic_add(&ts->smt_start->ss_refcount, 1);
      }
    }
  }
  return 0;
}
Beispiel #6
0
static int _timeshift_skip
  ( timeshift_t *ts, int64_t req_time, int64_t cur_time,
    timeshift_file_t *cur_file, timeshift_file_t **new_file,
    timeshift_index_iframe_t **iframe )
{
  timeshift_index_iframe_t *tsi  = *iframe;
  timeshift_file_t         *tsf  = cur_file, *tsf_last;
  int64_t                   sec  = req_time / (1000000 * TIMESHIFT_FILE_PERIOD);
  int                       back = (req_time < cur_time) ? 1 : 0;
  int                       end  = 0;
  
  /* Hold local ref */
  if (cur_file)
    cur_file->refcount++;

  /* Coarse search */
  if (!tsi) {
    while (tsf && !end) {
      if (back) {
        if ((tsf->time <= sec) &&
            (tsi = TAILQ_LAST(&tsf->iframes, timeshift_index_iframe_list)))
          break;
        tsf = timeshift_filemgr_prev(tsf, &end, 1);
      } else {
        if ((tsf->time >= sec) &&
            (tsi = TAILQ_FIRST(&tsf->iframes)))
          break;
        tsf = timeshift_filemgr_next(tsf, &end, 0);
      }
      tsi = NULL;
    }
  }

  /* Fine search */
  if (back) {
    while (!end && tsf && tsi && (tsi->time > req_time)) {
      tsi = TAILQ_PREV(tsi, timeshift_index_iframe_list, link);
      while (!end && tsf && !tsi) {
        if ((tsf = timeshift_filemgr_prev(tsf, &end, 1)))
          tsi = TAILQ_LAST(&tsf->iframes, timeshift_index_iframe_list);
      }
    }
  } else {
    while (!end && tsf && tsi && (tsi->time < req_time)) {
      tsi = TAILQ_NEXT(tsi, link);
      while (!end && tsf && !tsi) {
        if ((tsf = timeshift_filemgr_next(tsf, &end, 0)))
          tsi = TAILQ_FIRST(&tsf->iframes);
      }
    }
  }

  /* End */
  if (!tsf || !tsi)
    end = 1;

  /* Find start/end of buffer */
  if (end) {
    if (back) {
      tsf = tsf_last = timeshift_filemgr_oldest(ts);
      tsi = NULL;
      while (tsf && !tsi) {
        tsf_last = tsf;
        if (!(tsi = TAILQ_FIRST(&tsf->iframes)))
          tsf = timeshift_filemgr_next(tsf, &end, 0);
      }
      if (!tsf)
        tsf = tsf_last;
      end = -1;
    } else {
      tsf = tsf_last = timeshift_filemgr_get(ts, 0);
      tsi = NULL;
      while (tsf && !tsi) {
        tsf_last = tsf;
        if (!(tsi = TAILQ_LAST(&tsf->iframes, timeshift_index_iframe_list)))
          tsf = timeshift_filemgr_prev(tsf, &end, 0);
      }
      if (!tsf)
        tsf = tsf_last;
      end = 1;
    }
  }

  if (cur_file)
    cur_file->refcount--;

  /* Done */
  *new_file = tsf;
  *iframe   = tsi;
  return end;
}
static int _timeshift_skip
  ( timeshift_t *ts, int64_t req_time, int64_t cur_time,
    timeshift_seek_t *seek, timeshift_seek_t *nseek )
{
  timeshift_index_iframe_t *tsi  = seek->frame;
  timeshift_file_t         *tsf  = seek->file, *tsf_last;
  int64_t                   sec  = mono2sec(req_time) / TIMESHIFT_FILE_PERIOD;
  int                       back = (req_time < cur_time) ? 1 : 0;
  int                       end  = 0;

  /* Coarse search */
  if (!tsi) {
    while (tsf && !end) {
      if (back) {
        if ((tsf->time <= sec) &&
            (tsi = TAILQ_LAST(&tsf->iframes, timeshift_index_iframe_list)))
          break;
        tsf = timeshift_filemgr_prev(tsf, &end, 1);
      } else {
        if ((tsf->time >= sec) &&
            (tsi = TAILQ_FIRST(&tsf->iframes)))
          break;
        tsf = timeshift_filemgr_next(tsf, &end, 0);
      }
      tsi = NULL;
    }
  }

  /* Fine search */
  if (back) {
    while (!end && tsf && tsi && (tsi->time > req_time)) {
      tsi = TAILQ_PREV(tsi, timeshift_index_iframe_list, link);
      while (!end && tsf && !tsi) {
        if ((tsf = timeshift_filemgr_prev(tsf, &end, 1)))
          tsi = TAILQ_LAST(&tsf->iframes, timeshift_index_iframe_list);
      }
    }
  } else {
    while (!end && tsf && tsi && (tsi->time < req_time)) {
      tsi = TAILQ_NEXT(tsi, link);
      while (!end && tsf && !tsi) {
        if ((tsf = timeshift_filemgr_next(tsf, &end, 0)))
          tsi = TAILQ_FIRST(&tsf->iframes);
      }
    }
  }

  /* End */
  if (!tsf || !tsi)
    end = 1;

  /* Find start/end of buffer */
  if (end) {
    timeshift_file_put(tsf);
    if (back) {
      tsf = tsf_last = timeshift_filemgr_oldest(ts);
      tsi = NULL;
      while (tsf && !tsi) {
        tsf_last = tsf;
        if (!(tsi = TAILQ_FIRST(&tsf->iframes)))
          tsf = timeshift_filemgr_next(tsf, &end, 0);
      }
      if (!tsf)
        tsf = tsf_last;
      end = -1;
    } else {
      tsf = tsf_last = timeshift_filemgr_newest(ts);
      tsi = NULL;
      while (tsf && !tsi) {
        tsf_last = tsf;
        if (!(tsi = TAILQ_LAST(&tsf->iframes, timeshift_index_iframe_list)))
          tsf = timeshift_filemgr_prev(tsf, &end, 0);
      }
      if (!tsf)
        tsf = tsf_last;
      end = 1;
    }
  }

  /* Done */
  nseek->file  = tsf;
  nseek->frame = tsi;
  return end;
}