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

📄 mpeg2_transport.c

📁 网络MPEG4IP流媒体开发源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
  section_len -= 4; // remove CRC  len = 0;  /*   * Now, add all elementary streams for this PMAP   */  while (len < section_len) {    stream_type = pmapptr[0];    e_pid = ((pmapptr[1] << 8) | pmapptr[2]) & 0x1fff;    es_len = ((pmapptr[3] << 8) | pmapptr[4]) & 0xfff;    if (es_len + len > section_len) return 0;    if (mpeg2t_lookup_pid(ptr, e_pid) == NULL) {      mpeg2t_message(LOG_INFO, "Creating es pid %x", e_pid);      create_es(ptr, e_pid, stream_type, &pmapptr[5], es_len);      ptr->program_maps_recvd++;    }    // create_es    len += 5 + es_len;    pmapptr += 5 + es_len;  }  return 1;}/* * clean_es_data * clean all data needed for processing the stream.  This  * should really be broken out into other files, like the * frame processing. */static void clean_es_data (mpeg2t_es_t *es_pid) {  es_pid->have_ps_ts = 0;  switch (es_pid->stream_type) {  case 1:  case 2:    // mpeg1 or mpeg2 video    es_pid->work_state = 0;    es_pid->header = 0;    es_pid->work_loaded = 0;    es_pid->have_seq_header = 0;    break;  case 3:  case 4:    // mpeg1/mpeg2 audio (mp3 codec    if (es_pid->work != NULL ) {      free(es_pid->work);      es_pid->work = NULL;    }    es_pid->work_loaded = 0;    es_pid->left = 0;    break;  case 0xf:    // aac    break;  }}  /* * 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 (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->ps_ts = es_pid->ps_ts;  es_pid->have_ps_ts = 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;  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;}  /* * 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;  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 PES %x should be %d is %d", 	   ifptr->pid, nextcc, pakcc);    clean_es_data(es_pid);  }  ifptr->lastcc = pakcc;  buflen = 188;  // process pas pointer  esptr = mpeg2t_transport_payload_start(buffer, &buflen);  if (esptr == NULL) return -1;    if (mpeg2t_payload_unit_start_indicator(buffer) != 0) {    // start of PES packet    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;    mpeg2t_message(LOG_DEBUG, 		   "PES start stream id %02x len %d", stream_id, pes_len);    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 && stream_id <= 0xff)) {	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;    if (read_pes_options) {      if (esptr[2] + 3 > buflen) {	return 0;      }      //mpeg2t_read_pes_options(es_pid, esptr);      if (((esptr[1] & 0xc0) == 0x80) ||	  ((esptr[1] & 0xc0) == 0xc0)) {	// read presentation timestamp	uint64_t pts;#if 1	mpeg2t_message(LOG_DEBUG, "Stream %x %02x %02x %02x", 	       stream_id, esptr[0], esptr[1], esptr[2]);	mpeg2t_message(LOG_DEBUG, "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 * M_LLU) / (90 * M_LLU); // give msec	mpeg2t_message(LOG_DEBUG, "pid %x psts "LLU, 		       es_pid->pid.pid, es_pid->ps_ts);      }      buflen -= esptr[2] + 3;      esptr += esptr[2] + 3;    }  // process esptr, buflen    if (buflen == 0) {      es_pid->have_ps_ts = 0;      return 0;    }  } 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 0xf:    // aac    break;  }  //es_pid->have_ps_ts = 0;  return ret;}			    /* * 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);  while (used < buflen) {    offset = mpeg2t_find_sync_byte(buffer, remaining);    if (offset >= remaining) {      *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",		   rpid, mpeg2t_payload_unit_start_indicator(buffer),		   mpeg2t_continuity_counter(buffer));#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;	}      }    }    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->pas.pid.collect_pes = 1;  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;  pidptr = ptr->pas.pid.next_pid;  while (pidptr != NULL) {    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);  SDL_DestroyMutex(ptr->pid_mutex);  free(ptr);}/* * Other API routines */void *mpeg2t_es_get_userdata (mpeg2t_es_t *es_pid){  return es_pid->es_userdata;}void mpeg2t_es_set_userdata (mpeg2t_es_t *es_pid, void *ud){  es_pid->es_userdata = ud;}void mpeg2t_start_saving_frames (mpeg2t_es_t *es_pid){  es_pid->save_frames = 1;}void mpeg2t_stop_saving_frames (mpeg2t_es_t *es_pid){  es_pid->save_frames = 0;}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 0xf:    // aac    break;  }  return ret;}

⌨️ 快捷键说明

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