├── 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 |
--------------------------------------------------------------------------------