@@ -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() | |||
{ | |||
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" | |||
/// </summary> | |||
public static partial class JT808BinaryExtensions | |||
internal static partial class JT808BinaryExtensions | |||
{ | |||
public static string ToHexString(this byte[] source) | |||
{ | |||
@@ -15,9 +15,7 @@ | |||
<PackageReference Include="System.Memory" Version="4.5.4" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<ProjectReference Include="..\JT1078.Flv.Benchmark\JT1078.Flv.Benchmark.csproj" /> | |||
<ProjectReference Include="..\JT1078.Flv\JT1078.Flv.csproj" /> | |||
<ProjectReference Include="..\JT1078.Protocol\JT1078.Protocol.csproj" /> | |||
</ItemGroup> | |||
</Project> |
@@ -7,7 +7,7 @@ using JT1078.Flv.MessagePack; | |||
using JT1078.Protocol; | |||
using JT1078.Protocol.H264; | |||
using JT1078.Protocol.MessagePack; | |||
using JT808.Protocol.Extensions; | |||
using JT1078.Protocol.Extensions; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.IO; | |||
@@ -78,7 +78,7 @@ namespace JT1078.Flv.Benchmark | |||
{ | |||
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.Jobs; | |||
using BenchmarkDotNet.Toolchains.CsProj; | |||
using JT808.Protocol.Extensions; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using JT1078.Protocol.Extensions; | |||
namespace JT1078.Protocol.Benchmark | |||
{ | |||
@@ -58,7 +58,7 @@ namespace JT1078.Protocol.Benchmark | |||
{ | |||
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> | |||
<license>https://github.com/SmallChi/JT1078/blob/master/LICENSE</license> | |||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> | |||
<Version>1.0.4-preview1</Version> | |||
<Version>1.0.4-preview2</Version> | |||
<SignAssembly>false</SignAssembly> | |||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance> | |||
<PackageLicenseFile>LICENSE</PackageLicenseFile> | |||
@@ -115,80 +115,72 @@ namespace JT1078.Protocol | |||
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; | |||
} | |||
} | |||
@@ -34,9 +34,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT1078.Hls", "JT1078.Hls\JT | |||
EndProject | |||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT1078.Hls.Test", "JT1078.Hls.Test\JT1078.Hls.Test.csproj", "{5564C20B-BFF4-4A2A-BDF2-C7427E93E993}" | |||
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 | |||
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 | |||
Global | |||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | |||