void timeshift_destroy(streaming_target_t *pad) { timeshift_t *ts = (timeshift_t*)pad; streaming_message_t *sm; /* Must hold global lock */ lock_assert(&global_lock); /* Ensure the threads exits */ // Note: this is a workaround for the fact the Q might have been flushed // in reader thread (VERY unlikely) pthread_mutex_lock(&ts->state_mutex); sm = streaming_msg_create(SMT_EXIT); streaming_target_deliver2(&ts->wr_queue.sq_st, sm); timeshift_write_exit(ts->rd_pipe.wr); pthread_mutex_unlock(&ts->state_mutex); /* Wait for all threads */ pthread_join(ts->rd_thread, NULL); pthread_join(ts->wr_thread, NULL); /* Shut stuff down */ streaming_queue_deinit(&ts->wr_queue); close(ts->rd_pipe.rd); close(ts->rd_pipe.wr); /* Flush files */ timeshift_filemgr_flush(ts, NULL); free(ts->path); free(ts); }
/* * Receive data */ static void timeshift_input ( void *opaque, streaming_message_t *sm ) { int type = sm->sm_type; timeshift_t *ts = opaque; th_pkt_t *pkt, *pkt2; if (ts->exit) return; /* Control */ if (type == SMT_SKIP) { timeshift_write_skip(ts->rd_pipe.wr, sm->sm_data); streaming_msg_free(sm); } else if (type == SMT_SPEED) { timeshift_write_speed(ts->rd_pipe.wr, sm->sm_code); streaming_msg_free(sm); } else { /* Change PTS/DTS offsets */ if (ts->packet_mode && ts->start_pts && type == SMT_PACKET) { pkt = sm->sm_data; pkt2 = pkt_copy_shallow(pkt); pkt_ref_dec(pkt); sm->sm_data = pkt2; pkt2->pkt_pts += ts->start_pts; pkt2->pkt_dts += ts->start_pts; } /* Check for exit */ else if (type == SMT_EXIT || (type == SMT_STOP && sm->sm_code != SM_CODE_SOURCE_RECONFIGURED)) ts->exit = 1; else if (type == SMT_MPEGTS) ts->packet_mode = 0; /* Send to the writer thread */ if (ts->packet_mode) { sm->sm_time = ts->last_wr_time; if ((type == SMT_PACKET) && !timeshift_packet(ts, sm)) goto _exit; } else { if (ts->ref_time == 0) { ts->ref_time = getfastmonoclock(); sm->sm_time = 0; } else { sm->sm_time = getfastmonoclock() - ts->ref_time; } } streaming_target_deliver2(&ts->wr_queue.sq_st, sm); /* Exit/Stop */ _exit: if (ts->exit) timeshift_write_exit(ts->rd_pipe.wr); } }
/* * Receive data */ static void timeshift_input ( void *opaque, streaming_message_t *sm ) { int exit = 0; timeshift_t *ts = opaque; 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; } /* Pass-thru */ if (ts->state <= TS_LIVE) { 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; /* Buffer to disk */ if ((ts->state > TS_LIVE) || (!ts->ondemand && (ts->state == TS_LIVE))) { sm->sm_time = getmonoclock(); 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); }
void timeshift_destroy(streaming_target_t *pad) { timeshift_t *ts = (timeshift_t*)pad; streaming_message_t *sm; int i; /* Must hold global lock */ lock_assert(&global_lock); /* Ensure the threads exits */ // Note: this is a workaround for the fact the Q might have been flushed // in reader thread (VERY unlikely) pthread_mutex_lock(&ts->state_mutex); sm = streaming_msg_create(SMT_EXIT); streaming_target_deliver2(&ts->wr_queue.sq_st, sm); timeshift_write_exit(ts->rd_pipe.wr); pthread_mutex_unlock(&ts->state_mutex); /* Wait for all threads */ pthread_join(ts->rd_thread, NULL); pthread_join(ts->wr_thread, NULL); /* Shut stuff down */ streaming_queue_deinit(&ts->wr_queue); for (i = 0; i < TIMESHIFT_BACKLOG_MAX; i++) streaming_queue_clear(&ts->backlog[i]); close(ts->rd_pipe.rd); close(ts->rd_pipe.wr); /* Flush files */ timeshift_filemgr_flush(ts, NULL); /* Release SMT_START index */ if (ts->smt_start) streaming_start_unref(ts->smt_start); if (ts->path) free(ts->path); free(ts); }
/* * 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) timeshift_set_pts_delta(ts, pkt->pkt_pts); /* 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); }
/* * Receive data */ static void timeshift_input ( void *opaque, streaming_message_t *sm ) { int exit = 0; timeshift_t *ts = opaque; 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; } /* 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) { th_pkt_t *pkt = sm->sm_data; 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(); 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); }
/* * Receive data */ static void timeshift_input ( void *opaque, streaming_message_t *sm ) { int exit = 0, type = sm->sm_type; timeshift_t *ts = opaque; th_pkt_t *pkt = sm->sm_data, *pkt2; pthread_mutex_lock(&ts->state_mutex); /* Control */ if (type == SMT_SKIP) { if (ts->state >= TS_LIVE) timeshift_write_skip(ts->rd_pipe.wr, sm->sm_data); streaming_msg_free(sm); } else if (type == SMT_SPEED) { if (ts->state >= TS_LIVE) timeshift_write_speed(ts->rd_pipe.wr, sm->sm_code); streaming_msg_free(sm); } else { /* Start */ if (type == SMT_START && ts->state == TS_INIT) ts->state = TS_LIVE; /* Change PTS/DTS offsets */ if (ts->packet_mode && ts->start_pts && type == SMT_PACKET) { pkt2 = pkt_copy_shallow(pkt); pkt_ref_dec(pkt); sm->sm_data = pkt = pkt2; pkt->pkt_pts += ts->start_pts; pkt->pkt_dts += ts->start_pts; } /* Pass-thru */ if (ts->state <= TS_LIVE) { if (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); if (ts->packet_mode) { timeshift_packet_flush(ts, ts->last_time + MAX_TIME_DELTA + 1000, ts->dobuf); if (ts->last_time) ts->start_pts = ts->last_time + 1000; } } streaming_target_deliver2(ts->output, streaming_msg_clone(sm)); } /* Check for exit */ if (type == SMT_EXIT || (type == SMT_STOP && sm->sm_code != SM_CODE_SOURCE_RECONFIGURED)) exit = 1; if (type == SMT_MPEGTS) ts->packet_mode = 0; /* Buffer to disk */ if ((ts->state > TS_LIVE) || (ts->dobuf && (ts->state == TS_LIVE))) { if (ts->packet_mode) { sm->sm_time = ts->last_time; if (type == SMT_PACKET) { timeshift_packet(ts, pkt, 1); goto msg_free; } } else { if (ts->ref_time == 0) { ts->ref_time = getmonoclock(); sm->sm_time = 0; } else { sm->sm_time = getmonoclock() - ts->ref_time; } } streaming_target_deliver2(&ts->wr_queue.sq_st, sm); } else { if (type == SMT_PACKET) { timeshift_packet(ts, pkt, 0); tvhtrace("timeshift", "ts %d pkt in - stream %d type %c pts %10"PRId64 " dts %10"PRId64" dur %10d len %6zu", 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)); } msg_free: 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); }