feat: sync group call livestream support
This commit is contained in:
parent
56d995474c
commit
f1a27996d3
37 changed files with 2219 additions and 83 deletions
70
internal/app/livestream/part.go
Normal file
70
internal/app/livestream/part.go
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
package livestream
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
// tgcalls broadcast part 打包(消费方 tgcalls VideoStreamingPart.cpp
|
||||
// consumeVideoStreamInfo)。unified(RTMP)模式的 part 结构:
|
||||
//
|
||||
// int32(LE) 签名 0xa12e810d
|
||||
// TL 风格短字符串:容器名(本实现恒 "mp4")
|
||||
// int32 activeMask(单一 unified 轨恒 1)
|
||||
// int32 eventCount(消费方只读第一个 event,恒写 1)
|
||||
// event: int32 offset(=0,相对头部之后的数据) + 字符串 endpointId("unified")
|
||||
// + int32 rotation(0) + int32 extra(0)
|
||||
// 随后紧跟容器数据(音视频同容器,客户端分别按 Video/Audio content type 解)。
|
||||
const partSignature uint32 = 0xa12e810d
|
||||
|
||||
// partContainer 必须落在 TDesktop 裁剪版 ffmpeg 的 demuxer 白名单内
|
||||
// (Telegram/build/prepare/prepare.py --enable-demuxer=...,含 mov/mp4、无 mpegts)。
|
||||
// "mp4" 由 mov demuxer 别名匹配;tgcalls AVIO 支持 seek,完整 mp4(moov 在尾)可解。
|
||||
const (
|
||||
partContainer = "mp4"
|
||||
partEndpointID = "unified"
|
||||
)
|
||||
|
||||
// appendTLString 按 tgcalls readSerializedString 的逆操作写入字符串:
|
||||
// 长度 <254 用 1 字节长度 + 数据,整体(含长度字节)补齐到 4 字节;
|
||||
// 否则 0xFE + 3 字节小端长度 + 数据,数据补齐到 4 字节。
|
||||
func appendTLString(dst []byte, s string) []byte {
|
||||
n := len(s)
|
||||
if n < 254 {
|
||||
dst = append(dst, byte(n))
|
||||
dst = append(dst, s...)
|
||||
for (n+1)%4 != 0 {
|
||||
dst = append(dst, 0)
|
||||
n++
|
||||
}
|
||||
return dst
|
||||
}
|
||||
dst = append(dst, 0xFE, byte(n), byte(n>>8), byte(n>>16))
|
||||
dst = append(dst, s...)
|
||||
for n%4 != 0 {
|
||||
dst = append(dst, 0)
|
||||
n++
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
func appendUint32(dst []byte, v uint32) []byte {
|
||||
var buf [4]byte
|
||||
binary.LittleEndian.PutUint32(buf[:], v)
|
||||
return append(dst, buf[:]...)
|
||||
}
|
||||
|
||||
func appendInt32(dst []byte, v int32) []byte {
|
||||
return appendUint32(dst, uint32(v))
|
||||
}
|
||||
|
||||
// packUnifiedPart 把一段自包含 MPEG-TS 数据包成 tgcalls broadcast part。
|
||||
func packUnifiedPart(tsData []byte) []byte {
|
||||
out := make([]byte, 0, len(tsData)+48)
|
||||
out = appendUint32(out, partSignature)
|
||||
out = appendTLString(out, partContainer)
|
||||
out = appendInt32(out, 1) // activeMask
|
||||
out = appendInt32(out, 1) // eventCount
|
||||
out = appendInt32(out, 0) // event.offset
|
||||
out = appendTLString(out, partEndpointID)
|
||||
out = appendInt32(out, 0) // event.rotation
|
||||
out = appendInt32(out, 0) // event.extra
|
||||
return append(out, tsData...)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue