owpengram-server/internal/app/livestream/part.go

70 lines
2.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package livestream
import "encoding/binary"
// tgcalls broadcast part 打包(消费方 tgcalls VideoStreamingPart.cpp
// consumeVideoStreamInfo。unifiedRTMP模式的 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完整 mp4moov 在尾)可解。
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...)
}