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