ts文件格式解析

2023-11-10

TS格式解析

by ahuner

1.TS格式介绍

   TS:全称为MPEG2-TS。TS即"Transport Stream"的缩写。它是分包发送的,每一个包长为188字节(还有192和204个字节的包)。包的结构为,包头为4个字节(第一个字节为0x47),负载为184个字节。在TS流里可以填入很多类型的数据,如视频、音频、自定义信息等。MPEG2-TS主要应用于实时传送的节目,比如实时广播的电视节目。MPEG2-TS格式的特点就是要求从视频流的任一片段开始都是可以独立解码的。简单地说,将DVD上的VOB文件的前面一截cut掉(或者是数据损坏数据)就会导致整个文件无法解码,而电视节目是任何时候打开电视机都能解码(收看)的。

   TS解析需要参考:ISO/IEC 13818-1的2.4 Transport Stream bitstream requirements

2.TS流包含的内容

    一段TS流,必须包含PAT包、PMT包、多个音频包、多个视频包、多个PCR包、以及其他信息包。

    解析TS流数据的流程:查找PID为0x0的包,解析PAT,PAT包中的program_map_PID表示PMT的PID;查找PMT,PMT包中的elementary_PID表示音视频包的PID,PMT包中的PCR_PID表示PCR的PID,有的时候PCR的PID跟音频或者视频的PID相同,说明PCR会融进音视频的包,注意解析,有的时候PCR是自己单独的包;CAT、NIT、SDT、EIT的PID分别为: 0x01、0x10、0x11、0x12。

3.TS包头解析

    TS包头有4个字节

//Transport Stream header
typedef  struct  TS_header
{
          unsigned sync_byte                    :8;      //同步字节,固定为0x47 ,表示后面的是一个TS分组,当然,后面包中的数据是不会出现0x47的
          unsigned transport_error_indicator       :1;      //传输错误标志位,一般传输错误的话就不会处理这个包了
          unsigned payload_unit_start_indicator    :1;      //有效负载的开始标志,根据后面有效负载的内容不同功能也不同
          // payload_unit_start_indicator为1时,在前4个字节之后会有一个调整字节,它的数值决定了负载内容的具体开始位置。
          unsigned transport_priority              :1;      //传输优先级位,1表示高优先级
          unsigned PID                          :13;     //有效负载数据的类型
          unsigned transport_scrambling_control     :2;      //加密标志位,00表示未加密
          unsigned adaption_field_control          :2;      //调整字段控制,。01仅含有效负载,10仅含调整字段,11含有调整字段和有效负载。为00的话解码器不进行处理。
          unsigned continuity_counter              :4;      //一个4bit的计数器,范围0-15
} TS_header;
     //特殊参数说明:
    //sync_byte:0x47
    //payload_unit_start_indicator:0x01表示含有PSI或者PES头
    //PID:0x0表示后面负载内容为PAT,不同的PID表示不同的负载
    //adaption_field_control:
         // 0x0: // reserved for future use by ISO/IEC
         // 0x1: // 无调整字段,仅含有效负载  
         // 0x2: // 仅含调整字段,无有效负载
         // 0x3: // 调整字段后含有效负载
 
// Parse TS header
int  Parse_TS_header(unsigned char  *pTSBuf, TS_header *pheader)
{
     pheader->sync_byte                                     = pTSBuf[0];
     if  (pheader->sync_byte != 0x47)
         return  -1;
     pheader->transport_error_indicator       = pTSBuf[1] >> 7;
     pheader->payload_unit_start_indicator    = pTSBuf[1] >> 6 & 0x01;
     pheader->transport_priority             = pTSBuf[1] >> 5 & 0x01;
     pheader->PID                         = (pTSBuf[1] & 0x1F) << 8 | pTSBuf[2];
     pheader->transport_scrambling_control   = pTSBuf[3] >> 6;
     pheader->adaption_field_control         = pTSBuf[3] >> 4 & 0x03;
     pheader->continuity_counter            = pTSBuf[3] & 0x0F;
     return  0;
}

      TS包头解析需要参考:ISO/IEC 13818-1的2.4.3.2 Transport Stream packet layer

4.TS负载格式解析

4.1 PAT解析

   TS_header包头中的PID值为0x0,表示当前负载为PAT(Program Association Table)。PAT数据的信息可以理解为整个TS流包含的节目信息。

// Program Association Table
typedef  struct  PAT_Packet_tag
{
     unsigned table_id                        : 8; //固定为0x00 ,标志是该表是PAT
     unsigned section_syntax_indicator        : 1; //段语法标志位,固定为1
     unsigned zero                            : 1; //0
     unsigned reserved_1                      : 2; // 保留位
     unsigned section_length                  : 12; //表示有用的字节数,包括CRC32
     unsigned transport_stream_id             : 16; //该传输流的ID,区别于一个网络中其它多路复用的流
     unsigned reserved_2                      : 2; // 保留位
     unsigned version_number                  : 5; //范围0-31,表示PAT的版本号
     unsigned current_next_indicator          : 1; //发送的PAT是当前有效还是下一个PAT有效
     unsigned section_number                  : 8; //分段的号码。PAT可能分为多段传输,第一段为00,以后每个分段加1,最多可能有256个分段
     unsigned last_section_number             : 8; //最后一个分段的号码
     // for(i=0; i<N; i++)
     // {
     unsigned program_number                  : 16;
     unsigned reserved_3                      : 3;
     unsigned network_PID                     : 13;  // 或者program_map_PID
  // }
     unsigned CRC_32                          : 32;
} PAT_Packet;
 
// Parse PAT
int  Parse_PAT(unsigned char  *pTSBuf, PAT_Packet *packet)
{
     TS_header TSheader;
     if  (Parse_TS_packet_header(pTSBuf, &TSheader) != 0)
         return  -1;
     if  (TSheader.payload_unit_start_indicator == 0x01) // 表示含有PSI或者PES头
     {
         if  (TSheader.PID == 0x0)  // 表示PAT
         {
              int  iBeginlen = 4;
              int  adaptation_field_length = pTSBuf[4];
              switch (TSheader.adaption_field_control)
              {
              case  0x0:                                    // reserved for future use by ISO/IEC
                   return  -1;
              case  0x1:                                    // 无调整字段,仅含有效负载      
                   iBeginlen += pTSBuf[iBeginlen] + 1;  // + pointer_field
                   break ;
              case  0x2:                                     // 仅含调整字段,无有效负载
                   return  -1;
              case  0x3: // 调整字段后含有效负载
                  if  (adaptation_field_length > 0)
                  {
                       iBeginlen += 1;                   // adaptation_field_length占8位
                       iBeginlen += adaptation_field_length; // + adaptation_field_length
                  }
                  else
                  {
                       iBeginlen += 1;                       // adaptation_field_length占8位
                  }
                  iBeginlen += pTSBuf[iBeginlen] + 1;           // + pointer_field
                  break ;
             default :
                  break ;
             }
             unsigned char  *pPAT = pTSBuf + iBeginlen;
             packet->table_id                    = pPAT[0];
             packet->section_syntax_indicator    = pPAT[1] >> 7;
             packet->zero                        = pPAT[1] >> 6 & 0x1;
             packet->reserved_1                  = pPAT[1] >> 4 & 0x3;
             packet->section_length              = (pPAT[1] & 0x0F) << 8 |pPAT[2];
             packet->transport_stream_id         = pPAT[3] << 8 | pPAT[4];
             packet->reserved_2                  = pPAT[5] >> 6;
             packet->version_number              = pPAT[5] >> 1 &  0x1F;
             packet->current_next_indicator      = (pPAT[5] << 7) >> 7;
             packet->section_number              = pPAT[6];
             packet->last_section_number         = pPAT[7];
             int  len = 0;
             len = 3 + packet->section_length;
             packet->CRC_32                      = (pPAT[len-4] & 0x000000FF) << 24
                                                 | (pPAT[len-3] & 0x000000FF) << 16
                                                 | (pPAT[len-2] & 0x000000FF) << 8
                                                 | (pPAT[len-1] & 0x000000FF);
 
             int  n = 0;
             for  ( n = 0; n < (packet->section_length - 12); n += 4 )
             {
                  packet->program_number = pPAT[8 + n ] << 8 | pPAT[9 + n ];
                  packet->reserved_3                = pPAT[10 + n ] >> 5;
                  if  ( packet->program_number == 0x00)
                  {
                      packet->network_PID = (pPAT[10 + n ] & 0x1F) << 8 |pPAT[11 + n ];
                  }
                  else
                  {
                      // 有效的PMT的PID,然后通过这个PID值去查找PMT包
                      program_map_PID = (pPAT[10 + n] & 0x1F) << 8 |pPAT[11 + n];
                  }
             }
             return  0;
          }
     }
     return  -1;
}

  PAT数据解析需要参考:ISO/IEC 13818-1的2.4.4.3 Program Association Table

4.2 PMT解析

    由PAT包中的program_map_PID可以确定PMT(Program Map Table)的PID。PMT数据的信息可以理解为这个节目包含的音频和视频信息。 

   

// Program Map Table
typedef  struct  PMT_Packet_tag
{
      unsigned table_id                        : 8;
      unsigned section_syntax_indicator        : 1;
      unsigned zero                            : 1;
      unsigned reserved_1                      : 2;
      unsigned section_length                  : 12;
      unsigned program_number                  : 16;
      unsigned reserved_2                      : 2;
      unsigned version_number                  : 5;
      unsigned current_next_indicator          : 1;
      unsigned section_number                  : 8;
      unsigned last_section_number             : 8;
      unsigned reserved_3                      : 3;
      unsigned PCR_PID                         : 13;
      unsigned reserved_4                      : 4;
      unsigned program_info_length             : 12;
      // for(i=0; i<N; i++)
      // {
      unsigned stream_type                     : 8;
      unsigned reserved_5                      : 3;
      unsigned elementary_PID                  : 13;
      unsigned reserved_6                      : 4;
      unsigned ES_info_length                  : 12;
      // }
      unsigned CRC_32                          : 32;
} PMT_Packet;
    // Parse PMT
int  Parse_PMT(unsigned char  *pTSBuf, PMT_Packet *packet)
{
     // 参考Parse_PAT()来做就行了
     // ...
     
     return  0;
}

  PMT数据解析需要参考:ISO/IEC 13818-1的2.4.4.8 Program Map Table

4.3 PES解析

    根据文档参考PAT、PMT的解析流程就能完成PES的解析了。

    需要注意的是PES中PTS的解析,一般来说在90 kHz 中,PTS/9000的值为秒单位。

    

unsigned long  long  Parse_PTS(unsigned *pBuf)
{
      unsigned long  long  llpts = (((unsigned long  long )(pBuf[0] & 0x0E)) << 29)
          | (unsigned long  long )(pBuf[1] << 22)
          | (((unsigned long  long )(pBuf[2] & 0xFE)) << 14)
          | (unsigned long  long )(pBuf[3] << 7)
          | (unsigned long  long )(pBuf[4] >> 1);
      return  llpts;
}
PES结构详解
2013年08月05日  ⁄ 编程 ⁄ 共 1100字 ⁄ 评论数 2 ⁄ 被围观 3,562+

PES是Packetized Elementary Stream的简称,是将原始ES流打包后形成的,再将PES经过不同的打包方式可以组成MPEG program stream 和 MPEG transport stream,即PS流和TS流。

PES的组成结构如图,包括6个字节的包头字段,加上3个字节基本流信息字段,根据信息字段的设置可在之后附加其他字段。

<a href="http://www.yunlipiao.com/wp-content/uploads/2013/08/pes.jpg" class="cboxElement" rel="example4" 208"="" style="text-decoration: none; color: rgb(1, 150, 227);"> PES结构

PES结构

前三字节是包头起始标识字段,内容为0x000001

第四个字节是流ID字段,不同的流ID有不用的意义,如图,音频流ID范围从0xC0到0xDF,视频流ID范围从0xE0到0xEF。

PES流ID字段

PES流ID字段

第五六个字节是PES包长度,表示PES包头部在该字段之后的长度,单位是字节

接下来的第七八九字节是PES的扩展头部字段,用于设置流的基本信息,结构如图

PES可选扩展

PES可选扩展

第六字节的高两位是标识位,值为10b

第七字节的高两位是PTS和DTS指示位,00表示无PTS无DTS,01禁止使用,10表示PES头部字段会附加PTS结构

pts结构

pts结构

11表示PES头部字段会附加PTS和DTS结构

pts和dts结构

pts和dts结构

其中PTS和DTS使用的是90KHZ时钟单位,即1PTS表示1/90000秒,PTS和DTS虽然是33位,但占用了5个字节

ESCR FLAG字段设为1,会在头部附加6个字节的ESCR结构,ES RATE FLAG字段设置为1,会在头部附加3个字节ES rate结构,其他标识位如果设置为1也会相应的在头部附加对应字段。

ES rate结构

ES rate结构

ESCR结构

ESCR结构

 

本文地址:http://www.yunlipiao.com/208.html,出自云里飘博客,转载请保留链接

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ts文件格式解析 的相关文章

  • 工作上关于MySQL数据库备份与还原

    使用 mysqldump 备份数据库 默认该工具会将SQL语句信息导出至标准输出 可以通过重定向将输出保存至文件 1 备份所有的数据库 mysqldump u username ppassword all databases gt bak
  • 开机后提示no boot device detected解决方法

    我用华擎主板b360m pro4 为了提高CPU效率 打算设置BIOS提高风扇的转速 结果重启后出现提示 no boot device detected 我的硬盘是nvme的m 2 走pcie的固态硬盘 型号是建兴t10 plus 出现的原
  • Android Flutter Could not download kotlin.jar Kotlin-stdlib.jar

    原因就是无法下载包 1 科学 上网 去Google下载 2 配置阿里镜像 需要改动的地方 1 修改 工程build gradle 即 android build gradle buildscript repositories maven u
  • 文件服务器事件id8193,执行备份时的事件 ID 8193 - Windows Server

    VSS 错误 XML 文档太长 hr 0x80070018中执行备份时出现 Windows 09 17 2020 本文内容 本文提供了一种解决在备份过程中执行备份时Windows 适用于 Windows 10 所有版本 Windows Se
  • 华为OD机试真题-开心消消乐【2023.Q1】

    题目描述 给定一个N行M列的二维矩阵 矩阵中每个位置的数字取值为0或1 矩阵示例如 1100 0001 0011 1111 现需要将矩阵中所有的1进行反转为0 规则如下 1 当点击一个1时 该1便被反转为0 同时相邻的上 下 左 右 以及左
  • Net跨平台UI框架Avalonia入门-资源和样式

    Net跨平台UI框架Avalonia入门 资源和样式编写和使用 资源和样式编写和使用 样式 Styles 和资源 Resources 样式 Styles 样式定义 定义的位置 定义内容 样式文件的定义和引用 资源 Resources 资源的
  • Android VLC播放器二次开发3——音乐播放(歌曲列表+歌词同步滚动)

    今天讲一下对VLC播放器音频播放功能进行二次开发 讲解如何改造音乐播放相关功能 最近一直在忙着优化视频解码部分代码 因为我的视频播放器需要在一台主频比较低的机器上跑 800M主频 所以视频解码能力受到极大考验 VLC的解码库挺复杂 花了两三
  • Android 架构设计的思想与原则是什么?

    http www zhihu com question 19717380
  • JAVA中常见的异常

    Java 中的异常在 Java 程序中是以类的形式体现的 在 java 中每个包下都有专门的异常类 1 java lang NullPointerException 空指针异常 2 java lang ArrayIndexOutOfBoun
  • 人脸识别学习总结

    对人脸识别算法进行了一定程度的学习 从最开始的特征脸到如今的CNN人脸检测 有了较为全面的了解 重点掌握了基于PCA的特征脸检测 LDA线性判别分析 Fisher线性判别 以及基于级联器的Haar特征 LBP特征的人脸检测算法 人脸检测的学
  • asp二进制mysql_asP 读取二进制数据库

    OleContainer操作Excel以二进制方式读写数据库 需求源头 OleContainer操作Excel 想把Excel以二进制方式存入数据库 并且以二进制方式读取存入流 Procedure SaveToStream ADOTable
  • C++ String 类常用函数

    string类的构造函数 string const char s 用c字符串s初始化 string int n char c 用n个字符c初始化 此外 string类还支持默认构造函数和复制构造函数 如string s1 string s2
  • 【前端】JavaScript构造函数

    文章目录 概念 执行过程 返回值 原型与constructor 继承方式 原型链 其他继承方式 还没写 参考 概念 在JS中 通过new来实例化对象的函数叫构造函数 实例化对象 也就是初始化一个实例对象 构造函数一般首字母大写 构造函数的目
  • 赏析

    2017年秀H5赏析 排名不分先后 尽可能多得挑选了不同展现形式 或是不同行业的案例 点击相应的图片即可查看案例 本文适合手机端浏览 人 工 智 能 类 点击图片进入案例 美图秀秀 妙啊 史上最奇妙的圣诞祝福 点评 这个特别好玩 任意上传一
  • Jar的远程调试【java的远程调试Debug】

    什么是远程调试 什么是远程调试 我们使用IDEA本地的时候运行可以打本地的Debug 但是若我们的服务在线上呢 我们的服务部署到了服务器上面 比如服务器的IP为 127 0 0 1接下来我们开始远程调试 Jar包的启动命令 前面一直到 ja

随机推荐

  • 数据挖掘算法总结

    原文链接 http qing blog sina com cn tj 591d4f4933002uc9 html 数据挖掘的算法有很多种 我们经常会疑虑到底用哪种方法最合适 所以专门收集了常见的数据挖掘算法 让大家有一个总体的了解 一 聚类
  • Anaconda详细安装教程!!

    1 Anaconda下载 方法一 官网安装 直接点击Download即可 可自行选择Windows 64位或32位的版本进行下载 方法二 可以选择清华大学开源软件镜像站下载 2 详细安装步骤 1 双击完成后的安装包 2 点击Next 3 点
  • 查看通过Windows凭证查看浏览器保存的密码

    1 打开控制面板 2 打开凭据管理器
  • 贝叶斯优化神经网络参数_贝叶斯超参数优化:神经网络,TensorFlow,相预测示例

    贝叶斯优化神经网络参数 The purpose of this work is to optimize the neural network model hyper parameters to estimate facies classes
  • SpringBoot整合Redis

    要在Spring Boot中整合Redis 可以按照以下步骤进行操作 一 在pom xml文件中添加Redis的依赖
  • 轻舟已过万重山

    罗翔说 其实没什么好后悔的 很多事就算时间能重来一遍 以当时的心智和阅历 还是会做同样的选择 避免不了同样的结果 人本来就是在失败中学乖的 与其抱着过去后悔 不如擦擦眼泪向前走吧 我时常在想 我是过了365天 还是把一天过了365遍 这种一
  • 修改bug的一个小故事

    今天在网站上看见一个故事 很有趣 但也值得思考 那还是80年代初期 我爸爸在一家存储设备公司工作 这个公司现在已经不存在了 它生产磁带机和驱动这些磁带高速运转的气动系统 这是那个时代的产物 他们技术改造了磁带驱动器 使得你可以只有一个中心驱
  • HAProxy--理论--01--简介

    HAProxy 理论 01 简介 1 HAProxy 是一款提供高可用性 负载均衡以及基于TCP 第四层 和HTTP 第七层 应用的代理软件 支持虚拟主机 它是免费的 适用于那些负载特大的web站点 这些站点通常又需要会话保持或七层处理 H
  • 模拟实现strchar函数

    strchar 查找字符串 s 中首次出现字符 c 的位置 函数实现 char my strchar const char str char c assert str while str if str c return str else s
  • STL(二) map容器插入、删除小技巧

    这里写目录标题 STL 二 map容器插入 删除小技巧 一 map插入 1 用数组方式插入数据 2 在insert函数中使用make pair 函数 3 插入前先查找该key值 是否已存在 4 insert or assign直接插入 如果
  • VueJS 中的动画菜单效果的实现

    英文 https mattmaribojoc medium com animated active menu highlights in vuejs daily vue tips 1 accd47fac612 最近 我在写一个项目 我想要一
  • 解决springboot2.x集成redis节点故障redisTemplate报错redis Command timed out

    pringboot2 x集成redis redis节点故障 集群状态ok的情况下 程序使用redisTemplate操作redis一直报错 Redis command timed out nested exception is io let
  • 若依框架注册功能的实现并且给分配菜单可见菜单权限

    前端设置 打开 ruoyi ui 模块 然后 找到 views 文件夹 然后找到 login vue 文件 在 94 行左右的位置 找到 register 属性 将其从 false 改为 true 后端设置 找到数据库中的sys confi
  • flutter mac 环境变量配置

    open bash profile export FLUTTER ROOT Applications flutter export PUB HOSTED URL https pub flutter io cn export FLUTTER
  • MySQL数据库基础知识9,InnoDB和MyISAM的数据分布对比

    目录 一 InnoDB存储引擎 二 MyISAM存储引擎 1 MyISAM简介 2 MyISAM压缩表 三 InnoDB的数据分布 四 MyISAM数据分布 五 顺序的主键什么时候会造成更坏的结果 MySQL进阶实战系列文章 哪吒精品系列文
  • Jupyter notebook项目文件默认路径更改(win10,Anaconda)

    Jupyter notebook项目文件默认路径更改 问题描述 解决方法 参考 问题描述 在jupyter notebook中 其默认文件路径是保存在C盘的C Users xxx路径当中 这会导致入门小白被jupyter中许多文件夹搞得云里
  • matlab如何提取某一列的数据_MATLAB如何提取某一矩阵的某一列的部分数据?

    展开全部 使用2113a M N 可以提取矩阵a中符合5261M 4102N要求的部分 最简单1653是M N都是标量 就是一回个数例如 答 a 1 1 a 2 3 分别返回a矩阵1行1列的单元 和 2行3列的单元 M N还可以是矢量 例如
  • C++11实用技术(四)for循环该怎么写

    普通用法 在C 遍历stl容器的方法通常是 include
  • ubuntu使用systemd设置开机启动

    title ubuntu使用systemd设置开机启动 date 2021 11 17 18 57 11 tag ubuntu categories Ubuntu System 在项目过程中 经常会碰到需要设置开机启动脚本 以下将介绍使用s
  • ts文件格式解析

    TS格式解析 by ahuner 1 TS格式介绍 TS 全称为MPEG2 TS TS即 Transport Stream 的缩写 它是分包发送的 每一个包长为188字节 还有192和204个字节的包 包的结构为 包头为4个字节 第一个字节