/* * Report on TS packets with a particular PID in the given file * * Returns 0 if all went well, 1 if something went wrong. */ static int report_single_pid(TS_reader_p tsreader, int max, int quiet, uint32_t just_pid) { int err; int count = 0; int pid_count = 0; for (;;) { uint32_t pid; int payload_unit_start_indicator; byte *adapt, *payload; int adapt_len, payload_len; if (max > 0 && pid_count >= max) { printf("Stopping after %d packets with PID %0x\n",max,just_pid); 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) { fprintf(stderr,"### Error reading TS packet %d at " OFFSET_T_FORMAT "\n",count,tsreader->posn - TS_PACKET_SIZE); return 1; } count ++; if (pid != just_pid) continue; pid_count ++; if (!quiet) { printf(OFFSET_T_FORMAT_8 ": TS Packet %2d PID %04x%s\n", tsreader->posn - TS_PACKET_SIZE,count,pid, (payload_unit_start_indicator?" [pusi]":"")); if (adapt_len > 0) print_data(stdout," Adapt",adapt,adapt_len,adapt_len); print_data(stdout, " Payload",payload,payload_len,payload_len); } } printf("Read %d TS packet%s, %d with PID %0x\n", count,(count==1?"":"s"),pid_count,just_pid); return 0; }
/* * Report on the given file * * Returns 0 if all went well, 1 if something went wrong. */ static int report_ts(TS_reader_p tsreader, int max, int verbose, int show_data, int report_timing) { struct timing times = {0}; pidint_list_p prog_list = NULL; pmt_p pmt = NULL; int err; int count = 0; timing_p time_ptr = NULL; byte *pat_data = NULL; int pat_data_len = 0; int pat_data_used = 0; uint32_t unfinished_pmt_pid = 0; byte *pmt_data = NULL; int pmt_data_len = 0; int pmt_data_used = 0; if (report_timing) time_ptr = × for (;;) { uint32_t pid; int payload_unit_start_indicator; byte *adapt, *payload; int adapt_len, payload_len; if (max > 0 && count >= max) { printf("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) { fprintf(stderr,"### Error reading TS packet %d at " OFFSET_T_FORMAT "\n",count,tsreader->posn - TS_PACKET_SIZE); free_pidint_list(&prog_list); if (pmt_data) free(pmt_data); return 1; } count ++; if (verbose) printf(OFFSET_T_FORMAT_8 ": TS Packet %2d PID %04x%s", tsreader->posn - TS_PACKET_SIZE,count,pid, (payload_unit_start_indicator?" [pusi]":"")); // Report on what we may if (verbose) { if (pid == 0x1fff) printf(" PADDING - ignored\n"); else if (pid == 0x0000) printf(" PAT\n"); else if (pid == 0x0001) printf(" Conditional Access Table - ignored\n"); else if (pid >= 0x0002 && pid <= 0x000F) printf(" RESERVED - ignored\n"); else if (pid_in_pidint_list(prog_list,pid)) printf(" PMT\n"); else if (pid_in_pmt(pmt,pid)) { pmt_stream_p stream = pid_stream_in_pmt(pmt,pid); if (stream == NULL) { fprintf(stderr,"### Internal error: stream for PID %0x returned NULL" " in PMT\n",pid); report_pmt(stderr," ",pmt); free_pidint_list(&prog_list); free_pmt(&pmt); if (pmt_data) free(pmt_data); return 1; } printf(" stream type %02x (%s)\n", stream->stream_type,h222_stream_type_str(stream->stream_type)); } else printf(" stream type not identified\n"); } // Ignore padding packets if (pid == 0x1fff) continue; // Conditional Access Tables *might* contain a PCR - do we want // to ignore them anyway? Well, since I've never seen one, do so for now if (pid == 0x0001) continue; if (report_timing) report_adaptation_timing(time_ptr,adapt,adapt_len,count); else if (verbose) report_adaptation_field(adapt,adapt_len); if (pid == 0) { if (payload_unit_start_indicator && pat_data) { // Lose any data we started but didn't complete free(pat_data); pat_data = NULL; pat_data_len = 0; pat_data_used = 0; } else if (!payload_unit_start_indicator && !pat_data) { fprintf(stderr,"!!! Discarding partial (unstarted) PAT in TS" " packet at " OFFSET_T_FORMAT "\n", tsreader->posn - TS_PACKET_SIZE); continue; } err = build_psi_data(verbose,payload,payload_len,pid, &pat_data,&pat_data_len,&pat_data_used); if (err) { fprintf(stderr,"### Error %s PAT in TS packet at " OFFSET_T_FORMAT "\n", (payload_unit_start_indicator?"starting new":"continuing"), tsreader->posn - TS_PACKET_SIZE); free_pidint_list(&prog_list); if (pat_data) free(pat_data); return 1; } // Still need more data for this PAT if (pat_data_len > pat_data_used) continue; // Free any earlier program list we'd read, now we've got a new one free_pidint_list(&prog_list); err = extract_prog_list_from_pat(verbose,pat_data,pat_data_len,&prog_list); if (err) { fprintf(stderr,"### Error extracting program list from PAT in TS" " packet at " OFFSET_T_FORMAT "\n", tsreader->posn - TS_PACKET_SIZE); free_pidint_list(&prog_list); if (pat_data) free(pat_data); return 1; } if (pat_data) free(pat_data); pat_data = NULL; pat_data_len = 0; pat_data_used = 0; } else if (pid_in_pidint_list(prog_list,pid)) { // We don't cope with interleaved PMT's with different PIDs if (unfinished_pmt_pid != 0 && pid != unfinished_pmt_pid) { // We're already part way through a PMT packet, but it's not // the same PMT as the one in this TS packet if (payload_unit_start_indicator) { // This is the start (and maybe also the end) of a new PMT, // so let's read this one // - actually, we don't need to do anything here, as our // data will get "thrown away" further down } else { // This is the continuation of another PMT - let's ignore // it for now and hope we'll find the rest of the one we're // still waiting to finish fprintf(stderr,"!!! Discarding partial PMT with PID %04x in TS" " packet at " OFFSET_T_FORMAT ", already building PMT with PID %04x\n", unfinished_pmt_pid, tsreader->posn - TS_PACKET_SIZE,pid); continue; } } if (payload_unit_start_indicator && pmt_data) { // Lose any data we started but didn't complete free(pmt_data); pmt_data = NULL; pmt_data_len = 0; pmt_data_used = 0; } else if (!payload_unit_start_indicator && !pmt_data) { fprintf(stderr,"!!! Discarding partial (unstarted) PMT in TS" " packet at " OFFSET_T_FORMAT "\n", tsreader->posn - TS_PACKET_SIZE); continue; } err = build_psi_data(verbose,payload,payload_len,pid, &pmt_data,&pmt_data_len,&pmt_data_used); if (err) { fprintf(stderr,"### Error %s PMT in TS packet at " OFFSET_T_FORMAT "\n", (payload_unit_start_indicator?"starting new":"continuing"), tsreader->posn - TS_PACKET_SIZE); free_pidint_list(&prog_list); free_pmt(&pmt); if (pmt_data) free(pmt_data); return 1; } // Still need more data for this PMT if (pmt_data_len > pmt_data_used) { unfinished_pmt_pid = pid; continue; } // Free any earlier PMT data we'd read, now we've got a new one free_pmt(&pmt); // Which isn't unfinished anymore unfinished_pmt_pid = 0; err = extract_pmt(verbose,pmt_data,pmt_data_len,pid,&pmt); if (err) { fprintf(stderr,"### Error extracting stream list from PMT in TS" " packet at " OFFSET_T_FORMAT "\n", tsreader->posn - TS_PACKET_SIZE); free_pidint_list(&prog_list); free_pmt(&pmt); if (pmt_data) free(pmt_data); return err; } if (pmt_data) free(pmt_data); pmt_data = NULL; pmt_data_len = 0; pmt_data_used = 0; #if 0 printf("PMT data read as:\n"); report_pmt(stdout," ",pmt); printf("\n"); #endif } else if (verbose) { pmt_stream_p stream = pid_stream_in_pmt(pmt,pid); int stream_type; if (stream == NULL) stream_type = -1; else stream_type = stream->stream_type; report_payload(show_data,stream_type,payload,payload_len, payload_unit_start_indicator); if (!show_data && payload_unit_start_indicator) { print_data(stdout," Data",payload,payload_len,20); } #if 0 // XXX print_end_of_data(stdout," ",payload,payload_len,20); #endif } } printf("Read %d TS packet%s\n",count,(count==1?"":"s")); free_pidint_list(&prog_list); free_pmt(&pmt); if (pmt_data) free(pmt_data); return 0; }
/* * 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; }