/*
 * get_frame_for_pid - process further into the file, until we get
 * a frame.  This has the effect of perhaps loading the frame for the
 * other streams.
 */
void CMpeg2tFile::get_frame_for_pid (mpeg2t_es_t *es_pid)
{
  mpeg2t_pid_t *pidptr;
  uint32_t buflen_used;

  lock_file_mutex();
  do {
    while (m_buffer_on + 188 < m_buffer_size) {
      pidptr = mpeg2t_process_buffer(m_mpeg2t, 
				     &m_buffer[m_buffer_on],
				     m_buffer_size - m_buffer_on,
				     &buflen_used);
      m_buffer_on += buflen_used;
      if (es_pid->list != NULL) {
	unlock_file_mutex();
	return;
      }
    }
    if (!feof(m_ifile)) {
      if (m_buffer_on < m_buffer_size) {
	memmove(m_buffer, m_buffer + m_buffer_on, m_buffer_size - m_buffer_on);
	m_buffer_on = m_buffer_size - m_buffer_on;
      } else {
	m_buffer_on = 0;
      }
      m_buffer_size = fread(m_buffer + m_buffer_on, 1, 
			    m_buffer_size_max - m_buffer_on, m_ifile);
      m_buffer_size += m_buffer_on;
      m_buffer_on = 0;
      if (m_buffer_size < 188) m_buffer_size = 0;
    }
  } while (!feof(m_ifile));

  unlock_file_mutex();
}
int main (int argc, char **argv)
{
  FILE *ifile;
  uint8_t *buffer, *ptr;
  uint32_t buflen, readfromfile;
  uint32_t offset;
  int done_with_buf;
  mpeg2t_t *mpeg2t;
  mpeg2t_es_t *es_pid;
  mpeg2t_pid_t *pidptr;
  bool verbose = false;
  fpos_t pos;
  const char *ProgName = argv[0];
  const char *usage = "";
  uint16_t pid = 0;
  const char *filename;

  //  int lastcc, ccset;
  while (true) {
    int c = -1;
    int option_index = 0;
    static struct option long_options[] = {
      { "help", 0, 0, '?' },
      { "version", 0, 0, 'v'},
      { "verbose", 0, 0, 'V'},
      { "pid", 1, 0, 'p' },
      { NULL, 0, 0, 0 }
    };

    c = getopt_long_only(argc, argv, "?vVp:",
			 long_options, &option_index);

    if (c == -1)
      break;
    
    switch (c) {
    case '?':
      printf("%s", usage);
      exit(1);
    case 'V':
      verbose = true;
      break;
    case 'v':
      printf("%s - %s version %s", 
	      ProgName, MPEG4IP_PACKAGE, MPEG4IP_VERSION);
      exit(1);
    case 'p': {
      int readval;
      if (sscanf(optarg, "%i", &readval) != 1) {
	fprintf(stderr, "can't read pid value %s\n", optarg);
	exit(1);
      }
      if (readval > 0x1fff) {
	fprintf(stderr, "illegal pid value %s\n", optarg);
      }
      pid = readval;
    }
    }
  }

  if (pid == 0) {
    fprintf(stderr, "must specify pid to extract\n");
    exit(-1);
  }
   
  filename = argv[optind];

  buffer = (uint8_t *)malloc(BUFFER_SIZE);

  if (verbose)
    mpeg2t_set_loglevel(LOG_DEBUG);
  else
    mpeg2t_set_loglevel(LOG_ERR);
  mpeg2t = create_mpeg2_transport();
  mpeg2t->save_frames_at_start = 1;
  ifile = fopen(filename, FOPEN_READ_BINARY);
  if (ifile == NULL) {
    fprintf(stderr, "Couldn't open file %s\n", filename);
    exit(1);
  }

  buflen = 0;
  readfromfile = 0;
  char outfilename[MAXPATHLEN], spid[20];
  strip_filename(filename, outfilename);
  sprintf(spid, ".%u", pid);
  strcat(outfilename, spid);
    FILE *ofile;
    //    bool has_pat = false;
    ofile = fopen(outfilename, FOPEN_WRITE_BINARY);

  //lastcc = 0;
  while (!feof(ifile)) {
    if (buflen > 0) {
      memmove(buffer, buffer + readfromfile - buflen, buflen);
    }
    fgetpos(ifile, &pos);
    uint64_t position;
    FPOS_TO_VAR(pos, uint64_t, position);
    fprintf(stdout, "file pos %llu\n", position);
    readfromfile = buflen + fread(buffer + buflen, 1, BUFFER_SIZE - buflen, ifile);
    buflen = readfromfile;
    ptr = buffer;
    done_with_buf = 0;


    while (done_with_buf == 0) {
      pidptr = mpeg2t_process_buffer(mpeg2t, ptr, buflen, &offset);
      ptr += offset;
      buflen -= offset;
      if (buflen < 188) {
	done_with_buf = 1;
      }
      if (pidptr != NULL && pidptr->pak_type == MPEG2T_ES_PAK) {
	mpeg2t_frame_t *p;
	es_pid = (mpeg2t_es_t *)pidptr;

	while ((p = mpeg2t_get_es_list_head(es_pid)) != NULL) {
	  if (pidptr->pid == pid) {
	    printf("Pid %x %d frame len %5d psts %d "U64" dts %d "U64"\n", 
		   pidptr->pid,
		   es_pid->stream_type,
		   p->frame_len,
		   p->have_ps_ts, p->ps_ts,
		   p->have_dts, p->dts);
	    
	    fwrite(p->frame, 1, p->frame_len, ofile);
	  }
	  mpeg2t_free_frame(p);
	}
      }
    }
  }
  free(buffer);
  fclose(ifile);
  fclose(ofile);
  return 0;
}
/*
 * Create - will determine pids and psts ranges in file.  Will also
 * loop through the file and determine CFilePosRec points at percentages
 */
int CMpeg2tFile::create (CPlayerSession *psptr)
{
  m_mpeg2t = create_mpeg2_transport();
  if (m_mpeg2t == NULL) {
    psptr->set_message("Couldn't create mpeg2 transport");
    fclose(m_ifile);
    return -1;
  }
  // nice, large buffers to process
  m_buffer_size_max = 188 * 2000;
  m_buffer = (uint8_t *)malloc(m_buffer_size_max);

  if (m_buffer == NULL) {
    psptr->set_message("Malloc error");
    return -1;
  }
  m_buffer[0] = MPEG2T_SYNC_BYTE;
  m_buffer_size = fread(&m_buffer[1], 1, m_buffer_size_max - 1, m_ifile) + 1;

  bool done = false;
  mpeg2t_pid_t *pidptr;
  uint32_t buflen_used;
  bool have_psts = false;
  uint64_t earliest_psts = 0;
  mpeg2t_es_t *es_pid;

  int olddebuglevel;
  olddebuglevel = config.get_config_value(CONFIG_MPEG2T_DEBUG);
  if (olddebuglevel != LOG_DEBUG)
    mpeg2t_set_loglevel(LOG_CRIT);
  m_mpeg2t->save_frames_at_start = 1;
  /*
   * We need to determine which PIDs are present, and try to establish
   * a starting psts.  We also want to establish what type of video and
   * audio are in the mix.  Note: if we try to run this on a file that
   * we don't understand the video, this could take a while, because the
   * info never gets loaded.
   */
  do {
    m_buffer_on = 0;
    while (m_buffer_on + 188 < m_buffer_size && done == false) {
      
      pidptr = mpeg2t_process_buffer(m_mpeg2t, 
				     &m_buffer[m_buffer_on],
				     m_buffer_size - m_buffer_on,
				     &buflen_used);
      m_buffer_on += buflen_used;
      if (pidptr != NULL && pidptr->pak_type == MPEG2T_ES_PAK) {
	es_pid = (mpeg2t_es_t *)pidptr;
	mpeg2t_frame_t *fptr;

	// determine earliest PS_TS
	while ((fptr = mpeg2t_get_es_list_head(es_pid)) != NULL) {
	  if (fptr->have_ps_ts != 0 || fptr->have_dts != 0) {
	    uint64_t ps_ts = 0;
	    bool store_psts = true;
	    if (fptr->have_dts != 0) {
	      ps_ts = fptr->dts;
	    } else {
	      if (es_pid->is_video == 1) { // mpeg2
		// video - make sure we get the first I frame, then we can
		// get the real timestamp
		if (fptr->frame_type != 1) {
		  store_psts = false;
		} else {
		  ps_ts = fptr->ps_ts;
		  uint16_t temp_ref = MP4AV_Mpeg3PictHdrTempRef(fptr->frame + fptr->pict_header_offset);
		  ps_ts -= ((temp_ref + 1) * es_pid->tick_per_frame);
		}
	      } else {
		ps_ts = fptr->ps_ts;
	      }
	    }
	    if (store_psts) {
	      // when we have the first psts for a ES_PID, turn off
	      // parsing frames for that PID.
	      mpeg2t_set_frame_status(es_pid, MPEG2T_PID_NOTHING);
	      if (have_psts) {
		earliest_psts = MIN(earliest_psts, ps_ts);
	      } else {
		earliest_psts = ps_ts;
		have_psts = true;
	      }
	    }
	  }
	  mpeg2t_free_frame(fptr);
	}

	// Each time, search through and see if there are any ES_PIDs 
	// that have not returned a psts.  We're done when the info is
	// loaded for all the es pids.
	pidptr = m_mpeg2t->pas.pid.next_pid;
	bool finished = true;
	while (pidptr != NULL && finished) {
	  if (pidptr->pak_type == MPEG2T_ES_PAK) {
	    es_pid = (mpeg2t_es_t *)pidptr;
	    if (es_pid->info_loaded == 0) {
	      finished = false;
	    }
	  }
	  pidptr = pidptr->next_pid;
	}
	done = finished || have_psts;
      }
    }
    if (done == false) {
      m_buffer_size = fread(m_buffer, 1, m_buffer_size_max, m_ifile);
    }
  } while (m_buffer_size >=188 && done == false);

  if (done == false) {
    psptr->set_message("Could not find information in TS");
    mpeg2t_set_loglevel(olddebuglevel);
    return -1;
  }

#ifdef DEBUG_MPEG2F_SEARCH
  mpeg2f_message(LOG_DEBUG, "initial psts is "U64, earliest_psts);
#endif
  m_start_psts = earliest_psts;

  // Now, we'll try to build a rough index for the file
  // enable psts reading for the pid
  for (pidptr = m_mpeg2t->pas.pid.next_pid; pidptr != NULL; pidptr = pidptr->next_pid) {
    if (pidptr->pak_type == MPEG2T_ES_PAK) {
      es_pid = (mpeg2t_es_t *)pidptr;
      mpeg2t_set_frame_status(es_pid, MPEG2T_PID_REPORT_PSTS);
    }
  }
  m_file_record.record_point(0, earliest_psts, 0);
  fpos_t fpos;
  uint64_t end;
  uint64_t perc, cur;

  // find out the length of the file.
  struct stat filestat;
  if (fstat(fileno(m_ifile), &filestat) != 0) {
    return -1;
  }
  end = filestat.st_size;
  perc = end;
  // perc is what size of the file to skip through to get a rough
  // timetable.  We want to do 10% chunks, or 100Mb chunks, whichever is
  // less.
  while (perc > TO_U64(100000000)) {
    perc /= 2;
  }
  if (perc > (end / TO_U64(10))) {
    perc = end / TO_U64(10);
  }
  if (perc < (end / TO_U64(50))) {
    perc = end / TO_U64(50);
  }
#ifdef DEBUG_MPEG2F_SEARCH
  mpeg2f_message(LOG_DEBUG, "perc is "U64" "U64, perc, (perc * TO_U64(100)) / end );
#endif

  cur = perc;

  bool is_seekable = true;
  uint64_t last_psts, ts;
  last_psts = earliest_psts;

  // Now - skip to the next perc chunk, and try to find the next psts
  // we'll record this info.
  do {
#ifdef DEBUG_MPEG2F_SEARCH
    mpeg2f_message(LOG_DEBUG, "current "U64" end "U64, cur, end);
#endif
    VAR_TO_FPOS(fpos, cur);
    fsetpos(m_ifile, &fpos);
    done = false;
    uint64_t count = 0;
    m_buffer_on = 0;
    m_buffer_size = 0;
    do {
      if (m_buffer_on + 188 > m_buffer_size) {
	if (m_buffer_on < m_buffer_size) {
	  memmove(m_buffer, m_buffer + m_buffer_on, 
		  m_buffer_size - m_buffer_on);
	  m_buffer_on = m_buffer_size - m_buffer_on;
	} else {
	  m_buffer_on = 0;
	}
	m_buffer_size = fread(m_buffer + m_buffer_on, 
			      1, 
			      (188 * 10) - m_buffer_on, 
			      m_ifile);

	count += m_buffer_size - m_buffer_on;
	m_buffer_size += m_buffer_on;
	m_buffer_on = 0;
	if (m_buffer_size < 188) {
	  m_buffer_size = 0;
	  done = true;
	}
      }

      pidptr = mpeg2t_process_buffer(m_mpeg2t,
				     m_buffer + m_buffer_on, 
				     m_buffer_size - m_buffer_on, 
				     &buflen_used);
      m_buffer_on += buflen_used;
      if (pidptr != NULL && pidptr->pak_type == MPEG2T_ES_PAK) {
	es_pid = (mpeg2t_es_t *)pidptr;
	// If we have a psts, record it.
	// If it is less than the previous one, we've got a discontinuity, so
	// we can't seek.
	if (es_pid->have_ps_ts || es_pid->have_dts) {
	  ts = es_pid->have_ps_ts ? es_pid->ps_ts : es_pid->dts;
	  if (ts < last_psts) {
	    player_error_message("pid %x psts "U64" is less than prev record point "U64, 
				 es_pid->pid.pid, ts, last_psts);
	    cur = end;
	    is_seekable = false;
	  } else {
#ifdef DEBUG_MPEG2F_SEARCH
	    mpeg2f_message(LOG_DEBUG, "pid %x psts "U64" %d", 
			       pidptr->pid, ts, 
			       es_pid->is_video);
#endif
	    m_file_record.record_point(cur, ts, 0);
	  }
	  done = true;
	}
      }

    } while (done == false && count < perc / 2);
    cur += perc;

  } while (cur < end - (m_buffer_size_max * 2));

  //mpeg2f_message(LOG_DEBUG, "starting end search");
  // Now, we'll go to close to the end of the file, and look for a 
  // final PSTS.  This gives us a rough estimate of the elapsed time
  long seek_offset;
  seek_offset = 0;
  seek_offset -= (m_buffer_size_max) * 2;
  fseek(m_ifile, seek_offset, SEEK_END);
  m_buffer_on = m_buffer_size = 0;
  uint64_t max_psts;
  max_psts = m_start_psts;
  do {
    while (m_buffer_on + 188 <= m_buffer_size) {
      
      pidptr = mpeg2t_process_buffer(m_mpeg2t, 
				     &m_buffer[m_buffer_on],
				     m_buffer_size - m_buffer_on,
				     &buflen_used);
      m_buffer_on += buflen_used;
      if (pidptr != NULL && pidptr->pak_type == MPEG2T_ES_PAK) {
	es_pid = (mpeg2t_es_t *)pidptr;
	if (es_pid->have_ps_ts) {
	  es_pid->have_ps_ts = 0;
	  max_psts = MAX(es_pid->ps_ts, max_psts);
	} else if (es_pid->have_dts) {
	  es_pid->have_dts = 0;
	  max_psts = MAX(es_pid->dts, max_psts);
	}
      }
    }
    if (m_buffer_size > m_buffer_on) {
      memmove(m_buffer, m_buffer + m_buffer_on, m_buffer_size - m_buffer_on);
    }
    m_buffer_on = m_buffer_size - m_buffer_on;
    m_buffer_size = fread(m_buffer + m_buffer_on, 1, 
			  m_buffer_size_max - m_buffer_on, m_ifile);
    m_buffer_size += m_buffer_on;
    m_buffer_on = 0;
    if (m_buffer_size < 188) m_buffer_size = 0;
  } while (m_buffer_size > 188) ;
  m_last_psts = max_psts;
  // Calculate the rough max time; hopefully it will be greater than the
  // initial...
  m_max_time = max_psts;
  m_max_time -= m_start_psts;
  m_max_time /= 90000.0;
#ifdef DEBUG_MPEG2F_SEARCH
  player_debug_message("last psts is "U64" "U64" %g", max_psts,
		       (max_psts - m_start_psts) / TO_U64(90000),
		       m_max_time);
#endif
  mpeg2t_set_loglevel(olddebuglevel);

  if (is_seekable) {
    psptr->session_set_seekable(1);
  }
  m_ts_seeked_in_msec = UINT64_MAX;
  rewind(m_ifile);

  return 0;
}
Exemple #4
0
int main (int argc, char **argv)
{
  FILE *ifile;
  uint8_t *buffer, *ptr;
  uint32_t buflen, readfromfile;
  uint32_t offset;
  int done_with_buf;
  mpeg2t_t *mpeg2t;
  mpeg2t_es_t *es_pid;
  mpeg2t_pid_t *pidptr;
  bool verbose = false;
  fpos_t pos;
  const char *ProgName = argv[0];
  const char *usage = "";
  uint16_t pid = 0;
  bool diff = false;

  //  int lastcc, ccset;
  while (true) {
    int c = -1;
    int option_index = 0;
    static struct option long_options[] = {
      { "help", 0, 0, '?' },
      { "version", 0, 0, 'v'},
      { "verbose", 0, 0, 'V'},
      { "pid", 1, 0, 'p' },
      { "diff", 0, 0, 'd' },
      { NULL, 0, 0, 0 }
    };

    c = getopt_long_only(argc, argv, "?vVp:d",
			 long_options, &option_index);

    if (c == -1)
      break;
    
    switch (c) {
    case '?':
      printf("%s", usage);
      exit(1);
    case 'V':
      verbose = true;
      break;
    case 'v':
      printf("%s - %s version %s", 
	      ProgName, MPEG4IP_PACKAGE, MPEG4IP_VERSION);
      exit(1);
    case 'd':
      diff = true;
      break;
    case 'p': {
      int readval;
      if (sscanf(optarg, "%i", &readval) != 1) {
	fprintf(stderr, "can't read pid value %s\n", optarg);
	exit(1);
      }
      if (readval > 0x1fff) {
	fprintf(stderr, "illegal pid value %s\n", optarg);
      }
      pid = readval;
    }
    }
  }

  argc -= optind;
  argv += optind;

  buffer = (uint8_t *)malloc(BUFFER_SIZE);

  if (verbose)
    mpeg2t_set_loglevel(LOG_DEBUG);
  else
    mpeg2t_set_loglevel(LOG_ERR);
  mpeg2t = create_mpeg2_transport();
  mpeg2t->save_frames_at_start = 1;
  ifile = fopen(*argv, FOPEN_READ_BINARY);
  if (ifile == NULL) {
    fprintf(stderr, "Couldn't open file %s\n", *argv);
    exit(1);
  }

  buflen = 0;
  readfromfile = 0;
  uint64_t last_pts = 0;

  //lastcc = 0;
  while (!feof(ifile)) {
    if (buflen > 0) {
      memmove(buffer, buffer + readfromfile - buflen, buflen);
    }
    fgetpos(ifile, &pos);
    if (verbose) {
      uint64_t position;
      FPOS_TO_VAR(pos, uint64_t, position);
      fprintf(stdout, "file pos %llu\n", position);
    }
    readfromfile = buflen + fread(buffer + buflen, 1, BUFFER_SIZE - buflen, ifile);
    buflen = readfromfile;
    ptr = buffer;
    done_with_buf = 0;


    while (done_with_buf == 0) {
      pidptr = mpeg2t_process_buffer(mpeg2t, ptr, buflen, &offset);
      ptr += offset;
      buflen -= offset;
      if (buflen < 188) {
	done_with_buf = 1;
      }
      if (pidptr != NULL && pidptr->pak_type == MPEG2T_ES_PAK) {
	mpeg2t_frame_t *p;
	es_pid = (mpeg2t_es_t *)pidptr;

	while ((p = mpeg2t_get_es_list_head(es_pid)) != NULL) {
	  if (pid == 0 || pidptr->pid == pid) {
	    printf("Pid %u %d frame len %5u",
		   pidptr->pid,
		   es_pid->stream_type,
		   p->frame_len);

	    uint64_t comp;
	    if (p->have_dts && p->have_ps_ts) {
	      printf(" dts "U64" pts "U64, p->dts, p->ps_ts);
	      comp = p->dts;
	    } else {
	      comp = p->ps_ts;
	      if (p->have_ps_ts) {
		printf(" pts "U64, p->ps_ts);
	      }
	      if (p->have_dts) {
		printf(" dts "U64, p->dts);
	      }
	    }
	    if (diff) {
	      if (last_pts != 0) {
		printf("\tdiff "U64, comp - last_pts);
	      } else {
		printf("\tno diff");
	      }
	      last_pts = comp;
	    }
	    printf("\n");
	  }
	  mpeg2t_free_frame(p);
	}
      }
    }
  }
  free(buffer);
  fclose(ifile);
  return 0;
}