Annotation of multiplexer/pes2es.c, revision 1.2
1.1 oskar 1: /*
2: * read packetised elementary stream
3: * Copyright (C) 1999-2004 Christian Wolff
4: *
5: * This program is free software; you can redistribute it and/or modify
6: * it under the terms of the GNU General Public License as published by
7: * the Free Software Foundation; either version 2 of the License, or
8: * (at your option) any later version.
9: *
10: * This program is distributed in the hope that it will be useful,
11: * but WITHOUT ANY WARRANTY; without even the implied warranty of
12: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13: * GNU General Public License for more details.
14: *
15: * You should have received a copy of the GNU General Public License
16: * along with this program; if not, write to the Free Software
17: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18: */
19:
1.2 ! oskar 20: #include <stdint.h>
1.1 oskar 21: #include "pes2es.h"
22: #include "crc16.h"
23:
24: PES_header *PES;
25:
26: unsigned short CRC;
27:
28: void print_PES(PES_header *PES) { // debug output of PES-Header
29: int i;
30: printf("- PES Header -\n\
31: stream_id: 0x%02X\n\
32: PES_packet_length: %i\n",
33: PES->stream_id,
34: PES->PES_packet_length);
35: if (
36: (PES->stream_id!=padding_stream_id) &&
37: (PES->stream_id!=private_stream_2_id) &&
38: (PES->stream_id!=ECM_stream_id) &&
39: (PES->stream_id!=EMM_stream_id) &&
40: (PES->stream_id!=DSMCC_stream_id) &&
41: (PES->stream_id!=ITU_E_id) &&
42: (PES->stream_id!=program_stream_directory_id)) {
43: printf("\
44: PES_scrambling_control: %i\n\
45: PES_priority: %i\n\
46: data_alignment_indicator: %i\n\
47: copyright: %i\n\
48: original_or_copy: %i\n\
49: PTS_flag: %i\n\
50: DTS_flag: %i\n\
51: ESCR_flag: %i\n\
52: ES_rate_flag: %i\n\
53: DSM_trick_mode_flag: %i\n\
54: additional_copy_info_flag: %i\n\
55: PES_CRC_flag: %i\n\
56: PES_extension_flag: %i\n\
57: PES_header_data_length: %i\n",
58: PES->PES_scrambling_control,
59: ((PES->PES_priority)?1:0),
60: ((PES->data_alignment_indicator)?1:0),
61: ((PES->copyright)?1:0),
62: ((PES->original_or_copy)?1:0),
63: ((PES->PTS_flag)?1:0),
64: ((PES->DTS_flag)?1:0),
65: ((PES->ESCR_flag)?1:0),
66: ((PES->ES_rate_flag)?1:0),
67: ((PES->DSM_trick_mode_flag)?1:0),
68: ((PES->additional_copy_info_flag)?1:0),
69: ((PES->PES_CRC_flag)?1:0),
70: ((PES->PES_extension_flag)?1:0),
71: PES->PES_header_data_length);
72: if (PES->PTS_flag) {
73: printf("\
74: PTS: %lld\n",
75: PES->PTS);
76: if (PES->DTS_flag) {
77: printf("\
78: DTS: %lld\n",
79: PES->DTS);
80: }
81: }
82: if (PES->ESCR_flag) {
83: printf("\
84: ESCR_base: %lld\n\
85: ESCR_extension: %d\n",
86: PES->ESCR_base,
87: PES->ESCR_extension);
88: }
89: if (PES->ES_rate_flag) {
90: printf("\
91: ES_rate: %i (%i bytes/sec)\n",
92: PES->ES_rate,PES->ES_rate*50);
93: }
94: if (PES->DSM_trick_mode_flag) {
95: printf("\
96: trick_mode_control: 0x%02X\n",
97: PES->trick_mode_control);
98: }
99: if (PES->additional_copy_info_flag) {
100: printf("\
101: additional_copy_info: 0x%02X\n",
102: PES->additional_copy_info);
103: }
104: if (PES->PES_CRC_flag) {
105: printf("\
106: previous_PES_packet_CRC: 0x%04X\n",
107: PES->previous_PES_packet_CRC);
108: }
109: if (PES->PES_extension_flag) {
110: printf("\
111: PES_private_data_flag %i\n\
112: pack_header_field_flag %i\n\
113: program_packet_sequence_counter_flag %i\n\
114: P_STD_buffer_flag %i\n\
115: PES_extension_flag_2 %i\n",
116: ((PES->PES_private_data_flag)?1:0),
117: ((PES->pack_header_field_flag)?1:0),
118: ((PES->program_packet_sequence_counter_flag)?1:0),
119: ((PES->P_STD_buffer_flag)?1:0),
120: ((PES->PES_extension_flag_2)?1:0));
121: if (PES->PES_private_data_flag) {
122: for (i=0; i<128; i++) {
123: printf("%02X ",PES->PES_private_data[i] & 0xFF);
124: if ((i % 24)==23) printf("\n");
125: }
126: printf("\n");
127: }
128: if (PES->pack_header_field_flag) {
129: printf("\
130: pack_field_length %i\n",
131: PES->pack_field_length);
132: }
133: if (PES->program_packet_sequence_counter_flag) {
134: printf("\
135: program_packet_sequence_counter %i\n\
136: MPEG1_MPEG2_identifier %i\n\
137: original_stuff_length %i\n",
138: PES->program_packet_sequence_counter,
139: ((PES->MPEG1_MPEG2_identifier)?1:0),
140: PES->original_stuff_length);
141: }
142: if (PES->P_STD_buffer_flag) {
143: printf("\
144: P_STD_buffer_scale %i\n\
145: P_STD_buffer_size %i\n",
146: ((PES->P_STD_buffer_scale)?1:0),
147: PES->P_STD_buffer_size);
148: }
149: if (PES->PES_extension_flag_2) {
150: printf("\
151: PES_extension_field_length %i\n",
152: PES->PES_extension_field_length);
153: }
154: }
155: }
156: printf("\n");
157: }
158:
159: int parse_PES(
160: FILE* inputstream, // mpeg-2 file
161: int parse, // true: parse false: skip packet
162: int verbose, // true: debug output
163: int pipe, // true: selected PES as binary false: as Hexdump
164: int useCRC) { // true: ignore CRC of PSI
165:
166: #define fetchchar if((filechar=fgetc(inputstream))<0)return
167:
168: char HD[256];
169:
170: int i,k,n,filechar;
171: unsigned char ch,ch0,ch1,ch2;
172:
173: unsigned int packet_data_length;
174:
175: unsigned int compare;
176: #define sequence_end_code 0x000001B7
177:
178: // scanning for 23 zero bits and a one-bit in up to 1003 bytes
179: fetchchar 0x0101; ch0=filechar;
180: fetchchar 0x0201; ch1=filechar;
181: fetchchar 0x0301; ch2=filechar;
182: k=1000; i=0;
183: while (((ch0) || (ch1) || (ch2!=0x01)) && (k--)) {
184: if (verbose) {
185: printf("%02X ",ch0 & 0xFF);
186: if ((i++ % 24) == 23) printf("\n");
187: }
188: ch0=ch1;
189: ch1=ch2;
190: fetchchar 0x0401; ch2=filechar;
191: }
192:
193: if (k) { // 0x000001 found
194: if ((verbose) && (k<1000)) printf("\nSkipped %i byte looking for 0x000001\n",1000-k);
195:
196: fetchchar 0x0501; PES->stream_id=filechar & 0xFF;
197:
198: //if (verbose) printf("- PES Packet with %i bytes and stream_id 0x%02X\n",PES->PES_packet_length,PES->stream_id);
199:
200: // Padding bytes, ignore
201: if (PES->stream_id==padding_stream_id) {
202: fetchchar 0x0601; ch=filechar;
203: fetchchar 0x0701; PES->PES_packet_length=((ch << 8) | (filechar & 0xFF)) & 0xFFFF;
204: if (verbose) printf("- %i Padding bytes.\n",PES->PES_packet_length);
205: for (i=0; i<PES->PES_packet_length; i++)
206: fetchchar 0x0801;
207: // Direct data, no further header
208: } else if (
209: (PES->stream_id==private_stream_2_id) ||
210: (PES->stream_id==ECM_stream_id) ||
211: (PES->stream_id==EMM_stream_id) ||
212: (PES->stream_id==DSMCC_stream_id) ||
213: (PES->stream_id==ITU_E_id) ||
214: (PES->stream_id==program_stream_directory_id)) {
215: fetchchar 0x0601; ch=filechar;
216: fetchchar 0x0701; PES->PES_packet_length=((ch << 8) | (filechar & 0xFF)) & 0xFFFF;
217: if (verbose) print_PES(PES);
218: if (verbose || !pipe) {
219: printf("- %i Packet data bytes.\n",PES->PES_packet_length);
220: for (i=0; i<PES->PES_packet_length; i++) {
221: fetchchar 0x0901;
222: printf("%02X ",filechar & 0xFF);
223: if ((i % 24)==23) printf("\n");
224: }
225: printf("\n");
226: } else if (pipe) {
227: for (i=0; i<PES->PES_packet_length; i++) {
228: fetchchar 0x0A01;
229: putchar(filechar & 0xFF);
230: }
231: }
232:
233: // PES-Header, parse for subheaders
234: } else if (PES->stream_id>=0xBC) {
235: fetchchar 0x0601; ch=filechar;
236: fetchchar 0x0701; PES->PES_packet_length=((ch << 8) | (filechar & 0xFF)) & 0xFFFF;
237: fetchchar 0x0B01;
238: if ((filechar & 0xC0) != 0x80) {
239: if (verbose) printf("- SYNTAX error (wrong marker bits)\n");
240: if (useCRC) return 0x0104;
241: }
242: PES->PES_scrambling_control=((filechar >> 4) & 0x03);
243: PES->PES_priority=filechar & 0x08;
244: PES->data_alignment_indicator=filechar & 0x04;
245: PES->copyright=filechar & 0x02;
246: PES->original_or_copy=filechar & 0x01;
247: fetchchar 0x0C01;
248: PES->PTS_flag=filechar & 0x80;
249: PES->DTS_flag=filechar & 0x40;
250: PES->ESCR_flag=filechar & 0x20;
251: PES->ES_rate_flag=filechar & 0x10;
252: PES->DSM_trick_mode_flag=filechar & 0x08;
253: PES->additional_copy_info_flag=filechar & 0x04;
254: PES->PES_CRC_flag=filechar & 0x02;
255: PES->PES_extension_flag=filechar & 0x01;
256: fetchchar 0x0D01;
257: PES->PES_header_data_length=filechar & 0xFF;
258:
259: // Read remaining header bytes
260: if (fread(&HD[0],1,PES->PES_header_data_length,inputstream)!=PES->PES_header_data_length) return 0x0E01;
261:
262: // parse subheaders
263: n=0;
264: if (PES->PTS_flag) {
265: if ((HD[n] & 0xF0) != ((PES->DTS_flag)?0x30:0x20)) {
266: if (verbose) printf("- SYNTAX error (wrong marker bits for PTS)\n");
267: if (useCRC) return 0x0204;
268: }
269: PES->PTS=(HD[n++] >> 1) & 0x07ULL; // Bit 32-30
270: PES->PTS=(PES->PTS << 8) | (HD[n++] & 0xFFULL); // Bit 29-22
271: PES->PTS=(PES->PTS << 7) | ((HD[n++] >> 1) & 0x7FULL); // Bit 21-15
272: PES->PTS=(PES->PTS << 8) | (HD[n++] & 0xFFULL); // Bit 14-7
273: PES->PTS=(PES->PTS << 7) | ((HD[n++] >> 1) & 0x7FULL); // Bit 6-0
274: if (PES->DTS_flag) {
275: if ((HD[n] & 0xF0) != 0x10) {
276: if (verbose) printf("- SYNTAX error (wrong marker bits for DTS)\n");
277: if (useCRC) return 0x0304;
278: }
279: PES->DTS=(HD[n++] >> 1) & 0x07ULL; // Bit 32-30
280: PES->DTS=(PES->DTS << 8) | (HD[n++] & 0xFFULL); // Bit 29-22
281: PES->DTS=(PES->DTS << 7) | ((HD[n++] >> 1) & 0x7FULL); // Bit 21-15
282: PES->DTS=(PES->DTS << 8) | (HD[n++] & 0xFFULL); // Bit 14-7
283: PES->DTS=(PES->DTS << 7) | ((HD[n++] >> 1) & 0x7FULL); // Bit 6-0
284: }
285: }
286: if (PES->ESCR_flag) {
287: PES->ESCR_base=(HD[n] >> 3) & 0x07ULL; // Bit 32-30
288: PES->ESCR_base=(PES->ESCR_base << 2) | (HD[n++] & 0x03ULL); // Bit 29-28
289: PES->ESCR_base=(PES->ESCR_base << 8) | (HD[n++] & 0xFFULL); // Bit 27-20
290: PES->ESCR_base=(PES->ESCR_base << 5) | ((HD[n] >> 3) & 0x1FULL); // Bit 19-15
291: PES->ESCR_base=(PES->ESCR_base << 2) | (HD[n++] & 0x03ULL); // Bit 14-13
292: PES->ESCR_base=(PES->ESCR_base << 8) | (HD[n++] & 0xFFULL); // Bit 12-5
293: PES->ESCR_base=(PES->ESCR_base << 5) | ((HD[n] >> 3) & 0x7FULL); // Bit 4-0
294: PES->ESCR_extension=HD[n++] & 0x03; // Bit 8-7
295: PES->ESCR_extension=(PES->ESCR_extension << 7) | ((HD[n++] >> 1) & 0x7F); // Bit 6-0
296: }
297: if (PES->ES_rate_flag) {
298: PES->ES_rate=HD[n++] & 0x7F; // Bit 21-15
299: PES->ES_rate=(PES->ES_rate << 7) | (HD[n++] & 0xFF); // Bit 14-7
300: PES->ES_rate=(PES->ES_rate << 8) | ((HD[n++] >> 1) & 0x7F); // Bit 6-0
301: }
302: if (PES->DSM_trick_mode_flag) {
303: PES->trick_mode_control=HD[n++] & 0xFF;
304: }
305: if (PES->additional_copy_info_flag) {
306: PES->additional_copy_info=HD[n++] & 0x7F;
307: }
308: if (PES->PES_CRC_flag) {
309: PES->previous_PES_packet_CRC=HD[n++] & 0xFF;
310: PES->previous_PES_packet_CRC=(PES->previous_PES_packet_CRC << 8) | (HD[n++] & 0xFF);
311: if (PES->previous_PES_packet_CRC!=CRC) {
312: if (verbose) printf("- CRC error in previous block 0x%04X / 0x%04X\n",PES->previous_PES_packet_CRC,CRC);
313: //if (useCRC) return 0x0304;
314: }
315: }
316: if (PES->PES_extension_flag) {
317: PES->PES_private_data_flag=HD[n] & 0x80;
318: PES->pack_header_field_flag=HD[n] & 0x40;
319: PES->program_packet_sequence_counter_flag=HD[n] & 0x20;
320: PES->P_STD_buffer_flag=HD[n] & 0x10;
321: PES->PES_extension_flag_2=HD[n] & 0x01;
322: if (PES->PES_private_data_flag) {
323: for (i=0; i<128; i++) {
324: PES->PES_private_data[i]=HD[n++] & 0xFF;
325: }
326: }
327: if (PES->pack_header_field_flag) {
328: PES->pack_field_length=HD[n++] & 0xFF;
329: n+=PES->pack_field_length;
330: // *** TO DO *** parse pack header data
331: }
332: if (PES->program_packet_sequence_counter_flag) {
333: PES->program_packet_sequence_counter=HD[n++] & 0x7F;
334: PES->MPEG1_MPEG2_identifier=HD[n] & 0x40;
335: PES->original_stuff_length=HD[n++] & 0x3F;
336: }
337: if (PES->P_STD_buffer_flag) {
338: if ((HD[n] & 0xC0) != 0x40) {
339: if (verbose) printf("- SYNTAX error (wrong marker bits for P-STD)\n");
340: if (useCRC) return 0x0404;
341: }
342: PES->P_STD_buffer_scale=HD[n] & 0x20;
343: PES->P_STD_buffer_size=HD[n++] & 0x1F;
344: PES->P_STD_buffer_size=(PES->P_STD_buffer_size << 8) | (HD[n++] & 0xFF);
345: }
346: if (PES->PES_extension_flag_2) {
347: PES->PES_extension_field_length=HD[n++] & 0x7F;
348: n+=PES->PES_extension_field_length;
349: }
350: }
351:
352: // debug output
353: if (verbose) print_PES(PES);
354:
355: // initialise CRC for next block
356: CRC=CRC_INIT_16;
357:
358: if (PES->PES_packet_length) {
359: // how long is the size of the remaining PES-data? (now ES-data, that is)
360: packet_data_length=PES->PES_packet_length - (3 + PES->PES_header_data_length);
361: compare=0xFFFFFFFF;
362:
363: // dump or pipe raw ES-data
364: if (verbose || !pipe) {
365: printf("- %i Packet data bytes.\n%5d - ",packet_data_length,0);
366: for (i=0; i<packet_data_length; i++) {
367: fetchchar 0x0F01;
368: CRC=update_crc_16(CRC,filechar & 0xFF);
369: compare=(compare << 8) | (filechar & 0xFF);
370: // ANSI colors, 0=black, 1=red, 2=green, 3=yellow, 4=blue, 5=magenta; 6=cyan, 7=white ESC[3<fgcol>;4<bgcol>;1<for bold>m
371: //if ((compare & 0xFFFFFF00)==0x100) printf("\033[32m%02X\033[37m ",filechar & 0xFF);
372: //else printf("%02X ",filechar & 0xFF);
373: printf("%02X%c",filechar & 0xFF,(((compare & 0x00FFFFFF)==0x00000001)?'[':(((compare & 0xFFFFFF00)==0x00000100)?']':' ')));
374: //printf("%02X ",filechar & 0xFF);
375: if ((i % 24)==23) printf("\n%5d - ",i+1);
376: }
377: printf("\n");
378: } else if (pipe) {
379: for (i=0; i<packet_data_length; i++) {
380: fetchchar 0x1001;
381: CRC=update_crc_16(CRC,filechar & 0xFF);
382: putchar(filechar & 0xFF);
383: }
384: }
385: } else if ((PES->stream_id & 0xF0) == 0xE0) { // endless video stream
386: compare=0xFFFFFFFF;
387: // dump or pipe raw ES-data
388: if (verbose || !pipe) {
389: printf("- Unbound video stream.\n");
390: for (i=0; compare!=sequence_end_code; i++) {
391: fetchchar 0x1101;
392: CRC=update_crc_16(CRC,filechar & 0xFF);
393: compare=(compare << 8) | (filechar & 0xFF);
394: printf("%02X%c",filechar & 0xFF,(((compare & 0x00FFFFFF)==0x00000001)?'<':(((compare & 0xFFFFFF00)==0x00000100)?'>':' ')));
395: if ((i % 24)==23) printf("\n");
396: }
397: printf("\n");
398: } else if (pipe) {
399: while (compare!=sequence_end_code) {
400: fetchchar 0x1201;
401: CRC=update_crc_16(CRC,filechar & 0xFF);
402: compare=(compare << 8) | (filechar & 0xFF);
403: putchar(filechar & 0xFF);
404: }
405: }
406: } else {
407: if (verbose) printf("- ERROR: Unbound stream, but no video stream.\n");
408: }
409: if (verbose) printf("CRC: 0x%04X\n\n",CRC);
410: } else {
411: if (verbose) {
412: printf("ERROR - This is not a PES-Packet!\n Start code value: 0x%02X (",PES->stream_id);
413: if (PES->stream_id==0x00)
414: printf("picture_start_code");
415: else if (PES->stream_id<=0xAF)
416: printf("slice_start_code");
417: else if ((PES->stream_id==0xB0) || (PES->stream_id==0xB1) || (PES->stream_id==0xB6))
418: printf("reserved");
419: else if (PES->stream_id==0xB2)
420: printf("user_data_start_code");
421: else if (PES->stream_id==0xB3)
422: printf("sequence_header_code");
423: else if (PES->stream_id==0xB4)
424: printf("sequence_error_code");
425: else if (PES->stream_id==0xB5)
426: printf("extension_start_code");
427: else if (PES->stream_id==0xB7)
428: printf("sequence_end_code");
429: else if (PES->stream_id==0xB8)
430: printf("group_start_code");
431: else if (PES->stream_id==0xB9)
432: printf("iso_11172_end_code");
433: else if (PES->stream_id==0xBA)
434: printf("pack_start_code");
435: else if (PES->stream_id==0xBB)
436: printf("system_header_start_code");
437: else
438: printf("unidentified start code");
439: printf(")\n");
440: }
441: }
442: }
443: return 0;
444: }
445:
446:
447:
448: int main (int argc, char* argv[]) {
449:
450: FILE* inputstream;
451: int i,filearg,startpacket,stoppacket,err,verbose,pipe,useCRC;
452:
453: if (argc < 2) {
454: printf("\
455: Usage: %s [-v] [-p] [-c] [<file> [<first packet> <last packet> | <packet>]]\n\
456: -v: verbose on\n\
457: -p: pipe on (only raw output)\n\
458: -c: use CRC on PSI\n\
459: -s <prog>/<type>: show/pipe only PES of this program and this type\n\
460: ",argv[0]);
461: exit (0);
462: }
463:
464: i=1;
465: filearg=0;
466: verbose=0;
467: pipe=0;
468: startpacket=0;
469: stoppacket=0;
470: useCRC=0;
471: while (i<argc) {
472: if (argv[i][0]=='-') { // option
473: if (argv[i][1]=='v') verbose=1; // verbose on
474: else if (argv[i][1]=='p') pipe=1; // pipe on
475: else if (argv[i][1]=='c') useCRC=1; // CRC on
476: } else if (!filearg) filearg=i;
477: else if (!startpacket) startpacket=atoi(argv[i]);
478: else if (!stoppacket) stoppacket=atoi(argv[i]);
479: i++;
480: }
481:
482:
483: if (filearg) {
484: if ((inputstream=fopen(argv[filearg],"r"))==NULL) {
485: printf("Couldn't open file %s\n",argv[1]);
486: exit (0);
487: }
488: } else inputstream=stdin;
489:
490: gen_crc16_table();
491:
492: if (startpacket) {
493: if (!stoppacket) stoppacket=startpacket;
494: } else stoppacket=32767; // argh, i have to change this...
495:
496: PES=(PES_header *)malloc(sizeof(PES_header));
497:
498: err=0;
499: for (i=0; (i<stoppacket) && (err==0); i++) {
500: if ((startpacket<=(i+1)) && verbose) printf("--- Packet %i --- %ld\n",i+1,ftell(inputstream));
501: err=parse_PES(inputstream,(startpacket<=(i+1)),verbose,pipe,useCRC);
502: }
503: 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")));
504: fclose(inputstream);
505:
506: return 0;
507: }
LinuxTV legacy CVS <linuxtv.org/cvs>