root/trunk/tvheadend/src/rawtsinput.c @ 3081

Revision 3081, 5.3 KB (checked in by andoma, 15 months ago)

Initial stab of a 'raw MPEG TS' input.

This allows Tvheadend to read a raw ts stream and act as if it's a live feed.

Great for debugging.

Line 
1/*
2 *  Raw TS input (for debugging)
3 *  Copyright (C) 2009 Andreas Öman
4 *
5 *  This program is free software: you can redistribute it and/or modify
6 *  it under the terms of the GNU General Public License as published by
7 *  the Free Software Foundation, either version 3 of the License, or
8 *  (at your option) any later version.
9 *
10 *  This program is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 *  GNU General Public License for more details.
14 *
15 *  You should have received a copy of the GNU General Public License
16 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <pthread.h>
20#include <stdint.h>
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <unistd.h>
24#include <fcntl.h>
25#include <stdio.h>
26#include <string.h>
27#include <errno.h>
28
29#include "tvhead.h"
30#include "transports.h"
31#include "rawtsinput.h"
32#include "psi.h"
33#include "tsdemux.h"
34
35typedef struct rawts {
36  int rt_fd;
37
38  char *rt_identifier;
39  psi_section_t rt_pat;
40
41  struct th_transport_list rt_transports;
42
43} rawts_t;
44
45
46/**
47 *
48 */
49static int
50rawts_transport_start(th_transport_t *t, unsigned int weight, int status,
51                      int force_start)
52{
53  return 0; // Always ok
54}
55
56/**
57 *
58 */
59static void
60rawts_transport_stop(th_transport_t *t)
61{
62 
63}
64
65/**
66 *
67 */
68static void
69rawts_transport_save(th_transport_t *t)
70{
71}
72
73
74/**
75 *
76 */
77static int
78rawts_transport_quality(th_transport_t *t)
79{
80  return 100;
81}
82
83
84/**
85 * Generate a descriptive name for the source
86 */
87static const char *
88rawts_transport_sourcename(th_transport_t *t)
89{
90  return "rawts";
91}
92
93
94/**
95 * Generate a descriptive name for the source
96 */
97static const char *
98rawts_transport_networkname(th_transport_t *t)
99{
100  return "rawts";
101}
102
103
104
105/**
106 *
107 */
108static th_transport_t *
109rawts_transport_add(rawts_t *rt, uint16_t sid, int pmt_pid)
110{
111  th_transport_t *t;
112  channel_t *ch;
113
114  char tmp[200];
115
116  LIST_FOREACH(t, &rt->rt_transports, tht_mux_link) {
117    if(t->tht_dvb_service_id == sid)
118      return t;
119  }
120 
121  snprintf(tmp, sizeof(tmp), "%s_%04x", rt->rt_identifier, sid);
122
123  t = transport_create(tmp, TRANSPORT_DVB, THT_MPEG_TS);
124  t->tht_flags |= THT_DEBUG;
125
126  t->tht_dvb_service_id = sid;
127  t->tht_pmt_pid        = pmt_pid;
128
129  t->tht_start_feed = rawts_transport_start;
130  t->tht_stop_feed  = rawts_transport_stop;
131  t->tht_config_change = rawts_transport_save;
132  t->tht_sourcename = rawts_transport_sourcename;
133  t->tht_networkname = rawts_transport_networkname;
134  t->tht_quality_index = rawts_transport_quality;
135
136  t->tht_svcname = strdup(tmp);
137
138  tvhlog(LOG_NOTICE, "rawts", "Added service %d (pmt: %d)", sid, pmt_pid);
139
140  LIST_INSERT_HEAD(&rt->rt_transports, t, tht_mux_link);
141
142  ch = channel_find_by_name(tmp, 1);
143
144  transport_map_channel(t, ch);
145  return t;
146}
147
148
149/*
150 *
151 */
152
153static void
154got_pmt(struct th_transport *t, th_stream_t *st,
155        uint8_t *table, int table_len)
156{
157  if(table[0] != 2)
158    return;
159
160  pthread_mutex_lock(&global_lock);
161  psi_parse_pmt(t, table + 3, table_len - 3, 1);
162  pthread_mutex_unlock(&global_lock);
163}
164
165
166
167/**
168 *
169 */
170static void
171got_pat(rawts_t *rt)
172{
173  th_transport_t *t;
174  th_stream_t *st;
175  int len = rt->rt_pat.ps_offset;
176  uint8_t *ptr = rt->rt_pat.ps_data;
177  uint16_t prognum;
178  uint16_t pid;
179
180  len -= 8;
181  ptr += 8;
182
183  if(len < 0)
184    return;
185
186  pthread_mutex_lock(&global_lock);
187
188  while(len >= 4) {
189   
190    prognum =  ptr[0]         << 8 | ptr[1];
191    pid     = (ptr[2] & 0x1f) << 8 | ptr[3];
192
193    if(prognum != 0) {
194      t = rawts_transport_add(rt, prognum, pid);
195
196      if(t != NULL) {
197        pthread_mutex_lock(&t->tht_stream_mutex);
198        st = transport_add_stream(t, pid, SCT_PMT);
199        st->st_section_docrc = 1;
200        st->st_got_section = got_pmt;
201        pthread_mutex_unlock(&t->tht_stream_mutex);
202      }
203    }
204    ptr += 4;
205    len -= 4;
206  } 
207  pthread_mutex_unlock(&global_lock);
208}
209
210/**
211 *
212 */
213static void
214rawts_pat(rawts_t *rt, uint8_t *tsb)
215{
216  int off  = tsb[3] & 0x20 ? tsb[4] + 5 : 4;
217  int pusi = tsb[1] & 0x40;
218  int len;
219
220  if(off >= 188)
221    return;
222
223  if(pusi) {
224    len = tsb[off++];
225    if(len > 0) {
226      if(len > 188 - off)
227        return;
228      if(!psi_section_reassemble(&rt->rt_pat, tsb + off, len, 0, 1))
229        got_pat(rt);
230      off += len;
231    }
232  }
233   
234  if(!psi_section_reassemble(&rt->rt_pat, tsb + off, 188 - off, pusi, 1))
235    got_pat(rt);
236}
237
238
239/**
240 *
241 */
242static void
243process_ts_packet(rawts_t *rt, uint8_t *tsb)
244{
245  uint16_t pid;
246  th_transport_t *t;
247
248  pid = ((tsb[1] & 0xf) << 8) | tsb[2];
249
250  if(pid == 0) {
251    /* PAT */
252    rawts_pat(rt, tsb);
253    return;
254  }
255 
256  LIST_FOREACH(t, &rt->rt_transports, tht_mux_link)
257    ts_recv_packet1(t, tsb);
258}
259
260
261/**
262 *
263 */
264static void *
265raw_ts_reader(void *aux)
266{
267  rawts_t *rt = aux;
268  uint8_t tsblock[188];
269  int c = 0;
270  int i;
271
272  while(1) {
273
274    for(i = 0; i < 2; i++) {
275      if(read(rt->rt_fd, tsblock, 188) != 188) {
276        lseek(rt->rt_fd, 0, SEEK_SET);
277        continue;
278      }
279      c++;
280      process_ts_packet(rt, tsblock);
281    }
282    usleep(1000);
283  }
284
285  return NULL;
286}
287
288
289/**
290 *
291 */
292void
293rawts_init(const char *filename)
294{
295  pthread_t ptid;
296  rawts_t *rt;
297  int fd = open(filename, O_RDONLY);
298
299  if(fd == -1) {
300    fprintf(stderr, "Unable to open %s -- %s\n", filename, strerror(errno));
301    return;
302  }
303
304  rt = calloc(1, sizeof(rawts_t));
305  rt->rt_fd = fd;
306
307  rt->rt_identifier = strdup("rawts");
308
309  pthread_create(&ptid, NULL, raw_ts_reader, rt);
310}
Note: See TracBrowser for help on using the browser.