@@ -0,0 +1,109 @@ | |||||
using JT1078.FMp4.MessagePack; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
using Xunit; | |||||
using JT1078.Protocol.Extensions; | |||||
namespace JT1078.FMp4.Test | |||||
{ | |||||
public class FMp4Box_Test | |||||
{ | |||||
/// <summary> | |||||
/// 使用doc/video/fragmented_demo.mp4 | |||||
/// </summary> | |||||
[Fact(DisplayName = "ftyp")] | |||||
public void ftyp_test() | |||||
{ | |||||
var MinorVersion = Encoding.ASCII.GetString(new byte[4] { 0,0,2,0}); | |||||
FileTypeBox fileTypeBox = new FileTypeBox(); | |||||
fileTypeBox.MajorBrand = "isom"; | |||||
fileTypeBox.MinorVersion = "\0\0\u0002\0"; | |||||
fileTypeBox.CompatibleBrands.Add("isom"); | |||||
fileTypeBox.CompatibleBrands.Add("iso2"); | |||||
fileTypeBox.CompatibleBrands.Add("avc1"); | |||||
fileTypeBox.CompatibleBrands.Add("iso6"); | |||||
fileTypeBox.CompatibleBrands.Add("mp41"); | |||||
FMp4MessagePackWriter writer = new MessagePack.FMp4MessagePackWriter(new byte[0x25]); | |||||
fileTypeBox.ToBuffer(ref writer); | |||||
var hex = writer.FlushAndGetArray().ToHexString(); | |||||
Assert.Equal("000000246674797069736f6d0000020069736f6d69736f326176633169736f366d703431".ToUpper(), hex); | |||||
} | |||||
/// <summary> | |||||
/// 使用doc/video/fragmented_demo.mp4 | |||||
/// </summary> | |||||
[Fact(DisplayName = "moov_mvhd")] | |||||
public void moov_mvhd_test() | |||||
{ | |||||
MovieHeaderBox movieHeaderBox = new MovieHeaderBox(0); | |||||
movieHeaderBox.CreationTime = 0; | |||||
movieHeaderBox.ModificationTime = 0; | |||||
movieHeaderBox.Timescale = 1000; | |||||
movieHeaderBox.Duration = 0; | |||||
movieHeaderBox.NextTrackID = 2; | |||||
FMp4MessagePackWriter writer = new MessagePack.FMp4MessagePackWriter(new byte[10240]); | |||||
movieHeaderBox.ToBuffer(ref writer); | |||||
var hex = writer.FlushAndGetArray().ToHexString(); | |||||
Assert.Equal("0000006c6d766864000000000000000000000000000003e8000000000001000001000000000000000000000000010000000000000000000000000000000100000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002".ToUpper(), hex); | |||||
} | |||||
/// <summary> | |||||
/// 使用doc/video/fragmented_demo.mp4 | |||||
/// </summary> | |||||
[Fact(DisplayName = "trak_tkhd")] | |||||
public void trak_tkhd_test() | |||||
{ | |||||
TrackHeaderBox trackHeaderBox = new TrackHeaderBox(0,3); | |||||
trackHeaderBox.CreationTime = 0; | |||||
trackHeaderBox.ModificationTime = 0; | |||||
trackHeaderBox.TrackID = 1; | |||||
trackHeaderBox.Duration = 0; | |||||
trackHeaderBox.Width = 544u; | |||||
trackHeaderBox.Height = 960u; | |||||
FMp4MessagePackWriter writer = new MessagePack.FMp4MessagePackWriter(new byte[10240]); | |||||
trackHeaderBox.ToBuffer(ref writer); | |||||
var hex = writer.FlushAndGetArray().ToHexString(); | |||||
Assert.Equal("0000005C746B68640000000300000000000000000000000100000000000000000000000000000000000000000000000000010000000000000000000000000000000100000000000000000000000000004000000000000220000003C0".ToUpper(), hex); | |||||
} | |||||
/// <summary> | |||||
/// 使用doc/video/fragmented_demo.mp4 | |||||
/// </summary> | |||||
[Fact(DisplayName = "trak_mdia")] | |||||
public void trak_mdia_test() | |||||
{ | |||||
} | |||||
/// <summary> | |||||
/// 使用doc/video/fragmented_demo.mp4 | |||||
/// </summary> | |||||
[Fact(DisplayName = "trak_mdia_mdhd")] | |||||
public void trak_mdia_mdhd_test() | |||||
{ | |||||
MediaHeaderBox mediaHeaderBox = new MediaHeaderBox(0, 0); | |||||
mediaHeaderBox.CreationTime = 0; | |||||
mediaHeaderBox.ModificationTime = 0; | |||||
mediaHeaderBox.Timescale = 0x00124f80; | |||||
mediaHeaderBox.Duration = 0; | |||||
mediaHeaderBox.Language = "und"; | |||||
FMp4MessagePackWriter writer = new MessagePack.FMp4MessagePackWriter(new byte[10240]); | |||||
mediaHeaderBox.ToBuffer(ref writer); | |||||
var hex = writer.FlushAndGetArray().ToHexString(); | |||||
//000000206d64686400000000000000000000000000124f800000000055c40000 | |||||
//00000020 | |||||
//6d646864 | |||||
//00000000 | |||||
//00000000 | |||||
//00000000 | |||||
//00124f80 | |||||
//00000000 | |||||
//55c4 | |||||
//0000 | |||||
Assert.Equal("000000206d64686400000000000000000000000000124f800000000055c40000".ToUpper(), hex); | |||||
} | |||||
} | |||||
} |
@@ -69,7 +69,7 @@ namespace JT1078.Flv.Benchmark | |||||
{ | { | ||||
public JT1078FlvEncoderConfig() | public JT1078FlvEncoderConfig() | ||||
{ | { | ||||
Add(Job.Default.WithGcServer(false).With(CsProjCoreToolchain.NetCoreApp31).With(Platform.AnyCpu)); | |||||
AddJob(Job.Default.WithGcServer(false).WithToolchain(CsProjCoreToolchain.NetCoreApp31).WithPlatform(Platform.AnyCpu)); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -6,7 +6,7 @@ namespace JT808.Protocol.Extensions | |||||
/// | /// | ||||
/// ref:"www.codeproject.com/tips/447938/high-performance-csharp-byte-array-to-hex-string-t" | /// ref:"www.codeproject.com/tips/447938/high-performance-csharp-byte-array-to-hex-string-t" | ||||
/// </summary> | /// </summary> | ||||
public static partial class JT808BinaryExtensions | |||||
internal static partial class JT808BinaryExtensions | |||||
{ | { | ||||
public static string ToHexString(this byte[] source) | public static string ToHexString(this byte[] source) | ||||
{ | { | ||||
@@ -15,9 +15,7 @@ | |||||
<PackageReference Include="System.Memory" Version="4.5.4" /> | <PackageReference Include="System.Memory" Version="4.5.4" /> | ||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
<ProjectReference Include="..\JT1078.Flv.Benchmark\JT1078.Flv.Benchmark.csproj" /> | |||||
<ProjectReference Include="..\JT1078.Flv\JT1078.Flv.csproj" /> | <ProjectReference Include="..\JT1078.Flv\JT1078.Flv.csproj" /> | ||||
<ProjectReference Include="..\JT1078.Protocol\JT1078.Protocol.csproj" /> | |||||
</ItemGroup> | </ItemGroup> | ||||
</Project> | </Project> |
@@ -7,7 +7,7 @@ using JT1078.Flv.MessagePack; | |||||
using JT1078.Protocol; | using JT1078.Protocol; | ||||
using JT1078.Protocol.H264; | using JT1078.Protocol.H264; | ||||
using JT1078.Protocol.MessagePack; | using JT1078.Protocol.MessagePack; | ||||
using JT808.Protocol.Extensions; | |||||
using JT1078.Protocol.Extensions; | |||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.IO; | using System.IO; | ||||
@@ -78,7 +78,7 @@ namespace JT1078.Flv.Benchmark | |||||
{ | { | ||||
public JT1078FlvEncoderConfig() | public JT1078FlvEncoderConfig() | ||||
{ | { | ||||
Add(Job.Default.WithGcServer(false).With(CsProjCoreToolchain.NetCoreApp31).With(Platform.AnyCpu)); | |||||
AddJob(Job.Default.WithGcServer(false).WithToolchain(CsProjCoreToolchain.NetCoreApp31).WithPlatform(Platform.AnyCpu)); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -3,10 +3,10 @@ using BenchmarkDotNet.Configs; | |||||
using BenchmarkDotNet.Environments; | using BenchmarkDotNet.Environments; | ||||
using BenchmarkDotNet.Jobs; | using BenchmarkDotNet.Jobs; | ||||
using BenchmarkDotNet.Toolchains.CsProj; | using BenchmarkDotNet.Toolchains.CsProj; | ||||
using JT808.Protocol.Extensions; | |||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Linq; | using System.Linq; | ||||
using JT1078.Protocol.Extensions; | |||||
namespace JT1078.Protocol.Benchmark | namespace JT1078.Protocol.Benchmark | ||||
{ | { | ||||
@@ -58,7 +58,7 @@ namespace JT1078.Protocol.Benchmark | |||||
{ | { | ||||
public JT1078SerializerConfig() | public JT1078SerializerConfig() | ||||
{ | { | ||||
Add(Job.Default.WithGcServer(false).With(CsProjCoreToolchain.NetCoreApp31).With(Platform.AnyCpu)); | |||||
AddJob(Job.Default.WithGcServer(false).WithToolchain(CsProjCoreToolchain.NetCoreApp31).WithPlatform(Platform.AnyCpu)); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -14,7 +14,7 @@ | |||||
<licenseUrl>https://github.com/SmallChi/JT1078/blob/master/LICENSE</licenseUrl> | <licenseUrl>https://github.com/SmallChi/JT1078/blob/master/LICENSE</licenseUrl> | ||||
<license>https://github.com/SmallChi/JT1078/blob/master/LICENSE</license> | <license>https://github.com/SmallChi/JT1078/blob/master/LICENSE</license> | ||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> | <GeneratePackageOnBuild>false</GeneratePackageOnBuild> | ||||
<Version>1.0.4-preview1</Version> | |||||
<Version>1.0.4-preview2</Version> | |||||
<SignAssembly>false</SignAssembly> | <SignAssembly>false</SignAssembly> | ||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance> | <PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance> | ||||
<PackageLicenseFile>LICENSE</PackageLicenseFile> | <PackageLicenseFile>LICENSE</PackageLicenseFile> | ||||
@@ -115,80 +115,72 @@ namespace JT1078.Protocol | |||||
return jT1078Package; | return jT1078Package; | ||||
} | } | ||||
} | } | ||||
public static byte[] AnalyzeJsonBuffer(ReadOnlySpan<byte> bytes, JsonWriterOptions options = default, int minBufferSize = 8096) | |||||
public static byte[] AnalyzeJsonBuffer(ReadOnlySpan<byte> bytes, JsonWriterOptions options = default) | |||||
{ | { | ||||
byte[] buffer = JT1078ArrayPool.Rent(minBufferSize); | |||||
try | |||||
JT1078MessagePackReader jT1078MessagePackReader = new JT1078MessagePackReader(bytes); | |||||
using (MemoryStream memoryStream = new MemoryStream()) | |||||
using (Utf8JsonWriter writer = new Utf8JsonWriter(memoryStream, options)) | |||||
{ | { | ||||
JT1078MessagePackReader jT1078MessagePackReader = new JT1078MessagePackReader(bytes); | |||||
using (MemoryStream memoryStream = new MemoryStream()) | |||||
using (Utf8JsonWriter writer = new Utf8JsonWriter(memoryStream, options)) | |||||
{ | |||||
writer.WriteStartObject(); | |||||
var header = jT1078MessagePackReader.ReadUInt32(); | |||||
writer.WriteString($"[{header}]头部", header.ReadNumber()); | |||||
var val1 = jT1078MessagePackReader.ReadByte(); | |||||
var label1 = new JT1078Label1(val1); | |||||
var labelSpan = val1.ReadBinary(); | |||||
writer.WriteStartObject($"[{labelSpan.ToString()}]object1[{val1.ReadNumber()}]"); | |||||
writer.WriteNumber($"({labelSpan.Slice(0,2).ToString()})V[固定为2]", label1.V); | |||||
writer.WriteNumber($"({labelSpan[2]})P[固定为0]", label1.P); | |||||
writer.WriteNumber($"({labelSpan[3]})X[RTP头是否需要扩展位固定为0]", label1.X); | |||||
writer.WriteNumber($"({labelSpan.Slice(4).ToString()})CC[固定为1]", label1.CC); | |||||
writer.WriteEndObject(); | |||||
writer.WriteStartObject(); | |||||
var header = jT1078MessagePackReader.ReadUInt32(); | |||||
writer.WriteNumber($"[{header.ReadNumber()}]头部", header); | |||||
var val1 = jT1078MessagePackReader.ReadByte(); | |||||
var label1 = new JT1078Label1(val1); | |||||
var labelSpan = val1.ReadBinary(); | |||||
writer.WriteStartObject($"[{labelSpan.ToString()}]object1[{val1.ReadNumber()}]"); | |||||
writer.WriteNumber($"({labelSpan.Slice(0,2).ToString()})V[固定为2]", label1.V); | |||||
writer.WriteNumber($"({labelSpan[2]})P[固定为0]", label1.P); | |||||
writer.WriteNumber($"({labelSpan[3]})X[RTP头是否需要扩展位固定为0]", label1.X); | |||||
writer.WriteNumber($"({labelSpan.Slice(4).ToString()})CC[固定为1]", label1.CC); | |||||
writer.WriteEndObject(); | |||||
var val2 = jT1078MessagePackReader.ReadByte(); | |||||
var label2 = new JT1078Label2(val2); | |||||
var label2Span = val2.ReadBinary(); | |||||
writer.WriteStartObject($"[{label2Span.ToString()}]object2[{val2.ReadNumber()}]"); | |||||
writer.WriteNumber($"({label2Span.Slice(0, 4).ToString()})M[确定是否是完整数据帧的边界]", label2.M); | |||||
writer.WriteString($"({label2Span.Slice(4).ToString()})PT[负载类型]", label2.PT.ToString()); | |||||
writer.WriteEndObject(); | |||||
var val2 = jT1078MessagePackReader.ReadByte(); | |||||
var label2 = new JT1078Label2(val2); | |||||
var label2Span = val2.ReadBinary(); | |||||
writer.WriteStartObject($"[{label2Span.ToString()}]object2[{val2.ReadNumber()}]"); | |||||
writer.WriteNumber($"({label2Span.Slice(0, 4).ToString()})M[确定是否是完整数据帧的边界]", label2.M); | |||||
writer.WriteString($"({label2Span.Slice(4).ToString()})PT[负载类型]", label2.PT.ToString()); | |||||
writer.WriteEndObject(); | |||||
var sn = jT1078MessagePackReader.ReadUInt16(); | |||||
writer.WriteNumber($"{sn.ReadNumber()}[序列号]", sn); | |||||
var sim = jT1078MessagePackReader.ReadBCD(12); | |||||
writer.WriteString($"[终端设备SIM卡号]", sim); | |||||
var logicChannelNumber = jT1078MessagePackReader.ReadByte(); | |||||
writer.WriteNumber($"{logicChannelNumber.ReadNumber()}[逻辑通道号]", logicChannelNumber); | |||||
var sn = jT1078MessagePackReader.ReadUInt16(); | |||||
writer.WriteNumber($"{sn.ReadNumber()}[序列号]", sn); | |||||
var sim = jT1078MessagePackReader.ReadBCD(12); | |||||
writer.WriteString($"[终端设备SIM卡号]", sim); | |||||
var logicChannelNumber = jT1078MessagePackReader.ReadByte(); | |||||
writer.WriteNumber($"{logicChannelNumber.ReadNumber()}[逻辑通道号]", logicChannelNumber); | |||||
var val3 = jT1078MessagePackReader.ReadByte(); | |||||
var label3 = new JT1078Label3(val3); | |||||
var label3Span = val3.ReadBinary(); | |||||
writer.WriteStartObject($"[{label3Span.ToString()}]object3[{val3.ReadNumber()}]"); | |||||
writer.WriteString($"({label3Span.Slice(0, 4).ToString()})[数据类型]", label3.DataType.ToString()); | |||||
writer.WriteString($"({label3Span.Slice(4).ToString()})[分包处理标记]", label3.SubpackageType.ToString()); | |||||
writer.WriteEndObject(); | |||||
if (label3.DataType != JT1078DataType.透传数据) | |||||
{ | |||||
var timestamp = jT1078MessagePackReader.ReadUInt64(); | |||||
writer.WriteNumber($"{timestamp.ReadNumber()}[标识此RTP数据包当前帧的相对时间,单位毫秒(ms)]", timestamp); | |||||
} | |||||
if (label3.DataType != JT1078DataType.透传数据 && | |||||
label3.DataType != JT1078DataType.音频帧) | |||||
{ | |||||
var lastIFrameInterval = jT1078MessagePackReader.ReadUInt16(); | |||||
writer.WriteNumber($"{lastIFrameInterval.ReadNumber()}[该帧与上一个关键帧之间的时间间隔,单位毫秒(ms)]", lastIFrameInterval); | |||||
var lastFrameInterval = jT1078MessagePackReader.ReadUInt16(); | |||||
writer.WriteNumber($"{lastFrameInterval.ReadNumber()}[该帧与上一个关键帧之间的时间间隔,单位毫秒(ms)]", lastFrameInterval); | |||||
} | |||||
var dataBodyLength = jT1078MessagePackReader.ReadUInt16(); | |||||
writer.WriteNumber($"{dataBodyLength.ReadNumber()}[数据体长度]", dataBodyLength); | |||||
var bodies = jT1078MessagePackReader.ReadRemainArray().ToArray(); | |||||
writer.WriteString("[数据体]", string.Join(" ", (bodies).Select(p => p.ToString("X2")))); | |||||
writer.WriteEndObject(); | |||||
writer.Flush(); | |||||
return memoryStream.ToArray(); | |||||
var val3 = jT1078MessagePackReader.ReadByte(); | |||||
var label3 = new JT1078Label3(val3); | |||||
var label3Span = val3.ReadBinary(); | |||||
writer.WriteStartObject($"[{label3Span.ToString()}]object3[{val3.ReadNumber()}]"); | |||||
writer.WriteString($"({label3Span.Slice(0, 4).ToString()})[数据类型]", label3.DataType.ToString()); | |||||
writer.WriteString($"({label3Span.Slice(4).ToString()})[分包处理标记]", label3.SubpackageType.ToString()); | |||||
writer.WriteEndObject(); | |||||
if (label3.DataType != JT1078DataType.透传数据) | |||||
{ | |||||
var timestamp = jT1078MessagePackReader.ReadUInt64(); | |||||
writer.WriteNumber($"{timestamp.ReadNumber()}[标识此RTP数据包当前帧的相对时间,单位毫秒(ms)]", timestamp); | |||||
} | } | ||||
} | |||||
finally | |||||
{ | |||||
JT1078ArrayPool.Return(buffer); | |||||
if (label3.DataType != JT1078DataType.透传数据 && | |||||
label3.DataType != JT1078DataType.音频帧) | |||||
{ | |||||
var lastIFrameInterval = jT1078MessagePackReader.ReadUInt16(); | |||||
writer.WriteNumber($"{lastIFrameInterval.ReadNumber()}[该帧与上一个关键帧之间的时间间隔,单位毫秒(ms)]", lastIFrameInterval); | |||||
var lastFrameInterval = jT1078MessagePackReader.ReadUInt16(); | |||||
writer.WriteNumber($"{lastFrameInterval.ReadNumber()}[该帧与上一个关键帧之间的时间间隔,单位毫秒(ms)]", lastFrameInterval); | |||||
} | |||||
var dataBodyLength = jT1078MessagePackReader.ReadUInt16(); | |||||
writer.WriteNumber($"{dataBodyLength.ReadNumber()}[数据体长度]", dataBodyLength); | |||||
var bodies = jT1078MessagePackReader.ReadRemainArray().ToArray(); | |||||
writer.WriteString("[数据体]", string.Join(" ", (bodies).Select(p => p.ToString("X2")))); | |||||
writer.WriteEndObject(); | |||||
writer.Flush(); | |||||
return memoryStream.ToArray(); | |||||
} | } | ||||
} | } | ||||
public static string Analyze(ReadOnlySpan<byte> bytes,JsonWriterOptions options = default, int minBufferSize = 8096) | |||||
public static string Analyze(ReadOnlySpan<byte> bytes,JsonWriterOptions options = default) | |||||
{ | { | ||||
string json = Encoding.UTF8.GetString(AnalyzeJsonBuffer(bytes, options, minBufferSize)); | |||||
string json = Encoding.UTF8.GetString(AnalyzeJsonBuffer(bytes, options)); | |||||
return json; | return json; | ||||
} | } | ||||
} | } | ||||
@@ -34,9 +34,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT1078.Hls", "JT1078.Hls\JT | |||||
EndProject | EndProject | ||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT1078.Hls.Test", "JT1078.Hls.Test\JT1078.Hls.Test.csproj", "{5564C20B-BFF4-4A2A-BDF2-C7427E93E993}" | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT1078.Hls.Test", "JT1078.Hls.Test\JT1078.Hls.Test.csproj", "{5564C20B-BFF4-4A2A-BDF2-C7427E93E993}" | ||||
EndProject | EndProject | ||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT1078.FMp4", "JT1078.FMp4\JT1078.FMp4.csproj", "{73F13894-0967-422C-8AC3-5EEF9189AAFC}" | |||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT1078.FMp4", "JT1078.FMp4\JT1078.FMp4.csproj", "{73F13894-0967-422C-8AC3-5EEF9189AAFC}" | |||||
EndProject | EndProject | ||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JT1078.FMp4.Test", "JT1078.FMp4.Test\JT1078.FMp4.Test.csproj", "{56E76D56-4CCC-401F-B25D-9AB41D58A10A}" | |||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT1078.FMp4.Test", "JT1078.FMp4.Test\JT1078.FMp4.Test.csproj", "{56E76D56-4CCC-401F-B25D-9AB41D58A10A}" | |||||
EndProject | EndProject | ||||
Global | Global | ||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||||