docs: add detailed 32960 pipeline comments

This commit is contained in:
kkfluous
2026-06-23 13:17:37 +08:00
parent ba68ffe061
commit a096e4ce0e
125 changed files with 493 additions and 14 deletions

View File

@@ -5,6 +5,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "lingniu.ingest.jt1078")
public class Jt1078Properties {
/** 是否启用 JT/T 1078 音视频能力;它不参与 32960 快照/历史字段查询。 */
private boolean enabled = false;
private MediaStream mediaStream = new MediaStream();
@@ -14,13 +15,18 @@ public class Jt1078Properties {
public void setMediaStream(MediaStream mediaStream) { this.mediaStream = mediaStream; }
public static class MediaStream {
/** 媒体流子模块开关,便于只启用信令、不落媒体文件。 */
private boolean enabled = true;
/** TCP 媒体流监听,适合生产默认路径。 */
private boolean tcpEnabled = true;
/** UDP 媒体流监听默认关闭,开启前需要确认网络和包乱序处理能力。 */
private boolean udpEnabled = false;
private int port = 11078;
private int udpPort = 11078;
private int workerThreads = 0;
/** 单包最大长度保护,防止异常媒体流耗尽内存。 */
private int maxPacketLength = 1024 * 1024;
/** 媒体文件分段秒数,影响归档文件粒度。 */
private int segmentSeconds = 300;
public boolean isEnabled() { return enabled; }

View File

@@ -54,6 +54,7 @@ public final class Jt1078MediaArchiveService {
long segment = segment(packet.timestamp());
String key = key(vin, packet, segment);
try {
// JT1078 是 RTP 分片流,同一分段追加写入 .media只发布一次 MediaMeta 作为索引事件。
String uri = archive.append(key, packet.payload());
long segmentSizeBytes = archiveSize(key, packet.payload().length);
publishOnce(packet, peer, identity, vin, segment, key, uri, segmentSizeBytes);
@@ -103,6 +104,7 @@ public final class Jt1078MediaArchiveService {
: archiveKey;
String old = publishedSegmentRefs.getIfPresent(segmentKey);
if (old != null) {
// 同一个分段只发一次索引事件,避免每个 RTP 包都在历史库产生一条 media meta。
return;
}
publishedSegmentRefs.put(segmentKey, uri);
@@ -166,6 +168,7 @@ public final class Jt1078MediaArchiveService {
private long segment(long timestamp) {
long seconds = timestamp > 10_000_000_000L ? timestamp / 1000 : timestamp;
// 按配置秒数对齐分段,保证同一路通道同一时间窗落到同一个 archive key。
return seconds - Math.floorMod(seconds, segmentSeconds);
}

View File

@@ -19,6 +19,7 @@ final class Jt1078RtpPacketParser {
String sim = readBcd(in, 6);
int channelId = in.readUnsignedByte();
int dataAndPacketType = in.readUnsignedByte();
// 高 4 位是数据类型,低 4 位是分包类型;归档 key 需要二者共同区分。
int dataType = (dataAndPacketType >>> 4) & 0x0F;
int packetType = dataAndPacketType & 0x0F;
long timestamp = in.readLong();
@@ -37,6 +38,7 @@ final class Jt1078RtpPacketParser {
if (in == null || in.readableBytes() < HEADER_LEN || in.getInt(in.readerIndex()) != MAGIC) {
return "";
}
// UDP/TCP 解码器在完整 parse 前先取 SIM用于日志和初步身份定位不移动 readerIndex。
StringBuilder sb = new StringBuilder(12);
int simOffset = in.readerIndex() + 6;
for (int i = 0; i < 6; i++) {