Browse Source

1.组装测试fmp4盒子

2.升级808库
pull/13/head
SmallChi(Koike) 4 years ago
parent
commit
347d1dfb07
12 changed files with 335 additions and 48 deletions
  1. +58
    -0
      src/JT1078.FMp4.Test/Boxs/AVCConfigurationBoxTest.cs
  2. +67
    -17
      src/JT1078.FMp4.Test/FMp4Box_Test.cs
  3. +79
    -0
      src/JT1078.FMp4.Test/Samples/AVC1SampleEntryTest.cs
  4. +37
    -13
      src/JT1078.FMp4/Boxs/AVCConfigurationBox.cs
  5. +6
    -0
      src/JT1078.FMp4/Boxs/MovieExtendsBox.cs
  6. +31
    -2
      src/JT1078.FMp4/Boxs/SampleSizeBox.cs
  7. +8
    -2
      src/JT1078.FMp4/Boxs/SampleTableBox.cs
  8. +8
    -0
      src/JT1078.FMp4/Boxs/TrackExtendsBox.cs
  9. +17
    -0
      src/JT1078.FMp4/JT1078.FMp4.xml
  10. +7
    -1
      src/JT1078.FMp4/Samples/AVC1SampleEntry.cs
  11. +15
    -11
      src/JT1078.FMp4/Samples/VisualSampleEntry.cs
  12. +2
    -2
      src/JT808.Protocol.Extensions.JT1078/JT808.Protocol.Extensions.JT1078.csproj

+ 58
- 0
src/JT1078.FMp4.Test/Boxs/AVCConfigurationBoxTest.cs View File

@@ -0,0 +1,58 @@
using JT1078.FMp4.MessagePack;
using JT1078.Protocol.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;

namespace JT1078.FMp4.Test.Boxs
{
public class AVCConfigurationBoxTest
{
/// <summary>
/// 使用doc/video/fragmented_demo.mp4
/// </summary>
[Fact]
public void Test1()
{
//0000002f617663430164001fffe100176764001facd940881e684000f4240037b40883c60c658001000568efbcb000
//00 00 00 2f
//61 76 63 43
//01
//64
//00
//1f
//ff
//e1 numOfSequenceParameterSets 1
//00 17
//67 64 00 1f
//ac d9 40 88
//1e 68 40 00
//f4 24 00 37
//b4 08 83 c6
//0c 65 80
//01 NumOfPictureParameterSets 1
//00 05
//68 ef bc b0 00
AVCConfigurationBox aVCConfigurationBox = new AVCConfigurationBox();
aVCConfigurationBox.AVCProfileIndication = 0x64;
aVCConfigurationBox.ProfileCompatibility = 0;
aVCConfigurationBox.AVCLevelIndication = 0x1f;
aVCConfigurationBox.LengthSizeMinusOne = 0xff;
aVCConfigurationBox.SPSs = new List<byte[]>()
{
"6764001facd940881e684000f4240037b40883c60c6580".ToHexBytes()
};
aVCConfigurationBox.PPSs = new List<byte[]>()
{
"68efbcb000".ToHexBytes()
};
FMp4MessagePackWriter writer = new FMp4MessagePackWriter(new byte[0x0000002f]);
aVCConfigurationBox.ToBuffer(ref writer);
var hex = writer.FlushAndGetArray().ToHexString();
Assert.Equal("0000002f617663430164001fffe100176764001facd940881e684000f4240037b40883c60c658001000568efbcb000".ToUpper(), hex);
}
}
}

+ 67
- 17
src/JT1078.FMp4.Test/FMp4Box_Test.cs View File

@@ -4,6 +4,8 @@ using System.Collections.Generic;
using System.Text;
using Xunit;
using JT1078.Protocol.Extensions;
using JT1078.FMp4.Enums;
using JT1078.FMp4.Samples;

namespace JT1078.FMp4.Test
{
@@ -49,8 +51,8 @@ namespace JT1078.FMp4.Test
/// <summary>
/// 使用doc/video/fragmented_demo.mp4
/// </summary>
[Fact(DisplayName = "trak_tkhd")]
public void trak_tkhd_test()
[Fact(DisplayName = "moov_trak_tkhd")]
public void moov_trak_tkhd_test()
{
TrackHeaderBox trackHeaderBox = new TrackHeaderBox(0,3);
trackHeaderBox.CreationTime = 0;
@@ -67,8 +69,8 @@ namespace JT1078.FMp4.Test
/// <summary>
/// 使用doc/video/fragmented_demo.mp4
/// </summary>
[Fact(DisplayName = "trak_mdia")]
public void trak_mdia_test()
[Fact(DisplayName = "moov_trak_mdia")]
public void moov_trak_mdia_test()
{


@@ -76,8 +78,8 @@ namespace JT1078.FMp4.Test
/// <summary>
/// 使用doc/video/fragmented_demo.mp4
/// </summary>
[Fact(DisplayName = "trak_mdia_mdhd")]
public void trak_mdia_mdhd_test()
[Fact(DisplayName = "moov_trak_mdia_mdhd")]
public void moov_trak_mdia_mdhd_test()
{
MediaHeaderBox mediaHeaderBox = new MediaHeaderBox(0, 0);
@@ -104,8 +106,8 @@ namespace JT1078.FMp4.Test
/// <summary>
/// 使用doc/video/fragmented_demo.mp4
/// </summary>
[Fact(DisplayName = "trak_mdia_hdlr")]
public void trak_mdia_hdlr_test()
[Fact(DisplayName = "moov_trak_mdia_hdlr")]
public void moov_trak_mdia_hdlr_test()
{
HandlerBox handlerBox = new HandlerBox(0, 0);
handlerBox.HandlerType = Enums.HandlerType.vide;
@@ -118,8 +120,8 @@ namespace JT1078.FMp4.Test
/// <summary>
/// 使用doc/video/fragmented_demo.mp4
/// </summary>
[Fact(DisplayName = "trak_mdia_hdlr_minf")]
public void trak_mdia_hdlr_minf_test()
[Fact(DisplayName = "moov_trak_mdia_hdlr_minf")]
public void moov_trak_mdia_hdlr_minf_test()
{
HandlerBox handlerBox = new HandlerBox(0, 0);
handlerBox.HandlerType = Enums.HandlerType.vide;
@@ -132,8 +134,8 @@ namespace JT1078.FMp4.Test
/// <summary>
/// 使用doc/video/fragmented_demo.mp4
/// </summary>
[Fact(DisplayName = "trak_mdia_hdlr_minf_vmhd")]
public void trak_mdia_hdlr_minf_vmhd_test()
[Fact(DisplayName = "moov_trak_mdia_hdlr_minf_vmhd")]
public void moov_trak_mdia_hdlr_minf_vmhd_test()
{
VideoMediaHeaderBox videoMediaHeaderBox = new VideoMediaHeaderBox();
FMp4MessagePackWriter writer = new MessagePack.FMp4MessagePackWriter(new byte[10240]);
@@ -144,8 +146,8 @@ namespace JT1078.FMp4.Test
/// <summary>
/// 使用doc/video/fragmented_demo.mp4
/// </summary>
[Fact(DisplayName = "trak_mdia_hdlr_minf_dinf")]
public void trak_mdia_hdlr_minf_dinf_test()
[Fact(DisplayName = "moov_trak_mdia_hdlr_minf_dinf")]
public void moov_trak_mdia_hdlr_minf_dinf_test()
{
DataInformationBox dataInformationBox = new DataInformationBox();
DataReferenceBox dataReferenceBox = new DataReferenceBox();
@@ -161,10 +163,58 @@ namespace JT1078.FMp4.Test
/// <summary>
/// 使用doc/video/fragmented_demo.mp4
/// </summary>
[Fact(DisplayName = "trak_mdia_hdlr_minf_stbl")]
public void trak_mdia_hdlr_minf_stbl_test()
[Fact(DisplayName = "moov_trak_mdia_hdlr_minf_stbl")]
public void moov_trak_mdia_hdlr_minf_stbl_test()
{
//000000e17374626c000000957374736400000000000000010000008561766331000000000000000100000000000000000000000000000000022003c0004800000048000000000000000100000000000000000000000000000000000000000000000000000000000000000018ffff0000002f617663430164001fffe100176764001facd940881e684000f4240037b40883c60c658001000568efbcb0000000001073747473000000000000000000000010737473630000000000000000000000147374737a000000000000000000000000000000107374636f0000000000000000
//stbl
SampleTableBox sampleTableBox = new SampleTableBox();
//stbl->stsd
SampleDescriptionBox sampleDescriptionBox = new SampleDescriptionBox(HandlerType.none);
//stbl->stsd->avc1
AVC1SampleEntry aVC1SampleEntry = new AVC1SampleEntry();
aVC1SampleEntry.Width = 0x0220;
aVC1SampleEntry.Height = 0x03c0;
//stbl->stsd->avc1->avcc
AVCConfigurationBox aVCConfigurationBox = new AVCConfigurationBox();
aVCConfigurationBox.AVCProfileIndication = 0x64;
aVCConfigurationBox.ProfileCompatibility = 0;
aVCConfigurationBox.AVCLevelIndication = 0x1f;
aVCConfigurationBox.LengthSizeMinusOne = 0xff;
aVCConfigurationBox.SPSs = new List<byte[]>()
{
"6764001facd940881e684000f4240037b40883c60c6580".ToHexBytes()
};
aVCConfigurationBox.PPSs = new List<byte[]>()
{
"68efbcb000".ToHexBytes()
};
aVC1SampleEntry.AVCConfigurationBox = aVCConfigurationBox;
sampleDescriptionBox.SampleEntries = new List<SampleEntry>()
{
aVC1SampleEntry
};
sampleTableBox.SampleDescriptionBox = sampleDescriptionBox;
//stbl->stts
sampleTableBox.TimeToSampleBox = new TimeToSampleBox();
//stbl->stsc
sampleTableBox.SampleToChunkBox = new SampleToChunkBox();
//stbl->stsz
sampleTableBox.SampleSizeBox = new SampleSizeBox();
//stbl->stco
sampleTableBox.ChunkOffsetBox = new ChunkOffsetBox();
FMp4MessagePackWriter writer = new MessagePack.FMp4MessagePackWriter(new byte[0x000000e1]);
sampleTableBox.ToBuffer(ref writer);
var hex = writer.FlushAndGetArray().ToHexString();
Assert.Equal("000000e17374626c000000957374736400000000000000010000008561766331000000000000000100000000000000000000000000000000022003c0004800000048000000000000000100000000000000000000000000000000000000000000000000000000000000000018ffff0000002f617663430164001fffe100176764001facd940881e684000f4240037b40883c60c658001000568efbcb0000000001073747473000000000000000000000010737473630000000000000000000000147374737a000000000000000000000000000000107374636f0000000000000000".ToUpper(), hex);
}
/// <summary>
/// 使用doc/video/fragmented_demo.mp4
/// </summary>
[Fact(DisplayName = "moov_mvex")]
public void trak_mvex_test()
{
//todo:moov_mvex
}
}
}

+ 79
- 0
src/JT1078.FMp4.Test/Samples/AVC1SampleEntryTest.cs View File

@@ -0,0 +1,79 @@
using JT1078.FMp4.MessagePack;
using JT1078.FMp4.Samples;
using JT1078.Protocol.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;

namespace JT1078.FMp4.Test.Samples
{
public class AVC1SampleEntryTest
{
/// <summary>
/// 使用doc/video/fragmented_demo.mp4
/// </summary>
[Fact]
public void Test1()
{
//0000008561766331000000000000000100000000000000000000000000000000022003C0004800000048000000000000000100000000000000000000000000000000000000000000000000000000000000000018FFFF0000002F617663430164001FFFE100176764001FACD940881E684000F4240037B40883C60C658001000568EFBCB000
//1.avc1
//0000008561766331000000000000000100000000000000000000000000000000022003C0004800000048000000000000000100000000000000000000000000000000000000000000000000000000000000000018FFFF
//2.avc1->avcc
//0000002F617663430164001FFFE100176764001FACD940881E684000F4240037B40883C60C658001000568EFBCB000
//0000008561766331000000000000000100000000000000000000000000000000022003c0004800000048000000000000000100000000000000000000000000000000000000000000000000000000000000000018ffff
//-------------avc1
//00 00 00 85
//61 76 63 31
//00 00 00
//00 00 00
//00 01
//00 00
//00 00
//00 00 00 00
//00 00 00 00
//00 00 00 00
//02 20
//03 c0
//00 48 00 00
//00 48 00 00
//00 00 00 00
//00 01
//00
//00 00 00 00
//00 00 00 00
//00 00 00 00
//00 00 00 00
//00 00 00 00
//00 00 00 00
//00 00 00 00
//00 00 00
//00 18
//ff ff
AVC1SampleEntry aVC1SampleEntry = new AVC1SampleEntry();
aVC1SampleEntry.Width = 0x0220;
aVC1SampleEntry.Height = 0x03c0;
AVCConfigurationBox aVCConfigurationBox = new AVCConfigurationBox();
aVCConfigurationBox.AVCProfileIndication = 0x64;
aVCConfigurationBox.ProfileCompatibility = 0;
aVCConfigurationBox.AVCLevelIndication = 0x1f;
aVCConfigurationBox.LengthSizeMinusOne = 0xff;
aVCConfigurationBox.SPSs = new List<byte[]>()
{
"6764001facd940881e684000f4240037b40883c60c6580".ToHexBytes()
};
aVCConfigurationBox.PPSs = new List<byte[]>()
{
"68efbcb000".ToHexBytes()
};
aVC1SampleEntry.AVCConfigurationBox = aVCConfigurationBox;
FMp4MessagePackWriter writer = new FMp4MessagePackWriter(new byte[0x00000085]);
aVC1SampleEntry.ToBuffer(ref writer);
var hex = writer.FlushAndGetArray().ToHexString();
Assert.Equal("0000008561766331000000000000000100000000000000000000000000000000022003C0004800000048000000000000000100000000000000000000000000000000000000000000000000000000000000000018FFFF0000002F617663430164001FFFE100176764001FACD940881E684000F4240037B40883C60C658001000568EFBCB000".ToUpper(), hex);
}
}
}

+ 37
- 13
src/JT1078.FMp4/Boxs/AVCConfigurationBox.cs View File

@@ -45,17 +45,15 @@ namespace JT1078.FMp4
//bit(8*pictureParameterSetLength) pictureParameterSetNALUnit;
//}
//}
public byte ConfigurationVersion { get; set; } = 1;
private byte ConfigurationVersion { get; set; } = 1;
public byte AVCProfileIndication { get; set; }
public byte ProfileCompatibility { get; set; }
public byte AVCLevelIndication { get; set; }
public int LengthSizeMinusOne { get; set; }
public int NumOfSequenceParameterSets { get; set; }
//public List<(ushort SequenceParameterSetLength,byte[] SequenceParameterSetNALUnit)> SPS { get; set; }
public byte[] SPSBuffer { get; set; }
public byte NumOfPictureParameterSets { get; set; } = 1;
//public List<(ushort PictureParameterSetLength,byte[] PictureParameterSetNALUnit)> PPS { get; set; }
public byte[] PPSBuffer { get; set; }
//private byte NumOfSequenceParameterSets { get; set; }
public List<byte[]> SPSs { get; set; }
//private byte NumOfPictureParameterSets { get; set; } = 1;
public List<byte[]> PPSs { get; set; }

public void ToBuffer(ref FMp4MessagePackWriter writer)
{
@@ -65,12 +63,38 @@ namespace JT1078.FMp4
writer.WriteByte(ProfileCompatibility);
writer.WriteByte(AVCLevelIndication);
writer.WriteByte((byte)(0xfc | LengthSizeMinusOne));
writer.WriteByte((byte)(0xE0 | NumOfSequenceParameterSets));
writer.WriteUInt16((ushort)SPSBuffer.Length);
writer.WriteArray(SPSBuffer);
writer.WriteByte(NumOfPictureParameterSets);
writer.WriteUInt16((ushort)PPSBuffer.Length);
writer.WriteArray(PPSBuffer);
if (SPSs!=null && SPSs.Count > 0)
{
//NumOfSequenceParameterSets
writer.WriteByte((byte)(0xE0 | SPSs.Count));
foreach(var sps in SPSs)
{
//SequenceParameterSetLength
writer.WriteUInt16((ushort)sps.Length);
writer.WriteArray(sps);
}
}
else
{
//NumOfSequenceParameterSets
writer.WriteByte(0xE0);
}
if (PPSs != null && PPSs.Count > 0)
{
//NumOfPictureParameterSets
writer.WriteByte((byte)PPSs.Count);
foreach (var pps in PPSs)
{
//PictureParameterSetLength
writer.WriteUInt16((ushort)pps.Length);
writer.WriteArray(pps);
}
}
else
{
//NumOfPictureParameterSets
writer.WriteByte(0);
}
End(ref writer);
}
}


+ 6
- 0
src/JT1078.FMp4/Boxs/MovieExtendsBox.cs View File

@@ -17,7 +17,13 @@ namespace JT1078.FMp4
public MovieExtendsBox() : base("mvex")
{
}
/// <summary>
/// mehd
/// </summary>
public MovieExtendsHeaderBox MovieExtendsHeaderBox { get; set; }
/// <summary>
/// trex
/// </summary>
public List<TrackExtendsBox> TrackExtendsBoxs { get; set; }

public void ToBuffer(ref FMp4MessagePackWriter writer)


+ 31
- 2
src/JT1078.FMp4/Boxs/SampleSizeBox.cs View File

@@ -1,11 +1,21 @@
using System;
using JT1078.FMp4.Interfaces;
using JT1078.FMp4.MessagePack;
using System;
using System.Collections.Generic;
using System.Text;

namespace JT1078.FMp4
{
public class SampleSizeBox : FullBox
/// <summary>
/// stsz
/// </summary>
public class SampleSizeBox : FullBox, IFMp4MessagePackFormatter
{
/// <summary>
/// stsz
/// </summary>
/// <param name="version"></param>
/// <param name="flags"></param>
public SampleSizeBox(byte version=0, uint flags=0) : base("stsz", version, flags)
{
}
@@ -17,5 +27,24 @@ namespace JT1078.FMp4
/// length:sample_count
/// </summary>
public List<uint> EntrySize { get; set; }
public void ToBuffer(ref FMp4MessagePackWriter writer)
{
Start(ref writer);
WriterFullBoxToBuffer(ref writer);
writer.WriteUInt32(SampleSize);
if (EntrySize != null && EntrySize.Count > 0)
{
writer.WriteUInt32((uint)EntrySize.Count);
foreach (var item in EntrySize)
{
writer.WriteUInt32(item);
}
}
else
{
writer.WriteUInt32(0);
}
End(ref writer);
}
}
}

+ 8
- 2
src/JT1078.FMp4/Boxs/SampleTableBox.cs View File

@@ -33,7 +33,10 @@ namespace JT1078.FMp4
/// stsc
/// </summary>
public SampleToChunkBox SampleToChunkBox { get; set; }
//public SampleSizeBox SampleSizeBox { get; set; }
/// <summary>
/// stsz
/// </summary>
public SampleSizeBox SampleSizeBox { get; set; }
//public CompactSampleSizeBox CompactSampleSizeBox { get; set; }
/// <summary>
/// stco
@@ -54,8 +57,11 @@ namespace JT1078.FMp4
Start(ref writer);
SampleDescriptionBox.ToBuffer(ref writer);
TimeToSampleBox.ToBuffer(ref writer);
CompositionOffsetBox.ToBuffer(ref writer);
if(CompositionOffsetBox!=null)
CompositionOffsetBox.ToBuffer(ref writer);
SampleToChunkBox.ToBuffer(ref writer);
if (SampleSizeBox != null)
SampleSizeBox.ToBuffer(ref writer);
ChunkOffsetBox.ToBuffer(ref writer);
End(ref writer);
}


+ 8
- 0
src/JT1078.FMp4/Boxs/TrackExtendsBox.cs View File

@@ -6,8 +6,16 @@ using System.Text;

namespace JT1078.FMp4
{
/// <summary>
/// trex
/// </summary>
public class TrackExtendsBox : FullBox, IFMp4MessagePackFormatter
{
/// <summary>
/// trex
/// </summary>
/// <param name="version"></param>
/// <param name="flags"></param>
public TrackExtendsBox(byte version=0, uint flags=0) : base("trex", version, flags)
{
}


+ 17
- 0
src/JT1078.FMp4/JT1078.FMp4.xml View File

@@ -545,6 +545,18 @@
if (version==1)
</summary>
</member>
<member name="T:JT1078.FMp4.SampleSizeBox">
<summary>
stsz
</summary>
</member>
<member name="M:JT1078.FMp4.SampleSizeBox.#ctor(System.Byte,System.UInt32)">
<summary>
stsz
</summary>
<param name="version"></param>
<param name="flags"></param>
</member>
<member name="P:JT1078.FMp4.SampleSizeBox.EntrySize">
<summary>
if (sample_size==0)
@@ -581,6 +593,11 @@
stsc
</summary>
</member>
<member name="P:JT1078.FMp4.SampleTableBox.SampleSizeBox">
<summary>
stsz
</summary>
</member>
<member name="P:JT1078.FMp4.SampleTableBox.ChunkOffsetBox">
<summary>
stco


+ 7
- 1
src/JT1078.FMp4/Samples/AVC1SampleEntry.cs View File

@@ -15,6 +15,8 @@ namespace JT1078.FMp4.Samples
/// </summary>
public AVC1SampleEntry() : base("avc1")
{
DataReferenceIndex = 1;
PreDefined3 = 0xffff;
}
/// <summary>
/// avcC
@@ -28,8 +30,12 @@ namespace JT1078.FMp4.Samples
public override void ToBuffer(ref FMp4MessagePackWriter writer)
{
Start(ref writer);
WriterSampleEntryToBuffer(ref writer);
WriterVisualSampleEntryToBuffer(ref writer);
AVCConfigurationBox.ToBuffer(ref writer);
if (AVCConfigurationBox != null)
{
AVCConfigurationBox.ToBuffer(ref writer);
}
if (MPEG4BitRateBox != null)
{
MPEG4BitRateBox.ToBuffer(ref writer);


+ 15
- 11
src/JT1078.FMp4/Samples/VisualSampleEntry.cs View File

@@ -10,6 +10,7 @@ namespace JT1078.FMp4.Samples
/// </summary>
public abstract class VisualSampleEntry : SampleEntry
{
const string COMPRESSORNAME = "jt1078&SmallChi(koike)&TK";
/// <summary>
/// VisualSampleEntry
/// </summary>
@@ -27,9 +28,13 @@ namespace JT1078.FMp4.Samples
public uint VertreSolution { get; set; }= 0x00480000;
public uint Reserved3{ get; set; }
public ushort FrameCount { get; set; } = 1;
#if DEBUG
public string CompressorName { get; set; }
#else
public string CompressorName { get; set; } = COMPRESSORNAME;
#endif
public ushort Depth { get; set; } = 0x0018;
public short PreDefined3 { get; set; } = 0x1111;
public ushort PreDefined3 { get; set; } = 0x1111;
/// <summary>
/// clap
/// optional
@@ -61,19 +66,18 @@ namespace JT1078.FMp4.Samples
writer.WriteUInt16(FrameCount);
if (string.IsNullOrEmpty(CompressorName))
{
CompressorName = "";
//CompressorNameLength
writer.WriteByte(0);
writer.WriteArray(new byte[31]);
}
writer.WriteUTF8(CompressorName.PadLeft(32, '\0'));
writer.WriteUInt16(Depth);
writer.WriteInt16(PreDefined3);
if (Clap != null)
{
Clap.ToBuffer(ref writer);
}
if (Pasp != null)
else
{
Pasp.ToBuffer(ref writer);
//CompressorNameLength
writer.WriteByte((byte)CompressorName.Length);
writer.WriteUTF8(CompressorName.PadRight(31, '\0'));
}
writer.WriteUInt16(Depth);
writer.WriteUInt16(PreDefined3);
}
}
}

+ 2
- 2
src/JT808.Protocol.Extensions.JT1078/JT808.Protocol.Extensions.JT1078.csproj View File

@@ -15,14 +15,14 @@
<licenseUrl>https://github.com/SmallChi/JT1078/blob/master/LICENSE</licenseUrl>
<license>https://github.com/SmallChi/JT1078/blob/master/LICENSE</license>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Version>2.3.0</Version>
<Version>2.3.1</Version>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<DocumentationFile>JT808.Protocol.Extensions.JT1078.xml</DocumentationFile>
</PropertyGroup>


<ItemGroup>
<PackageReference Include="JT808" Version="2.3.0" />
<PackageReference Include="JT808" Version="2.3.1" />
</ItemGroup>

<ItemGroup>


Loading…
Cancel
Save