Annotation of multiplexer/ts2pes.c, revision 1.3
1.1 oskar 1: /*
2: * read transport stream
3: * Copyright (C) 1999-2004 Christian Wolff
4: *
1.3 ! oskar 5: * This program is free software; you can redistribute it and/or modify
! 6: * it under the terms of the GNU General Public License as published by
! 7: * the Free Software Foundation; either version 2 of the License, or
! 8: * (at your option) any later version.
1.1 oskar 9: *
10: * This program is distributed in the hope that it will be useful,
11: * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.3 ! oskar 12: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! 13: * GNU General Public License for more details.
1.1 oskar 14: *
1.3 ! oskar 15: * You should have received a copy of the GNU General Public License
! 16: * along with this program; if not, write to the Free Software
1.1 oskar 17: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18: */
19:
1.2 oskar 20: #include <stdint.h>
1.1 oskar 21: #include "ts2pes.h"
22: #include "crc32.h"
23:
24: unsigned long CRC;
25:
26: // current stream parameters
27:
28: #define TS_packet_length 188
29:
30: // list of TS-Programs (as linked list)
31: ElementaryStream *first_ES=NULL;
32:
33: // the curent valid PAT from PID 0x0000
34: ProgramAssociationTable *PAT=NULL;
35: // the intermediate PAT while building it from PID 0x0000
36: ProgramAssociationTable *current_PAT,*next_PAT;
37:
38: // the curent valid CAT from PID 0x0001
39: ConditionalAccessTable *CAT=NULL;
40: // the intermediate CAT while building it from PID 0x0001
41: ConditionalAccessTable *current_CAT,*next_CAT;
42:
43: // list of Programs (as linked list)
44: ProgramMapTable *first_PMT=NULL, *first_nextPMT=NULL, *phantom_PMT=NULL;
45:
46:
47: // -------------------------------------------------------------- //
48: // List management function for transport stream packet headers
49: // -------------------------------------------------------------- //
50:
51: ElementaryStream *find_ES(unsigned int PID) { // find TSP with this PID
52: ElementaryStream *ptr=first_ES;
53: while (ptr!=NULL) {
54: if ((ptr->TSP!=NULL) && (ptr->TSP->PID==PID)) return ptr;
55: ptr=(ElementaryStream *)ptr->next;
56: }
57: return ptr;
58: }
59:
60: ElementaryStream *new_ES(unsigned int PID) { // find or create TSP with this PID
61: ElementaryStream *ptr=first_ES;
62: while (ptr!=NULL) {
63: if ((ptr->TSP!=NULL) && (ptr->TSP->PID==PID)) return ptr;
64: ptr=(ElementaryStream *)ptr->next;
65: }
66: if (first_ES==NULL) {
67: first_ES=(ElementaryStream *)malloc(sizeof(ElementaryStream));
68: ptr=first_ES;
69: } else {
70: ptr=first_ES;
71: while (ptr->next!=NULL) ptr=(ElementaryStream *)ptr->next;
72: ptr->next=malloc(sizeof(ElementaryStream));
73: ptr=(ElementaryStream *)ptr->next;
74: }
75: if (ptr==NULL) return NULL;
76: ptr->next=NULL;
77: ptr->TSP=(TransportStreamProgram *)malloc(sizeof(TransportStreamProgram));
78: if (ptr->TSP==NULL) return NULL;
79: ptr->TSP->AF=NULL;
80: ptr->TSP->continuity_counter=0x0F; // For continuity. First real CC is 0x00
81: ptr->TSP->PID=PID; // set PID
82: ptr->Payload=NULL;
83: ptr->payload_count=0;
84: ptr->payload_length=0;
85: return ptr;
86: }
87:
88: void kill_ES(unsigned int PID) { // search&destroy(tm Henry Rollins) TSP with this PID
89: ElementaryStream *ptr=first_ES, *ptr0=NULL;
90: while (ptr!=NULL) {
91: if ((ptr->TSP!=NULL) && (ptr->TSP->PID==PID)) {
92: if (ptr->TSP!=NULL) free(ptr->TSP);
93: if (ptr->Payload!=NULL) free(ptr->Payload);
94: if (ptr0==NULL) {
95: first_ES=ptr->next;
96: free(ptr);
97: ptr=first_ES;
98: } else {
99: ptr0->next=ptr->next;
100: free(ptr);
101: ptr=ptr0;
102: }
103: }
104: ptr0=ptr;
105: if (ptr!=NULL) ptr=(ElementaryStream *)ptr->next;
106: }
107: }
108:
109:
110: // -------------------------------------------------------------- //
111: // List management functions for program map tables
112: // -------------------------------------------------------------- //
113:
114: ProgramMapTable *find_PMT(ProgramMapTable **anker, unsigned int program_number) { // find TSP with this program_number
115: ProgramMapTable *ptr=*anker;
116: while (ptr!=NULL) {
117: if ((ptr->program_number==program_number)) return ptr;
118: ptr=(ProgramMapTable *)ptr->next;
119: }
120: return ptr;
121: }
122:
123: ProgramMapTable *new_PMT(ProgramMapTable **anker, unsigned int program_number) { // find or create TSP with this program_number
124: int i;
125: ProgramMapTable *ptr=*anker;
126: while (ptr!=NULL) {
127: if ((ptr->program_number==program_number)) return ptr;
128: ptr=(ProgramMapTable *)ptr->next;
129: }
130: if (*anker==NULL) {
131: *anker=(ProgramMapTable *)malloc(sizeof(ProgramMapTable));
132: ptr=*anker;
133: } else {
134: ptr=*anker;
135: while (ptr->next!=NULL) ptr=(ProgramMapTable *)ptr->next;
136: ptr->next=malloc(sizeof(ProgramMapTable));
137: ptr=(ProgramMapTable *)ptr->next;
138: }
139: if (ptr==NULL) return NULL;
140: ptr->next=NULL;
141: ptr->descriptor_count=0;
142: for (i=0; i<16; i++) ptr->descriptor[i]=NULL;
143: ptr->program_count=0;
144: for (i=0; i<256; i++) ptr->program[i]=NULL;
145: ptr->program_number=program_number; // set program_number
146: return ptr;
147: }
148:
149: void kill_PMT(ProgramMapTable **anker, unsigned int program_number) { // search&destroy(tm Henry Rollins) TSP with this program_number
150: ProgramMapTable *ptr=*anker, *ptr0=NULL;
151: int i,j;
152: while (ptr!=NULL) {
153: if ((ptr->program_number==program_number)) {
154: if (ptr0==NULL) {
155: *anker=(ProgramMapTable *)ptr->next;
156: ptr0=*anker;
157: } else {
158: ptr0->next=ptr->next;
159: }
160: for (i=0; i<16; i++) if (ptr->descriptor[i]!=NULL) {
161: if (ptr->descriptor[i]->data!=NULL) free(ptr->descriptor[i]->data);
162: free(ptr->descriptor[i]);
163: }
164: for (i=0; i<256; i++) if (ptr->program[i]!=NULL) {
165: for (j=0; j<16; j++) if (ptr->program[i]->descriptor[j]!=NULL) {
166: if (ptr->program[i]->descriptor[j]->data!=NULL) free(ptr->program[i]->descriptor[j]->data);
167: free(ptr->program[i]->descriptor[j]);
168: }
169: free(ptr->program[i]);
170: }
171: free(ptr);
172: ptr=ptr0;
173: }
174: ptr0=ptr;
175: if (ptr!=NULL) ptr=(ProgramMapTable *)ptr->next;
176: }
177: }
178:
179:
180: // -------------------------------------------------------------- //
181: // debug output of header information
182: // -------------------------------------------------------------- //
183:
184: void print_TP(TransportStreamProgram *TP) { // debug output of TP-Header
185: printf("- Transport Packet Header -\n\
186: transport_error_indicator: %i\n\
187: payload_unit_start_indicator: %i\n\
188: transport_priority: %i\n\
189: PID: 0x%04X\n\
190: transport_scrambling_control: 0x%02X\n\
191: adaption_field_control_1: %i\n\
192: adaption_field_control_0: %i\n\
193: continuity_counter: 0x%02X\n\
194: \n",
195: ((TP->transport_error_indicator)?1:0),
196: ((TP->payload_unit_start_indicator)?1:0),
197: ((TP->transport_priority)?1:0),
198: TP->PID,
199: TP->transport_scrambling_control,
200: ((TP->adaption_field_control_1)?1:0),
201: ((TP->adaption_field_control_0)?1:0),
202: TP->continuity_counter
203: );
204: }
205:
206: void print_AF(AdaptionField *AF) { // debug output of AF
207: int i;
208: printf("- Adaption Field -\n\
209: discontinuity_indicator: %i\n\
210: random_access_indicator: %i\n\
211: elementary_stream_priority_indicator: %i\n\
212: PCR_flag: %i\n\
213: OPCR_flag: %i\n\
214: splicing_point_flag: %i\n\
215: transport_private_data_flag: %i\n\
216: adaption_field_extension_flag: %i\n",
217: ((AF->discontinuity_indicator)?1:0),
218: ((AF->random_access_indicator)?1:0),
219: ((AF->elementary_stream_priority_indicator)?1:0),
220: ((AF->PCR_flag)?1:0),
221: ((AF->OPCR_flag)?1:0),
222: ((AF->splicing_point_flag)?1:0),
223: ((AF->transport_private_data_flag)?1:0),
224: ((AF->adaption_field_extension_flag)?1:0));
225: if (AF->PCR_flag) printf("\
226: program_clock_reference_base: %lld\n\
227: program_clock_reference_extension: %d\n",
228: AF->program_clock_reference_base,
229: AF->program_clock_reference_extension);
230: if (AF->OPCR_flag) printf("\
231: original_program_clock_reference_base: %lld\n\
232: original_program_clock_reference_extension: %d\n",
233: AF->original_program_clock_reference_base,
234: AF->original_program_clock_reference_extension);
235: if (AF->splicing_point_flag) printf("SC: %i\n",
236: AF->splice_countdown);
237: if (AF->transport_private_data_flag) {
238: printf("\
239: transport_private_data_length: %i\n",
240: AF->transport_private_data_length);
241: for (i=0; i<AF->transport_private_data_length; i++) {
242: printf("%02X ",(AF->private_data_byte[i] & 0xFF));
243: if (((i % 24)==23) || (i == AF->transport_private_data_length-1)) printf("\n");
244: }
245: }
246: if (AF->adaption_field_extension_flag) {
247: printf("\
248: adaption_field_extension_length: %i\n\
249: ltw_flag: %i\n\
250: piecewise_rate_flag: %i\n\
251: seamless_splice_flag: %i\n",
252: AF->adaption_field_extension_length,
253: ((AF->ltw_flag)?1:0),
254: ((AF->piecewise_rate_flag)?1:0),
255: ((AF->seamless_splice_flag)?1:0));
256: if (AF->ltw_flag) {
257: printf("\
258: ltw_valid_flag: %i\n\
259: ltw_offset: %i\n",
260: ((AF->ltw_valid_flag)?1:0),
261: AF->ltw_offset);
262: }
263: if (AF->piecewise_rate_flag) {
264: printf("\
265: piecewise_rate: %i\n",
266: AF->piecewise_rate);
267: }
268: if (AF->seamless_splice_flag) {
269: printf("\
270: splice_type: 0x%01X\n\
271: DTS_next_AU: %lld\n",
272: AF->splice_type,
273: AF->DTS_next_AU);
274: }
275: }
276: printf("\n");
277: }
278:
279: void print_PAT(ProgramAssociationTable *PAT) { // debug output of PAT
280: int i;
281: printf("- Program Association Table -\n\
282: table_id: %i\n\
283: section_syntax_indicator: %i\n\
284: private_indicator: %i\n\
285: section_length: %i\n\
286: transport_stream_id: 0x%04X\n\
287: version_number: %i\n\
288: current_next_indicator: %i\n\
289: section_number: %i\n\
290: last_section_number: %i\n\
291: Table Size: %i\n\
292: PN PID\n",
293: PAT->table_id,
294: ((PAT->section_syntax_indicator)?1:0),
295: ((PAT->private_indicator)?1:0),
296: PAT->section_length,
297: PAT->transport_stream_id,
298: PAT->version_number,
299: ((PAT->current_next_indicator)?1:0),
300: PAT->section_number,
301: PAT->last_section_number,
302: PAT->program_count);
303: for (i=0; i<PAT->program_count; i++) {
304: printf(" 0x%04X 0x%04X\n",PAT->program_number[i],PAT->PID[i]);
305: }
306: printf("\n");
307: }
308:
309: void print_CAT(ConditionalAccessTable *CAT) { // debug output of CAT
310: int i;
311: printf("- Conditional Access Table -\n\
312: table_id: %i\n\
313: section_syntax_indicator: %i\n\
314: private_indicator: %i\n\
315: section_length: %i\n\
316: version_number: %i\n\
317: current_next_indicator: %i\n\
318: section_number: %i\n\
319: last_section_number: %i\n\
320: Table Size: %i\n\
321: SysID CA_PID\n",
322: CAT->table_id,
323: ((CAT->section_syntax_indicator)?1:0),
324: ((CAT->private_indicator)?1:0),
325: CAT->section_length,
326: CAT->version_number,
327: ((CAT->current_next_indicator)?1:0),
328: CAT->section_number,
329: CAT->last_section_number,
330: CAT->descriptor_count);
331: for (i=0; i<CAT->descriptor_count; i++) {
332: printf("\
333: 0x%04X 0x%04X",
334: CAT->CA_descriptor[i]->CA_system_ID,
335: CAT->CA_descriptor[i]->CA_PID);
336: show_descriptor(CAT->CA_descriptor[i]->descriptor,1);
337: printf("\n");
338: }
339: printf("\n");
340: }
341:
342: void print_PMT(ProgramMapTable *PMT) { // debug output of PMT
343: int i,j;
344: Program *prog; // temp. pointer
345: printf("- Program Map Table -\n\
346: table_id: %i\n\
347: section_syntax_indicator: %i\n\
348: private_indicator: %i\n\
349: section_length: %i\n\
350: program_number: 0x%04X\n\
351: version_number: %i\n\
352: current_next_indicator: %i\n\
353: section_number: %i\n\
354: last_section_number: %i\n\
355: PCR_PID: 0x%04X\n\
356: Table Size: %i\n\
357: type PID\n",
358: PMT->table_id,
359: ((PMT->section_syntax_indicator)?1:0),
360: ((PMT->private_indicator)?1:0),
361: PMT->section_length,
362: PMT->program_number,
363: PMT->version_number,
364: ((PMT->current_next_indicator)?1:0),
365: PMT->section_number,
366: PMT->last_section_number,
367: PMT->PCR_PID,
368: PMT->program_count);
369: for (i=0; i<PMT->descriptor_count; i++) {
370: show_descriptor(PMT->descriptor[i],1);
371: }
372: for (i=0; i<PMT->program_count; i++) {
373: prog=PMT->program[i];
374: printf(" 0x%02X 0x%04X\n",prog->stream_type,prog->elementary_PID);
375: for (j=0; j<prog->descriptor_count; j++) {
376: show_descriptor(prog->descriptor[j],1);
377: }
378: }
379: printf("\n");
380: }
381:
382: void print_TSP(TransportStreamProgram *TSP) { // debug output of whole TP
383: print_TP(TSP);
384: if (TSP->AF!=NULL) print_AF(TSP->AF);
385: }
386:
387:
388: // -------------------------------------------------------------- //
389: // parsing of one PSI, collected from the TS-packet payload
390: // -------------------------------------------------------------- //
391:
392: int parse_PSI(ElementaryStream *ES, unsigned int PSI, int verbose, int useCRC) {
393: // header data for all PSI's
394: unsigned char table_id; // Table ID
395: unsigned int section_syntax_indicator, // Section Syntax Indicator
396: private_indicator, // Private Indicator
397: section_length, // Section Length
398: PSI_word; // Transport Stream ID / Program Number / Table ID Extension
399: unsigned char version_number; // Version Number
400: unsigned int current_next_indicator, // Current/Next Indicator
401: section_number, // Section Number
402: last_section_number; // Last Section Number
403:
404: ProgramMapTable *PMT, *ptr; // current PMT
405:
406: int i,j,n, // counters
407: program_info_length, // ProgramInformationLength
408: ES_info_length, // ESinfolength
409: desc_length; // descriptor length
410: unsigned char ch, // single byte
411: desc_tag; // descriptor tag
412: Program *prog; // temp. pointer
413:
414: table_id=ES->Payload[0];
415: section_syntax_indicator=ES->Payload[1] & 0x80;
416: private_indicator=ES->Payload[1] & 0x40;
417: section_length=((ES->Payload[1] << 8) | (ES->Payload[2] & 0xFF)) & 0x0FFF;
418: if (section_syntax_indicator) {
419: PSI_word=((ES->Payload[3] << 8) | (ES->Payload[4] & 0xFF)) & 0xFFFF;
420: version_number=(ES->Payload[5] & 0x3E) >> 1;
421: current_next_indicator=ES->Payload[5] & 0x01;
422: section_number=ES->Payload[6] & 0xFF;
423: last_section_number=ES->Payload[7] & 0xFF;
424: } else {
425: PSI_word=0;
426: version_number=0;
427: current_next_indicator=0;
428: section_number=0;
429: last_section_number=0;
430: }
431:
432: if (section_length+3 > ES->payload_count) {
433: if (verbose) printf("ERROR in PSI-header, section length shows %i byte, but there are only %i\n",
434: section_length+3,
435: ES->payload_count);
436: return 0x0104;
437: }
438: if (section_syntax_indicator)
439: CRC=update_crc_32_block(CRC_INIT_32,ES->Payload,section_length+3);
440:
441: if (verbose) {
442: printf("PSI Section: %i bytes\n",section_length+3);
443: for (i=0; i<section_length+3; i++) {
444: printf("%02X ",(ES->Payload[i] & 0xFF));
445: if ((i % 24)==23) printf("\n");
446: }
447: printf("\n");
448: if (section_syntax_indicator)
449: printf("CRC of section %i: 0x%08lX - %s\n",
450: section_number,
451: CRC,
452: ((CRC==0x00000000L)?"OK":"NG")); // if you do it wrong, you get CRC==0xC704DD7BL
453: }
454:
455: if (section_syntax_indicator && CRC) { // CRC error
456: if (verbose) printf("ERROR in PSI - CRC error (0x%08lX)\n",CRC);
457: if (useCRC) return 0x0204;
458: }
459:
460: if (PSI==1) { // This is a PAT
461: if (table_id!=0x00) {
462: if (verbose) printf("- WRONG Table ID 0x%02X in section, PSI-type=%i!\n",table_id,PSI);
463: if (useCRC) return 0x0304;
464: }
465: if (!section_syntax_indicator || private_indicator) {
466: if (verbose) printf("- SYNTAX error in section, PSI-type=%i!\n",PSI);
467: if (useCRC) return 0x0404;
468: }
469: next_PAT->table_id=table_id;
470: next_PAT->section_syntax_indicator=section_syntax_indicator;
471: next_PAT->private_indicator=private_indicator;
472: next_PAT->section_length=section_length;
473: next_PAT->transport_stream_id=PSI_word;
474: next_PAT->version_number=version_number;
475: next_PAT->current_next_indicator=current_next_indicator;
476: next_PAT->section_number=section_number;
477: next_PAT->last_section_number=last_section_number;
478: i=8;
479: while (i+4<section_length) {
480: ch=ES->Payload[i++]; // you'll never know the evaluation order...
481: next_PAT->program_number[next_PAT->program_count]=((ch << 8) | (ES->Payload[i++] & 0xFF)) & 0xFFFF;
482: ch=ES->Payload[i++];
483: next_PAT->PID[next_PAT->program_count++]=((ch << 8) | (ES->Payload[i++] & 0xFF)) & 0x1FFF;
484: }
485: if (verbose) print_PAT(next_PAT);
486: if (current_next_indicator && (section_number==last_section_number)) { // our new PAT has completely arrived
487: PAT=next_PAT;
488: next_PAT=current_PAT;
489: current_PAT=PAT;
490: next_PAT->program_count=0;
491: }
492:
493: } else if (PSI==2) { // CAT
494: //if (verbose) printf("- Conditional Access Table -\n\n");
495: if (table_id!=0x01) {
496: if (verbose) printf("- WRONG Table ID 0x%02X in section, PSI-type=%i!\n",table_id,PSI);
497: if (useCRC) return 0x0304;
498: }
499: if (!section_syntax_indicator || private_indicator) {
500: if (verbose) printf("- SYNTAX error in section, PSI-type=%i!\n",PSI);
501: if (useCRC) return 0x0404;
502: }
503: next_CAT->table_id=table_id;
504: next_CAT->section_syntax_indicator=section_syntax_indicator;
505: next_CAT->private_indicator=private_indicator;
506: next_CAT->section_length=section_length;
507: next_CAT->version_number=version_number;
508: next_CAT->current_next_indicator=current_next_indicator;
509: next_CAT->section_number=section_number;
510: next_CAT->last_section_number=last_section_number;
511: i=8;
512: while ((i+2<=section_length) && (next_CAT->descriptor_count<256)) {
513: n=next_CAT->descriptor_count;
514: if (next_CAT->CA_descriptor[n]==NULL) {
515: next_CAT->CA_descriptor[n]=(ConditionalAccessDescriptor *)malloc(sizeof(ConditionalAccessDescriptor));
516: next_CAT->CA_descriptor[n]->descriptor=NULL;
517: }
518: desc_tag=ES->Payload[i++];
519: desc_length=ES->Payload[i++] & 0xFF;
520: if (next_CAT->CA_descriptor[n]==NULL) {
521: next_CAT->CA_descriptor[n]->descriptor=(Descriptor *)malloc(sizeof(Descriptor));
522: next_CAT->CA_descriptor[n]->descriptor->data=NULL;
523: }
524: next_CAT->CA_descriptor[n]->descriptor->tag=desc_tag;
525: next_CAT->CA_descriptor[n]->descriptor->length=desc_length;
526: if (desc_length>0) {
527: if (i+desc_length>n) {
528: if (verbose) printf("ERROR: insufficent data in descriptor\n");
529: if (useCRC) return 0x0704;
530: }
531: next_CAT->CA_descriptor[n]->descriptor->data=(unsigned char *)realloc(next_CAT->CA_descriptor[n]->descriptor->data,desc_length*sizeof(unsigned char));
532: for (j=0; j<desc_length; j++) {
533: next_CAT->CA_descriptor[n]->descriptor->data[j]=ES->Payload[i++];
534: }
535: if (desc_length>=2) next_CAT->CA_descriptor[n]->CA_system_ID=((next_CAT->CA_descriptor[n]->descriptor->data[0] << 8) | (next_CAT->CA_descriptor[n]->descriptor->data[1] & 0xFF)) & 0xFFFF;
536: else next_CAT->CA_descriptor[n]->CA_system_ID=0;
537: if (desc_length>=4) next_CAT->CA_descriptor[n]->CA_PID=((next_CAT->CA_descriptor[n]->descriptor->data[2] << 8) | (next_CAT->CA_descriptor[n]->descriptor->data[3] & 0xFF)) & 0x1FFF;
538: else next_CAT->CA_descriptor[n]->CA_PID=0x1FFF;
539: }
540: next_CAT->descriptor_count++;
541: }
542:
543: /*
544: while (i+4<section_length) {
545: next_CAT->descriptor[next_CAT->descriptor_count].descriptor_tag=ES->Payload[i++];
546: next_CAT->descriptor[next_CAT->descriptor_count].descriptor_length=ES->Payload[i++];
547: ch=ES->Payload[i++];
548: next_CAT->descriptor[next_CAT->descriptor_count].CA_system_ID=((ch << 8) | (ES->Payload[i++] & 0xFF)) & 0xFFFF;
549: ch=ES->Payload[i++];
550: next_CAT->descriptor[next_CAT->descriptor_count].CA_PID=((ch << 8) | (ES->Payload[i++] & 0xFF)) & 0x1FFF;
551: next_CAT->descriptor[next_CAT->descriptor_count].descriptor_tag=ES->Payload[i++];
552: n=next_CAT->descriptor[next_CAT->descriptor_count].descriptor_length;
553: if (n>4) {
554: next_CAT->descriptor[next_CAT->descriptor_count].private_data_length=n-4;
555: next_CAT->descriptor[next_CAT->descriptor_count].private_data_byte=(char *)malloc(n-4);
556: for (j=0; j<n-4; j++)
557: next_CAT->descriptor[next_CAT->descriptor_count].private_data_byte[j]=ES->Payload[i++];
558: } else next_CAT->descriptor[next_CAT->descriptor_count].private_data_length=0;
559: next_CAT->descriptor_count++;
560: }
561: */
562:
563: if (verbose) print_CAT(next_CAT);
564: if (current_next_indicator && (section_number==last_section_number)) { // our new CAT has completely arrived
565: CAT=next_CAT;
566: next_CAT=current_CAT;
567: current_CAT=CAT;
568: next_CAT->descriptor_count=0;
569: }
570:
571: } else if (PSI==3) { // PMT
572: if (table_id!=0x02) {
573: if (verbose) printf("- WRONG Table ID 0x%02X in section, PSI-type=%i!\n",table_id,PSI);
574: if (useCRC) return 0x0304;
575: }
576: if (!section_syntax_indicator || private_indicator) {
577: if (verbose) printf("- SYNTAX error in section, PSI-type=%i!\n",PSI);
578: if (useCRC) return 0x0404;
579: }
580: PMT=new_PMT(&first_nextPMT,PSI_word);
581: if (PMT==NULL) return 0x0503;
582: PMT->table_id=table_id;
583: PMT->section_syntax_indicator=section_syntax_indicator;
584: PMT->private_indicator=private_indicator;
585: PMT->section_length=section_length;
586: PMT->program_number=PSI_word;
587: PMT->version_number=version_number;
588: PMT->current_next_indicator=current_next_indicator;
589: PMT->section_number=section_number;
590: PMT->last_section_number=last_section_number;
591: PMT->PCR_PID=((ES->Payload[8] << 8) | (ES->Payload[9] & 0xFF)) & 0x1FFF;
592: program_info_length=((ES->Payload[10] << 8) | (ES->Payload[11] & 0xFF)) & 0x0FFF;
593: i=12; n=i+program_info_length;
594: while ((i+2<=n) && (PMT->descriptor_count<16)) {
595: desc_tag=ES->Payload[i++];
596: desc_length=ES->Payload[i++] & 0xFF;
597: if (PMT->descriptor[PMT->descriptor_count]==NULL) {
598: PMT->descriptor[PMT->descriptor_count]=(Descriptor *)malloc(sizeof(Descriptor));
599: PMT->descriptor[PMT->descriptor_count]->data=NULL;
600: }
601: PMT->descriptor[PMT->descriptor_count]->tag=desc_tag;
602: PMT->descriptor[PMT->descriptor_count]->length=desc_length;
603: if (desc_length>0) {
604: if (i+desc_length>n) {
605: if (verbose) printf("ERROR: insufficent data in descriptor %i+%i>=%i\n",i,desc_length,n);
606: if (useCRC) return 0x0604;
607: }
608: PMT->descriptor[PMT->descriptor_count]->data=(unsigned char *)realloc(PMT->descriptor[PMT->descriptor_count]->data,desc_length*sizeof(unsigned char));
609: for (j=0; j<desc_length; j++) {
610: PMT->descriptor[PMT->descriptor_count]->data[j]=ES->Payload[i++];
611: }
612: }
613: PMT->descriptor_count++;
614: }
615: i=n;
616: while ((i+4<section_length) && (PMT->program_count<256)) {
617: prog=PMT->program[PMT->program_count];
618: if (prog==NULL) {
619: prog=(Program *)malloc(sizeof(Program));
620: PMT->program[PMT->program_count]=prog;
621: prog->descriptor_count=0;
622: for (j=0; j<16; j++) prog->descriptor[j]=NULL;
623: }
624: prog->stream_type=ES->Payload[i++];
625: ch=ES->Payload[i++]; // you'll never know the evaluation order...
626: prog->elementary_PID=((ch << 8) | (ES->Payload[i++] & 0xFF)) & 0x1FFF;
627: ch=ES->Payload[i++];
628: ES_info_length=((ch << 8) | (ES->Payload[i++] & 0xFF)) & 0x0FFF;
629: n=i+ES_info_length;
630: while ((i+2<=n) && (prog->descriptor_count<16)) {
631: desc_tag=ES->Payload[i++];
632: desc_length=ES->Payload[i++] & 0xFF;
633: if (prog->descriptor[prog->descriptor_count]==NULL) {
634: prog->descriptor[prog->descriptor_count]=(Descriptor *)malloc(sizeof(Descriptor));
635: prog->descriptor[prog->descriptor_count]->data=NULL;
636: }
637: prog->descriptor[prog->descriptor_count]->tag=desc_tag;
638: prog->descriptor[prog->descriptor_count]->length=desc_length;
639: if (desc_length>0) {
640: if (i+desc_length>n) {
641: if (verbose) printf("ERROR: insufficent data in descriptor %i+%i>=%i\n",i,desc_length,n);
642: if (useCRC) return 0x0704;
643: }
644: prog->descriptor[prog->descriptor_count]->data=(unsigned char *)realloc(prog->descriptor[prog->descriptor_count]->data,desc_length*sizeof(unsigned char));
645: for (j=0; j<desc_length; j++) {
646: prog->descriptor[prog->descriptor_count]->data[j]=ES->Payload[i++];
647: }
648: }
649: prog->descriptor_count++;
650: }
651: PMT->program_count++;
652: i=n;
653: }
654: if (verbose) print_PMT(PMT);
655: if (current_next_indicator && (section_number==last_section_number)) { // our new PMT has completely arrived
656: kill_PMT(&first_PMT,PMT->program_number); // kill outdated PMT
657: ptr=first_PMT; // move PMT from "next" to "current" list
658: if (first_PMT==NULL) {
659: first_PMT=PMT;
660: } else {
661: ptr=first_PMT;
662: while (ptr->next!=NULL) ptr=(ProgramMapTable *)ptr->next;
663: ptr->next=PMT;
664: }
665: if (first_nextPMT==PMT) {
666: first_nextPMT=PMT->next;
667: } else {
668: ptr=first_nextPMT;
669: while (ptr!=NULL) {
670: if ((ptr->next==PMT)) {
671: ptr->next=PMT->next;
672: }
673: ptr=(ProgramMapTable *)ptr->next;
674: }
675: }
676: PMT->next=NULL;
677: }
678:
679: } else if (PSI==4) { // NIT
680: if ((table_id<0x40) || (table_id>0xFE)) {
681: if (verbose) printf("- WRONG Table ID 0x%02X in section, PSI-type=%i!\n",table_id,PSI);
682: if (useCRC) return 0x0304;
683: }
684: if (!private_indicator) {
685: if (verbose) printf("- SYNTAX error in section, PSI-type=%i!\n",PSI);
686: if (useCRC) return 0x0404;
687: }
688: if (verbose) printf("- Network Information Table -\n\n");
689: } else if (verbose) printf("- Internal error, Unknown PSI-id 0x%02X, table_id 0x%02X.\n",PSI,table_id);
690: return 0;
691: }
692:
693:
694: // -------------------------------------------------------------- //
695: // Parsing the TS-packet and calling parse_PSI
696: // or copy PES to stdout, if neccessary.
697: // parse_TP is analyzing one Transport Stream Packet at a time,
698: // then the payload gets either sent to the parse_PSI function
699: // or, if it's a PES, is piped to stdout.
700: // -------------------------------------------------------------- //
701:
702: int parse_TP(
703: FILE* inputstream, // mpeg-2 file
704: int parse, // true: parse false: skip packet
705: int verbose, // true: debug output
706: int pipe, // true: selected PES as binary false: as Hexdump
707: unsigned int select_program, // number of the program to pipe out
708: unsigned int select_stream, // number of the stream in the PMT
709: int useCRC) { // true: ignore CRC of PSI
710:
711: // Return codes:
712: // 0x0000: OK
713: // 0xXXEE: XX: error location EE: error type
714: // 0x0001: unexpected end of file
715: // 0x0002: unexpected end of data
716: // 0x0003: unexpected end of memory
717:
718: // bool evals to true if not 0
719:
720: unsigned char TP[TS_packet_length]; // one Transport Packet, raw
721:
722: ElementaryStream *ES; // current ES
723:
724: TransportStreamProgram *TSP; // current TSP
725:
726: unsigned int PID, // Packet IDentification (13 bits)
727: pointer_field; // Pointer Field (1 byte, used in PSI-packets)
728:
729: AdaptionField *AF; // current Adaption Field
730: unsigned int AFL; // Adaption Field Length
731:
732: int PSI,
733: partlen;
734: unsigned char table_id; // Table ID
735: unsigned int section_length; // Section Length
736:
737: ProgramMapTable *PMT; // current PMT
738:
739: Program *prog; // temp. pointer
740:
741: unsigned int PESprog; // Elementary Stream Program Number
742: unsigned char PEStype; // Elementary Stream Media Type
743: unsigned int PESstream; // Elementary Stream PMT-number
744:
745: int n,i,j,k; // counters
746: unsigned char ch; // single byte
747: int filechar;
748:
749: if (!parse) verbose=0; // skipping
750:
751: // scanning up to 1000 chars for the sync-character 0x47
752: k=1000; i=0;
753: while (((filechar=fgetc(inputstream))!=0x47) && (filechar>=0) && (k--)) {
754: if (verbose) {
755: printf("%02X ",filechar & 0xFF); // looking for sync byte
756: if ((i++ % 24) == 23) printf("\n");
757: }
758: }
759: if (k) {
760: if ((verbose) && (k<1000)) printf("\nSkipped %i byte looking for 0x47\n",1000-k);
761: if (filechar<0) return 0x0001;
762: TP[0]=filechar;
763:
764: // reading the remaining 187 bytes of the 188 byte TP-Packet
765: if (fread(&TP[1],1,TS_packet_length-1,inputstream)!=TS_packet_length-1) return 0x0101;
766:
767: //if (!parse) return 0; // skipping
768:
769: // finding/creating our TSP-structure for this PID
770: PID=((TP[1] & 0x1F) << 8) | (TP[2] & 0xFF);
771: ES=new_ES(PID);
772: if (ES==NULL) return 0x0003; // Insufficient Memory;
773: TSP=ES->TSP;
774: if (TSP==NULL) return 0x0103; // Insufficient Memory;
775:
776: // parsing header parameters into TSP-structure
777: TSP->transport_error_indicator= TP[1] & 0x80;
778: TSP->payload_unit_start_indicator= TP[1] & 0x40;
779: TSP->transport_priority= TP[1] & 0x20;
780: //TSP->PID=((TP[1] & 0x1F) << 8) | (TP[2] & 0xFF); // is already done
781: TSP->transport_scrambling_control=(TP[3] >> 6) & 0x03;
782: TSP->adaption_field_control_1= TP[3] & 0x20;
783: TSP->adaption_field_control_0= TP[3] & 0x10;
784: TSP->previous_cc=TSP->continuity_counter;
785: TSP->continuity_counter= TP[3] & 0x0F;
786:
787: // debugging output
788: if (verbose) print_TP(TSP);
789:
790: if (TSP->transport_error_indicator) {
791: if (verbose) printf("- Broken packet (transport_error_indicator)%s",(useCRC?", skipping...\n":""));
792: if (useCRC) return 0;
793: }
794:
795: if (PID==0x1FFF) { // Null packet
796: if (verbose) printf("- Null packet - %i byte\n\n",TS_packet_length-4);
797: ES->payload_count=0;
798: if (TSP->transport_scrambling_control)
799: if (verbose) printf("- ERROR in transport_scrambling_control of null packet\n");
800: if (!TSP->adaption_field_control_0 || TSP->adaption_field_control_1)
801: if (verbose) printf("- ERROR in adaption_field_control of null packet\n");
802: return 0;
803: }
804:
805: if (!(TSP->adaption_field_control_1 && (TP[5] & 0x80))) { // AF discontinuity_indicator?
806: if (TSP->adaption_field_control_0 && (TSP->continuity_counter==TSP->previous_cc)) {
807: if (verbose) printf("- Duplicate Packet - skipping...\n");
808: return 0;
809: }
810: if (TSP->adaption_field_control_0 && (TSP->continuity_counter!=((TSP->previous_cc+1)&0x0F))) {
811: if (verbose) printf("ERROR: Missing Packet(s): %i\n",(TSP->continuity_counter-TSP->previous_cc)&0x0F);
812: }
813: }
814:
815: // parsing Adaption Field, if any, and storing it into our TSP
816: if (TSP->adaption_field_control_1) { // Adaption Field present
817: AFL=TP[4] & 0xFF;
818: TSP->AF=(AdaptionField *)malloc(sizeof(AdaptionField));
819: if ((AF=TSP->AF)==NULL) return 0x0203;
820: if (AFL) {
821: AF->discontinuity_indicator=TP[5] & 0x80;
822: AF->random_access_indicator=TP[5] & 0x40;
823: AF->elementary_stream_priority_indicator=TP[5] & 0x20;
824: AF->PCR_flag=TP[5] & 0x10;
825: AF->OPCR_flag=TP[5] & 0x08;
826: AF->splicing_point_flag=TP[5] & 0x04;
827: AF->transport_private_data_flag=TP[5] & 0x02;
828: AF->adaption_field_extension_flag=TP[5] & 0x01;
829:
830: n=6; // from here on we don't have static positions anymore
831:
832: if (AF->PCR_flag && ((n+6) <= (AFL+5))) {
833: AF->program_clock_reference_base=TP[n++] & 0x000000FFULL; // Bit 32-25
834: AF->program_clock_reference_base=(AF->program_clock_reference_base << 8) | (TP[n++] & 0x000000FFULL); // Bit 24-17
835: AF->program_clock_reference_base=(AF->program_clock_reference_base << 8) | (TP[n++] & 0x000000FFULL); // Bit 16-9
836: AF->program_clock_reference_base=(AF->program_clock_reference_base << 8) | (TP[n++] & 0x000000FFULL); // Bit 8-1
837: ch=TP[n++];
838: AF->program_clock_reference_base=(AF->program_clock_reference_base << 1) | ((ch >> 7) & 0x00000001ULL); // Bit 0
839: AF->program_clock_reference_extension=ch & 0x01;
840: AF->program_clock_reference_extension=(AF->program_clock_reference_extension << 8) | (TP[n++] & 0xFF);
841: } else if (AF->PCR_flag) return 0x0102;
842:
843: if (AF->OPCR_flag && ((n+6) <= (AFL+5))) {
844: AF->original_program_clock_reference_base=TP[n++] & 0x000000FFULL; // Bit 32-25
845: AF->original_program_clock_reference_base=(AF->original_program_clock_reference_base << 8) | (TP[n++] & 0x000000FFULL); // Bit 24-17
846: AF->original_program_clock_reference_base=(AF->original_program_clock_reference_base << 8) | (TP[n++] & 0x000000FFULL); // Bit 16-9
847: AF->original_program_clock_reference_base=(AF->original_program_clock_reference_base << 8) | (TP[n++] & 0x000000FFULL); // Bit 8-1
848: ch=TP[n++];
849: AF->original_program_clock_reference_base=(AF->original_program_clock_reference_base << 1) | ((ch >> 7) & 0x00000001ULL); // Bit 0
850: AF->original_program_clock_reference_extension=ch & 0x01;
851: AF->original_program_clock_reference_extension=(AF->original_program_clock_reference_extension << 8) | (TP[n++] & 0xFF);
852: } else if (AF->OPCR_flag) return 0x0202;
853:
854: if (AF->splicing_point_flag && (n < (AFL+5))) {
855: AF->splice_countdown=TP[n++] & 0xFF;
856: } else if (AF->splicing_point_flag) return 0x0302;
857:
858: if (AF->transport_private_data_flag && (n < (AFL+5))) {
859: AF->transport_private_data_length=TP[n++] & 0xFF;
860: if (n+AF->transport_private_data_length > AFL) return 0x0402;
861: for (i=0; (i<AF->transport_private_data_length) && (n<AFL); i++) {
862: AF->private_data_byte[i]=TP[n++];
863: }
864: } else if (AF->transport_private_data_flag) return 0x0502;
865:
866: if (AF->adaption_field_extension_flag && (n < (AFL+5))) {
867: AF->adaption_field_extension_length=TP[n++] & 0xFF;
868: if (n+AF->adaption_field_extension_length > (AFL+5)) return 0x0602;
869: ch=TP[n++];
870: AF->ltw_flag=ch & 0x80;
871: AF->piecewise_rate_flag=ch & 0x40;
872: AF->seamless_splice_flag=ch & 0x20;
873: if (AF->ltw_flag) {
874: ch=TP[n++];
875: AF->ltw_valid_flag=ch & 0x80;
876: AF->ltw_offset=((ch & 0x7F) << 8) | (TP[n++] & 0xFF);
877: }
878: if (AF->piecewise_rate_flag) {
879: AF->piecewise_rate=TP[n++] & 0x3F;
880: AF->piecewise_rate=(AF->piecewise_rate << 8) | (TP[n++] & 0xFF);
881: AF->piecewise_rate=(AF->piecewise_rate << 8) | (TP[n++] & 0xFF);
882: }
883: if (AF->seamless_splice_flag) {
884: ch=TP[n++];
885: AF->splice_type=(ch >> 4) & 0x0F;
886: AF->DTS_next_AU=(ch >> 1) & 0x07ULL; // Bit 32-30
887: AF->DTS_next_AU=(AF->DTS_next_AU << 8) | (TP[n++] & 0xFFULL); // Bit 29-22
888: AF->DTS_next_AU=(AF->DTS_next_AU << 7) | ((TP[n++] >> 1) & 0x7FULL); // Bit 21-15
889: AF->DTS_next_AU=(AF->DTS_next_AU << 8) | (TP[n++] & 0xFFULL); // Bit 14-7
890: AF->DTS_next_AU=(AF->DTS_next_AU << 7) | ((TP[n++] >> 1) & 0x7FULL); // Bit 6-0
891: }
892: } else if (AF->adaption_field_extension_flag) return 0x0702;
893:
894: // debugging output
895: if (verbose) {
896: //printf("Adaption Field Length: %i bytes\n",AFL);
897: //for (i=0; i<AFL; i++) {
898: // printf("%02X ",(TP[i+5] & 0xFF));
899: // if (((i % 24)==23) || (i == AFL-1)) printf("\n");
900: //}
901: print_AF(AF);
902: }
903:
904: }
905: AFL++; // AFL includes now the AFL-byte itself
906: } else AFL=0;
907:
908: if (TSP->adaption_field_control_0) { // Payload present
909:
910: n=AFL+4; // offset of Payload in TP[]
911:
912: // determine payload type: PES or PSI?
913: // PSI-type: 0:PES 1:PAT 2:CAT 3:PMT 4:NIT 5:Null -1:Unknown
914: if (PID==0x0000) PSI=1; // is the PSI a PAT?
915: else if (PID==0x0001) PSI=2; // is the PSI a CAT?
916: else if (PID==0x1FFF) PSI=-2; // Null Packet? Already sorted out, but anyhow...
917: else {
918: PSI=-1; // default to Unknown
919: if (PAT!=NULL) {
920: for (i=0; i<PAT->program_count; i++) { // unless the PID is in the current PAT
921: if (PID==PAT->PID[i])
922: PSI=((PAT->program_number[i])?3:4); // Program Number 0 means NIT, otherwise PMT
923: }
924: }
925: if (CAT!=NULL) {
926: for (i=0; i<CAT->descriptor_count; i++) { // PES-PID can be in CAT, too. (ECM and EMM)
927: if (PID==CAT->CA_descriptor[i]->CA_PID) {
928: PSI=0; // ECM or EMM, has to go to the PES-decoder
929: PESprog=0; // Program Number
930: PEStype=0; // Stream Media Type
931: PESstream=0;
932: }
933: }
934: }
935: PMT=first_PMT;
936: while (PMT!=NULL) { // check all current PMT's
937: for (i=0; i<PMT->program_count; i++) { // or the PID is in the current PMT, then it's a PES
938: if (PID==PMT->program[i]->elementary_PID) {
939: PSI=0; // it's a PES
940: PESprog=PMT->program_number; // Program Number
941: PEStype=PMT->program[i]->stream_type; // Stream Media Type
942: PESstream=i+1;
943: }
944: }
945: PMT=(ProgramMapTable *)PMT->next;
946: }
947: }
948:
949: if (PSI<0) { // unknown PSI, let's see if we already guessed the PID
950: if (phantom_PMT!=NULL) {
951: for (i=0; i<phantom_PMT->program_count; i++) { // or the PID is in the current PMT, then it's a PES
952: if (PID==phantom_PMT->program[i]->elementary_PID) {
953: PSI=0; // it's a PES
954: PESprog=phantom_PMT->program_number; // Program Number
955: PEStype=phantom_PMT->program[i]->stream_type; // Stream Media Type
956: PESstream=i+1;
957: if (verbose) printf(" previous GUESS: PES # %i, type 0x%02X\n",PESstream,PEStype);
958: }
959: }
960: }
961: }
962:
963: if (PSI<0) { // unknown PSI, let's try to guess what it might be
964: if (TSP->payload_unit_start_indicator) { // a new payload block, only here we have a chance
965: if ((!TP[n]) && (!TP[n+1]) && (TP[n+2]=0x01)) {
966: PSI=0; // Packet start code prefix, it's a PES
967: PESprog=0xFFFF; // Program Number
968: PEStype=0xFF; // Stream Media Type
969: PESstream=0;
970: if ((TP[n+3] & 0xF0) == 0xE0) {
971: PEStype=0x02; // MPEG-2 Video
972: } else if ((TP[n+3] & 0xE0) == 0xC0) {
973: PEStype=0x04; // MPEG-2 Audio
974: }
975: if (phantom_PMT!=NULL) {
976: prog=phantom_PMT->program[phantom_PMT->program_count];
977: if (prog==NULL) {
978: prog=(Program *)malloc(sizeof(Program));
979: phantom_PMT->program[phantom_PMT->program_count]=prog;
980: prog->descriptor_count=0;
981: for (j=0; j<16; j++) prog->descriptor[j]=NULL;
982: }
983: prog->elementary_PID=PID;
984: prog->stream_type=PEStype;
985: phantom_PMT->program_count++;
986: PESstream=phantom_PMT->program_count;
987: }
988: if (verbose) printf(" GUESS: PES # %i, type 0x%02X\n",PESstream,PEStype);
989: } else {
990: pointer_field=TP[n];
991: if (n+pointer_field+1<TS_packet_length) {
992: table_id=TP[n+pointer_field+1];
993: if (table_id==0x02) PSI=3; // might be a PMT
994: else if (table_id==0xFF) PSI=5; // might be a Null PSI
995: else if (table_id>=0x40) PSI=4; // might be a NIT
996: if (verbose && (PSI>0)) printf(" GUESS: PSI, %s, table_id 0x%02X\n",((PSI==3)?"PMT":((PSI==4)?"NIT":"Null PSI")),table_id);
997: }
998: }
999: }
1000: }
1001:
1002: if (PSI<0) {
1003: if (verbose) printf("- ERROR packet with Unknown PID.\n");
1004: } else if (PSI) {
1005: pointer_field=((TSP->payload_unit_start_indicator)?TP[n++] & 0xFF:0);
1006: while (n<TS_packet_length) {
1007: if (ES->payload_count>=1) { // this PSI has already started
1008: table_id=ES->Payload[0];
1009: if (ES->payload_count>=2) {
1010: section_length=((ES->Payload[1] << 8) | (TP[n] & 0xFF)) & 0x0FFF;
1011: } else if (ES->payload_count>=3) {
1012: section_length=((ES->Payload[1] << 8) | (ES->Payload[2] & 0xFF)) & 0x0FFF;
1013: } else {
1014: section_length=((TP[n] << 8) | (TP[n+1] & 0xFF)) & 0x0FFF;
1015: }
1016: } else {
1017: table_id=TP[n];
1018: section_length=((TP[n+1] << 8) | (TP[n+2] & 0xFF)) & 0x0FFF;
1019: }
1020: if (table_id==0xFF) { // stuffing bytes
1021: i=n;
1022: while (TP[n]==0xFF) n++;
1023: ES->payload_count=0;
1024: if (verbose) printf("- PSI section - %i stuffing bytes\n",n-i);
1025: } else {
1026: partlen=TS_packet_length-n;
1027: if (partlen+ES->payload_count>section_length+3) partlen=section_length+3-ES->payload_count;
1028: if ((ES->payload_length - ES->payload_count) < partlen) { // we need more memory
1029: ES->Payload=(char *)realloc(ES->Payload,ES->payload_count+partlen);
1030: if (ES->Payload==NULL) return 0x0203;
1031: ES->payload_length=ES->payload_count+partlen;
1032: }
1033: for (i=0; i<partlen; i++) {
1034: ES->Payload[ES->payload_count++]=TP[n++];
1035: //if (verbose) {
1036: // printf("- Payload - for PID 0x%04X (PSI) now %i byte\n",PID,ES->payload_count);
1037: // for (i=0; i<ES->payload_count; i++) {
1038: // printf("%02X ",(ES->Payload[i] & 0xFF));
1039: // if ((i % 24)==23) printf("\n");
1040: // }
1041: // printf("\n");
1042: //}
1043: }
1044: if (ES->payload_count>=section_length+3) { // section complete
1045: parse_PSI(ES,PSI,verbose,useCRC);
1046: ES->payload_count=0; // PSI done, dispose.
1047: } else {
1048: if (verbose) printf("Incomplete PSI section, appending %i byte to buffer, now %i byte.\n",partlen,ES->payload_count);
1049: }
1050: }
1051: }
1052:
1053: } else if (parse) {
1054: if (verbose || !pipe) {
1055: if (verbose || ((select_program==PESprog) && (select_stream==PESstream))) {
1056: printf("PES packet:\nProgram: 0x%04X\nStream: %i\nType: 0x%02X\n",PESprog,PESstream,PEStype);
1057: printf("- PES fragment - %i byte\n",TS_packet_length-n);
1058: for (i=0; i<TS_packet_length-n; i++) {
1059: printf("%02X ",(TP[n+i] & 0xFF));
1060: if ((i % 24)==23) printf("\n");
1061: }
1062: printf("\n");
1063: }
1064: } else if (pipe && ((select_program==PESprog) && (select_stream==PESstream))) {
1065: while (n<TS_packet_length) putchar(TP[n++]); // ... und dafuer der ganze Aufwand.
1066: }
1067: }
1068: }
1069: if (verbose) printf("\n");
1070: }
1071: return 0;
1072: }
1073:
1074: char *StreamType(unsigned char stream_type) {
1075: if (stream_type==0x00) return "ITU-T | ISO/IEC reserved";
1076: else if (stream_type==0x01) return "ISO/IEC 11172-2 Video";
1077: else if (stream_type==0x02) return "ITU-T Rec. H.262 | ISO/IEC 13818-2 Video";
1078: else if (stream_type==0x03) return "ISO/IEC 11172-3 Audio";
1079: else if (stream_type==0x04) return "ISO/IEC 13818-3 Audio";
1080: else if (stream_type==0x05) return "ITU-T Rec. H.222.0 | ISO/IEC 13818-1 private_sections";
1081: else if (stream_type==0x06) return "ITU-T Rec. H.222.0 | ISO/IEC 13818-3 PES private data";
1082: else if (stream_type==0x07) return "ISO/IEC 13522 MHEG";
1083: else if (stream_type==0x08) return "DSM CC";
1084: else if (stream_type==0x09) return "ITU-T Rec. H.222.1";
1085: else if (stream_type==0x0A) return "ISO/IEC 13818-6 Type A";
1086: else if (stream_type==0x0B) return "ISO/IEC 13818-6 Type B";
1087: else if (stream_type==0x0C) return "ISO/IEC 13818-6 Type C";
1088: else if (stream_type==0x0D) return "ISO/IEC 13818-6 Type D";
1089: else if (stream_type==0x0E) return "ISO/IEC 13818-1 auxiliary";
1090: else if (stream_type>=0x80) return "User private";
1091: else return "ITU-T Rec. H.222.0 | ISO/IEC 13818-1 reserved";
1092: }
1093:
1094:
1095: // -------------------------------------------------------------- //
1096: // main: opening file and repeat calling parse_TP
1097: // -------------------------------------------------------------- //
1098:
1099: int main (int argc, char* argv[]) {
1100:
1101: FILE* inputstream;
1102: int i,j,filearg,startpacket,stoppacket,err,verbose,pipe,useCRC;
1103: unsigned int prog,stream;
1104: char buf[256];
1105:
1106: ProgramMapTable *PMT; // current PMT
1107:
1108: i=1;
1109: filearg=0;
1110: prog=0;
1111: stream=0;
1112: verbose=0;
1113: pipe=0;
1114: startpacket=0;
1115: stoppacket=0;
1116: useCRC=0;
1117: while (i<argc) {
1118: if (argv[i][0]=='-') { // option
1119: if (argv[i][1]=='v') verbose=1; // verbose on
1120: else if (argv[i][1]=='p') pipe=1; // pipe on
1121: else if (argv[i][1]=='c') useCRC=1; // CRC on
1122: else if (argv[i][1]=='s') { // select a program
1123: i++;
1124: for (j=0; (j<strlen(argv[i])) && (argv[i][j]!='/'); j++);
1125: if (j<strlen(argv[i])) {
1126: prog=atoi(strncpy(buf,argv[i],j));
1127: stream=atoi(strcpy(buf,&argv[i][j+1]));
1128: }
1129: } else { // unknown option
1130: printf("\
1131: Usage: %s [-v] [-p] [-c] [-s <prog>/<stream>] [<file> [<first packet> <last packet> | <packet>]]\n\
1132: -v: verbose on\n\
1133: -p: pipe on (only raw output)\n\
1134: -c: use CRC on PSI\n\
1135: -s <prog>/<stream>: show/pipe only the <stream>th PES-stream of program <prog>\n\
1136: ",argv[0]);
1137: }
1138: } else if (!filearg) filearg=i;
1139: else if (!startpacket) startpacket=atoi(argv[i]);
1140: else if (!stoppacket) stoppacket=atoi(argv[i]);
1141: i++;
1142: }
1143:
1144: if (filearg) {
1145: if ((inputstream=fopen(argv[filearg],"r"))==NULL) {
1146: printf("Couldn't open file %s\n",argv[1]);
1147: exit (0);
1148: }
1149: } else inputstream=stdin;
1150:
1151: gen_crc32_table();
1152:
1153: if (startpacket) {
1154: if (!stoppacket) stoppacket=startpacket;
1155: } else stoppacket=-1;
1156:
1157: current_PAT=(ProgramAssociationTable *)malloc(sizeof(ProgramAssociationTable));
1158: next_PAT=(ProgramAssociationTable *)malloc(sizeof(ProgramAssociationTable));
1159: PAT=NULL;
1160: current_PAT->program_count=0;
1161: next_PAT->program_count=0;
1162:
1163: current_CAT=(ConditionalAccessTable *)malloc(sizeof(ConditionalAccessTable));
1164: next_CAT=(ConditionalAccessTable *)malloc(sizeof(ConditionalAccessTable));
1165: CAT=NULL;
1166: current_CAT->descriptor_count=0;
1167: for (i=0; i<256; i++) current_CAT->CA_descriptor[i]=NULL;
1168: next_CAT->descriptor_count=0;
1169: for (i=0; i<256; i++) next_CAT->CA_descriptor[i]=NULL;
1170:
1171: phantom_PMT=(ProgramMapTable *)malloc(sizeof(ProgramMapTable)); // PMT for guessed channels
1172: phantom_PMT->program_number=0xFFFF;
1173: phantom_PMT->program_count=0;
1174:
1175: err=0;
1176: for (i=0; ((stoppacket<0) || (i<stoppacket)) && (err==0); i++) {
1177: if ((startpacket<=(i+1)) && verbose) printf("--- Packet %i --- %ld\n",i+1,ftell(inputstream));
1178: err=parse_TP(inputstream,(startpacket<=(i+1)),verbose,pipe,prog,stream,useCRC);
1179: }
1180: if (err && verbose) printf("\nError in packet %i at %ld: 0x%04X (%s)\n",i,ftell(inputstream),err,(((err & 0xFF)==0x01)?"End of File":(((err & 0xFF)==0x02)?"Data Format Error":"Unknown Error")));
1181:
1182: if (!pipe) {
1183: if (PAT!=NULL) {
1184: printf("Transport stream ID: 0x%04X\n",PAT->transport_stream_id);
1185: if (PAT->program_count>0) {
1186: printf(" Contains %i Program%s:\n",PAT->program_count,((PAT->program_count==1)?"":"s"));
1187: for (i=0; i<PAT->program_count; i++) {
1188: printf(" %i\n",PAT->program_number[i]);
1189: }
1190: }
1191: }
1192: PMT=first_PMT;
1193: while (PMT!=NULL) {
1194: printf(" Program %i with %i stream%s\n",PMT->program_number,PMT->program_count,((PMT->program_count==1)?"":"s"));
1195: for (i=0; i<PMT->descriptor_count; i++) {
1196: printf(" ");
1197: show_descriptor(PMT->descriptor[i],0);
1198: }
1199: for (i=0; i<PMT->program_count; i++) {
1200: printf(" Stream %i, Type: %s (0x%02X)\n",
1201: i+1,
1202: StreamType(PMT->program[i]->stream_type),
1203: PMT->program[i]->stream_type);
1204: for (j=0; j<PMT->program[i]->descriptor_count; j++) {
1205: printf(" ");
1206: show_descriptor(PMT->program[i]->descriptor[j],0);
1207: }
1208: }
1209: PMT=(ProgramMapTable *)PMT->next;
1210: }
1211: }
1212: fclose(inputstream);
1213:
1214: return 0;
1215: }
LinuxTV legacy CVS <linuxtv.org/cvs>