Annotation of multiplexer/splitps.c, revision 1.3
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:
293: static int ps_stream_dir_get45 (file_descr *f,
294: int i,
295: long long *r)
296: {
297: byte a;
298: int b, n;
299: n = 2;
300: *r = 0;
301: do {
302: list_incr (i,f->data,1);
303: b = f->data.ptr[i];
304: list_incr (i,f->data,1);
305: a = f->data.ptr[i];
306: marker_bit (a,0);
307: b = (b << 7) | (a >> 1);
308: *r = (*r << 15) | b;
309: } while (--n >= 0);
310: return (i);
311: }
312:
313: static boolean ps_stream_directory (file_descr *f,
314: int size)
315: {
316: int i, n;
317: long x;
318: byte a;
319: int numoau;
320: long long prevdo, nextdo;
321: warn (LINF,"Stream Dir",EPST,5,0,0);
322: i = f->data.out;
323: list_incr (i,f->data,PES_HEADER_SIZE);
324: x = f->data.ptr[i];
325: list_incr (i,f->data,1);
326: a = f->data.ptr[i];
327: marker_bit (a,0);
328: numoau = (x << 7) | (a >> 1);
329: warn (LSEC,"Num Acces Units",EPST,5,1,numoau);
330: if (size != (PS_STRDIR_SIZE + numoau * PS_STRDIR_SIZEAU)) {
331: warn (LWAR,"Invalid Size",EPST,5,2,size);
332: return (FALSE);
333: }
334: i = ps_stream_dir_get45 (f,i,&prevdo);
335: warn (LSEC,"Prev Dir Offset",EPST,5,3,((long)prevdo));
336: i = ps_stream_dir_get45 (f,i,&nextdo);
337: warn (LSEC,"Next Dir Offset",EPST,5,4,((long)nextdo));
338: n = 0;
339: while (n < numoau) {
340: byte psid;
341: boolean idi;
342: int refo, btr, cpi;
343: long long headpo;
344: clockref pts; /* and process all this ... */
345: list_incr (i,f->data,1);
346: psid = f->data.ptr[i];
347: warn (LSEC,"Packet Str Id",EPST,5,5,psid);
348: i = ps_stream_dir_get45 (f,i,&headpo);
349: if (headpo & (1LL << 44)) {
350: headpo = (1LL << 44) - headpo;
351: }
352: warn (LSEC,"Head Pos Offset",EPST,5,6,((long)headpo));
353: list_incr (i,f->data,1);
354: refo = f->data.ptr[i];
355: list_incr (i,f->data,1);
356: refo = (refo << 8) | f->data.ptr[i];
357: warn (LSEC,"Reference Offset",EPST,5,7,refo);
358: list_incr (i,f->data,1);
359: a = f->data.ptr[i];
360: marker_check (a,0x81,0x81);
361: pts.ba33 = (a >> 3) & 1;
362: x = a & 0x06;
363: list_incr (i,f->data,1);
364: x = (x << 7) | f->data.ptr[i];
365: list_incr (i,f->data,1);
366: a = f->data.ptr[i];
367: marker_bit (a,0);
368: x = (x << 8) | (a & 0xFE);
369: list_incr (i,f->data,1);
370: x = (x << 7) | f->data.ptr[i];
371: list_incr (i,f->data,1);
372: a = f->data.ptr[i];
373: marker_bit (a,0);
374: pts.base = (x << 7) | (a >> 1);
375: pts.ext = 0;
376: warn (LSEC,"PTS base",EPST,5,8,pts.base);
377: list_incr (i,f->data,1);
378: btr = f->data.ptr[i];
379: list_incr (i,f->data,1);
380: a = f->data.ptr[i];
381: marker_bit (a,0);
382: btr = (btr << 8) | (a & 0xFE);
383: list_incr (i,f->data,1);
384: btr = (btr << 7) | f->data.ptr[i];
385: list_incr (i,f->data,1);
386: a = f->data.ptr[i];
387: marker_bit (a,7);
388: cpi = (a >> 4) & 0x03;
389: idi = (a >> 6) & 0x01;
390: n += 1;
391: }
392: return (TRUE);
393: }
394:
395: static boolean ps_data_stream (file_descr *f,
396: int size,
397: byte sourceid)
398: {
399: stream_descr *s;
400: ctrl_buffer *c;
401: warn (LINF,"Data Stream",EPST,6,0,size);
402: if ((f->u.ps.stream[sourceid] == NULL)
403: && (f->automatic)) {
404: f->u.ps.stream[sourceid] =
405: connect_streamprog (f,f->auto_programnb,sourceid,-sourceid,
406: guess_streamtype(sourceid),NULL,f->u.ps.stream[0],FALSE);
407: }
408: s = f->u.ps.stream[sourceid];
409: if (s != NULL) {
410: if ((!list_full (s->ctrl))
411: && (list_free (s->data) >= 2*size-1)) {
412: c = &s->ctrl.ptr[s->ctrl.in];
413: c->length = size;
414: f->payload += size;
415: f->total += size;
416: c->index = pes_transfer (&f->data,&s->data,size);
417: warn (LDEB,"Sequence",EPST,6,1,f->sequence);
418: c->sequence = f->sequence++;
419: c->scramble = 0;
1.2 oskar 420: c->msecread = msec_now ();
421: c->msecpush = f->u.ps.stream[0]->u.m.msectime;
1.1 oskar 422: c->pcr.valid = FALSE;
423: c->opcr.valid = FALSE;
424: list_incr (s->ctrl.in,s->ctrl,1);
425: return (TRUE);
426: }
427: return (FALSE);
428: }
429: f->total += size;
430: list_incr (f->data.out,f->data,size);
431: return (TRUE);
432: }
433:
434: boolean split_ps (file_descr *f)
435: {
436: int l, p;
437: byte a;
438: warn (LDEB,"Split PS",EPST,0,0,f);
439: if (pes_skip_to_prefix (f)) {
440: l = list_size (f->data);
441: if (l >= PES_HDCODE_SIZE) {
442: a = pes_stream_id (&f->data);
443: if (a >= PS_CODE_SYST_HDR) {
444: if (l >= PES_HEADER_SIZE) {
445: p = pes_packet_length (&f->data);
446: p += PES_HEADER_SIZE;
447: if (l >= p) {
448: switch (a) {
449: case PS_CODE_SYST_HDR:
450: if (!ps_system_header (f,p)) {
451: p = PES_SYNC_SIZE;
452: }
453: break;
454: case PES_CODE_STR_MAP:
455: if (!ps_stream_map (f,p)) {
456: p = PES_SYNC_SIZE;
457: }
458: break;
459: case PES_CODE_PADDING:
460: break;
461: case PES_CODE_PRIVATE2:
462: /* p = PES_SYNC_SIZE; */
463: break;
464: case PES_CODE_ECM:
465: /* p = PES_SYNC_SIZE; */
466: break;
467: case PES_CODE_EMM:
468: /* p = PES_SYNC_SIZE; */
469: break;
470: case PES_CODE_DSMCC:
471: /* p = PES_SYNC_SIZE; */
472: break;
473: case PES_CODE_ITU222E:
474: /* p = PES_SYNC_SIZE; */
475: break;
476: case PES_CODE_STR_DIR:
477: if (!ps_stream_directory (f,p)) {
478: p = PES_SYNC_SIZE;
479: }
480: break;
481: default:
482: return (ps_data_stream (f,p,a));
483: break;
484: }
485: } else {
486: p = 0;
487: }
488: } else {
489: p = 0;
490: }
491: } else if (a == PS_CODE_END) {
492: p = ps_program_end_code (f);
493: } else if (a == PS_CODE_PACK_HDR) {
494: p = ps_pack_header (f,l);
495: } else {
496: warn (LWAR,"Unknown Stream Id",EPST,0,1,a);
497: p = PES_SYNC_SIZE;
498: }
499: if (p > 0) {
500: f->total += p;
501: list_incr (f->data.out,f->data,p);
502: return (TRUE);
503: }
504: }
505: }
506: return (FALSE);
507: }
508:
LinuxTV legacy CVS <linuxtv.org/cvs>