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