golang原生解析与解复用MPEG传输流(.ts)插件库go-astits的使用
Golang原生解析与解复用MPEG传输流(.ts)插件库go-astits的使用
这是一个用于在Go中原生解复用和复用MPEG传输流(ts)的库。
警告:该库尚未准备好用于生产环境,请自行承担使用风险!
安装
要安装库,请使用以下命令:
go get -u github.com/asticode/go-astits/...
要安装可执行文件,请使用以下命令:
go install github.com/asticode/go-astits/cmd
使用说明
传输流由数据包组成。每个数据包都有一个头部、一个可选的适配字段和一个有效载荷。多个有效载荷可以附加并解析为数据。
TRANSPORT STREAM
+--------------------------------------------------------------------------------------------------+
| |
PACKET PACKET
+----------------------------------------------+----------------------------------------------+----
| | |
+--------+---------------------------+---------+--------+---------------------------+---------+
| HEADER | OPTIONAL ADAPTATION FIELD | PAYLOAD | HEADER | OPTIONAL ADAPTATION FIELD | PAYLOAD | ...
+--------+---------------------------+---------+--------+---------------------------+---------+
| | | |
+---------+ +---------+
| |
+----------------------------------------------+
DATA
代码示例
解复用(Demux)
// 创建一个可取消的上下文,以便随时停止读取数据包/数据
ctx, cancel := context.WithCancel(context.Background())
// 处理SIGTERM信号
ch := make(chan os.Signal, 1)
signal.Notify(ch, syscall.SIGTERM)
go func() {
<-ch
cancel()
}()
// 打开文件或初始化任何类型的io.Reader
// 建议使用bufio.Reader进行缓冲以提高性能
f, _ := os.Open("/path/to/file.ts")
defer f.Close()
// 创建解复用器
dmx := astits.NewDemuxer(ctx, f)
for {
// 获取下一个数据
d, _ := dmx.NextData()
// 如果是PMT数据
if d.PMT != nil {
// 遍历基本流
for _, es := range d.PMT.ElementaryStreams {
fmt.Printf("Stream detected: %d\n", es.ElementaryPID)
}
return
}
}
复用(Mux)
// 创建一个可取消的上下文,以便随时停止写入数据包/数据
ctx, cancel := context.WithCancel(context.Background())
// 处理SIGTERM信号
ch := make(chan os.Signal, 1)
signal.Notify(ch, syscall.SIGTERM)
go func() {
<-ch
cancel()
}()
// 创建文件或初始化任何类型的io.Writer
// 建议使用bufio.Writer进行缓冲以提高性能
f, _ := os.Create("/path/to/file.ts")
defer f.Close()
// 创建复用器
mx := astits.NewMuxer(ctx, f)
// 添加基本流
mx.AddElementaryStream(astits.PMTElementaryStream{
ElementaryPID: 1,
StreamType: astits.StreamTypeMetadata,
})
// 写入表
// 使用该函数不是强制性的,WriteData会不时重新传输表
mx.WriteTables()
// 写入数据
mx.WriteData(&astits.MuxerData{
PES: &astits.PESData{
Data: []byte("test"),
},
PID: 1,
})
选项
要为解复用器或复用器传递选项,请查找前缀为"DemuxerOpt"或"MuxerOpt"的方法,并在调用"NewDemuxer"或"NewMuxer"时添加它们:
// 这是自定义的数据包解析器
p := func(ps []*astits.Packet) (ds []*astits.Data, skip bool, err error) {
// 这里是你的逻辑
skip = true
return
}
// 现在你可以创建带有适当选项的解复用器
dmx := NewDemuxer(ctx, f, DemuxerOptPacketSize(192), DemuxerOptPacketsParser(p))
CLI
该库提供了2个CLI工具,它们会在执行"go get"时自动安装在"GOPATH/bin"中。
astits-probe
列出流
$ astits-probe -i <path to your file> -f <format: text|json (default: text)>
列出数据包
$ astits-probe packets -i <path to your file>
列出数据
$ astits-probe data -i <path to your file> -d <data type: eit|nit|... (repeatable argument | if empty, all data types are shown)>
astits-es-split
将流拆分为单独的.ts文件
$ astits-es-split <path to your file> -o <path to output dir>
特性和路线图
- [x] 添加解复用器
- [x] 添加复用器
- [x] 解复用PES数据包
- [x] 复用PES数据包
- [x] 解复用PAT数据包
- [x] 复用PAT数据包
- [x] 解复用PMT数据包
- [x] 复用PMT数据包
- [x] 解复用EIT数据包
- [ ] 复用EIT数据包
- [x] 解复用NIT数据包
- [ ] 复用NIT数据包
- [x] 解复用SDT数据包
- [ ] 复用SDT数据包
- [x] 解复用TOT数据包
- [ ] 复用TOT数据包
- [ ] 解复用BAT数据包
- [ ] 复用BAT数据包
- [ ] 解复用DIT数据包
- [ ] 复用DIT数据包
- [ ] 解复用RST数据包
- [ ] 复用RST数据包
- [ ] 解复用SIT数据包
- [ ] 复用SIT数据包
- [ ] 复用ST数据包
- [ ] 解复用TDT数据包
- [ ] 复用TDT数据包
- [ ] 解复用TSDT数据包
- [ ] 复用TSDT数据包
更多关于golang原生解析与解复用MPEG传输流(.ts)插件库go-astits的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang原生解析与解复用MPEG传输流(.ts)插件库go-astits的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
使用go-astits解析与解复用MPEG传输流(.ts)
go-astits是一个用于解析和解复用MPEG传输流(.ts)的Go语言库。它允许你从.ts文件中提取基本流(PES)和数据包(PES packets),支持解析MPEG-TS头部信息、节目关联表(PAT)、节目映射表(PMT)等。
基本用法
安装
go get github.com/asticode/go-astits
示例代码
package main
import (
"fmt"
"os"
"github.com/asticode/go-astits"
)
func main() {
// 打开.ts文件
f, err := os.Open("example.ts")
if err != nil {
fmt.Printf("打开文件失败: %s\n", err)
return
}
defer f.Close()
// 创建demuxer
dmx := astits.NewDemuxer(f)
// 解析文件
for {
// 读取数据
d, err := dmx.NextData()
if err != nil {
fmt.Printf("读取数据失败: %s\n", err)
break
}
// 处理不同类型的数据
switch {
case d.PAT != nil:
// 处理节目关联表
fmt.Printf("PAT: %+v\n", d.PAT)
for _, program := range d.PAT.Programs {
fmt.Printf(" Program: %d -> PID: %d\n", program.ProgramNumber, program.ProgramMapPID)
}
case d.PMT != nil:
// 处理节目映射表
fmt.Printf("PMT: %+v\n", d.PMT)
fmt.Printf(" PCR PID: %d\n", d.PMT.PCRPID)
for _, es := range d.PMT.ElementaryStreams {
fmt.Printf(" Elementary Stream: Type=%d, PID=%d\n", es.StreamType, es.ElementaryPID)
}
case d.PES != nil:
// 处理PES包
fmt.Printf("PES Packet: PID=%d, StreamID=%d, DataLength=%d\n",
d.PID, d.PES.Header.StreamID, len(d.PES.Data))
// 这里可以根据PID和StreamType处理特定的基本流
// 例如提取视频或音频数据
case d.TOT != nil:
// 处理时间偏移表
fmt.Printf("TOT: %+v\n", d.TOT)
default:
// 其他类型的包
fmt.Printf("Unknown packet type on PID %d\n", d.PID)
}
}
}
高级功能
1. 提取特定PID的数据
// 假设视频流的PID是256
targetPID := uint16(256)
for {
d, err := dmx.NextData()
if err != nil {
break
}
if d.PID == targetPID && d.PES != nil {
// 处理视频数据
processVideoData(d.PES.Data)
}
}
2. 处理特定类型的流
var videoPID uint16
// 首先找到视频流的PID
for {
d, err := dmx.NextData()
if err != nil {
break
}
if d.PMT != nil {
for _, es := range d.PMT.ElementaryStreams {
if es.StreamType == astits.StreamTypeH264Video {
videoPID = es.ElementaryPID
break
}
}
break
}
}
// 然后处理视频流
if videoPID != 0 {
for {
d, err := dmx.NextData()
if err != nil {
break
}
if d.PID == videoPID && d.PES != nil {
processH264Data(d.PES.Data)
}
}
}
3. 解析PES头部信息
if d.PES != nil {
pesHeader := d.PES.Header
fmt.Printf("PES Header Info:\n")
fmt.Printf(" Packet Length: %d\n", pesHeader.PacketLength)
fmt.Printf(" PTS: %v\n", pesHeader.OptionalHeader.PTS)
fmt.Printf(" DTS: %v\n", pesHeader.OptionalHeader.DTS)
fmt.Printf(" Data Alignment Indicator: %v\n", pesHeader.OptionalHeader.DataAlignmentIndicator)
}
注意事项
-
性能考虑:处理大.ts文件时,考虑使用缓冲读取器提高性能:
f, _ := os.Open("large.ts") buffered := bufio.NewReaderSize(f, 1024*1024) // 1MB缓冲区 dmx := astits.NewDemuxer(buffered)
-
错误处理:TS流可能包含错误,应妥善处理错误情况。
-
内存管理:处理大文件时,注意内存使用,及时处理或丢弃不需要的数据。
-
时间戳处理:PES包可能包含PTS(显示时间戳)和DTS(解码时间戳),用于同步音视频。
go-astits提供了基础的TS流解析功能,但对于完整的媒体处理流程,通常需要结合其他库(如解码H.264的库)一起使用。