/* * 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; } tvhtrace("timeshift", "ts %d seek to %jd (fd %i)", ts->id, tsf->roff, tsf->rfd); if (tsf->rfd >= 0) if ((off = lseek(tsf->rfd, tsf->roff, SEEK_SET)) != tsf->roff) tvherror("timeshift", "seek to %s failed (off %"PRId64" != %"PRId64"): %s", 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); tvhlog(LOG_ERR, "timeshift", "ts %d could not read buffer", ts->id); return -1; } #if ENABLE_ANDROID tvhtrace("timeshift", "ts %d read msg %p (%ld)", ts->id, *sm, r); // Android bug, ssize_t is long int #else tvhtrace("timeshift", "ts %d read msg %p (%zd)", ts->id, *sm, r); #endif /* Incomplete */ if (r == 0) { if (tsf->rfd >= 0) { tvhtrace("timeshift", "ts %d seek to %jd (fd %i) (incomplete)", ts->id, 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; }
/* * Receive data */ static void timeshift_input ( void *opaque, streaming_message_t *sm ) { int exit = 0; timeshift_t *ts = opaque; th_pkt_t *pkt = sm->sm_data; pthread_mutex_lock(&ts->state_mutex); /* Control */ if (sm->sm_type == SMT_SKIP) { if (ts->state >= TS_LIVE) timeshift_write_skip(ts->rd_pipe.wr, sm->sm_data); } else if (sm->sm_type == SMT_SPEED) { if (ts->state >= TS_LIVE) timeshift_write_speed(ts->rd_pipe.wr, sm->sm_code); } else { /* Start */ if (sm->sm_type == SMT_START && ts->state == TS_INIT) { ts->state = TS_LIVE; } if (sm->sm_type == SMT_PACKET) { tvhtrace("timeshift", "ts %d pkt in - stream %d type %c pts %10"PRId64 " dts %10"PRId64" dur %10d len %zu", ts->id, pkt->pkt_componentindex, pkt_frametype_to_char(pkt->pkt_frametype), ts_rescale(pkt->pkt_pts, 1000000), ts_rescale(pkt->pkt_dts, 1000000), pkt->pkt_duration, pktbuf_len(pkt->pkt_payload)); } /* Pass-thru */ if (ts->state <= TS_LIVE) { if (sm->sm_type == SMT_START) { if (ts->smt_start) streaming_start_unref(ts->smt_start); ts->smt_start = sm->sm_data; atomic_add(&ts->smt_start->ss_refcount, 1); } streaming_target_deliver2(ts->output, streaming_msg_clone(sm)); } /* Check for exit */ if (sm->sm_type == SMT_EXIT || (sm->sm_type == SMT_STOP && sm->sm_code == 0)) exit = 1; /* Record (one-off) PTS delta */ if (sm->sm_type == SMT_PACKET && ts->pts_delta == PTS_UNSET) { if (pkt->pkt_pts != PTS_UNSET) ts->pts_delta = getmonoclock() - ts_rescale(pkt->pkt_pts, 1000000); } /* Buffer to disk */ if ((ts->state > TS_LIVE) || (!ts->ondemand && (ts->state == TS_LIVE))) { sm->sm_time = getmonoclock(); if (sm->sm_type == SMT_PACKET) { tvhtrace("timeshift", "ts %d pkt buf - stream %d type %c pts %10"PRId64 " dts %10"PRId64" dur %10d len %zu", ts->id, pkt->pkt_componentindex, pkt_frametype_to_char(pkt->pkt_frametype), ts_rescale(pkt->pkt_pts, 1000000), ts_rescale(pkt->pkt_dts, 1000000), pkt->pkt_duration, pktbuf_len(pkt->pkt_payload)); } streaming_target_deliver2(&ts->wr_queue.sq_st, sm); } else streaming_msg_free(sm); /* Exit/Stop */ if (exit) { timeshift_write_exit(ts->rd_pipe.wr); ts->state = TS_EXIT; } } pthread_mutex_unlock(&ts->state_mutex); }