/* * 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; }
/* * 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; } } }