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