Exemplo n.º 1
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;
}
Exemplo n.º 2
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;
    }
  }
}
Exemplo n.º 3
0
/*
 * Report on the given file
 *
 * Returns 0 if all went well, 1 if something went wrong.
 */
static int report_buffering_stats(TS_reader_p  tsreader,
                                  int          max,
                                  int          verbose,
                                  int          quiet,
                                  char        *output_name,
                                  uint32_t     continuity_cnt_pid,
                                  uint64_t     report_mask)
{
  pmt_p         pmt = NULL;
  int           err;
  FILE         *file = NULL;
  int           num_streams = 0;
  FILE         *file_cnt = NULL;

  // Define an arbitrary maximum number of streams we support
  // -- this is simpler than coping with changing the array sizes
  // when we find PMTs that indicate we need more streams -- this
  // limit should be big enough (we believe!) for any file we're
  // likely to find.
#define MAX_NUM_STREAMS       100

  struct stream_data stats[MAX_NUM_STREAMS];

  // We want to be able to report on how well a simple linear-prediction
  // model for PCRs would work (i.e., given the last two PCRs, how well
  // can we predict the *actual* PCR value). It's useful to bundle the
  // data for that in one place...
  struct linear_prediction_data {
    int           had_a_pcr;      // Have we had a PCR from a PCR PID TS?
    uint64_t      prev_pcr;       // if we have, what the last one was
    offset_t      prev_pcr_posn;  // and which TS it was from
    double        pcr_rate;
    int           know_pcr_rate;
    int64_t       min_pcr_error;  // 27MHz
    int64_t       max_pcr_error;  // 27MHz
  };
  struct linear_prediction_data predict = {0};

  uint32_t      pcr_pid;
  uint64_t      first_pcr = 0;
  int           pmt_at = 0;     // in case we don't look for a PMT
  int           index;
  int           ii;

  int           first = TRUE;
  offset_t      posn = 0;
  offset_t      start_posn = 0;
  uint32_t       count = 0;
  uint32_t       start_count = 0;

  memset(stats,0,sizeof(stats));
  for (ii=0; ii<MAX_NUM_STREAMS; ii++)
  {
    stats[ii].pcr_pts_diff.min = LONG_MAX;
    stats[ii].pcr_dts_diff.min = LONG_MAX;
    stats[ii].pcr_pts_diff.max = LONG_MIN;
    stats[ii].pcr_dts_diff.max = LONG_MIN;
    stats[ii].last_cc = -1;
  }
  predict.min_pcr_error = LONG_MAX;
  predict.max_pcr_error = LONG_MIN;

  if (output_name)
  {
    file = fopen(output_name,"w");
    if (file == NULL)
    {
      fprintf(stderr,"### tsreport: Unable to open file %s: %s\n",
              output_name,strerror(errno));
      return 1;
    }
    printf("Writing CSV data to file %s\n",output_name);
    fprintf(file,"#TSoffset,calc|read,PCR/300,stream,audio|video,PTS,DTS,ESCR\n");
  }

  // First we need to determine what we're taking our data from.
  err = find_pmt(tsreader,max,FALSE,quiet,&pmt_at,&pmt);
  if (err) return 1;

  pcr_pid = pmt->PCR_pid;

  for (ii=0; ii<pmt->num_streams; ii++)
  {
    uint32_t pid = pmt->streams[ii].elementary_PID;
    if (ii >= MAX_NUM_STREAMS)
    {
      printf("!!! Found more than %d streams -- just reporting on the first %d found\n",
             MAX_NUM_STREAMS,MAX_NUM_STREAMS);
      break;
    }
    if (pid >= 0x10 && pid <= 0x1FFE)
    {
      stats[num_streams].stream_type = pmt->streams[ii].stream_type;
      stats[num_streams].pid = pid;
      num_streams ++;
    }
  }

  printf("Looking at PCR PID %04x (%d)\n",pcr_pid,pcr_pid);
  for (ii=0; ii<num_streams; ii++)
    printf("  Stream %d: PID %04x (%d), %s\n",ii,stats[ii].pid,stats[ii].pid,
           h222_stream_type_str(stats[ii].stream_type));

  // Now do the actual work...
  start_count = count = pmt_at;
  start_posn  = posn  = tsreader->posn - TS_PACKET_SIZE;

  if (continuity_cnt_pid != INVALID_PID)
  {
    file_cnt = fopen("continuity_counter.txt","w"); //lorenzo
    if (file_cnt == NULL)
    {
      fprintf(stderr,"### tsreport: Unable to open file continuity_counter.txt\n");
      return 1;
    }
  }
  for (;;)
  {
    uint32_t pid;
    int     payload_unit_start_indicator;
    byte   *packet;
    byte   *adapt, *payload;
    int     adapt_len, payload_len;
    int     got_pcr = FALSE;
    uint64_t acc_pcr = 0;        // The accurate PCR per TS packet

    if (max > 0 && count >= (uint32_t)max)
    {
      printf("Stopping after %d packets (PMT was at %d)\n",max,pmt_at);
      break;
    }

    // Read the next TS packet, taking advantage of our read-ahead buffering
    // so that we know what its PCR *really* is
    if (first)
    {
      err = read_first_TS_packet_from_buffer(tsreader,pcr_pid,start_count,
                                             &packet,&pid,&acc_pcr,&count);
      posn = start_posn + (count-start_count)*TS_PACKET_SIZE;
      first = FALSE;
    }
    else
    {
      err = read_next_TS_packet_from_buffer(tsreader,&packet,&pid,&acc_pcr);
      count ++;
      posn += TS_PACKET_SIZE;
    }
    if (err == EOF)
      break;
    else if (err)
    {
      fprintf(stderr,"### Error reading TS packet %d at " OFFSET_T_FORMAT
              "\n",count,posn);
      return 1;
    }

    err = split_TS_packet(packet,&pid,
                          &payload_unit_start_indicator,
                          &adapt,&adapt_len,&payload,&payload_len);
    if (err)
    {
      fprintf(stderr,"### Error splitting TS packet %d at " OFFSET_T_FORMAT
              "\n",count,posn);
      return 1;
    }

    // ========================================================================
    // If we actually had a PCR, then we need to remember it
    if (pid == pcr_pid)
    {
      uint64_t   adapt_pcr;
      // Do I need to check that this is the same PCR I got earlier?
      // I certainly hope not...
      get_PCR_from_adaptation_field(adapt,adapt_len,&got_pcr,&adapt_pcr);
      if (got_pcr)
      {
        if (predict.know_pcr_rate)
        {
          // OK, so what we have predicted this PCR would be,
          // given the previous two PCRs and a linear rate?
          uint64_t guess_pcr = estimate_pcr(posn,predict.prev_pcr_posn,
                                           predict.prev_pcr,predict.pcr_rate);
          int64_t delta = adapt_pcr - guess_pcr;
          if (delta < predict.min_pcr_error)
            predict.min_pcr_error = delta;
          if (delta > predict.max_pcr_error)
            predict.max_pcr_error = delta;
        }

        if (verbose)
          printf(OFFSET_T_FORMAT_8 ": read PCR %s\n",
                 posn,
                 fmtx_timestamp(adapt_pcr, tfmt_abs | FMTX_TS_N_27MHz));
        if (file)
          fprintf(file,LLU_FORMAT ",read," LLU_FORMAT ",,,,\n",
                  posn,(adapt_pcr / (int64_t)300) & report_mask);

        if (predict.had_a_pcr)
        {
          if (predict.prev_pcr > adapt_pcr)
          {
            fprintf(stderr,"!!! PCR %s at TS packet "
                    OFFSET_T_FORMAT " is not more than previous PCR %s\n",
                    fmtx_timestamp(adapt_pcr, tfmt_abs | FMTX_TS_N_27MHz),
                    posn,
                    fmtx_timestamp(predict.prev_pcr, tfmt_abs | FMTX_TS_N_27MHz));
          }
          else
          {
            uint64_t delta_pcr = adapt_pcr - predict.prev_pcr;
            int delta_bytes = (int)(posn - predict.prev_pcr_posn);
            predict.pcr_rate = ((double)delta_bytes * 27.0 / (double)delta_pcr) * 1000000.0;
            predict.know_pcr_rate = TRUE;
#if 0   // XXX
            printf("PCR RATE = %f, DELTA_BYTES = %d, DELTA_PCR " LLU_FORMAT
                   ", PCR = " LLU_FORMAT "\n",
                   predict.pcr_rate,delta_bytes,delta_pcr,adapt_pcr);
#endif
          }
        }
        else
        {
          if (!quiet)
            printf("First PCR at " OFFSET_T_FORMAT "\n",posn);
          first_pcr = adapt_pcr;
          predict.had_a_pcr = TRUE;
        }
        predict.prev_pcr = adapt_pcr;
        predict.prev_pcr_posn = posn;
      }
    }   // end of working with a PCR PID packet
    // ========================================================================

    index = pid_index(stats,num_streams,pid);

    if (index != -1)
    {
      // Do continuity counter checking
      int cc = packet[3] & 15;

      // Log if required
      if (continuity_cnt_pid == pid)
        fprintf(file_cnt, "%d%c", cc, cc == 15 ? '\n' : ' ');

      if (stats[index].last_cc > 0)
      {
        // We are allowed 1 dup packet
        // *** Could check that it actually is a dup...
        if (stats[index].last_cc == cc)
        {
          if (stats[index].cc_dup_count++ != 0)
          {
            if (stats[index].err_cc_dup_error++ == 0)
            {
              if (continuity_cnt_pid == pid)
                fprintf(file_cnt, "[Duplicate error] ");
              printf("### PID(%d): Continuity Counter >1 duplicate %d at " OFFSET_T_FORMAT "\n",
                stats[index].pid, cc, posn);
            }
          }
        }
        else
        {
          // Otherwise CC must go up by 1 mod 16
          stats[index].cc_dup_count = 0;
          if (((stats[index].last_cc + 1) & 15) != cc)
          {
            if (stats[index].err_cc_error++ == 0)
            {
              if (continuity_cnt_pid == pid)
                fprintf(file_cnt, "[Discontinuity] ");
              printf("### PID(%d): Continuity Counter discontinuity %d->%d at " OFFSET_T_FORMAT "\n",
                stats[index].pid, stats[index].last_cc, cc, posn);
            }
          }
        }
      }
      stats[index].last_cc = cc;
    }

    if (index != -1 && payload && payload_unit_start_indicator)
    {
      // We are the start of a PES packet
      // We'll assume "enough" of the PES packet is in this TS
      int   got_pts, got_dts;
      const uint64_t last_dts = stats[index].dts;
      uint64_t pcr_time_now_div300 = 0;
      int64_t   difference;
      err = find_PTS_DTS_in_PES(payload,payload_len,
                                &got_pts,&stats[index].pts,&got_dts,&stats[index].dts);
      if (err)
      {
        fprintf(stderr,"### Error looking for PTS/DTS in TS packet at "
                OFFSET_T_FORMAT "\n",posn);
        return 1;
      }

      if (got_dts && !got_pts)
      {
        fprintf(stderr,"### Got DTS but not PTS, in TS packet at "
                OFFSET_T_FORMAT "\n",posn);
        return 1;
      }

      if (!got_pts)
        continue;

      pcr_time_now_div300 = acc_pcr/300;

      // Do a few simple checks
      // For the sake of simplicity we ignore 33bit wrap...
      if (stats[index].pts < stats[index].dts)
      {
        if (stats[index].err_pts_lt_dts++ == 0)
          printf("### PID(%d): PTS (%s) < DTS (%s)\n",
            stats[index].pid,
            fmtx_timestamp(stats[index].pts, tfmt_abs),
            fmtx_timestamp(stats[index].dts, tfmt_abs));
      }
      if (stats[index].had_a_dts && stats[index].dts < last_dts)
      {
        if (stats[index].err_dts_lt_prev_dts++ == 0)
          printf("### PID(%d): DTS (%s) < previous DTS (%s)\n",
            stats[index].pid,
            fmtx_timestamp(stats[index].dts, tfmt_abs),
            fmtx_timestamp(last_dts, tfmt_abs));
      }
      if (stats[index].dts < pcr_time_now_div300)
      {
        if (stats[index].err_dts_lt_pcr++ == 0)
          printf("### PID(%d): DTS (%s) < PCR (%s)\n",
            stats[index].pid,
            fmtx_timestamp(stats[index].dts, tfmt_abs),
            fmtx_timestamp(acc_pcr, tfmt_abs | FMTX_TS_N_27MHz));
      }

      if (!stats[index].had_a_pts)
      {
#if 0  // XXX Sometimes useful to know
        printf("  First stream %d PTS (after first PCR) at " OFFSET_T_FORMAT "\n",
               index,posn);
#endif
        stats[index].first_pts = stats[index].pts;
        stats[index].had_a_pts = TRUE;
      }
      if (got_dts && !stats[index].had_a_dts)
      {
#if 0  // XXX Sometimes useful to know
        printf("  First stream %d DTS (after first PCR) at " OFFSET_T_FORMAT "\n",
               index,posn);
#endif
        stats[index].first_dts = stats[index].dts;
        stats[index].had_a_dts = TRUE;
      }
      if (got_pts != got_dts || (got_pts && stats[index].pts != stats[index].dts))
        stats[index].pts_ne_dts = TRUE;

      if (file)
      {
        // At the moment, we only report any ESCR to the file
        int       got_escr = FALSE;
        uint64_t   escr;
        (void) find_ESCR_in_PES(payload,payload_len,&got_escr,&escr);

        fprintf(file,OFFSET_T_FORMAT ",%s," LLU_FORMAT ",%d,%s,",
                posn,
                (pcr_pid == pid && got_pcr)?"read":"calc",
                pcr_time_now_div300 & report_mask,
                index,
                IS_AUDIO_STREAM_TYPE(stats[index].stream_type)?"audio":
                IS_VIDEO_STREAM_TYPE(stats[index].stream_type)?"video":"");

        fprintf(file,LLU_FORMAT ",",stats[index].pts & report_mask);
        if (got_dts)
          fprintf(file,LLU_FORMAT,stats[index].dts & report_mask);
        else
          fprintf(file,LLU_FORMAT,stats[index].pts & report_mask);
        fprintf(file,",");
        if (got_escr)
        {
          if (!quiet)
            printf("Found ESCR " LLU_FORMAT " at " OFFSET_T_FORMAT "\n",
                   escr,posn);
          fprintf(file,LLU_FORMAT,escr & report_mask);
        }
        fprintf(file,"\n");
      }

      if (verbose)
      {
        printf(OFFSET_T_FORMAT_8 ": %s PCR " LLU_FORMAT " %d %5s",
               posn,
               (pcr_pid == pid && got_pcr)?"    ":"calc",
               pcr_time_now_div300,
               index,
               IS_AUDIO_STREAM_TYPE(stats[index].stream_type)?"audio":
               IS_VIDEO_STREAM_TYPE(stats[index].stream_type)?"video":"");
      }

      difference = stats[index].pts - pcr_time_now_div300;
      if (verbose)
      {
        printf(" PTS " LLU_FORMAT,stats[index].pts);
        printf(" PTS-PCR ");
        printf(LLD_FORMAT, difference);
      }
      if (difference > stats[index].pcr_pts_diff.max)
      {
        stats[index].pcr_pts_diff.max = difference;
        stats[index].pcr_pts_diff.max_at = stats[index].pts;
        stats[index].pcr_pts_diff.max_posn = posn;
      }
      if (difference < stats[index].pcr_pts_diff.min)
      {
        stats[index].pcr_pts_diff.min = difference;
        stats[index].pcr_pts_diff.min_at = stats[index].pts;
        stats[index].pcr_pts_diff.min_posn = posn;
      }
      stats[index].pcr_pts_diff.sum += difference;
      stats[index].pcr_pts_diff.num ++;

      if (got_dts)
      {
        difference = stats[index].dts - pcr_time_now_div300;
        if (verbose)
        {
          printf(" DTS " LLU_FORMAT,stats[index].dts);
          printf(" DTS-PCR ");
          printf(LLD_FORMAT, difference & report_mask);
        }
        if (difference > stats[index].pcr_dts_diff.max)
        {
          stats[index].pcr_dts_diff.max = difference;
          stats[index].pcr_dts_diff.max_at = stats[index].dts;
          stats[index].pcr_dts_diff.max_posn = posn;
        }
        if (difference < stats[index].pcr_dts_diff.min)
        {
          stats[index].pcr_dts_diff.min = difference;
          stats[index].pcr_dts_diff.min_at = stats[index].dts;
          stats[index].pcr_dts_diff.min_posn = posn;
        }
        stats[index].pcr_dts_diff.sum += difference;
        stats[index].pcr_dts_diff.num ++;
      }

      if (verbose)
        printf("\n");
    }
  }

  if (continuity_cnt_pid != INVALID_PID)
  {
    fprintf(file_cnt, "\n");
    fclose(file_cnt); //lorenzo
  }

  if (!quiet)
    printf("Last PCR at " OFFSET_T_FORMAT "\n",predict.prev_pcr_posn);
  printf("Read %d TS packet%s\n",count,(count==1?"":"s"));
  if (pmt) free_pmt(&pmt);
  if (file) fclose(file);

  printf("Linear PCR prediction errors: min=%s, max=%s\n",
         fmtx_timestamp(predict.min_pcr_error, tfmt_diff),
         fmtx_timestamp(predict.max_pcr_error, tfmt_diff));

  if (!stats[0].had_a_pts && !stats[1].had_a_pts &&
      !stats[0].had_a_dts && !stats[1].had_a_dts)
    printf("\n"
           "No PTS or DTS values found\n");

  for (ii = 0; ii < num_streams; ii++)
  {
    printf("\nStream %d: PID %04x (%d), %s\n",ii,stats[ii].pid,stats[ii].pid,
           h222_stream_type_str(stats[ii].stream_type));
    if (stats[ii].pcr_pts_diff.num > 0)
    {
      printf("  PCR/%s:\n    Minimum difference was %6s at DTS %8s, TS packet at " OFFSET_T_FORMAT_8 "\n",
             stats[ii].pts_ne_dts ? "PTS" : "PTS,DTS",
             fmtx_timestamp(stats[ii].pcr_pts_diff.min, tfmt_diff),
             fmtx_timestamp(stats[ii].pcr_pts_diff.min_at, tfmt_abs),
             stats[ii].pcr_pts_diff.min_posn);
      printf("    Maximum difference was %6s at DTS %8s, TS packet at " OFFSET_T_FORMAT_8 "\n",
             fmtx_timestamp(stats[ii].pcr_pts_diff.max, tfmt_diff),
             fmtx_timestamp(stats[ii].pcr_pts_diff.max_at, tfmt_abs),
             stats[ii].pcr_pts_diff.max_posn);
      printf("    i.e., a span of %s\n",
             fmtx_timestamp(stats[ii].pcr_pts_diff.max - stats[ii].pcr_pts_diff.min, tfmt_diff));
      printf("    Mean difference (of %u) is %s\n",
             stats[ii].pcr_pts_diff.num,
             fmtx_timestamp((int64_t)(stats[ii].pcr_pts_diff.sum/(double)stats[ii].pcr_pts_diff.num), tfmt_diff));
    }

    if (stats[ii].pcr_dts_diff.num > 0 && stats[ii].pts_ne_dts)
    {
      printf("  PCR/DTS:\n    Minimum difference was %6s at DTS %8s, TS packet at " OFFSET_T_FORMAT_8 "\n",
             fmtx_timestamp(stats[ii].pcr_dts_diff.min, tfmt_diff),
             fmtx_timestamp(stats[ii].pcr_dts_diff.min_at, tfmt_abs),
             stats[ii].pcr_dts_diff.min_posn);
      printf("    Maximum difference was %6s at DTS %8s, TS packet at " OFFSET_T_FORMAT_8 "\n",
             fmtx_timestamp(stats[ii].pcr_dts_diff.max, tfmt_diff),
             fmtx_timestamp(stats[ii].pcr_dts_diff.max_at, tfmt_abs),
             stats[ii].pcr_dts_diff.max_posn);
      printf("    i.e., a span of %s\n",
             fmtx_timestamp(stats[ii].pcr_dts_diff.max - stats[ii].pcr_dts_diff.min, tfmt_diff));
      printf("    Mean difference (of %u) is %s\n",
             stats[ii].pcr_dts_diff.num,
             fmtx_timestamp((int64_t)(stats[ii].pcr_dts_diff.sum/(double)stats[ii].pcr_dts_diff.num), tfmt_diff));
    }

    printf("  First PCR %8s, last %8s\n",
             fmtx_timestamp(first_pcr, tfmt_abs | FMTX_TS_N_27MHz),
             fmtx_timestamp(predict.prev_pcr, tfmt_abs | FMTX_TS_N_27MHz));
    if (stats[ii].pcr_pts_diff.num > 0)
      printf("  First PTS %8s, last %8s\n",
             fmtx_timestamp(stats[ii].first_pts, tfmt_abs),
             fmtx_timestamp(stats[ii].pts, tfmt_abs));
    if (stats[ii].pcr_dts_diff.num > 0)
      printf("  First DTS %8s, last %8s\n",
             fmtx_timestamp(stats[ii].first_dts, tfmt_abs),
             fmtx_timestamp(stats[ii].dts, tfmt_abs));

    if (stats[ii].err_cc_error != 0)
      printf("  ### CC error * %d\n", stats[ii].err_cc_error);
    if (stats[ii].err_cc_dup_error != 0)
      printf("  ### CC duplicate error * %d\n", stats[ii].err_cc_dup_error);
    if (stats[ii].err_pts_lt_dts != 0)
      printf("  ### PTS < DTS * %d\n", stats[ii].err_pts_lt_dts);
    if (stats[ii].err_dts_lt_prev_dts != 0)
      printf("  ### DTS < prev DTS * %d\n", stats[ii].err_dts_lt_prev_dts);
    if (stats[ii].err_dts_lt_pcr != 0)
      printf("  ### DTS < PCR * %d\n", stats[ii].err_dts_lt_pcr);
  }
  return 0;
}
Exemplo n.º 4
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;
}