/************************************************************************* bbDMUX by Brent Beyeler, beyeler@home.com *************************************************************************/ #include "bits.h" #include #undef SHOW_RESYNCHS #define MPEG_PROGRAM_END_CODE 0x000001B9 #define PACK_START_CODE 0x000001BA #define SYSTEM_HEADER_START_CODE 0x000001BB #define PACKET_START_CODE_PREFIX 0x000001 #define PROGRAM_ASSOCIATION_TABLE 0x0000 #define CONDITIONAL_ACCESS_TABLE 0x0001 #define NULL_PACKET 0x1FFF #define TRANSPORT_SYNC_BYTE 0x47 #define PROGRAM_STREAM_MAP 0xBC #define PRIVATE_STREAM_1 0xBD #define PADDING_STREAM 0xBE #define PRIVATE_STREAM_2 0xBF #define ECM_STREAM 0xF0 #define EMM_STREAM 0xF1 #define PROGRAM_STREAM_DIRECTORY 0xFF #define DSMCC_STREAM 0xF2 #define ITUTRECH222TYPEE_STREAM 0xF8 #define SUBSTREAM_AC3_0 0x80 #define SUBSTREAM_AC3_8 0x87 #define SUBSTREAM_DTS_0 0x88 #define SUBSTREAM_DTS_8 0x8F #define SUBSTREAM_PCM_0 0xA0 #define SUBSTREAM_PCM_F 0xAF #define SUBSTREAM_SUBPIC_0 0x20 #define SUBSTREAM_SUBPIC_1F 0x3F //#define BUFFER_SIZE 32768 #define BUFFER_SIZE 65536 static unsigned char buffer[BUFFER_SIZE]; static int bufidx; static FILE *outfp; static char outname[256]; static bool vob_flag; static void transport_stream(char *fname, int argc, int PID_to_get); void write_buffer() { if (fwrite(buffer, sizeof(unsigned char), bufidx + 1, outfp) != (unsigned int)bufidx + 1) { printf("Error writing to output file %s.", outname); exit (1); } bufidx = -1; } void flush_buffer() { if (bufidx >= 0) write_buffer(); } int main(int argc, char* argv[]) { unsigned long i, j, k, PES_packet_length, PES_header_data_length; unsigned long PTS_DTS_flags, ESCR_flag, ES_rate_flag, DSM_trick_mode_flag; unsigned long additional_copy_info_flag, PES_CRC_flag, PES_extension_flag; unsigned long PES_private_data_flag, pack_header_field_flag; unsigned long program_packet_sequence_counter_flag, PSTD_buffer_flag; unsigned long PES_extension_flag_2, PES_extension_field_length; unsigned long bytes_used, encrypted; int substream_to_get, stream_to_get, stream_id, substream_id; bool firsttime = true; unsigned long stream_packets[256], stream_bytes[256], pack_packets; unsigned long system_packets, mpeg_type; unsigned long ac3_bytes[8], dts_bytes[8], pcm_bytes[16], subpic_bytes[32];; unsigned long substream_packets[256], substream_bytes[256]; bool streams_found[256]; bool stream_encrypted[256]; bool substream_encrypted[256]; bool substreams_found[256]; bool mpeg2; char tmpStr[256]; for (i = 0; i < 256; i++) { streams_found[i] = false; stream_packets[i] = 0; stream_bytes[i] = 0; substreams_found[i] = false; stream_encrypted[i] = false; substream_encrypted[i] = false; substream_packets[i] = 0; substream_bytes[i] = 0; } for (i = 0; i < 8; i++) { ac3_bytes[i] = 0; dts_bytes[i] = 0; } for (i = 0; i < 16; i++) pcm_bytes[i] = 0; for (i = 0; i < 32; i++) subpic_bytes[i] = 0; pack_packets = 0; system_packets = 0; outfp = NULL; stream_to_get = -1; substream_to_get = -1; mpeg2 = false; bufidx = -1; printf("bbDMUX - version 1.9, by Brent Beyeler (beyeler@home.com)\n"); printf(" speed increases by, Apachez and Christian Vogelgsang\n\n"); if (argc < 2 || argc == 3) { printf("bbDUMX is an MPEG transport and program stream de-multiplexor\n\n"); printf("Usage: bbDMUX MPEG filename \n\n"); printf("Program stream examples:\n"); printf(" To get a list of the stream and substream id's present in an MPEG file\n"); printf(" bbDMUX testfile.mpg\n\n"); printf(" To save a video stream (id 0xe0) to the file video.m2v\n"); printf(" bbDMUX testfile.m2p 0xe0 video.m2v\n\n"); printf(" To save an audio stream (id 0xc0) to the file audio.m2a\n"); printf(" bbDMUX testfile.mpg 0xc0 audio.m2a\n\n"); printf(" To save an AC3 audio stream (substream 0x80) to the file audio.ac3\n"); printf(" bbDMUX testfile.vob 0xbd audio.ac3 0x80\n\n"); printf("Transport stream example:\n"); printf(" To save an video stream (PID = 0x001B) to the file video.m2v\n"); printf(" bbDMUX testfile.vob 0x001B video.m2v\n"); exit (1); } init_getbits(argv[1]); strcpy(tmpStr, argv[1]); strlwr(tmpStr); vob_flag = (strstr(tmpStr, ".vob") != NULL); mpeg_type = 0; while (!mpeg_type) { if (look_ahead(32) == PACK_START_CODE) mpeg_type = 1; else if (look_ahead(8) == TRANSPORT_SYNC_BYTE) mpeg_type = 2; else getbits(8); } if (!mpeg_type) { printf("\nUnknown file type.\n"); exit(1); } if (argc > 2) { sscanf(argv[2], "0x%x", &i); if (mpeg_type == 1) { if (i < 0 || i > 0xFF) { printf("Stream ID must be in the range 0..0xFF\n"); exit (1); } } else { if (i < 0 || i > 0x1FFF) { printf("PID must be in the range 0..0x1FFF\n"); exit (1); } } stream_to_get = i; if (argc > 3) { outfp = fopen(argv[3], "wb"); if (!outfp) { printf("Unable to open %s for output\n", argv[3]); exit (1); } strcpy(outname, argv[3]); } else { printf("An output filename must be specified\n"); exit(1); } if (argc > 4) { sscanf(argv[4], "0x%x", &i); if (i < 0 || i > 0xFF) { printf("Substream ID must be in the range 0..0xFF\n"); exit (1); } substream_to_get = i; vob_flag = true; } } else if (mpeg_type == 1) printf("Scanning for stream id's, press control-c to quit ...\n"); else printf("Scanning for PID's, press control-c to quit ...\n"); if (outfp) { if (mpeg_type == 1) { if ((vob_flag) && (stream_to_get == PRIVATE_STREAM_1) && (substream_to_get > -1)) printf("Saving stream 0x%02X, substream 0x%02X into file %s...\n", stream_to_get, substream_to_get, argv[3]); else printf("Saving stream 0x%02X into file %s...\n", stream_to_get, argv[3]); } else printf("Saving PID stream 0x%04X into file %s...\n", stream_to_get, argv[3]); } if (mpeg_type == 2) { transport_stream(argv[1], argc, stream_to_get); exit(0); } do { i = getbits(32); //nextpass: switch (i) { case PACK_START_CODE: pack_packets++; if (firsttime) { mpeg2 = look_ahead(2) == 1; // check if MPEG-1 or MPEG-2 if (mpeg2) printf("\nFile %s is an MPEG-2 Program Stream\n\n", argv[1]); else printf("\nFile %s is an MPEG-1 Program Stream\n\n", argv[1]); firsttime = false; } if (mpeg2) { getbits(32); // MPEG2 pack header getbits(32); getbits(13); i = getbits(3); for (j = 0; j < i; j++) getbits(8); // stuffing bytes } else { getbits(32); // MPEG1 pack header getbits(32); } break; case SYSTEM_HEADER_START_CODE: system_packets++; getbits(32); // system header getbits(32); while (look_ahead(1) == 1) getbits(24); // P-STD info break; case MPEG_PROGRAM_END_CODE: break; default: if ((i >> 8) != PACKET_START_CODE_PREFIX) // { break; //#ifdef SHOW_RESYNCHS // if (argc > 3) // { // printf("\nUnknown bits in stream = 0x%08X at byte %.0f\n", i, bitcount() / 8 - 4); // printf("\nAttempting resynch ... "); // } //#endif // if (seek_sync(PACKET_START_CODE_PREFIX, 24)) // { // i = 0x00000100 | getbits(8); //#ifdef SHOW_RESYNCHS // if (argc > 3) // printf("succesfully resynched\n"); //#endif // goto nextpass; // } //#ifdef SHOW_RESYNCHS // if (argc > 3) // printf("could not resynch\n"); // else //#endif // printf("\nUnknown bits in stream = 0x%08X at byte %.0f\n", i, bitcount() / 8 - 4); // if (outfp) // { // flush_buffer(); // fclose(outfp); // } // exit(1); // } stream_id = i & 0x000000FF; stream_packets[stream_id]++; PES_packet_length = getbits(16); encrypted = 0; switch (stream_id) { case PROGRAM_STREAM_MAP: case ECM_STREAM: case EMM_STREAM: case PROGRAM_STREAM_DIRECTORY: case DSMCC_STREAM: case ITUTRECH222TYPEE_STREAM: case PRIVATE_STREAM_2: case PADDING_STREAM: if (stream_id == stream_to_get) { for (j = 0; j < PES_packet_length; j++) { buffer[++bufidx] = (unsigned char)getbits(8); if (bufidx == BUFFER_SIZE - 1) write_buffer(); } } for (j = 0; j < PES_packet_length; j++) getbits(8); stream_bytes[stream_id] += j; break; default: bytes_used = 0; if (!mpeg2) { /* flush stuffing bytes */ while (look_ahead(8) == 0xff) { getbits(8); bytes_used++; } if (look_ahead(2) == 1) { /* Get STD buffer size */ getbits(16); bytes_used += 2; } if (look_ahead(4) == 2) { /* Get presentation time stamp and flag it as present in packet*/ getbits(32); getbits(8); bytes_used += 5; } else if (look_ahead(4) == 3) { /* Get presentation time stamp and decoding time stamp */ getbits(32); getbits(8); getbits(32); getbits(8); bytes_used += 10; } else { if (getbits(8) != 0x0f) { printf("Invalid bits in MPEG-1 file %s.", argv[1]); exit (1); } bytes_used++; } stream_bytes[stream_id] += PES_packet_length - bytes_used; if (stream_id == stream_to_get) { for (j = 0; j < PES_packet_length - bytes_used; j++) { buffer[++bufidx] = (unsigned char)getbits(8); if (bufidx == BUFFER_SIZE - 1) write_buffer(); } } else for (j = 0; j < PES_packet_length - bytes_used; j++) getbits(8); } else { getbits(2); encrypted = getbits(2); // PES_scrambling_control getbits(4); PTS_DTS_flags = getbits(2); ESCR_flag = get1bit(); ES_rate_flag = get1bit(); DSM_trick_mode_flag = get1bit(); additional_copy_info_flag = get1bit(); PES_CRC_flag = get1bit(); PES_extension_flag = get1bit(); PES_header_data_length = getbits(8); if (PTS_DTS_flags > 1) { getbits(32); // PTS stamp getbits(8); bytes_used += 5; } if (PTS_DTS_flags > 2) { getbits(32); // DTS stamp getbits(8); bytes_used += 5; } if (ESCR_flag == 1) { getbits(32); getbits(16); bytes_used += 6; } if (ES_rate_flag == 1) { getbits(24); bytes_used += 3; } if (DSM_trick_mode_flag == 1) { getbits(8); bytes_used++; } if (additional_copy_info_flag == 1) { getbits(8); bytes_used++; } if (PES_CRC_flag == 1) { getbits(16); bytes_used += 2; } if (PES_extension_flag == 1) { PES_private_data_flag = get1bit(); pack_header_field_flag = get1bit(); program_packet_sequence_counter_flag = get1bit(); PSTD_buffer_flag = get1bit(); getbits(3); PES_extension_flag_2 = get1bit(); bytes_used++; if (PES_private_data_flag == 1) { for (j = 0; j < 128; j++) getbits(8); bytes_used += 128; } if (pack_header_field_flag == 1) { printf(" pack header field flag value not allowed in program streams\n"); exit(1); } if (program_packet_sequence_counter_flag == 1) { getbits(16); bytes_used += 2; } if (PSTD_buffer_flag == 1) { getbits(16); bytes_used += 2; } if (PES_extension_flag_2 == 1) { get1bit(); PES_extension_field_length = getbits(7); bytes_used++; for (j = 0; j < PES_extension_field_length; j++) { getbits(8); bytes_used++; } } } for (j = 0; j < PES_header_data_length - bytes_used; j++) getbits(8); substream_id = getbits(8); stream_bytes[stream_id] += PES_packet_length - PES_header_data_length - 3; if ((stream_id == PRIVATE_STREAM_1) && (vob_flag)) { substream_packets[substream_id]++; j = PES_packet_length - PES_header_data_length - 3; substream_bytes[substream_id] += j; if ((substream_id >= SUBSTREAM_AC3_0) && (substream_id <= SUBSTREAM_AC3_8)) ac3_bytes[substream_id - SUBSTREAM_AC3_0] += j - 4; if ((substream_id >= SUBSTREAM_DTS_0) && (substream_id <= SUBSTREAM_DTS_8)) dts_bytes[substream_id - SUBSTREAM_DTS_0] += j - 4; if ((substream_id >= SUBSTREAM_PCM_0) && (substream_id <= SUBSTREAM_PCM_F)) pcm_bytes[substream_id - SUBSTREAM_PCM_0] += j - 7; if ((substream_id >= SUBSTREAM_SUBPIC_0) && (substream_id <= SUBSTREAM_SUBPIC_1F)) subpic_bytes[substream_id - SUBSTREAM_SUBPIC_0] += j - 1; } if (stream_id == stream_to_get) { if ((stream_id == PRIVATE_STREAM_1) && (vob_flag) && (substream_to_get > -1)) { if (substream_id == substream_to_get) { if ((substream_id >= SUBSTREAM_AC3_0) && (substream_id <= SUBSTREAM_AC3_8)) { getbits(24); // discard the 3 AC3 info bytes j = 4; } else if ((substream_id >= SUBSTREAM_DTS_0) && (substream_id <= SUBSTREAM_DTS_8)) { getbits(24); // discard the 3 DTS info bytes j = 4; } else if ((substream_id >= SUBSTREAM_PCM_0) && (substream_id <= SUBSTREAM_PCM_F)) { getbits(24); // discard the 6 PCM info bytes getbits(24); j = 7; } else if ((substream_id >= SUBSTREAM_SUBPIC_0) && (substream_id <= SUBSTREAM_SUBPIC_1F)) j = 1; else { buffer[++bufidx] = (unsigned char)substream_id; j = 1; } for (k = 0; k < PES_packet_length - PES_header_data_length - 3 - j; k++) { buffer[++bufidx] = (unsigned char)getbits(8); if (bufidx == BUFFER_SIZE - 1) write_buffer(); } } else for (j = 0; j < PES_packet_length - PES_header_data_length - 4; j++) getbits(8); } else { buffer[++bufidx] = (unsigned char)substream_id; if (bufidx == BUFFER_SIZE - 1) write_buffer(); for (j = 0; j < PES_packet_length - PES_header_data_length - 4; j++) { buffer[++bufidx] = (unsigned char)getbits(8); if (bufidx == BUFFER_SIZE - 1) write_buffer(); } } } else for (j = 0; j < PES_packet_length - PES_header_data_length - 4; j++) getbits(8); } break; } if (argc == 2) { if ((!streams_found[stream_id]) || ((vob_flag) && (stream_id == PRIVATE_STREAM_1) && (!substreams_found[substream_id]))) { switch (stream_id) { case PROGRAM_STREAM_MAP: printf("Found stream id 0x%02X = Program Stream Map\n", stream_id); break; case PRIVATE_STREAM_1: if (vob_flag) { if ((substream_id >= SUBSTREAM_AC3_0) && (substream_id <= SUBSTREAM_AC3_8)) printf("Found stream id 0x%02X = Private Stream 1, substream 0x%02X, AC3 Audio stream %u\n", stream_id, substream_id, substream_id - SUBSTREAM_AC3_0); else if ((substream_id >= SUBSTREAM_DTS_0) && (substream_id <= SUBSTREAM_DTS_8)) printf("Found stream id 0x%02X = Private Stream 1, substream 0x%02X, DTS Audio stream %u\n", stream_id, substream_id, substream_id - SUBSTREAM_DTS_0); else if ((substream_id >= SUBSTREAM_PCM_0) && (substream_id <= SUBSTREAM_PCM_F)) printf("Found stream id 0x%02X = Private Stream 1, substream 0x%02X, PCM Audio stream %u\n", stream_id, substream_id, substream_id - SUBSTREAM_PCM_0); else if ((substream_id >= SUBSTREAM_SUBPIC_0) && (substream_id <= SUBSTREAM_SUBPIC_1F)) printf("Found stream id 0x%02X = Private Stream 1, substream 0x%02X, Subpicture stream %u\n", stream_id, substream_id, substream_id - SUBSTREAM_SUBPIC_0); else printf("Found stream id 0x%02X = Private Stream 1, substream 0x%02X\n", stream_id, substream_id); substreams_found[substream_id] = true; } else printf("Found stream id 0x%02X = Private Stream 1\n", stream_id); break; case PRIVATE_STREAM_2: printf("Found stream id 0x%02X = Private Stream 2\n", stream_id); break; case ECM_STREAM: printf("Found stream id 0x%02X = ECM Stream\n", stream_id); break; case EMM_STREAM: printf("Found stream id 0x%02X = EMM Stream\n", stream_id); break; case PROGRAM_STREAM_DIRECTORY: printf("Found stream id 0x%02X = Program Stream Directory\n", stream_id); break; case DSMCC_STREAM: printf("Found stream id 0x%02X = DSMCC Stream\n", stream_id); break; case ITUTRECH222TYPEE_STREAM: printf("Found stream id 0x%02X = ITU-T Rec. H.222.1 type E\n", stream_id); break; case PADDING_STREAM: printf("Found stream id 0x%02X = Padding Stream\n", stream_id); break; default: if ((stream_id >= 0xE0) && (stream_id <= 0xEF)) printf("Found stream id 0x%02X = Video Stream %d\n", stream_id, stream_id - 0xE0); else if ((stream_id >= 0xC0) && (stream_id <= 0xDF)) printf("Found stream id 0x%02X = MPEG Audio Stream %d\n", stream_id, stream_id - 0xC0); else printf("Found stream id 0x%02X = other stream\n", stream_id); } streams_found[stream_id] = true; } if ((stream_id == PRIVATE_STREAM_1) && (vob_flag)) { if (encrypted) { if (!substream_encrypted[substream_id]) { printf("Stream id 0x%02X, substream 0x%02X is encrypted\n", stream_id, substream_id); substream_encrypted[substream_id] = true; } } } else { if (encrypted) { if (!stream_encrypted[stream_id]) { printf("Stream id 0x%02X is encrypted\n", stream_id); stream_encrypted[stream_id] = true; } } } } } } while ((i != MPEG_PROGRAM_END_CODE) && (!end_bs())); printf("\nSummary:\n"); printf("\nMPEG Packs = %d\n", pack_packets); if (system_packets) printf("System headers = %d\n", system_packets); for (i = 0; i < 256; i++) { if (stream_packets[i]) { switch (i) { case PROGRAM_STREAM_MAP: printf("Program Stream Map packets = %u, total bytes = %u\n", stream_packets[i], stream_bytes[i]); break; case PRIVATE_STREAM_1: printf("Private Stream 1 packets = %u, total bytes = %u\n", stream_packets[i], stream_bytes[i]); if (vob_flag) { for (j = 0; j < 256; j++) { if (substream_packets[j]) { if ((j >= SUBSTREAM_AC3_0) && (j <= SUBSTREAM_AC3_8)) printf(" AC3 Audio stream %u packets = %u, total bytes = %u\n", j - SUBSTREAM_AC3_0, substream_packets[j], ac3_bytes[j - SUBSTREAM_AC3_0]); else if ((j >= SUBSTREAM_DTS_0) && (j <= SUBSTREAM_DTS_8)) printf(" DTS Audio stream %u packets = %u, total bytes = %u\n", j - SUBSTREAM_DTS_0, substream_packets[j], dts_bytes[j - SUBSTREAM_DTS_0]); else if ((j >= SUBSTREAM_PCM_0) && (j <= SUBSTREAM_PCM_F)) printf(" PCM Audio stream %u packets = %u, total bytes = %u\n", j - SUBSTREAM_PCM_0, substream_packets[j], pcm_bytes[j - SUBSTREAM_PCM_0]); else if ((j >= SUBSTREAM_SUBPIC_0) && (j <= SUBSTREAM_SUBPIC_1F)) printf(" Subpicture stream %u packets = %u, total bytes = %u\n", j - SUBSTREAM_SUBPIC_0, substream_packets[j], subpic_bytes[j - SUBSTREAM_SUBPIC_0]); else printf(" Substream 0x%02X packets = %u, total bytes = %u\n", j, substream_packets[j], substream_bytes[j]); } } } break; case PRIVATE_STREAM_2: printf("Private Stream 2 packets = %u, total bytes = %u\n", stream_packets[i], stream_bytes[i]); break; case ECM_STREAM: printf("ECM Stream packets = %u, total bytes = %u\n", stream_packets[i], stream_bytes[i]); break; case EMM_STREAM: printf("EMM Stream packets = %u, total bytes = %u\n", stream_packets[i], stream_bytes[i]); break; case PROGRAM_STREAM_DIRECTORY: printf("Program Stream Directory packets = %u, total bytes = %u\n", stream_packets[i], stream_bytes[i]); break; case DSMCC_STREAM: printf("DSMCC Stream packets = %u, total bytes = %u\n", stream_packets[i], stream_bytes[i]); break; case ITUTRECH222TYPEE_STREAM: printf("ITU-T Rec. H.222.1 type E packets = %u, total bytes = %u\n", stream_packets[i], stream_bytes[i]); break; case PADDING_STREAM: printf("Padding Stream packets = %u, total bytes = %u\n", stream_packets[i], stream_bytes[i]); break; default: if ((i >= 0xE0) && (i <= 0xEF)) printf("Video stream %d packets = %u, total bytes = %u\n", i - 0xE0, stream_packets[i], stream_bytes[i]); else if ((i >= 0xC0) && (i <= 0xDF)) printf("MPEG Audio stream %d packets = %u, total bytes = %u\n", i - 0xC0, stream_packets[i], stream_bytes[i]); else printf("Other stream 0x%02X packets = %u, total bytes = %u\n", i, stream_packets[i], stream_bytes[i]); } } } finish_getbits(); if (outfp) { flush_buffer(); fclose(outfp); } return (0); } struct stream_entry { unsigned long stream_id; unsigned long substream_id; unsigned long stream_packets; unsigned long stream_bytes; int stream_encrypted; int stream_found; int pcm_bytes; int subpic_bytes; int ac3_bytes; int dts_bytes; }; void transport_stream(char *fname, int argc, int PID_to_get) { unsigned long i, j, k, PES_packet_length, PES_header_data_length; unsigned long adaptation_bytes; int payload_unit_start_indicator, PID; bool firsttime = true; unsigned long transport_packets, packet_data_bytes; stream_entry *streams[8192]; for (i = 0; i < 8192; i++) streams[i] = NULL; transport_packets = 0; bufidx = -1; do { i = getbits(8); //nextpass: if (i == TRANSPORT_SYNC_BYTE) { transport_packets++; if (firsttime) { printf("\nFile %s is an MPEG-2 Transport Stream\n\n", fname); firsttime = false; } j = getbits(3); payload_unit_start_indicator = (j & 0x2) >> 1; PID = getbits(13); if (streams[PID] == NULL) { streams[PID] = (stream_entry*)malloc(sizeof(stream_entry)); if (streams[PID] == NULL) { printf("Unable to allocate memory for stream entry.\n"); exit(1); } streams[PID]->stream_id = 0; streams[PID]->substream_id = 0; streams[PID]->stream_packets = 0; streams[PID]->stream_bytes = 0; streams[PID]->stream_encrypted = 0; streams[PID]->stream_found = 0; streams[PID]->pcm_bytes = 0; streams[PID]->subpic_bytes = 0; streams[PID]->ac3_bytes = 0; streams[PID]->dts_bytes = 0; } streams[PID]->stream_packets++; getbits(2); i = getbits(2); getbits(4); if (i > 1) { j = getbits(8); for (k = 0; k < j; k++) getbits(8); adaptation_bytes = j + 1; } else adaptation_bytes = 0; if ((i == 1) || (i == 3)) { packet_data_bytes = 184 - adaptation_bytes; if (packet_data_bytes > 0) { if ((look_ahead(24) == 0x000001) && payload_unit_start_indicator && (PID > 0x0F)) { i = getbits(32); packet_data_bytes -= 4; if ((i >> 8) != PACKET_START_CODE_PREFIX) { printf("Packet start code not found.\n"); exit(1); } streams[PID]->stream_id = i & 0x000000FF; PES_packet_length = getbits(16); packet_data_bytes -= 2; switch (streams[PID]->stream_id) { case PROGRAM_STREAM_MAP: case ECM_STREAM: case EMM_STREAM: case PROGRAM_STREAM_DIRECTORY: case DSMCC_STREAM: case ITUTRECH222TYPEE_STREAM: case PRIVATE_STREAM_2: case PADDING_STREAM: break; default: getbits(2); streams[PID]->stream_encrypted = getbits(2); // PES_scrambling_control getbits(12); PES_header_data_length = getbits(8); packet_data_bytes -= (3 + PES_header_data_length); for (j = 0; j < PES_header_data_length; j++) getbits(8); streams[PID]->substream_id = getbits(8); if ((streams[PID]->stream_id == PRIVATE_STREAM_1) && (vob_flag)) { j = PES_packet_length - PES_header_data_length - 3; if ((streams[PID]->substream_id >= SUBSTREAM_AC3_0) && (streams[PID]->substream_id <= SUBSTREAM_AC3_8)) streams[PID]->ac3_bytes += j - 4; if ((streams[PID]->substream_id >= SUBSTREAM_DTS_0) && (streams[PID]->substream_id <= SUBSTREAM_DTS_8)) streams[PID]->dts_bytes += j - 4; if ((streams[PID]->substream_id >= SUBSTREAM_PCM_0) && (streams[PID]->substream_id <= SUBSTREAM_PCM_F)) streams[PID]->pcm_bytes += j - 7; if ((streams[PID]->substream_id >= SUBSTREAM_SUBPIC_0) && (streams[PID]->substream_id <= SUBSTREAM_SUBPIC_1F)) streams[PID]->subpic_bytes += j - 1; } if ((streams[PID]->stream_id == PRIVATE_STREAM_1) && (vob_flag)) { if ((streams[PID]->substream_id >= SUBSTREAM_AC3_0) && (streams[PID]->substream_id <= SUBSTREAM_AC3_8)) { getbits(24); // discard the 3 AC3 info bytes j = 4; } else if ((streams[PID]->substream_id >= SUBSTREAM_DTS_0) && (streams[PID]->substream_id <= SUBSTREAM_DTS_8)) { getbits(24); // discard the 3 DTS info bytes j = 4; } else if ((streams[PID]->substream_id >= SUBSTREAM_PCM_0) && (streams[PID]->substream_id <= SUBSTREAM_PCM_F)) { getbits(24); // discard the 6 PCM info bytes getbits(24); j = 7; } else if ((streams[PID]->substream_id >= SUBSTREAM_SUBPIC_0) && (streams[PID]->substream_id <= SUBSTREAM_SUBPIC_1F)) j = 1; else { if (PID == PID_to_get) { buffer[++bufidx] = (unsigned char)streams[PID]->substream_id; if (bufidx == BUFFER_SIZE - 1) write_buffer(); } j = 1; streams[PID]->stream_bytes++; } packet_data_bytes -= j; } else { if (PID == PID_to_get) { buffer[++bufidx] = (unsigned char)streams[PID]->substream_id; if (bufidx == BUFFER_SIZE - 1) write_buffer(); } streams[PID]->stream_bytes++; packet_data_bytes--; } break; } if (packet_data_bytes > 0) { if (PID == PID_to_get) { for (j = 0; j < packet_data_bytes; j++) { buffer[++bufidx] = (unsigned char)getbits(8); if (bufidx == BUFFER_SIZE - 1) write_buffer(); } } else { for (j = 0; j < packet_data_bytes; j++) getbits(8); } streams[PID]->stream_bytes += j; } } else { if (PID == PID_to_get) { for (j = 0; j < packet_data_bytes; j++) { buffer[++bufidx] = (unsigned char)getbits(8); if (bufidx == BUFFER_SIZE - 1) write_buffer(); } } else { for (j = 0; j < packet_data_bytes; j++) getbits(8); } streams[PID]->stream_bytes += j; } } if ((argc == 2) && (!streams[PID]->stream_found)) { switch (streams[PID]->stream_id) { case PROGRAM_STREAM_MAP: printf("Found PID 0x%04X, stream id 0x%02X = Program Stream Map\n", PID, streams[PID]->stream_id); break; case PRIVATE_STREAM_1: if (vob_flag) { if ((streams[PID]->substream_id >= SUBSTREAM_AC3_0) && (streams[PID]->substream_id <= SUBSTREAM_AC3_8)) printf("Found PID 0x%04X, stream id 0x%02X = Private Stream 1, substream 0x%02X, AC3 Audio stream %u\n", PID, streams[PID]->stream_id, streams[PID]->substream_id, streams[PID]->substream_id - SUBSTREAM_AC3_0); else if ((streams[PID]->substream_id >= SUBSTREAM_DTS_0) && (streams[PID]->substream_id <= SUBSTREAM_DTS_8)) printf("Found PID 0x%04X, stream id 0x%02X = Private Stream 1, substream 0x%02X, DTS Audio stream %u\n", PID, streams[PID]->stream_id, streams[PID]->substream_id, streams[PID]->substream_id - SUBSTREAM_DTS_0); else if ((streams[PID]->substream_id >= SUBSTREAM_PCM_0) && (streams[PID]->substream_id <= SUBSTREAM_PCM_F)) printf("Found PID 0x%04X, stream id 0x%02X = Private Stream 1, substream 0x%02X, PCM Audio stream %u\n", PID, streams[PID]->stream_id, streams[PID]->substream_id, streams[PID]->substream_id - SUBSTREAM_PCM_0); else if ((streams[PID]->substream_id >= SUBSTREAM_SUBPIC_0) && (streams[PID]->substream_id <= SUBSTREAM_SUBPIC_1F)) printf("Found PID 0x%04X, stream id 0x%02X = Private Stream 1, substream 0x%02X, Subpicture stream %u\n", PID, streams[PID]->stream_id, streams[PID]->substream_id, streams[PID]->substream_id - SUBSTREAM_SUBPIC_0); else printf("Found PID 0x%04X, stream id 0x%02X = Private Stream 1, substream 0x%02X\n", PID, streams[PID]->stream_id, streams[PID]->substream_id); } else printf("Found PID 0x%04X, stream id 0x%02X = Private Stream 1\n", PID, streams[PID]->stream_id); break; case PRIVATE_STREAM_2: printf("Found PID 0x%04X, stream id 0x%02X = Private Stream 2\n", PID, streams[PID]->stream_id); break; case ECM_STREAM: printf("Found PID 0x%04X, stream id 0x%02X = ECM Stream\n", PID, streams[PID]->stream_id); break; case EMM_STREAM: printf("Found PID 0x%04X, stream id 0x%02X = EMM Stream\n", PID, streams[PID]->stream_id); break; case PROGRAM_STREAM_DIRECTORY: printf("Found PID 0x%04X, stream id 0x%02X = Program Stream Directory\n", PID, streams[PID]->stream_id); break; case DSMCC_STREAM: printf("Found PID 0x%04X, stream id 0x%02X = DSMCC Stream\n", PID, streams[PID]->stream_id); break; case ITUTRECH222TYPEE_STREAM: printf("Found PID 0x%04X, stream id 0x%02X = ITU-T Rec. H.222.1 type E\n", PID, streams[PID]->stream_id); break; case PADDING_STREAM: printf("Found PID 0x%04X, stream id 0x%02X = Padding Stream\n", PID, streams[PID]->stream_id); break; default: if ((streams[PID]->stream_id >= 0xE0) && (streams[PID]->stream_id <= 0xEF)) printf("Found PID 0x%04X, stream id 0x%02X = Video Stream %d\n", PID, streams[PID]->stream_id, streams[PID]->stream_id - 0xE0); else if ((streams[PID]->stream_id >= 0xC0) && (streams[PID]->stream_id <= 0xDF)) printf("Found PID 0x%04X, stream id 0x%02X = MPEG Audio Stream %d\n", PID, streams[PID]->stream_id, streams[PID]->stream_id - 0xC0); else { if (!streams[PID]->stream_id) { switch (PID) { case PROGRAM_ASSOCIATION_TABLE: printf("Found PID 0x%04X, Program Association Table Stream\n", PID); break; case CONDITIONAL_ACCESS_TABLE: printf("Found PID 0x%04X, Conditional Access Table Stream\n", PID); break; case NULL_PACKET: printf("Found PID 0x%04X, Null Packet Stream\n", PID); break; default: printf("Found PID 0x%04X, Other Stream\n", PID); break; } } else printf("Found PID 0x%04X, stream id 0x%02X = other stream\n", PID, streams[PID]->stream_id); } } streams[PID]->stream_found = 1; if ((streams[PID]->stream_id == PRIVATE_STREAM_1) && (vob_flag)) { if (streams[PID]->stream_encrypted) printf("PID 0x%04X, Stream id 0x%02X, substream 0x%02X is encrypted\n", PID, streams[PID]->stream_id, streams[PID]->substream_id); } else { if (streams[PID]->stream_encrypted) printf("PID 0x%04X, Stream id 0x%02X is encrypted\n", PID, streams[PID]->stream_id); } } } } } while (!end_bs()); printf("\nSummary:\n"); printf("\nMPEG Transport Packets = %d\n", transport_packets); for (i = 0; i < 8192; i++) { if (streams[i] != NULL) { if (streams[i]->stream_packets) { switch (streams[i]->stream_id) { case PROGRAM_STREAM_MAP: printf("PID 0x%04X, Program Stream Map packets = %u, total bytes = %u\n", i, streams[i]->stream_packets, streams[i]->stream_bytes); break; case PRIVATE_STREAM_1: printf("PID 0x%04X, Private Stream 1 packets = %u, total bytes = %u\n", i, streams[i]->stream_packets, streams[i]->stream_bytes); if (vob_flag) { j = streams[i]->substream_id; if ((j >= SUBSTREAM_AC3_0) && (j <= SUBSTREAM_AC3_8)) printf(" AC3 Audio stream %u packets = %u, total bytes = %u\n", j - SUBSTREAM_AC3_0, streams[i]->stream_packets, streams[i]->ac3_bytes); else if ((j >= SUBSTREAM_DTS_0) && (j <= SUBSTREAM_DTS_8)) printf(" DTS Audio stream %u packets = %u, total bytes = %u\n", j - SUBSTREAM_DTS_0, streams[i]->stream_packets, streams[i]->dts_bytes); else if ((j >= SUBSTREAM_PCM_0) && (j <= SUBSTREAM_PCM_F)) printf(" PCM Audio stream %u packets = %u, total bytes = %u\n", j - SUBSTREAM_PCM_0, streams[i]->stream_packets, streams[i]->pcm_bytes); else if ((j >= SUBSTREAM_SUBPIC_0) && (j <= SUBSTREAM_SUBPIC_1F)) printf(" Subpicture stream %u packets = %u, total bytes = %u\n", j - SUBSTREAM_SUBPIC_0, streams[i]->stream_packets, streams[i]->subpic_bytes); else printf(" Substream 0x%02X packets = %u, total bytes = %u\n", j, streams[i]->stream_packets, streams[i]->stream_bytes); } break; case PRIVATE_STREAM_2: printf("PID 0x%04X, Private Stream 2 packets = %u, total bytes = %u\n", PID, streams[i]->stream_packets, streams[i]->stream_bytes); break; case ECM_STREAM: printf("PID 0x%04X, ECM Stream packets = %u, total bytes = %u\n", PID, streams[i]->stream_packets, streams[i]->stream_bytes); break; case EMM_STREAM: printf("PID 0x%04X, EMM Stream packets = %u, total bytes = %u\n", PID, streams[i]->stream_packets, streams[i]->stream_bytes); break; case PROGRAM_STREAM_DIRECTORY: printf("PID 0x%04X, Program Stream Directory packets = %u, total bytes = %u\n", PID, streams[i]->stream_packets, streams[i]->stream_bytes); break; case DSMCC_STREAM: printf("PID 0x%04X, DSMCC Stream packets = %u, total bytes = %u\n", PID, streams[i]->stream_packets, streams[i]->stream_bytes); break; case ITUTRECH222TYPEE_STREAM: printf("PID 0x%04X, ITU-T Rec. H.222.1 type E packets = %u, total bytes = %u\n", PID, streams[i]->stream_packets, streams[i]->stream_bytes); break; case PADDING_STREAM: printf("PID 0x%04X, Padding Stream packets = %u, total bytes = %u\n", PID, streams[i]->stream_packets, streams[i]->stream_bytes); break; default: j = streams[i]->stream_id; if ((j >= 0xE0) && (j <= 0xEF)) printf("PID 0x%04X, Video stream %d packets = %u, total bytes = %u\n", i, j - 0xE0, streams[i]->stream_packets, streams[i]->stream_bytes); else if ((j >= 0xC0) && (j <= 0xDF)) printf("PID 0x%04X, MPEG Audio stream %d packets = %u, total bytes = %u\n", i, j - 0xC0, streams[i]->stream_packets, streams[i]->stream_bytes); else if (!j) { switch (i) { case PROGRAM_ASSOCIATION_TABLE: printf("PID 0x%04X, Program Association Table packets = %u, total bytes = %u\n", i, streams[i]->stream_packets, streams[i]->stream_bytes); break; case CONDITIONAL_ACCESS_TABLE: printf("PID 0x%04X, Conditional Access Table packets = %u, total bytes = %u\n", i, streams[i]->stream_packets, streams[i]->stream_bytes); break; case NULL_PACKET: printf("PID 0x%04X, Null packets = %u, total bytes = %u\n", i, streams[i]->stream_packets, streams[i]->stream_bytes); break; default: printf("PID 0x%04X, Other packets = %u, total bytes = %u\n", i, streams[i]->stream_packets, streams[i]->stream_bytes); break; } } else printf("PID %04X, Other stream 0x%02X packets = %u, total bytes = %u\n", i, j, streams[i]->stream_packets, streams[i]->stream_bytes); } } free(streams[i]); } } finish_getbits(); if (outfp) { flush_buffer(); fclose(outfp); } }