ts 流基础(白话讲解).

2023-11-20

----------------------------------------
author: hjjdebug
date:     2022年 09月 27日 星期二
----------------------------------------

ts 流就是188个字节构成的流数据.
先来点最简单的. ts 头部,4字节
ts 流是47开头的,以188字节为单位的打包流,由4字节包头及包体构成.
4字节第一个4字节为47.第2,3个字节为包id,占低位13个bit,故最多8192个包id, 第4各字节是计数器占低4bit.
包ID 是标明包身份的,以后慢慢会熟悉起来,连续计数器是用来判断是否有丢包的,正常同id的包是依次向上加1.
这就是最基本的认知了

要想搞清头部,再说说第2byte的前3bit,
最高位bit7, error bit, 表示该包是否出错,出错当然应该扔掉了.
次高位bit6, 叫syntax_indicatior, 该位以后会讲到,不同的包类型会对它分别置0或置1.
bit5, 是表示该包的重要性的.
再说说第4byte 的高4bit,
最高2bit是加扰控制, 00为未加扰,其它用户定义
次2bit为适配域,00:保留,01:无适配域有负载,10:有适配域无负载,11:有适配域有负载

于是用c语言可以定义出下面一个结构: ts_header
typedef struct
{
    uint8_t sync_byte; /*0x47*/
    uint16_t transport_error_indicator : 1;
    uint16_t payload_unit_start_indicator : 1;        //负载开始标记
    uint16_t transport_priority : 1;
    uint16_t PID : 13;
    uint8_t transport_scrambling_control : 2;
    uint8_t adaptation_field_control : 2;
    uint8_t continuity_counter : 4;  
} __attribute__((packed)) ts_header;
第5个字节是适配域长度,然后后边的字节是适配域. 无适配域此值为0.
至于适配域都包含什么内容,以后再说. 先说无适配域的情况。从第6个字节开始。

要想播出节目,ts流中除了要包含音频流,视频流这些基础流外,还要包含其它一些信息。
这些信息专业名词叫PSI/SI, (节目专有信息/服务信息),
那么什么是节目专有信息呢(program specific information)?
PAT,PMT,CAT,NIT这4个表是节目专有信息 , 节目播放所必须
服务信息是由其它表构成的,例如SDT,EIT,TDT等,这些是附加信息。

各种表一般都对应的是一个table表头,后面是表体.
table表头由1byte tableid,及2bytes 长度构成,长度占低12位,意味着表不会超过4K大小
后边的数据归入本表.
那长度前面的4bit 又是什么意思呢? 用途不大,看后面定义. 这样讲清了table表的前3byte
长度之后的后5bytes分别是扩展表id 2byte,version_number,section_number,last_section_number
版本号 version_number 的意思是,以pat表为例,当pat表变化时, version_number 会改变
section_number,last_section_number 用来表达pat 表是否已经被收完整了. 这样就占掉了8个字节
后面的数据用表体来解释.


用c可如下定义了table_header
struct table_header
{
    uint8_t table_id;
    uint16_t section_syntax_indicator : 1;        //格式标记,pat,pmt 都为1,标记section 开始?
    uint16_t private_bit : 1;
    uint16_t reserved : 2;
    uint16_t section_length : 12;                //节的长度
    uint16_t table_id_ext;                        //扩展的id
    uint8_t reserved1 : 2;
    uint8_t version_number : 5;                    //版本号
    uint8_t current_next_indicator : 1;            //当前,下一个标记
    uint8_t section_number;                        // 节号及最后的节号
    uint8_t last_section_number;                //对应到流中的字节,后面除crc外,只在内存中存在
};

还好,这些表头的格式各种表是一致的
开头8bytes, tableID(1)+len(2)+表头(5),及crcbyte, 中间为表体.

--------------------------------------------------------
那么什么是PAT呢?(pragram association table) 节目关联表.
--------------------------------------------------------
这个表用来描述ts流中由几套节目,节目的pmt_id 是多少.
这个表的13bits pid 固定为0,8bits tableID 固定为0,播放节目都是从搜pat开始的。
前面20个pid 都是被固定分配好的,都成标准了,不能随便定义了,这里先介绍pid固定为0的pat
ts 流中可能有一套节目,也可能有多套节目。
这个pat表头就是从第6byte 开始的. 当然pmt表头也是从第6字节开始.此为后话。
从第6字节开始,

我们给一个实例分析:
47 40 00 10 00 00 B0 0D 00 01 C1 00 00 00 01 F0
00 2A B1 04 B2

47 40 00 10:
47 同步头
40 00: 13bitpid 为0, 前面3bit代表

:transport_error_indicatior(1),payload_unit_start(1),transport_priority(1)

第4byte含义trasport_scramling(2),adaption_field_ctrol(2),continuity_counter(4)
10: 不加扰,有负载,计数值为0
00 适配域长度为0

下面就是pat表数据了

其数据结构定义如下:

PAT数据结构
program_association_section()
{
    table_id;//8位固定为0x00,表示该表是PAT表
    section_syntax_indicator;//1,段语法标志位,固定为1
    '0';//1,固定为0 为了防止和ISO13818Video流格式中的控制字冲突而设置的
    reserved;//2,保留位,一般都是1,这样前4位就是B
    section_length;//12,段的大小,表示这个字节后面有用的字节数,包括CRC32.假如后面的字节加上前面的字节数少于188,后面会用0xFF填充,假如这个数值比较大,则PAT会分成几部分来传输。
    transport_stream_id;//16该传输流的ID,区别于一个网络中其他多路复用的流
    reserved;//2
    version_number;//5,范围0-31,表示PAT的版本号,标注当前节目的版本,这是个非常有用的参数,当检测到这个字段改变时,说明TS流中的节目已经改变了,程序必须重新收索节目
    current_next_indicator;//1,表示发送的PAT是当前有效还是下一个PAT有效
    section_number;//8,分段的号码,PAT可能分为多个段传输,第一段为00,以后每个分段加1,最大可能有256个分段
    last_section_number;//8,最后一个分段的号码
    for(i=0;i<N;i++)
    {
        program_number;//16,节目号
        reserved;//3
        if(program_number=='0')
        {
            network_PID;//13,网络信息表(NIT)的PID,网络信息表提供了该物理网络的一些信息,和电视台相关的,
        }
        else
        {
            program_map_PID//13,节目映射表的PID,节目号大于0时对应的PID,每个节目对应一个
        }
        CRC_32;//32,CRC32校验码
    }
}

下面来分析具体数据:

00 B0 0D:
00 tableid
B0 0D: 数据长度12bits,B的含义'1011' 必需要这样写,代表section_syntax_indicator 为1,保留位11
00 01 c1 00 00: 5数据解释,扩展id及3个number
00 01 是扩展id, 也有叫transport_stream_id?
c1 是,reserved1(2bit),version_number(5)=0, current_next_indicator((1)
00 00, section_number 和last_section_number 都是0,在本节就把表数据表示完了.

循环体数据从pat偏移8字节开始,每4bytes为1组

00 01 F0 00
前16个bit为节目号,后13bit 为pmt_pid, 当节目号为0时, 后13bit 时nit pid, 本码流没有nit信息
此时的pmt_pid为0x1000

我看到有人写代码, 当判定是PAT表时(PID=0),直接从buffer[15],buffer[16]拿PMT的PID, 真是简单直接啊,省掉了一大堆没有啥用途的东西!. PAT主要就是干这个的.

2A B1 04 B2: 为crc32
讲清了pat, 再来看什么是pmt
--------------------------------------------------------
什么是PMT(pragram mat table) 节目映射表
--------------------------------------------------------
回顾pat 它告诉了我们有几套节目,每套节目的pmt表id是多少.
pmt 会告诉我们该套节目包含哪些基础流,及基础流的相关信息. lets go!

其数据结构定义如下:

PMT数据结构:

TS_program_map_section()
{
    table_id; // 8 固定为0x02,表示该表是PMT
    section_syntax_indicator; //1 段语法标志位,固定为1
    '0';//1
    reserved;//2
    section_length; //12 表示这个字节后面有用的字节数,包括CRC32。假如后面的字节加上前面的字节数少于188,后面会用0XFF填充。假如这个数值比较大,则PMT会分成几部分来传输。
    program_number; //16 节目号,表示该PMT对应的节目号
    reserved;// 2
    version_number; //5范围0-31,表示PMT的版本号,标注当前节目的版本,这是个非常有用的参数,当检测到这个字段改变时,说明TS流中的节目已经改变了,程序必须重新收索节目
    current_next_indicator;//1表示发送的PMT是当前有效还是下一个PAT有效
    section_number; // 8 分段的号码固定为0x00
    last_section_number;//8最后分段的号码 固定为0x00
    reserved;//3
    PCR_PID; //13 PCR(节目时钟参考)所在TS分组的PID,根据PID可以去搜索相应的TS分组,解出PCR信息。
    reserved; //4
    program_info_length; //12该节目的信息长度,在此字段之后可能会有一些字节描述该节目的信息
    for (i=0; i<N; i++)
    {
        descriptor();
    }
    for (i=0;i<N1;i++)
    {
        stream_type;//8 指示了PID为elementary_PID的PES分组中原始流的类型,比如视频流,音频流等
        reserved; //3
        elementary_PID;//13 该节目中包括的视频流,音频流等对应的TS分组的PID
        reserved; //4
        ES_info_length;//12 该节目相关原始流的描述符的信息长度
        for (i=0; i<N2; i++)
        {
            descriptor();
        }
    }
}

上个例子数据吧.
47 50 00 10 00 02 B0 1D 00 01 C1 00 00 E1 00 F0
00 1B E1 00 F0 00 0F E1 01 F0 06 0A 04 65 6E 67
00 8D 82 9A 07
//有了上面的基础,下面拣重要的叙述
47 50 00 10: pid 是0x1000, pmt pid
00 : 适配域长度为0
02 B0 1D: tableid 02, 长度0x1d, 正好把数据分完 ,  PMT_TID = 0x02  buffer[7]是loop 长度
00 01 c1 00 00: 扩展id 2bytes,,这里的扩展id实际是节目号, version号0,current_next_indicator(1), sec_num:00, last_sec_num:00,一个表搞定.
最末4byte为crc, 中间为私有数据
E1 00 : 低13bits 是PCR_PID = 0x100                有人直接从buffer[13],buffer[14]取PCR_PID
F0 00 : 低12bits 是节目信息长度,为0                buffer[15],buffer[16]为额外信息长度,可以跳过
然后进入循环体:

1B : 流类型, H.264/14496-10 video (MPEG-4/AVC)  (0x1B,0x02 都是视频流)
E1 00 : 低13bit 为基础流id = 0x100
F0 00 : 低12bit 为描述符长度 = 0

0F : 流类型 ,     STEAM_TYPE_ADTS_AUDIO = 0x0F,  (0x03,0x04,0x06,0x0F都是音频流)
E1 01 : 基础流id=0x101
F0 06 : 描述符长度为6,
0A 04 65 6E 67 00

0A 是一个标签,代表语言 _(ISO_639_language, 0x0A)
04 为标签长度,后面是描述字符串. "eng" 代表英文

有了这两个表,就可以找到基础流了,至于其它表例如sdt等,告诉你节目叫什么名字等,并不是必需的,但有时也是需要的


参考: 1. tsanalyse     代码(github)
参考: 2. tsinfo     代码(ubuntu source)
参考: 3. ISO/IEC 13818-1 标准

参考图1:pat 表

 参考图2: pmt 表

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

ts 流基础(白话讲解). 的相关文章

  • 交换机与路由器技术-35-端口多路复用PAT

    目录 一 端口多路复用 PAT 1 1 概述 1 2 端口映射 服务器映射 1 3 配置端口多路复用 1 3 1 方式一 使用单独的公网IP 第一步 定义内网和外网接口 第二步 定义内网地址范围 外网地址 1 使用ACL 允许某个范围的内网
  • PAT乙级1074. 宇宙无敌加法器(C语言)

    PAT乙级真题题解目录 可回顾 1048 数字加密 都涉及使数字位数一致 1 不同位数的PAT数之间如何方便相加 构造相同大小的字符数组 按位数存储对应的数字 2 相加时转为数字进行运算 3 结果为0 为特殊情况 单独写输出代码 inclu
  • ts项目打包报错 error TS6504: xxxxxx is a JavaScript file. Did you mean to enable the ‘allowJs‘ option?

    项目vue3 ts 打包时一个组件如下错误 解决 加上lang
  • 【报错】onMounted is called when there is no active component instance too be associated with.

    文章目录 报错 分析 解决 报错 onMounted is called when there is no active component instance too be associated with Lifecycle injecti
  • 1012 数字分类

    1012 数字分类 题目 输入格式 输入样例 输出样例 代码 小结 题目 给定一系列正整数 请按要求对数字进行分类 并输出以下 5 个数字 A 1
  • L1-029. 是不是太胖了

    据说一个人的标准体重应该是其身高 单位 厘米 减去100 再乘以0 9所得到的公斤数 已知市斤是公斤的两倍 现给定某人身高 请你计算其标准体重应该是多少 顺便也悄悄给自己算一下吧 输入格式 输入第一行给出一个正整数H 100 lt H lt
  • Vue3头像(Avatar)

    效果如下图 在线预览 APIs 参数 说明 类型 默认值 必传 shape 指定头像的形状 circle square circle false size 设置头像的大小 number large small default Respons
  • 1033 旧键盘打字 (20分)

    这道题很坑的一点就是 有可能坏掉的键盘是空串 所有的键都是好的 如下测试用例 input NULL abcdefg output abcdefg 所以 用字符串数组的不能直接用scanf s str 读入 用string的也不能直接用cin
  • PAT乙级题解—— 1071 小赌怡情 (15分)

    常言道 小赌怡情 这是一个很简单的小游戏 首先由计算机给出第一个整数 然后玩家下注赌第二个整数将会比第一个数大还是小 玩家下注 t 个筹码后 计算机给出第二个数 若玩家猜对了 则系统奖励玩家 t 个筹码 否则扣除玩家 t 个筹码 注意 玩家
  • TypeScript的类型推导

    TypeScript 简称ts 是一种静态类型的编程语言 在类型检查和类型推导方面具有一定的优势 类型推导是TypeScript在代码编写的过程中自动识别并设置变量类型 从而提高代码的可读性和健壮性 减少了代码中潜在的错误 在 TypeSc
  • 1074 Reversing Linked List (25 point(s))

    1074 Reversing Linked List 25 point s Given a constant K and a singly linked list L you are supposed to reverse the link
  • TypeScript笔记

    数据基础类型定义 let username string 管理员 username 系统管理员 模板字符串 使用反引号 let describe string 今天天气 weather sencence方式 let info string
  • 【PAT乙级】旧键盘打字

    题目描述 旧键盘上坏了几个键 于是在敲一段文字的时候 对应的字符就不会出现 现在给出应该输入的一段文字 以及坏掉的那些键 打出的结果文字会是怎样 输入格式 输入在 2 行中分别给出坏掉的那些键 以及应该输入的文字 其中对应英文字母的坏键以大
  • 1001 害死人不偿命的(3n+1)猜想 (15 分)

    1001 害死人不偿命的 3n 1 猜想 15 分 卡拉兹 Callatz 猜想 对任何一个正整数 n 如果它是偶数 那么把它砍掉一半 如果它是奇数 那么把 3n 1 砍掉一半 这样一直反复砍下去 最后一定在某一步得到 n 1 卡拉兹在 1
  • vue3+ts实现todolist功能

    先看一下实现效果 可以看到内部实现的内容有enter输入 单项删除 全选 以及删除选中项等功能 具体在实现前需要常见有ts的vue3项目 项目创建 具体项目创建 就是 vue create 项目名称 在创建后 选择的时候有vue2和vue3
  • pat 乙级 1015. 德才论 (25) c++

    http 39 106 25 239 个人网站 欢迎访问 交流 1015 德才论 25 时间限制 200 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN Li 宋代史学家司马光在 资
  • 8-0. 查找整数(10)

    本题要求从输入的N个整数中查找给定的X 如果找到 输出X的位置 从0开始数 如果没有找到 输出 Not Found 输入格式 输入在第1行中给出2个正整数N lt 20 和X 第2行给出N个整数 数字均不超过长整型 其间以空格分隔 输出格式
  • 【Umi+Antd+Ts实战】新增商品弹框组件【V1.0】

    新增商品弹框组件 先看效果 1 点击 符号 弹出新增商品组件 路由配置可以参考下面博客 https blog csdn net weixin 43352901 article details 108536112 2 新增商品弹框内容 文件目
  • TS装饰器

    一 定义 装饰器本质是一种函数 通过添加标注的方式 对数据 类 方法 属性 参数等 的功能进行增加或者修改 二 使用 准备工作 ts config json文件中 1 基础使用 装饰器名字 例子 function test target a
  • ts 流基础(白话讲解).

    author hjjdebug date 2022年 09月 27日 星期二 ts 流就是188个字节构成的流数据 先来点最简单的 ts 头部 4字节 ts 流是47开头的 以188字节为单位的打包流 由4字节包头及包体构成 4字节第一个4

随机推荐

  • Prim算法解决修路问题

    普里姆算法 Prim算法 图论中的一种算法 可在加权连通图里搜索最小生成树 意即由此算法搜索到的边子集所构成的树中 不但包括了连通图里的所有顶点 英语 Vertex graph theory 且其所有边的权值之和亦为最小 普里姆算法和Kru
  • storm集成kafka简单使用示例2

    StormKafkaTopo java package stormUse stormUse import java util Properties import org apache storm Config import org apac
  • 9.2 单片机上下拉电阻

    前边似乎我们很多次提到了上拉电阻 下拉电阻 具体到底什么样的电阻算是上下拉电阻 上下拉电阻都有何作用呢 上拉电阻就是将不确定的信号通过一个电阻拉到高电平 同时此电阻也起到一个限流作用 下拉就是下拉到低电平
  • app id(wildcard ID和explicit ID)

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 最近做ios游戏的平台相关的工作 平台商要求把我们产品的bundle id加上他们的标记 比如我们的bundle id叫 com lc test 如果我上CSDN的平台 就
  • CleanMyMac X4.14.1苹果Mac电脑系统最好用的系统清理工具

    macOS 平台的知名系统清理应用 CleanMyMac 在经历了一段时间的beta测试后 全新设计的 CleanMyMac X 正式上线 与 CleanMyMac3相比 新版本的 UI 设计焕然一新 采用了完全不同的风格 除了设计上的变化
  • gdb attach 方法

    第一步 获得正在运行的进程的进程号 程序编译时要有 g参数 第二步 gdb attach 根据上一步获得进程号 现在attach上去 此处可stop暂停程序 第三步 打断点 gdb有两种打断点的方式 b 行号 如果是当前文件 则直接加上行号
  • 用wordpress编辑网站使页面中的图片全屏展示和全屏轮播展示

    在利用wordpress建立网站中 页面中的bannner图如何使其全屏展示以及如何添加轮播图 一 页面中的图片如何设置为全屏图片展示 操作步骤如下 1 打开网站的后台 点击 页面 选择所有页面 如图所示 2 选择相应的页面 点击 使用El
  • nacos简易实现负载均衡

    目录 一 什么是Nacos 二 Nacos下载和安装 1 使用Windows启动 2 验证nacos是否成功启动 三 Nacos Discovery服务注册 发现 四 简易实现负载均衡 1 注册者配置 2 注册者启动类 3 注册者业务层 4
  • 数组添加进formdata_FormData使用方法详解

    FormData的主要用途有两个 1 将form表单元素的name与value进行组合 实现表单数据的序列化 从而减少表单元素的拼接 提高工作效率 2 异步上传文件 一 创建formData对象 1 创建一个空对象 通过FormData构造
  • Linux命令_sort & 排序、去重

    目录 1 语法 1 1 常用参数 2 常见用法 2 1 按数值排序 2 2 按文件大小排序 2 3 指定某一列排序 2 4 去重后排序 2 5 生成随机数 2 6 同时查看多个文件 2 7 排序后的值写入文件 可直接修改文件 1 语法 so
  • 如何使用区块链技术保护个人隐私和数据安全

    区块链技术是一种分布式账本技术 它具有不可篡改 去中心化 透明度高等特点 区块链技术能够实现数据的可信存证 隐私保护和交易安全 并且能够通过智能合约的自动执行 因此被广泛应用于金融 电商 物流 社交网络等领域 区块链技术的核心是 分布式账本
  • Go语言List的使用与数据结构的选择

    container包下的函数 heap heap包提供了对任意类型 实现了heap Interface接口 的堆操作 list list包实现了双向链表 ring ring实现了环形链表的操作 一 List的使用 List列表是一种非连续存
  • JAVA多线程执行,等待返回结果,再执行

    JAVA多线程执行 等待返回结果 再执行 1 实现callable接口 1 配置线程池 package com neusoft demo server config import org springframework context an
  • 简单了解InnoDB底层原理

    存储引擎 很多文章都是直接开始介绍有哪些存储引擎 并没有去介绍存储引擎本身 那么究竟什么是存储引擎 不知道大家有没有想过 MySQL是如何存储我们丢进去的数据的 其实存储引擎也很简单 我认为就是一种存储解决方案 实现了新增数据 更新数据和建
  • 步进电机与直流电机(有刷无刷)的优缺点,与伺服电机区别

    1 步进 有刷 无刷小型电机的区别 记住这张表 参考 特性 的特点 2 一文看懂有刷 无刷电机 步进电机基础知识 3 步进电机与直流电机的优缺点 与伺服电机区别 伺服与控制 电子发烧友网 4 有刷电机 VS 无刷电机 看看哪个更厉害 5 2
  • Jmeter性能测试1

    性能测试的概述 性能 百度百科定义 器物的性质与效用 生活中 买手机 买电脑 买车 性能好 快 时间短 资源 软件的性能 软件在允许的过程中反应的速度 时间 消耗的资源的情况等等 性能测试 是通过自动化测试工具模拟多种正常 峰值 以及异常负
  • 【数据分析入门】Jupyter Notebook

    目录 一 保存 加载 二 适用多种编程语言 三 编写代码与文本 3 1 编辑单元格 3 2 插入单元格 3 3 运行单元格 3 4 查看单元格 四 Widgets 五 帮助 Jupyter Notebook是基于网页的用于交互计算的应用程序
  • Exception Oracle Error

    Exception Oracle Error SQLCODE Value ACCESS INTO NULL ORA 06530 6530 CASE NOT FOUND ORA 06592 6592 COLLECTION IS NULL OR
  • CRC校验(二)

    CRC校验 二 参考 https blog csdn net liyuanbhu article details 7882789 https www cnblogs com esestt archive 2007 08 09 848856
  • ts 流基础(白话讲解).

    author hjjdebug date 2022年 09月 27日 星期二 ts 流就是188个字节构成的流数据 先来点最简单的 ts 头部 4字节 ts 流是47开头的 以188字节为单位的打包流 由4字节包头及包体构成 4字节第一个4