水煮苹果的做法煮多久:DVBPSI中PAT PMT 编码函数注解 - 放下的窝棚 - CSDN博客

来源:百度文库 编辑:中财网 时间:2024/04/29 18:04:20

DVBPSI中PAT PMT 编码函数注解收藏

和段师兄一起学习dvbpsi的笔记

主要是PAT、PMT的编码函数的注释

/*****************************************************************************
 * dvbpsi_GenPATSections
 *****************************************************************************
 * 用传入的p_pat信息构建PAT,i_max_pps参数用于限制每个pat里携带节目信息的数量(最多253个)
 *****************************************************************************/
dvbpsi_psi_section_t* dvbpsi_GenPATSections(dvbpsi_pat_t* p_pat,
                                            int i_max_pps)
{
  dvbpsi_psi_section_t* p_result = dvbpsi_NewPSISection(1024); /*保存返回值*/
  dvbpsi_psi_section_t* p_current = p_result;
  dvbpsi_psi_section_t* p_prev;
  dvbpsi_pat_program_t* p_program = p_pat->p_first_program; /*传入的不同节目PMT所使用的PID号的结构链*/
  int i_count = 0; /*存储已经写入的节目数*/

  /* 一个PAT表最多能携带253个节目信息 */
  if((i_max_pps <= 0) || (i_max_pps > 253))
    i_max_pps = 253;

  p_current->i_table_id = 0; /*标志本表格的类型,PAT应该是0x00*/
  p_current->b_syntax_indicator = 1; /*段语法标志*/
  p_current->b_private_indicator = 0;
  p_current->i_length = 9;                      /* header + CRC_32 */
  p_current->i_extension = p_pat->i_ts_id; /*16bits的当前流ID,DVB内唯一.(事实上很多都是自定义的TS ID)*/
  p_current->i_version = p_pat->i_version; /*5bits版本号码,标注当前节目的版本.这是个非常有用的参数,当检测到这个字段改变时,说明TS流中的节目已经变化了,程序必须重新搜索节目*/
  p_current->b_current_next = p_pat->b_current_next; /*当前还是未来使用标志符,一般情况下为'0'*/
  p_current->i_number = 0; /*当前段号码*/
  p_current->p_payload_end += 8;                /* 跳过8字节的表头信息*/
  p_current->p_payload_start = p_current->p_payload_end; /*未写入数据时,开始和结束在同一位置*/

  /* 向PAT中填入节目信息 */
  while(p_program != NULL)
  {
    /* 如果一个PAT表保存不完,则需新建一个PAT表*/
    if(++i_count > i_max_pps)
    {
      p_prev = p_current;
      p_current = dvbpsi_NewPSISection(1024);
      p_prev->p_next = p_current;
      i_count = 1; /*下面将在新段写入第一个节目信息*/

      p_current->i_table_id = 0;
      p_current->b_syntax_indicator = 1;
      p_current->b_private_indicator = 0;
      p_current->i_length = 9;                  /* header + CRC_32 */
      p_current->i_extension = p_pat->i_ts_id;
      p_current->i_version = p_pat->i_version;
      p_current->b_current_next = p_pat->b_current_next;
      p_current->i_number = p_prev->i_number + 1;
      p_current->p_payload_end += 8;            /* 跳过头,指向节目信息开始*/
      p_current->p_payload_start = p_current->p_payload_end;
    }

    /* p_payload_end 指向节目信息开始处,从这里开始填充数据*/
    p_current->p_payload_end[0] = p_program->i_number >> 8; /*填入16bits的节目号*/
    p_current->p_payload_end[1] = p_program->i_number;
    p_current->p_payload_end[2] = (p_program->i_pid >> 8) | 0xe0; /*0xe0=11100000  保留的三位置1,填入PMT的PID的高5位*/
    p_current->p_payload_end[3] = p_program->i_pid; /*PID的低8位*/

    /* 每个PMT占4字节,所以按4字节递增*/
    p_current->p_payload_end += 4;
    p_current->i_length += 4;

    p_program = p_program->p_next;
  }

  /* 将所有PAT表中的最后段号码设置成最后一个PAT的号码*/
  p_prev = p_result;
  while(p_prev != NULL)
  {
    p_prev->i_last_number = p_current->i_number;
    dvbpsi_BuildPSISection(p_prev); /*调用dvbpsi_BuildPSISection构建PSI包*/
    p_prev = p_prev->p_next;
  }

  return p_result;
}

/*****************************************************************************
 * dvbpsi_GenPMTSections
 *****************************************************************************
 * 用传入的p_pmt信息构建PMT
 *****************************************************************************/
dvbpsi_psi_section_t* dvbpsi_GenPMTSections(dvbpsi_pmt_t* p_pmt)
{
  dvbpsi_psi_section_t* p_result = dvbpsi_NewPSISection(1024); /*分配空间,用来存放最后结果*/
  dvbpsi_psi_section_t* p_current = p_result;
  dvbpsi_psi_section_t* p_prev;
  dvbpsi_descriptor_t* p_descriptor = p_pmt->p_first_descriptor;
  dvbpsi_pmt_es_t* p_es = p_pmt->p_first_es;
  uint16_t i_info_length; /*存储段或描述符长度*/

  p_current->i_table_id = 0x02; /*表ID为0x02表示此表为PMT*/
  p_current->b_syntax_indicator = 1;
  p_current->b_private_indicator = 0; /*私有标志:0 不是私有数据*/
  p_current->i_length = 13;                     /* 表头 + 4bytes CRC_32校验数据,从program_number开始,到CRC_32(包含)的字节总数 */
  p_current->i_extension = p_pmt->i_program_number; /*16bits的频道号码,表示当前的PMT关联到的频道*/
 p_current->i_version =p_pmt->i_version; /*版本号码,如果PMT内容有更新,则version_number会递增1通知解复用程序需要重新接收节目信息,否则version_number是固定不变的.*/
  p_current->b_current_next = p_pmt->b_current_next;
  p_current->i_number = 0; /*当前未来标志符,一般是0*/
  p_current->p_payload_end += 12;               /* 指向频道描述符开始 */
  p_current->p_payload_start = p_current->p_data + 8; /*跳过表头,指向数据开始*/

  /* 填入PCR信息*/
  p_current->p_data[8] = (p_pmt->i_pcr_pid >> 8) | 0xe0; /*68~81bit的13bit位存储PCR信息,先填入高5位数据*/
  p_current->p_data[9] = p_pmt->i_pcr_pid;

  /* PMT descriptors */
  while(p_descriptor != NULL)
  {
    /* 判断是否需要新的PMT表*/
    /* 已写入的数据长度 + 描述符长度 + 2 > 1024 - CRC_32_length  ,2字节用于存储描述符长度*/
    if(   (p_current->p_payload_end - p_current->p_data)
                                + p_descriptor->i_length > 1018)
    {
      /* 节目信息长度,就是紧接着的若干个描述符的总长度*/
      i_info_length = (p_current->p_payload_end - p_current->p_data) - 12; /*减去表头的12个字节*/
      p_current->p_data[10] = (i_info_length >> 8) | 0xf0; /*将长度写入到77~88bit的14bit中,先写入高4位*/
      p_current->p_data[11] = i_info_length;

  /*一个PMT存储不完,构建新的PMT继续存储*/
      p_prev = p_current;
      p_current = dvbpsi_NewPSISection(1024);
      p_prev->p_next = p_current;

      p_current->i_table_id = 0x02;
      p_current->b_syntax_indicator = 1;
      p_current->b_private_indicator = 0;
      p_current->i_length = 13;                 /* header + CRC_32 */
      p_current->i_extension = p_pmt->i_program_number;
      p_current->i_version = p_pmt->i_version;
      p_current->b_current_next = p_pmt->b_current_next;
      p_current->i_number = p_prev->i_number + 1;
      p_current->p_payload_end += 12;           /* just after the header */
      p_current->p_payload_start = p_current->p_data + 8;

      /* PCR_PID */
      p_current->p_data[8] = (p_pmt->i_pcr_pid >> 8) | 0xe0;
      p_current->p_data[9] = p_pmt->i_pcr_pid;
    }

    /* p_payload_end 已经指向描述符开始处 */
    p_current->p_payload_end[0] = p_descriptor->i_tag; /*设置描述符标志*/
    p_current->p_payload_end[1] = p_descriptor->i_length; /*设置描述符长度*/
    memcpy(p_current->p_payload_end + 2, /*将描述符数据填充入p_data中*/
           p_descriptor->p_data,
           p_descriptor->i_length);

    /* 每个描述符只用2个字节来存储标志和长度,所以以2递增*/
    p_current->p_payload_end += p_descriptor->i_length + 2;
    p_current->i_length += p_descriptor->i_length + 2;

    p_descriptor = p_descriptor->p_next;
  }

  /* 写入描述符总长度信息*/
  i_info_length = (p_current->p_payload_end - p_current->p_data) - 12;
  p_current->p_data[10] = (i_info_length >> 8) | 0xf0;
  p_current->p_data[11] = i_info_length;

  /* PMT ESs */
  while(p_es != NULL)
  {
    uint8_t* p_es_start = p_current->p_payload_end;
    uint16_t i_es_length = 5;

    /* 测试当前PMT表能否存储所有描述符 */
    p_descriptor = p_es->p_first_descriptor;
    while(    (p_descriptor != NULL)
           && ((p_es_start - p_current->p_data) + i_es_length <= 1020)) /*1020=1024-4  留出4字节的CRC校验数据空间*/
    {
      i_es_length += p_descriptor->i_length + 2; /*2是指存储描述符标志和长度把占用的2字节*/
      p_descriptor = p_descriptor->p_next;
    }

    /* 如果描述符链末空,当前表不是空表,则创建新表*/
    if(    (p_descriptor != NULL) /*链未空,仍有描述符未被存储*/
        && (p_es_start - p_current->p_data != 12) /*当前表不是空表*/
        && (i_es_length <= 1008)) /*1008=1024-12-4 ,12字节的表头和4字节的CRC数据,我觉得该判断会始终为真???*/
    {
      /* 将剩余的描述符存入新表中 */
      DVBPSI_DEBUG("PMT generator",
                   "create a new section to carry more ES descriptors");
      p_prev = p_current;
      p_current = dvbpsi_NewPSISection(1024);
      p_prev->p_next = p_current;

      p_current->i_table_id = 0x02;
      p_current->b_syntax_indicator = 1;
      p_current->b_private_indicator = 0;
      p_current->i_length = 13;                 /* header + CRC_32 */
      p_current->i_extension = p_pmt->i_program_number;
      p_current->i_version = p_pmt->i_version;
      p_current->b_current_next = p_pmt->b_current_next;
      p_current->i_number = p_prev->i_number + 1;
      p_current->p_payload_end += 12;           /* just after the header */
      p_current->p_payload_start = p_current->p_data + 8;

      /* PCR_PID */
      p_current->p_data[8] = (p_pmt->i_pcr_pid >> 8) | 0xe0;
      p_current->p_data[9] = p_pmt->i_pcr_pid;

      /* program_info_length */
      i_info_length = 0; /*只携带ES描述符,所以节目信息长度设置为0*/
      p_current->p_data[10] = 0xf0; /*保留的4位置1*/
      p_current->p_data[11] = 0x00;

      p_es_start = p_current->p_payload_end;
    }

    /* p_es_start 已经指向ES数据开始处,写入ES相关信息 */
    p_es_start[0] = p_es->i_type;
    p_es_start[1] = (p_es->i_pid >> 8) | 0xe0; /*用14bit位存储ES PID,先写入高4位*/
    p_es_start[2] = p_es->i_pid;

    /* 占用了5个字节 */
    p_current->p_payload_end += 5;
    p_current->i_length += 5;

    /* ES descriptors */
    p_descriptor = p_es->p_first_descriptor;
    while(    (p_descriptor != NULL)
           && (   (p_current->p_payload_end - p_current->p_data)
                + p_descriptor->i_length <= 1018)) /*ES描述符不为空及空间足够,已用空间+4字节CRC+2字节(tag和length)<1018*/
    {
      /* p_payload_end is where the descriptor begins */
      p_current->p_payload_end[0] = p_descriptor->i_tag;
      p_current->p_payload_end[1] = p_descriptor->i_length;
      memcpy(p_current->p_payload_end + 2,
             p_descriptor->p_data,
             p_descriptor->i_length);

      /* 向后移动 descriptor_length + 2 */
      p_current->p_payload_end += p_descriptor->i_length + 2;
      p_current->i_length += p_descriptor->i_length + 2;

      p_descriptor = p_descriptor->p_next;
    }

    if(p_descriptor != NULL)
      DVBPSI_ERROR("PMT generator", "unable to carry all the ES descriptors");

    /* ES_info_length */
    i_es_length = p_current->p_payload_end - p_es_start - 5;
    p_es_start[3] = (i_es_length >> 8) | 0xf0; /*写入ES描述符的总长度*/
    p_es_start[4] = i_es_length;

    p_es = p_es->p_next;
  }

  /* Finalization */
  p_prev = p_result;
  while(p_prev != NULL)
  {
    p_prev->i_last_number = p_current->i_number;
    dvbpsi_BuildPSISection(p_prev);
    p_prev = p_prev->p_next;
  }

  return p_result;
}