diff --git a/src/JT1078.Protocol.Test/Extensions/JT1078PackageExtensionsTest.cs b/src/JT1078.Protocol.Test/Extensions/JT1078PackageExtensionsTest.cs new file mode 100644 index 0000000..4d1f2c5 --- /dev/null +++ b/src/JT1078.Protocol.Test/Extensions/JT1078PackageExtensionsTest.cs @@ -0,0 +1,39 @@ +using JT1078.Protocol.Extensions; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace JT1078.Protocol.Test.Extensions +{ + public class JT1078PackageExtensionsTest + { + [Fact] + public void Test() + { + var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "JT1078.txt")); + JT1078Package merge = null; + int mergeBodyLength = 0; + foreach (var line in lines) + { + var data = line.Split(','); + var bytes = data[5].ToHexBytes(); + JT1078Package package = JT1078Serializer.Deserialize(bytes); + mergeBodyLength += package.DataBodyLength; + merge = JT1078Serializer.Merge(package); + } + var packages = merge.Bodies.ConvertVideo(merge.SIM, merge.LogicChannelNumber, merge.Label2.PT, merge.Label3.DataType, + merge.Timestamp, merge.LastFrameInterval, merge.LastFrameInterval); + for(int i=0;i< packages.Count;i++) + { + var data = lines[i].Split(','); + var bytes1 = data[5].ToHexBytes(); + var bytes2 = JT1078Serializer.Serialize(packages[i]); + Assert.Equal(bytes1, bytes2); + } + } + } +} diff --git a/src/JT1078.Protocol/Extensions/JT1078PackageExtensions.cs b/src/JT1078.Protocol/Extensions/JT1078PackageExtensions.cs new file mode 100644 index 0000000..6ec4a76 --- /dev/null +++ b/src/JT1078.Protocol/Extensions/JT1078PackageExtensions.cs @@ -0,0 +1,289 @@ +using JT1078.Protocol.Enums; +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT1078.Protocol +{ + /// + /// 1078扩展类 + /// + public static class JT1078PackageExtensions + { + /// + /// 将音频数据包转换到1078包 + /// + /// + /// + /// + /// + /// + /// + public static List ConvertAudio(this byte[] value,string sim,int channelNo, JT1078AVType jT1078AVType, ulong timestamp) + { + List jT1078Packages = new List(); + var buffer=Slice(value); + if (buffer.Count == 1) + { + JT1078Package jT1078Package = new JT1078Package(); + jT1078Package.SIM = sim; + jT1078Package.LogicChannelNumber = (byte)channelNo; + jT1078Package.SN = SeqUtil.Increment(sim); + jT1078Package.Timestamp = timestamp; + jT1078Package.Label2 = new JT1078Label2(1, jT1078AVType); + jT1078Package.Label3 = new JT1078Label3(JT1078DataType.音频帧, JT1078SubPackageType.原子包_不可被拆分); + jT1078Package.Bodies = buffer[0]; + jT1078Packages.Add(jT1078Package); + } + else if(buffer.Count == 2) + { + JT1078Package jT1078Package1 = new JT1078Package(); + jT1078Package1.SIM = sim; + jT1078Package1.LogicChannelNumber = (byte)channelNo; + jT1078Package1.SN = SeqUtil.Increment(sim); + jT1078Package1.Timestamp = timestamp; + jT1078Package1.Label2 = new JT1078Label2(0, jT1078AVType); + jT1078Package1.Label3 = new JT1078Label3(JT1078DataType.音频帧, JT1078SubPackageType.分包处理时的第一个包); + jT1078Package1.Bodies = buffer[0]; + jT1078Packages.Add(jT1078Package1); + JT1078Package jT1078Package2= new JT1078Package(); + jT1078Package2.SIM = sim; + jT1078Package2.LogicChannelNumber = (byte)channelNo; + jT1078Package2.SN = SeqUtil.Increment(sim); + jT1078Package2.Timestamp = timestamp; + jT1078Package2.Label2 = new JT1078Label2(1, jT1078AVType); + jT1078Package2.Label3 = new JT1078Label3(JT1078DataType.音频帧, JT1078SubPackageType.分包处理时的最后一个包); + jT1078Package2.Bodies = buffer[1]; + jT1078Packages.Add(jT1078Package2); + } + else + { + for (var i = 0; i < buffer.Count; i++) + { + JT1078Package jT1078Package = new JT1078Package(); + jT1078Package.SIM = sim; + jT1078Package.LogicChannelNumber = (byte)channelNo; + jT1078Package.SN = SeqUtil.Increment(sim); + jT1078Package.Timestamp = timestamp; + jT1078Package.Label2 = new JT1078Label2(0, jT1078AVType); + jT1078Package.Label3 = new JT1078Label3(JT1078DataType.音频帧); + jT1078Package.Bodies = buffer[i]; + if (i == 0) + { + jT1078Package.Label3.SubpackageType = JT1078SubPackageType.分包处理时的第一个包; + } + else if (i == (buffer.Count - 1)) + { + jT1078Package.Label2.M = 1; + jT1078Package.Label3.SubpackageType = JT1078SubPackageType.分包处理时的最后一个包; + } + else + { + jT1078Package.Label3.SubpackageType = JT1078SubPackageType.分包处理时的中间包; + } + jT1078Packages.Add(jT1078Package); + } + } + return jT1078Packages; + } + + /// + /// 将视频数据包转换到1078包 + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static List ConvertVideo(this byte[] value, string sim, + int channelNo, + JT1078AVType jT1078AVType, + JT1078DataType jT1078DataType, + ulong timestamp, + int lastIFrameInterval, + int lastFrameInterval) + { + List jT1078Packages = new List(); + var buffer = Slice(value); + if (buffer.Count == 1) + { + JT1078Package jT1078Package = new JT1078Package(); + jT1078Package.SIM = sim; + jT1078Package.LogicChannelNumber = (byte)channelNo; + jT1078Package.SN = SeqUtil.Increment(sim); + jT1078Package.Timestamp = timestamp; + jT1078Package.LastIFrameInterval = (ushort)lastIFrameInterval; + jT1078Package.LastFrameInterval = (ushort)lastFrameInterval; + jT1078Package.Label2 = new JT1078Label2(1, jT1078AVType); + jT1078Package.Label3 = new JT1078Label3(jT1078DataType, JT1078SubPackageType.原子包_不可被拆分); + jT1078Package.Bodies = buffer[0]; + jT1078Packages.Add(jT1078Package); + } + else if (buffer.Count == 2) + { + JT1078Package jT1078Package1 = new JT1078Package(); + jT1078Package1.SIM = sim; + jT1078Package1.LogicChannelNumber = (byte)channelNo; + jT1078Package1.SN = SeqUtil.Increment(sim); + jT1078Package1.Timestamp = timestamp; + jT1078Package1.LastIFrameInterval = (ushort)lastIFrameInterval; + jT1078Package1.LastFrameInterval = (ushort)lastFrameInterval; + jT1078Package1.Label2 = new JT1078Label2(0, jT1078AVType); + jT1078Package1.Label3 = new JT1078Label3(jT1078DataType, JT1078SubPackageType.分包处理时的第一个包); + jT1078Package1.Bodies = buffer[0]; + jT1078Packages.Add(jT1078Package1); + JT1078Package jT1078Package2 = new JT1078Package(); + jT1078Package2.SIM = sim; + jT1078Package2.LogicChannelNumber = (byte)channelNo; + jT1078Package2.SN = SeqUtil.Increment(sim); + jT1078Package2.Timestamp = timestamp; + jT1078Package2.LastIFrameInterval = (ushort)lastIFrameInterval; + jT1078Package2.LastFrameInterval = (ushort)lastFrameInterval; + jT1078Package2.Label2 = new JT1078Label2(1, jT1078AVType); + jT1078Package2.Label3 = new JT1078Label3(jT1078DataType, JT1078SubPackageType.分包处理时的最后一个包); + jT1078Package2.Bodies = buffer[1]; + jT1078Packages.Add(jT1078Package2); + } + else + { + for (var i = 0; i < buffer.Count; i++) + { + JT1078Package jT1078Package = new JT1078Package(); + jT1078Package.SIM = sim; + jT1078Package.LogicChannelNumber = (byte)channelNo; + jT1078Package.SN = SeqUtil.Increment(sim); + jT1078Package.Timestamp = timestamp; + jT1078Package.LastIFrameInterval = (ushort)lastIFrameInterval; + jT1078Package.LastFrameInterval = (ushort)lastFrameInterval; + jT1078Package.Label2 = new JT1078Label2(0, jT1078AVType); + jT1078Package.Label3 = new JT1078Label3(jT1078DataType); + jT1078Package.Bodies = buffer[i]; + if (i == 0) + { + jT1078Package.Label3.SubpackageType = JT1078SubPackageType.分包处理时的第一个包; + } + else if (i == (buffer.Count - 1)) + { + jT1078Package.Label2.M = 1; + jT1078Package.Label3.SubpackageType = JT1078SubPackageType.分包处理时的最后一个包; + } + else + { + jT1078Package.Label3.SubpackageType = JT1078SubPackageType.分包处理时的中间包; + } + jT1078Packages.Add(jT1078Package); + } + } + return jT1078Packages; + } + + /// + /// 将透传数据包转换到1078包 + /// + /// + /// + /// + /// + public static List ConvertPassthrough(this byte[] value, string sim, int channelNo) + { + List jT1078Packages = new List(); + var buffer = Slice(value); + if (buffer.Count == 1) + { + JT1078Package jT1078Package = new JT1078Package(); + jT1078Package.SIM = sim; + jT1078Package.LogicChannelNumber = (byte)channelNo; + jT1078Package.SN = SeqUtil.Increment(sim); + jT1078Package.Label2 = new JT1078Label2(1, JT1078AVType.透传); + jT1078Package.Label3 = new JT1078Label3(JT1078DataType.透传数据, JT1078SubPackageType.原子包_不可被拆分); + jT1078Package.Bodies = buffer[0]; + jT1078Packages.Add(jT1078Package); + } + else if (buffer.Count == 2) + { + JT1078Package jT1078Package1 = new JT1078Package(); + jT1078Package1.SIM = sim; + jT1078Package1.LogicChannelNumber = (byte)channelNo; + jT1078Package1.SN = SeqUtil.Increment(sim); + jT1078Package1.Label2 = new JT1078Label2(0, JT1078AVType.透传); + jT1078Package1.Label3 = new JT1078Label3(JT1078DataType.透传数据, JT1078SubPackageType.分包处理时的第一个包); + jT1078Package1.Bodies = buffer[0]; + jT1078Packages.Add(jT1078Package1); + JT1078Package jT1078Package2 = new JT1078Package(); + jT1078Package2.SIM = sim; + jT1078Package2.LogicChannelNumber = (byte)channelNo; + jT1078Package2.SN = SeqUtil.Increment(sim); + jT1078Package2.Label2 = new JT1078Label2(1, JT1078AVType.透传); + jT1078Package2.Label3 = new JT1078Label3(JT1078DataType.透传数据, JT1078SubPackageType.分包处理时的最后一个包); + jT1078Package2.Bodies = buffer[1]; + jT1078Packages.Add(jT1078Package2); + } + else + { + for (var i = 0; i < buffer.Count; i++) + { + JT1078Package jT1078Package = new JT1078Package(); + jT1078Package.SIM = sim; + jT1078Package.LogicChannelNumber = (byte)channelNo; + jT1078Package.SN = SeqUtil.Increment(sim); + jT1078Package.Label2 = new JT1078Label2(0, JT1078AVType.透传); + jT1078Package.Label3 = new JT1078Label3(JT1078DataType.透传数据); + jT1078Package.Bodies = buffer[i]; + if (i == 0) + { + jT1078Package.Label3.SubpackageType = JT1078SubPackageType.分包处理时的第一个包; + } + else if (i == (buffer.Count - 1)) + { + jT1078Package.Label2.M = 1; + jT1078Package.Label3.SubpackageType = JT1078SubPackageType.分包处理时的最后一个包; + } + else + { + jT1078Package.Label3.SubpackageType = JT1078SubPackageType.分包处理时的中间包; + } + jT1078Packages.Add(jT1078Package); + } + } + return jT1078Packages; + } + + /// + /// 切分数据包 + /// + /// + /// + public static List Slice(byte[] value) + { + const int MAXCONTENTLENGTH = 950; + if (value.Length <= MAXCONTENTLENGTH) + { + return new List() { value }; + } + List s = new List(); + var quotient = value.Length / MAXCONTENTLENGTH; + var remainder = value.Length % MAXCONTENTLENGTH; + if (remainder != 0) + { + quotient = quotient + 1; + } + ReadOnlySpan valueReadOnlySpan = value; + for (int i = 1; i <= quotient; i++) + { + if (i == quotient) + { + s.Add(valueReadOnlySpan.Slice((i - 1) * MAXCONTENTLENGTH).ToArray()); + } + else + { + s.Add(valueReadOnlySpan.Slice((i - 1) * MAXCONTENTLENGTH, MAXCONTENTLENGTH).ToArray()); + } + } + return s; + } + } +} diff --git a/src/JT1078.Protocol/JT1078.Protocol.xml b/src/JT1078.Protocol/JT1078.Protocol.xml index 96d7779..b73d231 100644 --- a/src/JT1078.Protocol/JT1078.Protocol.xml +++ b/src/JT1078.Protocol/JT1078.Protocol.xml @@ -67,6 +67,52 @@ + + + 1078扩展类 + + + + + 将音频数据包转换到1078包 + + + + + + + + + + + 将视频数据包转换到1078包 + + + + + + + + + + + + + + 将透传数据包转换到1078包 + + + + + + + + + 切分数据包 + + + + diff --git a/src/JT1078.Protocol/JT1078Label3.cs b/src/JT1078.Protocol/JT1078Label3.cs index 79b5b21..dbfdf31 100644 --- a/src/JT1078.Protocol/JT1078Label3.cs +++ b/src/JT1078.Protocol/JT1078Label3.cs @@ -21,6 +21,10 @@ namespace JT1078.Protocol DataType = dataType; SubpackageType = subpackageType; } + public JT1078Label3(JT1078DataType dataType) + { + DataType = dataType; + } /// /// 数据类型 /// diff --git a/src/JT1078.Protocol/JT1078Serializer.cs b/src/JT1078.Protocol/JT1078Serializer.cs index a5d8e54..819d727 100644 --- a/src/JT1078.Protocol/JT1078Serializer.cs +++ b/src/JT1078.Protocol/JT1078Serializer.cs @@ -46,6 +46,7 @@ namespace JT1078.Protocol JT1078ArrayPool.Return(buffer); } } + public static JT1078Package Deserialize(ReadOnlySpan bytes) { JT1078Package jT1078Package = new JT1078Package(); diff --git a/src/JT1078.Protocol/SeqUtil.cs b/src/JT1078.Protocol/SeqUtil.cs new file mode 100644 index 0000000..229cf3b --- /dev/null +++ b/src/JT1078.Protocol/SeqUtil.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Text; + +namespace JT1078.Protocol +{ + public static class SeqUtil + { + static readonly ConcurrentDictionary counterDict; + static SeqUtil() + { + counterDict = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + } + public static ushort Increment(string terminalPhoneNo) + { + return (ushort)counterDict.AddOrUpdate(terminalPhoneNo, 0, (id, count) => count + 1); + } + public static ushort Reset(string terminalPhoneNo) + { + return (ushort)counterDict.AddOrUpdate(terminalPhoneNo, 0, (id, count) => 0); + } + } +} diff --git a/src/JT808.Protocol.Extensions.JT1078/JT808.Protocol.Extensions.JT1078.csproj b/src/JT808.Protocol.Extensions.JT1078/JT808.Protocol.Extensions.JT1078.csproj index 1586341..adc1152 100644 --- a/src/JT808.Protocol.Extensions.JT1078/JT808.Protocol.Extensions.JT1078.csproj +++ b/src/JT808.Protocol.Extensions.JT1078/JT808.Protocol.Extensions.JT1078.csproj @@ -15,7 +15,7 @@ https://github.com/SmallChi/JT1078/blob/master/LICENSE https://github.com/SmallChi/JT1078/blob/master/LICENSE false - 2.3.4 + 2.3.5 LICENSE JT808.Protocol.Extensions.JT1078.xml @@ -28,7 +28,7 @@ - + diff --git a/src/JT808.Protocol.Extensions.JT1078/MessageBody/JT808_0x0200_0x14.cs b/src/JT808.Protocol.Extensions.JT1078/MessageBody/JT808_0x0200_0x14.cs index c0e7289..b06c751 100644 --- a/src/JT808.Protocol.Extensions.JT1078/MessageBody/JT808_0x0200_0x14.cs +++ b/src/JT808.Protocol.Extensions.JT1078/MessageBody/JT808_0x0200_0x14.cs @@ -34,7 +34,7 @@ namespace JT808.Protocol.Extensions.JT1078.MessageBody writer.WriteNumber($"[{value.AttachInfoLength.ReadNumber()}]附加信息长度", value.AttachInfoLength); value.VideoRelateAlarm = reader.ReadUInt32(); writer.WriteNumber($"[{value.VideoRelateAlarm.ReadNumber()}]视频相关报警", value.VideoRelateAlarm); - var videoRelateAlarmFlags = JT808EnumExtensions.GetEnumTypes((int)value.VideoRelateAlarm, 32); + var videoRelateAlarmFlags = JT808EnumExtensions.GetEnumTypes(value.VideoRelateAlarm, 32); if (videoRelateAlarmFlags.Any()) { writer.WriteStartArray("视频报警集合");