Annotation of multiplexer/spliceps.c, revision 1.16
1.1 oskar 1: /*
2: * ISO 13818 stream multiplexer
3: * Copyright (C) 2001 Convergence Integrated Media GmbH Berlin
1.16 ! oskar 4: * Copyright (C) 2005 Oskar Schirmer (schirmer@scara.com)
1.13 oskar 5: *
6: * This program is free software; you can redistribute it and/or modify
7: * it under the terms of the GNU General Public License as published by
8: * the Free Software Foundation; either version 2 of the License, or
9: * (at your option) any later version.
10: *
11: * This program is distributed in the hope that it will be useful,
12: * but WITHOUT ANY WARRANTY; without even the implied warranty of
13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14: * GNU General Public License for more details.
15: *
16: * You should have received a copy of the GNU General Public License
17: * along with this program; if not, write to the Free Software
18: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1.1 oskar 19: */
20:
21: /*
22: * Module: Splice PS
23: * Purpose: Generate a program stream
24: *
25: * This module generates from the available input stream data (as
26: * seperated by the split functions) the complete output stream.
27: * It provides functions to handle programs for the resulting stream,
28: * as these are output format dependent (though multiple programs are
29: * obsolete for a program stream). Further, it accepts PSI data
30: * just in time, validating it not earlier than with the arrival of
31: * the corresponding payload at this stage.
32: */
33:
34: #include "global.h"
1.15 oskar 35: #include "crc32.h"
1.1 oskar 36: #include "error.h"
37: #include "input.h"
38: #include "output.h"
39: #include "descref.h"
40: #include "pes.h"
41: #include "ps.h"
42: #include "splice.h"
43: #include "spliceps.h"
44:
45: const boolean splice_multipleprograms = FALSE;
46:
47: static int psi_size;
48: static byte psi_data [MAX_PSI_SIZE + PS_SYSTHD_SIZE + PS_STRMAP_SIZE +
49: MAX_STRPERPRG * (PS_SYSTHD_STRLEN + PS_STRMAP_STRLEN)];
50:
51: static prog_descr prog;
52:
1.5 oskar 53: boolean splice_specific_init (void)
1.1 oskar 54: {
1.9 oskar 55: prog.program_number = 0;
1.1 oskar 56: prog.pmt_conticnt = 0;
57: prog.pmt_version = 0;
58: prog.changed = TRUE;
59: prog.streams = 0;
1.7 oskar 60: prog.stump = NULL;
1.9 oskar 61: clear_descrdescr (&prog.manudescr);
1.1 oskar 62: psi_size = 0;
63: return (TRUE);
64: }
65:
66: void splice_settransportstreamid (int tsid)
67: {
68: }
69:
1.6 oskar 70: void splice_setpsifrequency (t_msec freq)
1.1 oskar 71: {
72: psi_frequency_msec = freq;
73: psi_frequency_changed = TRUE;
74: }
75:
1.16 ! oskar 76: void splice_setnetworkpid (short pid)
! 77: {
! 78: }
! 79:
1.5 oskar 80: void splice_all_configuration (void)
81: {
1.9 oskar 82: if (configuration_must_print) {
1.5 oskar 83: fprintf (stderr, configuration_total, 1);
84: splice_one_configuration (&prog);
1.9 oskar 85: configuration_was_printed;
1.5 oskar 86: }
87: }
88:
1.7 oskar 89: void splice_addsirange (file_descr *f,
90: int lower,
91: int upper)
92: {
93: }
94:
95: void splice_createstump (int programnb,
96: short pid,
97: byte styp)
98: {
99: }
100:
101: stump_descr *splice_getstumps (int programnb,
102: short pid)
103: {
104: return (NULL);
105: }
106:
1.9 oskar 107: void splice_modifytargetdescriptor (int programnb,
108: short sid,
109: short pid,
110: int dtag,
111: int dlength,
112: byte *data)
113: {
114: splice_modifytargetdescrprog (&prog,0,sid,pid,dtag,dlength,data,NULL);
115: }
116:
1.3 oskar 117: prog_descr *splice_getprog (int programnb)
118: {
119: return (&prog);
120: }
121:
1.1 oskar 122: prog_descr *splice_openprog (int programnb)
123: {
1.9 oskar 124: /* prog.program_number = programnb; must stay zero */
125: /* configuration_changed = TRUE; */
1.1 oskar 126: warn (LIMP,"Open prog",EPSC,1,0,programnb);
127: return (&prog);
128: }
129:
130: void splice_closeprog (prog_descr *p)
131: {
132: stream_descr *s;
133: file_descr *f;
134: warn (LIMP,"Close prog",EPSC,2,0,prog.streams);
135: while (prog.streams > 0) {
136: s = prog.stream[0];
137: input_delprog (s,&prog);
138: splice_delstream (&prog,s);
139: if (s->u.d.progs == 0) {
140: f = s->fdescr;
141: input_closestream (s);
142: input_closefileifunused (f);
143: } else {
144: warn (LERR,"Close prog",EPSC,2,s->u.d.progs,s->stream_id);
145: }
146: }
1.5 oskar 147: configuration_changed = TRUE;
1.1 oskar 148: }
149:
150: int splice_addstream (prog_descr *p,
151: stream_descr *s,
152: boolean force_sid)
153: {
154: /* add stream to main program */
155: int sid = 0;
156: warn (LIMP,"Add stream",EPSC,3,force_sid,s->stream_id);
157: if (prog.streams < MAX_STRPERPRG) {
158: if (!force_sid) {
1.3 oskar 159: s->stream_id = splice_findfreestreamid (&prog,s->stream_id);
1.1 oskar 160: }
161: prog.stream[prog.streams++] = s;
162: prog.changed = TRUE;
163: s->u.d.pid = sid = s->stream_id;
1.5 oskar 164: configuration_changed = TRUE;
1.9 oskar 165: splice_modifycheckmatch (0,&prog,s,NULL);
1.1 oskar 166: }
167: return (sid);
168: }
169:
170: boolean splice_delstream (prog_descr *p,
171: stream_descr *s)
172: {
173: int i;
174: warn (LIMP,"Del stream",EPSC,4,0,s->u.d.pid);
175: i = p->streams;
176: while (--i >= 0) {
177: if (p->stream[i] == s) {
178: prog.stream[i] = prog.stream[--(prog.streams)];
179: prog.changed = TRUE;
180: s->u.d.pid = 0;
1.5 oskar 181: configuration_changed = TRUE;
1.1 oskar 182: return (TRUE);
183: }
184: }
185: warn (LERR,"Del lost stream",EPSC,4,1,p->streams);
186: return (FALSE);
187: }
188:
1.5 oskar 189: void process_finish (void)
190: {
191: byte *d;
192: warn (LIMP,"Finish",EPSC,5,0,0);
1.11 oskar 193: d = output_pushdata (PES_HDCODE_SIZE, FALSE, 0);
1.5 oskar 194: if (d != NULL) {
195: *d++ = 0x00;
196: *d++ = 0x00;
197: *d++ = 0x01;
198: *d++ = PS_CODE_END;
199: warn (LIMP,"Finish Done",EPSC,5,1,0);
200: }
201: }
202:
1.1 oskar 203: static int make_systemheader (stream_descr *s,
204: byte *dest)
205: {
1.11 oskar 206: int i, pid;
1.3 oskar 207: byte v, a;
1.1 oskar 208: byte *d;
209: d = dest;
210: *d++ = 0x00;
211: *d++ = 0x00;
212: *d++ = 0x01;
213: *d++ = PS_CODE_SYST_HDR;
214: d += 2;
215: if (s->fdescr->content == ct_program) {
216: i = s->fdescr->u.ps.sh.ratebound;
217: } else {
218: i = 4500000 / 400; /* wrong for sure */
219: }
220: *d++ = 0x80
221: | (i >> 15);
222: *d++ = (i >> 7);
223: *d++ = (i << 1)
224: | 0x01;
225: d += 2;
226: *d++ = 0 /* packet_rate_restriction_flag */
227: | 0x7F;
228: a = v = 0;
229: i = prog.streams;
230: while (--i >= 0) {
1.11 oskar 231: pid = prog.stream[i]->u.d.pid;
232: if ((pid >= PES_CODE_VIDEO)
233: && (pid < (PES_CODE_VIDEO + PES_NUMB_VIDEO))) {
1.1 oskar 234: if (v == 0) {
235: *d++ = PES_JOKER_AUDIO;
236: *d++ = 0xC0
237: | (0 << 5) /* buffer bound scale */
238: | ((4096/128) >> 8);
239: *d++ = (4096/128) & 0xFF; /* fixme! propagate from input, or derive */
240: }
241: v += 1;
242: } else {
1.11 oskar 243: if ((pid >= PES_CODE_AUDIO)
244: && (pid < (PES_CODE_AUDIO + PES_NUMB_AUDIO))) {
1.1 oskar 245: if (a == 0) {
246: *d++ = PES_JOKER_VIDEO;
247: *d++ = 0xC0
248: | (0 << 5) /* buffer bound scale */
249: | ((237568/128) >> 8);
250: *d++ = (237568/128) & 0xFF;
251: }
252: a += 1;
253: } else {
1.11 oskar 254: *d++ = pid;
1.1 oskar 255: *d++ = 0xC0
256: | (0 << 5) /* buffer bound scale */
257: | ((2048/128) >> 8);
258: *d++ = (2048/128) & 0xFF;
259: }
260: }
261: }
262: dest[PS_SYSTHD_AUDBND] = (a << 2)
263: | 0 /* fixed_flag */
264: | 0; /* CSPS_flag */
265: dest[PS_SYSTHD_VIDBND] = 0 /* system_audio_lock_flag */
266: | 0 /* system_video_lock_flag */
267: | 0x20
268: | v;
269: i = d - dest - PES_HEADER_SIZE;
270: dest[PES_PACKET_LENGTH] = (i >> 8);
271: dest[PES_PACKET_LENGTH+1] = i;
272: return (i + PES_HEADER_SIZE);
273: }
274:
275: static int make_streammap (stream_descr *s,
276: byte *dest)
277: {
278: int i, l;
279: byte *d;
1.11 oskar 280: stream_descr *t;
1.1 oskar 281: d = dest;
282: *d++ = 0x00;
283: *d++ = 0x00;
284: *d++ = 0x01;
285: *d++ = PES_CODE_STR_MAP;
286: d += 2;
287: *d++ = (1 << 7) /* current applicable */
288: | 0x60
289: | prog.pmt_version;
290: *d++ = 0xFE
291: | 0x01;
292: d += 2;
1.8 oskar 293: i = NUMBER_DESCR;
1.11 oskar 294: while (--i >= 0) {
1.9 oskar 295: byte *y;
296: y = prog.manudescr.refx[i];
297: if ((y == NULL)
298: && (s->u.d.mapstream != NULL)) {
299: y = s->u.d.mapstream->autodescr->refx[i];
300: }
301: if (y != NULL) {
302: int yl = y[1];
303: if (yl != 0) {
304: yl += 2;
305: memcpy (d,y,yl);
306: d += yl;
1.1 oskar 307: }
308: }
309: }
310: l = d - dest - PS_STRMAP_PSID;
311: dest[PS_STRMAP_PSIL] = (l >> 8);
312: dest[PS_STRMAP_PSIL+1] = l;
313: d += 2;
314: i = prog.streams;
315: while (--i >= 0) {
1.11 oskar 316: t = prog.stream[i];
317: if (t->u.d.mention) {
1.1 oskar 318: int x;
319: byte *e;
1.11 oskar 320: *d++ = t->stream_type;
321: *d++ = t->u.d.pid;
1.1 oskar 322: d += 2;
323: e = d;
1.8 oskar 324: x = NUMBER_DESCR;
1.11 oskar 325: while (--x >= 0) {
1.1 oskar 326: byte *y;
1.11 oskar 327: y = t->manudescr->refx[x];
1.7 oskar 328: if (y == NULL) {
1.11 oskar 329: y = t->autodescr->refx[x];
1.7 oskar 330: }
1.1 oskar 331: if (y != NULL) {
1.9 oskar 332: int yl = y[1];
333: if (yl != 0) {
334: yl += 2;
335: memcpy (d,y,yl);
336: d += yl;
337: }
1.1 oskar 338: }
339: }
340: x = d - e;
341: *--e = x;
342: *--e = (x >> 8);
343: }
344: }
345: i = d - dest - l - (PS_STRMAP_SIZE - CRC_SIZE);
346: dest[PS_STRMAP_PSID + l] = (i >> 8);
347: dest[PS_STRMAP_PSID+l+1] = i;
348: i = d + CRC_SIZE - dest - PES_HEADER_SIZE;
349: dest[PES_PACKET_LENGTH] = (i >> 8);
350: dest[PES_PACKET_LENGTH+1] = i;
351: crc32_calc (dest,i + PES_HEADER_SIZE - CRC_SIZE,d);
352: return (i + PES_HEADER_SIZE);
353: }
354:
355: stream_descr *process_something (stream_descr *s)
356: {
357: byte *d;
358: ctrl_buffer *c;
359: clockref pcr;
360: int i;
1.3 oskar 361: t_msec now;
1.1 oskar 362: warn (LDEB,"Splice PS",EPSC,0,0,s->ctrl.out);
1.4 oskar 363: if (s->streamdata == sd_map) {
1.1 oskar 364: validate_mapref (s);
365: return (NULL);
366: }
367: c = &s->ctrl.ptr[s->ctrl.out];
368: now = msec_now ();
369: if ((psi_frequency_changed)
370: || ((psi_frequency_msec > 0)
371: && ((next_psi_periodic - now) <= 0))) {
1.10 oskar 372: prog.unchanged = TRUE;
1.1 oskar 373: psi_frequency_changed = FALSE;
374: next_psi_periodic = now + psi_frequency_msec;
375: }
1.10 oskar 376: if (prog.unchanged || prog.changed) {
377: if (prog.changed) {
378: prog.pmt_version = (prog.pmt_version+1) & 0x1F;
379: }
1.1 oskar 380: psi_size = make_systemheader (s,&psi_data[0]);
381: psi_size += make_streammap (s,&psi_data[psi_size]);
382: prog.changed = FALSE;
1.10 oskar 383: prog.unchanged = FALSE;
1.1 oskar 384: }
1.11 oskar 385: i = c->msecpush + s->u.d.delta;
386: d = output_pushdata (PS_PACKHD_SIZE + psi_size + c->length, TRUE, i);
1.1 oskar 387: if (d == NULL) {
388: return (s);
389: }
390: *d++ = 0x00;
391: *d++ = 0x00;
392: *d++ = 0x01;
393: *d++ = PS_CODE_PACK_HDR;
1.11 oskar 394: msec2cref (&s->u.d.conv, i, &pcr);
1.1 oskar 395: *d++ = 0x40
396: | (((pcr.ba33 << 5) | (pcr.base >> 27)) & 0x38)
397: | 0x04
398: | ((pcr.base >> 28) & 0x03);
399: *d++ = (pcr.base >> 20);
400: *d++ = ((pcr.base >> 12) & 0xF8)
401: | 0x04
402: | ((pcr.base >> 13) & 0x03);
403: *d++ = (pcr.base >> 5);
404: *d++ = ((pcr.base << 3) & 0xF8)
405: | 0x04
406: | ((pcr.ext >> 7) & 0x03);
407: *d++ = (pcr.ext << 1)
408: | 0x01;
409: if (s->fdescr->content == ct_program) {
410: i = s->fdescr->u.ps.ph.muxrate; /* wrong, because maybe old */
411: } else {
1.2 oskar 412: i = 4500000 / 400; /* xxx wrong for sure */
1.1 oskar 413: }
414: *d++ = (i >> 14);
415: *d++ = (i >> 6);
416: *d++ = (i << 2)
417: | 0x03;
418: *d++ = 0xF8
419: | 0; /* stuffing length */
420: if (psi_size > 0) {
421: memcpy (d,&psi_data[0],psi_size);
422: d += psi_size;
423: psi_size = 0;
424: }
425: memcpy (d,&s->data.ptr[c->index],c->length);
426: d[PES_STREAM_ID] = s->stream_id;
427: warn (LINF,"Splice Done",EPSC,0,s->stream_id,c->length);
428: list_incr (s->ctrl.out,s->ctrl,1);
429: if (list_empty (s->ctrl)) {
430: s->data.out = s->data.in;
431: } else {
432: s->data.out = s->ctrl.ptr[s->ctrl.out].index;
433: }
434: return (NULL);
435: }
436:
LinuxTV legacy CVS <linuxtv.org/cvs>