Annotation of multiplexer/splicets.c, revision 1.1
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:
! 54: static int next_psi_periodic;
! 55: static int psi_frequency_msec;
! 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 prog_descr *openprog (int programnb)
! 87: {
! 88: int i;
! 89: i = progs;
! 90: while (--i >= 0) {
! 91: if (prog[i]->program_number == programnb) {
! 92: return (prog[i]);
! 93: }
! 94: }
! 95: return (NULL);
! 96: }
! 97:
! 98: static int findapid (stream_descr *s)
! 99: {
! 100: boolean ok = TRUE;
! 101: do {
! 102: if ((nextpid < TS_PID_LOWEST) || (nextpid >= TS_PID_HIGHEST)) {
! 103: if (!ok) {
! 104: warn (LERR,"No PID found",ETSC,2,1,0);
! 105: return (0);
! 106: }
! 107: ok = FALSE;
! 108: nextpid = TS_PID_LOWEST;
! 109: } else {
! 110: nextpid += 1;
! 111: }
! 112: } while (outs[nextpid] != NULL);
! 113: outs[nextpid] = s;
! 114: warn (LDEB,"Next PID",ETSC,2,2,nextpid);
! 115: return (nextpid);
! 116: }
! 117:
! 118: prog_descr *splice_openprog (int programnb)
! 119: {
! 120: prog_descr *p;
! 121: int pid;
! 122: warn (LIMP,"Open prog",ETSC,1,0,programnb);
! 123: p = openprog (programnb);
! 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->map_sequence = -1;
! 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: stream_descr *s;
! 155: file_descr *f;
! 156: warn (LIMP,"Close prog",ETSC,3,0,p->program_number);
! 157: while (p->streams > 0) {
! 158: s = p->stream[0];
! 159: input_delprog (s,p);
! 160: splice_delstream (p,s);
! 161: if (s->u.d.progs == 0) {
! 162: f = s->fdescr;
! 163: input_closestream (s);
! 164: input_closefileifunused (f);
! 165: }
! 166: }
! 167: n = -1;
! 168: if (p->pmt_pid >= 0) {
! 169: i = progs;
! 170: while (--i >= 0) {
! 171: if (prog[i]->pmt_pid == p->pmt_pid) {
! 172: n += 1;
! 173: }
! 174: }
! 175: }
! 176: i = progs;
! 177: while (--i >= 0) {
! 178: if (prog[i] == p) {
! 179: prog[i] = prog[--progs];
! 180: if (n == 0) {
! 181: outs[p->pmt_pid] = NULL;
! 182: }
! 183: free (p);
! 184: changed_pat = TRUE;
! 185: return;
! 186: }
! 187: }
! 188: warn (LERR,"Close lost prog",ETSC,3,1,progs);
! 189: }
! 190:
! 191: boolean splice_emptyprog (prog_descr *p)
! 192: {
! 193: return (p->streams == 0);
! 194: }
! 195:
! 196: int splice_addstream (prog_descr *p,
! 197: stream_descr *s,
! 198: boolean force_sid)
! 199: {
! 200: int pid = 0;
! 201: warn (LIMP,"Add stream",ETSC,4,force_sid,s->stream_id);
! 202: if (p->streams < MAX_STRPERPRG) {
! 203: if ((pid = findapid (s)) > 0) {
! 204: if (!force_sid) {
! 205: s->stream_id = input_findfreestreamid (p,s->stream_id);
! 206: }
! 207: p->stream[p->streams++] = s;
! 208: p->changed = TRUE;
! 209: s->u.d.pid = pid;
! 210: }
! 211: }
! 212: return (pid);
! 213: }
! 214:
! 215: boolean splice_delstream (prog_descr *p,
! 216: stream_descr *s)
! 217: {
! 218: int i;
! 219: warn (LIMP,"Del stream",ETSC,5,0,s->u.d.pid);
! 220: i = p->streams;
! 221: while (--i >= 0) {
! 222: if (p->stream[i] == s) {
! 223: outs[s->u.d.pid] = NULL;
! 224: p->stream[i] = p->stream[--(p->streams)];
! 225: p->changed = TRUE;
! 226: if (p->pcr_pid == s->u.d.pid) {
! 227: p->pcr_pid = -1;
! 228: }
! 229: s->u.d.pid = 0;
! 230: return (TRUE);
! 231: }
! 232: }
! 233: warn (LERR,"Del lost stream",ETSC,5,1,p->streams);
! 234: return (FALSE);
! 235: }
! 236:
! 237: static int make_patsection (int section,
! 238: byte *dest)
! 239: {
! 240: int i;
! 241: byte *d;
! 242: d = dest;
! 243: *d++ = TS_TABLEID_PAT;
! 244: d += 2;
! 245: *d++ = transportstreamid >> 8;
! 246: *d++ = (byte)transportstreamid;
! 247: *d++ = 0xC0 | 0x01 | (nextpat_version << 1);
! 248: *d++ = section;
! 249: *d++ = last_patsection;
! 250: i = progs;
! 251: while (--i >= 0) {
! 252: if (prog[i]->pat_section == section) {
! 253: int x;
! 254: x = prog[i]->program_number;
! 255: *d++ = (x >> 8);
! 256: *d++ = x;
! 257: x = prog[i]->pmt_pid;
! 258: *d++ = 0xE0 | (x >> 8);
! 259: *d++ = x;
! 260: }
! 261: }
! 262: i = d + CRC_SIZE - dest - TS_TRANSPORTID;
! 263: dest[TS_SECTIONLEN] = 0xB0 | (i >> 8);
! 264: dest[TS_SECTIONLEN+1] = i;
! 265: crc32_calc (dest,i + TS_TRANSPORTID - CRC_SIZE,d);
! 266: return (i + TS_TRANSPORTID);
! 267: }
! 268:
! 269: static int make_pmtsection (stream_descr *s,
! 270: prog_descr *p,
! 271: byte *dest)
! 272: {
! 273: int i;
! 274: byte *d;
! 275: p->changed = FALSE;
! 276: d = dest;
! 277: *d++ = TS_TABLEID_PMT;
! 278: d += 2;
! 279: i = p->program_number;
! 280: *d++ = (i >> 8);
! 281: *d++ = i;
! 282: *d++ = 0xC0 | 0x01 | (p->pmt_version << 1);
! 283: p->pmt_version = (p->pmt_version+1) & 0x1F;
! 284: *d++ = 0;
! 285: *d++ = 0;
! 286: if (p->pcr_pid < 0) {
! 287: stream_descr *pcrs;
! 288: pcrs = input_findpcrstream (p);
! 289: if (pcrs == NULL) {
! 290: pcrs = s;
! 291: }
! 292: pcrs->u.d.has_clockref = TRUE;
! 293: pcrs->u.d.next_clockref = msec_now () - MAX_MSEC_PCRDIST;
! 294: p->pcr_pid = pcrs->u.d.pid;
! 295: }
! 296: i = p->pcr_pid;
! 297: *d++ = 0xE0 | (i >> 8);
! 298: *d++ = i;
! 299: d += 2;
! 300: i = NUMBER_ELEMD;
! 301: while (--i > 0) {
! 302: if (s->fdescr->content == ct_program) {
! 303: byte *y;
! 304: y = s->fdescr->u.ps.stream[0]->elemdvld[i]; /* this one ? why ? */
! 305: if (y != NULL) {
! 306: memcpy (d,y,y[1]+2);
! 307: d += y[1]+2;
! 308: }
! 309: }
! 310: }
! 311: i = d - dest - (TS_PMT_PILEN+2);
! 312: dest[TS_PMT_PILEN] = 0xF0 | (i >> 8);
! 313: dest[TS_PMT_PILEN+1] = i;
! 314: i = p->streams;
! 315: while (--i >= 0) {
! 316: if (p->stream[i]->u.d.mention) {
! 317: int x;
! 318: byte *e;
! 319: *d++ = p->stream[i]->stream_type;
! 320: x = p->stream[i]->u.d.pid;
! 321: *d++ = 0xE0 | (x >> 8);
! 322: *d++ = x;
! 323: d += 2;
! 324: e = d;
! 325: x = NUMBER_ELEMD;
! 326: while (--x > 0) {
! 327: byte *y;
! 328: y = p->stream[i]->elemdvld[x];
! 329: if (y != NULL) {
! 330: memcpy (d,y,y[1]+2);
! 331: d += y[1]+2;
! 332: }
! 333: }
! 334: x = d - e;
! 335: *--e = x;
! 336: *--e = 0xF0 | (x >> 8);
! 337: }
! 338: }
! 339: i = d + CRC_SIZE - dest - TS_TRANSPORTID;
! 340: dest[TS_SECTIONLEN] = 0xB0 | (i >> 8);
! 341: dest[TS_SECTIONLEN+1] = i;
! 342: crc32_calc (dest,i + TS_TRANSPORTID - CRC_SIZE,d);
! 343: return (i + TS_TRANSPORTID);
! 344: }
! 345:
! 346: void process_finish (void)
! 347: {
! 348: warn (LIMP,"Finish",ETSC,6,0,0);
! 349: }
! 350:
! 351: stream_descr *process_something (stream_descr *s)
! 352: {
! 353: byte *d;
! 354: int pid;
! 355: byte scramble;
! 356: ctrl_buffer *c;
! 357: int l, f, k;
! 358: int privdata;
! 359: int adapt_ext_len;
! 360: int now;
! 361: byte adapt_field_ctrl;
! 362: byte adapt_flags1, adapt_flags2;
! 363: warn (LDEB,"Splice TS",ETSC,0,0,s->ctrl.out);
! 364: if (s->isamap) {
! 365: validate_mapref (s);
! 366: return (NULL);
! 367: }
! 368: c = &s->ctrl.ptr[s->ctrl.out];
! 369: if (psi_size > 0) {
! 370: pid = psi_pid;
! 371: scramble = 0;
! 372: k = psi_size;
! 373: } else {
! 374: if (unit_start != 0) {
! 375: now = msec_now ();
! 376: if ((psi_frequency_changed)
! 377: || ((psi_frequency_msec > 0)
! 378: && ((next_psi_periodic - now) <= 0))) {
! 379: changed_pat = TRUE;
! 380: l = progs;
! 381: while (--l >= 0) {
! 382: prog[l]->changed = TRUE;
! 383: }
! 384: psi_frequency_changed = FALSE;
! 385: next_psi_periodic = now + psi_frequency_msec;
! 386: }
! 387: if (changed_pat) {
! 388: psi_pid = TS_PID_PAT;
! 389: conticnt = &pat_conticnt;
! 390: psi_data[0] = 0;
! 391: psi_size = make_patsection (pat_section,&psi_data[1]) + 1;
! 392: if (pat_section >= last_patsection) {
! 393: changed_pat = FALSE;
! 394: nextpat_version = (nextpat_version+1) & 0x1F;
! 395: pat_section = 0;
! 396: } else {
! 397: pat_section += 1;
! 398: }
! 399: psi_done = 0;
! 400: pid = psi_pid;
! 401: scramble = 0;
! 402: k = psi_size;
! 403: } else {
! 404: l = s->u.d.progs;
! 405: while (--l >= 0) {
! 406: if (s->u.d.pdescr[l]->changed) {
! 407: f = s->u.d.pdescr[l]->streams;
! 408: while ((--f >= 0)
! 409: && (!s->u.d.pdescr[l]->stream[f]->u.d.mention)) {
! 410: }
! 411: if (f >= 0) {
! 412: psi_pid = s->u.d.pdescr[l]->pmt_pid;
! 413: conticnt = &s->u.d.pdescr[l]->pmt_conticnt;
! 414: psi_data[0] = 0;
! 415: psi_size = make_pmtsection (s,s->u.d.pdescr[l],&psi_data[1]) + 1;
! 416: psi_done = 0;
! 417: pid = psi_pid;
! 418: scramble = 0;
! 419: k = psi_size;
! 420: break;
! 421: }
! 422: }
! 423: }
! 424: if (l < 0) {
! 425: s->data.ptr[c->index+PES_STREAM_ID] = s->stream_id;
! 426: conticnt = &s->conticnt;
! 427: pid = s->u.d.pid;
! 428: scramble = c->scramble;
! 429: k = c->length;
! 430: }
! 431: }
! 432: } else {
! 433: pid = s->u.d.pid;
! 434: scramble = c->scramble;
! 435: k = c->length;
! 436: }
! 437: }
! 438: d = output_pushdata (TS_PACKET_SIZE,c->time.push + s->u.d.delta);
! 439: if (d == NULL) {
! 440: return (s);
! 441: }
! 442: adapt_ext_len = 1;
! 443: adapt_flags2 = 0;
! 444: adapt_flags1 = 0;
! 445: f = TS_PACKET_SIZE - TS_PACKET_HEADSIZE;
! 446: if ((psi_size <= 0)
! 447: && (s->u.d.discontinuity)) { /* o, not for contents, but PCR-disco ? */
! 448: s->u.d.discontinuity = FALSE;
! 449: adapt_flags1 |= TS_ADAPT_DISCONTI;
! 450: }
! 451: if (0) {
! 452: adapt_flags1 |= TS_ADAPT_RANDOMAC;
! 453: }
! 454: if (0) {
! 455: adapt_flags1 |= TS_ADAPT_PRIORITY;
! 456: }
! 457: if ((psi_size <= 0)
! 458: && (s->u.d.has_clockref)
! 459: && ((c->pcr.valid)
! 460: || (s->u.d.next_clockref - (c->time.push + s->u.d.delta) <= 0))) {
! 461: /*
! 462: fprintf (stderr,"n=%10d, p=%10d, (now %10d)\n",
! 463: s->u.d.next_clockref,
! 464: c->time.push + s->delta,
! 465: msec_now ());
! 466: */
! 467: adapt_flags1 |= TS_ADAPT_PCRFLAG;
! 468: f -= 6;
! 469: }
! 470: if ((psi_size <= 0)
! 471: && (c->opcr.valid)) {
! 472: adapt_flags1 |= TS_ADAPT_OPCRFLAG;
! 473: f -= 6;
! 474: }
! 475: if (0) {
! 476: adapt_flags1 |= TS_ADAPT_SPLICING;
! 477: f -= 1;
! 478: }
! 479: if (0) {
! 480: adapt_flags1 |= TS_ADAPT_TPRIVATE;
! 481: privdata = 0;
! 482: f -= (privdata + 1);
! 483: }
! 484: if (0) {
! 485: adapt_flags2 |= TS_ADAPT_LTWFLAG;
! 486: adapt_ext_len += 2;
! 487: }
! 488: if (0) {
! 489: adapt_flags2 |= TS_ADAPT_PIECEWRF;
! 490: adapt_ext_len += 3;
! 491: }
! 492: if (0) {
! 493: adapt_flags2 |= TS_ADAPT_SEAMLESS;
! 494: adapt_ext_len += 5;
! 495: }
! 496: if (adapt_flags2 != 0) {
! 497: adapt_flags1 |= TS_ADAPT_EXTENSIO;
! 498: f -= adapt_ext_len;
! 499: }
! 500: if (adapt_flags1 != 0) {
! 501: f -= 2;
! 502: }
! 503: if (k < f) {
! 504: l = k;
! 505: if (adapt_flags1 == 0) {
! 506: f -= 1;
! 507: if (f > l) {
! 508: f -= 1;
! 509: }
! 510: }
! 511: adapt_field_ctrl = TS_AFC_BOTH;
! 512: } else {
! 513: l = f;
! 514: if (f == 0) {
! 515: adapt_field_ctrl = TS_AFC_ADAPT;
! 516: } else if (adapt_flags1 == 0) {
! 517: adapt_field_ctrl = TS_AFC_PAYLD;
! 518: } else {
! 519: adapt_field_ctrl = TS_AFC_BOTH;
! 520: }
! 521: }
! 522: *d++ = TS_SYNC_BYTE;
! 523: warn (LSEC,"Splice unitstart",ETSC,0,1,unit_start);
! 524: warn (LSEC,"Splice PID",ETSC,0,2,pid);
! 525: *d++ = (0 << 7) /* transport_error_indicator */
! 526: | unit_start
! 527: | (0 << 5) /* transport_priority */
! 528: | (pid >> 8);
! 529: *d++ = pid;
! 530: *d++ = (scramble << 6)
! 531: | adapt_field_ctrl
! 532: | *conticnt;
! 533: warn (LSEC,"Splice continuity cnt",ETSC,0,3,*conticnt);
! 534: if (adapt_field_ctrl & TS_AFC_PAYLD) {
! 535: *conticnt = (*conticnt+1) & 0x0F;
! 536: }
! 537: if (adapt_field_ctrl & TS_AFC_ADAPT) {
! 538: if ((*d++ = (TS_PACKET_SIZE - TS_PACKET_FLAGS1) - l) != 0) {
! 539: *d++ = adapt_flags1;
! 540: if (adapt_flags1 & TS_ADAPT_PCRFLAG) {
! 541: clockref pcr;
! 542: msec2clockref (c->time.push + s->u.d.delta,pcr);
! 543: *d++ = (pcr.base >> 25) | (pcr.ba33 << 7);
! 544: *d++ = pcr.base >> 17;
! 545: *d++ = pcr.base >> 9;
! 546: *d++ = pcr.base >> 1;
! 547: *d++ = (pcr.base << 7) | (pcr.ext >> 8) | 0x7E;
! 548: *d++ = pcr.ext;
! 549: s->u.d.next_clockref =
! 550: (c->time.push + s->u.d.delta) + MAX_MSEC_PCRDIST * 8/10;
! 551: c->pcr.valid = FALSE;
! 552: }
! 553: if (adapt_flags1 & TS_ADAPT_OPCRFLAG) {
! 554: *d++ = (c->opcr.base >> 25) | (c->opcr.ba33 << 7);
! 555: *d++ = c->opcr.base >> 17;
! 556: *d++ = c->opcr.base >> 9;
! 557: *d++ = c->opcr.base >> 1;
! 558: *d++ = (c->opcr.base << 7) | (c->opcr.ext >> 8) | 0x7E;
! 559: *d++ = c->opcr.ext;
! 560: c->opcr.valid = FALSE;
! 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;
! 569: if (adapt_flags2 & TS_ADAPT_LTWFLAG) {
! 570: }
! 571: if (adapt_flags2 & TS_ADAPT_PIECEWRF) {
! 572: }
! 573: if (adapt_flags2 & TS_ADAPT_SEAMLESS) {
! 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>