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