/* * Read the next ADTS frame. * * Assumes that the input stream is synchronised - i.e., it does not * try to cope if the next three bytes are not '1111 1111 1111'. * * - `file` is the file descriptor of the ADTS file to read from * - `frame` is the ADTS frame that is read * - `flags` indicates if we are forcing the recognition of "emphasis" * fields, etc. * * Returns 0 if all goes well, EOF if end-of-file is read, and 1 if something * goes wrong. */ extern int read_next_adts_frame(int file, audio_frame_p *frame, unsigned int flags) { #define JUST_ENOUGH 6 // just enough to hold the bits of the headers we want int err, ii; int id, layer; byte header[JUST_ENOUGH]; byte *data = NULL; int frame_length; int has_emphasis = 0; offset_t posn = tell_file(file); #if DEBUG fprint_msg("Offset: " OFFSET_T_FORMAT "\n",posn); #endif err = read_bytes(file,JUST_ENOUGH,header); if (err == EOF) return EOF; else if (err) { fprint_err("### Error reading header bytes of ADTS frame\n" " (in frame starting at " OFFSET_T_FORMAT ")\n",posn); free(data); return 1; } #if DEBUG print_msg("ADTS frame\n"); print_data(TRUE,"Start",header,JUST_ENOUGH,JUST_ENOUGH); #endif if (header[0] != 0xFF || (header[1] & 0xF0) != 0xF0) { fprint_err("### ADTS frame does not start with '1111 1111 1111'" " syncword - lost synchronisation?\n" " Found 0x%X%X%X instead of 0xFFF\n", (unsigned)(header[0] & 0xF0) >> 4, (header[0] & 0x0F), (unsigned)(header[1] & 0xF0) >> 4); fprint_err(" (in frame starting at " OFFSET_T_FORMAT ")\n",posn); return 1; }
static int write_out_packet(pcapreport_ctx_t * const ctx, pcapreport_stream_t * const st, const byte *data, const uint32_t len) { int rv; unsigned int pkts = len / 188; if (st->output_name) { if (!st->output_file) { fprint_msg("pcapreport: Dumping all packets for %s:%d to %s\n", ipv4_addr_to_string(st->output_dest_addr), st->output_dest_port, st->output_name); st->output_file = fopen(st->output_name, "wb"); if (!st->output_file) { fprint_err("### pcapreport: Cannot open %s .\n", st->output_name); return 1; } } if (ctx->verbose) { fprint_msg("++ Dumping %d bytes to output file.\n", len); } rv = fwrite(data, 188, pkts, st->output_file); if (rv != pkts) { fprint_err( "### pcapreport: Couldn't write %d bytes" " to %s (error = %d).\n", len, st->output_name, ferror(st->output_file)); return 1; } } return 0; }
/* * Look for an initial 0x47 sync byte, and check for TS * * Returns 0 if nothing went wrong, 1 if something did. */ static int check_if_TS(int input, byte cur_byte, int verbose, int *decided, int *result) { int ii; if (verbose) print_msg("Is it Transport Stream?\n"); // It may be enough to look at the first byte of the stream if (cur_byte != 0x47) { if (verbose) fprint_msg(" First byte in file is 0x%02X not 0x47, so it is not\n",cur_byte); return 0; } // Transport Stream packets start with 0x47, so it's a good bet. if (verbose) print_msg(" First byte in file is 0x47, so it looks like Transport Stream\n"); // To check a bit, we can try looking at every 188th byte if (verbose) print_msg(" Checking next 500 packets to see if they start 0x47\n"); for (ii=0; ii<500; ii++) { byte buf[TS_PACKET_SIZE]; int err = read_bytes(input,TS_PACKET_SIZE,buf); if (err) { fprint_err("### %s trying to read start of packet %d\n", (err==EOF?"EOF":"Error"),ii+1); return 1; } if (buf[TS_PACKET_SIZE-1] != 0x47) { if (verbose) fprint_msg(" Packet %d does not start with 0x47 (%02x instead)\n", ii+1,buf[TS_PACKET_SIZE-1]); return 0; } } if (verbose) print_msg("The checked packets all start with 0x47 - looks like TS\n"); *decided = TRUE; *result = STREAM_IS_TS; return 0; }
int read_next_ac3_frame(int file, audio_frame_p *frame) { int i, err; byte sync_info[SYNCINFO_SIZE]; byte *data = NULL; int fscod; int frmsizecod; int frame_length; offset_t posn = tell_file(file); err = read_bytes(file, SYNCINFO_SIZE, sync_info); if (err == EOF) return EOF; else if (err) { fprint_err("### Error reading syncinfo from AC3 file\n" " (in frame starting at " OFFSET_T_FORMAT ")\n", posn); return 1; } if (sync_info[0] != 0x0b || sync_info[1] != 0x77) { fprint_err("### AC3 frame does not start with 0x0b77" " syncword - lost synchronisation?\n" " Found 0x%02x%02x instead of 0x0b77\n", (unsigned)sync_info[0], (unsigned)sync_info[1]); fprint_err(" (in frame starting at " OFFSET_T_FORMAT ")\n", posn); return 1; } fscod = sync_info[4] >> 6; if (fscod == 3) { // Bad sample rate code fprint_err("### Bad sample rate code in AC3 syncinfo\n" " (in frame starting at " OFFSET_T_FORMAT ")\n", posn); return 1; } frmsizecod = sync_info[4] & 0x3f; if (frmsizecod > 37) { fprint_err("### Bad frame size code %d in AC3 syncinfo\n", frmsizecod); fprint_err(" (in frame starting at " OFFSET_T_FORMAT ")\n", posn); return 1; } frame_length = l_frmsizecod[frmsizecod >> 1][fscod]; if (fscod == 1) frame_length += frmsizecod & 1; frame_length <<= 1; // Convert from 16-bit words to bytes data = malloc(frame_length); if (data == NULL) { print_err("### Unable to extend data buffer for AC3 frame\n"); return 1; } for (i = 0; i < SYNCINFO_SIZE; i++) data[i] = sync_info[i]; err = read_bytes(file, frame_length - SYNCINFO_SIZE, &data[SYNCINFO_SIZE]); if (err) { if (err == EOF) print_err("### Unexpected EOF reading rest of AC3 frame\n"); else print_err("### Error reading rest of AC3 frame\n"); free(data); return 1; } err = build_audio_frame(frame); if (err) { free(data); return 1; } (*frame)->data = data; (*frame)->data_len = frame_length; return 0; }
int main(int argc, char **argv) { int had_video_name = FALSE; int had_audio_name = FALSE; int had_output_name = FALSE; char *video_name = NULL; char *audio_name = NULL; char *output_name = NULL; int err = 0; ES_p video_es = NULL; access_unit_context_p h264_video_context = NULL; avs_context_p avs_video_context = NULL; int audio_file = -1; TS_writer_p output1 = NULL; // TS_writer_p output2 = NULL; int quiet = FALSE; int verbose = FALSE; int debugging = FALSE; int audio_samples_per_frame = ADTS_SAMPLES_PER_FRAME; int audio_sample_rate = CD_RATE; int video_frame_rate = DEFAULT_VIDEO_FRAME_RATE; int audio_type = AUDIO_ADTS; int video_type = VIDEO_H264; int pat_pmt_freq = 0; int ii = 1; #if TEST_PTS_DTS test_pts(); return 0; #endif if (argc < 2) { print_usage(); return 0; } while (ii < argc) { if (argv[ii][0] == '-') { if (!strcmp("--help",argv[ii]) || !strcmp("-help",argv[ii]) || !strcmp("-h",argv[ii])) { print_usage(); return 0; } else if (!strcmp("-err",argv[ii])) { CHECKARG("esmerge",ii); if (!strcmp(argv[ii+1],"stderr")) redirect_output_stderr(); else if (!strcmp(argv[ii+1],"stdout")) redirect_output_stdout(); else { fprint_err("### esmerge: " "Unrecognised option '%s' to -err (not 'stdout' or" " 'stderr')\n",argv[ii+1]); return 1; } ii++; } else if (!strcmp("-verbose",argv[ii]) || !strcmp("-v",argv[ii])) { verbose = TRUE; } else if (!strcmp("-quiet",argv[ii]) || !strcmp("-q",argv[ii])) { quiet = TRUE; } else if (!strcmp("-x",argv[ii])) { debugging = TRUE; quiet = FALSE; } else if (!strcmp("-rate",argv[ii])) { CHECKARG("esmerge",ii); err = int_value("esmerge",argv[ii],argv[ii+1],TRUE,10,&audio_sample_rate); if (err) return 1; ii++; } else if (!strcmp("-cd",argv[ii])) { audio_sample_rate = CD_RATE; } else if (!strcmp("-dat",argv[ii])) { audio_sample_rate = DAT_RATE; } else if (!strcmp("-vidrate",argv[ii])) { CHECKARG("esmerge",ii); err = int_value("esmerge",argv[ii],argv[ii+1],TRUE,10,&video_frame_rate); if (err) return 1; ii++; } else if (!strcmp("-adts",argv[ii])) { audio_type = AUDIO_ADTS; } else if (!strcmp("-l2",argv[ii])) { audio_type = AUDIO_L2; } else if (!strcmp("-ac3", argv[ii])) { audio_type = AUDIO_AC3; } else if (!strcmp("-h264",argv[ii])) { video_type = VIDEO_H264; } else if (!strcmp("-mp2adts", argv[ii])) { audio_type = AUDIO_ADTS_MPEG2; } else if (!strcmp("-mp4adts", argv[ii])) { audio_type = AUDIO_ADTS_MPEG4; } else if (!strcmp("-avs",argv[ii])) { video_type = VIDEO_AVS; } else if (!strcmp("-patpmtfreq", argv[ii])) { CHECKARG("esmerge",ii); err = int_value("esmerge", argv[ii], argv[ii+1], TRUE, 10, &pat_pmt_freq); if (err) { return 1; } ++ii; } else { fprint_err("### esmerge: " "Unrecognised command line switch '%s'\n",argv[ii]); return 1; } } else { if (!had_video_name) { video_name = argv[ii]; had_video_name = TRUE; } else if (!had_audio_name) { audio_name = argv[ii]; printf("got audio name 123 %s\n",audio_name); had_audio_name = TRUE; } else if (!had_output_name) { output_name = argv[ii]; had_output_name = TRUE; } else { fprint_err("### esmerge: Unexpected '%s'\n",argv[ii]); return 1; } } ii++; } if (!had_video_name) { print_err("### esmerge: No video input file specified\n"); return 1; } /* if (!had_audio_name) { print_err("### esmerge: No audio input file specified\n"); return 1; }*/ if (!had_output_name) { print_err("### esmerge: No output file specified\n"); return 1; } char output_name1[255]; char output_name2[255]; strcpy(output_name1, output_name); strcpy(output_name2, output_name); int num1=atoi(audio_name); char fileSerial1[20]; char fileSerial2[20]; sprintf(fileSerial1,"%d.ts", num1); sprintf(fileSerial2,"%d.te", num1); strcat(output_name1,fileSerial1); strcat(output_name2,fileSerial2); uint32_t timeElapsed=0; err = open_elementary_stream(video_name,&video_es); if (err) { print_err("### esmerge: " "Problem starting to read video as ES - abandoning reading\n"); return 1; } if (video_type == VIDEO_H264) { err = build_access_unit_context(video_es,&h264_video_context); if (err) { print_err("### esmerge: " "Problem starting to read video as H.264 - abandoning reading\n"); close_elementary_stream(&video_es); return 1; } } else if (video_type == VIDEO_AVS) { err = build_avs_context(video_es,&avs_video_context); if (err) { print_err("### esmerge: " "Problem starting to read video as H.264 - abandoning reading\n"); close_elementary_stream(&video_es); return 1; } } else { print_err("### esmerge: Unknown video type\n"); return 1; } /* audio_file = open_binary_file(audio_name,FALSE); if (audio_file == -1) { print_err("### esmerge: " "Problem opening audio file - abandoning reading\n"); close_elementary_stream(&video_es); free_access_unit_context(&h264_video_context); free_avs_context(&avs_video_context); return 1; }*/ err = tswrite_open(TS_W_FILE,output_name1,NULL,0,quiet,&output1); //err = tswrite_open(TS_W_FILE,output_name2,NULL,0,quiet,&output2); if (err) { fprint_err("### esmerge: " "Problem opening output file %s - abandoning reading\n", output_name); close_elementary_stream(&video_es); close_file(audio_file); free_access_unit_context(&h264_video_context); free_avs_context(&avs_video_context); return 1; } /* switch (audio_type) { case AUDIO_ADTS: audio_samples_per_frame = ADTS_SAMPLES_PER_FRAME; break; case AUDIO_L2: audio_samples_per_frame = L2_SAMPLES_PER_FRAME; break; case AUDIO_AC3: audio_samples_per_frame = AC3_SAMPLES_PER_FRAME; break; default: // hmm - or we could give up... audio_samples_per_frame = ADTS_SAMPLES_PER_FRAME; break; } */ if (!quiet) { fprint_msg("Reading video from %s\n",video_name); fprint_msg("Reading audio from %s (as %s)\n",audio_name,AUDIO_STR(audio_type)); fprint_msg("Writing output to %s\n",output_name); fprint_msg("Audio sample rate: %dHz (%.2fKHz)\n",audio_sample_rate, audio_sample_rate/1000.0); fprint_msg("Audio samples per frame: %d\n",audio_samples_per_frame); fprint_msg("Video frame rate: %dHz\n",video_frame_rate); } if (video_type == VIDEO_H264) err = merge_with_h264(h264_video_context,audio_file,output1,//output2, audio_type, audio_samples_per_frame,audio_sample_rate, video_frame_rate, pat_pmt_freq, quiet,verbose,debugging,num1, &timeElapsed); else if (video_type == VIDEO_AVS) printf("disable"); /*err = merge_with_avs(avs_video_context,audio_file,output, audio_type, audio_samples_per_frame,audio_sample_rate, video_frame_rate, pat_pmt_freq, quiet,verbose,debugging);*/ else { print_err("### esmerge: Unknown video type\n"); return 1; } if (err) { print_err("### esmerge: Error merging video and audio streams\n"); close_elementary_stream(&video_es); close_file(audio_file); free_access_unit_context(&h264_video_context); free_avs_context(&avs_video_context); (void) tswrite_close(output1,quiet); //(void) tswrite_close(output2,quiet); return 1; } FILE *pFileLen = fopen (output_name2,"w"); fprintf(pFileLen, "%.2f", timeElapsed/100.0); fclose(pFileLen); close_elementary_stream(&video_es); close_file(audio_file); free_access_unit_context(&h264_video_context); free_avs_context(&avs_video_context); err = tswrite_close(output1,quiet); //err = tswrite_close(output2,quiet); if (err) { fprint_err("### esmerge: Error closing output %s\n",output_name); return 1; } return 0; }
int main(int argc, char **argv) { int use_stdin = FALSE; int use_stdout = FALSE; int use_tcpip = FALSE; int port = 88; // Useful default port number char *input_name = NULL; char *output_name = NULL; int had_input_name = FALSE; int had_output_name = FALSE; PS_reader_p ps = NULL; TS_writer_p output = NULL; int verbose = FALSE; int quiet = FALSE; int max = 0; uint32_t pmt_pid = 0x66; uint32_t video_pid = 0x68; uint32_t pcr_pid = video_pid; // Use PCRs from the video stream uint32_t audio_pid = 0x67; int keep_audio = TRUE; int repeat_program_every = 100; int pad_start = 8; int err = 0; int ii = 1; int video_type = VIDEO_H262; // hopefully a sensible default int force_stream_type = FALSE; int video_stream = -1; int audio_stream = -1; int want_ac3_audio = FALSE; int input_is_dvd = TRUE; int want_dolby_as_dvb = TRUE; if (argc < 2) { print_usage(); return 0; } while (ii < argc) { if (argv[ii][0] == '-') { if (!strcmp("--help",argv[ii]) || !strcmp("-help",argv[ii]) || !strcmp("-h",argv[ii])) { print_usage(); return 0; } else if (!strcmp("-avc",argv[ii]) || !strcmp("-h264",argv[ii])) { force_stream_type = TRUE; video_type = VIDEO_H264; } else if (!strcmp("-h262",argv[ii])) { force_stream_type = TRUE; video_type = VIDEO_H262; } else if (!strcmp("-vtype",argv[ii])) { CHECKARG("ps2ts",ii); err = int_value("ps2ts",argv[ii],argv[ii+1],TRUE,0, &video_type); if (err) return 1; ii++; force_stream_type = TRUE; } else if (!strcmp("-mp42",argv[ii])) { force_stream_type = TRUE; video_type = VIDEO_MPEG4_PART2; } else if (!strcmp("-dolby",argv[ii])) { CHECKARG("ps2ts",ii); if (!strcmp("dvb",argv[ii+1])) want_dolby_as_dvb = TRUE; else if (!strcmp("atsc",argv[ii+1])) want_dolby_as_dvb = FALSE; else { print_err("### ps2ts: -dolby must be followed by dvb or atsc\n"); return 1; } ii++; } else if (!strcmp("-stdin",argv[ii])) { had_input_name = TRUE; // more or less use_stdin = TRUE; } else if (!strcmp("-stdout",argv[ii])) { had_output_name = TRUE; // more or less use_stdout = TRUE; redirect_output_stderr(); } else if (!strcmp("-err",argv[ii])) { CHECKARG("ps2ts",ii); if (!strcmp(argv[ii+1],"stderr")) redirect_output_stderr(); else if (!strcmp(argv[ii+1],"stdout")) redirect_output_stdout(); else { fprint_err("### ps2ts: " "Unrecognised option '%s' to -err (not 'stdout' or" " 'stderr')\n",argv[ii+1]); return 1; } ii++; } else if (!strcmp("-dvd",argv[ii])) { input_is_dvd = TRUE; } else if (!strcmp("-notdvd",argv[ii]) || !strcmp("-nodvd",argv[ii])) { input_is_dvd = FALSE; } else if (!strcmp("-host",argv[ii])) { CHECKARG("ps2ts",ii); err = host_value("ps2ts",argv[ii],argv[ii+1],&output_name,&port); if (err) return 1; had_output_name = TRUE; // more or less use_tcpip = TRUE; ii++; } else if (!strcmp("-verbose",argv[ii]) || !strcmp("-v",argv[ii])) { verbose = TRUE; quiet = FALSE; } else if (!strcmp("-quiet",argv[ii]) || !strcmp("-q",argv[ii])) { verbose = FALSE; quiet = TRUE; } else if (!strcmp("-max",argv[ii]) || !strcmp("-m",argv[ii])) { CHECKARG("ps2ts",ii); err = int_value("ps2ts",argv[ii],argv[ii+1],TRUE,10,&max); if (err) return 1; ii++; } else if (!strcmp("-prepeat",argv[ii])) { CHECKARG("ps2ts",ii); err = int_value("ps2ts",argv[ii],argv[ii+1],TRUE,10, &repeat_program_every); if (err) return 1; ii++; } else if (!strcmp("-pad",argv[ii])) { CHECKARG("ps2ts",ii); err = int_value("ps2ts",argv[ii],argv[ii+1],TRUE,10,&pad_start); if (err) return 1; ii++; } else if (!strcmp("-vpid",argv[ii])) { CHECKARG("ps2ts",ii); err = unsigned_value("ps2ts",argv[ii],argv[ii+1],0,&video_pid); if (err) return 1; ii++; } else if (!strcmp("-apid",argv[ii])) { CHECKARG("ps2ts",ii); err = unsigned_value("ps2ts",argv[ii],argv[ii+1],0,&audio_pid); if (err) return 1; ii++; } else if (!strcmp("-pmt",argv[ii])) { CHECKARG("ps2ts",ii); err = unsigned_value("ps2ts",argv[ii],argv[ii+1],0,&pmt_pid); if (err) return 1; ii++; } else if (!strcmp("-noaudio",argv[ii])) { keep_audio = FALSE; } else if (!strcmp("-vstream",argv[ii])) { CHECKARG("ps2ts",ii); err = int_value_in_range("ps2ts",argv[ii],argv[ii+1],0,0xF,0, &video_stream); if (err) return 1; ii++; } else if (!strcmp("-astream",argv[ii])) { CHECKARG("ps2ts",ii); err = int_value_in_range("ps2ts",argv[ii],argv[ii+1],0,0x1F,0, &audio_stream); if (err) return 1; want_ac3_audio = FALSE; ii++; } else if (!strcmp("-ac3stream",argv[ii])) { CHECKARG("ps2ts",ii); err = int_value_in_range("ps2ts",argv[ii],argv[ii+1],0,0x7,0, &audio_stream); if (err) return 1; want_ac3_audio = TRUE; input_is_dvd = TRUE; ii++; } else { fprint_err("### ps2ts: " "Unrecognised command line switch '%s'\n",argv[ii]); return 1; } } else { if (had_input_name && had_output_name) { fprint_err("### ps2ts: Unexpected '%s'\n",argv[ii]); return 1; } else if (had_input_name) { output_name = argv[ii]; had_output_name = TRUE; } else { input_name = argv[ii]; had_input_name = TRUE; } } ii++; } if (!had_input_name) { print_err("### ps2ts: No input file specified\n"); return 1; } if (!had_output_name) { print_err("### ps2ts: No output file specified\n"); return 1; } // Try to stop extraneous data ending up in our output stream if (use_stdout) { verbose = FALSE; quiet = TRUE; } err = open_PS_file(input_name,quiet,&ps); if (err) { fprint_err("### ps2ts: Unable to open input %s\n", (use_stdin?"<stdin>":input_name)); return 1; } if (!quiet) fprint_msg("Reading from %s\n",(use_stdin?"<stdin>":input_name)); // Try to decide what sort of data stream we have if (force_stream_type || use_stdin) { if (!quiet) fprint_msg("Reading input as %s (0x%02x)\n", h222_stream_type_str(video_type),video_type); } else { err = determine_PS_video_type(ps,&video_type); if (err) return 1; if (!quiet) fprint_msg("Video appears to be %s (0x%02x)\n", h222_stream_type_str(video_type),video_type); } if (!quiet) { if (input_is_dvd) print_msg("Treating input as from DVD\n"); else print_msg("Treating input as NOT from DVD\n"); print_msg("Reading video from "); if (video_stream == -1) print_msg("first stream found"); else fprint_msg("stream %0#x (%d)",video_stream,video_stream); if (keep_audio) { print_msg(", audio from "); if (audio_stream == -1) fprint_msg("first %s found",(want_ac3_audio?"AC3 stream":"stream")); else fprint_msg("%s %0#x (%d)",(want_ac3_audio?"AC3 stream":"stream"), audio_stream,audio_stream); print_msg("\n"); } fprint_msg("Writing video with PID 0x%02x",video_pid); if (keep_audio) fprint_msg(", audio with PID 0x%02x,",audio_pid); fprint_msg(" PMT PID 0x%02x, PCR PID 0x%02x\n",pmt_pid,pcr_pid); if (max) fprint_msg("Stopping after %d program stream packets\n",max); } if (use_stdout) err = tswrite_open(TS_W_STDOUT,NULL,NULL,0,quiet,&output); else if (use_tcpip) err = tswrite_open(TS_W_TCP,output_name,NULL,port,quiet,&output); else err = tswrite_open(TS_W_FILE,output_name,NULL,0,quiet,&output); if (err) { fprint_err("### ps2ts: Unable to open %s\n",output_name); (void) close_PS_file(&ps); return 1; } err = ps_to_ts(ps,output,pad_start,repeat_program_every, video_type,input_is_dvd, video_stream,audio_stream,want_ac3_audio, want_dolby_as_dvb,pmt_pid,pcr_pid,video_pid, keep_audio,audio_pid,max,verbose,quiet); if (err) { print_err("### ps2ts: Error transferring data\n"); (void) close_PS_file(&ps); (void) tswrite_close(output,TRUE); return 1; } // And tidy up when we're finished err = tswrite_close(output,quiet); if (err) fprint_err("### ps2ts: Error closing output %s: %s\n",output_name, strerror(errno)); err = close_PS_file(&ps); if (err) fprint_err("### ps2ts: Error closing input %s\n", (use_stdin?"<stdin>":input_name)); return 0; }
/* * Read the next TS packet, coping with looping, etc. * * - `tsreader` is the TS reader context * - `count` is a running count of TS packets read from this input * - `data` is a pointer to the data for the packet * - `pid` is the PID of the TS packet * - `got_PCR` is TRUE if the adaptation field of this packet contains a PCR * - `pcr` is then the PCR value itself * - if `max` is greater than zero, then at most `max` TS packets should * be read from the input * - if `loop`, play the input file repeatedly (up to `max` TS packets * if applicable) - i.e., rewind to `start_posn` and start again if * `count` reaches `max` (obviously only if `max` is greater than zero). * - `start_count` is the value `count` should have after we've looped back * to `start_posn` * - if `quiet` is true, then only error messages should be written out * * Returns 0 if all went well, 1 if something went wrong, EOF if `loop` is * false and either EOF was read, or `max` TS packets were read. */ static int read_TS_packet(TS_reader_p tsreader, uint32_t *count, byte *data[TS_PACKET_SIZE], uint32_t *pid, int *got_pcr, uint64_t *pcr, int max, int loop, offset_t start_posn, uint32_t start_count, int quiet) { int err; int payload_unit_start_indicator; byte *adapt; int adapt_len; byte *payload; int payload_len; if (max > 0 && (*count) >= (uint32_t)max) { if (loop) { if (!quiet) fprint_msg("Read %d packets, rewinding and continuing\n",max); err = seek_using_TS_reader(tsreader,start_posn); if (err) return 1; *count = start_count; } else { if (!quiet) fprint_msg("Stopping after %d TS packets\n",max); return EOF; } } // Read the next packet err = read_next_TS_packet(tsreader,data); if (err) { if (err == EOF) { if (!loop) return EOF; if (!quiet) fprint_msg("EOF (after %d TS packets), rewinding and continuing\n", *count); } else { fprint_err("### Error reading TS packet %d\n",*count); if (!loop) return 1; if (!quiet) print_msg("!!! Rewinding and continuing anyway\n"); } err = seek_using_TS_reader(tsreader,start_posn); if (err) return 1; *count = start_count; } err = split_TS_packet(*data,pid,&payload_unit_start_indicator, &adapt,&adapt_len,&payload,&payload_len); if (err) { fprint_err("### Error splitting TS packet %d\n",*count); return 1; } get_PCR_from_adaptation_field(adapt,adapt_len,got_pcr,pcr); (*count) ++; return 0; }
/* * Look at the start of our "elementary" stream, and try to determine * its actual type. * * - `input` is the input stream to inspect * - if `verbose` is true, the caller wants details of how the decision * is being made * - `decided` is returned TRUE if the function believes it has identified * the stream type, in which case: * - `result` will an appropriate value indicating what we've decided * * Note that this function reads into the stream, and may attempt to * rewind it. * * Returns 0 if nothing went wrong, 1 if an error occurred */ static int determine_packet_type(int input, int verbose, int *decided, int *result) { int err; #ifdef _WIN32 int length; #else ssize_t length; #endif byte first_byte; int video_type; length = read(input,&first_byte,1); if (length == 0) { print_err("### EOF reading first byte\n"); return 1; } else if (length == -1) { fprint_err("### Error reading first byte: %s\n",strerror(errno)); return 1; } // Does it look like transport stream? err = check_if_TS(input,first_byte,verbose,decided,result); if (err) { close_file(input); return 1; } if (*decided) { close_file(input); return 0; } seek_file(input,0); // Does it look like program stream? err = check_if_PS(input,verbose,decided,result); if (err) { close_file(input); return 1; } if (*decided) { close_file(input); return 0; } seek_file(input,0); // Does it look like one of the types of ES we recognise? if (verbose) print_msg("Is it an Elementary Stream we recognise?\n"); err = decide_ES_file_video_type(input,!verbose,verbose,&video_type); if (err) { close_file(input); return 1; } switch (video_type) { case VIDEO_H264: *result = STREAM_IS_H264; *decided = TRUE; break; case VIDEO_H262: *result = STREAM_IS_H262; *decided = TRUE; break; case VIDEO_AVS: *result = STREAM_IS_AVS; *decided = TRUE; break; case VIDEO_UNKNOWN: *result = STREAM_IS_UNSURE; *decided = FALSE; if (verbose) print_msg("Still not sure\n"); break; default: fprint_msg("### stream_type: Unexpected decision from" " decide_ES_file_video_type: %d\n",video_type); close_file(input); return 1; } close_file(input); return 0; }
/* * Report on the given file with characters representing packets * * - `ps` is the PS file we're reading * - if `max` is more than zero, then it is the maximum number of PS packs * we want to read * - `verbose` is true if we want an explanation of the characters * * Returns 0 if all went well, 1 if something went wrong. */ static int report_ps_dots(PS_reader_p ps, int max, int verbose) { int err; int count = 0; int num_packs = 0; offset_t posn; // The location in the input file of the current packet byte stream_id; // The packet's stream id int end_of_file = FALSE; struct PS_packet packet = {0}; struct PS_pack_header header = {0}; if (verbose) print_msg("Characters represent the following:\n" " [ Pack header\n" " H System header\n" " ] MPEG_program_end_code\n" " p<n> Private stream <n> (1 or 2)\n" " v Video stream 0\n" " v<n> Video stream <n> (>0)\n" " a Audio stream 0\n" " a<n> Audio stream <n> (>0)\n" " M Program stream map\n" " D Program stream directory\n" " . Padding\n" " ? Something else\n" ); // Read the start of the first packet (we confidently expect this // to be a pack header) err = read_PS_packet_start(ps,FALSE,&posn,&stream_id); if (err == EOF) { print_err("### Error reading first pack header\n"); print_err(" Unexpected end of PS at start of stream\n"); return 1; } else if (err) { print_err("### Error reading first pack header\n"); return 1; } if (stream_id != 0xba) { print_err("### Program stream does not start with pack header\n"); fprint_err(" First packet has stream id %02X (",stream_id); print_stream_id(FALSE,stream_id); print_err(")\n"); return 1; } // But given that, we can now happily loop reading in packs for (;;) { int num_system_headers = 0; if (max > 0 && num_packs >= max) { fprint_msg("\nStopping after %d packs\n",num_packs); return 0; } num_packs ++; print_msg("["); fflush(stdout); err = read_PS_pack_header_body(ps,&header); if (err) { fprint_err("### Error reading data for pack header starting at " OFFSET_T_FORMAT "\n",posn); return 1; } // Read (and, for the moment, at least, ignore) any system headers for (;;) { err = read_PS_packet_start(ps,FALSE,&posn,&stream_id); if (err == EOF) { end_of_file = TRUE; if (stream_id == 0xB9) { print_msg("]"); fflush(stdout); } break; } else if (err) return 1; if (stream_id == 0xbb) // System header { print_msg("H"); fflush(stdout); err = read_PS_packet_body(ps,stream_id,&packet); if (err) { fprint_err("### Error reading system header starting at " OFFSET_T_FORMAT "\n",posn); return 1; } // For the moment, just ignore the system header content num_system_headers ++; } else break; } if (end_of_file) break; // We've finished with system headers - onto data (one fondly hopes) for (;;) { if (stream_id == 0xba) // Start of the next pack break; if (stream_id == 0xBC) print_msg("M"); else if (stream_id == 0xFF) print_msg("D"); else if (stream_id == 0xBD) print_msg("p1"); else if (stream_id == 0xBE) print_msg("."); else if (stream_id == 0xBF) print_msg("p2"); else if (stream_id >= 0xC0 && stream_id <=0xDF) { int number = stream_id & 0x1F; if (number == 0) print_msg("a"); else fprint_msg("a%x",number); } else if (stream_id >= 0xE0 && stream_id <= 0xEF) { int number = stream_id & 0x0F; if (number == 0) print_msg("v"); else fprint_msg("v%x",number); } else print_msg("?"); fflush(stdout); err = read_PS_packet_body(ps,stream_id,&packet); if (err) { fprint_err("### Error reading PS packet starting at " OFFSET_T_FORMAT "\n",posn); return 1; } err = read_PS_packet_start(ps,FALSE,&posn,&stream_id); if (err == EOF) { if (stream_id == 0xB9) { print_msg("]"); fflush(stdout); } end_of_file = TRUE; break; } else if (err) return 1; } if (end_of_file) break; } clear_PS_packet(&packet); fprint_msg("\nRead %d PS packet%s in %d pack%s\n", count,(count==1?"":"s"), num_packs,(num_packs==1?"":"s")); return 0; }
/* * Extract all the TS packets for either a video or audio stream. * * Returns 0 if all went well, 1 if something went wrong. */ static int extract_av_via_pes(char *input_name, char *output_name, int want_video, int quiet) { int err; PES_reader_p reader = NULL; ES_p es = NULL; FILE *output; if (!want_video) { print_err("### Audio output is not supported via PES in this utility\n"); return 1; } output = fopen(output_name,"wb"); if (output == NULL) { fprint_err("### Unable to open output file %s: %s\n",output_name, strerror(errno)); return 1; } err = open_PES_reader(input_name,!quiet,!quiet,&reader); if (err) { fprint_err("### Error opening file %s\n",input_name); fclose(output); return 1; } set_PES_reader_video_only(reader,TRUE); // Wrap our PES stream up as an ES stream err = build_elementary_stream_PES(reader,&es); if (err) { print_err("### Error trying to build ES reader from PES reader\n"); (void) close_PES_reader(&reader); (void) fclose(output); return 1; } for (;;) { ES_unit_p unit; err = find_and_build_next_ES_unit(es,&unit); if (err == EOF) break; else if (err) { print_err("### Error reading next ES unit\n"); (void) fclose(output); (void) close_PES_reader(&reader); close_elementary_stream(&es); return 1; } err = write_ES_unit(output,unit); if (err) { print_err("### Error writing ES unit out to file\n"); free_ES_unit(&unit); (void) fclose(output); (void) close_PES_reader(&reader); close_elementary_stream(&es); return 1; } free_ES_unit(&unit); } (void) fclose(output); // naughtily ignore the return code (void) close_PES_reader(&reader); // naughtily ignore the return code close_elementary_stream(&es); return 0; }
int main(int argc, char **argv) { int use_stdout = FALSE; int use_stdin = FALSE; char *input_name = NULL; char *output_name = NULL; int had_input_name = FALSE; int had_output_name = FALSE; char *action_switch = "None"; EXTRACT extract = EXTRACT_VIDEO; // What we're meant to extract int input = -1; // Our input file descriptor FILE *output = NULL; // The stream we're writing to (if any) int max = 0; // The maximum number of TS packets to read (or 0) uint32_t pid = 0; // The PID of the (single) stream to extract int quiet = FALSE; // True => be as quiet as possible int verbose = FALSE; // True => output diagnostic/progress messages int use_pes = FALSE; int err = 0; int ii = 1; if (argc < 2) { print_usage(); return 0; } while (ii < argc) { if (argv[ii][0] == '-') { if (!strcmp("--help",argv[ii]) || !strcmp("-h",argv[ii]) || !strcmp("-help",argv[ii])) { print_usage(); return 0; } else if (!strcmp("-verbose",argv[ii]) || !strcmp("-v",argv[ii])) { verbose = TRUE; quiet = FALSE; } else if (!strcmp("-quiet",argv[ii]) || !strcmp("-q",argv[ii])) { verbose = FALSE; quiet = TRUE; } else if (!strcmp("-max",argv[ii]) || !strcmp("-m",argv[ii])) { CHECKARG("ts2es",ii); err = int_value("ts2es",argv[ii],argv[ii+1],TRUE,10,&max); if (err) return 1; ii++; } else if (!strcmp("-pes",argv[ii]) || !strcmp("-ps",argv[ii])) { use_pes = TRUE; } else if (!strcmp("-pid",argv[ii])) { CHECKARG("ts2es",ii); err = unsigned_value("ts2es",argv[ii],argv[ii+1],0,&pid); if (err) return 1; ii++; extract = EXTRACT_PID; } else if (!strcmp("-video",argv[ii])) { extract = EXTRACT_VIDEO; } else if (!strcmp("-audio",argv[ii])) { extract = EXTRACT_AUDIO; } else if (!strcmp("-stdin",argv[ii])) { use_stdin = TRUE; had_input_name = TRUE; // so to speak } else if (!strcmp("-stdout",argv[ii])) { use_stdout = TRUE; had_output_name = TRUE; // so to speak redirect_output_stderr(); } else if (!strcmp("-err",argv[ii])) { CHECKARG("ts2es",ii); if (!strcmp(argv[ii+1],"stderr")) redirect_output_stderr(); else if (!strcmp(argv[ii+1],"stdout")) redirect_output_stdout(); else { fprint_err("### ts2es: " "Unrecognised option '%s' to -err (not 'stdout' or" " 'stderr')\n",argv[ii+1]); return 1; } ii++; } else { fprint_err("### ts2es: " "Unrecognised command line switch '%s'\n",argv[ii]); return 1; } } else { if (had_input_name && had_output_name) { fprint_err("### ts2es: Unexpected '%s'\n",argv[ii]); return 1; } else if (had_input_name) // shouldn't do this if had -stdout { output_name = argv[ii]; had_output_name = TRUE; } else { input_name = argv[ii]; had_input_name = TRUE; } } ii++; } if (!had_input_name) { print_err("### ts2es: No input file specified\n"); return 1; } if (!had_output_name) { fprint_err("### ts2es: " "No output file specified for %s\n",action_switch); return 1; } // ============================================================ // Testing PES output if (use_pes && extract == EXTRACT_PID) { print_err("### ts2es: -pid is not supported with -pes\n"); return 1; } if (use_pes && use_stdout) { print_err("### ts2es: -stdout is not supported with -pes\n"); return 1; } if (use_pes && use_stdin) { print_err("### ts2es: -stdin is not supported with -pes\n"); return 1; } if (use_pes) { err = extract_av_via_pes(input_name,output_name,(extract==EXTRACT_VIDEO), quiet); if (err) { print_err("### ts2es: Error writing via PES\n"); return 1; } return 0; } // ============================================================ // Try to stop extraneous data ending up in our output stream if (use_stdout) { verbose = FALSE; quiet = TRUE; } if (use_stdin) input = STDIN_FILENO; else { input = open_binary_file(input_name,FALSE); if (input == -1) { fprint_err("### ts2es: Unable to open input file %s\n",input_name); return 1; } } if (!quiet) fprint_msg("Reading from %s\n",(use_stdin?"<stdin>":input_name)); if (had_output_name) { if (use_stdout) output = stdout; else { output = fopen(output_name,"wb"); if (output == NULL) { if (!use_stdin) (void) close_file(input); fprint_err("### ts2es: " "Unable to open output file %s: %s\n",output_name, strerror(errno)); return 1; } } if (!quiet) fprint_msg("Writing to %s\n",(use_stdout?"<stdout>":output_name)); } if (!quiet) { if (extract == EXTRACT_PID) fprint_msg("Extracting packets for PID %04x (%d)\n",pid,pid); else fprint_msg("Extracting %s\n",(extract==EXTRACT_VIDEO?"video":"audio")); } if (max && !quiet) fprint_msg("Stopping after %d TS packets\n",max); if (extract == EXTRACT_PID) err = extract_pid(input,output,pid,max,verbose,quiet); else err = extract_av(input,output,(extract==EXTRACT_VIDEO), max,verbose,quiet); if (err) { print_err("### ts2es: Error extracting data\n"); if (!use_stdin) (void) close_file(input); if (!use_stdout) (void) fclose(output); return 1; } // And tidy up when we're finished if (!use_stdout) { errno = 0; err = fclose(output); if (err) { fprint_err("### ts2es: Error closing output file %s: %s\n", output_name,strerror(errno)); (void) close_file(input); return 1; } } if (!use_stdin) { err = close_file(input); if (err) fprint_err("### ts2es: Error closing input file %s\n",input_name); } return 0; }
/* * Extract all the TS packets for either a video or audio stream. * * Returns 0 if all went well, 1 if something went wrong. */ static int extract_av(int input, FILE *output, int want_video, int max, int verbose, int quiet) { int err, ii; int max_to_read = max; int total_num_read = 0; uint32_t pid = 0; TS_reader_p tsreader = NULL; pmt_p pmt = NULL; // Turn our file into a TS reader err = build_TS_reader(input,&tsreader); if (err) return 1; // First, find out what program streams we actually have for (;;) { int num_read; // Give up if we've read more than our limit if (max > 0 && max_to_read <= 0) break; err = find_pmt(tsreader,max_to_read,verbose,quiet,&num_read,&pmt); if (err == EOF) { if (!quiet) print_msg("No program stream information in the input file\n"); free_TS_reader(&tsreader); free_pmt(&pmt); return 0; } else if (err) { print_err("### Error finding program stream information\n"); free_TS_reader(&tsreader); free_pmt(&pmt); return 1; } max_to_read -= num_read; total_num_read += num_read; // From that, find a stream of the type we want... // Note that the audio detection will accept either DVB or ADTS Dolby (AC-3) // stream types for (ii=0; ii < pmt->num_streams; ii++) { if (( want_video && IS_VIDEO_STREAM_TYPE(pmt->streams[ii].stream_type)) || (!want_video && (IS_AUDIO_STREAM_TYPE(pmt->streams[ii].stream_type)))) { pid = pmt->streams[ii].elementary_PID; break; } } free_pmt(&pmt); // Did we find what we want? If not, go round again and look for the // next PMT (subject to the number of records we're willing to search) if (pid != 0) break; } if (pid == 0) { fprint_err("### No %s stream specified in first %d TS packets in input file\n", (want_video?"video":"audio"),max); free_TS_reader(&tsreader); return 1; } if (!quiet) fprint_msg("Extracting %s PID %04x (%d)\n",(want_video?"video":"audio"), pid,pid); // Amend max to take account of the packets we've already read max -= total_num_read; // And do the extraction. err = extract_pid_packets(tsreader,output,pid,max,verbose,quiet); free_TS_reader(&tsreader); return err; }
/* * Extract all the TS packets for a nominated PID to another file. * * Returns 0 if all went well, 1 if something went wrong. */ static int extract_pid_packets(TS_reader_p tsreader, FILE *output, uint32_t pid_wanted, int max, int verbose, int quiet) { int err; int count = 0; int extracted = 0; int pes_packet_len = 0; int got_pes_packet_len = FALSE; // It doesn't make sense to start outputting data for our PID until we // get the start of a packet int need_packet_start = TRUE; for (;;) { uint32_t pid; int payload_unit_start_indicator; byte *adapt, *payload; int adapt_len, payload_len; if (max > 0 && count >= max) { if (!quiet) fprint_msg("Stopping after %d packets\n",max); break; } err = get_next_TS_packet(tsreader,&pid, &payload_unit_start_indicator, &adapt,&adapt_len,&payload,&payload_len); if (err == EOF) break; else if (err) { print_err("### Error reading TS packet\n"); return 1; } count++; // If the packet is empty, all we can do is ignore it if (payload_len == 0) continue; if (pid == pid_wanted) { byte *data; int data_len; size_t written; if (verbose) { fprint_msg("%4d: TS Packet PID %04x",count,pid); if (payload_unit_start_indicator) print_msg(" (start)"); else if (need_packet_start) print_msg(" <ignored>"); print_msg("\n"); } if (payload_unit_start_indicator) { // It's the start of a PES packet, so we need to drop the header int offset; if (need_packet_start) need_packet_start = FALSE; pes_packet_len = (payload[4] << 8) | payload[5]; if (verbose) fprint_msg("PES packet length %d\n",pes_packet_len); got_pes_packet_len = (pes_packet_len > 0); if (IS_H222_PES(payload)) { // It's H.222.0 - payload[8] is the PES_header_data_length, // so our ES data starts that many bytes after that field offset = payload[8] + 9; } else { // We assume it's MPEG-1 offset = calc_mpeg1_pes_offset(payload,payload_len); } data = &payload[offset]; data_len = payload_len-offset; if (verbose) print_data(TRUE,"data",data,data_len,1000); } else { // If we haven't *started* a packet, we can't use this, // since it will just look like random bytes when written out. if (need_packet_start) { continue; } data = payload; data_len = payload_len; if (verbose) print_data(TRUE,"Data",payload,payload_len,1000); if (got_pes_packet_len) { // Try not to write more data than the PES packet declares if (data_len > pes_packet_len) { data_len = pes_packet_len; if (verbose) print_data(TRUE,"Reduced data",data,data_len,1000); pes_packet_len = 0; } else pes_packet_len -= data_len; } } if (data_len > 0) { // Windows doesn't seem to like writing 0 bytes, so be careful... written = fwrite(data,data_len,1,output); if (written != 1) { fprint_err("### Error writing TS packet - units written = %d\n", (int)written); return 1; } } extracted ++; } } if (!quiet) fprint_msg("Extracted %d of %d TS packet%s\n", extracted,count,(count==1?"":"s")); // If the user has forgotten to say -pid XX, or -video/-audio, // and are piping the output to another program, it can be surprising // if there is no data! if (quiet && extracted == 0) fprint_err("### No data extracted for PID %#04x (%d)\n", pid_wanted,pid_wanted); return 0; }
int main(int argc, char **argv) { char *input_name = NULL; int had_input_name = FALSE; int input = -1; int verbose = FALSE; int quiet = FALSE; int err = 0; int ii = 1; int decided = FALSE; int result = STREAM_IS_ERROR; if (argc < 2) { print_usage(); return 0; } while (ii < argc) { if (argv[ii][0] == '-') { if (!strcmp("--help",argv[ii]) || !strcmp("-h",argv[ii]) || !strcmp("-help",argv[ii])) { print_usage(); return STREAM_IS_ERROR; } else if (!strcmp("-verbose",argv[ii]) || !strcmp("-v",argv[ii])) { verbose = TRUE; quiet = FALSE; } else if (!strcmp("-err",argv[ii])) { CHECKARG("stream_type",ii); if (!strcmp(argv[ii+1],"stderr")) redirect_output_stderr(); else if (!strcmp(argv[ii+1],"stdout")) redirect_output_stdout(); else { fprint_err("### stream_type: " "Unrecognised option '%s' to -err (not 'stdout' or" " 'stderr')\n",argv[ii+1]); return 1; } ii++; } else if (!strcmp("-quiet",argv[ii]) || !strcmp("-q",argv[ii])) { verbose = FALSE; quiet = TRUE; } else { fprint_err("### stream_type: " "Unrecognised command line switch '%s'\n",argv[ii]); return STREAM_IS_ERROR; } } else { if (had_input_name) { fprint_err("### stream_type: Unexpected '%s'\n",argv[ii]); return STREAM_IS_ERROR; } else { input_name = argv[ii]; had_input_name = TRUE; } } ii++; } if (!had_input_name) { print_err("### stream_type: No input file specified\n"); return STREAM_IS_ERROR; } input = open_binary_file(input_name,FALSE); if (input == -1) { fprint_err("### stream_type: Unable to open input file %s\n", input_name); return 1; } if (!quiet) fprint_msg("Reading from %s\n",input_name); // Try to guess err = determine_packet_type(input,verbose,&decided,&result); if (err) { print_err("### Unable to decide on stream type due to error\n"); return STREAM_IS_ERROR; } if (!quiet) { if (!decided) { print_msg("Unable to decide\n"); result = STREAM_IS_UNSURE; } else { switch (result) { case STREAM_IS_TS: print_msg("It appears to be Transport Stream\n"); break; case STREAM_IS_PS: print_msg("It appears to be Program Stream\n"); break; case STREAM_IS_H262: print_msg("It appears to be Elementary Stream, MPEG-2 (H.262)\n"); break; case STREAM_IS_H264: print_msg("It appears to be Elementary Stream, MPEG-4 (H.264)\n"); break; case STREAM_IS_AVS: print_msg("It appears to be Elementary Stream, AVS\n"); break; case STREAM_MAYBE_PES: print_msg("It looks likely to be PES\n"); break; case STREAM_IS_UNSURE: print_msg("It is not recognised\n"); break; default: fprint_msg("Unexpected decision value %d\n",result); result = STREAM_IS_ERROR; break; } } } return result; }
int main(int argn, char *args[]) { int ii = 1; int verbose = FALSE; int invert = 0; unsigned int max_pkts = (unsigned int)-1; const char *input_file = NULL, *output_file = NULL; if (argn < 2) { print_usage(); return 0; } ensurePidList(1024); while (ii < argn) { if (args[ii][0] == '-') { if (!strcmp("--help", args[ii]) || !strcmp("-h", args[ii]) || !strcmp("-help", args[ii])) { print_usage(); return 0; } else if (!strcmp("-verbose", args[ii]) || !strcmp("-v", args[ii])) { verbose = TRUE; } else if (!strcmp("-m", args[ii]) || !strcmp("-max", args[ii])) { if (argn <= ii) { fprint_err("### tsfilter: -max requires an argument\n"); return 1; } max_pkts = atoi(args[ii+1]); ++ii; } else if (!strcmp("-!", args[ii]) || !strcmp("-invert", args[ii])) { invert = 1; } else if (!strcmp("-i", args[ii]) || !strcmp("-input", args[ii])) { if (argn <= ii) { fprint_err("### tsfilter: -input requires an argument\n"); return 1; } input_file = args[ii+1]; ++ii; } else if (!strcmp("-o", args[ii]) || !strcmp("-output", args[ii])) { if (argn <= ii) { fprint_err("### tsfilter: -output requires an argument\n"); return 1; } output_file = args[ii+1]; ++ii; } else { fprint_err("### tsfilter: " "Unrecognised command line switch '%s'\n", args[ii]); return 1; } } else { char *p = NULL; // It's a pid. if (pidListUsed >= pidListAlloc) { ensurePidList(pidListAlloc + 1024); } pidList[pidListUsed] = strtoul(args[ii], &p, 0); if (!(p && *p == '\0')) { fprint_err("### tsfilter: '%s' wasn't a valid number. \n", args[ii]); return 1; } ++pidListUsed; } ++ii; } if (!pidListUsed) { fprint_err("### tsfilter: No pids to filter. \n"); return 1; } // Now .. { int err; TS_reader_p tsreader; TS_writer_p tswriter; byte *pkt = NULL; unsigned int pid, pkt_num; int pusi, adapt_len, payload_len; byte *adapt, *payload; pkt_num = 0; err = open_file_for_TS_read((char *)input_file, &tsreader); if (err) { fprint_err("## tsfilter: Unable to open stdin for reading TS.\n"); return 1; } if (output_file) { err = tswrite_open(TS_W_FILE, (char *)output_file, NULL, 0, 1, &tswriter); } else { err = tswrite_open(TS_W_STDOUT, NULL, NULL, 0, 1, &tswriter); } if (err) { fprint_err("## tsfilter: Unable to open stdout for writing TS. \n"); return 1; } while (1) { err = read_next_TS_packet(tsreader, &pkt); if (err == EOF) { /* We're done */ break; } err = split_TS_packet(pkt, &pid, &pusi, &adapt, &adapt_len, &payload, &payload_len); if (err) { fprint_err("### Error splitting TS packet - continuing. \n"); } else { int i; int found = 0; for (i = 0 ;i < pidListUsed; ++i) { if (pid == pidList[i]) { ++found; // Yes! break; } } if (max_pkts != (unsigned int)-1 && pkt_num > max_pkts) { // We're done processing. If invert is on, // copy the rest of the output, otherwise quit. if (!invert) { break; } else { found = 0; } } // Invert the result, whatever it was. if (invert) { found = !found; } if (found) { // Write it out. err = tswrite_write(tswriter, pkt, pid, 0, 0); if (err) { fprint_err("### Error writing output - %d \n", err); return 2; } } ++pkt_num; } } // It's the end! tswrite_close(tswriter, 1); close_TS_reader(&tsreader); return 0; } }
/* * Read TS packets until we have found the PCR PID for our program stream, * outputting packets (without using their PCR) as we go. * * - `tsreader` is the TS reader context * - `tswriter` is our (buffered) writer * - `pcr_pid` is the PID containing PCRs as indicated by the PMT * - `num_read` is how many TS packets we read * - if `max` is greater than zero, then at most `max` TS packets should * be read from the input * - if `quiet` is true, then only error messages should be written out * * Returns 0 if all went well, 1 if something went wrong. */ static int find_PCR_PID(TS_reader_p tsreader, TS_writer_p tswriter, uint32_t *pcr_pid, uint32_t *num_read, int max, int quiet) { int err; int count = 0; byte *data; uint32_t pid; int payload_unit_start_indicator; byte *adapt; int adapt_len; byte *payload; int payload_len; int got_PAT = FALSE; pidint_list_p prog_list = NULL; pmt_p pmt = NULL; uint32_t pmt_pid = 0; // safe initial value byte *pat_data = NULL; int pat_data_len = 0; int pat_data_used = 0; byte *pmt_data = NULL; int pmt_data_len = 0; int pmt_data_used = 0; int pmt_program_number = -1; for (;;) { err = read_next_TS_packet(tsreader,&data); if (err == EOF) { fprint_err("### EOF (after %d TS packets), before finding program" " information\n",count); if (pmt_data) free(pmt_data); return 1; } else if (err) { fprint_err("### Error reading TS packet %d\n",count+1); if (pmt_data) free(pmt_data); return 1; } count++; err = split_TS_packet(data,&pid,&payload_unit_start_indicator, &adapt,&adapt_len,&payload,&payload_len); if (err) { fprint_err("### Error splitting TS packet %d\n",count); if (pmt_data) free(pmt_data); return 1; } // Whatever we've found, don't forget to write it out via the // circular buffer (and we *know* it doesn't have a PCR that is // useful to us, as yet) err = tswrite_write(tswriter,data,pid,FALSE,0); if (err) { fprint_err("### Error writing TS packet %d to circular buffer\n", count); if (pmt_data) free(pmt_data); return 1; } if (pid == 0x0000) { if (!quiet) fprint_msg("Packet %d is PAT\n",count); if (payload_unit_start_indicator && pat_data) { // This is the start of a new PAT packet, but we'd already // started one, so throw its data away print_err("!!! Discarding previous (uncompleted) PAT data\n"); free(pat_data); pat_data = NULL; pat_data_len = 0; pat_data_used = 0; } else if (!payload_unit_start_indicator && !pat_data) { // This is the continuation of a PAT packet, but we hadn't // started one yet print_err("!!! Discarding PAT continuation, no PAT started\n"); continue; } err = build_psi_data(FALSE,payload,payload_len,pid, &pat_data,&pat_data_len,&pat_data_used); if (err) { fprint_err("### Error %s PAT\n", (payload_unit_start_indicator?"starting new":"continuing")); if (pat_data) free(pat_data); return 1; } // Do we need more data to complete this PAT? if (pat_data_len > pat_data_used) continue; err = extract_prog_list_from_pat(FALSE,pat_data,pat_data_len,&prog_list); if (err != 0) { free(pat_data); return err; } if (!quiet) report_pidint_list(prog_list,"Program list","Program",FALSE); if (prog_list->length > 1 && !quiet) print_msg("Multiple programs in PAT - using the first\n\n"); pmt_pid = prog_list->pid[0]; pmt_program_number = prog_list->number[0]; got_PAT = TRUE; free_pidint_list(&prog_list); free(pat_data); pat_data = NULL; pat_data_len = 0; pat_data_used = 0; } else if (got_PAT && pid == pmt_pid) { if (!quiet) fprint_msg("Packet %d %s PMT with PID %04x\n", count, payload_unit_start_indicator?"starts":"continues", pmt_pid); if (payload_unit_start_indicator && pmt_data) { // This is the start of a new PMT packet, but we'd already // started one, so throw its data away print_err("!!! Discarding previous (uncompleted) PMT data\n"); free(pmt_data); pmt_data = NULL; pmt_data_len = 0; pmt_data_used = 0; } else if (!payload_unit_start_indicator && !pmt_data) { // This is the continuation of a PMT packet, but we hadn't // started one yet print_err("!!! Discarding PMT continuation, no PMT started\n"); continue; } err = build_psi_data(FALSE,payload,payload_len,pid, &pmt_data,&pmt_data_len,&pmt_data_used); if (err) { fprint_err("### Error %s PMT\n", (payload_unit_start_indicator?"starting new":"continuing")); if (pmt_data) free(pmt_data); return 1; } // Do we need more data to complete this PMT? if (pmt_data_len > pmt_data_used) continue; err = extract_pmt(FALSE,pmt_data,pmt_data_len,pmt_pid,&pmt); free(pmt_data); pmt_data = NULL; if (err) return err; if (pmt->program_number != pmt_program_number) { if (!quiet) fprint_msg("Discarding PMT program %d - looking for %d\n", pmt->program_number, pmt_program_number); free_pmt(&pmt); continue; } if (!quiet) report_pmt(TRUE," ",pmt); *pcr_pid = pmt->PCR_pid; free_pmt(&pmt); if (!quiet) fprint_msg("Taking timing information from PID 0x%03x\n",*pcr_pid); *num_read = count; return 0; } if (max > 0 && count >= max) { fprint_err("### Stopping after %d TS packets, before finding program" " information\n",max); if (pmt_data) free(pmt_data); return 1; } } }
static int digest_times(pcapreport_ctx_t *ctx, pcapreport_stream_t * const st, const pcaprec_hdr_t *pcap_pkt_hdr, const ethernet_packet_t *epkt, const ipv4_header_t *ipv4_header, const ipv4_udp_header_t *udp_header, const byte *data, const uint32_t len) { int rv; const uint64_t ts_byte_start = st->ts_bytes; if (st->ts_r == NULL) { rv = build_TS_reader_with_fns(st, digest_times_read, digest_times_seek, &st->ts_r); if (rv) { print_err( "### pcapreport: Cannot create ts reader.\n"); return 1; } } // Add all our data to the pool. { unsigned int pkts = len / 188; unsigned int pktlen = pkts * 188; if (pktlen != len) ++st->pkts_overlength; st->tmp_buf = (byte *)realloc(st->tmp_buf, st->tmp_len + pktlen); memcpy(&st->tmp_buf[st->tmp_len], data, pktlen); st->tmp_len += pktlen; st->ts_bytes += pktlen; } // Now read out all the ts packets we can. while (1) { byte *pkt; int rv; rv = read_next_TS_packet(st->ts_r, &pkt); if (rv == EOF) { // Got to EOF - return for more data return 0; } // Right. Split it .. { const uint64_t t_pcr = pkt_time(pcap_pkt_hdr); uint32_t pid; int pusi; byte *adapt; int adapt_len; byte *payload; int payload_len; rv = split_TS_packet(pkt, &pid, &pusi, &adapt, &adapt_len, &payload, &payload_len); if (rv) { fprint_msg(">%d> WARNING: TS packet %d [ packet %d @ %d.%d s ] cannot be split.\n", st->stream_no, st->ts_counter, ctx->pkt_counter, pcap_pkt_hdr->ts_sec, pcap_pkt_hdr->ts_usec); } else { //int cc; // PCR ? if (adapt && adapt_len) { int has_pcr; uint64_t pcr; int64_t pcr_time_offset; get_PCR_from_adaptation_field(adapt, adapt_len, &has_pcr, &pcr); if (has_pcr) { int64_t skew; if (ctx->time_report) { fprint_msg(">%d> Found PCR %lld at %d.%d s \n", st->stream_no, pcr, pcap_pkt_hdr->ts_sec, pcap_pkt_hdr->ts_usec); } if (st->pcr_pid == 0) st->pcr_pid = pid; if (pid != st->pcr_pid) { // *** If this happens often then fix to track each Pid if (!st->multiple_pcr_pids) { fprint_msg("!%d! Multiple pids detected: pids: %d,%d,...\n", st->stream_no, st->pcr_pid, pid); } st->multiple_pcr_pids = TRUE; } else { // PCR pops out in 27MHz units. Let's do all our comparisons // in 90kHz. pcr /= 300; // fprint_msg("pcr = %lld t_pcr = %lld diff = %lld\n", // pcr, t_pcr, t_pcr - pcr); pcr_time_offset = ((int64_t)t_pcr - (int64_t)pcr); skew = st->section_last == NULL ? 0LL : pcr_time_offset - (st->section_last->time_start - st->section_last->pcr_start); if (st->section_last == NULL || skew > st->skew_discontinuity_threshold || skew < -st->skew_discontinuity_threshold) { pcapreport_section_t * const tsect = section_create(st); if (tsect->section_no != 0) { fprint_msg(">%d> Skew discontinuity! Skew = %lld (> %lld) at" " ts = %d network = %d (PCR %lld Time %d.%d)\n", st->stream_no, skew, st->skew_discontinuity_threshold, st->ts_counter, ctx->pkt_counter, pcr, pcap_pkt_hdr->ts_sec, pcap_pkt_hdr->ts_usec); } tsect->pkt_final = tsect->pkt_start = ctx->pkt_counter; tsect->pcr_last = tsect->pcr_start = pcr; tsect->time_last = tsect->time_start = t_pcr; tsect->ts_byte_start = tsect->ts_byte_final = ts_byte_start; jitter_clear(&st->jitter); st->last_time_offset = 0; } else { pcapreport_section_t * const tsect = st->section_last; // Extract jitter over up to the last 10s. skew will be within // an int by now unsigned int cur_jitter = jitter_add(&st->jitter, (int)skew, (uint32_t)(t_pcr & 0xffffffffU), 90000 * 10); if (tsect->jitter_max < cur_jitter) tsect->jitter_max = cur_jitter; if (ctx->time_report) { int64_t rel_tim = t_pcr - tsect->time_start; // 90kHz double skew_rate = (double)skew / ((double)((double)rel_tim / (60*90000))); fprint_msg(">%d> [ts %d net %d ] PCR %lld Time %d.%d [rel %d.%d] - skew = %lld (delta = %lld, rate = %.4g PTS/min) - jitter=%u\n", st->stream_no, st->ts_counter, ctx->pkt_counter, pcr, pcap_pkt_hdr->ts_sec, pcap_pkt_hdr->ts_usec, (int)(rel_tim / (int64_t)1000000), (int)rel_tim%1000000, skew, pcr_time_offset - st->last_time_offset, skew_rate, cur_jitter); } if (st->csv_name != NULL) // We should be outputting to file { if (st->csv_file == NULL) { if ((st->csv_file = fopen(st->csv_name, "wt")) == NULL) { fprint_err("### pcapreport: Cannot open %s .\n", st->csv_name); exit(1); } fprintf(st->csv_file, "\"PKT\",\"Time\",\"PCR\",\"Skew\",\"Jitter\"\n"); } fprintf(st->csv_file, "%d,%llu,%llu,%lld,%u\n", ctx->pkt_counter, t_pcr - ctx->time_start, pcr, skew, cur_jitter); } // Remember where we are for posterity tsect->pcr_last = pcr; tsect->time_last = t_pcr; st->last_time_offset = pcr_time_offset; } } } } } { pcapreport_section_t * const tsect = st->section_last; if (tsect != NULL) { tsect->time_final = t_pcr; tsect->ts_byte_final = st->ts_bytes; tsect->pkt_final = ctx->pkt_counter; } } ++st->ts_counter; } } }
/* * Read TS packets and then output them, using the buffered approach * so that we read-ahead to get the next PCR, and thus have reliable * timing information. * * Assumes (strongly) that it is starting from the start of the file. * * - `tsreader` is the TS reader context * - `tswriter` is our (maybe buffered) writer * - if `pid_to_ignore` is non-zero, then any TS packets with that PID * will not be written out (note: any PCR information in them may still * be used) * - if `override_pcr_pid` is non-zero, then it is the PID to use for PCRs, * ignoring any value found in a PMT * - if `max` is greater than zero, then at most `max` TS packets should * be read from the input * - if `loop`, play the input file repeatedly (up to `max` TS packets * if applicable) * - if `quiet` is true, then only error messages should be written out * - if `verbose` is true, then give extra progress messages * * Returns 0 if all went well, 1 if something went wrong. */ static int play_buffered_TS_packets(TS_reader_p tsreader, TS_writer_p tswriter, uint32_t pid_to_ignore, uint32_t override_pcr_pid, int max, int loop, int quiet, int verbose) { int err; int total = 0; uint32_t count = 0; uint32_t pcr_pid; uint32_t start_count = 0; // which TS packet to loop from offset_t start_posn = 0; // These are only used in the loop below, but the compiler grumbles if // they're uninitialised (it isn't sure if they're being set by the call // to read_buffered_TS_packet() or not). I don't want to have to keep // thinking about the compiler warning, but I also know that these values // *will* be set by the function, so I don't want them reinitialised // every time round the loop. So hoist them back up to here... byte *data = NULL; uint32_t pid = 0; uint64_t pcr = 0; // Before we can use PCRs for timing, we need to read a PMT which tells us // what our video stream is (so we can get our PCRs therefrom). if (override_pcr_pid) { pcr_pid = override_pcr_pid; if (!quiet) fprint_msg("Forcing use of PCR PID 0x%03x (%d)\n",pcr_pid,pcr_pid); } else { err = find_PCR_PID(tsreader,tswriter,&pcr_pid,&start_count,max,quiet); if (err) { fprint_err("### Unable to find PCR PID for timing information\n" " Looked in first %d TS packets\n",max); return 1; } } // Once we've found that, we're ready to play our data err = prime_read_buffered_TS_packet(tsreader,pcr_pid); if (err) return 1; // If we're looping, remember the location of the first packet of (probable) // data - there's not much point rewinding before that point if (loop) start_posn = start_count * TS_PACKET_SIZE; count = start_count; for (;;) { err = read_buffered_TS_packet(tsreader,&count,&data,&pid,&pcr, max,loop,start_posn,start_count,quiet); if (err == EOF) // shouldn't occur if `loop` break; else if (err) { if (tsreader->file != STDIN_FILENO) { fprint_err("### Last TS packet read was at " LLU_FORMAT "\n", (uint64_t)count * TS_PACKET_SIZE); } return 1; } total ++; // If we've been asked to ignore this packet, we should be able to // just ignore it -- since all TS packets have their time associated // with them, we shouldn't need to send a "dummy" packet, just in // case it had time on it. if (pid_to_ignore != 0 && pid == pid_to_ignore) continue; // And write it out via the circular buffer err = tswrite_write(tswriter,data,pid,TRUE,pcr); if (err) { fprint_err("### Error writing TS packet %d to circular buffer\n", count); return 1; } if (!quiet && verbose && total%TSPLAY_REPORT_EVERY == 0) fprint_msg("Transferred %d TS packets\n",total); } if (!quiet) fprint_msg("Transferred %d TS packet%s in total\n",total,(total==1?"":"s")); return 0; }
int main(int argc, char **argv) { int use_stdin = FALSE; char *input_name = NULL; int had_input_name = FALSE; PS_reader_p ps; // The PS file we're reading int max = 0; // The maximum number of PS packets to read (or 0) int verbose = FALSE; // True => output diagnostic/progress messages int err = 0; int ii = 1; if (argc < 2) { print_usage(); return 0; } while (ii < argc) { if (argv[ii][0] == '-') { if (!strcmp("--help",argv[ii]) || !strcmp("-h",argv[ii]) || !strcmp("-help",argv[ii])) { print_usage(); return 0; } else if (!strcmp("-err",argv[ii])) { CHECKARG("psdots",ii); if (!strcmp(argv[ii+1],"stderr")) redirect_output_stderr(); else if (!strcmp(argv[ii+1],"stdout")) redirect_output_stdout(); else { fprint_err("### psdots: " "Unrecognised option '%s' to -err (not 'stdout' or" " 'stderr')\n",argv[ii+1]); return 1; } ii++; } else if (!strcmp("-verbose",argv[ii]) || !strcmp("-v",argv[ii])) { verbose = TRUE; } else if (!strcmp("-max",argv[ii]) || !strcmp("-m",argv[ii])) { CHECKARG("psdots",ii); err = int_value("psdots",argv[ii],argv[ii+1],TRUE,10,&max); if (err) return 1; ii++; } else if (!strcmp("-stdin",argv[ii])) { use_stdin = TRUE; had_input_name = TRUE; // so to speak } else { fprint_err("### psdots: " "Unrecognised command line switch '%s'\n",argv[ii]); return 1; } } else { if (had_input_name) { fprint_err("### psdots: Unexpected '%s'\n",argv[ii]); return 1; } else { input_name = argv[ii]; had_input_name = TRUE; } } ii++; } if (!had_input_name) { print_err("### psdots: No input file specified\n"); return 1; } err = open_PS_file(input_name,FALSE,&ps); if (err) { fprint_err("### psdots: Unable to open input file %s\n", (use_stdin?"<stdin>":input_name)); return 1; } fprint_msg("Reading from %s\n",(use_stdin?"<stdin>":input_name)); if (max) fprint_msg("Stopping after %d PS packets\n",max); err = report_ps_dots(ps,max,verbose); if (err) print_err("### psdots: Error reporting on input stream\n"); err = close_PS_file(&ps); if (err) { fprint_err("### psdots: Error closing input file %s\n", (use_stdin?"<stdin>":input_name)); return 1; } return 0; }
/* * Read TS packets and then output them. * * Assumes (strongly) that it is starting from the start of the file. * * - `tsreader` is the TS reader context * - `tswriter` is our (maybe buffered) writer * - if `pid_to_ignore` is non-zero, then any TS packets with that PID * will not be written out (note: any PCR information in them may still * be used) * - if `max` is greater than zero, then at most `max` TS packets should * be read from the input * - if `loop`, play the input file repeatedly (up to `max` TS packets * if applicable) * - if `quiet` is true, then only error messages should be written out * - if `verbose` is true, then give extra progress messages * * Returns 0 if all went well, 1 if something went wrong. */ extern int play_TS_packets(TS_reader_p tsreader, TS_writer_p tswriter, uint32_t pid_to_ignore, int max, int loop, int quiet, int verbose) { int err; int total = 0; uint32_t count = 0; int pcrs_used = 0; int pcrs_ignored = 0; uint32_t pcr_pid; uint32_t start_count = 0; // which TS packet to loop from offset_t start_posn = 0; // Before we can use PCRs for timing, we need to read a PMT which tells us // what our video stream is (so we can get our PCRs therefrom). err = find_PCR_PID(tsreader,tswriter,&pcr_pid,&start_count,max,quiet); if (err) { fprint_err("### Unable to find PCR PID for timing information\n" " Looked in first %d TS packets\n",max); return 1; } // Once we've found that, we're ready to play our data // If we're looping, remember the location of the first packet of (probable) // data - there's not much point rewinding before that point if (loop) start_posn = start_count * TS_PACKET_SIZE; count = start_count; for (;;) { byte *data; uint32_t pid; int got_pcr; uint64_t pcr; err = read_TS_packet(tsreader,&count,&data,&pid,&got_pcr,&pcr, max,loop,start_posn,start_count,quiet); if (err == EOF) // shouldn't occur if `loop` break; else if (err) { if (tsreader->file != STDIN_FILENO) { fprint_err("### Last TS packet read was at " LLU_FORMAT "\n", (uint64_t)count * TS_PACKET_SIZE); } return 1; } total ++; // We are only interested in timing information from our PCR PID stream if (got_pcr) { if (pid == pcr_pid) pcrs_used ++; else { pcrs_ignored ++; got_pcr = FALSE; } } if (pid_to_ignore != 0 && pid == pid_to_ignore) { // We want to "transmit" this packet, since that's the simplest // way of sending its timing information (if any) to the writer. // However, we don't want to *actually* send meaningful data. // The simplest thing is to ignore it if it doesn't have a PCR: // and otherwise, change it to a null packet, by resetting its PID. if (!got_pcr) continue; else { data[2] = 0xFF; data[1] |= 0x1F; } } // And write it out via the circular buffer err = tswrite_write(tswriter,data,pid,got_pcr,pcr); if (err) { fprint_err("### Error writing TS packet %d to circular buffer\n", count); return 1; } if (!quiet && verbose && total%TSPLAY_REPORT_EVERY == 0) fprint_msg("Transferred %d TS packets\n",total); } if (!quiet) { fprint_msg("Transferred %d TS packet%s in total\n",total,(total==1?"":"s")); fprint_msg("Used PCRs from %d packets, ignored PCRs from %d packets\n", pcrs_used,pcrs_ignored); } return 0; }
/* * Extract data and output it as PS * * Returns 0 if all went well, 1 if something went wrong. */ static int extract_data(int input, FILE *output, uint16_t program_number, int max, int verbose, int quiet) { int err; PES_reader_p reader; err = build_PES_reader(input,TRUE,!quiet,!quiet,program_number,&reader); if (err) { print_err("### Error building PES reader over input file\n"); return 1; } // Temporarily, just writes out PES packets, not a PS stream... for (;;) { size_t count; err = read_next_PES_packet(reader); if (err == EOF) break; else if (err) { print_err("### Error reading next PES packet\n"); (void) free_PES_reader(&reader); return 1; } err = write_pack_header(output); if (err) { print_err("### Error writing PS pack header\n"); (void) free_PES_reader(&reader); return 1; } // It is possible that the TS data for video might have specified a zero // length in the PES. Our TS reader will have read all of the packet for // us, but will not have "adjusted" said length at the start of the packet. // It is thus up to us to catch this case and amend it before we output // the data... if (reader->packet->data[4] == 0 && reader->packet->data[5] == 0) { int32_t PES_packet_length = reader->packet->data_len - 6; byte *start = reader->packet->data; // Our maximum length is determined by the maximum length we can // indicate in the two bytes of the PES_packet_length. When we're // *writing* data, we also have to allow for writing the two flag // bytes and PES_header_data_length that come thereafter. #define MAX_LENGTH 0xFFFF if (PES_packet_length > MAX_LENGTH) { fprint_err("PES packet of 'zero' length is really %6d - too long for one packet\n", PES_packet_length); // Output what we can of the original packet reader->packet->data[4] = (MAX_LENGTH & 0xFF00) >> 8; reader->packet->data[5] = (MAX_LENGTH & 0x00FF); // Remember that we also write out the 6 bytes preceding those // MAX_LENGTH bytes... fprint_err(".. writing out %5d (%5d total)\n",MAX_LENGTH,MAX_LENGTH+6); count = fwrite(reader->packet->data,MAX_LENGTH+6,1,output); if (count != 1) { print_err("### Error writing (start of) PES packet out to file\n"); (void) free_PES_reader(&reader); return 1; } PES_packet_length -= MAX_LENGTH; start += MAX_LENGTH+6; while (PES_packet_length > 0) { // Now, when writing out chunks of data as PES packets, // we have 6 bytes of header (00 00 01 stream_id length/length) // followed by two bytes of flags (81 00) and a zero // PES_header_data_length (00). Those last three bytes have // to be included in the PES_packet_length of the PES packet // we write out, which means that the longest "chunk" of data // we can write is three less than the (otherwise) maximum. int this_length = min(MAX_LENGTH-3,PES_packet_length); int err; fprint_err(".. writing out %5d\n",this_length); err = write_PES_packet(output,start,this_length, reader->packet->data[3]); if (err) { print_err("### Error writing (part of) PES packet out to file\n"); (void) free_PES_reader(&reader); return 1; } PES_packet_length -= this_length; start += this_length; } } else {
/* * Try to decide if we *have* got program stream * * Returns 0 if nothing went wrong, 1 if something did. */ static int check_if_PS(int input, int verbose, int *decided, int *result) { int err; byte buf[10]; int stuffing_length; if (verbose) { print_msg("Is it Program Stream?\n"); print_msg(" Trying to read pack header\n"); } err = read_bytes(input,4,buf); if (err) { fprint_err("### %s trying to read start of first PS packet\n", (err==EOF?"EOF":"Error")); return 1; } if (buf[0] != 0 || buf[1] != 0 || buf[2] != 1 || buf[3] != 0xba) { if (verbose) fprint_msg(" File starts %02X %02X %02X %02X, not 00 00 01 BA - not PS\n", buf[0],buf[1],buf[2],buf[3]); return 0; } if (verbose) print_msg(" File starts 00 00 01 BA - could be PS," " reading pack header body\n"); err = read_bytes(input,8,buf); if (err) { fprint_err("### %s trying to read body of PS pack header\n", (err==EOF?"EOF":"Error")); return 1; } if ((buf[0] & 0xF0) == 0x20) { if (verbose) print_msg(" Looks like ISO/IEC 11171-1/MPEG-1 pack header\n"); } else if ((buf[0] & 0xC0) == 0x40) { if (verbose) print_msg(" Looks like ISO/IEC 13818-1/H.222.0 pack header\n"); err = read_bytes(input,2,&(buf[8])); if (err) { fprint_err("### %s trying to read last 2 bytes of body of PS pack header\n", (err==EOF?"EOF":"Error")); return 1; } stuffing_length = buf[9] & 0x07; // And ignore that many stuffing bytes... if (stuffing_length > 0) { err = read_bytes(input,stuffing_length,buf); if (err) { fprint_err("### %s trying to read PS pack header stuffing bytes\n", (err==EOF?"EOF":"Error")); return 1; } } } // We could check for reserved bits - maybe at another time if (verbose) print_msg(" OK, trying to read start of next packet\n"); err = read_bytes(input,4,buf); if (err) { fprint_err("### %s trying to read start of next PS packet\n", (err==EOF?"EOF":"Error")); return 1; } if (buf[0] != 0 || buf[1] != 0 || buf[2] != 1) { if (verbose) fprint_msg(" Next 'packet' starts %02X %02X %02X, not 00 00 01 - not PS\n", buf[0],buf[1],buf[2]); return 0; } if (verbose) print_msg(" Start of second packet found at right place - looks like PS\n"); *decided = TRUE; *result = STREAM_IS_PS; return 0; }