├── README.md ├── Release └── TSdecode.exe ├── TSdecode.cpp ├── menu.cpp ├── misc.cpp └── setup.h /README.md: -------------------------------------------------------------------------------- 1 | # ts-packet-anlayser 2 | Decode MPEG-2 transport streams 3 | http://www.pjdaniel.org.uk/mpeg/ 4 | 5 | Usage: 6 | ``` 7 | TSDECODE -i of TS file to decode 8 | -p 9 | -q do not show progress when extracting 10 | ``` 11 | Example: TSDECODE -ic:\test.mpg -p600 12 | will open file c:\test.mpg and process PID 600 packets 13 | 14 | 15 | Automatically exported from code.google.com/p/ts-packet-anlayser 16 | -------------------------------------------------------------------------------- /Release/TSdecode.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniep01/ts-packet-anlayser/fcca88b4b00cb3c4de2ffedf80c1c6457382a787/Release/TSdecode.exe -------------------------------------------------------------------------------- /TSdecode.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | TSdecode.cpp 3 | Decode MPEG-2 transport streams 4 | Peter Daniel, Final year project 2000/2001 5 | */ 6 | 7 | #include "setup.h" // prototype functions 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | char version[] = "1.00"; // current version number 16 | unsigned int current_header_add = 0; // add of header being decoded/displayed 17 | int index = 0; // index for found PID table 18 | unsigned int search_PID = 0; // PID value to search for, from command line 19 | long int payload_start = 0; // add of payload start when found 20 | long ip_file_length = 0; // how long? 21 | char *ip_filepath; // from command line 22 | int quite_mode = 0; // display progress when extracting? yes/no 23 | int sync_bytes[10]; // array of where the sync_bytes are found 24 | int end_of_file = 0; // check for end of file 25 | unsigned char TS_raw_header[4]; // 4 byte space to read data from file 26 | unsigned char adaption_field_length; 27 | 28 | struct found_packet 29 | { 30 | struct found_packet *next_ptr; // linked list, pointer to address of next list 31 | int index; 32 | unsigned int header_address; 33 | unsigned int payload_address; 34 | unsigned char payload_start_indicator; 35 | unsigned int PID; 36 | unsigned char continuity_counter; 37 | } ; 38 | 39 | struct found_packet *new_item_ptr = NULL; // pointer for new list 40 | struct found_packet *first_ptr = NULL; // pointer for first list 41 | struct found_packet *last_ptr = NULL; // pointer for last list 42 | 43 | struct TS_header 44 | { 45 | unsigned char sync_byte; 46 | unsigned char transport_error_indicator; 47 | unsigned char payload_start_indicator; 48 | unsigned char transport_priority; 49 | unsigned int PID; 50 | unsigned char transport_scrambling_control; 51 | unsigned char adaption_field_control; 52 | unsigned char continuity_counter; 53 | } TS_header; 54 | 55 | FILE *ip_file; 56 | FILE *op_pid_table_file; 57 | FILE *op_pes_file; 58 | 59 | long get_ip_file_length(char *ip_filepath) 60 | { 61 | // find length of file 62 | 63 | int ip_file2 = 0; 64 | ip_file2 = _open( ip_filepath, _O_RDONLY ); 65 | if( ip_file2 == -1 ) 66 | { 67 | exit_prog("Error: cannot open input file"); 68 | } 69 | ip_file_length = _filelength(ip_file2); 70 | _close( ip_file2 ); 71 | return ip_file_length; 72 | } 73 | 74 | void file_seek(int offset) 75 | { 76 | // seek forward offset bytes, checking for end of file 77 | // needed because fseek can look beyond the end of the file without reporting an error. 78 | if ( ftell(ip_file) + (offset + 200) > ip_file_length ) 79 | { 80 | end_of_file = 1; 81 | // press_key("End of file"); 82 | } 83 | else 84 | fseek(ip_file, offset, 1); 85 | } 86 | 87 | 88 | int main(int argc, char *argv[]) 89 | { 90 | 91 | puts ("MPEG-2 decoder : TSdecode.exe"); 92 | printf("Peter Daniel Version : %s \n", version); 93 | puts ("=============================\n"); 94 | 95 | if (argc == 1) 96 | { display_usage(); 97 | exit_prog(""); } 98 | 99 | while ((argc > 1) && (argv[1][0] == '-')) { 100 | switch (argv[1][1]) { 101 | case 'i': 102 | ip_filepath = &argv[1][2]; 103 | break; 104 | case 'p': 105 | search_PID = atoi(&argv[1][2]); 106 | break; 107 | case 'q': 108 | quite_mode = 1; 109 | break; 110 | default: 111 | printf("Bad option %s\n", argv[1]); 112 | display_usage(); 113 | exit_prog(""); 114 | } 115 | ++argv; 116 | --argc; 117 | } 118 | 119 | 120 | ip_file_length = get_ip_file_length(ip_filepath); 121 | printf("Opening MPEG-2 file %s, %d bytes.\n", ip_filepath, ip_file_length); 122 | printf("Search PID : %d", search_PID); 123 | ip_file = fopen(ip_filepath, "rb"); 124 | 125 | char menu_choice = 0; 126 | 127 | find_TS_sync_byte(); // synchronise to sync_bytes 128 | // display_sync_byte_table(); // display location of sync_bytes 129 | puts("\n5 occurances of Transport Stream sync_byte 0x47 found ok.\n"); 130 | fseek(ip_file, sync_bytes[1], 0); // go back to first sync_byte 131 | menu_choice = menu(); // display menu options 132 | switch (menu_choice) // decode menu choice 133 | { 134 | case '1' : // TS header decode 135 | menu_option1(); 136 | break; 137 | case '2' : // PID address table 138 | menu_option2(); 139 | break; 140 | case '3' : // Save PID address table 141 | menu_option3(); 142 | break; 143 | case '4' : // Extract PES 144 | menu_option4(); 145 | break; 146 | case '5' : // exit 147 | exit_prog(""); 148 | break; 149 | default: 150 | puts("\nERROR : Not a valid menu entry."); 151 | } 152 | exit_prog(""); 153 | return 0; 154 | } 155 | 156 | 157 | 158 | 159 | void TS_header_decode() 160 | { 161 | // printf("\nSize of TS-header: %dbytes", sizeof(TS_raw_header)); 162 | current_header_add = ftell(ip_file); 163 | fread(&TS_raw_header, sizeof(TS_raw_header), 1, ip_file); // read the header 164 | // for (count=0; count <=sizeof(TS_raw_header); count++) 165 | // printf("\nByte %d: \t \t x%x",count, TS_raw_header[count]); 166 | // use bit masking and shifting to get the data we want from header 167 | TS_header.sync_byte = TS_raw_header[0]; 168 | TS_header.transport_error_indicator = (TS_raw_header[1] & 0x80) >> 7; 169 | TS_header.payload_start_indicator = (TS_raw_header[1] & 0x40) >> 6; 170 | TS_header.transport_priority = (TS_raw_header[1] & 0x20) >> 5; 171 | TS_header.PID = ((TS_raw_header[1] & 31) << 8) | TS_raw_header[2]; 172 | TS_header.transport_scrambling_control = (TS_raw_header[3] & 0xC0); 173 | TS_header.adaption_field_control = (TS_raw_header[3] & 0x30) >> 4; 174 | TS_header.continuity_counter = (TS_raw_header[3] & 0xF); 175 | } 176 | 177 | void add_found_packet(void) 178 | { // save found packets in an linked list 179 | struct found_packet *new_item_ptr = NULL; 180 | // create a new structure if there is enough memory 181 | if (( new_item_ptr = (struct found_packet* ) malloc(sizeof(struct found_packet))) == NULL) 182 | { 183 | exit_prog("FATAL ERROR : out of memory!"); 184 | } 185 | new_item_ptr->index = index; 186 | new_item_ptr->header_address = current_header_add; 187 | new_item_ptr->payload_address = current_header_add + 4; 188 | new_item_ptr->PID = TS_header.PID; 189 | new_item_ptr->continuity_counter = TS_header.continuity_counter; 190 | new_item_ptr->payload_start_indicator = TS_header.payload_start_indicator; 191 | 192 | new_item_ptr->next_ptr = NULL; 193 | if ( first_ptr == NULL ) first_ptr = new_item_ptr; 194 | else last_ptr->next_ptr = new_item_ptr; 195 | last_ptr = new_item_ptr; 196 | index ++; 197 | } 198 | 199 | void find_TS_sync_byte(void) 200 | { // scan file looking for sync_bytes 201 | int sync_data = 0; // storage for data read from file 202 | int occurance = 0; // keep track of how many sync_bytes have been found 203 | long int current_file_pos = 0; // where are we? 204 | 205 | while ( !feof(ip_file) && occurance < 6) 206 | { 207 | current_file_pos = ftell(ip_file); 208 | sync_data = 0; 209 | fread(&sync_data, 1, 1, ip_file); 210 | switch (sync_data) 211 | { // if sync_byte is found then remember it in sync_bytes[] 212 | case 0x47 : 213 | sync_bytes[occurance] = current_file_pos; 214 | occurance++; 215 | file_seek(187); // look for next one 216 | break; 217 | 218 | default : // if byte is not equal to 0x47 219 | occurance = 0; 220 | } 221 | } 222 | if ( occurance < 6 ) 223 | { // report error if 5 cannot be found 224 | exit_prog("Error: End of file reached before 5 sync_bytes found."); 225 | } 226 | } 227 | 228 | void display_sync_byte_table() 229 | { // display information about sync_bytes 230 | int count; 231 | printf("\nTransport packet sync bytes found:"); 232 | printf("\nOccurance \t Address"); 233 | for (count=0; count < 6; count++) 234 | printf("\n %d \t\t x%x", count, sync_bytes[count]); 235 | } 236 | 237 | void save_pid_table(void) 238 | { 239 | struct found_packet *current_ptr = NULL; 240 | current_ptr = first_ptr; 241 | while ( current_ptr != NULL ) 242 | { 243 | fprintf(op_pid_table_file, "d%d \t x%x \t x%x \t d%d \t d%d \t d%d\n", 244 | current_ptr->index, 245 | current_ptr->header_address, 246 | current_ptr->payload_address, 247 | current_ptr->PID, 248 | current_ptr->continuity_counter, 249 | current_ptr->payload_start_indicator); 250 | current_ptr = current_ptr->next_ptr; 251 | } 252 | fclose(op_pid_table_file); 253 | } 254 | 255 | void display_pid_table(void) 256 | { // display list of found PID's and addresses etc 257 | 258 | puts("\n\nIndex \t Payload Add \t Header Add \t PID \t Cont \t Payload"); 259 | puts("================================================================\n"); 260 | 261 | struct found_packet *current_ptr = NULL; 262 | 263 | current_ptr = first_ptr; 264 | while ( current_ptr != NULL ) 265 | { 266 | printf("d%d \t x%x \t x%x \t d%d \t d%d \t d%d\n", 267 | current_ptr->index, 268 | current_ptr->header_address, 269 | current_ptr->payload_address, 270 | current_ptr->PID, 271 | current_ptr->continuity_counter, 272 | current_ptr->payload_start_indicator); 273 | current_ptr = current_ptr->next_ptr; 274 | } 275 | } 276 | 277 | 278 | void display_transport_header(void) 279 | { // display the TS header and add extra info 280 | printf("\nHeader address: \t x%x \t d%d",current_header_add, current_header_add); 281 | printf("\nSync byte: \t \t x%x",TS_header.sync_byte); 282 | printf("\t should be x47"); 283 | printf("\nError indicator: \t d%d",TS_header.transport_error_indicator); 284 | printf("\nPayload start: \t \t d%d",TS_header.payload_start_indicator); 285 | if (TS_header.payload_start_indicator == 0x1) 286 | printf("\t Payload is start of PID %d", TS_header.PID); 287 | printf("\nTans priority: \t \t d%d",TS_header.transport_priority); 288 | printf("\nPID: \t \t x%x \t d%d",TS_header.PID, TS_header.PID); 289 | printf("\nScrambling: \t \t d%d",TS_header.transport_scrambling_control); 290 | if (TS_header.transport_scrambling_control == 0x0) 291 | printf("\t not scrambled"); 292 | printf("\nAdaption: \t \t d%d",TS_header.adaption_field_control); 293 | if (TS_header.adaption_field_control == 0x01) 294 | { printf("\t no adaption field, payload only"); } 295 | if (TS_header.adaption_field_control == 0x02) 296 | { printf("\t adaption field only, no payload"); 297 | adaption_field(); } 298 | if (TS_header.adaption_field_control == 0x03) 299 | { printf("\t adaption field followed by payload"); 300 | adaption_field(); } 301 | printf("\nContinuity: \t \t d%d",TS_header.continuity_counter); 302 | } 303 | 304 | void adaption_field(void) 305 | { // find length of the adaption field 306 | 307 | fread(&adaption_field_length, sizeof(adaption_field_length), 1, ip_file); 308 | printf("\nAdaption length: \t d%d \t bytes", adaption_field_length); 309 | // return file pointer 310 | fseek (ip_file, -1, 1); 311 | } 312 | 313 | 314 | void menu_option1() 315 | { 316 | while ( end_of_file == 0 ) 317 | { 318 | TS_header_decode(); 319 | if (TS_header.PID == search_PID) 320 | { 321 | display_transport_header(); 322 | press_key("\nPress a key for next header or Control-C to exit.\n"); 323 | } 324 | file_seek(184); 325 | } 326 | puts("ERROR : End of file reached"); 327 | } 328 | 329 | void menu_option2(void) 330 | { 331 | printf("Looking for payload start of PID %d...", search_PID); 332 | int payload_start_found = 0; 333 | 334 | while ( end_of_file==0 ) 335 | { 336 | TS_header_decode(); 337 | if (TS_header.PID == search_PID) 338 | { 339 | if ( payload_start_found == 0 && TS_header.payload_start_indicator == 1) 340 | { 341 | payload_start = ftell(ip_file); 342 | printf("\nPayload start found, header add: x%x", current_header_add); 343 | payload_start_found = 1; 344 | } 345 | 346 | if ( payload_start_found == 1 ) 347 | { 348 | add_found_packet(); 349 | // display_transport_header(); 350 | display_pid_table(); 351 | press_key("\nPress a key for next PID or Control-C to exit.\n"); 352 | } 353 | } 354 | 355 | file_seek(184); 356 | } 357 | puts("\nERROR : End of file reached"); 358 | } 359 | 360 | void menu_option3() 361 | { 362 | printf("Looking for payload start of PID %d...", search_PID); 363 | int payload_start_found = 0; 364 | char op_pid_table_filepath[1024]; 365 | 366 | while ( end_of_file == 0 ) 367 | { 368 | TS_header_decode(); 369 | if (TS_header.PID == search_PID) 370 | { 371 | if ( payload_start_found == 0 && TS_header.payload_start_indicator == 1) 372 | { 373 | payload_start = ftell(ip_file); 374 | printf("\nPayload start found at: %x", current_header_add); 375 | printf("\nScanning the entire file... (may take some time)"); 376 | payload_start_found = 1; 377 | } 378 | if ( payload_start_found == 1 ) 379 | { 380 | add_found_packet(); 381 | } 382 | } 383 | file_seek(184); 384 | } 385 | display_pid_table(); 386 | puts("Enter a filepath to save this table:"); 387 | scanf("%s", op_pid_table_filepath); 388 | if (( op_pid_table_file = fopen(op_pid_table_filepath, "w")) == NULL) 389 | { 390 | exit_prog("ERROR : File cannot be created"); 391 | } 392 | fputs("Table showing PID address", op_pid_table_file); 393 | fputs("\nCreated by TSdecode from ", op_pid_table_file); 394 | fputs(ip_filepath, op_pid_table_file); 395 | fputs("\n\nIndex \t Payload Add \t Header Add \t PID \t Cont \t Payload", op_pid_table_file); 396 | fputs("\n================================================================\n", op_pid_table_file); 397 | save_pid_table(); 398 | printf("This table has been saved as %s.\n", op_pid_table_filepath); 399 | } 400 | 401 | void menu_option4() 402 | { 403 | int count = 0; 404 | int payload_add = 0; 405 | int next_packet = 0; 406 | int payload_start_found = 0; 407 | char op_pes_filepath[1024]; 408 | 409 | printf("Enter a filepath to extract the PES of PID %d to:\n", search_PID); 410 | scanf("%s", op_pes_filepath); 411 | if (( op_pes_file = fopen(op_pes_filepath, "wb")) == NULL) 412 | { 413 | exit_prog("ERROR : File cannot be created"); 414 | } 415 | 416 | printf("\nLooking for payload start of PID %d...", search_PID); 417 | 418 | while ( end_of_file == 0 ) 419 | { 420 | int data = 0; // temp space used when copying between files 421 | int loop = 0; // loop counter for copying payload (184 bytes) 422 | 423 | // decode the header 424 | TS_header_decode(); 425 | 426 | if (TS_header.PID == search_PID) 427 | { // loop until payload start is found 428 | if ( payload_start_found == 0 && TS_header.payload_start_indicator == 1) 429 | { 430 | payload_start = ftell(ip_file); 431 | printf("\nPayload start found at: x%x", current_header_add); 432 | printf("\nProcessing..."); 433 | payload_start_found = 1; 434 | // store_found_packet(); 435 | 436 | } 437 | 438 | if ( payload_start_found == 1 ) 439 | { // ie, payload start has been found 440 | 441 | add_found_packet(); // record data about TS header in array found_packets[] 442 | next_packet = last_ptr->continuity_counter; 443 | 444 | // check continuity 445 | // printf("\nCurrent packet continuity: %d \nTS header continuity: %d ",next_packet, TS_header.continuity_counter); 446 | // press_key(""); 447 | if (TS_header.continuity_counter != next_packet) 448 | { printf("\nERROR : The continuity count is not correct. \nContinuity count from stream: %d \nExpected: %d ", TS_header.continuity_counter, next_packet); 449 | press_key("\nPress a key to continue or Control C to exit"); 450 | } 451 | 452 | // copy payload to new file 453 | payload_add = ftell(ip_file); 454 | if (quite_mode == 0) 455 | printf("\nSaving payload, start address: x%x \t continuity: d%d", payload_add, TS_header.continuity_counter); 456 | // press_key("... press key"); 457 | for (loop = 0; loop < 184; loop ++) 458 | { // loop for 184 bytes of payload and copy to new file 459 | fread(&data, 1, 1, ip_file); 460 | fwrite(&data, 1, 1, op_pes_file); 461 | } // end of loop 462 | fseek(ip_file, -184, 1); // move back because next header will probably have a different PID 463 | 464 | 465 | next_packet = ++ next_packet %16; 466 | 467 | } 468 | } 469 | file_seek(184); // next header 470 | // printf("Current location: x%x", ftell(ip_file)); 471 | // printf("payload_add: x%x", payload_add); 472 | // press_key(""); 473 | } 474 | printf("\nPES stream with PID %d extracted from %s and saved as %s.",search_PID, ip_filepath, op_pes_filepath); 475 | printf("\nEnd of source file, %s.\n", ip_filepath); 476 | press_key("Press a key..."); 477 | fclose(op_pes_file); 478 | } 479 | -------------------------------------------------------------------------------- /menu.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | TSdecode - menu.cpp 3 | Decode MPEG-2 transport streams 4 | Peter Daniel, Final year project 2000/2001 5 | */ 6 | 7 | 8 | #include 9 | 10 | unsigned int menu(void) 11 | { // put menu on screen 12 | char menu_choice; 13 | puts("Menu:"); 14 | 15 | puts("1 - TS header decode"); 16 | puts("2 - Display table of PID addresses"); 17 | puts("3 - Create text file of PID addresses"); 18 | puts("4 - Extract a PES stream to another file"); 19 | puts("5 - Exit"); 20 | // ask for input 21 | puts("\nEnter choice:"); 22 | scanf("%s", &menu_choice); 23 | // return the input 24 | return menu_choice; 25 | } -------------------------------------------------------------------------------- /misc.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | TSdecode - misc.cpp 3 | Decode MPEG-2 transport streams 4 | Peter Daniel, Final year project 2000/2001 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | void press_key(char press_key_text[]) 12 | { // wait for a key press 13 | printf("%s", press_key_text); 14 | while ( !_kbhit() ) 15 | {;} 16 | _getch(); 17 | } 18 | 19 | void display_usage(void) 20 | { 21 | puts("Usage:\t TSDECODE -i of TS file to decode"); 22 | puts("\t \t -p"); 23 | puts("\t \t -q do not show progress when extracting"); 24 | 25 | puts("\nExample: TSDECODE -ic:\\test.mpg -p600"); 26 | puts("\t will open file c:\\test.mpg and process PID 600 packets\n"); 27 | 28 | } 29 | 30 | void exit_prog(char error_msg[]) 31 | { 32 | printf("\n%s\n", error_msg); 33 | _fcloseall( ); 34 | press_key("Press a key to exit..."); 35 | exit(0); 36 | } -------------------------------------------------------------------------------- /setup.h: -------------------------------------------------------------------------------- 1 | /* 2 | TSdecode - setup.h 3 | Decode MPEG-2 transport streams 4 | Peter Daniel, Final year project 2000/2001 5 | */ 6 | 7 | // Prototype functions 8 | 9 | // TSdecode.cpp 10 | void display_sync_byte_table(void); 11 | void find_TS_sync_byte(void); 12 | void TS_header_decode(void); 13 | void display_transport_header(void); 14 | void display_pid_table(void); 15 | void add_found_packet(void); 16 | unsigned int menu(void); 17 | void adaption_field(void); 18 | void file_seek(int offset); 19 | void save_pid_table(void); 20 | void menu_option1(void); 21 | void menu_option2(void); 22 | void menu_option3(void); 23 | void menu_option4(void); 24 | long get_ip_file_length(char ip_filepath[]); 25 | 26 | // menu.cpp 27 | unsigned int menu(void); 28 | 29 | // misc.cpp 30 | void press_key(char press_key_text[]); 31 | void display_usage(void); 32 | void exit_prog(char error_msg[]); 33 | --------------------------------------------------------------------------------