Annotation of multiplexer/splitps.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: Split PS
! 9: * Purpose: Split a program stream.
! 10: *
! 11: * This module examines a program stream and copies the packets to
! 12: * the input stream buffers. PSI data is extracted, descriptors are
! 13: * copied to the mapstream (stream 0).
! 14: */
! 15:
! 16: #include "global.h"
! 17: #include "error.h"
! 18: #include "pes.h"
! 19: #include "ps.h"
! 20: #include "input.h"
! 21: #include "descref.h"
! 22: #include "splitpes.h"
! 23: #include "splitps.h"
! 24:
! 25: static int ps_program_end_code (file_descr *f)
! 26: {
! 27: warn (LIMP,"Program End Code",EPST,3,0,0);
! 28: /* close file, do ... */
! 29: return (PES_HDCODE_SIZE);
! 30: }
! 31:
! 32: static int ps_pack_header (file_descr *f,
! 33: int l)
! 34: {
! 35: int i, s;
! 36: long x;
! 37: byte a, b;
! 38: clockref oldscr; /* used for correcting bad DVB scr values */
! 39: if (l < PS_PACKHD_SIZE) {
! 40: warn (LDEB,"Pack header (incomplete)",EPST,2,1,l);
! 41: return (0);
! 42: }
! 43: i = f->data.out;
! 44: list_incr (i,f->data,PS_PACKHD_STUFLN);
! 45: s = (f->data.ptr[i] & 0x07) + PS_PACKHD_SIZE;
! 46: if (l < s) {
! 47: warn (LDEB,"Pack header (incomplete)",EPST,2,2,l);
! 48: return (0);
! 49: }
! 50: oldscr = f->u.ps.ph.scr;
! 51: warn (LINF,"Pack header",EPST,2,0,s);
! 52: i = f->data.out;
! 53: list_incr (i,f->data,PS_PACKHD_SCR);
! 54: a = f->data.ptr[i];
! 55: marker_check (a,0x44,0xC4);
! 56: f->u.ps.ph.scr.ba33 = (a >> 5) & 1;
! 57: x = ((a & 0x18) | ((a & 0x03) << 1)) << 7;
! 58: list_incr (i,f->data,1);
! 59: x = (x | f->data.ptr[i]) << 8;
! 60: list_incr (i,f->data,1);
! 61: a = f->data.ptr[i];
! 62: marker_bit (a,2);
! 63: x = (x | ((a & 0xF8) | ((a & 0x03) << 1))) << 7;
! 64: list_incr (i,f->data,1);
! 65: x = (x | f->data.ptr[i]);
! 66: list_incr (i,f->data,1);
! 67: a = f->data.ptr[i];
! 68: marker_bit (a,2);
! 69: f->u.ps.ph.scr.base = (x << 5) | (a >> 3);
! 70: warn (LSEC,"SCR base",EPST,2,3,f->u.ps.ph.scr.base);
! 71: if (accept_weird_scr
! 72: && ((oldscr.base - (90*40+1)) == f->u.ps.ph.scr.base)) {
! 73: /* the DVB card produces weird scr-s, every second scr is less than
! 74: previous one, indicating an odd value decrease of 40ms. weird! */
! 75: f->u.ps.ph.scr.base = oldscr.base + (90*40);
! 76: }
! 77: list_incr (i,f->data,1);
! 78: b = f->data.ptr[i];
! 79: marker_bit (b,0);
! 80: f->u.ps.ph.scr.ext = ((a & 0x03) << 7) | (b >> 1);
! 81: warn (LSEC,"SCR ext",EPST,2,4,f->u.ps.ph.scr.ext);
! 82: f->u.ps.time.read = clockref2msec (f->u.ps.ph.scr);
! 83: warn (LDEB,"(time read)",EPST,2,5,f->u.ps.time.read);
! 84: list_incr (i,f->data,1);
! 85: x = f->data.ptr[i] << 8;
! 86: list_incr (i,f->data,1);
! 87: x = (x | f->data.ptr[i]) << 6;
! 88: list_incr (i,f->data,1);
! 89: a = f->data.ptr[i];
! 90: marker_check (a,0x03,0x03);
! 91: f->u.ps.ph.muxrate = x | (a >> 2);
! 92: warn (LSEC,"muxrate",EPST,2,6,f->u.ps.ph.muxrate);
! 93: return (s);
! 94: }
! 95:
! 96: static boolean ps_system_header (file_descr *f,
! 97: int size)
! 98: {
! 99: int i;
! 100: byte a, sid;
! 101: long x;
! 102: boolean bbs;
! 103: int bsb;
! 104: warn (LINF,"System header",EPST,1,0,size);
! 105: if (size < PS_SYSTHD_STREAM) {
! 106: warn (LWAR,"System header too short",EPST,1,1,size);
! 107: return (FALSE);
! 108: }
! 109: i = f->data.out;
! 110: list_incr (i,f->data,PES_HEADER_SIZE);
! 111: a = f->data.ptr[i];
! 112: marker_bit (a,7);
! 113: x = (a & 0x7F) << 8;
! 114: list_incr (i,f->data,1);
! 115: x = (x | f->data.ptr[i]) << 7;
! 116: list_incr (i,f->data,1);
! 117: a = f->data.ptr[i];
! 118: marker_bit (a,0);
! 119: f->u.ps.sh.ratebound = x | (a >> 1);
! 120: warn (LSEC,"rate_bound",EPST,1,5,f->u.ps.sh.ratebound);
! 121: list_incr (i,f->data,1);
! 122: a = f->data.ptr[i];
! 123: f->u.ps.sh.csps_flag = a & 0x01;
! 124: warn (LSEC,"csps_flag",EPST,1,6,f->u.ps.sh.csps_flag);
! 125: f->u.ps.sh.fixed_flag = (a >>= 1) & 0x01;
! 126: warn (LSEC,"fixed_flag",EPST,1,7,f->u.ps.sh.fixed_flag);
! 127: f->u.ps.sh.audiobound = a >> 1;
! 128: warn (LSEC,"audiobound",EPST,1,8,f->u.ps.sh.audiobound);
! 129: list_incr (i,f->data,1);
! 130: a = f->data.ptr[i];
! 131: marker_bit (a,5);
! 132: f->u.ps.sh.videobound = a & 0x1F;
! 133: warn (LSEC,"videobound",EPST,1,9,f->u.ps.sh.videobound);
! 134: f->u.ps.sh.system_video_lock_flag = (a >>= 6) & 0x01;
! 135: warn (LSEC,
! 136: "system_video_lock_flag",EPST,1,10,f->u.ps.sh.system_video_lock_flag);
! 137: f->u.ps.sh.system_audio_lock_flag = a >> 1;
! 138: warn (LSEC,
! 139: "system_audio_lock_flag",EPST,1,11,f->u.ps.sh.system_audio_lock_flag);
! 140: list_incr (i,f->data,1);
! 141: f->u.ps.sh.packet_rate_restriction_flag = f->data.ptr[i] >> 7;
! 142: warn (LSEC,"packet_rate_restriction_flag",
! 143: EPST,1,12,f->u.ps.sh.packet_rate_restriction_flag);
! 144: memset (f->u.ps.sh.buffer_bound,0,sizeof(f->u.ps.sh.buffer_bound));
! 145: size -= PS_SYSTHD_STREAM;
! 146: while ((size -= PS_SYSTHD_STRLEN) >= 0) {
! 147: list_incr (i,f->data,1);
! 148: a = f->data.ptr[i];
! 149: if (a & 0x80) {
! 150: sid = a;
! 151: warn (LSEC,"stream_id",EPST,1,13,sid);
! 152: list_incr (i,f->data,1);
! 153: a = f->data.ptr[i];
! 154: if (marker_check (a,0xC0,0xC0)) {
! 155: warn (LWAR,"Missing 11",EPST,1,3,a);
! 156: return (FALSE);
! 157: }
! 158: bbs = (a >> 5) & 0x01;
! 159: warn (LSEC,"buffer bound scale",EPST,1,14,bbs);
! 160: list_incr (i,f->data,1);
! 161: bsb = ((a & 0x1F) << 8) | f->data.ptr[i];
! 162: warn (LSEC,"buffer size bound",EPST,1,15,bsb);
! 163: /* register stream here, if auto */
! 164: if (a == PES_JOKER_AUDIO) {
! 165: a = PES_CODE_AUDIO;
! 166: x = PES_NUMB_AUDIO;
! 167: } else if (a == PES_JOKER_VIDEO) {
! 168: a = PES_CODE_VIDEO;
! 169: x = PES_NUMB_VIDEO;
! 170: } else if (a >= PES_LOWEST_SID) {
! 171: x = 1;
! 172: } else {
! 173: x = 0;
! 174: }
! 175: if (bbs) {
! 176: bsb = -bsb;
! 177: }
! 178: while (--x >= 0) {
! 179: f->u.ps.sh.buffer_bound[a-PES_LOWEST_SID] = bsb;
! 180: a += 1;
! 181: }
! 182: } else {
! 183: warn (LWAR,"Next bit 0",EPST,1,2,a);
! 184: return (FALSE);
! 185: }
! 186: }
! 187: if (size != -PS_SYSTHD_STRLEN) {
! 188: warn (LWAR,"System header length",EPST,1,4,size);
! 189: return (FALSE);
! 190: }
! 191: return (TRUE);
! 192: }
! 193:
! 194: static boolean ps_stream_map (file_descr *f,
! 195: int size)
! 196: {
! 197: int i, psmv, psil, esil, esml;
! 198: byte a, styp, esid;
! 199: boolean cni;
! 200: warn (LINF,"Stream Map",EPST,4,0,size);
! 201: if ((size > (1018 + PES_HEADER_SIZE))
! 202: || (size < PS_STRMAP_SIZE)) {
! 203: warn (LWAR,"Map size bad",EPST,4,12,size);
! 204: return (FALSE);
! 205: }
! 206: i = f->data.out;
! 207: list_incr (i,f->data,PES_HEADER_SIZE);
! 208: a = f->data.ptr[i];
! 209: psmv = a & 0x1F;
! 210: warn (LSEC,"Map Version",EPST,4,1,psmv);
! 211: alloc_descriptor (f->u.ps.stream[0],0,0,psmv);
! 212: cni = a >> 7;
! 213: warn (LSEC,"Current Next",EPST,4,2,cni);
! 214: list_incr (i,f->data,2);
! 215: psil = f->data.ptr[i] << 8;
! 216: list_incr (i,f->data,1);
! 217: psil = psil | f->data.ptr[i];
! 218: list_incr (i,f->data,1);
! 219: warn (LSEC,"PS Info Length",EPST,4,3,psil);
! 220: size -= PS_STRMAP_SIZE;
! 221: if (size < psil) {
! 222: warn (LWAR,"Invalid Size",EPST,4,7,size);
! 223: return (FALSE);
! 224: }
! 225: size -= psil;
! 226: while (psil > 0) {
! 227: i = put_descriptor (f,f->u.ps.stream[0],i,&psil);
! 228: }
! 229: if (psil < 0) {
! 230: warn (LWAR,"PS Info Broken",EPST,4,4,psil);
! 231: return (FALSE);
! 232: }
! 233: if (cni) {
! 234: finish_descriptor (f->u.ps.stream[0]);
! 235: }
! 236: esml = f->data.ptr[i] << 8;
! 237: list_incr (i,f->data,1);
! 238: esml = esml | f->data.ptr[i];
! 239: list_incr (i,f->data,1);
! 240: warn (LSEC,"ES Map Length",EPST,4,5,esml);
! 241: if (size != esml) {
! 242: warn (LWAR,"Invalid Size",EPST,4,8,size);
! 243: return (FALSE);
! 244: }
! 245: while (esml > 0) {
! 246: styp = f->data.ptr[i];
! 247: list_incr (i,f->data,1);
! 248: esid = f->data.ptr[i];
! 249: list_incr (i,f->data,1);
! 250: esil = f->data.ptr[i] << 8;
! 251: list_incr (i,f->data,1);
! 252: esil = esil | f->data.ptr[i];
! 253: list_incr (i,f->data,1);
! 254: warn (LSEC,"Stream Type",EPST,4,9,styp);
! 255: warn (LSEC,"E Stream Id",EPST,4,10,esid);
! 256: warn (LSEC,"ES Info Length",EPST,4,11,esil);
! 257: if (esid >= PES_LOWEST_SID) {
! 258: if (f->automatic) {
! 259: if (f->u.ps.stream[esid] == NULL) {
! 260: f->u.ps.stream[esid] =
! 261: connect_streamprog (
! 262: f,f->auto_programnb,esid,-esid,styp,
! 263: NULL,f->u.ps.stream[0],FALSE);
! 264: }
! 265: }
! 266: }
! 267: esml -= (esil + 4);
! 268: if (esml >= 0) {
! 269: alloc_descriptor (f->u.ps.stream[0],esid,0,psmv);
! 270: while (esil > 0) {
! 271: i = put_descriptor (f,f->u.ps.stream[0],i,&esil);
! 272: }
! 273: if (esil < 0) {
! 274: warn (LWAR,"ES Map Broken",EPST,4,13,esil);
! 275: return (FALSE);
! 276: }
! 277: if (cni) {
! 278: finish_descriptor (f->u.ps.stream[0]);
! 279: }
! 280: }
! 281: }
! 282: if (esml < 0) {
! 283: warn (LWAR,"ES Map Broken",EPST,4,6,esml);
! 284: return (FALSE);
! 285: }
! 286: return (TRUE);
! 287: }
! 288:
! 289: static int ps_stream_dir_get45 (file_descr *f,
! 290: int i,
! 291: long long *r)
! 292: {
! 293: byte a;
! 294: int b, n;
! 295: n = 2;
! 296: *r = 0;
! 297: do {
! 298: list_incr (i,f->data,1);
! 299: b = f->data.ptr[i];
! 300: list_incr (i,f->data,1);
! 301: a = f->data.ptr[i];
! 302: marker_bit (a,0);
! 303: b = (b << 7) | (a >> 1);
! 304: *r = (*r << 15) | b;
! 305: } while (--n >= 0);
! 306: return (i);
! 307: }
! 308:
! 309: static boolean ps_stream_directory (file_descr *f,
! 310: int size)
! 311: {
! 312: int i, n;
! 313: long x;
! 314: byte a;
! 315: int numoau;
! 316: long long prevdo, nextdo;
! 317: warn (LINF,"Stream Dir",EPST,5,0,0);
! 318: i = f->data.out;
! 319: list_incr (i,f->data,PES_HEADER_SIZE);
! 320: x = f->data.ptr[i];
! 321: list_incr (i,f->data,1);
! 322: a = f->data.ptr[i];
! 323: marker_bit (a,0);
! 324: numoau = (x << 7) | (a >> 1);
! 325: warn (LSEC,"Num Acces Units",EPST,5,1,numoau);
! 326: if (size != (PS_STRDIR_SIZE + numoau * PS_STRDIR_SIZEAU)) {
! 327: warn (LWAR,"Invalid Size",EPST,5,2,size);
! 328: return (FALSE);
! 329: }
! 330: i = ps_stream_dir_get45 (f,i,&prevdo);
! 331: warn (LSEC,"Prev Dir Offset",EPST,5,3,((long)prevdo));
! 332: i = ps_stream_dir_get45 (f,i,&nextdo);
! 333: warn (LSEC,"Next Dir Offset",EPST,5,4,((long)nextdo));
! 334: n = 0;
! 335: while (n < numoau) {
! 336: byte psid;
! 337: boolean idi;
! 338: int refo, btr, cpi;
! 339: long long headpo;
! 340: clockref pts; /* and process all this ... */
! 341: list_incr (i,f->data,1);
! 342: psid = f->data.ptr[i];
! 343: warn (LSEC,"Packet Str Id",EPST,5,5,psid);
! 344: i = ps_stream_dir_get45 (f,i,&headpo);
! 345: if (headpo & (1LL << 44)) {
! 346: headpo = (1LL << 44) - headpo;
! 347: }
! 348: warn (LSEC,"Head Pos Offset",EPST,5,6,((long)headpo));
! 349: list_incr (i,f->data,1);
! 350: refo = f->data.ptr[i];
! 351: list_incr (i,f->data,1);
! 352: refo = (refo << 8) | f->data.ptr[i];
! 353: warn (LSEC,"Reference Offset",EPST,5,7,refo);
! 354: list_incr (i,f->data,1);
! 355: a = f->data.ptr[i];
! 356: marker_check (a,0x81,0x81);
! 357: pts.ba33 = (a >> 3) & 1;
! 358: x = a & 0x06;
! 359: list_incr (i,f->data,1);
! 360: x = (x << 7) | f->data.ptr[i];
! 361: list_incr (i,f->data,1);
! 362: a = f->data.ptr[i];
! 363: marker_bit (a,0);
! 364: x = (x << 8) | (a & 0xFE);
! 365: list_incr (i,f->data,1);
! 366: x = (x << 7) | f->data.ptr[i];
! 367: list_incr (i,f->data,1);
! 368: a = f->data.ptr[i];
! 369: marker_bit (a,0);
! 370: pts.base = (x << 7) | (a >> 1);
! 371: pts.ext = 0;
! 372: warn (LSEC,"PTS base",EPST,5,8,pts.base);
! 373: list_incr (i,f->data,1);
! 374: btr = f->data.ptr[i];
! 375: list_incr (i,f->data,1);
! 376: a = f->data.ptr[i];
! 377: marker_bit (a,0);
! 378: btr = (btr << 8) | (a & 0xFE);
! 379: list_incr (i,f->data,1);
! 380: btr = (btr << 7) | f->data.ptr[i];
! 381: list_incr (i,f->data,1);
! 382: a = f->data.ptr[i];
! 383: marker_bit (a,7);
! 384: cpi = (a >> 4) & 0x03;
! 385: idi = (a >> 6) & 0x01;
! 386: n += 1;
! 387: }
! 388: return (TRUE);
! 389: }
! 390:
! 391: static boolean ps_data_stream (file_descr *f,
! 392: int size,
! 393: byte sourceid)
! 394: {
! 395: stream_descr *s;
! 396: ctrl_buffer *c;
! 397: warn (LINF,"Data Stream",EPST,6,0,size);
! 398: if ((f->u.ps.stream[sourceid] == NULL)
! 399: && (f->automatic)) {
! 400: f->u.ps.stream[sourceid] =
! 401: connect_streamprog (f,f->auto_programnb,sourceid,-sourceid,
! 402: guess_streamtype(sourceid),NULL,f->u.ps.stream[0],FALSE);
! 403: }
! 404: s = f->u.ps.stream[sourceid];
! 405: if (s != NULL) {
! 406: if ((!list_full (s->ctrl))
! 407: && (list_free (s->data) >= 2*size-1)) {
! 408: c = &s->ctrl.ptr[s->ctrl.in];
! 409: c->length = size;
! 410: f->payload += size;
! 411: f->total += size;
! 412: c->index = pes_transfer (&f->data,&s->data,size);
! 413: warn (LDEB,"Sequence",EPST,6,1,f->sequence);
! 414: c->sequence = f->sequence++;
! 415: c->scramble = 0;
! 416: c->time.read = msec_now ();
! 417: c->time.push = f->u.ps.time.read; /* good if multi packages per pack ? */
! 418: c->pcr.valid = FALSE;
! 419: c->opcr.valid = FALSE;
! 420: list_incr (s->ctrl.in,s->ctrl,1);
! 421: return (TRUE);
! 422: }
! 423: return (FALSE);
! 424: }
! 425: f->total += size;
! 426: list_incr (f->data.out,f->data,size);
! 427: return (TRUE);
! 428: }
! 429:
! 430: boolean split_ps (file_descr *f)
! 431: {
! 432: int l, p;
! 433: byte a;
! 434: warn (LDEB,"Split PS",EPST,0,0,f);
! 435: if (pes_skip_to_prefix (f)) {
! 436: l = list_size (f->data);
! 437: if (l >= PES_HDCODE_SIZE) {
! 438: a = pes_stream_id (&f->data);
! 439: if (a >= PS_CODE_SYST_HDR) {
! 440: if (l >= PES_HEADER_SIZE) {
! 441: p = pes_packet_length (&f->data);
! 442: p += PES_HEADER_SIZE;
! 443: if (l >= p) {
! 444: switch (a) {
! 445: case PS_CODE_SYST_HDR:
! 446: if (!ps_system_header (f,p)) {
! 447: p = PES_SYNC_SIZE;
! 448: }
! 449: break;
! 450: case PES_CODE_STR_MAP:
! 451: if (!ps_stream_map (f,p)) {
! 452: p = PES_SYNC_SIZE;
! 453: }
! 454: break;
! 455: case PES_CODE_PADDING:
! 456: break;
! 457: case PES_CODE_PRIVATE2:
! 458: /* p = PES_SYNC_SIZE; */
! 459: break;
! 460: case PES_CODE_ECM:
! 461: /* p = PES_SYNC_SIZE; */
! 462: break;
! 463: case PES_CODE_EMM:
! 464: /* p = PES_SYNC_SIZE; */
! 465: break;
! 466: case PES_CODE_DSMCC:
! 467: /* p = PES_SYNC_SIZE; */
! 468: break;
! 469: case PES_CODE_ITU222E:
! 470: /* p = PES_SYNC_SIZE; */
! 471: break;
! 472: case PES_CODE_STR_DIR:
! 473: if (!ps_stream_directory (f,p)) {
! 474: p = PES_SYNC_SIZE;
! 475: }
! 476: break;
! 477: default:
! 478: return (ps_data_stream (f,p,a));
! 479: break;
! 480: }
! 481: } else {
! 482: p = 0;
! 483: }
! 484: } else {
! 485: p = 0;
! 486: }
! 487: } else if (a == PS_CODE_END) {
! 488: p = ps_program_end_code (f);
! 489: } else if (a == PS_CODE_PACK_HDR) {
! 490: p = ps_pack_header (f,l);
! 491: } else {
! 492: warn (LWAR,"Unknown Stream Id",EPST,0,1,a);
! 493: p = PES_SYNC_SIZE;
! 494: }
! 495: if (p > 0) {
! 496: f->total += p;
! 497: list_incr (f->data.out,f->data,p);
! 498: return (TRUE);
! 499: }
! 500: }
! 501: }
! 502: return (FALSE);
! 503: }
! 504:
LinuxTV legacy CVS <linuxtv.org/cvs>