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

📄 mpeg2_transport.c

📁 完整的RTP RTSP代码库
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * mpeg2t_malloc_es_work - create or clean a mpeg2t_frame_t for an * elementary stream. */void mpeg2t_malloc_es_work (mpeg2t_es_t *es_pid, uint32_t frame_len){  uint8_t *frameptr;#if 0  mpeg2t_message(LOG_DEBUG, "es %x malloc %d", es_pid->pid.pid,		 es_pid->have_ps_ts);#endif  if (es_pid->work == NULL || es_pid->work->frame_len < frame_len) {    if (es_pid->work != NULL) {      free(es_pid->work);      es_pid->work = NULL;    }    frameptr = (uint8_t *)malloc(sizeof(mpeg2t_frame_t) + frame_len);    if (frameptr == NULL) return;    es_pid->work = (mpeg2t_frame_t *)frameptr;    es_pid->work->frame = frameptr + sizeof(mpeg2t_frame_t);    es_pid->work->frame_len = frame_len;  }  es_pid->work->next_frame = NULL;  es_pid->work->have_ps_ts = es_pid->have_ps_ts;  es_pid->work->have_dts = es_pid->have_dts;  es_pid->work->ps_ts = es_pid->ps_ts;  es_pid->work->dts = es_pid->dts;  es_pid->have_ps_ts = 0;  es_pid->have_dts = 0;}/* * mpeg2t_finished_es_work - when we have a frame, this is  * called to save the frame on the list (if so configured) */void mpeg2t_finished_es_work (mpeg2t_es_t *es_pid,			      uint32_t frame_len){  mpeg2t_frame_t *p;#if 1  mpeg2t_message(LOG_WARNING, "pid %x pts %d "U64" listing %d", 		 es_pid->pid.pid, es_pid->work->have_ps_ts, 		 es_pid->work->ps_ts, es_pid->save_frames);#endif  SDL_LockMutex(es_pid->list_mutex);  if (es_pid->save_frames == 0) {    mpeg2t_malloc_es_work(es_pid, es_pid->work->frame_len);  } else {    es_pid->work->frame_len = frame_len;    if (es_pid->list == NULL) {      es_pid->list = es_pid->work;    } else {      p = es_pid->list;      while (p->next_frame != NULL) p = p->next_frame;      p->next_frame = es_pid->work;    }    es_pid->frames_in_list++;    es_pid->work = NULL;  }  es_pid->work_loaded = 0;  SDL_UnlockMutex(es_pid->list_mutex);}/* * mpeg2t_get_es_list_head - get the first frame on the list */mpeg2t_frame_t *mpeg2t_get_es_list_head (mpeg2t_es_t *es_pid){  mpeg2t_frame_t *p;  SDL_LockMutex(es_pid->list_mutex);  p = es_pid->list;  if (p != NULL) {    es_pid->list = p->next_frame;    p->next_frame = NULL;    es_pid->frames_in_list--;  }  SDL_UnlockMutex(es_pid->list_mutex);  return p;}void mpeg2t_free_frame (mpeg2t_frame_t *fptr){  free(fptr);}/* * mpeg2t_process_es - process a transport stream pak for an * elementary stream */static int mpeg2t_process_es (mpeg2t_t *ptr, 			      mpeg2t_pid_t *ifptr,			      const uint8_t *buffer){  uint32_t buflen;  uint32_t pes_len;  const uint8_t *esptr;  mpeg2t_es_t *es_pid = (mpeg2t_es_t *)ifptr;  int read_pes_options;  uint8_t stream_id;  uint32_t nextcc, pakcc;  int ret;  int ac;  int have_psts;  uint64_t pts;  uint32_t offset;#ifdef DEBUG_MPEG2T  uint32_t ix;#endif  ac = mpeg2t_adaptation_control(buffer);  // Note to self - if ac is 0x3, we may have to check  // the discontinuity indicator in the adapation control - this  // can cause a cc to be non-sequential, as well.  // ASDF - not implemented yet  nextcc = ifptr->lastcc;  if (!(ac == 0 || ac == 2)) {    // don't add to continuity counter if adaptation counter is 0 or 2    nextcc = (nextcc + 1) & 0xf;  }  pakcc = mpeg2t_continuity_counter(buffer);  if (nextcc != pakcc) {    // Note - this message will occur for the first packet    mpeg2t_message(LOG_ERR, "cc error in PID %x should be %d is %d %x", 	   ifptr->pid, nextcc, pakcc, buffer[3]);    clean_es_data(es_pid);  }  ifptr->lastcc = pakcc;  if (es_pid->save_frames == 0 &&      es_pid->report_psts == 0 &&      es_pid->info_loaded > 0) {    //    mpeg2t_message(LOG_INFO, "PID %x not processing", ifptr->pid);    return 0;  }  buflen = 188;  // process pas pointer  esptr = mpeg2t_transport_payload_start(buffer, &buflen);  if (esptr == NULL) return -1;    have_psts = 0;  if (mpeg2t_payload_unit_start_indicator(buffer) != 0) {    // start of PES packet    es_pid->peshdr_loaded = 1;    if ((esptr[0] != 0) ||	(esptr[1] != 0) ||	(esptr[2] != 1)) {      mpeg2t_message(LOG_ERR, 		     "Illegal start to PES packet - pid %x - %02x %02x %02x",		     ifptr->pid, esptr[0], esptr[1], esptr[2]);      return -1;    }    stream_id = es_pid->stream_id = esptr[3];    pes_len = (esptr[4] << 8) | esptr[5];    esptr += 6;    buflen -= 6;    read_pes_options = 0;    // do we have header extensions    switch ((stream_id & 0x70) >> 4) {    default:      if ((stream_id == 0xbd) ||	    (stream_id >= 0xf3 && stream_id <= 0xf7) ||	    (stream_id >= 0xf9)) {	read_pes_options = 1;	break;      }      // fall through    case 4:    case 5:    case 6:      if (esptr[2] <= buflen - 3) {	// multiple PES for header	read_pes_options = 1;      } else {	// don't have enough to read the header      }      break;    }    es_pid->have_ps_ts = 0;    es_pid->have_dts = 0;    if (read_pes_options) {      if (esptr[2] + 3U > buflen) {	return 0;      }      mpeg2t_message(LOG_INFO, "pid %x pes bits %x %x", 		     es_pid->pid.pid, esptr[0], esptr[1]);#ifdef DEBUG_MPEG2T      if ((esptr[1] & 0x20)) {	mpeg2t_message(LOG_INFO, "pid %x has ESCR", es_pid->pid.pid);      }      if ((esptr[1] & 0x10)) {	mpeg2t_message(LOG_INFO, "pid %x has ES rate", es_pid->pid.pid);      }#endif      offset = 3;      //mpeg2t_read_pes_options(es_pid, esptr);      if (esptr[1] & 0x80) {	// read presentation timestamp#if 0	mpeg2t_message(LOG_INFO, "Stream %x %02x %02x %02x", 	       stream_id, esptr[0], esptr[1], esptr[2]);	mpeg2t_message(LOG_INFO, "PTS %02x %02x %02x %02x %02x", 	       esptr[3], esptr[4], esptr[5], esptr[6], esptr[7]);#endif	if (((esptr[1] >> 6) & 0x3) !=	    ((esptr[3] >> 4) & 0xf)) {	  mpeg2t_message(LOG_ERR, "PID %x Timestamp flag value not same %x %x",			 es_pid->pid.pid, esptr[1], esptr[2]);	  return -1;	}	pts = ((esptr[3] >> 1) & 0x7);	pts <<= 8;	pts |= esptr[4];	pts <<= 7;	pts |= ((esptr[5] >> 1) & 0x7f);	pts <<= 8;	pts |= esptr[6];	pts <<= 7;	pts |= ((esptr[7] >> 1) & 0x7f);	es_pid->have_ps_ts = 1;	es_pid->ps_ts = pts; // (pts * M_64) / (90 * M_64); // give msec	have_psts = 1;	mpeg2t_message(LOG_INFO, "pid %x psts "U64, 		      es_pid->pid.pid, es_pid->ps_ts);	offset = 8;      }      // this is how we would read the dts, if we wanted to use it      if (esptr[1] & 0x40) {	pts = ((esptr[offset] >> 1) & 0x7);	pts <<= 8;	pts |= esptr[offset + 1];	pts <<= 7;	pts |= ((esptr[offset + 2] >> 1) & 0x7f);	pts <<= 8;	pts |= esptr[offset + 3];	pts <<= 7;	pts |= ((esptr[offset + 4] >> 1) & 0x7f);	mpeg2t_message(LOG_INFO, "pid %x  dts "U64,		       es_pid->pid.pid, pts);	have_psts = 1;	es_pid->have_dts = 1;	es_pid->dts = pts;      }#ifdef DEBUG_MPEG2T      mpeg2t_message(LOG_INFO, "pid %x pes buflen %d\n", es_pid->pid.pid, esptr[2]);      for (ix = 0; ix < esptr[2]; ix += 4) {	mpeg2t_message(LOG_ERR, "pid %x %d - %02x %02x %02x %02x", 		       es_pid->pid.pid, ix, 		       esptr[3 + ix],		       esptr[4 + ix],		       esptr[5 + ix],		       esptr[6 + ix]);      }#endif      buflen -= esptr[2] + 3;      esptr += esptr[2] + 3;      if (pes_len > 0)	pes_len -= esptr[2] + 3;    }  // process esptr, buflen    if (buflen == 0) {      es_pid->have_ps_ts = 0;      es_pid->have_dts = 0;      return 0;    }    mpeg2t_message(LOG_DEBUG, 		   "%x PES start stream id %02x len %u (%u)", ifptr->pid, 		   stream_id, pes_len, buflen);  } else {    // 0 in Payload start - process frame at start    read_pes_options = 0;  }  // have start of data is at esptr, buflen data  ret = 0;  switch (es_pid->stream_type) {  case 1:  case 2:    // mpeg1 or mpeg2 video    ret = process_mpeg2t_mpeg_video(es_pid, esptr, buflen);    break;  case 3:  case 4:    // mpeg1/mpeg2 audio (mp3 codec)    ret = process_mpeg2t_mpeg_audio(es_pid, esptr, buflen);    break;  case 0x10:    ret = process_mpeg2t_mpeg4_video(es_pid, esptr, buflen);    break;  case 129:    ret = process_mpeg2t_ac3_audio(es_pid, esptr, buflen);    break;  case 0x1b:    ret = process_mpeg2t_h264_video(es_pid, esptr, buflen);    break;  case 0xf:    // aac    break;  }  //es_pid->have_ps_ts = 0;  if (have_psts != 0 &&       es_pid->report_psts != 0) ret = 1;  return ret;}static void add_unknown_pid (mpeg2t_t *ptr, uint16_t rpid){  mpeg2t_unk_pid_t *p = MALLOC_STRUCTURE(mpeg2t_unk_pid_t);  p->next_unk = ptr->unk_pids;  ptr->unk_pids = p;  p->pid = rpid;  p->count = 1;}  static mpeg2t_unk_pid_t *look_up_unknown_pid (mpeg2t_t *ptr, uint16_t rpid){  mpeg2t_unk_pid_t *p = ptr->unk_pids;  while (p != NULL) {    if (p->pid == rpid) return p;    p = p->next_unk;  }  return NULL;}/* * mpeg2t_process_buffer - API routine that allows us to * process a buffer filled with transport streams */      mpeg2t_pid_t *mpeg2t_process_buffer (mpeg2t_t *ptr, 				     const uint8_t *buffer, 				     uint32_t buflen,				     uint32_t *buflen_used){  uint32_t offset;  uint32_t remaining;  uint32_t used;  uint16_t rpid;  mpeg2t_pid_t *pidptr;  int ret;  used = 0;  remaining = buflen;  mpeg2t_message(LOG_DEBUG, "start processing buffer - len %d", buflen);  if (buflen < 188) {    *buflen_used = buflen;    return NULL;  }  while (used < buflen) {    offset = mpeg2t_find_sync_byte(buffer, remaining);    //mpeg2t_message(LOG_DEBUG, "offset %d", offset);    if (offset >= remaining) {      mpeg2t_message(LOG_ERR, "sync not found in buffer");      *buflen_used = buflen;      return NULL;    }    remaining -= offset;    buffer += offset;    used += offset;    if (remaining < 188) {      *buflen_used = used;      return NULL;    }    // we have a complete buffer    rpid = mpeg2t_pid(buffer);#if 1    mpeg2t_message(LOG_DEBUG, "Buffer- PID %x start %d cc %d %x",		   rpid, mpeg2t_payload_unit_start_indicator(buffer),		   mpeg2t_continuity_counter(buffer),		   buffer[3]);#endif    if (rpid == 0x1fff) {      // just skip    } else {      // look up pid in table      pidptr = mpeg2t_lookup_pid(ptr, rpid);      if (pidptr != NULL) {	// okay - we've got a valid pid ptr	switch (pidptr->pak_type) {	case MPEG2T_PAS_PAK:	  ret = mpeg2t_process_pas(ptr, buffer);	  if (ret > 0) {	    *buflen_used = used + 188;	    return pidptr;	  }	  break;	case MPEG2T_PROG_MAP_PAK:	  ret = mpeg2t_process_pmap(ptr, pidptr, buffer);	  if (ret > 0) {	    *buflen_used = used + 188;	    return pidptr;	  }	  break;	case MPEG2T_ES_PAK:	  if (mpeg2t_process_es(ptr, pidptr, buffer) > 0) {	    *buflen_used = used + 188;	    return pidptr;	  }	  break;	}      } else {	if (ptr->pas.programs_added >= ptr->pas.programs) {	  mpeg2t_unk_pid_t *unk;	  unk = look_up_unknown_pid(ptr, rpid);	  if (unk != NULL) {	    unk->count++;	    if ((unk->count % 1000) == 0) {	      mpeg2t_message(LOG_ERR, 			     "unknown pid %x received %u packets", 			     rpid, unk->count);	    }	  } else {	    add_unknown_pid(ptr, rpid);	  	    mpeg2t_message(LOG_ALERT, 			 "pid %x received - not in pas/program map table", rpid);	  }	}      }			     }    used += 188;    buffer += 188;    remaining -= 188;  }  *buflen_used = buflen;  return NULL;}/* * create_mpeg2_tranport - create the basic structure - we always * need a PAS, so we create one (PAS has a pid of 0). */  mpeg2t_t *create_mpeg2_transport (void){  mpeg2t_t *ptr;  ptr = MALLOC_STRUCTURE(mpeg2t_t);  memset(ptr, 0, sizeof(mpeg2t_t));  ptr->pas.pid.pak_type = MPEG2T_PAS_PAK;  ptr->pas.pid.next_pid = NULL;  ptr->pas.pid.pid = 0;  ptr->program_count = 0;  ptr->program_maps_recvd = 0;  ptr->pid_mutex = SDL_CreateMutex();  return (ptr);}static void clean_pid (mpeg2t_pid_t *pidptr){  CHECK_AND_FREE(pidptr->data);}static void clean_es_pid (mpeg2t_es_t *es_pid){  mpeg2t_frame_t *p;  clean_es_data(es_pid);    do {    p = mpeg2t_get_es_list_head(es_pid);    if (p != NULL)      free(p);  } while (p != NULL);  CHECK_AND_FREE(es_pid->work);  CHECK_AND_FREE(es_pid->es_data);  SDL_DestroyMutex(es_pid->list_mutex);}  void delete_mpeg2t_transport (mpeg2t_t *ptr){  mpeg2t_pid_t *pidptr, *p;  mpeg2t_pmap_t *pmap;  mpeg2t_unk_pid_t *unk;  pidptr = ptr->pas.pid.next_pid;  while (pidptr != NULL) {    mpeg2t_message(LOG_CRIT, "cleaning %p pid %x", 		   pidptr, pidptr->pid);    switch (pidptr->pak_type) {    case MPEG2T_ES_PAK:      clean_es_pid((mpeg2t_es_t *)pidptr);      break;    case MPEG2T_PROG_MAP_PAK:      pmap = (mpeg2t_pmap_t *)pidptr;      CHECK_AND_FREE(pmap->prog_info);      clean_pid(pidptr);      break;    case MPEG2T_PAS_PAK:      clean_pid(pidptr);      break;    }    p = pidptr;    pidptr = pidptr->next_pid;    free(p);  }  clean_pid(&ptr->pas.pid);  while (ptr->unk_pids != NULL) {    unk = ptr->unk_pids;    ptr->unk_pids = unk->next_unk;    free(unk);  }  SDL_DestroyMutex(ptr->pid_mutex);  free(ptr);}/* * Other API routines */void *mpeg2t_get_userdata (mpeg2t_pid_t *pid){  return pid->userdata;}void mpeg2t_set_userdata (mpeg2t_pid_t *pid, void *ud){  pid->userdata = ud;}void mpeg2t_set_frame_status (mpeg2t_es_t *es_pid, 			      uint32_t flags){  es_pid->save_frames = 0;  es_pid->report_psts = 0;  if (flags == MPEG2T_PID_NOTHING) {    mpeg2t_clear_frames(es_pid);    return;  }  if ((flags & MPEG2T_PID_REPORT_PSTS) != 0) {    es_pid->report_psts = 1;  }  if ((flags & MPEG2T_PID_SAVE_FRAME) != 0) {    es_pid->save_frames = 1;  }}void mpeg2t_clear_frames (mpeg2t_es_t *es_pid) {  SDL_LockMutex(es_pid->list_mutex);  es_pid->have_ps_ts = 0;  es_pid->have_dts = 0;  es_pid->have_seq_header = 0;  es_pid->frames_in_list = 0;  while (es_pid->list != NULL) {    mpeg2t_frame_t *f = es_pid->list;    es_pid->list = f->next_frame;    mpeg2t_free_frame(f);  }  clean_es_data(es_pid);  SDL_UnlockMutex(es_pid->list_mutex);}  int mpeg2t_write_stream_info (mpeg2t_es_t *es_pid, 			      char *buffer,			      size_t buflen){  int ret = -1;  switch (es_pid->stream_type) {  case 1:  case 2:    // mpeg1 or mpeg2 video    //ret = process_mpeg2t_mpeg_video(es_pid, esptr, buflen);    ret = mpeg2t_mpeg_video_info(es_pid, buffer, buflen);    break;  case 3:  case 4:    // mpeg1/mpeg2 audio (mp3 codec)    ret = mpeg2t_mpeg_audio_info(es_pid, buffer, buflen);    break;  case 0x10:    ret = mpeg2t_mpeg4_video_info(es_pid, buffer, buflen);    break;  case 129:    ret = mpeg2t_ac3_audio_info(es_pid, buffer, buflen);    break;  case 0x1b:    ret = mpeg2t_h264_video_info(es_pid, buffer, buflen);    break;  case 0xf:    // aac    break;  }  return ret;}

⌨️ 快捷键说明

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