Annotation of multiplexer/splitps.c, revision 1.5

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

LinuxTV legacy CVS <linuxtv.org/cvs>