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

📄 mpeg2ps.c

📁 完整的RTP RTSP代码库
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ *  * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. *  * The Original Code is MPEG4IP. *  * The Initial Developer of the Original Code is Cisco Systems Inc. * Portions created by Cisco Systems Inc. are * Copyright (C) Cisco Systems Inc. 2004.  All Rights Reserved. *  * Contributor(s):  *		Bill May wmay@cisco.com *//* * mpeg2ps.c - parse program stream and vob files */#include "mpeg2_ps.h"#include "mpeg2ps_private.h"#include <mp4av.h>#include <mp4av_h264.h>//#define DEBUG_LOC 1//#define DEBUG_STATE 1static const uint lpcm_freq_tab[4] = {48000, 96000, 44100, 32000};/************************************************************************* * File access routines.  Could all be inlined *************************************************************************/static FDTYPE file_open (const char *name){  return open(name, OPEN_RDONLY);}static bool file_okay (FDTYPE fd){  return fd >= 0;}static void file_close (FDTYPE fd){  close(fd);}static bool file_read_bytes (FDTYPE fd,			     uint8_t *buffer, 			     uint32_t len){  uint32_t readval = read(fd, buffer, len);  return readval == len;}// note: len could be negative.static void file_skip_bytes (FDTYPE fd, int32_t len){  lseek(fd, len, SEEK_CUR);}static off_t file_location (FDTYPE fd){  return lseek(fd, 0, SEEK_CUR);}static off_t file_seek_to (FDTYPE fd, off_t loc){  return lseek(fd, loc, SEEK_SET);}static off_t file_size (FDTYPE fd){  off_t ret = lseek(fd, 0, SEEK_END);  file_seek_to(fd, 0);  return ret;}static uint64_t read_pts (uint8_t *pak){  uint64_t pts;  uint16_t temp;    pts = ((pak[0] >> 1) & 0x7);  pts <<= 15;  temp = convert16(&pak[1]) >> 1;  pts |= temp;  pts <<= 15;  temp = convert16(&pak[3]) >> 1;  pts |= temp;  return pts;}static mpeg2ps_stream_t *mpeg2ps_stream_create (uint8_t stream_id,						uint8_t substream){  mpeg2ps_stream_t *ptr = MALLOC_STRUCTURE(mpeg2ps_stream_t);  memset(ptr, 0, sizeof(*ptr));  ptr->m_stream_id = stream_id;  ptr->m_substream_id = substream;  ptr->is_video = stream_id >= 0xe0;  ptr->pes_buffer = (uint8_t *)malloc(4*4096);  ptr->pes_buffer_size_max = 4 * 4096;  return ptr;}static void mpeg2ps_stream_destroy (mpeg2ps_stream_t *sptr){  mpeg2ps_record_pes_t *p;  while (sptr->record_first != NULL) {    p = sptr->record_first;    sptr->record_first = p->next_rec;    free(p);  }  if (sptr->m_fd != FDNULL) {    file_close(sptr->m_fd);    sptr->m_fd = FDNULL;  }  CHECK_AND_FREE(sptr->pes_buffer);  free(sptr);}/* * adv_past_pack_hdr - read the pack header, advance past it * we don't do anything with the data */static void adv_past_pack_hdr (FDTYPE fd, 			       uint8_t *pak,			       uint32_t read_from_start){  uint8_t stuffed;  uint8_t readbyte;  uint8_t val;  if (read_from_start < 5) {    file_skip_bytes(fd, 5 - read_from_start);    file_read_bytes(fd, &readbyte, 1);    val = readbyte;  } else {    val = pak[4];  }      // we've read 6 bytes  if ((val & 0xc0) != 0x40) {    // mpeg1    file_skip_bytes(fd, 12 - read_from_start); // skip 6 more bytes    return;  }  file_skip_bytes(fd, 13 - read_from_start);  file_read_bytes(fd, &readbyte, 1);  stuffed = readbyte & 0x7;  file_skip_bytes(fd, stuffed);}/* * find_pack_start * look for the pack start code in the file - read 512 bytes at a time,  * searching for that code. * Note: we may also be okay looking for >= 00 00 01 bb */static bool find_pack_start (FDTYPE fd, 			     uint8_t *saved,			     uint32_t len){  uint8_t buffer[512];  uint32_t buffer_on = 0, new_offset, scode;  memcpy(buffer, saved, len);  if (file_read_bytes(fd, buffer + len, sizeof(buffer) - len) == FALSE) {    return FALSE;  }  while (1) {    if (MP4AV_Mpeg3FindNextStart(buffer + buffer_on,				 sizeof(buffer) - buffer_on, 				 &new_offset, 				 &scode) >= 0) {      buffer_on += new_offset;      if (scode == MPEG2_PS_PACKSTART) {	file_skip_bytes(fd, buffer_on - 512); // go back to header	return TRUE;      }      buffer_on += 1;    } else {      len = 0;      if (buffer[sizeof(buffer) - 3] == 0 &&	  buffer[sizeof(buffer) - 2] == 0 &&	  buffer[sizeof(buffer) - 1] == 1) {	buffer[0] = 0;	buffer[1] = 0;	buffer[2] = 1;	len = 3;      } else if (*(uint16_t *)(buffer + sizeof(buffer) - 2) == 0) {	buffer[0] = 0;	buffer[1] = 0;	len = 2;      } else if (buffer[sizeof(buffer) - 1] == 0) {	buffer[0] = 0;	len = 1;      }      if (file_read_bytes(fd, buffer + len, sizeof(buffer) - len) == FALSE) {	return FALSE;      }      buffer_on = 0;    }  }  return FALSE;}/* * copy_bytes_to_pes_buffer - read pes_len bytes into the buffer,  * adjusting it if we need it */static void copy_bytes_to_pes_buffer (mpeg2ps_stream_t *sptr, 			       uint16_t pes_len){  uint32_t to_move;  if (sptr->pes_buffer_size + pes_len > sptr->pes_buffer_size_max) {    // if no room in the buffer, we'll move it - otherwise, just fill    // note - we might want a better strategy about moving the buffer -     // right now, we might be moving a number of bytes if we have a large    // followed by large frame.    to_move = sptr->pes_buffer_size - sptr->pes_buffer_on;    memmove(sptr->pes_buffer,	    sptr->pes_buffer + sptr->pes_buffer_on,	    to_move);    sptr->pes_buffer_size = to_move;    sptr->pes_buffer_on = 0;    //printf("moving %d bytes\n", to_move);    if (to_move + pes_len > sptr->pes_buffer_size_max) {      sptr->pes_buffer = (uint8_t *)realloc(sptr->pes_buffer, 					    to_move + pes_len + 2048);      sptr->pes_buffer_size_max = to_move + pes_len + 2048;    }  }  file_read_bytes(sptr->m_fd, sptr->pes_buffer + sptr->pes_buffer_size, pes_len);  sptr->pes_buffer_size += pes_len;#if 0  printf("copying %u bytes - on %u size %u\n",	 pes_len, sptr->pes_buffer_on, sptr->pes_buffer_size);#endif}/* * read_to_next_pes_header - read the file, look for the next valid * pes header.  We will skip over PACK headers, but not over any of the * headers listed in 13818-1, table 2-18 - basically, anything with the * 00 00 01 and the next byte > 0xbb. * We return the pes len to read, and the "next byte" */static bool read_to_next_pes_header (FDTYPE fd, 				     uint8_t *stream_id,				     uint16_t *pes_len){  uint32_t hdr;  uint8_t local[6];  while (1) {    // read the pes header    if (file_read_bytes(fd, local, 6) == FALSE) {      return FALSE;    }    hdr = convert32(local);    // if we're not a 00 00 01, read until we get the next pack start    // we might want to also read until next PES - look into that.    if (((hdr & MPEG2_PS_START_MASK) != MPEG2_PS_START) ||	(hdr < MPEG2_PS_END)) {      if (find_pack_start(fd, local, 6) == FALSE) {	return FALSE;      }      continue;    }    if (hdr == MPEG2_PS_PACKSTART) {      // pack start code - we can skip down      adv_past_pack_hdr(fd, local, 6);      continue;    }    if (hdr == MPEG2_PS_END) {      file_skip_bytes(fd, -2);      continue;    }    // we should have a valid stream and pes_len here...    *stream_id = hdr & 0xff;    *pes_len = convert16(local + 4);#if 0    printf("loc: "X64" %x %x len %u\n", file_location(fd) - 6,	   local[3],	   *stream_id,	   *pes_len);#endif    return TRUE;  }  return FALSE;}/* * read_pes_header_data * this should read past the pes header for the audio and video streams * it will store the timestamps if it reads them */static bool read_pes_header_data (FDTYPE fd, 				  uint16_t orig_pes_len,				  uint16_t *pes_left,				  bool *have_ts,				  mpeg2ps_ts_t *ts){  uint16_t pes_len = orig_pes_len;  uint8_t local[10];  uint32_t hdr_len;  ts->have_pts = FALSE;  ts->have_dts = FALSE;  *have_ts = false;  if (file_read_bytes(fd, local, 1) == FALSE) {    return FALSE;  }  pes_len--; // remove this first byte from length  while (*local == 0xff) {    if (file_read_bytes(fd, local, 1) == FALSE) {      return FALSE;    }    pes_len--;    if (pes_len == 0) {      *pes_left = 0;      return TRUE;    }  }  if ((*local & 0xc0) == 0x40) {     // buffer scale & size    file_skip_bytes(fd, 1);    if (file_read_bytes(fd, local, 1) == FALSE) {      return FALSE;    }    pes_len -= 2;  }  if ((*local & 0xf0) == 0x20) {    // mpeg-1 with pts    if (file_read_bytes(fd, local + 1, 4) == FALSE) {      return FALSE;    }    ts->have_pts = TRUE;    ts->pts = ts->dts = read_pts(local);    //printf("mpeg1 pts "U64"\n", ts->pts);    *have_ts = true;    pes_len -= 4;  } else if ((*local & 0xf0) == 0x30) {    // have mpeg 1 pts and dts    if (file_read_bytes(fd, local + 1, 9) == FALSE) {      return FALSE;    }    ts->have_pts = TRUE;    ts->have_dts = TRUE;    *have_ts = true;    ts->pts = read_pts(local);    ts->dts = read_pts(local + 5);    pes_len -= 9;  } else if ((*local & 0xc0) == 0x80) {    // mpeg2 pes header  - we're pointing at the flags field now    if (file_read_bytes(fd, local + 1, 2) == FALSE) {      return FALSE;    }    hdr_len = local[2];    pes_len -= hdr_len + 2; // first byte removed already    if ((local[1] & 0xc0) == 0x80) {      // just pts      ts->have_pts = TRUE;      file_read_bytes(fd, local, 5);      ts->pts = ts->dts = read_pts(local);      //printf("pts "U64"\n", ts->pts);      *have_ts = true;      hdr_len -= 5;    } else if ((local[1] & 0xc0) == 0xc0) {      // pts and dts      ts->have_pts = TRUE;      ts->have_dts = TRUE;      *have_ts = true;      file_read_bytes(fd, local, 10);      ts->pts = read_pts(local);      ts->dts = read_pts(local  + 5);          hdr_len -= 10;    }    file_skip_bytes(fd, hdr_len);  } else if (*local != 0xf) {    file_skip_bytes(fd, pes_len);    pes_len = 0;  }   *pes_left = pes_len;  return TRUE;}static bool search_for_next_pes_header (mpeg2ps_stream_t *sptr, 					uint16_t *pes_len,					bool *have_ts, 					off_t *found_loc){  uint8_t stream_id;  uint8_t local;  off_t loc;  mpeg2ps_ts_t *ps_ts;  while (1) {    // this will read until we find the next pes.  We don't know if the    // stream matches - this will read over pack headers    if (read_to_next_pes_header(sptr->m_fd, &stream_id, pes_len) == FALSE) {      return FALSE;    }    if (stream_id != sptr->m_stream_id) {      file_skip_bytes(sptr->m_fd, *pes_len);      continue;    }    loc = file_location(sptr->m_fd) - 6;     // advance past header, reading pts    // if our existing next_ps has pts stuff, we use the next_next    // this happens when a frame is small, and at the very end of     // a pes, with a frame starting at the next pes.    ps_ts = (sptr->next_pes_ts.have_pts || sptr->next_pes_ts.have_dts) ?      &sptr->next_next_pes_ts : &sptr->next_pes_ts;    if (read_pes_header_data(sptr->m_fd, 			     *pes_len, 			     pes_len, 			     have_ts, 			     ps_ts) == FALSE) {      return FALSE;    }#if 0    printf("loc: "X64" have ts %u "U64" %d\n",	   loc, *have_ts, sptr->next_pes_ts.dts, *pes_len);#endif    // If we're looking at a private stream, make sure that the sub-stream    // matches.    if (sptr->m_stream_id == 0xbd) {      // ac3 or pcm      file_read_bytes(sptr->m_fd, &local, 1);      *pes_len -= 1;      if (local != sptr->m_substream_id) {	file_skip_bytes(sptr->m_fd, *pes_len);	continue; // skip to the next one      }      if (sptr->m_substream_id >= 0xa0) {	*pes_len -= 6;	file_read_bytes(sptr->m_fd, sptr->audio_private_stream_info, 6);#if 0	printf("reading %x %x %x %x\n", 	       sptr->audio_private_stream_info[0],	       sptr->audio_private_stream_info[1],	       sptr->audio_private_stream_info[2],	       sptr->audio_private_stream_info[3]);#endif      } else {	*pes_len -= 3;	file_skip_bytes(sptr->m_fd, 3); // 4 bytes - we don't need now...      }      // we need more here...    }    if (*have_ts) {      mpeg2ps_record_pts(sptr, loc, ps_ts);    }    if (found_loc != NULL) *found_loc = loc;    return true;  }  return false;}/* * mpeg2ps_stream_read_next_pes_buffer - for the given stream,  * go forward in the file until the next PES for the stream is read.  Read * the header (pts, dts), and read the data into the pes_buffer pointer */static bool mpeg2ps_stream_read_next_pes_buffer (mpeg2ps_stream_t *sptr){  uint16_t pes_len;  bool have_ts;  if (search_for_next_pes_header(sptr, &pes_len, &have_ts, NULL) == false) {    return false;  }  copy_bytes_to_pes_buffer(sptr, pes_len);  return TRUE;}static void copy_next_pes_ts_to_frame_ts (mpeg2ps_stream_t *sptr){  sptr->frame_ts = sptr->next_pes_ts;#if 1  sptr->next_pes_ts = sptr->next_next_pes_ts;  sptr->next_next_pes_ts.have_pts =     sptr->next_next_pes_ts.have_dts = false;#else  sptr->next_pes_ts.have_pts = sptr->next_pes_ts.have_dts = false;#endif}/*************************************************************************** * Frame reading routine.  For each stream, the fd's should be different. * we will read from the pes stream, and save it in the stream's pes buffer. * This will give us raw data that we can search through for frame headers,  * and the like.  We shouldn't read more than we need - when we need to read,  * we'll put the whole next pes buffer in the buffer * * Audio routines are of the format: *   look for header *   determine length *   make sure length is in buffer * * Video routines *   look for start header (GOP, SEQ, Picture) *   look for pict header *   look for next start (END, GOP, SEQ, Picture) *    ***************************************************************************/#define IS_MPEG_START(a) ((a) == 0xb3 || (a) == 0x00 || (a) == 0xb8)static bool mpeg2ps_stream_find_mpeg_video_frame (mpeg2ps_stream_t *sptr){  uint32_t offset, scode;  bool have_pict;  bool started_new_pes = false;  uint32_t start;  /*   * First thing - determine if we have enough bytes to read the header.   * if we do, we have the correct timestamp.  If not, we read the new   * pes, so we'd want to use the timestamp we read.   */  sptr->frame_ts = sptr->next_pes_ts; #if 0  printf("frame read %u "U64"\n", sptr->frame_ts.have_dts, sptr->frame_ts.dts);#endif

⌨️ 快捷键说明

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