Annotation of multiplexer/splicets.c, revision 1.3
1.1 oskar 1: /*
2: * ISO 13818 stream multiplexer
3: * Copyright (C) 2001 Convergence Integrated Media GmbH Berlin
4: * Author: Oskar Schirmer (oskar@convergence.de)
5: */
6:
7: /*
8: * Module: Splice TS
9: * Purpose: Generate transport stream.
10: *
11: * This module generates from the available input stream data (as
12: * seperated by the split functions) the complete output stream.
13: * It provides functions to handle programs for the resulting stream,
14: * as these are output format dependent. Further, it accepts PSI data
15: * just in time, validating it not earlier than with the arrival of
16: * the corresponding payload at this stage.
17: */
18:
19: #include "global.h"
20: #include "crc.h"
21: #include "error.h"
22: #include "input.h"
23: #include "output.h"
24: #include "descref.h"
25: #include "pes.h"
26: #include "ts.h"
27: #include "splice.h"
28: #include "splicets.h"
29:
30: const boolean splice_multipleprograms = TRUE;
31:
32: static boolean changed_pat;
33: static int pat_section;
34: static const int last_patsection = 0;
35: static byte nextpat_version;
36: static byte pat_conticnt;
37:
38: static int transportstreamid;
39:
40: static int psi_size;
41: static int psi_done;
42: static byte psi_data [MAX_PSI_SIZE];
43:
44: static byte unit_start;
45: static byte *conticnt;
46: static int psi_pid;
47:
48: static int progs;
49: static prog_descr *prog [MAX_OUTPROG];
50:
51: static int nextpid;
52: static stream_descr *outs [MAX_STRPERTS];
53:
1.3 ! oskar 54: static t_msec next_psi_periodic;
! 55: static t_msec psi_frequency_msec;
1.1 oskar 56: static boolean psi_frequency_changed;
57:
58: boolean splice_init (void)
59: {
60: progs = 0;
61: nextpid = 0;
62: memset (outs,0,sizeof(outs));
63: changed_pat = TRUE;
64: pat_section = 0;
65: nextpat_version = 0;
66: pat_conticnt = 0;
67: psi_size = psi_done = 0;
68: unit_start = TS_UNIT_START;
69: transportstreamid = 0x4227;
70: psi_frequency_msec = 0;
71: psi_frequency_changed = FALSE;
72: return (TRUE);
73: }
74:
75: void splice_settransportstreamid (int tsid)
76: {
77: transportstreamid = tsid;
78: }
79:
80: void splice_setpsifrequency (int freq)
81: {
82: psi_frequency_msec = freq;
83: psi_frequency_changed = TRUE;
84: }
85:
86: static int findapid (stream_descr *s)
87: {
88: boolean ok = TRUE;
89: do {
1.2 oskar 90: if ((nextpid < TS_PID_SPLICELO) || (nextpid >= TS_PID_SPLICEHI)) {
1.1 oskar 91: if (!ok) {
92: warn (LERR,"No PID found",ETSC,2,1,0);
93: return (0);
94: }
95: ok = FALSE;
1.2 oskar 96: nextpid = TS_PID_SPLICELO;
1.1 oskar 97: } else {
98: nextpid += 1;
99: }
100: } while (outs[nextpid] != NULL);
101: outs[nextpid] = s;
102: warn (LDEB,"Next PID",ETSC,2,2,nextpid);
103: return (nextpid);
104: }
105:
1.3 ! oskar 106: prog_descr *splice_getprog (int programnb)
! 107: {
! 108: int i;
! 109: i = progs;
! 110: while (--i >= 0) {
! 111: if (prog[i]->program_number == programnb) {
! 112: return (prog[i]);
! 113: }
! 114: }
! 115: return (NULL);
! 116: }
! 117:
1.1 oskar 118: prog_descr *splice_openprog (int programnb)
119: {
120: prog_descr *p;
121: int pid;
122: warn (LIMP,"Open prog",ETSC,1,0,programnb);
1.3 ! oskar 123: p = splice_getprog (programnb);
1.1 oskar 124: if (p == NULL) {
125: if (progs < MAX_OUTPROG) {
126: if ((pid = findapid (PMT_STREAM)) > 0) {
127: if ((p = malloc(sizeof(prog_descr))) != NULL) {
128: p->program_number = programnb;
129: p->pcr_pid = -1;
130: p->pmt_pid = pid;
131: p->pmt_conticnt = 0;
132: p->pmt_version = 0;
133: p->changed = TRUE;
134: p->pat_section = 0; /* more ? */
135: p->streams = 0;
136: prog[progs++] = p;
137: changed_pat = TRUE;
138: } else {
139: outs[pid] = NULL;
140: warn (LERR,"Open prog",ETSC,1,1,0);
141: }
142: }
143: } else {
144: warn (LERR,"Max prog open",ETSC,1,2,0);
145: }
146: }
147: return (p);
148: }
149:
150: void splice_closeprog (prog_descr *p)
151: {
152: int i, n;
153: warn (LIMP,"Close prog",ETSC,3,0,p->program_number);
154: while (p->streams > 0) {
1.3 ! oskar 155: unlink_streamprog (p->stream[0],p);
1.1 oskar 156: }
157: n = -1;
158: if (p->pmt_pid >= 0) {
159: i = progs;
160: while (--i >= 0) {
161: if (prog[i]->pmt_pid == p->pmt_pid) {
162: n += 1;
163: }
164: }
165: }
166: i = progs;
167: while (--i >= 0) {
168: if (prog[i] == p) {
169: prog[i] = prog[--progs];
170: if (n == 0) {
171: outs[p->pmt_pid] = NULL;
172: }
173: free (p);
174: changed_pat = TRUE;
175: return;
176: }
177: }
178: warn (LERR,"Close lost prog",ETSC,3,1,progs);
179: }
180:
181: int splice_addstream (prog_descr *p,
182: stream_descr *s,
183: boolean force_sid)
184: {
185: int pid = 0;
186: warn (LIMP,"Add stream",ETSC,4,force_sid,s->stream_id);
187: if (p->streams < MAX_STRPERPRG) {
188: if ((pid = findapid (s)) > 0) {
189: if (!force_sid) {
1.3 ! oskar 190: s->stream_id = splice_findfreestreamid (p,s->stream_id);
1.1 oskar 191: }
192: p->stream[p->streams++] = s;
193: p->changed = TRUE;
194: s->u.d.pid = pid;
195: }
196: }
197: return (pid);
198: }
199:
200: boolean splice_delstream (prog_descr *p,
201: stream_descr *s)
202: {
203: int i;
204: warn (LIMP,"Del stream",ETSC,5,0,s->u.d.pid);
205: i = p->streams;
206: while (--i >= 0) {
207: if (p->stream[i] == s) {
208: outs[s->u.d.pid] = NULL;
209: p->stream[i] = p->stream[--(p->streams)];
210: p->changed = TRUE;
211: if (p->pcr_pid == s->u.d.pid) {
212: p->pcr_pid = -1;
213: }
214: s->u.d.pid = 0;
215: return (TRUE);
216: }
217: }
218: warn (LERR,"Del lost stream",ETSC,5,1,p->streams);
219: return (FALSE);
220: }
221:
222: static int make_patsection (int section,
223: byte *dest)
224: {
225: int i;
226: byte *d;
227: d = dest;
228: *d++ = TS_TABLEID_PAT;
229: d += 2;
230: *d++ = transportstreamid >> 8;
231: *d++ = (byte)transportstreamid;
232: *d++ = 0xC0 | 0x01 | (nextpat_version << 1);
233: *d++ = section;
234: *d++ = last_patsection;
235: i = progs;
236: while (--i >= 0) {
237: if (prog[i]->pat_section == section) {
238: int x;
239: x = prog[i]->program_number;
240: *d++ = (x >> 8);
241: *d++ = x;
242: x = prog[i]->pmt_pid;
243: *d++ = 0xE0 | (x >> 8);
244: *d++ = x;
245: }
246: }
247: i = d + CRC_SIZE - dest - TS_TRANSPORTID;
248: dest[TS_SECTIONLEN] = 0xB0 | (i >> 8);
249: dest[TS_SECTIONLEN+1] = i;
250: crc32_calc (dest,i + TS_TRANSPORTID - CRC_SIZE,d);
251: return (i + TS_TRANSPORTID);
252: }
253:
254: static int make_pmtsection (stream_descr *s,
255: prog_descr *p,
256: byte *dest)
257: {
258: int i;
259: byte *d;
260: p->changed = FALSE;
261: d = dest;
262: *d++ = TS_TABLEID_PMT;
263: d += 2;
264: i = p->program_number;
265: *d++ = (i >> 8);
266: *d++ = i;
267: *d++ = 0xC0 | 0x01 | (p->pmt_version << 1);
268: p->pmt_version = (p->pmt_version+1) & 0x1F;
269: *d++ = 0;
270: *d++ = 0;
271: if (p->pcr_pid < 0) {
272: stream_descr *pcrs;
1.3 ! oskar 273: pcrs = splice_findpcrstream (p);
1.1 oskar 274: if (pcrs == NULL) {
275: pcrs = s;
276: }
277: pcrs->u.d.has_clockref = TRUE;
278: pcrs->u.d.next_clockref = msec_now () - MAX_MSEC_PCRDIST;
279: p->pcr_pid = pcrs->u.d.pid;
280: }
281: i = p->pcr_pid;
282: *d++ = 0xE0 | (i >> 8);
283: *d++ = i;
284: d += 2;
285: i = NUMBER_ELEMD;
286: while (--i > 0) {
287: if (s->fdescr->content == ct_program) {
288: byte *y;
289: y = s->fdescr->u.ps.stream[0]->elemdvld[i]; /* this one ? why ? */
290: if (y != NULL) {
291: memcpy (d,y,y[1]+2);
292: d += y[1]+2;
293: }
294: }
295: }
296: i = d - dest - (TS_PMT_PILEN+2);
297: dest[TS_PMT_PILEN] = 0xF0 | (i >> 8);
298: dest[TS_PMT_PILEN+1] = i;
299: i = p->streams;
300: while (--i >= 0) {
301: if (p->stream[i]->u.d.mention) {
302: int x;
303: byte *e;
304: *d++ = p->stream[i]->stream_type;
305: x = p->stream[i]->u.d.pid;
306: *d++ = 0xE0 | (x >> 8);
307: *d++ = x;
308: d += 2;
309: e = d;
310: x = NUMBER_ELEMD;
311: while (--x > 0) {
312: byte *y;
313: y = p->stream[i]->elemdvld[x];
314: if (y != NULL) {
315: memcpy (d,y,y[1]+2);
316: d += y[1]+2;
317: }
318: }
319: x = d - e;
320: *--e = x;
321: *--e = 0xF0 | (x >> 8);
322: }
323: }
324: i = d + CRC_SIZE - dest - TS_TRANSPORTID;
325: dest[TS_SECTIONLEN] = 0xB0 | (i >> 8);
326: dest[TS_SECTIONLEN+1] = i;
327: crc32_calc (dest,i + TS_TRANSPORTID - CRC_SIZE,d);
328: return (i + TS_TRANSPORTID);
329: }
330:
331: void process_finish (void)
332: {
333: warn (LIMP,"Finish",ETSC,6,0,0);
334: }
335:
336: stream_descr *process_something (stream_descr *s)
337: {
338: byte *d;
339: int pid;
340: byte scramble;
341: ctrl_buffer *c;
342: int l, f, k;
343: int privdata;
344: int adapt_ext_len;
1.3 ! oskar 345: t_msec now;
1.1 oskar 346: byte adapt_field_ctrl;
347: byte adapt_flags1, adapt_flags2;
348: warn (LDEB,"Splice TS",ETSC,0,0,s->ctrl.out);
349: if (s->isamap) {
350: validate_mapref (s);
351: return (NULL);
352: }
353: c = &s->ctrl.ptr[s->ctrl.out];
354: if (psi_size > 0) {
355: pid = psi_pid;
356: scramble = 0;
357: k = psi_size;
358: } else {
359: if (unit_start != 0) {
360: now = msec_now ();
361: if ((psi_frequency_changed)
362: || ((psi_frequency_msec > 0)
363: && ((next_psi_periodic - now) <= 0))) {
364: changed_pat = TRUE;
365: l = progs;
366: while (--l >= 0) {
367: prog[l]->changed = TRUE;
368: }
369: psi_frequency_changed = FALSE;
370: next_psi_periodic = now + psi_frequency_msec;
371: }
372: if (changed_pat) {
373: psi_pid = TS_PID_PAT;
374: conticnt = &pat_conticnt;
375: psi_data[0] = 0;
376: psi_size = make_patsection (pat_section,&psi_data[1]) + 1;
377: if (pat_section >= last_patsection) {
378: changed_pat = FALSE;
379: nextpat_version = (nextpat_version+1) & 0x1F;
380: pat_section = 0;
381: } else {
382: pat_section += 1;
383: }
384: psi_done = 0;
385: pid = psi_pid;
386: scramble = 0;
387: k = psi_size;
388: } else {
389: l = s->u.d.progs;
390: while (--l >= 0) {
391: if (s->u.d.pdescr[l]->changed) {
392: f = s->u.d.pdescr[l]->streams;
393: while ((--f >= 0)
394: && (!s->u.d.pdescr[l]->stream[f]->u.d.mention)) {
395: }
396: if (f >= 0) {
397: psi_pid = s->u.d.pdescr[l]->pmt_pid;
398: conticnt = &s->u.d.pdescr[l]->pmt_conticnt;
399: psi_data[0] = 0;
400: psi_size = make_pmtsection (s,s->u.d.pdescr[l],&psi_data[1]) + 1;
401: psi_done = 0;
402: pid = psi_pid;
403: scramble = 0;
404: k = psi_size;
405: break;
406: }
407: }
408: }
409: if (l < 0) {
410: s->data.ptr[c->index+PES_STREAM_ID] = s->stream_id;
411: conticnt = &s->conticnt;
412: pid = s->u.d.pid;
413: scramble = c->scramble;
414: k = c->length;
415: }
416: }
417: } else {
418: pid = s->u.d.pid;
419: scramble = c->scramble;
420: k = c->length;
421: }
422: }
1.2 oskar 423: d = output_pushdata (TS_PACKET_SIZE,c->msecpush + s->u.d.delta);
1.1 oskar 424: if (d == NULL) {
425: return (s);
426: }
427: adapt_ext_len = 1;
428: adapt_flags2 = 0;
429: adapt_flags1 = 0;
430: f = TS_PACKET_SIZE - TS_PACKET_HEADSIZE;
431: if ((psi_size <= 0)
432: && (s->u.d.discontinuity)) { /* o, not for contents, but PCR-disco ? */
433: s->u.d.discontinuity = FALSE;
434: adapt_flags1 |= TS_ADAPT_DISCONTI;
435: }
436: if (0) {
437: adapt_flags1 |= TS_ADAPT_RANDOMAC;
438: }
439: if (0) {
440: adapt_flags1 |= TS_ADAPT_PRIORITY;
441: }
442: if ((psi_size <= 0)
443: && (s->u.d.has_clockref)
444: && ((c->pcr.valid)
1.2 oskar 445: || (s->u.d.next_clockref - (c->msecpush + s->u.d.delta) <= 0))) {
1.1 oskar 446: adapt_flags1 |= TS_ADAPT_PCRFLAG;
447: f -= 6;
448: }
449: if ((psi_size <= 0)
450: && (c->opcr.valid)) {
451: adapt_flags1 |= TS_ADAPT_OPCRFLAG;
452: f -= 6;
453: }
454: if (0) {
455: adapt_flags1 |= TS_ADAPT_SPLICING;
456: f -= 1;
457: }
458: if (0) {
459: adapt_flags1 |= TS_ADAPT_TPRIVATE;
460: privdata = 0;
461: f -= (privdata + 1);
462: }
463: if (0) {
464: adapt_flags2 |= TS_ADAPT_LTWFLAG;
465: adapt_ext_len += 2;
466: }
467: if (0) {
468: adapt_flags2 |= TS_ADAPT_PIECEWRF;
469: adapt_ext_len += 3;
470: }
471: if (0) {
472: adapt_flags2 |= TS_ADAPT_SEAMLESS;
473: adapt_ext_len += 5;
474: }
475: if (adapt_flags2 != 0) {
476: adapt_flags1 |= TS_ADAPT_EXTENSIO;
477: f -= adapt_ext_len;
478: }
479: if (adapt_flags1 != 0) {
480: f -= 2;
481: }
482: if (k < f) {
483: l = k;
484: if (adapt_flags1 == 0) {
485: f -= 1;
486: if (f > l) {
487: f -= 1;
488: }
489: }
490: adapt_field_ctrl = TS_AFC_BOTH;
491: } else {
492: l = f;
493: if (f == 0) {
494: adapt_field_ctrl = TS_AFC_ADAPT;
495: } else if (adapt_flags1 == 0) {
496: adapt_field_ctrl = TS_AFC_PAYLD;
497: } else {
498: adapt_field_ctrl = TS_AFC_BOTH;
499: }
500: }
501: *d++ = TS_SYNC_BYTE;
502: warn (LSEC,"Splice unitstart",ETSC,0,1,unit_start);
503: warn (LSEC,"Splice PID",ETSC,0,2,pid);
504: *d++ = (0 << 7) /* transport_error_indicator */
505: | unit_start
506: | (0 << 5) /* transport_priority */
507: | (pid >> 8);
508: *d++ = pid;
509: *d++ = (scramble << 6)
510: | adapt_field_ctrl
511: | *conticnt;
512: warn (LSEC,"Splice continuity cnt",ETSC,0,3,*conticnt);
513: if (adapt_field_ctrl & TS_AFC_PAYLD) {
514: *conticnt = (*conticnt+1) & 0x0F;
515: }
516: if (adapt_field_ctrl & TS_AFC_ADAPT) {
517: if ((*d++ = (TS_PACKET_SIZE - TS_PACKET_FLAGS1) - l) != 0) {
518: *d++ = adapt_flags1;
519: if (adapt_flags1 & TS_ADAPT_PCRFLAG) {
520: clockref pcr;
1.2 oskar 521: msec2cref (&s->u.d.conv,c->msecpush + s->u.d.delta,&pcr);
1.1 oskar 522: *d++ = (pcr.base >> 25) | (pcr.ba33 << 7);
523: *d++ = pcr.base >> 17;
524: *d++ = pcr.base >> 9;
525: *d++ = pcr.base >> 1;
526: *d++ = (pcr.base << 7) | (pcr.ext >> 8) | 0x7E;
527: *d++ = pcr.ext;
528: s->u.d.next_clockref =
1.2 oskar 529: (c->msecpush + s->u.d.delta) + MAX_MSEC_PCRDIST;
1.1 oskar 530: c->pcr.valid = FALSE;
531: }
532: if (adapt_flags1 & TS_ADAPT_OPCRFLAG) {
533: *d++ = (c->opcr.base >> 25) | (c->opcr.ba33 << 7);
534: *d++ = c->opcr.base >> 17;
535: *d++ = c->opcr.base >> 9;
536: *d++ = c->opcr.base >> 1;
537: *d++ = (c->opcr.base << 7) | (c->opcr.ext >> 8) | 0x7E;
538: *d++ = c->opcr.ext;
539: c->opcr.valid = FALSE;
540: }
541: if (adapt_flags1 & TS_ADAPT_SPLICING) {
542: }
543: if (adapt_flags1 & TS_ADAPT_TPRIVATE) {
544: }
545: if (adapt_flags1 & TS_ADAPT_EXTENSIO) {
546: *d++ = adapt_ext_len;
547: *d++ = adapt_flags2 | 0x1F;
548: if (adapt_flags2 & TS_ADAPT_LTWFLAG) {
549: }
550: if (adapt_flags2 & TS_ADAPT_PIECEWRF) {
551: }
552: if (adapt_flags2 & TS_ADAPT_SEAMLESS) {
553: }
554: }
555: }
556: if (f > l) {
557: warn (LSEC,"Splice padding",ETSC,0,4,f-l);
558: memset (d,-1,f-l);
559: d += (f-l);
560: }
561: }
562: if (l > 0) {
563: if (psi_size > 0) {
564: memcpy (d,&psi_data[psi_done],l);
565: if (l < psi_size) {
566: warn (LSEC,"Splice PSI Data",ETSC,0,s->stream_id,l);
567: psi_done += l;
568: psi_size -= l;
569: unit_start = 0;
570: } else {
571: warn (LINF,"Splice PSI Done",ETSC,0,s->stream_id,l);
572: psi_done = psi_size = 0;
573: unit_start = TS_UNIT_START;
574: }
575: } else {
576: memcpy (d,&s->data.ptr[c->index],l);
577: if (l < c->length) {
578: warn (LSEC,"Splice Data",ETSC,0,s->stream_id,l);
579: c->length -= l;
580: s->data.out = (c->index += l);
581: unit_start = 0;
582: } else {
583: warn (LINF,"Splice Done",ETSC,0,s->stream_id,l);
584: list_incr (s->ctrl.out,s->ctrl,1);
585: if (list_empty (s->ctrl)) {
586: s->data.out = s->data.in;
587: } else {
588: s->data.out = s->ctrl.ptr[s->ctrl.out].index;
589: }
590: s = NULL;
591: unit_start = TS_UNIT_START;
592: }
593: }
594: }
595: return (s);
596: }
597:
LinuxTV legacy CVS <linuxtv.org/cvs>