⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mpeg2ps.c

📁 完整的RTP RTSP代码库
💻 C
📖 第 1 页 / 共 4 页
字号:
		      sptr->m_stream_id,		      sptr->m_substream_id);      return;    }  } else {    mpeg2ps_message(LOG_ERR, "unknown stream id %x", sptr->m_stream_id);    return;  }      mpeg2ps_message(LOG_INFO, "audio stream %x - freq %u chans %u bitrate %u spf %u", 		sptr->m_stream_id, sptr->freq, sptr->channels, sptr->bitrate, 		sptr->samples_per_frame);}/* * clear_stream_buffer - called when we seek to clear out any data in  * the buffers */static void clear_stream_buffer (mpeg2ps_stream_t *sptr){  sptr->pes_buffer_on = sptr->pes_buffer_size = 0;  sptr->frame_len = 0;  sptr->have_frame_loaded = false;  sptr->next_pes_ts.have_dts = sptr->next_pes_ts.have_pts = false;  sptr->frame_ts.have_dts = sptr->frame_ts.have_pts = false;  sptr->lpcm_read_offset = true;}/* * convert_to_msec - convert ts (at 90000) to msec, based on base_ts and * frames_since_last_ts. */static uint64_t convert_ts (mpeg2ps_stream_t *sptr,			    mpeg2ps_ts_type_t ts_type,			    uint64_t ts,			    uint64_t base_ts,			    uint32_t frames_since_ts){  uint64_t ret, calc;  ret = ts - base_ts;  if (sptr->is_video) {    // video    ret += frames_since_ts * sptr->ticks_per_frame;  } else {    // audio    if (frames_since_ts != 0 && sptr->freq != 0) {      calc = (frames_since_ts * 90000 * sptr->samples_per_frame) / sptr->freq;      ret += calc;    }  }  if (ts_type == TS_MSEC)    ret /= TO_U64(90); // * 1000 / 90000#if 0  printf("stream %x - ts "U64" base "U64" frames since %d ret "U64"\n",	 sptr->m_stream_id, ts, base_ts, frames_since_ts, ret);#endif  return ret;}/* * find_stream_from_id - given the stream, get the sptr. * only used in inital set up, really.  APIs use index into  * video_streams and audio_streams arrays. */static mpeg2ps_stream_t *find_stream_from_id (mpeg2ps_t *ps, 					      uint8_t stream_id, 					      uint8_t substream){  uint8_t ix;  if (stream_id >= 0xe0) {    for (ix = 0; ix < ps->video_cnt; ix++) {      if (ps->video_streams[ix]->m_stream_id == stream_id) {	return ps->video_streams[ix];      }    }  } else {    for (ix = 0; ix < ps->audio_cnt; ix++) {      if (ps->audio_streams[ix]->m_stream_id == stream_id &&	  (stream_id != 0xbd ||	   substream == ps->audio_streams[ix]->m_substream_id)) {	return ps->audio_streams[ix];      }    }  }  return NULL;}/* * add_stream - add a new stream */static bool add_stream (mpeg2ps_t *ps,			uint8_t stream_id,			uint8_t substream,			off_t first_loc,			mpeg2ps_ts_t *ts){  mpeg2ps_stream_t *sptr;    sptr = find_stream_from_id(ps, stream_id, substream);  if (sptr != NULL) return FALSE;  // need to add  sptr = mpeg2ps_stream_create(stream_id, substream);  sptr->first_pes_loc = first_loc;  if (ts == NULL ||      (ts->have_dts == false && ts->have_pts == false)) {    sptr->first_pes_has_dts = false;    mpeg2ps_message(LOG_CRIT, "stream %x doesn't have start pts",		    sptr->m_stream_id);  } else {    sptr->start_dts = ts->have_dts ? ts->dts : ts->pts;    sptr->first_pes_has_dts = true;  }  if (sptr->is_video) {    // can't be more than 16 - e0 to ef...    ps->video_streams[ps->video_cnt] = sptr;    mpeg2ps_message(LOG_DEBUG, 		    "added video stream %x "X64" "U64, 		    stream_id, first_loc, sptr->start_dts);    ps->video_cnt++;  } else {    if (ps->audio_cnt >= 32) {      mpeg2ps_stream_destroy(sptr);      return FALSE;    }    mpeg2ps_message(LOG_DEBUG, 		    "added audio stream %x %x "X64" "U64, 		    stream_id, substream, first_loc, sptr->start_dts);    ps->audio_streams[ps->audio_cnt] = sptr;    ps->audio_cnt++;  }  return TRUE;}static void check_fd_for_stream (mpeg2ps_t *ps, 			  mpeg2ps_stream_t *sptr){  if (sptr->m_fd != FDNULL) return;  sptr->m_fd = file_open(ps->filename);}/* * advance_frame - when we're reading frames, this indicates that we're * done.  We will call this when we read a frame, but not when we * seek.  It allows us to leave the last frame we're seeking in the * buffer */static void advance_frame (mpeg2ps_stream_t *sptr){  sptr->pes_buffer_on += sptr->frame_len;  sptr->have_frame_loaded = false;  if (sptr->frame_ts.have_dts || sptr->frame_ts.have_pts) {    if (sptr->frame_ts.have_dts)       sptr->last_ts = sptr->frame_ts.dts;    else      sptr->last_ts = sptr->frame_ts.pts;    sptr->frames_since_last_ts = 0;  } else {    sptr->frames_since_last_ts++;  }}/* * get_info_for_all_streams - loop through found streams - read an * figure out the info */static void get_info_for_all_streams (mpeg2ps_t *ps){  uint8_t stream_ix, max_ix, av;  mpeg2ps_stream_t *sptr;  uint8_t *buffer;  uint32_t buflen;  // av will be 0 for video streams, 1 for audio streams  // av is just so I don't have to dup a lot of code that does the  // same thing.  for (av = 0; av < 2; av++) {    if (av == 0) max_ix = ps->video_cnt;    else max_ix = ps->audio_cnt;    for (stream_ix = 0; stream_ix < max_ix; stream_ix++) {      if (av == 0) sptr = ps->video_streams[stream_ix];      else sptr = ps->audio_streams[stream_ix];      if (file_seek_to(ps->fd, sptr->first_pes_loc) != sptr->first_pes_loc) {	mpeg2ps_message(LOG_ERR, "stream %x error - can't seek to "X64" %s", 			sptr->m_stream_id, sptr->first_pes_loc, 			strerror(errno));      }      // we don't open a seperate file descriptor yet (only when they      // start reading or seeking).  Use the one from the ps.      sptr->m_fd = ps->fd; // for now      clear_stream_buffer(sptr);      if (mpeg2ps_stream_read_frame(sptr,				    &buffer, 				    &buflen,				    false) == FALSE) {	mpeg2ps_message(LOG_CRIT, "Couldn't read frame of stream %x",			sptr->m_stream_id);	sptr->m_stream_id = 0;	sptr->m_fd = FDNULL;	continue;      }      get_info_from_frame(sptr, buffer, buflen);      //printf("got stream av %d %d\n", av, sptr->first_pes_has_dts);      // here - if (sptr->first_pes_has_dts == false) should be processed      if (sptr->first_pes_has_dts == false) {	uint32_t frames_from_beg = 0;	bool have_frame;	do {	  advance_frame(sptr);	  have_frame = 	    mpeg2ps_stream_read_frame(sptr, &buffer, &buflen, false);	  frames_from_beg++;	} while (have_frame && 		 sptr->frame_ts.have_dts == false && 		 sptr->frame_ts.have_pts == false && 		 frames_from_beg < 1000);	if (have_frame == false ||	    (sptr->frame_ts.have_dts == false &&	     sptr->frame_ts.have_pts == false)) {	  mpeg2ps_message(LOG_ERR, 			  "can't find initial pts of stream %x - have_frame %d cnt %u",			  sptr->m_stream_id, have_frame, frames_from_beg);	} else {	  sptr->start_dts = sptr->frame_ts.have_dts ? sptr->frame_ts.dts : 	    sptr->frame_ts.pts;	  if (sptr->is_video) {	    sptr->start_dts -= frames_from_beg * sptr->ticks_per_frame;	  } else {	    uint64_t conv;	    conv = sptr->samples_per_frame * 90000;	    conv /= (uint64_t)sptr->freq;	    sptr->start_dts -= conv;	  }	  mpeg2ps_message(LOG_DEBUG, "stream %x - calc start pts of "U64,			  sptr->m_stream_id, sptr->start_dts);	}      }      clear_stream_buffer(sptr);      sptr->m_fd = FDNULL;    }  }}/* * mpeg2ps_scan_file - read file, grabbing all the information that * we can out of it (what streams exist, timing, etc). */static void mpeg2ps_scan_file (mpeg2ps_t *ps){  uint8_t stream_id, stream_ix, substream, av_ix, max_cnt;  uint16_t pes_len, pes_left;  mpeg2ps_ts_t ts;  off_t loc, first_video_loc = 0, first_audio_loc = 0;  off_t check, orig_check;  mpeg2ps_stream_t *sptr;  bool valid_stream;  uint8_t *buffer;  uint32_t buflen;  bool have_ts;  ps->end_loc = file_size(ps->fd);  orig_check = check = MAX(ps->end_loc / 50, 200 * 1024);  /*   * This part reads and finds the streams.  We check up until we   * find audio and video plus a little, with a max of either 200K or   * the file size / 50   */  loc = 0;  while (read_to_next_pes_header(ps->fd, &stream_id, &pes_len) && 	 loc < check) {    pes_left = pes_len;    if (stream_id >= 0xbd && stream_id < 0xf0) {      loc = file_location(ps->fd) - 6;      if (read_pes_header_data(ps->fd, 			       pes_len, 			       &pes_left, 			       &have_ts, 			       &ts) == FALSE) {	return;      }      valid_stream = FALSE;      substream = 0;      if (stream_id == 0xbd) {	if (file_read_bytes(ps->fd, &substream, 1) == FALSE) {	  return;	}	pes_left--; // remove byte we just read	if ((substream >= 0x80 && substream < 0x90) ||	    (substream >= 0xa0 && substream < 0xb0)){	  valid_stream = TRUE;	}      } else if (stream_id >= 0xc0 &&		 stream_id <= 0xef) {	// audio and video	valid_stream = TRUE;      }#if 0      mpeg2ps_message(LOG_DEBUG, 		      "stream %x %x loc "X64" pts %d dts %d\n",		      stream_id, substream, loc, ts.have_pts, ts.have_dts);#endif      if (valid_stream) {	if (add_stream(ps, stream_id, substream, loc, &ts)) {	  // added	  if (stream_id >= 0xe0) {	    if (ps->video_cnt == 1) {	      first_video_loc = loc;	    }	  } else if (ps->audio_cnt == 1) {	    first_audio_loc = loc;	  }	  if (ps->audio_cnt > 0 && ps->video_cnt > 0) {	    off_t diff;	    if (first_audio_loc > first_video_loc) 	      diff = first_audio_loc - first_video_loc;	    else 	      diff = first_video_loc - first_audio_loc;	    diff *= 2;	    diff += first_video_loc;	    if (diff < check) {	      check = diff;	    }	  }	}      }    }    file_skip_bytes(ps->fd, pes_left);  }  if (ps->video_cnt == 0 && ps->audio_cnt == 0) {    return;  }  /*   * Now, we go to close to the end, and try to find the last    * dts that we can   */  //  printf("to end "X64"\n", end - orig_check);  file_seek_to(ps->fd, ps->end_loc - orig_check);  while (read_to_next_pes_header(ps->fd, &stream_id, &pes_len)) {    loc = file_location(ps->fd) - 6;    if (stream_id == 0xbd || (stream_id >= 0xc0 && stream_id < 0xf0)) {      if (read_pes_header_data(ps->fd, 			       pes_len, 			       &pes_left, 			       &have_ts, 			       &ts) == FALSE) {	return;      }      if (stream_id == 0xbd) {	if (file_read_bytes(ps->fd, &substream, 1) == FALSE) {	  return;	}	pes_left--; // remove byte we just read	if (!((substream >= 0x80 && substream < 0x90) ||	      (substream >= 0xa0 && substream < 0xb0))) {	  file_skip_bytes(ps->fd, pes_left);	  continue;	}      } else {	substream = 0;      }      sptr = find_stream_from_id(ps, stream_id, substream);      if (sptr == NULL) {	mpeg2ps_message(LOG_INFO, 			"adding stream from end search %x %x",			stream_id, substream);	add_stream(ps, stream_id, substream, 0, NULL);	sptr = find_stream_from_id(ps, stream_id, substream);      }      if (sptr != NULL && have_ts) {	sptr->end_dts = ts.have_dts ? ts.dts : ts.pts;	sptr->end_dts_loc = loc;      }#if 0      printf("loc "X64" stream %x %x", loc, stream_id, substream);      if (ts.have_pts) printf(" pts "U64, ts.pts);      if (ts.have_dts) printf(" dts "U64, ts.dts);      printf("\n");#endif      file_skip_bytes(ps->fd, pes_left);    }  }  /*   * Now, get the info for all streams, so we can use it again   * we could do this before the above, I suppose   */  get_info_for_all_streams(ps);  ps->first_dts = MAX_UINT64;  /*   * we need to find the earliest start pts - we use that to calc   * the rest of the timing, so we're 0 based.   */  for (av_ix = 0; av_ix < 2; av_ix++) {    if (av_ix == 0) max_cnt = ps->video_cnt;    else max_cnt = ps->audio_cnt;    for (stream_ix = 0; stream_ix < max_cnt; stream_ix++) {      sptr = av_ix == 0 ? ps->video_streams[stream_ix] :	ps->audio_streams[stream_ix];      if (sptr != NULL && sptr->start_dts < ps->first_dts) {	ps->first_dts = sptr->start_dts;      }    }  }  mpeg2ps_message(LOG_INFO, "start ps is "U64, ps->first_dts);  /*   * Now, for each thread, we'll start at the last pts location, and   * read the number of frames.  This will give us a max time   */  for (av_ix = 0; av_ix < 2; av_ix++) {    if (av_ix == 0) max_cnt = ps->video_cnt;    else max_cnt = ps->audio_cnt;    for (stream_ix = 0; stream_ix < max_cnt; stream_ix++) {      uint32_t frame_cnt_since_last;	  sptr = av_ix == 0 ? ps->video_streams[stream_ix] :	ps->audio_streams[stream_ix];            // pick up here - find the final time...      if (sptr->end_dts_loc != 0) {	//printf("end loc "U64"\n", sptr->end_dts_loc);	file_seek_to(ps->fd, sptr->end_dts_loc);	sptr->m_fd = ps->fd;	frame_cnt_since_last = 0;	clear_stream_buffer(sptr);	while (mpeg2ps_stream_read_frame(sptr,					 &buffer, 					 &buflen,					 true)) {	  //printf("loc "U64"\n", file_location(sptr->m_fd)); 	  frame_cnt_since_last++;	}	sptr->m_fd = FDNULL;	clear_stream_buffer(sptr);	mpeg2ps_message(LOG_DEBUG, "stream %x last ts "U64" since last %u\n", 			sptr->m_stream_id, 			sptr->end_dts,			frame_cnt_since_last);	ps->max_time = MAX(ps->max_time, 			   convert_ts(sptr, 				      TS_MSEC,				      sptr->end_dts,				      ps->first_dts, 				      frame_cnt_since_last));      } else {	mpeg2ps_message(LOG_DEBUG, "stream %x no end dts", sptr->m_stream_id);      }    }  }  ps->max_dts = (ps->max_time * 90) + ps->first_dts;  mpeg2ps_message(LOG_DEBUG, "max time is "U64, ps->max_time);  file_seek_to(ps->fd, 0);}/************************************************************************* * API routines *************************************************************************/uint64_t mpeg2ps_get_max_time_msec (mpeg2ps_t *ps) {  return ps->max_time;}uint32_t mpeg2ps_get_video_stream_count (mpeg2ps_t *ps){  return ps->video_cnt;}// routine to check stream number passed.static bool invalid_video_streamno (mpeg2ps_t *ps, uint streamno){  if (streamno >= NUM_ELEMENTS_IN_ARRAY(ps->video_streams)) return true;  if (ps->video_streams[streamno] == NULL) return true;  return false;}char *mpeg2ps_get_video_stream_name (mpeg2ps_t *ps, uint streamno){  if (invalid_video_streamno(ps, streamno)) {    return NULL;  }  if (ps->video_streams[streamno]->have_h264) {    return h264_get_profile_level_string(ps->video_streams[streamno]->video_profile,					 ps->video_streams[streamno]->video_level);  }  if (ps->video_streams[streamno]->have_mpeg2) {    return strdup(mpeg2_type(ps->video_streams[streamno]->video_profile));  }  return strdup("Mpeg-1");}mpeg2ps_video_type_t mpeg2ps_get_video_stream_type (mpeg2ps_t *ps, 						    uint streamno){  if (invalid_video_streamno(ps, streamno)) {    return MPEG_AUDIO_UNKNOWN;  }  if (ps->video_streams[streamno]->have_h264) return MPEG_VIDEO_H264;  return ps->video_streams[streamno]->have_mpeg2 ? MPEG_VIDEO_MPEG2 :     MPEG_VIDEO_MPEG1;}uint32_t mpeg2ps_get_video_stream_width (mpeg2ps_t *ps, uint streamno){  if (invalid_video_streamno(ps, streamno)) {    return 0;  }  return ps->video_streams[streamno]->w;}uint32_t mpeg2ps_get_video_stream_height (mpeg2ps_t *ps, uint streamno){  if (invalid_video_streamno(ps, streamno)) {    return 0;  }  return ps->video_streams[streamno]->h;}double mpeg2ps_get_video_stream_bitrate (mpeg2ps_t *ps, uint streamno){  if (invalid_video_streamno(ps, streamno)) {    return 0;  }  return ps->video_streams[streamno]->bit_rate;}double mpeg2ps_get_video_stream_framerate (mpeg2ps_t *ps, uint streamno){  if (invalid_video_streamno(ps, streamno)) {    return 0;  }  return ps->video_streams[streamno]->frame_rate;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -