Annotation of multiplexer/splitps.c, revision 1.4
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"
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>