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 流基础(白话讲解). 的相关文章

  • 分支-20. 计算符号函数的值(10)

    对于任一整数n 符号函数sign n 的定义如下 请编写程序计算该函数对任一输入整数的值 输入格式 输入在一行中给出整数n 输出格式 在一行中按照格式 sign n 函数值 输出该整数n对应的函数值 输入样例 1 10 输出样例 1 sig
  • ts项目打包报错 error TS6504: xxxxxx is a JavaScript file. Did you mean to enable the ‘allowJs‘ option?

    项目vue3 ts 打包时一个组件如下错误 解决 加上lang
  • TypeScript中数组类型的定义

    TypeScript中数组类型的定义 现在我们可以定义一个最简单的数组类型 比如就是数字类型 那么就可以这么写 const numberArr 1 2 3 这时候你把鼠标放在numberArr上面可以看出 这个数组的类型就是 number
  • 1041. 考试座位号(15)

    每个PAT考生在参加考试时都会被分配两个座位号 一个是试机座位 一个是考试座位 正常情况下 考生在入场时先得到试机座位号码 入座进入试机状态后 系统会显示该考生的考试座位号码 考试时考生需要换到考试座位就座 但有些考生迟到了 试机已经结束
  • 【ts】数组、联合数据类型、类型推论

    一 ts约束数组 1变量 类型 let arr Number 1 3 3 4 arr push 1 arr push he 不能添加数组中没有约束的类型 2 数组泛型 变量 Array lt 类型 gt let arr Array
  • VSCode 中,TS 提示 ”无法找到 *.vue 声明文件“ 的解决方案

    在使用 VSCode 开发 Vue3 TS 项目时 编辑器一直有一个报错 因为不影响编译和运行 所以就一直没在意 但这两天看着这红杠提示实在是太别扭 今天就来解决一下这个问题 还自己一个清爽的开发环境 在网上查找了很多资料 靠谱的不好找 但
  • TypeScript中的泛型(泛型函数、接口、类、泛型约束)

    一 泛型函数 TypeScript泛型是一种可以使代码具有更高的可重用性和泛化能力的特性 通过泛型 我们可以定义一种通用的类型或函数 使其能够应对多种类型的输入 泛型在类 函数 接口等多种场景下都可以使用 具体来说 在定义泛型函数时 我们可
  • PAT-1059 C语言竞赛

    1059 C语言竞赛 20 分 C 语言竞赛是浙江大学计算机学院主持的一个欢乐的竞赛 既然竞赛主旨是为了好玩 颁奖规则也就制定得很滑稽 0 冠军将赢得一份 神秘大奖 比如很巨大的一本学生研究论文集 1 排名为素数的学生将赢得最好的奖品 小黄
  • PAT : PAT (Basic Level) Practice(中文)答案(1001 ~ 1095)(纯C编写)

    题目集地址 报名了12月的PAT B 先试试水 已完成 2018 10 22 2018 11 14 更新 2018 12 09 PAT乙级考试100分 考试代码已更新 冬天坐火车跑去考试冻懵了 来年对战PAT甲级考试 目录 目录 题目集地址
  • 1012 数字分类

    1012 数字分类 题目 输入格式 输入样例 输出样例 代码 小结 题目 给定一系列正整数 请按要求对数字进行分类 并输出以下 5 个数字 A 1
  • 【PAT甲级A1125】 Chain the Ropes (25分)(c++)

    1125 Chain the Ropes 25分 作者 CHEN Yue 单位 浙江大学 代码长度限制 16 KB 时间限制 200 ms 内存限制 64 MB Given some segments of rope you are sup
  • PAT B1016 部分A+B (15 分)(C语言实现)

    PAT B1016 部分A B 15 分 C语言实现 问题描述 正整数 A 的 D A 为 1 位整数 部分 定义为由 A 中所有 D A 组成的新整数 P A 例如 给定 A 3862767 D A 6 则 A 的 6 部分 P A 是
  • PAT 1018 锤子剪刀布 (20分)

    1018 锤子剪刀布 20分 大家应该都会玩 锤子剪刀布 的游戏 两人同时给出手势 胜负规则如图所示 现给出两人的交锋记录 请统计双方的胜 平 负次数 并且给出双方分别出什么手势的胜算最大 输入格式 输入第 1 行给出正整数 N 10 5
  • 1033 旧键盘打字 (20分)

    这道题很坑的一点就是 有可能坏掉的键盘是空串 所有的键都是好的 如下测试用例 input NULL abcdefg output abcdefg 所以 用字符串数组的不能直接用scanf s str 读入 用string的也不能直接用cin
  • 1063. 计算谱半径(20)

    在数学中 矩阵的 谱半径 是指其特征值的模集合的上确界 换言之 对于给定的n个复数空间的特征值 a1 b1i an bni 它们的模为实部与虚部的平方和的开方 而 谱半径 就是最大模 现在给定一些复数空间的特征值 请你计算并输出这些特征值的
  • 【PAT乙级】旧键盘打字

    题目描述 旧键盘上坏了几个键 于是在敲一段文字的时候 对应的字符就不会出现 现在给出应该输入的一段文字 以及坏掉的那些键 打出的结果文字会是怎样 输入格式 输入在 2 行中分别给出坏掉的那些键 以及应该输入的文字 其中对应英文字母的坏键以大
  • PAT甲级刷题:模拟(不断更新)

    目录 1001 A B Format 1005 Spell It Right 1035 Password 1061 Dating 18 20 1073 Scientific Notation 16 20 1077 Kuchiguse 17
  • 1055. 集体照 (25) PAT乙级真题

    1055 集体照 25 拍集体照时队形很重要 这里对给定的N个人K排的队形设计排队规则如下 每排人数为N K 向下取整 多出来的人全部站在最后一排 后排所有人的个子都不比前排任何人矮 每排中最高者站中间 中间位置为m 2 1 其中m为该排人
  • vue3+ts实现todolist功能

    先看一下实现效果 可以看到内部实现的内容有enter输入 单项删除 全选 以及删除选中项等功能 具体在实现前需要常见有ts的vue3项目 项目创建 具体项目创建 就是 vue create 项目名称 在创建后 选择的时候有vue2和vue3
  • PAT B1014

    include

随机推荐

  • 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