Browse Source

Merge branch 'SmallChi:master' into master

pull/14/head
Pangpang Don 3 years ago
committed by GitHub
parent
commit
9cc18d002c
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
100 changed files with 22388 additions and 4226 deletions
  1. +0
    -8
      .github/workflows/dotnetcore.yml
  2. +1
    -102
      README.md
  3. +9
    -1
      doc/ffmpeginfo.txt
  4. BIN
      doc/tools/SpecialVH264_jb51/SpecialVH264_1.1.exe
  5. +2
    -0
      doc/tools/SpecialVH264_jb51/configure.ini
  6. BIN
      doc/video/JT1078_5.flv
  7. BIN
      doc/video/JT1078_6_8.mp4
  8. BIN
      doc/video/fragmented_base_moof_demo.mp4
  9. BIN
      doc/video/jt1078_5.h264
  10. +17215
    -0
      doc/video/jt1078_5.txt
  11. +3287
    -0
      doc/video/jt1078_6.txt
  12. BIN
      doc/video/test_1920x1080.h264
  13. +4
    -0
      src/JT1078.AV.Benchmark/JT1078.AV.Benchmark.csproj
  14. +132
    -0
      src/JT1078.AV.Benchmark/JT1078AVEncoderContext.cs
  15. +0
    -76
      src/JT1078.AV.Benchmark/JT1078FlvEncoderContext.cs
  16. +1
    -1
      src/JT1078.AV.Benchmark/Program.cs
  17. +1
    -1
      src/JT1078.FMp4.Test/FMp4Box_Test.cs
  18. +3
    -0
      src/JT1078.FMp4.Test/H264/.vscode/settings.json
  19. +190
    -33
      src/JT1078.FMp4.Test/H264/index.html
  20. +17
    -0
      src/JT1078.FMp4.Test/H264/signalr.min.js
  21. +6
    -0
      src/JT1078.FMp4.Test/JT1078.FMp4.Test.csproj
  22. +217
    -24
      src/JT1078.FMp4.Test/JT1078ToFMp4Box_Test.cs
  23. +4
    -1
      src/JT1078.FMp4/Boxs/MovieBox.cs
  24. +6
    -0
      src/JT1078.FMp4/Boxs/MovieFragmentBox.cs
  25. +1
    -1
      src/JT1078.FMp4/Boxs/MovieFragmentRandomAccessBox.cs
  26. +8
    -10
      src/JT1078.FMp4/Boxs/SampleDependencyTypeBox.cs
  27. +3
    -5
      src/JT1078.FMp4/Boxs/SampleDescriptionBox.cs
  28. +8
    -1
      src/JT1078.FMp4/Boxs/SampleTableBox.cs
  29. +91
    -19
      src/JT1078.FMp4/Boxs/SegmentIndexBox.cs
  30. +51
    -0
      src/JT1078.FMp4/Boxs/SegmentTypeBox.cs
  31. +33
    -4
      src/JT1078.FMp4/Boxs/SyncSampleBox.cs
  32. +11
    -1
      src/JT1078.FMp4/Boxs/TrackFragmentHeaderBox.cs
  33. +21
    -5
      src/JT1078.FMp4/Boxs/TrackRunBox.cs
  34. +160
    -44
      src/JT1078.FMp4/FMp4Encoder.cs
  35. +3
    -5
      src/JT1078.FMp4/JT1078.FMp4.csproj
  36. +119
    -11
      src/JT1078.FMp4/JT1078.FMp4.xml
  37. +23
    -1
      src/JT1078.FMp4/MessagePack/FMp4MessagePackWriter.cs
  38. +7
    -4
      src/JT1078.Flv/FlvEncoder.cs
  39. +1
    -1
      src/JT1078.Flv/JT1078.Flv.csproj
  40. +5
    -0
      src/JT1078.Flv/JT1078.Flv.xml
  41. +3
    -0
      src/JT1078.Hls.Test/JT1078.Hls.Test.csproj
  42. +44
    -1
      src/JT1078.Hls.Test/M3U8_Test.cs
  43. +6
    -6
      src/JT1078.Hls.Test/TS_Package_Test.cs
  44. +5
    -6
      src/JT1078.Hls/JT1078.Hls.csproj
  45. +44
    -0
      src/JT1078.Hls/JT1078.Hls.xml
  46. +52
    -23
      src/JT1078.Hls/M3U8FileManage.cs
  47. +9
    -1
      src/JT1078.Hls/Options/M3U8Option.cs
  48. +7
    -4
      src/JT1078.Hls/TSEncoder.cs
  49. +0
    -84
      src/JT1078.Protocol.Benchmark/JT1078FlvEncoderContext.cs
  50. +47
    -5
      src/JT1078.Protocol.Test/H264/H264DecoderTest.cs
  51. +1
    -1
      src/JT1078.Protocol.Test/H264/NALUHeaderTest.cs
  52. +6
    -0
      src/JT1078.Protocol.Test/JT1078.Protocol.Test.csproj
  53. +2
    -2
      src/JT1078.Protocol.Test/JT1078SerializerTest.cs
  54. +63
    -3
      src/JT1078.Protocol/H264/H264Decoder.cs
  55. +6
    -0
      src/JT1078.Protocol/H264/H264NALU.cs
  56. +20
    -3
      src/JT1078.Protocol/H264/NALUHeader.cs
  57. +1
    -1
      src/JT1078.Protocol/JT1078.Protocol.csproj
  58. +16
    -0
      src/JT1078.Protocol/JT1078.Protocol.xml
  59. +48
    -0
      src/JT1078.SignalR.Test/Hubs/FMp4Hub.cs
  60. +30
    -0
      src/JT1078.SignalR.Test/JT1078.SignalR.Test.csproj
  61. +26
    -0
      src/JT1078.SignalR.Test/Program.cs
  62. +174
    -0
      src/JT1078.SignalR.Test/Services/ToWebSocketService.cs
  63. +38
    -0
      src/JT1078.SignalR.Test/Services/WsSession.cs
  64. +66
    -0
      src/JT1078.SignalR.Test/Startup.cs
  65. +9
    -0
      src/JT1078.SignalR.Test/appsettings.Development.json
  66. +10
    -0
      src/JT1078.SignalR.Test/appsettings.json
  67. +15
    -58
      src/JT1078.sln
  68. +0
    -22
      src/JT808.Protocol.Extensions.JT1078.Test/JT808.Protocol.Extensions.JT1078.Test.csproj
  69. +0
    -91
      src/JT808.Protocol.Extensions.JT1078.Test/JT808LocationAttach.cs
  70. +0
    -114
      src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x0200Test.cs
  71. +0
    -65
      src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x1003Test.cs
  72. +0
    -66
      src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x1005Test.cs
  73. +0
    -141
      src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x1205Test.cs
  74. +0
    -62
      src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x1206Test.cs
  75. +0
    -300
      src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x8103CustomId.cs
  76. +0
    -101
      src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x9101Test.cs
  77. +0
    -73
      src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x9102Test.cs
  78. +0
    -62
      src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x9105Test.cs
  79. +0
    -82
      src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x9201Test.cs
  80. +0
    -66
      src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x9202Test.cs
  81. +0
    -72
      src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x9205Test.cs
  82. +0
    -92
      src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x9206Test.cs
  83. +0
    -62
      src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x9207Test.cs
  84. +0
    -65
      src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x9301Test.cs
  85. +0
    -63
      src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x9302Test.cs
  86. +0
    -63
      src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x9303Test.cs
  87. +0
    -63
      src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x9304Test.cs
  88. +0
    -56
      src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x9305Test.cs
  89. +0
    -63
      src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x9306Test.cs
  90. +0
    -20
      src/JT808.Protocol.Extensions.JT1078/DependencyInjectionExtensions.cs
  91. +0
    -28
      src/JT808.Protocol.Extensions.JT1078/Enums/JT808_JT1078_MsgId.cs
  92. +0
    -18
      src/JT808.Protocol.Extensions.JT1078/Enums/VideoRelateAlarmType.cs
  93. +0
    -35
      src/JT808.Protocol.Extensions.JT1078/JT808.Protocol.Extensions.JT1078.csproj
  94. +0
    -1289
      src/JT808.Protocol.Extensions.JT1078/JT808.Protocol.Extensions.JT1078.xml
  95. +0
    -59
      src/JT808.Protocol.Extensions.JT1078/JT808_JT1078_Constants.cs
  96. +0
    -65
      src/JT808.Protocol.Extensions.JT1078/MessageBody/JT808_0x0200_0x14.cs
  97. +0
    -69
      src/JT808.Protocol.Extensions.JT1078/MessageBody/JT808_0x0200_0x15.cs
  98. +0
    -69
      src/JT808.Protocol.Extensions.JT1078/MessageBody/JT808_0x0200_0x16.cs
  99. +0
    -83
      src/JT808.Protocol.Extensions.JT1078/MessageBody/JT808_0x0200_0x17.cs
  100. +0
    -90
      src/JT808.Protocol.Extensions.JT1078/MessageBody/JT808_0x0200_0x18.cs

+ 0
- 8
.github/workflows/dotnetcore.yml View File

@@ -17,11 +17,3 @@ jobs:
run: dotnet --info
- name: dotnet restore
run: dotnet restore ./src/JT1078.sln
- name: dotnet JT808.Protocol.Extensions.JT1078.Test build
run: dotnet build ./src/JT808.Protocol.Extensions.JT1078.Test/JT808.Protocol.Extensions.JT1078.Test.csproj
- name: dotnet JT808.Protocol.Extensions.JT1078.Test test
run: dotnet test ./src/JT808.Protocol.Extensions.JT1078.Test/JT808.Protocol.Extensions.JT1078.Test.csproj
- name: dotnet JT809.Protocol.Extensions.JT1078.Test build
run: dotnet build ./src/JT809.Protocol.Extensions.JT1078.Test/JT809.Protocol.Extensions.JT1078.Test.csproj
- name: dotnet JT809.Protocol.Extensions.JT1078.Test test
run: dotnet test ./src/JT809.Protocol.Extensions.JT1078.Test/JT809.Protocol.Extensions.JT1078.Test.csproj

+ 1
- 102
README.md View File

@@ -2,7 +2,7 @@

道路运输车辆卫星定位系统-视频通讯协议主要分为三大部分。

1. [设备终端到平台的通信也就是JT808](#808Ext)
1. [设备终端到平台的通信也就是JT808]
2. [企业平台到政府监管的通信也就是JT809](#809Ext)
3. [设备终端上传的实时音视频流数据也就是视频服务器](#1078)
3.1 [将1078的数据(h264)编码成FLV](#1078flv)
@@ -20,8 +20,6 @@
| Install-Package JT1078.Flv | ![JT1078.Flv](https://img.shields.io/nuget/v/JT1078.Flv.svg) | ![JT1078.Flv](https://img.shields.io/nuget/dt/JT1078.Flv.svg) |
| Install-Package JT1078.Hls | ![JT1078.Hls](https://img.shields.io/nuget/v/JT1078.Hls.svg) | ![JT1078.Hls](https://img.shields.io/nuget/dt/JT1078.Hls.svg) |
| Install-Package JT1078.FMp4 | ![JT1078.FMp4](https://img.shields.io/nuget/v/JT1078.FMp4.svg) | ![JT1078.FMp4](https://img.shields.io/nuget/dt/JT1078.FMp4.svg) |
| Install-Package JT808.Protocol.Extensions.JT1078 | ![JT808.Protocol.Extensions.JT1078](https://img.shields.io/nuget/v/JT808.Protocol.Extensions.JT1078.svg) | ![JT808](https://img.shields.io/nuget/dt/JT808.Protocol.Extensions.JT1078.svg) |
| Install-Package JT809.Protocol.Extensions.JT1078 | ![JT809.Protocol.Extensions.JT1078](https://img.shields.io/nuget/v/JT809.Protocol.Extensions.JT1078.svg) | ![JT809](https://img.shields.io/nuget/dt/JT809.Protocol.Extensions.JT1078.svg) |

## <span id="1078">基于JT1078音视频流数据的RTP协议</span>

@@ -214,102 +212,3 @@ Platform=AnyCpu Server=False Toolchain=.NET Core 3.1
| **EXPGolombReader** | **100000** | **11,687.72 us** | **162.828 us** | **152.309 us** | **1515.6250** | **-** | **-** | **9375 KB** |
| H264Decoder | 100000 | 1,192,549.87 us | 7,656.632 us | 7,162.018 us | 128000.0000 | 3000.0000 | - | 786718.75 KB |
| FlvEncoder | 100000 | 216,951.31 us | 3,513.653 us | 2,934.059 us | 249333.3333 | - | - | 1528906.66 KB |

## <span id="808ext">基于JT808扩展的JT1078消息协议</span>

### JT808扩展协议消息对照表

| 序号 | 消息ID | 完成情况 | 测试情况 | 消息体名称 |
| :---: | :-----------: | :------: | :------: | :----------------------------: |
| 1 | 0x0200_0x14 | √ | √ | 视频相关报警 |
| 2 | 0x0200_0x15 | √ | √ | 视频信号丢失报警状态 |
| 3 | 0x0200_0x16 | √ | √ | 视频信号遮挡报警状态 |
| 4 | 0x0200_0x17 | √ | √ | 存储器故障报警状态 |
| 5 | 0x0200_0x18 | √ | √ | 异常驾驶行为报警详细描述 |
| 6 | 0x8103_0x0075 | √ | √ | 音视频参数设置 |
| 7 | 0x8103_0x0076 | √ | √ | 音视频通道列表设置 |
| 8 | 0x8103_0x0077 | √ | √ | 单独视频通道参数设置 |
| 9 | 0x8103_0x0079 | √ | √ | 特殊报警录像参数设置 |
| 10 | 0x8103_0x007A | √ | √ | 视频相关报警屏蔽字 |
| 11 | 0x8103_0x007B | √ | √ | 图像分析报警参数设置 |
| 12 | 0x8103_0x007C | √ | √ | 终端休眠模式唤醒设置 |
| 13 | 0x1003 | √ | √ | 终端上传音视频属性 |
| 14 | 0x1005 | √ | √ | 终端上传乘客流量 |
| 15 | 0x1205 | √ | √ | 终端上传音视频资源列表 |
| 16 | 0x1206 | √ | √ | 文件上传完成通知 |
| 17 | 0x9003 | √ | √ | 查询终端音视频属性 |
| 18 | 0x9101 | √ | √ | 实时音视频传输请求 |
| 19 | 0x9102 | √ | √ | 音视频实时传输控制 |
| 20 | 0x9105 | √ | √ | 实时音视频传输状态通知 |
| 21 | 0x9201 | √ | √ | 平台下发远程录像回放请求 |
| 22 | 0x9202 | √ | √ | 平台下发远程录像回放控制 |
| 23 | 0x9205 | √ | √ | 查询资源列表 |
| 24 | 0x9206 | √ | √ | 文件上传指令 |
| 25 | 0x9207 | √ | √ | 文件上传控制 |
| 26 | 0x9301 | √ | √ | 云台旋转 |
| 27 | 0x9302 | √ | √ | 云台调整焦距控制 |
| 28 | 0x9303 | √ | √ | 云台调整光圈控制 |
| 29 | 0x9304 | √ | √ | 云台雨刷控制 |
| 30 | 0x9305 | √ | √ | 红外补光控制 |
| 31 | 0x9306 | √ | √ | 云台变倍控制 |

### 使用方法

```dotnet
IServiceCollection serviceDescriptors1 = new ServiceCollection();
serviceDescriptors1.AddJT808Configure()
.AddJT1078Configure();
```

## <span id="809ext">基于JT809扩展的JT1078消息协议</span>

### JT809扩展协议消息对照表

#### 主链路动态信息交换消息

| 序号 | 消息ID | 完成情况 | 测试情况 | 消息体名称 |
| :---: | :-----------: | :------: | :------: | :----------------------------: |
| 1 | 0x1700 | √ | √ | 主链路时效口令交互消息 |
| 2 | 0x1700_0x1701 | √ | √ | 时效口令上报消息(有疑问:数据体有问题) |
| 3 | 0x1700_0x1702 | √ | √ | 时效口令请求消息 |
| 4 | 0x1800 | √ | √ | 主链路实时音视频交互消息 |
| 5 | 0x1800_0x1801 | √ | √ | 实时音视频请求应答消息 |
| 6 | 0x1800_0x1802 | √ | √ | 主动请求停止实时音视频传输应答消息 |
| 7 | 0x1900 | √ | √ | 主链路远程录像检索 |
| 8 | 0x1900_0x1901 | √ | √ | 主动上传音视频资源目录信息消息 |
| 9 | 0x1900_0x1902 | √ | √ | 查询音视频资源目录应答消息 |
| 10 | 0x1A00 | √ | √ | 主链路远程录像回放交互消息 |
| 11 | 0x1A00_0x1A01 | √ | √ | 远程录像回放请求应答消息 |
| 12 | 0x1A00_0x1A02 | √ | √ | 远程录像回放控制应答消息 |
| 13 | 0x1B00 | √ | √ | 主链路远程录像下载交互消息 |
| 14 | 0x1B00_0x1B01 | √ | √ | 远程录像下载请求应答消息 |
| 15 | 0x1B00_0x1B02 | √ | √ | 远程录像下载通知消息 |
| 16 | 0x1B00_0x1B03 | √ | √ | 远程录像下载控制应答消息 |

#### 从链路动态信息交换消息

| 序号 | 消息ID | 完成情况 | 测试情况 | 消息体名称 |
| :---: | :-----------: | :------: | :------: | :----------------------------: |
| 17 | 0x9700 | √ | √ | 从链路时效口令交互消息 |
| 18 | 0x9700_0x9702 | √ | √ | 时效口令请求应答消息(有疑问:应该有应答结果) |
| 19 | 0x9800 | √ | √ | 从链路实时音视频交互信息 |
| 20 | 0x9800_0x9801 | √ | √ | 实时音视频请求消息 |
| 21 | 0x9800_0x9802 | √ | √ | 主动请求停止实时音视频传输消息 |
| 22 | 0x9900 | √ | √ | 从链路远程录像检索交互消息 |
| 23 | 0x9900_0x9901 | √ | √ | 主动上传音视频资源目录信息应答消息 |
| 24 | 0x9900_0x9902 | √ | √ | 查询音视频资源目录请求消息 |
| 25 | 0x9A00 | √ | √ | 从链路远程录像回放交互消息 |
| 26 | 0x9A00_0x9A01 | √ | √ | 远程录像回放请求消息 |
| 27 | 0x9A00_0x9A02 | √ | √ | 远程录像回放控制消息 |
| 28 | 0x9B00 | √ | √ | 从链路远程录像下载交互消息 |
| 29 | 0x9B00_0x9B01 | √ | √ | 远程录像下载请求消息 |
| 30 | 0x9B00_0x9B02 | √ | √ | 远程录像下载完成通知应答消息 |
| 31 | 0x9B00_0x9B03 | √ | √ | 远程录像下载控制消息 |

### 使用方法

```dotnet
IServiceCollection serviceDescriptors1 = new ServiceCollection();
serviceDescriptors1.AddJT809Configure()
.AddJT1078Configure();
```

+ 9
- 1
doc/ffmpeginfo.txt View File

@@ -1,6 +1,6 @@
ffmpeg -i demo.mp4 -c copy -f flv -vcodec h264 -acodec aac demo_flv.flv

./ffmpeg -i JT1078_3.h264 -r 25 -c copy -f flv "D:\JT1078_3.flv"
ffmpeg -i JT1078_3.h264 -c copy -f flv JT1078_3.flv

ffmpeg -f dshow -i video="USB2.0 PC CAMERA" -t 60 -c copy -f h264 -vcodec h264 ipc.264

@@ -8,4 +8,12 @@ ffmpeg -i demo.264 -vcodec copy -f mp4 -movflags frag_keyframe+empty_moov fragme

ffmpeg -i ipc.264 -vcodec copy -f mp4 -movflags frag_keyframe+empty_moov ipc_fragmented_demo.mp4

ffmpeg -i jt1078_3.h264 -c:v copy -f mp4 -movflags empty_moov+default_base_moof+frag_keyframe fragmented_base_moof_demo.mp4

ffprobe -of json -show_frames jt1078_3.h264 > jt1078_3.json

ffmpeg -re -i JT1078_7.flv -acodec copy -vcodec copy -f flv rtmp://127.0.0.1:1935/live/JT1078_7

ffmpeg -re -i JT1078_7.h264 -acodec copy -vcodec copy -f flv rtmp://127.0.0.1:1935/live/JT1078_7

chrome://media-internals/

BIN
doc/tools/SpecialVH264_jb51/SpecialVH264_1.1.exe View File


+ 2
- 0
doc/tools/SpecialVH264_jb51/configure.ini View File

@@ -0,0 +1,2 @@
[Settings]
language=Chinese

BIN
doc/video/JT1078_5.flv View File


BIN
doc/video/JT1078_6_8.mp4 View File


BIN
doc/video/fragmented_base_moof_demo.mp4 View File


BIN
doc/video/jt1078_5.h264 View File


+ 17215
- 0
doc/video/jt1078_5.txt
File diff suppressed because it is too large
View File


+ 3287
- 0
doc/video/jt1078_6.txt
File diff suppressed because it is too large
View File


BIN
doc/video/test_1920x1080.h264 View File


+ 4
- 0
src/JT1078.AV.Benchmark/JT1078.AV.Benchmark.csproj View File

@@ -12,10 +12,14 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\JT1078.Flv\JT1078.Flv.csproj" />
<ProjectReference Include="..\JT1078.FMp4\JT1078.FMp4.csproj" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\doc\video\jt1078_1.txt" Link="jt1078_1.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="..\..\doc\video\jt1078_3.txt" Link="jt1078_3.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

+ 132
- 0
src/JT1078.AV.Benchmark/JT1078AVEncoderContext.cs View File

@@ -0,0 +1,132 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Environments;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Toolchains.CsProj;
using JT1078.Flv;
using JT1078.Flv.MessagePack;
using JT1078.FMp4;
using JT1078.Protocol;
using JT1078.Protocol.H264;
using JT1078.Protocol.MessagePack;
using JT808.Protocol.Extensions;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace JT1078.AV.Benchmark
{
[Config(typeof(JT1078AVEncoderConfig))]
[MarkdownExporterAttribute.GitHub]
[MemoryDiagnoser]
public class JT1078AVEncoderContext
{
JT1078Package Package;
List<H264NALU> H264NALUs;
List<H264NALU> FMp4H264NALUs;
H264NALU SPSNALu;
H264Decoder h264Decoder = new H264Decoder();
FlvEncoder flvEncoder = new FlvEncoder();
FMp4Encoder fmp4Encoder = new FMp4Encoder();

[Params(100, 10000, 100000)]
public int N;

[GlobalSetup]
public void Setup()
{
var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "JT1078_1.txt"));
foreach (var line in lines)
{
var data = line.Split(',');
var bytes = data[6].ToHexBytes();
JT1078Package package = JT1078Serializer.Deserialize(bytes);
Package = JT1078Serializer.Merge(package);
}
H264NALUs = h264Decoder.ParseNALU(Package);
SPSNALu = H264NALUs.FirstOrDefault(f => f.NALUHeader.NalUnitType == NalUnitType.SPS);
SPSNALu.RawData = h264Decoder.DiscardEmulationPreventionBytes(SPSNALu.RawData);

List<JT1078Package> packages = new List<JT1078Package>();
var lines3 = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "jt1078_3.txt"));
int mergeBodyLength = 0;
foreach (var line in lines3)
{
var data = line.Split(',');
var bytes = data[6].ToHexBytes();
JT1078Package package = JT1078Serializer.Deserialize(bytes);
mergeBodyLength += package.DataBodyLength;
var packageMerge = JT1078Serializer.Merge(package);
if (packageMerge != null)
{
packages.Add(packageMerge);
}
}
List<H264NALU> nalus = new List<H264NALU>();
bool segmentFlag = false;
foreach (var package in packages)
{
if (segmentFlag)
{
break;
}
List<H264NALU> h264NALUs = h264Decoder.ParseNALU(package);
foreach (var nalu in h264NALUs)
{
if (nalu.Slice)
{
//H264 NALU slice first_mb_in_slice
nalus.Add(nalu);
}
else
{
if (nalus.Count > 0)
{
FMp4H264NALUs = new List<H264NALU>(nalus);
segmentFlag = true;
nalus.Clear();
}
nalus.Add(nalu);
}
}
}
}

[Benchmark(Description = "EXPGolombReader")]
public void EXPGolombReaderTest()
{
for (var i = 0; i < N; i++)
{
ExpGolombReader h264GolombReader = new ExpGolombReader(SPSNALu.RawData);
h264GolombReader.ReadSPS();
}
}

[Benchmark(Description = "H264Decoder")]
public void H264Decoder()
{
for (var i = 0; i < N; i++)
{
var nalus = h264Decoder.ParseNALU(Package);
}
}

[Benchmark(Description = "FMp4Encoder")]
public void FMp4Encoder()
{
for (var i = 0; i < N; i++)
{
var buffer = fmp4Encoder.OtherVideoBox(FMp4H264NALUs);
}
}
}

public class JT1078AVEncoderConfig : ManualConfig
{
public JT1078AVEncoderConfig()
{
AddJob(Job.Default.WithGcServer(false).WithToolchain(CsProjCoreToolchain.NetCoreApp50).WithPlatform(Platform.AnyCpu));
}
}
}

+ 0
- 76
src/JT1078.AV.Benchmark/JT1078FlvEncoderContext.cs View File

@@ -1,76 +0,0 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Environments;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Toolchains.CsProj;
using JT1078.Flv;
using JT1078.Flv.MessagePack;
using JT1078.Protocol;
using JT1078.Protocol.H264;
using JT1078.Protocol.MessagePack;
using JT808.Protocol.Extensions;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace JT1078.AV.Benchmark
{
[Config(typeof(JT1078FlvEncoderConfig))]
[MarkdownExporterAttribute.GitHub]
[MemoryDiagnoser]
public class JT1078FlvEncoderContext
{
JT1078Package Package;
List<H264NALU> H264NALUs;
H264NALU SPSNALu;
H264Decoder h264Decoder = new H264Decoder();
FlvEncoder flvEncoder = new FlvEncoder();

[Params(100, 10000, 100000)]
public int N;

[GlobalSetup]
public void Setup()
{
var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "JT1078_1.txt"));
foreach (var line in lines)
{
var data = line.Split(',');
var bytes = data[6].ToHexBytes();
JT1078Package package = JT1078Serializer.Deserialize(bytes);
Package = JT1078Serializer.Merge(package);
}
H264NALUs = h264Decoder.ParseNALU(Package);
SPSNALu = H264NALUs.FirstOrDefault(f => f.NALUHeader.NalUnitType == 7);
SPSNALu.RawData = h264Decoder.DiscardEmulationPreventionBytes(SPSNALu.RawData);
}

[Benchmark(Description = "EXPGolombReader")]
public void EXPGolombReaderTest()
{
for (var i = 0; i < N; i++)
{
ExpGolombReader h264GolombReader = new ExpGolombReader(SPSNALu.RawData);
h264GolombReader.ReadSPS();
}
}

[Benchmark(Description = "H264Decoder")]
public void H264Decoder()
{
for (var i = 0; i < N; i++)
{
var nalus = h264Decoder.ParseNALU(Package);
}
}
}

public class JT1078FlvEncoderConfig : ManualConfig
{
public JT1078FlvEncoderConfig()
{
AddJob(Job.Default.WithGcServer(false).WithToolchain(CsProjCoreToolchain.NetCoreApp50).WithPlatform(Platform.AnyCpu));
}
}
}

+ 1
- 1
src/JT1078.AV.Benchmark/Program.cs View File

@@ -8,7 +8,7 @@ namespace JT1078.AV.Benchmark
{
static void Main(string[] args)
{
Summary summary = BenchmarkRunner.Run<JT1078FlvEncoderContext>();
Summary summary = BenchmarkRunner.Run<JT1078AVEncoderContext>();
}
}
}

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

@@ -172,7 +172,7 @@ namespace JT1078.FMp4.Test
//stbl
SampleTableBox sampleTableBox = new SampleTableBox();
//stbl->stsd
SampleDescriptionBox sampleDescriptionBox = new SampleDescriptionBox(HandlerType.none);
SampleDescriptionBox sampleDescriptionBox = new SampleDescriptionBox();
//stbl->stsd->avc1
AVC1SampleEntry aVC1SampleEntry = new AVC1SampleEntry();
aVC1SampleEntry.Width = 0x0220;


+ 3
- 0
src/JT1078.FMp4.Test/H264/.vscode/settings.json View File

@@ -0,0 +1,3 @@
{
"liveServer.settings.port": 5501
}

+ 190
- 33
src/JT1078.FMp4.Test/H264/index.html View File

@@ -3,47 +3,204 @@
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title>fmp4 demo</title>
<title>WebSocket MSE Fmp4 demo</title>
<script type="text/javascript" src="signalr.min.js"></script>
</head>
<body>
<h1>MSE FMp4 Demo</h1>
<video autoplay controls></video>
<video id="stream_live" width="640" height="480" controls="false" autoplay="true"
muted="muted"
preload="auto">
浏览器不支持
</video>
<ul id="messagesList"></ul>
<!--<video src="/JT1078_4.mp4" autoplay controls></video>-->
<script>
var video = document.querySelector('video');
var mimeCodec = 'video/mp4;codecs="avc1.42E01E, mp4a.40.2"';
if ('MediaSource' in window && MediaSource.isTypeSupported(mimeCodec)) {
var mediaSource = new MediaSource();
console.log(mediaSource.readyState);
video.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener('sourceopen', sourceOpen);
} else {
console.log('Unsupported MIME type pr cpdec:', mimeCodec);
}
function sourceOpen(_) {
URL.revokeObjectURL(video.src);
console.log(this.readyState);
var mediaSource = this;
var sourceBuffer = mediaSource.addSourceBuffer(mimeCodec);
fetchMedia("/JT1078_4.mp4", function (buf) {
sourceBuffer.addEventListener("updateend", function (_) {
mediaSource.endOfStream();
video.play();
console.log(mediaSource.readyState);
});
sourceBuffer.appendBuffer(buf);
//var mimeCodec = 'video/mp4;codecs="avc1.4D0014, mp4a.40.2"';
// *** USER PARAMETERS ***
var verbose = true;
var buffering_sec = 3; // use some reasonable value
var buffering_sec_seek = buffering_sec * 0.9;
// ..seek the stream if it's this much away or
// from the last available timestamp
var buffering_sec_seek_distance = buffering_sec * 0.5;
// .. jump to this distance from the last avail. timestamp
// *** INTERNAL PARAMETERS ***
// set mimetype and codec
var mimeType = "video/mp4";
var codecs = "avc1.4D0014"; // https://wiki.whatwg.org/wiki/Video_type_parameters
// if your stream has audio, remember to include it in these definitions.. otherwise your mse goes sour
var codecPars = mimeType + ';codecs="' + codecs + '"';
var stream_started = false; // is the source_buffer updateend callback active nor not
// create media source instance
var ms = new MediaSource();
// queue for incoming media packets
var queue = [];
var stream_live; // the HTMLMediaElement (i.e. <video> element)
var ws; // websocket
var seeked = false; // have have seeked manually once ..
var cc = 0;
var source_buffer; // source_buffer instance
var pass = 0;
// *** MP4 Box manipulation functions ***
// taken from here: https://stackoverflow.com/questions/54186634/sending-periodic-metadata-in-fragmented-live-mp4-stream/
function toInt(arr, index) { // From bytes to big-endian 32-bit integer. Input: Uint8Array, index
var dv = new DataView(arr.buffer, 0);
return dv.getInt32(index, false); // big endian
}
function toString(arr, fr, to) { // From bytes to string. Input: Uint8Array, start index, stop index.
// https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-String
return String.fromCharCode.apply(null, arr.slice(fr, to));
}
function getBox(arr, i) { // input Uint8Array, start index
return [toInt(arr, i), toString(arr, i + 4, i + 8)]
}
function getSubBox(arr, box_name) { // input Uint8Array, box name
var i = 0;
res = getBox(arr, i);
main_length = res[0]; name = res[1]; // this boxes length and name
i = i + 8;
var sub_box = null;
while (i < main_length) {
res = getBox(arr, i);
l = res[0]; name = res[1];

if (box_name == name) {
sub_box = arr.slice(i, i + l)
}
i = i + l;
}
return sub_box;
}
function hasFirstSampleFlag(arr) { // input Uint8Array
// [moof [mfhd] [traf [tfhd] [tfdt] [trun]]]
var traf = getSubBox(arr, "traf");
if (traf == null) { return false; }
var trun = getSubBox(traf, "trun");
if (trun == null) { return false; }
// ISO/IEC 14496-12:2012(E) .. pages 5 and 57
// bytes: (size 4), (name 4), (version 1 + tr_flags 3)
var flags = trun.slice(10, 13); // console.log(flags);
f = flags[1] & 4; // console.log(f);
return f == 4;
}
// consider these callbacks:
// - putPacket : called when websocket receives data
// - loadPacket : called when source_buffer is ready for more data
// Both operate on a common fifo
function putPacket(arr) {
// receives ArrayBuffer. Called when websocket gets more data
// first packet ever to arrive: write directly to source_buffer
// source_buffer ready to accept: write directly to source_buffer
// otherwise insert it to queue
var memview = new Uint8Array(arr);
if (verbose) { console.log("got", arr.byteLength, "bytes. Values=", memview[0], memview[1], memview[2], memview[3], memview[4]); }
res = getBox(memview, 0);
main_length = res[0]; name = res[1]; // this boxes length and name
// if ((name == "ftyp") && (pass == 0)) {
// pass = pass + 1;
// console.log("got ftyp");
// }
// else if ((name == "moov") && (pass == 1)) {
// pass = pass + 1;
// console.log("got moov");
// }
// else if ((name == "moof") && (pass == 2)) {
// if (hasFirstSampleFlag(memview)) {
// pass = pass + 1;
// console.log("got that special moof");
// }
// else {
// return;
// }
// }
// else if (pass < 3) {
// return;
// }
// keep the latency to minimum
// let latest = stream_live.duration;
// if ((stream_live.duration >= buffering_sec) && ((latest - stream_live.currentTime) > buffering_sec_seek)) {
// console.log("seek from ", stream_live.currentTime, " to ", latest);
// df = (stream_live.duration - stream_live.currentTime); // this much away from the last available frame
// if ((df > buffering_sec_seek)) {
// seek_to = stream_live.duration - buffering_sec_seek_distance;
// stream_live.currentTime = seek_to;
// }
// }
if (!source_buffer.updating) {
if (verbose) { console.log("Streaming started: ", memview[0], memview[1], memview[2], memview[3], memview[4]); }
stream_started = true;
source_buffer.appendBuffer(arr);
cc = cc + 1;
}else{
queue.push(arr); // add to the end
}
if (verbose) { console.log("queue push:", queue.length); }
}

function loadPacket() { // called when source_buffer is ready for more
if (!source_buffer.updating) { // really, really ready
if (queue.length > 0) {
var inp = queue.shift(); // pop from the beginning
if (verbose) { console.log("queue pop:", queue.length); }
var memview = new Uint8Array(inp);
if (verbose) { console.log(" ==> writing buffer with", memview[0], memview[1], memview[2], memview[3]); }
source_buffer.appendBuffer(inp);
cc = cc + 1;
}
// else { // the queue runs empty, so the next packet is fed directly
// stream_started = false;
// }
}
// else {
// // so it was not?

// }
}

function opened() { // MediaSource object is ready to go
// https://developer.mozilla.org/en-US/docs/Web/API/MediaSource/duration
ms.duration = buffering_sec;
source_buffer = ms.addSourceBuffer(codecPars);
// https://developer.mozilla.org/en-US/docs/Web/API/source_buffer/mode
var myMode = source_buffer.mode;
source_buffer.mode = 'sequence';
// source_buffer.mode = 'segments';
source_buffer.addEventListener("updateend", loadPacket);
ws = new signalR.HubConnectionBuilder()
.withUrl("http://127.0.0.1:5000/FMp4Hub")
.build();
ws.on("video", (message) => {
var buff=base64ToArrayBuffer(message);
//console.log(buff);
putPacket(buff);
//先直接喂进去
//mvhd.duration 谷歌浏览器不会缓存
//source_buffer.appendBuffer(buff);
});
ws.start().catch(err => console.error(err));
}
function fetchMedia(url, callback) {
console.log(url);
var xhr = new XMLHttpRequest;
xhr.open('get', url);
xhr.responseType = 'arraybuffer';
xhr.onload = function () {
callback(xhr.response);
};
xhr.send();

function startup() {
ms.addEventListener('sourceopen', opened, false);
// get reference to video
stream_live = document.getElementById('stream_live');
// set mediasource as source of video
stream_live.src = window.URL.createObjectURL(ms);
}
function base64ToArrayBuffer(base64) {
var binary_string = window.atob(base64);
var len = binary_string.length;
var bytes = new Uint8Array(len);
for (var i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
return bytes.buffer;
}
window.onload = function () {
startup();
}

</script>
</body>
</html>

+ 17
- 0
src/JT1078.FMp4.Test/H264/signalr.min.js
File diff suppressed because it is too large
View File


+ 6
- 0
src/JT1078.FMp4.Test/JT1078.FMp4.Test.csproj View File

@@ -58,6 +58,12 @@
<None Include="..\..\doc\video\jt1078_1_fragmented.mp4" Link="H264\jt1078_1_fragmented.mp4">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="..\..\doc\video\jt1078_5.txt" Link="H264\jt1078_5.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="..\..\doc\video\jt1078_6.txt" Link="H264\jt1078_6.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

+ 217
- 24
src/JT1078.FMp4.Test/JT1078ToFMp4Box_Test.cs View File

@@ -2,15 +2,18 @@
using JT1078.FMp4.MessagePack;
using JT1078.FMp4.Samples;
using JT1078.Protocol;
using JT1078.Protocol.Enums;
using JT1078.Protocol.Extensions;
using JT1078.Protocol.H264;
using JT1078.Protocol.MessagePack;
using System;
using System.Buffers;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Xunit;

@@ -24,10 +27,10 @@ namespace JT1078.FMp4.Test
var jT1078Package = ParseNALUTest();
H264Decoder decoder = new H264Decoder();
var nalus = decoder.ParseNALU(jT1078Package);
var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 7);
var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.SPS);
//SPS
spsNALU.RawData = decoder.DiscardEmulationPreventionBytes(spsNALU.RawData);
var ppsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 8);
var ppsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.PPS);
ppsNALU.RawData = decoder.DiscardEmulationPreventionBytes(ppsNALU.RawData);
//ftyp
FileTypeBox fileTypeBox = new FileTypeBox();
@@ -71,7 +74,7 @@ namespace JT1078.FMp4.Test
movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox.DataReferenceBox.DataEntryBoxes = new List<DataEntryBox>();
movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox.DataReferenceBox.DataEntryBoxes.Add(new DataEntryUrlBox(1));
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox = new SampleTableBox();
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox = new SampleDescriptionBox(movieBox.TrackBox.MediaBox.HandlerBox.HandlerType);
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox = new SampleDescriptionBox();
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox.SampleEntries = new List<SampleEntry>();
AVC1SampleEntry avc1 = new AVC1SampleEntry();
avc1.AVCConfigurationBox = new AVCConfigurationBox();
@@ -176,10 +179,10 @@ namespace JT1078.FMp4.Test
var jT1078Package = ParseNALUTest();
H264Decoder decoder = new H264Decoder();
var nalus = decoder.ParseNALU(jT1078Package);
var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 7);
var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.SPS);
//SPS
spsNALU.RawData = decoder.DiscardEmulationPreventionBytes(spsNALU.RawData);
var ppsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 8);
var ppsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.PPS);
ppsNALU.RawData = decoder.DiscardEmulationPreventionBytes(ppsNALU.RawData);
FMp4MessagePackWriter writer = new FMp4MessagePackWriter(new byte[65535]);
//ftyp
@@ -224,7 +227,7 @@ namespace JT1078.FMp4.Test
movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox.DataReferenceBox.DataEntryBoxes = new List<DataEntryBox>();
movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox.DataReferenceBox.DataEntryBoxes.Add(new DataEntryUrlBox(1));
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox = new SampleTableBox();
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox = new SampleDescriptionBox(movieBox.TrackBox.MediaBox.HandlerBox.HandlerType);
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox = new SampleDescriptionBox();
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox.SampleEntries = new List<SampleEntry>();
AVC1SampleEntry avc1 = new AVC1SampleEntry();
avc1.AVCConfigurationBox = new AVCConfigurationBox();
@@ -277,7 +280,7 @@ namespace JT1078.FMp4.Test
fragmentBox.MediaDataBox = new MediaDataBox();
fragmentBox.MediaDataBox.Data = nalus.Select(s => s.RawData).ToList();
moofs.Add(fragmentBox);
foreach(var moof in moofs)
foreach (var moof in moofs)
{
moof.ToBuffer(ref writer);
}
@@ -324,10 +327,10 @@ namespace JT1078.FMp4.Test
using var fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write);
var jT1078Package = packages.FirstOrDefault();
var nalus = decoder.ParseNALU(jT1078Package);
var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 7);
var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.SPS);
//SPS
spsNALU.RawData = decoder.DiscardEmulationPreventionBytes(spsNALU.RawData);
var ppsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 8);
var ppsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.PPS);
ppsNALU.RawData = decoder.DiscardEmulationPreventionBytes(ppsNALU.RawData);
ExpGolombReader h264GolombReader = new ExpGolombReader(spsNALU.RawData);
var spsInfo = h264GolombReader.ReadSPS();
@@ -373,7 +376,7 @@ namespace JT1078.FMp4.Test
movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox.DataReferenceBox.DataEntryBoxes = new List<DataEntryBox>();
movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox.DataReferenceBox.DataEntryBoxes.Add(new DataEntryUrlBox(1));
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox = new SampleTableBox();
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox = new SampleDescriptionBox(movieBox.TrackBox.MediaBox.HandlerBox.HandlerType);
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox = new SampleDescriptionBox();
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox.SampleEntries = new List<SampleEntry>();
AVC1SampleEntry avc1 = new AVC1SampleEntry();
avc1.AVCConfigurationBox = new AVCConfigurationBox();
@@ -437,26 +440,197 @@ namespace JT1078.FMp4.Test
public void Test4()
{
FMp4Encoder fMp4Encoder = new FMp4Encoder();
H264Decoder h264Decoder = new H264Decoder();
var packages = ParseNALUTests();
var filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_4.mp4");
var filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_5.mp4");
if (File.Exists(filepath))
{
File.Delete(filepath);
}

using var fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write);
var package1 = packages[0];
var buffer1 = fMp4Encoder.EncoderFirstVideoBox(package1);
fileStream.Write(buffer1);
int moofOffset = buffer1.Length;
foreach (var package in packages.Take(2))
var ftyp = fMp4Encoder.FtypBox();
fileStream.Write(ftyp);

var iNalus = h264Decoder.ParseNALU(packages[0]);
//判断第一帧是否关键帧
var moov = fMp4Encoder.VideoMoovBox(
iNalus.FirstOrDefault(f => f.NALUHeader.NalUnitType == NalUnitType.SPS),
iNalus.FirstOrDefault(f => f.NALUHeader.NalUnitType == NalUnitType.PPS));
fileStream.Write(moov);

List<H264NALU> nalus = new List<H264NALU>();
foreach (var package in packages)
{
List<H264NALU> h264NALUs = h264Decoder.ParseNALU(package);
foreach (var nalu in h264NALUs)
{
if (nalu.Slice)
{
//H264 NALU slice first_mb_in_slice
nalus.Add(nalu);
}
else
{
if (nalus.Count > 0)
{
var otherBuffer = fMp4Encoder.OtherVideoBox(nalus);
fileStream.Write(otherBuffer);
nalus.Clear();
}
nalus.Add(nalu);
}
}
}
fileStream.Close();
}

[Fact]
public void Test5()
{
FMp4Encoder fMp4Encoder = new FMp4Encoder();
H264Decoder h264Decoder = new H264Decoder();
var packages = ParseNALUTests();
var filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_6.mp4");
if (File.Exists(filepath))
{
File.Delete(filepath);
}
using var fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write);

var ftyp = fMp4Encoder.FtypBox();
fileStream.Write(ftyp);

var iNalus = h264Decoder.ParseNALU(packages[0]);
//判断第一帧是否关键帧
var moov = fMp4Encoder.VideoMoovBox(
iNalus.FirstOrDefault(f => f.NALUHeader.NalUnitType == NalUnitType.SPS),
iNalus.FirstOrDefault(f => f.NALUHeader.NalUnitType == NalUnitType.PPS));
fileStream.Write(moov);

List<H264NALU> nalus = new List<H264NALU>();
foreach (var package in packages)
{
List<H264NALU> h264NALUs = h264Decoder.ParseNALU(package);
if (package.Label3.DataType == Protocol.Enums.JT1078DataType.视频I帧)
{
if (nalus.Count > 0)
{
var otherBuffer = fMp4Encoder.OtherVideoBox(nalus);
fileStream.Write(otherBuffer);
nalus.Clear();
}
}
nalus = nalus.Concat(h264NALUs).ToList();
}
if (nalus.Count > 0)
{
var otherBuffer = fMp4Encoder.EncoderOtherVideoBox(package, (ulong)moofOffset);
moofOffset += otherBuffer.Length;
var otherBuffer = fMp4Encoder.OtherVideoBox(nalus);
fileStream.Write(otherBuffer);
nalus.Clear();
}
fileStream.Close();
}

[Fact]
public void Test6()
{
FMp4Encoder fMp4Encoder = new FMp4Encoder();
H264Decoder h264Decoder = new H264Decoder();
var packages = ParseNALUTests1();
var filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_7.mp4");
if (File.Exists(filepath))
{
File.Delete(filepath);
}
using var fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write);

var ftyp = fMp4Encoder.FtypBox();
fileStream.Write(ftyp);

var iPackage = packages.FirstOrDefault(f => f.Label3.DataType == JT1078DataType.视频I帧);
var iNalus = h264Decoder.ParseNALU(iPackage);
//判断第一帧是否关键帧
var moov = fMp4Encoder.VideoMoovBox(
iNalus.FirstOrDefault(f => f.NALUHeader.NalUnitType == NalUnitType.SPS),
iNalus.FirstOrDefault(f => f.NALUHeader.NalUnitType == NalUnitType.PPS));
fileStream.Write(moov);

List<H264NALU> nalus = new List<H264NALU>();
foreach (var package in packages)
{
List<H264NALU> h264NALUs = h264Decoder.ParseNALU(package);
if (package.Label3.DataType == Protocol.Enums.JT1078DataType.视频I帧)
{
if (nalus.Count > 0)
{
fileStream.Write(fMp4Encoder.StypBox());
var otherBuffer = fMp4Encoder.OtherVideoBox(nalus);
fileStream.Write(otherBuffer);
nalus.Clear();
}
}
nalus = nalus.Concat(h264NALUs).ToList();
}
if (nalus.Count > 0)
{
var otherBuffer = fMp4Encoder.OtherVideoBox(nalus);
fileStream.Write(otherBuffer);
nalus.Clear();
}
fileStream.Close();
}

[Fact]
public void Test6_2()
{
var filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_7.h264");
if (File.Exists(filepath))
{
File.Delete(filepath);
}
using var fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write);
List<JT1078Package> packages = new List<JT1078Package>();
var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "jt1078_6.txt"));
foreach (var line in lines)
{
var bytes = line.ToHexBytes();
JT1078Package package = JT1078Serializer.Deserialize(bytes);
fileStream.Write(package.Bodies);
}
fileStream.Close();
}

[Fact]
public void WebSocketMp4()
{
var filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_8.mp4");
if (File.Exists(filepath))
{
File.Delete(filepath);
}
using var fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write);
System.Net.WebSockets.ClientWebSocket clientWebSocket = new System.Net.WebSockets.ClientWebSocket();
clientWebSocket.ConnectAsync(new Uri("ws://127.0.0.1:81/live/JT1078_7.live.mp4"), CancellationToken.None).GetAwaiter().GetResult();
Task.Run(async() =>
{
while (true)
{
var buffer = new byte[4096];
var result = await clientWebSocket.ReceiveAsync(buffer, CancellationToken.None);
if (result.EndOfMessage)
{
await fileStream.WriteAsync(buffer.AsSpan(0, result.Count).ToArray());
}
else
{
await fileStream.WriteAsync(buffer);
}
}
});
Thread.Sleep(100 * 1000);
}

[Fact]
public void tkhd_width_height_test()
{
@@ -464,7 +638,7 @@ namespace JT1078.FMp4.Test
//01 20 00 00
var a = BinaryPrimitives.ReadUInt32LittleEndian(new byte[] { 0x01, 0x60, 0, 0 });
var b = BinaryPrimitives.ReadUInt32LittleEndian(new byte[] { 0x01, 0x20, 0, 0 });
//00 00 01 60
//00 00 01 20
var c = BinaryPrimitives.ReadUInt32BigEndian(new byte[] { 0, 0, 0x01, 0x20 });
@@ -495,15 +669,15 @@ namespace JT1078.FMp4.Test
{
var filepath1 = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_1.mp4");
var filepath2 = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "jt1078_1_fragmented.mp4");
var byte1=File.ReadAllBytes(filepath1);
var byte2=File.ReadAllBytes(filepath2);
if(byte1.Length== byte2.Length)
var byte1 = File.ReadAllBytes(filepath1);
var byte2 = File.ReadAllBytes(filepath2);
if (byte1.Length == byte2.Length)
{
for(var i=0;i< byte1.Length; i++)
for (var i = 0; i < byte1.Length; i++)
{
if (byte1[i] != byte2[i])
{
}
}
}
@@ -544,5 +718,24 @@ namespace JT1078.FMp4.Test
}
return packages;
}

public List<JT1078Package> ParseNALUTests1()
{
List<JT1078Package> packages = new List<JT1078Package>();
var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "jt1078_6.txt"));
int mergeBodyLength = 0;
foreach (var line in lines)
{
var bytes = line.ToHexBytes();
JT1078Package package = JT1078Serializer.Deserialize(bytes);
mergeBodyLength += package.DataBodyLength;
var packageMerge = JT1078Serializer.Merge(package);
if (packageMerge != null)
{
packages.Add(packageMerge);
}
}
return packages;
}
}
}

+ 4
- 1
src/JT1078.FMp4/Boxs/MovieBox.cs View File

@@ -40,7 +40,10 @@ namespace JT1078.FMp4
Start(ref writer);
MovieHeaderBox.ToBuffer(ref writer);
TrackBox.ToBuffer(ref writer);
MovieExtendsBox.ToBuffer(ref writer);
if (MovieExtendsBox != null)
{
MovieExtendsBox.ToBuffer(ref writer);
}
if (UserDataBox != null)
{
UserDataBox.ToBuffer(ref writer);


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

@@ -38,6 +38,12 @@ namespace JT1078.FMp4
TrackFragmentBox.ToBuffer(ref writer);
}
End(ref writer);
var moofOffsetPosition = writer.GetMoofOffsetPosition();
if (moofOffsetPosition > 0)
{
writer.WriteUInt64Return((ulong)writer.GetCurrentPosition(), moofOffsetPosition);
}
writer.ClearMoofOffsetPosition();
var trunOffsetPosition = writer.GetTrunOffsetPosition();
if (trunOffsetPosition > 0)
{


+ 1
- 1
src/JT1078.FMp4/Boxs/MovieFragmentRandomAccessBox.cs View File

@@ -38,7 +38,7 @@ namespace JT1078.FMp4
MovieFragmentRandomAccessOffsetBox.ToBuffer(ref writer);
}
End(ref writer);
var mfraSizePosition = writer.GetMfraSizePositionn();
var mfraSizePosition = writer.GetMfraSizePosition();
if (mfraSizePosition > 0)
{
writer.WriteInt32Return(writer.GetCurrentPosition() - SizePosition, mfraSizePosition);


+ 8
- 10
src/JT1078.FMp4/Boxs/SampleDependencyTypeBox.cs View File

@@ -30,15 +30,13 @@ namespace JT1078.FMp4
WriterFullBoxToBuffer(ref writer);
if(SampleDependencyTypes!=null && SampleDependencyTypes.Count > 0)
{
foreach(var item in SampleDependencyTypes)
foreach (var item in SampleDependencyTypes)
{
writer.WriteByte(item.IsLeading);
writer.WriteByte(item.SampleDependsOn);
writer.WriteByte(item.SampleIsDependedOn);
writer.WriteByte(item.SampleHasRedundancy);
writer.WriteByte(item.DegradPrio);
writer.WriteByte(item.IsNonSync);
writer.WriteByte(item.PaddingValue);
writer.WriteByte((byte)(item.IsLeading<<2 |
item.SampleDependsOn |
item.SampleIsDependedOn <<6|
item.SampleHasRedundancy << 4 |
item.IsNonSync));
}
}
End(ref writer);
@@ -50,9 +48,9 @@ namespace JT1078.FMp4
public byte SampleDependsOn { get; set; }
public byte SampleIsDependedOn { get; set; }
public byte SampleHasRedundancy { get; set; }
public byte DegradPrio { get; set; }
//public byte DegradPrio { get; set; }
public byte IsNonSync { get; set; }
public byte PaddingValue { get; set; }
//public byte PaddingValue { get; set; }
}
}
}

+ 3
- 5
src/JT1078.FMp4/Boxs/SampleDescriptionBox.cs View File

@@ -16,15 +16,13 @@ namespace JT1078.FMp4
/// <summary>
/// stsd
/// </summary>
/// <param name="handlerType"></param>
/// <param name="version"></param>
/// <param name="flags"></param>
public SampleDescriptionBox(HandlerType handlerType,byte version=0, uint flags=0) : base("stsd", version, flags)
public SampleDescriptionBox(byte version=0, uint flags=0) : base("stsd", version, flags)
{
HandlerType = handlerType;
}
public HandlerType HandlerType { get; set; }
public uint EntryCount { get; set; }
private uint EntryCount { get; set; }
public List<SampleEntry> SampleEntries { get; set; }
public void ToBuffer(ref FMp4MessagePackWriter writer)
{


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

@@ -26,6 +26,10 @@ namespace JT1078.FMp4
/// </summary>
public TimeToSampleBox TimeToSampleBox { get; set; }
/// <summary>
/// stss
/// </summary>
public SyncSampleBox SyncSampleBox { get; set; }
/// <summary>
/// ctts
/// </summary>
public CompositionOffsetBox CompositionOffsetBox { get; set; }
@@ -44,7 +48,6 @@ namespace JT1078.FMp4
/// </summary>
public ChunkOffsetBox ChunkOffsetBox { get; set; }
//public ChunkLargeOffsetBox ChunkLargeOffsetBox { get; set; }
//public SyncSampleBox SyncSampleBox { get; set; }
//public ShadowSyncSampleBox ShadowSyncSampleBox { get; set; }
//public PaddingBitsBox PaddingBitsBox { get; set; }
//public DegradationPriorityBox DegradationPriorityBox { get; set; }
@@ -58,6 +61,10 @@ namespace JT1078.FMp4
Start(ref writer);
SampleDescriptionBox.ToBuffer(ref writer);
TimeToSampleBox.ToBuffer(ref writer);
if (SyncSampleBox != null)
{
SyncSampleBox.ToBuffer(ref writer);
}
if(CompositionOffsetBox!=null)
CompositionOffsetBox.ToBuffer(ref writer);
SampleToChunkBox.ToBuffer(ref writer);


+ 91
- 19
src/JT1078.FMp4/Boxs/SegmentIndexBox.cs View File

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

namespace JT1078.FMp4
{
public class SegmentIndexBox : FullBox
/// <summary>
/// sidx
/// </summary>
public class SegmentIndexBox : FullBox,IFMp4MessagePackFormatter
{
/// <summary>
/// sidx
/// </summary>
/// <param name="version"></param>
/// <param name="flags"></param>
public SegmentIndexBox(byte version, uint flags=0) : base("sidx", version, flags)
{
ReferencedSizePositions = new List<int>();
}

public uint ReferenceID { get; set; }
public string Timescale { get; set; }
/// <summary>
///
/// </summary>
public ulong EarliestPresentationTimeLarge { get; set; }
public ulong FirstOffsetLarge { get; set; }
public uint ReferenceID { get; set; } = 1;
/// <summary>
/// if(version==0)
///
/// </summary>
public uint EarliestPresentationTime { get; set; }
public uint Timescale { get; set; } = 1000;
/// <summary>
/// if (version==0)
/// pts
/// if(version==0)
/// version==0 32 bit
/// version>0 64 bit
/// </summary>
public ulong EarliestPresentationTime { get; set; }
/// <summary>
///
/// </summary>
public ulong FirstOffset { get; set; } = 0;
private ushort Reserved { get; set; }
//private ushort ReferenceCount { get; set; }
/// <summary>
///
/// </summary>
public uint FirstOffset { get; set; }
public ushort Reserved { get; set; }
public ushort ReferenceCount { get; set; }

public List<SegmentIndex> SegmentIndexs { get; set; }

public List<int> ReferencedSizePositions { get; set; }

public void ToBuffer(ref FMp4MessagePackWriter writer)
{
Start(ref writer);
WriterFullBoxToBuffer(ref writer);
writer.WriteUInt32(ReferenceID);
writer.WriteUInt32(Timescale);
if (Version == 0)
{
writer.WriteUInt32((uint)EarliestPresentationTime);
writer.WriteUInt32((uint)FirstOffset);
}
else
{
writer.WriteUInt64(EarliestPresentationTime);
writer.WriteUInt64(FirstOffset);
}
writer.WriteUInt16(Reserved);
if(SegmentIndexs!=null && SegmentIndexs.Count > 0)
{
writer.WriteUInt16((ushort)SegmentIndexs.Count);
foreach(var si in SegmentIndexs)
{
if (si.ReferenceType)
{
ReferencedSizePositions.Add(writer.GetCurrentPosition());
writer.WriteUInt32(si.ReferencedSize | 0x80000000);
}
else
{
ReferencedSizePositions.Add(writer.GetCurrentPosition());
writer.WriteUInt32(si.ReferencedSize);
}
writer.WriteUInt32(si.SubsegmentDuration);
if (si.StartsWithSAP)
{
writer.WriteUInt32((si.SAPDeltaTime | 0x80000000 | (uint)(si.SAPType << 28 & 0x70000000)));
}
else
{
writer.WriteUInt32((si.SAPDeltaTime | (uint)((si.SAPType <<28) & 0x70000000)));
}
}
}
else
{
writer.WriteUInt16(0);
}
End(ref writer);
}

public class SegmentIndex
{
/// <summary>
/// 4byte 32 - 1
/// </summary>
public bool ReferenceType { get; set; }
public bool ReferenceType { get; set; } = false;
/// <summary>
/// 4byte 32 - 31
/// ReferencedSize=(moof size) + (mdat size)
/// </summary>
public uint ReferencedSize { get; set; } = 0;
/// <summary>
///
/// </summary>
public uint ReferencedSize { get; set; }
public uint SubsegmentDuration { get; set; }
/// <summary>
/// 4byte 32 - 1
/// </summary>
public bool StartsWithSAP { get; set; }
public bool StartsWithSAP { get; set; } = true;
/// <summary>
/// 4byte 32 - 3
/// </summary>
public byte SAPType { get; set; }
public byte SAPType { get; set; } = 1;
/// <summary>
/// 4byte 32 - 28
/// </summary>
public uint SAPDeltaTime { get; set; }
public uint SAPDeltaTime { get; set; } = 0;
}
}
}

+ 51
- 0
src/JT1078.FMp4/Boxs/SegmentTypeBox.cs View File

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

namespace JT1078.FMp4
{
/// <summary>
/// styp
/// </summary>
public class SegmentTypeBox : Mp4Box, IFMp4MessagePackFormatter
{
/// <summary>
/// styp
/// </summary>
public SegmentTypeBox() : base("styp")
{
}
/// <summary>
///因为兼容性一般可以分为推荐兼容性和默认兼容性。这里 major_brand 就相当于是推荐兼容性。通常,在 Web 中解码,一般而言都是使用 isom 这个万金油即可。如果是需要特定的格式,可以自行定义。
/// 4位
/// </summary>
public string MajorBrand { get; set; }
/// <summary>
/// 最低兼容版本
/// 4位
/// </summary>
public string MinorVersion { get; set; } = "\0\0\0\0";
/// <summary>
/// 和MajorBrand类似,通常是针对 MP4 中包含的额外格式,比如,AVC,AAC 等相当于的音视频解码格式。
/// 4位*n
/// </summary>
public List<string> CompatibleBrands { get; set; } = new List<string>();

public void ToBuffer(ref FMp4MessagePackWriter writer)
{
Start(ref writer);
writer.WriteASCII(MajorBrand);
writer.WriteASCII(MinorVersion);
if (CompatibleBrands != null && CompatibleBrands.Count > 0)
{
foreach (var item in CompatibleBrands)
{
writer.WriteASCII(item);
}
}
End(ref writer);
}
}
}

+ 33
- 4
src/JT1078.FMp4/Boxs/SyncSampleBox.cs View File

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

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

public uint EntryCount { get; set; }
//private uint EntryCount { get; set; }

public List<uint> SampleNumber { get; set; }
public List<uint> SampleNumbers { get; set; }

public void ToBuffer(ref FMp4MessagePackWriter writer)
{
Start(ref writer);
WriterFullBoxToBuffer(ref writer);
if(SampleNumbers!=null && SampleNumbers.Count > 0)
{
writer.WriteUInt32((uint)SampleNumbers.Count);
foreach(var item in SampleNumbers)
{
writer.WriteUInt32(item);
}
}
else
{
writer.WriteUInt32(0);
}
End(ref writer);
}
}
}

+ 11
- 1
src/JT1078.FMp4/Boxs/TrackFragmentHeaderBox.cs View File

@@ -49,6 +49,7 @@ namespace JT1078.FMp4
public uint DefaultSampleSize { get; set; }
/// <summary>
/// TFHD_FLAG_DEFAULT_FLAGS
/// MOV_AUDIO == handler_type ? 0x02000000 : (0x00010000| 0x01000000);
/// </summary>
public uint DefaultSampleFlags { get; set; }
#endregion
@@ -59,7 +60,16 @@ namespace JT1078.FMp4
writer.WriteUInt32(TrackID);
if ((FMp4Constants.TFHD_FLAG_BASE_DATA_OFFSET & Flags) > 0)
{
writer.WriteUInt64(BaseDataOffset);
if (BaseDataOffset > 0)
{
writer.WriteUInt64(BaseDataOffset);
}
else
{
//程序自动计算
writer.CreateMoofOffsetPosition();
writer.Skip(8, out _);
}
}
if ((FMp4Constants.TFHD_FLAG_SAMPLE_DESCRIPTION_INDEX & Flags) > 0)
{


+ 21
- 5
src/JT1078.FMp4/Boxs/TrackRunBox.cs View File

@@ -13,13 +13,27 @@ namespace JT1078.FMp4
{
/// <summary>
/// trun
/// 201 205 1
/// 201 0010 0000 0001
/// 205 0010 0000 0101
/// 1 0000 0000 0001
/// tr_flags 是用来表示下列 sample 相关的标识符是否应用到每个字段中:
/// 0x000001-0000 0000 0001: data-offset-present,只应用 data-offset
/// 0x000004-0000 0000 0100: 只对第一个 sample 应用对应的 flags。剩余 sample flags 就不管了。
/// 0x000100-0001 0000 0000: 这个比较重要,表示每个 sample 都有自己的 duration,否则使用默认的
/// 0x000200-0010 0000 0000: 每个 sample 有自己的 sample_size,否则使用默认的。
/// 0x000400-0100 0000 0000: 对每个 sample 使用自己的 flags。否则,使用默认的。
/// 0x000800-1000 0000 0000: 每个 sample 都有自己的 cts 值
/// 0x000f01-1111 0000 0001
/// </summary>
/// <param name="version"></param>
/// <param name="flags"></param>
public TrackRunBox(byte version=0, uint flags= 0x000f01) : base("trun", version, flags)
{
}

/// <summary>
///
/// </summary>
public uint SampleCount { get; set; }
/// <summary>
/// 可选的
@@ -88,11 +102,11 @@ namespace JT1078.FMp4
{
if (Version == 0)
{
writer.WriteUInt32(trun.SampleCompositionTimeOffset);
writer.WriteUInt32((uint)trun.SampleCompositionTimeOffset);
}
else
{
writer.WriteInt32(trun.SignedSampleCompositionTimeOffset);
writer.WriteInt32((int)trun.SampleCompositionTimeOffset);
}
}
}
@@ -106,10 +120,12 @@ namespace JT1078.FMp4
public uint SampleSize { get; set; }
public uint SampleFlags { get; set; }
/// <summary>
/// cts
/// version == 0
/// 0:uint
/// >0:int
/// </summary>
public uint SampleCompositionTimeOffset { get; set; }
public int SignedSampleCompositionTimeOffset { get; set; }
public long SampleCompositionTimeOffset { get; set; }
}
}
}

+ 160
- 44
src/JT1078.FMp4/FMp4Encoder.cs View File

@@ -2,6 +2,7 @@
using JT1078.FMp4.MessagePack;
using JT1078.FMp4.Samples;
using JT1078.Protocol;
using JT1078.Protocol.Enums;
using JT1078.Protocol.H264;
using JT1078.Protocol.MessagePack;
using System;
@@ -17,65 +18,92 @@ namespace JT1078.FMp4
/// stream data
/// ftyp
/// moov
/// styp 1
/// moof 1
/// mdat 1
/// ...
/// styp n
/// moof n
/// mdat n
/// mfra
/// ref: https://www.w3.org/TR/mse-byte-stream-format-isobmff/#movie-fragment-relative-addressing
/// </summary>
public class FMp4Encoder
{
readonly H264Decoder h264Decoder;
Dictionary<string, TrackInfo> TrackInfos;

const uint DefaultSampleDuration = 40u;
const uint DefaultSampleFlags = 0x1010000;
const uint FirstSampleFlags = 33554432;
const uint TfhdFlags = 0x2003a;
//const uint TrunFlags = 0x205;
const uint TrunFlags = 0x205;
const uint SampleDescriptionIndex = 1;
const uint TrackID = 1;

/// <summary>
///
/// </summary>
public FMp4Encoder()
{
h264Decoder = new H264Decoder();
TrackInfos = new Dictionary<string, TrackInfo>(StringComparer.OrdinalIgnoreCase);
}

/// <summary>
/// 编码首个视频盒子
/// 编码ftyp盒子
/// </summary>
/// <param name="package">jt1078完整包</param>
/// <returns></returns>
public byte[] EncoderFirstVideoBox(JT1078Package package)
public byte[] FtypBox()
{
byte[] buffer = FMp4ArrayPool.Rent(package.Bodies.Length + 4096);
FMp4MessagePackWriter writer = new FMp4MessagePackWriter(new byte[10 * 1024 * 1024]);
byte[] buffer = FMp4ArrayPool.Rent(1024);
FMp4MessagePackWriter writer = new FMp4MessagePackWriter(buffer);
try
{
var nalus = h264Decoder.ParseNALU(package);
var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 7);
//SPS
spsNALU.RawData = h264Decoder.DiscardEmulationPreventionBytes(spsNALU.RawData);
var ppsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 8);
ppsNALU.RawData = h264Decoder.DiscardEmulationPreventionBytes(ppsNALU.RawData);
ExpGolombReader h264GolombReader = new ExpGolombReader(spsNALU.RawData);
var spsInfo = h264GolombReader.ReadSPS();
//ftyp
FileTypeBox fileTypeBox = new FileTypeBox();
fileTypeBox.MajorBrand = "isom";
fileTypeBox.MinorVersion = "\0\0\u0002\0";
fileTypeBox.CompatibleBrands.Add("isom");
fileTypeBox.CompatibleBrands.Add("iso6");
fileTypeBox.CompatibleBrands.Add("iso2");
fileTypeBox.CompatibleBrands.Add("avc1");
fileTypeBox.CompatibleBrands.Add("mp41");
fileTypeBox.CompatibleBrands.Add("iso5");
fileTypeBox.CompatibleBrands.Add("iso6");
fileTypeBox.ToBuffer(ref writer);
var data = writer.FlushAndGetArray();
return data;
}
finally
{
FMp4ArrayPool.Return(buffer);
}
}

/// <summary>
/// 编码moov盒子
/// </summary>
/// <returns></returns>
public byte[] VideoMoovBox(in H264NALU sps, in H264NALU pps)
{
byte[] buffer = FMp4ArrayPool.Rent(sps.RawData.Length + pps.RawData.Length + 1024);
FMp4MessagePackWriter writer = new FMp4MessagePackWriter(buffer);
try
{
ExpGolombReader h264GolombReader = new ExpGolombReader(sps.RawData);
var spsInfo = h264GolombReader.ReadSPS();
//moov
MovieBox movieBox = new MovieBox();
movieBox.MovieHeaderBox = new MovieHeaderBox(0, 0);
movieBox.MovieHeaderBox = new MovieHeaderBox(0, 2);
movieBox.MovieHeaderBox.CreationTime = 0;
movieBox.MovieHeaderBox.ModificationTime = 0;
movieBox.MovieHeaderBox.Duration = 0;
movieBox.MovieHeaderBox.Timescale = 1000;
movieBox.MovieHeaderBox.NextTrackID = 2;
movieBox.MovieHeaderBox.NextTrackID = 99;
movieBox.TrackBox = new TrackBox();
movieBox.TrackBox.TrackHeaderBox = new TrackHeaderBox(0, 3);
movieBox.TrackBox.TrackHeaderBox.CreationTime = 0;
movieBox.TrackBox.TrackHeaderBox.ModificationTime = 0;
movieBox.TrackBox.TrackHeaderBox.TrackID = 1;
movieBox.TrackBox.TrackHeaderBox.TrackID = TrackID;
movieBox.TrackBox.TrackHeaderBox.Duration = 0;
movieBox.TrackBox.TrackHeaderBox.TrackIsAudio = false;
movieBox.TrackBox.TrackHeaderBox.Width = (uint)spsInfo.width;
@@ -84,7 +112,8 @@ namespace JT1078.FMp4
movieBox.TrackBox.MediaBox.MediaHeaderBox = new MediaHeaderBox();
movieBox.TrackBox.MediaBox.MediaHeaderBox.CreationTime = 0;
movieBox.TrackBox.MediaBox.MediaHeaderBox.ModificationTime = 0;
movieBox.TrackBox.MediaBox.MediaHeaderBox.Timescale = 1200000;
//movieBox.TrackBox.MediaBox.MediaHeaderBox.Timescale = 1200000;
movieBox.TrackBox.MediaBox.MediaHeaderBox.Timescale = 1000;
movieBox.TrackBox.MediaBox.MediaHeaderBox.Duration = 0;
movieBox.TrackBox.MediaBox.HandlerBox = new HandlerBox();
movieBox.TrackBox.MediaBox.HandlerBox.HandlerType = HandlerType.vide;
@@ -96,7 +125,7 @@ namespace JT1078.FMp4
movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox.DataReferenceBox.DataEntryBoxes = new List<DataEntryBox>();
movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox.DataReferenceBox.DataEntryBoxes.Add(new DataEntryUrlBox(1));
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox = new SampleTableBox();
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox = new SampleDescriptionBox(movieBox.TrackBox.MediaBox.HandlerBox.HandlerType);
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox = new SampleDescriptionBox();
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox.SampleEntries = new List<SampleEntry>();
AVC1SampleEntry avc1 = new AVC1SampleEntry();
avc1.AVCConfigurationBox = new AVCConfigurationBox();
@@ -106,23 +135,23 @@ namespace JT1078.FMp4
avc1.AVCConfigurationBox.AVCLevelIndication = spsInfo.levelIdc;
avc1.AVCConfigurationBox.AVCProfileIndication = spsInfo.profileIdc;
avc1.AVCConfigurationBox.ProfileCompatibility = (byte)spsInfo.profileCompat;
avc1.AVCConfigurationBox.PPSs = new List<byte[]>() { ppsNALU.RawData };
avc1.AVCConfigurationBox.SPSs = new List<byte[]>() { spsNALU.RawData };
avc1.AVCConfigurationBox.PPSs = new List<byte[]>() { pps.RawData };
avc1.AVCConfigurationBox.SPSs = new List<byte[]>() { sps.RawData };
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox.SampleEntries.Add(avc1);
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.TimeToSampleBox = new TimeToSampleBox();
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SyncSampleBox = new SyncSampleBox();
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleToChunkBox = new SampleToChunkBox();
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleSizeBox = new SampleSizeBox();
movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.ChunkOffsetBox = new ChunkOffsetBox();
movieBox.MovieExtendsBox = new MovieExtendsBox();
movieBox.MovieExtendsBox.TrackExtendsBoxs = new List<TrackExtendsBox>();
TrackExtendsBox trex = new TrackExtendsBox();
trex.TrackID = 1;
trex.DefaultSampleDescriptionIndex = 1;
trex.TrackID = TrackID;
trex.DefaultSampleDescriptionIndex = SampleDescriptionIndex;
trex.DefaultSampleDuration = 0;
trex.DefaultSampleSize = 0;
trex.DefaultSampleFlags = 0;
movieBox.MovieExtendsBox.TrackExtendsBoxs.Add(trex);
fileTypeBox.ToBuffer(ref writer);
movieBox.ToBuffer(ref writer);
var data = writer.FlushAndGetArray();
return data;
@@ -133,40 +162,121 @@ namespace JT1078.FMp4
}
}

/// <summary>
/// styp
/// </summary>
/// <returns></returns>
public byte[] StypBox()
{
byte[] buffer = FMp4ArrayPool.Rent(1024);
FMp4MessagePackWriter writer = new FMp4MessagePackWriter(buffer);
try
{
SegmentTypeBox stypTypeBox = new SegmentTypeBox();
stypTypeBox.MajorBrand = "isom";
stypTypeBox.MinorVersion = "\0\0\0\0";
stypTypeBox.CompatibleBrands.Add("isom");
stypTypeBox.CompatibleBrands.Add("mp42");
stypTypeBox.CompatibleBrands.Add("msdh");
stypTypeBox.CompatibleBrands.Add("msix");
stypTypeBox.CompatibleBrands.Add("iso5");
stypTypeBox.CompatibleBrands.Add("iso6");
stypTypeBox.ToBuffer(ref writer);
var data = writer.FlushAndGetArray();
return data;
}
finally
{
FMp4ArrayPool.Return(buffer);
}
}

/// <summary>
/// 编码其他视频数据盒子
/// </summary>
/// <param name="package">jt1078完整包</param>
/// <param name="moofOffset">moof位置</param>
/// <returns></returns>
public byte[] EncoderOtherVideoBox(JT1078Package package, ulong moofOffset = 0)
public byte[] OtherVideoBox(in List<H264NALU> nalus)
{
byte[] buffer = FMp4ArrayPool.Rent(package.Bodies.Length + 4096);
byte[] buffer = FMp4ArrayPool.Rent(nalus.Sum(s => s.RawData.Length + s.StartCodePrefix.Length) + 4096);
FMp4MessagePackWriter writer = new FMp4MessagePackWriter(buffer);
try
{
var nalus = h264Decoder.ParseNALU(package);
var truns = new List<TrackRunBox.TrackRunInfo>();
List<byte[]> rawdatas = new List<byte[]>();
uint iSize = 0;
ulong lastTimestamp = 0;
string key = string.Empty;
for (var i = 0; i < nalus.Count; i++)
{
var nalu = nalus[i];
if (string.IsNullOrEmpty(key))
{
key = nalu.GetKey();
}
rawdatas.Add(nalu.RawData);
if (nalu.DataType == Protocol.Enums.JT1078DataType.视频I帧)
{
iSize += (uint)(nalu.RawData.Length + nalu.StartCodePrefix.Length);
}
else
{
if (iSize > 0)
{
truns.Add(new TrackRunBox.TrackRunInfo()
{
SampleDuration=40,
SampleSize = iSize,
});
iSize = 0;
}
truns.Add(new TrackRunBox.TrackRunInfo()
{
SampleDuration = 40,
SampleSize = (uint)(nalu.RawData.Length + nalu.StartCodePrefix.Length),
});
}
if (i == (nalus.Count - 1))
{
lastTimestamp = nalu.Timestamp;
}
}
if (TrackInfos.TryGetValue(key, out TrackInfo trackInfo))
{
if (trackInfo.SN == uint.MaxValue)
{
trackInfo.SN = 1;
}
trackInfo.SN++;
}
else
{
trackInfo = new TrackInfo { SN = 1, DTS = 0 };
TrackInfos.Add(key, trackInfo);
}
var movieFragmentBox = new MovieFragmentBox();
movieFragmentBox.MovieFragmentHeaderBox = new MovieFragmentHeaderBox();
movieFragmentBox.MovieFragmentHeaderBox.SequenceNumber = package.SN;
movieFragmentBox.MovieFragmentHeaderBox.SequenceNumber = trackInfo.SN;
movieFragmentBox.TrackFragmentBox = new TrackFragmentBox();
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox = new TrackFragmentHeaderBox(0x39);
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.TrackID = 1;
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.BaseDataOffset = moofOffset;
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleDuration = 48000;
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleSize = (uint)package.Bodies.Length;
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleFlags = 0x1010000;
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox = new TrackFragmentHeaderBox(TfhdFlags);
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.TrackID = TrackID;
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.SampleDescriptionIndex = SampleDescriptionIndex;
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleDuration = DefaultSampleDuration;
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleSize = truns[0].SampleSize;
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleFlags = DefaultSampleFlags;
movieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox = new TrackFragmentBaseMediaDecodeTimeBox();
movieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox.BaseMediaDecodeTime = package.Timestamp * 1000;
movieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox.BaseMediaDecodeTime = trackInfo.DTS;
trackInfo.DTS += (ulong)(truns.Count * DefaultSampleDuration);
TrackInfos[key] = trackInfo;
//trun
movieFragmentBox.TrackFragmentBox.TrackRunBox = new TrackRunBox(flags: 0x5);
movieFragmentBox.TrackFragmentBox.TrackRunBox.FirstSampleFlags = 0;
movieFragmentBox.TrackFragmentBox.TrackRunBox.TrackRunInfos = new List<TrackRunBox.TrackRunInfo>();
movieFragmentBox.TrackFragmentBox.TrackRunBox.TrackRunInfos.Add(new TrackRunBox.TrackRunInfo());
movieFragmentBox.TrackFragmentBox.TrackRunBox = new TrackRunBox(flags: TrunFlags);
movieFragmentBox.TrackFragmentBox.TrackRunBox.FirstSampleFlags = FirstSampleFlags;
movieFragmentBox.TrackFragmentBox.TrackRunBox.TrackRunInfos = truns;
movieFragmentBox.ToBuffer(ref writer);

var mediaDataBox = new MediaDataBox();
mediaDataBox.Data = nalus.Select(s => s.RawData).ToList();
mediaDataBox.Data = rawdatas;
mediaDataBox.ToBuffer(ref writer);

var data = writer.FlushAndGetArray();
return data;
}
@@ -175,5 +285,11 @@ namespace JT1078.FMp4
FMp4ArrayPool.Return(buffer);
}
}

struct TrackInfo
{
public uint SN { get; set; }
public ulong DTS { get; set; }
}
}
}

+ 3
- 5
src/JT1078.FMp4/JT1078.FMp4.csproj View File

@@ -13,8 +13,8 @@
<PackageProjectUrl>https://github.com/SmallChi/JT1078</PackageProjectUrl>
<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.0-preview1</Version>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>1.0.0-preview5</Version>
<SignAssembly>false</SignAssembly>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
@@ -27,9 +27,7 @@
<PackagePath></PackagePath>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\JT1078.Protocol\JT1078.Protocol.csproj" />
</ItemGroup>


+ 119
- 11
src/JT1078.FMp4/JT1078.FMp4.xml View File

@@ -571,11 +571,10 @@
stsd
</summary>
</member>
<member name="M:JT1078.FMp4.SampleDescriptionBox.#ctor(JT1078.FMp4.Enums.HandlerType,System.Byte,System.UInt32)">
<member name="M:JT1078.FMp4.SampleDescriptionBox.#ctor(System.Byte,System.UInt32)">
<summary>
stsd
</summary>
<param name="handlerType"></param>
<param name="version"></param>
<param name="flags"></param>
</member>
@@ -622,6 +621,11 @@
stts
</summary>
</member>
<member name="P:JT1078.FMp4.SampleTableBox.SyncSampleBox">
<summary>
stss
</summary>
</member>
<member name="P:JT1078.FMp4.SampleTableBox.CompositionOffsetBox">
<summary>
ctts
@@ -672,19 +676,44 @@
</summary>
</member>
<!-- Badly formed XML comment ignored for member "P:JT1078.FMp4.SchemeTypeBox.SchemeUri" -->
<member name="P:JT1078.FMp4.SegmentIndexBox.EarliestPresentationTimeLarge">
<member name="T:JT1078.FMp4.SegmentIndexBox">
<summary>
sidx
</summary>
</member>
<member name="M:JT1078.FMp4.SegmentIndexBox.#ctor(System.Byte,System.UInt32)">
<summary>
sidx
</summary>
<param name="version"></param>
<param name="flags"></param>
</member>
<member name="P:JT1078.FMp4.SegmentIndexBox.ReferenceID">
<summary>
</summary>
</member>
<member name="P:JT1078.FMp4.SegmentIndexBox.Timescale">
<summary>
</summary>
</member>
<member name="P:JT1078.FMp4.SegmentIndexBox.EarliestPresentationTime">
<summary>
if(version==0)
pts
if(version==0)
version==0 32 bit
version>0 64 bit
</summary>
</member>
<member name="P:JT1078.FMp4.SegmentIndexBox.FirstOffset">
<summary>
if (version==0)
</summary>
</member>
<member name="P:JT1078.FMp4.SegmentIndexBox.SegmentIndexs">
<summary>
</summary>
</member>
<member name="P:JT1078.FMp4.SegmentIndexBox.SegmentIndex.ReferenceType">
@@ -695,6 +724,12 @@
<member name="P:JT1078.FMp4.SegmentIndexBox.SegmentIndex.ReferencedSize">
<summary>
4byte 32 - 31
ReferencedSize=(moof size) + (mdat size)
</summary>
</member>
<member name="P:JT1078.FMp4.SegmentIndexBox.SegmentIndex.SubsegmentDuration">
<summary>
</summary>
</member>
<member name="P:JT1078.FMp4.SegmentIndexBox.SegmentIndex.StartsWithSAP">
@@ -712,6 +747,34 @@
4byte 32 - 28
</summary>
</member>
<member name="T:JT1078.FMp4.SegmentTypeBox">
<summary>
styp
</summary>
</member>
<member name="M:JT1078.FMp4.SegmentTypeBox.#ctor">
<summary>
styp
</summary>
</member>
<member name="P:JT1078.FMp4.SegmentTypeBox.MajorBrand">
<summary>
因为兼容性一般可以分为推荐兼容性和默认兼容性。这里 major_brand 就相当于是推荐兼容性。通常,在 Web 中解码,一般而言都是使用 isom 这个万金油即可。如果是需要特定的格式,可以自行定义。
4位
</summary>
</member>
<member name="P:JT1078.FMp4.SegmentTypeBox.MinorVersion">
<summary>
最低兼容版本
4位
</summary>
</member>
<member name="P:JT1078.FMp4.SegmentTypeBox.CompatibleBrands">
<summary>
和MajorBrand类似,通常是针对 MP4 中包含的额外格式,比如,AVC,AAC 等相当于的音视频解码格式。
4位*n
</summary>
</member>
<member name="P:JT1078.FMp4.StereoVideoBox.Reserved">
<summary>
4btye 32 - 30
@@ -770,6 +833,18 @@
length:ItemCount
</summary>
</member>
<member name="T:JT1078.FMp4.SyncSampleBox">
<summary>
stss
</summary>
</member>
<member name="M:JT1078.FMp4.SyncSampleBox.#ctor(System.Byte,System.UInt32)">
<summary>
stss
</summary>
<param name="version"></param>
<param name="flags"></param>
</member>
<member name="T:JT1078.FMp4.TimeToSampleBox">
<summary>
stts
@@ -908,6 +983,7 @@
<member name="P:JT1078.FMp4.TrackFragmentHeaderBox.DefaultSampleFlags">
<summary>
TFHD_FLAG_DEFAULT_FLAGS
MOV_AUDIO == handler_type ? 0x02000000 : (0x00010000| 0x01000000);
</summary>
</member>
<member name="T:JT1078.FMp4.TrackFragmentRandomAccessBox">
@@ -978,10 +1054,27 @@
<member name="M:JT1078.FMp4.TrackRunBox.#ctor(System.Byte,System.UInt32)">
<summary>
trun
201 205 1
201 0010 0000 0001
205 0010 0000 0101
1 0000 0000 0001
tr_flags 是用来表示下列 sample 相关的标识符是否应用到每个字段中:
0x000001-0000 0000 0001: data-offset-present,只应用 data-offset
0x000004-0000 0000 0100: 只对第一个 sample 应用对应的 flags。剩余 sample flags 就不管了。
0x000100-0001 0000 0000: 这个比较重要,表示每个 sample 都有自己的 duration,否则使用默认的
0x000200-0010 0000 0000: 每个 sample 有自己的 sample_size,否则使用默认的。
0x000400-0100 0000 0000: 对每个 sample 使用自己的 flags。否则,使用默认的。
0x000800-1000 0000 0000: 每个 sample 都有自己的 cts 值
0x000f01-1111 0000 0001
</summary>
<param name="version"></param>
<param name="flags"></param>
</member>
<member name="P:JT1078.FMp4.TrackRunBox.SampleCount">
<summary>
</summary>
</member>
<member name="P:JT1078.FMp4.TrackRunBox.DataOffset">
<summary>
可选的
@@ -1002,7 +1095,10 @@
</member>
<member name="P:JT1078.FMp4.TrackRunBox.TrackRunInfo.SampleCompositionTimeOffset">
<summary>
cts
version == 0
0:uint
>0:int
</summary>
</member>
<member name="T:JT1078.FMp4.URIBox">
@@ -1213,12 +1309,15 @@
stream data
ftyp
moov
styp 1
moof 1
mdat 1
...
styp n
moof n
mdat n
mfra
ref: https://www.w3.org/TR/mse-byte-stream-format-isobmff/#movie-fragment-relative-addressing
</summary>
</member>
<member name="M:JT1078.FMp4.FMp4Encoder.#ctor">
@@ -1226,19 +1325,28 @@
</summary>
</member>
<member name="M:JT1078.FMp4.FMp4Encoder.EncoderFirstVideoBox(JT1078.Protocol.JT1078Package)">
<member name="M:JT1078.FMp4.FMp4Encoder.FtypBox">
<summary>
编码ftyp盒子
</summary>
<returns></returns>
</member>
<member name="M:JT1078.FMp4.FMp4Encoder.VideoMoovBox(JT1078.Protocol.H264.H264NALU@,JT1078.Protocol.H264.H264NALU@)">
<summary>
编码moov盒子
</summary>
<returns></returns>
</member>
<member name="M:JT1078.FMp4.FMp4Encoder.StypBox">
<summary>
编码首个视频盒子
styp
</summary>
<param name="package">jt1078完整包</param>
<returns></returns>
</member>
<member name="M:JT1078.FMp4.FMp4Encoder.EncoderOtherVideoBox(JT1078.Protocol.JT1078Package,System.UInt64)">
<member name="M:JT1078.FMp4.FMp4Encoder.OtherVideoBox(System.Collections.Generic.List{JT1078.Protocol.H264.H264NALU}@)">
<summary>
编码其他视频数据盒子
</summary>
<param name="package">jt1078完整包</param>
<param name="moofOffset">moof位置</param>
<returns></returns>
</member>
<member name="P:JT1078.FMp4.FullBox.Version">


+ 23
- 1
src/JT1078.FMp4/MessagePack/FMp4MessagePackWriter.cs View File

@@ -13,12 +13,14 @@ namespace JT1078.FMp4.MessagePack
private int TrunDataOffsetPosition;

private int MfraSizePosition;
private int MoofOffsetPosition;

public FMp4MessagePackWriter(Span<byte> buffer)
{
this.writer = new FMp4BufferWriter(buffer);
TrunDataOffsetPosition = 0;
MfraSizePosition = 0;
MoofOffsetPosition = 0;
}
public byte[] FlushAndGetArray()
{
@@ -109,6 +111,10 @@ namespace JT1078.FMp4.MessagePack
{
BinaryPrimitives.WriteUInt32BigEndian(writer.Written.Slice(position, 4), value);
}
public void WriteUInt64Return(ulong value, int position)
{
BinaryPrimitives.WriteUInt64BigEndian(writer.Written.Slice(position, 8), value);
}
public void WriteByteReturn(byte value, int position)
{
writer.Written[position] = value;
@@ -139,7 +145,7 @@ namespace JT1078.FMp4.MessagePack
MfraSizePosition = writer.WrittenCount;
}

public int GetMfraSizePositionn()
public int GetMfraSizePosition()
{
return MfraSizePosition;
}
@@ -149,6 +155,22 @@ namespace JT1078.FMp4.MessagePack
MfraSizePosition = 0;
}

public void CreateMoofOffsetPosition()
{
MoofOffsetPosition = writer.WrittenCount;
}

public int GetMoofOffsetPosition()
{
return MoofOffsetPosition;
}

public void ClearMoofOffsetPosition()
{
MoofOffsetPosition = 0;
}


/// <summary>
/// ref
/// </summary>


+ 7
- 4
src/JT1078.Flv/FlvEncoder.cs View File

@@ -40,6 +40,9 @@ namespace JT1078.Flv
readonly H264Decoder h264Decoder;
readonly AudioCodecFactory audioCodecFactory;
//public FlvEncoder(int sampleRate = 8000, int channels = 1, int sampleBit = 16, bool adts = false)
/// <summary>
///
/// </summary>
public FlvEncoder()
{
audioCodecFactory = new AudioCodecFactory();
@@ -207,9 +210,9 @@ namespace JT1078.Flv
var nalus = h264Decoder.ParseNALU(package);
if (nalus != null && nalus.Count > 0)
{
var sei = nalus.FirstOrDefault(x => x.NALUHeader.NalUnitType == 6);
var sps = nalus.FirstOrDefault(x => x.NALUHeader.NalUnitType == 7);
var pps = nalus.FirstOrDefault(x => x.NALUHeader.NalUnitType == 8);
var sei = nalus.FirstOrDefault(x => x.NALUHeader.NalUnitType == NalUnitType.SEI);
var sps = nalus.FirstOrDefault(x => x.NALUHeader.NalUnitType == NalUnitType.SPS);
var pps = nalus.FirstOrDefault(x => x.NALUHeader.NalUnitType == NalUnitType.PPS);
nalus.Remove(sps);
nalus.Remove(pps);
nalus.Remove(sei);
@@ -297,7 +300,7 @@ namespace JT1078.Flv
//1: keyframe (for AVC, a seekable frame) —— 即H.264的IDR帧;
//2: inter frame(for AVC, a non - seekable frame) —— H.264的普通I帧;
//ref:https://www.cnblogs.com/chyingp/p/flv-getting-started.html
if (nALU.NALUHeader.NalUnitType == 5)
if (nALU.NALUHeader.NalUnitType == NalUnitType.IDR)
{
flvTags.VideoTagsData.FrameType = FrameType.KeyFrame;
}


+ 1
- 1
src/JT1078.Flv/JT1078.Flv.csproj View File

@@ -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.1.0</Version>
<Version>1.1.1-preview1</Version>
<SignAssembly>false</SignAssembly>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<PackageLicenseFile>LICENSE</PackageLicenseFile>


+ 5
- 0
src/JT1078.Flv/JT1078.Flv.xml View File

@@ -181,6 +181,11 @@
4、<see cref="M:JT1078.Flv.FlvEncoder.EncoderAudioTag(JT1078.Protocol.JT1078Package,System.Boolean)"/>第二个参数传true
</summary>
</member>
<member name="M:JT1078.Flv.FlvEncoder.#ctor">
<summary>
</summary>
</member>
<member name="M:JT1078.Flv.FlvEncoder.EncoderFlvHeader(System.Boolean,System.Boolean)">
<summary>
编码flv头


+ 3
- 0
src/JT1078.Hls.Test/JT1078.Hls.Test.csproj View File

@@ -42,5 +42,8 @@
<None Include="..\..\doc\video\jt1078_2.txt" Link="H264\jt1078_2.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="..\..\doc\video\jt1078_5.txt" Link="H264\jt1078_5.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

+ 44
- 1
src/JT1078.Hls.Test/M3U8_Test.cs View File

@@ -5,11 +5,54 @@ using System.IO;
using System.Text;
using Xunit;
using JT1078.Protocol.Extensions;

using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities;
using System.Net.Sockets;
using System.Threading;
namespace JT1078.Hls.Test
{
public class M3U8_Test
{
/// <summary>
/// 模拟发送视频数据
/// </summary>
[Fact]
public void Test1()
{
try
{
var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "jt1078_5.txt"));
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
clientSocket.Connect("127.0.0.1", 10888);
long lasttime = 0;
foreach (var line in lines)
{
var temp = line.Split(',');
if (lasttime == 0)
{
lasttime = long.Parse(temp[0]);
}
else
{
var ts = long.Parse(temp[0]) - lasttime;
if(ts>0)
{
Thread.Sleep(TimeSpan.FromMilliseconds(ts));
}
else if (ts == 0)
{
}
lasttime = long.Parse(temp[0]);
}
var data= temp[1].ToHexBytes();
clientSocket.Send(data);
}
}
catch (Exception ex)
{
//Assert.Throws<Exception>(() => { });
}
}
/// <summary>
/// 生成m3u8索引文件
/// </summary>


+ 6
- 6
src/JT1078.Hls.Test/TS_Package_Test.cs View File

@@ -90,13 +90,13 @@ namespace JT1078.Hls.Test
JT1078Package fullpackage = JT1078Serializer.Merge(package);
if (fullpackage != null)
{
var sdt = tSEncoder.CreateSDT(fullpackage);
var sdt = tSEncoder.CreateSDT();
string sdtHEX = sdt.ToHexString();
fileStream.Write(sdt);
var pat = tSEncoder.CreatePAT(fullpackage);
var pat = tSEncoder.CreatePAT();
string patHEX = pat.ToHexString();
fileStream.Write(pat);
var pmt = tSEncoder.CreatePMT(fullpackage);
var pmt = tSEncoder.CreatePMT();
fileStream.Write(pmt);
var pes = tSEncoder.CreatePES(fullpackage);
fileStream.Write(pes);
@@ -139,13 +139,13 @@ namespace JT1078.Hls.Test
{
if (isNeedFirstHeadler)
{
var sdt = tSEncoder.CreateSDT(fullpackage);
var sdt = tSEncoder.CreateSDT();
string sdtHEX = sdt.ToHexString();
fileStream.Write(sdt);
var pat = tSEncoder.CreatePAT(fullpackage);
var pat = tSEncoder.CreatePAT();
string patHEX = pat.ToHexString();
fileStream.Write(pat);
var pmt = tSEncoder.CreatePMT(fullpackage);
var pmt = tSEncoder.CreatePMT();
fileStream.Write(pmt);
var pes = tSEncoder.CreatePES(fullpackage, 18888);
fileStream.Write(pes);


+ 5
- 6
src/JT1078.Hls/JT1078.Hls.csproj View File

@@ -7,14 +7,14 @@
<Authors>SmallChi(Koike)</Authors>
<PackageId>JT1078.Hls</PackageId>
<Product>JT1078.Hls</Product>
<Description>基于JT1078的Hls视频编码器</Description>
<Description>基于JT1078的Hls视频编码器、ts文件路径参数名改成可配置</Description>
<PackageReleaseNotes>基于JT1078的Hls视频编码器</PackageReleaseNotes>
<RepositoryUrl>https://github.com/SmallChi/JT1078</RepositoryUrl>
<PackageProjectUrl>https://github.com/SmallChi/JT1078</PackageProjectUrl>
<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.1.0-preview1</Version>
<Version>1.1.0-preview4</Version>
<SignAssembly>false</SignAssembly>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
@@ -24,10 +24,6 @@
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<PackageReference Include="System.Memory" Version="4.5.4" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\JT1078.Protocol\JT1078.Protocol.csproj" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\LICENSE">
<Pack>True</Pack>
@@ -37,4 +33,7 @@
<ItemGroup>
<PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\JT1078.Protocol\JT1078.Protocol.csproj" />
</ItemGroup>
</Project>

+ 44
- 0
src/JT1078.Hls/JT1078.Hls.xml View File

@@ -96,6 +96,19 @@
m3u8文件管理
</summary>
</member>
<member name="M:JT1078.Hls.M3U8FileManage.#ctor(JT1078.Hls.Options.M3U8Option)">
<summary>
</summary>
<param name="m3U8Option"></param>
</member>
<member name="M:JT1078.Hls.M3U8FileManage.#ctor(JT1078.Hls.Options.M3U8Option,JT1078.Hls.TSEncoder)">
<summary>
</summary>
<param name="m3U8Option"></param>
<param name="tSEncoder"></param>
</member>
<member name="M:JT1078.Hls.M3U8FileManage.CreateTsData(JT1078.Protocol.JT1078Package)">
<summary>
生成ts和m3u8文件
@@ -132,6 +145,12 @@
<param name="key">终端号_通道号(用作目录)</param>
<param name="data">文件内容</param>
</member>
<member name="M:JT1078.Hls.M3U8FileManage.AppendM3U8End">
<summary>
添加结束标识
直播流用不到
</summary>
</member>
<member name="M:JT1078.Hls.M3U8FileManage.Clear(System.String,System.Int32)">
<summary>
停止观看直播时清零数据
@@ -144,6 +163,16 @@
TS文件信息
</summary>
</member>
<member name="P:JT1078.Hls.M3U8FileManage.TsFileInfo.Sim">
<summary>
设备手机号
</summary>
</member>
<member name="P:JT1078.Hls.M3U8FileManage.TsFileInfo.ChannelNo">
<summary>
设备逻辑通道号
</summary>
</member>
<member name="P:JT1078.Hls.M3U8FileManage.TsFileInfo.FileName">
<summary>
ts文件名
@@ -184,6 +213,16 @@
每个ts文件的最大时长
</summary>
</member>
<member name="P:JT1078.Hls.Options.M3U8Option.TsPathSimParamName">
<summary>
ts路径sim参数名称
</summary>
</member>
<member name="P:JT1078.Hls.Options.M3U8Option.TsPathChannelParamName">
<summary>
ts路径通道参数名称
</summary>
</member>
<member name="P:JT1078.Hls.Options.M3U8Option.M3U8FileName">
<summary>
m3u8文件
@@ -263,6 +302,11 @@
4.PES
</summary>
</member>
<member name="M:JT1078.Hls.TSEncoder.#ctor">
<summary>
</summary>
</member>
<member name="P:JT1078.Hls.TS_AdaptationInfo.PCRIncluded">
<summary>
取0x50表示包含PCR或0x40表示不包含PCR


+ 52
- 23
src/JT1078.Hls/M3U8FileManage.cs View File

@@ -19,15 +19,28 @@ namespace JT1078.Hls
public class M3U8FileManage
{
private TSEncoder tSEncoder;
public readonly M3U8Option m3U8Option;
private M3U8Option m3U8Option;
ConcurrentDictionary<string, TsFileInfo> curTsFileInfoDic = new ConcurrentDictionary<string, TsFileInfo>();//当前文件信息
ConcurrentDictionary<string, Queue<TsFileInfo>> tsFileInfoQueueDic = new ConcurrentDictionary<string, Queue<TsFileInfo>>();
/// <summary>
///
/// </summary>
/// <param name="m3U8Option"></param>
public M3U8FileManage(M3U8Option m3U8Option):this(m3U8Option, new TSEncoder())
{

}
/// <summary>
///
/// </summary>
/// <param name="m3U8Option"></param>
/// <param name="tSEncoder"></param>
public M3U8FileManage(M3U8Option m3U8Option, TSEncoder tSEncoder)
{
this.tSEncoder = tSEncoder;
this.m3U8Option = m3U8Option;
}

/// <summary>
/// 生成ts和m3u8文件
/// </summary>
@@ -35,9 +48,8 @@ namespace JT1078.Hls
public void CreateTsData(JT1078Package jt1078Package)
{
string key = jt1078Package.GetKey();
string hlsFileDirectory = m3U8Option.HlsFileDirectory;
string m3u8FileName = Path.Combine(hlsFileDirectory, key, m3U8Option.M3U8FileName);
if (!File.Exists(m3u8FileName)) File.Create(m3u8FileName);//创建m3u8文件
//string hlsFileDirectory = m3U8Option.HlsFileDirectory;
//string m3u8FileName = Path.Combine(hlsFileDirectory, key, m3U8Option.M3U8FileName);
var buff = TSArrayPool.Rent(jt1078Package.Bodies.Length + 1024);
TSMessagePackWriter tSMessagePackWriter = new TSMessagePackWriter(buff);
try
@@ -50,7 +62,7 @@ namespace JT1078.Hls
CreateTsFile(curTsFileInfo.FileName,key, tSMessagePackWriter.FlushAndGetArray());
curTsFileInfo.Duration = (jt1078Package.Timestamp - curTsFileInfo.TsFirst1078PackageTimeStamp) / 1000.0;
//按设定的时间(默认为10秒)切分ts文件
if (curTsFileInfo.Duration > m3U8Option.TsFileMaxSecond)
if (curTsFileInfo.Duration > (m3U8Option.TsFileMaxSecond-1))
{
var tsFileInfoQueue = ManageTsFileInfo(key, curTsFileInfo);
CreateM3U8File(curTsFileInfo, tsFileInfoQueue);
@@ -63,11 +75,11 @@ namespace JT1078.Hls
curTsFileInfo.IsCreateTsFile = false;
curTsFileInfo.TsFirst1078PackageTimeStamp = jt1078Package.Timestamp;
curTsFileInfo.FileName = $"{curTsFileInfo.TsFileSerialNo}.ts";
var sdt = tSEncoder.CreateSDT(jt1078Package);
var sdt = tSEncoder.CreateSDT();
tSMessagePackWriter.WriteArray(sdt);
var pat = tSEncoder.CreatePAT(jt1078Package);
var pat = tSEncoder.CreatePAT();
tSMessagePackWriter.WriteArray(pat);
var pmt = tSEncoder.CreatePMT(jt1078Package);
var pmt = tSEncoder.CreatePMT();
tSMessagePackWriter.WriteArray(pmt);
var pes = tSEncoder.CreatePES(jt1078Package);
tSMessagePackWriter.WriteArray(pes);
@@ -92,7 +104,7 @@ namespace JT1078.Hls
if (tsFileInfoQueue.Count >= m3U8Option.TsFileCapacity)
{
var deleteTsFileInfo = tsFileInfoQueue.Dequeue();
var deleteTsFileName = Path.Combine(m3U8Option.HlsFileDirectory, deleteTsFileInfo.FileName);
var deleteTsFileName = Path.Combine(m3U8Option.HlsFileDirectory, key, deleteTsFileInfo.FileName);
if (File.Exists(deleteTsFileName)) File.Delete(deleteTsFileName);
}
tsFileInfoQueue.Enqueue(curTsFileInfo);
@@ -124,9 +136,10 @@ namespace JT1078.Hls
{
var tsFileInfo = tsFileInfoQueue.ElementAt(i);
sb.AppendLine($"#EXTINF:{tsFileInfo.Duration},");
sb.AppendLine(tsFileInfo.FileName);
sb.AppendLine($"{tsFileInfo.FileName}?{m3U8Option.TsPathSimParamName}={tsFileInfo.Sim}&{m3U8Option.TsPathChannelParamName}={tsFileInfo.ChannelNo}");
}
using (FileStream fs = new FileStream(m3U8Option.M3U8FileName, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
string m3u8FileName = Path.Combine(m3U8Option.HlsFileDirectory,$"{curTsFileInfo.Sim}_{curTsFileInfo.ChannelNo}", m3U8Option.M3U8FileName);
using (FileStream fs = new FileStream(m3u8FileName, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
{
var buffer = Encoding.UTF8.GetBytes(sb.ToString());
fs.Write(buffer,0, buffer.Length);
@@ -142,9 +155,17 @@ namespace JT1078.Hls
{
if (!curTsFileInfoDic.TryGetValue(key, out var curTsFileInfo))
{
curTsFileInfo = new TsFileInfo();
curTsFileInfo = new TsFileInfo()
{
Sim = key.Split('_')[0],
ChannelNo = key.Split('_')[1]
};
curTsFileInfoDic.TryAdd(key, curTsFileInfo);
}
else {
curTsFileInfo.Sim = key.Split('_')[0];
curTsFileInfo.ChannelNo = key.Split('_')[1];
}
return curTsFileInfo;
}
/// <summary>
@@ -162,17 +183,17 @@ namespace JT1078.Hls
}
}

///// <summary>
///// 添加结束标识
///// 直播流用不到
///// </summary>
///// <param name="filepath"></param>
////public void AppendM3U8End()
////{
//// StringBuilder sb = new StringBuilder();
//// sb.AppendLine("#EXT-X-ENDLIST"); //m3u8文件结束符 表示视频已经结束 有这个标志同时也说明当前流是一个非直播流
//// //#EXT-X-PLAYLIST-TYPE:VOD/Live //VOD表示当前视频流不是一个直播流,而是点播流(也就是视频的全部ts文件已经生成)
////}
/// <summary>
/// 添加结束标识
/// 直播流用不到
/// </summary>
public void AppendM3U8End()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("#EXT-X-ENDLIST");
//m3u8文件结束符 表示视频已经结束 有这个标志同时也说明当前流是一个非直播流
//#EXT-X-PLAYLIST-TYPE:VOD/Live //VOD表示当前视频流不是一个直播流,而是点播流(也就是视频的全部ts文件已经生成)
}

/// <summary>
/// 停止观看直播时清零数据
@@ -193,6 +214,14 @@ namespace JT1078.Hls
/// </summary>
internal class TsFileInfo
{
/// <summary>
/// 设备手机号
/// </summary>
public string Sim { get; set; }
/// <summary>
/// 设备逻辑通道号
/// </summary>
public string ChannelNo { get; set; }
/// <summary>
/// ts文件名
/// </summary>


+ 9
- 1
src/JT1078.Hls/Options/M3U8Option.cs View File

@@ -18,12 +18,20 @@ namespace JT1078.Hls.Options
/// </summary>
public int TsFileMaxSecond { get; set; } = 10;
/// <summary>
/// ts路径sim参数名称
/// </summary>
public string TsPathSimParamName { get; set; } = "sim";
/// <summary>
/// ts路径通道参数名称
/// </summary>
public string TsPathChannelParamName { get; set; } = "channel";
/// <summary>
/// m3u8文件
/// </summary>
public string M3U8FileName { get; set; } = "live.m3u8";
/// <summary>
/// hls文件路径(包括m3u8路径,ts路径)
/// </summary>
public string HlsFileDirectory { get; set; }
public string HlsFileDirectory { get; set; } = "wwwroot";
}
}

+ 7
- 4
src/JT1078.Hls/TSEncoder.cs View File

@@ -36,12 +36,15 @@ namespace JT1078.Hls
//todo:音频同步
//private Dictionary<string, byte> AudioCounter = new Dictionary<string, byte>();

/// <summary>
///
/// </summary>
public TSEncoder()
{
VideoCounter = new Dictionary<string, byte>(StringComparer.OrdinalIgnoreCase);
}

public byte[] CreateSDT(JT1078Package jt1078Package, int minBufferSize = 188)
public byte[] CreateSDT(int minBufferSize = 188)
{
byte[] buffer = TSArrayPool.Rent(minBufferSize);
try
@@ -85,7 +88,7 @@ namespace JT1078.Hls
TSArrayPool.Return(buffer);
}
}
public byte[] CreatePAT(JT1078Package jt1078Package, int minBufferSize = 188)
public byte[] CreatePAT(int minBufferSize = 188)
{
byte[] buffer = TSArrayPool.Rent(minBufferSize);
try
@@ -111,7 +114,7 @@ namespace JT1078.Hls
TSArrayPool.Return(buffer);
}
}
public byte[] CreatePMT(JT1078Package jt1078Package, int minBufferSize = 188)
public byte[] CreatePMT(int minBufferSize = 188)
{
byte[] buffer = TSArrayPool.Rent(minBufferSize);
try
@@ -139,7 +142,7 @@ namespace JT1078.Hls
TSArrayPool.Return(buffer);
}
}
public byte[] CreatePES(JT1078Package jt1078Package, int minBufferSize = 1024)
public byte[] CreatePES(in JT1078Package jt1078Package, int minBufferSize = 1024)
{
//将1078一帧的数据拆分成一小段一小段的PES包
byte[] buffer = TSArrayPool.Rent(jt1078Package.Bodies.Length + minBufferSize);


+ 0
- 84
src/JT1078.Protocol.Benchmark/JT1078FlvEncoderContext.cs View File

@@ -1,84 +0,0 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Environments;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Toolchains.CsProj;
using JT1078.Flv.MessagePack;
using JT1078.Protocol;
using JT1078.Protocol.H264;
using JT1078.Protocol.MessagePack;
using JT1078.Protocol.Extensions;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace JT1078.Flv.Benchmark
{
[Config(typeof(JT1078FlvEncoderConfig))]
[MarkdownExporterAttribute.GitHub]
[MemoryDiagnoser]
public class JT1078FlvEncoderContext
{
JT1078Package Package;
List<H264NALU> H264NALUs;
H264NALU SPSNALu;
H264Decoder h264Decoder = new H264Decoder();
FlvEncoder flvEncoder = new FlvEncoder();

[Params(100, 10000, 100000)]
public int N;

[GlobalSetup]
public void Setup()
{
var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "JT1078_1.txt"));
foreach (var line in lines)
{
var data = line.Split(',');
var bytes = data[6].ToHexBytes();
JT1078Package package = JT1078Serializer.Deserialize(bytes);
Package = JT1078Serializer.Merge(package);
}
H264NALUs = h264Decoder.ParseNALU(Package);
SPSNALu = H264NALUs.FirstOrDefault(f => f.NALUHeader.NalUnitType == 7);
SPSNALu.RawData = h264Decoder.DiscardEmulationPreventionBytes(SPSNALu.RawData);
}

[Benchmark(Description = "EXPGolombReader")]
public void EXPGolombReaderTest()
{
for (var i = 0; i < N; i++)
{
ExpGolombReader h264GolombReader = new ExpGolombReader(SPSNALu.RawData);
h264GolombReader.ReadSPS();
}
}

[Benchmark(Description = "H264Decoder")]
public void H264Decoder()
{
for (var i = 0; i < N; i++)
{
var nalus = h264Decoder.ParseNALU(Package);
}
}

//[Benchmark(Description = "FlvEncoder")]
//public void FlvEncoder()
//{
// for(var i=0;i< N;i++)
// {
// var contents = flvEncoder.CreateFlvFrame(H264NALUs);
// }
//}
}

public class JT1078FlvEncoderConfig : ManualConfig
{
public JT1078FlvEncoderConfig()
{
AddJob(Job.Default.WithGcServer(false).WithToolchain(CsProjCoreToolchain.NetCoreApp50).WithPlatform(Platform.AnyCpu));
}
}
}

+ 47
- 5
src/JT1078.Protocol.Test/H264/H264DecoderTest.cs View File

@@ -26,7 +26,7 @@ namespace JT1078.Protocol.Test.H264
var nalu = nalus[0];
Assert.Equal(0, nalu.NALUHeader.ForbiddenZeroBit);
Assert.Equal(3, nalu.NALUHeader.NalRefIdc);
Assert.Equal(1, nalu.NALUHeader.NalUnitType);
Assert.Equal(NalUnitType.SLICE, nalu.NALUHeader.NalUnitType);
}

[Fact]
@@ -48,7 +48,7 @@ namespace JT1078.Protocol.Test.H264
Assert.Equal(4, nalus.Count);

//SPS -> 7
var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 7);
var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.SPS);
Assert.NotNull(spsNALU);
spsNALU.RawData = decoder.DiscardEmulationPreventionBytes(spsNALU.RawData);
//"Z00AFJWoWCWQ"
@@ -63,15 +63,15 @@ namespace JT1078.Protocol.Test.H264
Assert.Equal(352, spsInfo.width);

//PPS -> 8
var ppsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 8);
var ppsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.PPS);
Assert.NotNull(ppsNALU);

//IDR -> 5 关键帧
var idrNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 5);
var idrNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.IDR);
Assert.NotNull(idrNALU);

//SEI -> 6
var seiNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 6);
var seiNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == NalUnitType.SEI);
Assert.NotNull(seiNALU);
}

@@ -95,5 +95,47 @@ namespace JT1078.Protocol.Test.H264
}
fileStream.Close();
}

[Fact]
public void ParseNALUTest4()
{
string file = "jt1078_5";
var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", $"{file}.txt"));
string filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", $"{file}.h264");
if (File.Exists(filepath))
{
File.Delete(filepath);
}
using var fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write);
foreach (var line in lines)
{
var data = line.Split(',');
var bytes = data[1].ToHexBytes();
JT1078Package package = JT1078Serializer.Deserialize(bytes);
fileStream.Write(package.Bodies);
}
fileStream.Close();
}

[Fact]
public void ParseNALUTest5()
{
string file = "jt1078_6";
var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", $"{file}.txt"));
List<H264NALU> nALUs = new List<H264NALU>();
H264Decoder decoder = new H264Decoder();
foreach (var line in lines)
{
var bytes = line.ToHexBytes();
JT1078Package package = JT1078Serializer.Deserialize(bytes);
var packageMerge = JT1078Serializer.Merge(package);
if (packageMerge != null)
{
var nalus = decoder.ParseNALU(packageMerge);
nALUs = nALUs.Concat(nalus).ToList();
}
}
var a = nALUs.Count(c => !c.Slice);
}
}
}

+ 1
- 1
src/JT1078.Protocol.Test/H264/NALUHeaderTest.cs View File

@@ -14,7 +14,7 @@ namespace JT1078.Flv.Test.H264
NALUHeader header = new NALUHeader(0xc0);
Assert.Equal(1, header.ForbiddenZeroBit);
Assert.Equal(2, header.NalRefIdc);
Assert.Equal(0, header.NalUnitType);
Assert.Equal(NalUnitType.None, header.NalUnitType);
}
}
}

+ 6
- 0
src/JT1078.Protocol.Test/JT1078.Protocol.Test.csproj View File

@@ -29,5 +29,11 @@
<None Include="..\..\doc\video\jt1078_2.txt" Link="H264\jt1078_2.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="..\..\doc\video\jt1078_5.txt" Link="H264\jt1078_5.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="..\..\doc\video\jt1078_6.txt" Link="H264\jt1078_6.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

+ 2
- 2
src/JT1078.Protocol.Test/JT1078SerializerTest.cs View File

@@ -336,13 +336,13 @@ namespace JT1078.Protocol.Test
[Fact]
public void MergeTest()
{
var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "JT1078.txt"));
var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "h264","JT1078_1.txt"));
JT1078Package merge=null;
int mergeBodyLength=0;
foreach (var line in lines)
{
var data = line.Split(',');
var bytes = data[5].ToHexBytes();
var bytes = data[6].ToHexBytes();
JT1078Package package = JT1078Serializer.Deserialize(bytes);
mergeBodyLength += package.DataBodyLength;
merge = JT1078Serializer.Merge(package);


+ 63
- 3
src/JT1078.Protocol/H264/H264Decoder.cs View File

@@ -18,7 +18,7 @@ namespace JT1078.Protocol.H264
public List<H264NALU> ParseNALU(JT1078Package package, string key = null)
{
List<H264NALU> h264NALUs = new List<H264NALU>();
int i=0,state=0;
int i=0,state=0,laststate=0;
int? lastIndex=null;
int length = package.Bodies.Length;
byte value;
@@ -45,9 +45,10 @@ namespace JT1078.Protocol.H264
if (lastIndex.HasValue)
{
var tmp = buffer.Slice(lastIndex.Value, i - state - 1 - lastIndex.Value);
h264NALUs.Add(Create(package, tmp, state));
h264NALUs.Add(Create(package, tmp, state+1));
}
lastIndex = i;
laststate = state+1;
state = 0;
}
else
@@ -61,11 +62,69 @@ namespace JT1078.Protocol.H264
}
if (lastIndex.HasValue)
{
h264NALUs.Add(Create(package, buffer.Slice(lastIndex.Value), 4));
h264NALUs.Add(Create(package, buffer.Slice(lastIndex.Value), laststate));
}
return h264NALUs;
}

/// <summary>
///
/// <see cref="https://github.com/samirkumardas/jmuxer/blob/master/src/parsers/h264.js"/>
/// </summary>
/// <param name="package"></param>
/// <param name="h264NALUs"></param>
/// <param name="key"></param>
/// <returns></returns>
public void ParseNALU(JT1078Package package, List<H264NALU> h264NALUs,string key = null)
{
int i = 0, state = 0, laststate = 0;
int? lastIndex = null;
int length = package.Bodies.Length;
byte value;
ReadOnlySpan<byte> buffer = package.Bodies;
while (i < length)
{
value = buffer[i++];
switch (state)
{
case 0:
if (value == 0) state = 1;
break;
case 1:
state = value == 0 ? 2 : 0;
break;
case 2:
case 3:
if (value == 0)
{
state = 3;
}
else if (value == 1 && i < length)
{
if (lastIndex.HasValue)
{
var tmp = buffer.Slice(lastIndex.Value, i - state - 1 - lastIndex.Value);
h264NALUs.Add(Create(package, tmp, lastIndex.Value));
}
lastIndex = i;
laststate = state + 1;
state = 0;
}
else
{
state = 0;
}
break;
default:
break;
}
}
if (lastIndex.HasValue)
{
h264NALUs.Add(Create(package, buffer.Slice(lastIndex.Value), laststate));
}
}

private H264NALU Create(JT1078Package package,ReadOnlySpan<byte> nalu, int startCodePrefix)
{
H264NALU nALU = new H264NALU();
@@ -75,6 +134,7 @@ namespace JT1078.Protocol.H264
nALU.LastFrameInterval = package.LastFrameInterval;
nALU.LastIFrameInterval = package.LastIFrameInterval;
nALU.Timestamp = package.Timestamp;
nALU.Slice = (nalu[1] & 0x80)== 0x80;
nALU.RawData = nalu.ToArray();
if (startCodePrefix == 3)
{


+ 6
- 0
src/JT1078.Protocol/H264/H264NALU.cs View File

@@ -40,6 +40,12 @@ namespace JT1078.Protocol.H264
/// 当数据类型为01000时,则没有该字段
/// </summary>
public ulong Timestamp { get; set; }

/// <summary>
/// 是否切片 0x80
/// H264 NALU slice first_mb_in_slice
/// </summary>
public bool Slice { get; set; }
/// <summary>
/// 数据体
/// </summary>


+ 20
- 3
src/JT1078.Protocol/H264/NALUHeader.cs View File

@@ -10,16 +10,33 @@ namespace JT1078.Protocol.H264
{
ForbiddenZeroBit = (value & 0x80) >> 7;
NalRefIdc = (value & 0x60) >> 5;
NalUnitType = value & 0x1f;
NalUnitType = (NalUnitType)(value & 0x1f);
}
public NALUHeader(ReadOnlySpan<byte> value)
{
ForbiddenZeroBit = (value[0] & 0x80) >> 7;
NalRefIdc = (value[0] & 0x60) >> 5;
NalUnitType = value[0] & 0x1f;
NalUnitType = (NalUnitType)(value[0] & 0x1f);
}
public int ForbiddenZeroBit { get; set; }
public int NalRefIdc { get; set; }
public int NalUnitType { get; set; }
public NalUnitType NalUnitType { get; set; }
}

public enum NalUnitType : int
{
None=0,
SLICE = 1,
DPA = 2,
DPB = 3,
DPC = 4,
IDR = 5,
SEI = 6,
SPS = 7,
PPS = 8,
AUD = 9,
EOSEQ = 10,
EOSTREAM = 11,
FILL = 12,
}
}

+ 1
- 1
src/JT1078.Protocol/JT1078.Protocol.csproj View File

@@ -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.1.0</Version>
<Version>1.1.1-preview1</Version>
<SignAssembly>false</SignAssembly>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<PackageLicenseFile>LICENSE</PackageLicenseFile>


+ 16
- 0
src/JT1078.Protocol/JT1078.Protocol.xml View File

@@ -122,6 +122,16 @@
<param name="key"></param>
<returns></returns>
</member>
<member name="M:JT1078.Protocol.H264.H264Decoder.ParseNALU(JT1078.Protocol.JT1078Package,System.Collections.Generic.List{JT1078.Protocol.H264.H264NALU},System.String)">
<summary>
<see cref="!:https://github.com/samirkumardas/jmuxer/blob/master/src/parsers/h264.js"/>
</summary>
<param name="package"></param>
<param name="h264NALUs"></param>
<param name="key"></param>
<returns></returns>
</member>
<member name="M:JT1078.Protocol.H264.H264Decoder.DiscardEmulationPreventionBytes(System.ReadOnlySpan{System.Byte})">
<summary>
Expunge any "Emulation Prevention" bytes from a "Raw Byte Sequence Payload"
@@ -166,6 +176,12 @@
当数据类型为01000时,则没有该字段
</summary>
</member>
<member name="P:JT1078.Protocol.H264.H264NALU.Slice">
<summary>
是否切片 0x80
H264 NALU slice first_mb_in_slice
</summary>
</member>
<member name="P:JT1078.Protocol.H264.H264NALU.RawData">
<summary>
数据体


+ 48
- 0
src/JT1078.SignalR.Test/Hubs/FMp4Hub.cs View File

@@ -0,0 +1,48 @@
using JT1078.SignalR.Test.Services;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Text.Json;
using System.Threading.Tasks;


namespace JT1078.SignalR.Test.Hubs
{

public class FMp4Hub : Hub
{
private readonly ILogger logger;
private readonly WsSession wsSession;

public FMp4Hub(
WsSession wsSession,
ILoggerFactory loggerFactory)
{
this.wsSession = wsSession;
logger = loggerFactory.CreateLogger<FMp4Hub>();
}

public override Task OnConnectedAsync()
{
if (logger.IsEnabled(LogLevel.Debug))
{
logger.LogDebug($"链接上:{Context.ConnectionId}");
}
wsSession.TryAdd(Context.ConnectionId);
return base.OnConnectedAsync();
}

public override Task OnDisconnectedAsync(Exception exception)
{
if (logger.IsEnabled(LogLevel.Debug))
{
logger.LogDebug($"断开链接:{Context.ConnectionId}");
}
wsSession.TryRemove(Context.ConnectionId);
return base.OnDisconnectedAsync(exception);
}
}
}

+ 30
- 0
src/JT1078.SignalR.Test/JT1078.SignalR.Test.csproj View File

@@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\JT1078.FMp4\JT1078.FMp4.csproj" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\doc\video\jt1078_3.txt" Link="H264\jt1078_3.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="..\..\doc\video\jt1078_1.txt" Link="H264\jt1078_1.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="..\..\doc\video\jt1078_2.txt" Link="H264\jt1078_2.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="..\..\doc\video\jt1078_1_fragmented.mp4" Link="H264\jt1078_1_fragmented.mp4">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="..\..\doc\video\jt1078_5.txt" Link="H264\jt1078_5.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="..\..\doc\video\jt1078_6.txt" Link="H264\jt1078_6.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

+ 26
- 0
src/JT1078.SignalR.Test/Program.cs View File

@@ -0,0 +1,26 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace JT1078.SignalR.Test
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}

+ 174
- 0
src/JT1078.SignalR.Test/Services/ToWebSocketService.cs View File

@@ -0,0 +1,174 @@
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using JT1078.SignalR.Test.Hubs;
using JT1078.FMp4;
using JT1078.Protocol;
using System.IO;
using JT1078.Protocol.Extensions;
using JT1078.Protocol.H264;
using System.Net.WebSockets;

namespace JT1078.SignalR.Test.Services
{
public class ToWebSocketService: BackgroundService
{
private readonly ILogger<ToWebSocketService> logger;

private readonly IHubContext<FMp4Hub> _hubContext;

private readonly FMp4Encoder fMp4Encoder;

private readonly WsSession wsSession;

private readonly H264Decoder h264Decoder;

public ToWebSocketService(
H264Decoder h264Decoder,
WsSession wsSession,
FMp4Encoder fMp4Encoder,
ILoggerFactory loggerFactory,
IHubContext<FMp4Hub> hubContext)
{
this.h264Decoder = h264Decoder;
logger = loggerFactory.CreateLogger<ToWebSocketService>();
this.fMp4Encoder = fMp4Encoder;
_hubContext = hubContext;
this.wsSession = wsSession;
}

public List<byte[]> q = new List<byte[]>();

public void a()
{
List<JT1078Package> packages = new List<JT1078Package>();
//var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "jt1078_3.txt"));
//var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "jt1078_5.txt"));
var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "jt1078_6.txt"));
int mergeBodyLength = 0;
foreach (var line in lines)
{
//var data = line.Split(',');
//jt1078_5
//var bytes = data[1].ToHexBytes();
//jt1078_3
//var bytes = data[6].ToHexBytes();
//jt1078_6
var bytes = line.ToHexBytes();

JT1078Package package = JT1078Serializer.Deserialize(bytes);
mergeBodyLength += package.DataBodyLength;
var packageMerge = JT1078Serializer.Merge(package);
if (packageMerge != null)
{
packages.Add(packageMerge);
}
}
List<byte[]> first = new List<byte[]>();
//var styp = fMp4Encoder.EncoderStypBox();
//first.Add(styp);
//q.Enqueue(styp);
var ftyp = fMp4Encoder.FtypBox();
//q.Enqueue(ftyp);
first.Add(ftyp);
var package1 = packages[0];
var nalus1 = h264Decoder.ParseNALU(package1);
var moov = fMp4Encoder.VideoMoovBox(
nalus1.FirstOrDefault(f => f.NALUHeader.NalUnitType == NalUnitType.SPS),
nalus1.FirstOrDefault(f => f.NALUHeader.NalUnitType == NalUnitType.PPS));
//q.Enqueue(moov);
first.Add(moov);
q.Add(first.SelectMany(s=>s).ToArray());
List<NalUnitType> filter = new List<NalUnitType>() { NalUnitType.SEI,NalUnitType.SPS,NalUnitType.PPS,NalUnitType.AUD};
List<H264NALU> nalus = new List<H264NALU>();
foreach (var package in packages)
{
List<H264NALU> h264NALUs = h264Decoder.ParseNALU(package);
//if(package.Label3.DataType== Protocol.Enums.JT1078DataType.视频I帧)
//{
// if (nalus.Count > 0)
// {
// var otherBuffer = fMp4Encoder.OtherVideoBox(nalus);
// q.Add(fMp4Encoder.StypBox().Concat(otherBuffer).ToArray());
// nalus.Clear();
// }
// else
// {
// nalus = nalus.Concat(h264NALUs).ToList();
// }
//}
//else
//{
// nalus = nalus.Concat(h264NALUs).ToList();
//}
foreach (var nalu in h264NALUs)
{
if (nalu.Slice)
{
//H264 NALU slice first_mb_in_slice
nalus.Add(nalu);
}
else
{
if (nalus.Count > 0)
{
q.Add(fMp4Encoder.StypBox());
var otherBuffer = fMp4Encoder.OtherVideoBox(nalus);
q.Add(otherBuffer);
nalus.Clear();
}
nalus.Add(nalu);
}
}
}
}


public Dictionary<string,int> flag = new Dictionary<string, int>();

protected async override Task ExecuteAsync(CancellationToken stoppingToken)
{
a();
while (!stoppingToken.IsCancellationRequested)
{
try
{
foreach(var session in wsSession.GetAll())
{
if (flag.ContainsKey(session))
{
var len = flag[session];
if (q.Count <= len)
{
break;
}
await _hubContext.Clients.Client(session).SendAsync("video", q[len], stoppingToken);
len++;
flag[session] = len;
}
else
{
await _hubContext.Clients.Client(session).SendAsync("video", q[0], stoppingToken);
flag.Add(session, 1);
}
}
}
catch (Exception ex)
{
logger.LogError(ex,"");
}
await Task.Delay(1000);
}
}
}
}

+ 38
- 0
src/JT1078.SignalR.Test/Services/WsSession.cs View File

@@ -0,0 +1,38 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace JT1078.SignalR.Test.Services
{
public class WsSession
{
private ConcurrentDictionary<string, string> sessions;

public WsSession()
{
sessions = new ConcurrentDictionary<string, string>();
}

public void TryAdd(string connectionId)
{
sessions.TryAdd(connectionId, connectionId);
}

public int GetCount()
{
return sessions.Count;
}

public void TryRemove(string connectionId)
{
sessions.TryRemove(connectionId,out _);
}

public List<string> GetAll()
{
return sessions.Keys.ToList();
}
}
}

+ 66
- 0
src/JT1078.SignalR.Test/Startup.cs View File

@@ -0,0 +1,66 @@
using JT1078.FMp4;
using JT1078.Protocol.H264;
using JT1078.SignalR.Test.Hubs;
using JT1078.SignalR.Test.Services;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace JT1078.SignalR.Test
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}

public IConfiguration Configuration { get; }

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSignalR();
services.AddSingleton<FMp4Encoder>();
services.AddSingleton<H264Decoder>();
services.AddSingleton<WsSession>();
services.AddHostedService<ToWebSocketService>();
services.AddCors(options => options.AddPolicy("CorsPolicy", builder =>
{
builder.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
.SetIsOriginAllowed(o => true);
}));
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseCors("CorsPolicy");
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<FMp4Hub>("/FMp4Hub");
});
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}

+ 9
- 0
src/JT1078.SignalR.Test/appsettings.Development.json View File

@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}

+ 10
- 0
src/JT1078.SignalR.Test/appsettings.json View File

@@ -0,0 +1,10 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}

+ 15
- 58
src/JT1078.sln View File

@@ -3,16 +3,8 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29020.237
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Protocol.Extensions.JT1078", "JT808.Protocol.Extensions.JT1078\JT808.Protocol.Extensions.JT1078.csproj", "{F060F379-C8E4-4CA6-A54C-938A9780ACD2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT809.Protocol.Extensions.JT1078", "JT809.Protocol.Extensions.JT1078\JT809.Protocol.Extensions.JT1078.csproj", "{2F987285-EB7A-4934-909E-50E42A2D1140}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT1078.Protocol", "JT1078.Protocol\JT1078.Protocol.csproj", "{60CAC24B-7317-48BF-9DBF-7F3ECA3689A4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT808.Protocol.Extensions.JT1078.Test", "JT808.Protocol.Extensions.JT1078.Test\JT808.Protocol.Extensions.JT1078.Test.csproj", "{C6A43FDF-C609-40BB-B598-87F0BF7B944B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT809.Protocol.Extensions.JT1078.Test", "JT809.Protocol.Extensions.JT1078.Test\JT809.Protocol.Extensions.JT1078.Test.csproj", "{E9FF2716-EF30-4180-879B-E8AB979ACFF3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT1078.Protocol.Test", "JT1078.Protocol.Test\JT1078.Protocol.Test.csproj", "{9ADD82F9-E0B2-4263-8573-151F673BB33F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{0655AF84-E578-409F-AB0E-B47E0D2F6814}"
@@ -40,6 +32,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Benchmarks", "Benchmarks",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT1078.AV.Benchmark", "JT1078.AV.Benchmark\JT1078.AV.Benchmark.csproj", "{93D6C094-5A3A-4DFA-B52B-605FDFFB6094}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT1078.SignalR.Test", "JT1078.SignalR.Test\JT1078.SignalR.Test.csproj", "{6A063AF3-611F-4A1C-ACCF-BF903B7C7014}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -50,30 +44,6 @@ Global
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{F060F379-C8E4-4CA6-A54C-938A9780ACD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F060F379-C8E4-4CA6-A54C-938A9780ACD2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F060F379-C8E4-4CA6-A54C-938A9780ACD2}.Debug|x64.ActiveCfg = Debug|Any CPU
{F060F379-C8E4-4CA6-A54C-938A9780ACD2}.Debug|x64.Build.0 = Debug|Any CPU
{F060F379-C8E4-4CA6-A54C-938A9780ACD2}.Debug|x86.ActiveCfg = Debug|Any CPU
{F060F379-C8E4-4CA6-A54C-938A9780ACD2}.Debug|x86.Build.0 = Debug|Any CPU
{F060F379-C8E4-4CA6-A54C-938A9780ACD2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F060F379-C8E4-4CA6-A54C-938A9780ACD2}.Release|Any CPU.Build.0 = Release|Any CPU
{F060F379-C8E4-4CA6-A54C-938A9780ACD2}.Release|x64.ActiveCfg = Release|Any CPU
{F060F379-C8E4-4CA6-A54C-938A9780ACD2}.Release|x64.Build.0 = Release|Any CPU
{F060F379-C8E4-4CA6-A54C-938A9780ACD2}.Release|x86.ActiveCfg = Release|Any CPU
{F060F379-C8E4-4CA6-A54C-938A9780ACD2}.Release|x86.Build.0 = Release|Any CPU
{2F987285-EB7A-4934-909E-50E42A2D1140}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2F987285-EB7A-4934-909E-50E42A2D1140}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2F987285-EB7A-4934-909E-50E42A2D1140}.Debug|x64.ActiveCfg = Debug|Any CPU
{2F987285-EB7A-4934-909E-50E42A2D1140}.Debug|x64.Build.0 = Debug|Any CPU
{2F987285-EB7A-4934-909E-50E42A2D1140}.Debug|x86.ActiveCfg = Debug|Any CPU
{2F987285-EB7A-4934-909E-50E42A2D1140}.Debug|x86.Build.0 = Debug|Any CPU
{2F987285-EB7A-4934-909E-50E42A2D1140}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2F987285-EB7A-4934-909E-50E42A2D1140}.Release|Any CPU.Build.0 = Release|Any CPU
{2F987285-EB7A-4934-909E-50E42A2D1140}.Release|x64.ActiveCfg = Release|Any CPU
{2F987285-EB7A-4934-909E-50E42A2D1140}.Release|x64.Build.0 = Release|Any CPU
{2F987285-EB7A-4934-909E-50E42A2D1140}.Release|x86.ActiveCfg = Release|Any CPU
{2F987285-EB7A-4934-909E-50E42A2D1140}.Release|x86.Build.0 = Release|Any CPU
{60CAC24B-7317-48BF-9DBF-7F3ECA3689A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{60CAC24B-7317-48BF-9DBF-7F3ECA3689A4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{60CAC24B-7317-48BF-9DBF-7F3ECA3689A4}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -86,30 +56,6 @@ Global
{60CAC24B-7317-48BF-9DBF-7F3ECA3689A4}.Release|x64.Build.0 = Release|Any CPU
{60CAC24B-7317-48BF-9DBF-7F3ECA3689A4}.Release|x86.ActiveCfg = Release|Any CPU
{60CAC24B-7317-48BF-9DBF-7F3ECA3689A4}.Release|x86.Build.0 = Release|Any CPU
{C6A43FDF-C609-40BB-B598-87F0BF7B944B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C6A43FDF-C609-40BB-B598-87F0BF7B944B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C6A43FDF-C609-40BB-B598-87F0BF7B944B}.Debug|x64.ActiveCfg = Debug|Any CPU
{C6A43FDF-C609-40BB-B598-87F0BF7B944B}.Debug|x64.Build.0 = Debug|Any CPU
{C6A43FDF-C609-40BB-B598-87F0BF7B944B}.Debug|x86.ActiveCfg = Debug|Any CPU
{C6A43FDF-C609-40BB-B598-87F0BF7B944B}.Debug|x86.Build.0 = Debug|Any CPU
{C6A43FDF-C609-40BB-B598-87F0BF7B944B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C6A43FDF-C609-40BB-B598-87F0BF7B944B}.Release|Any CPU.Build.0 = Release|Any CPU
{C6A43FDF-C609-40BB-B598-87F0BF7B944B}.Release|x64.ActiveCfg = Release|Any CPU
{C6A43FDF-C609-40BB-B598-87F0BF7B944B}.Release|x64.Build.0 = Release|Any CPU
{C6A43FDF-C609-40BB-B598-87F0BF7B944B}.Release|x86.ActiveCfg = Release|Any CPU
{C6A43FDF-C609-40BB-B598-87F0BF7B944B}.Release|x86.Build.0 = Release|Any CPU
{E9FF2716-EF30-4180-879B-E8AB979ACFF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E9FF2716-EF30-4180-879B-E8AB979ACFF3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E9FF2716-EF30-4180-879B-E8AB979ACFF3}.Debug|x64.ActiveCfg = Debug|Any CPU
{E9FF2716-EF30-4180-879B-E8AB979ACFF3}.Debug|x64.Build.0 = Debug|Any CPU
{E9FF2716-EF30-4180-879B-E8AB979ACFF3}.Debug|x86.ActiveCfg = Debug|Any CPU
{E9FF2716-EF30-4180-879B-E8AB979ACFF3}.Debug|x86.Build.0 = Debug|Any CPU
{E9FF2716-EF30-4180-879B-E8AB979ACFF3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E9FF2716-EF30-4180-879B-E8AB979ACFF3}.Release|Any CPU.Build.0 = Release|Any CPU
{E9FF2716-EF30-4180-879B-E8AB979ACFF3}.Release|x64.ActiveCfg = Release|Any CPU
{E9FF2716-EF30-4180-879B-E8AB979ACFF3}.Release|x64.Build.0 = Release|Any CPU
{E9FF2716-EF30-4180-879B-E8AB979ACFF3}.Release|x86.ActiveCfg = Release|Any CPU
{E9FF2716-EF30-4180-879B-E8AB979ACFF3}.Release|x86.Build.0 = Release|Any CPU
{9ADD82F9-E0B2-4263-8573-151F673BB33F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9ADD82F9-E0B2-4263-8573-151F673BB33F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9ADD82F9-E0B2-4263-8573-151F673BB33F}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -218,19 +164,30 @@ Global
{93D6C094-5A3A-4DFA-B52B-605FDFFB6094}.Release|x64.Build.0 = Release|Any CPU
{93D6C094-5A3A-4DFA-B52B-605FDFFB6094}.Release|x86.ActiveCfg = Release|Any CPU
{93D6C094-5A3A-4DFA-B52B-605FDFFB6094}.Release|x86.Build.0 = Release|Any CPU
{6A063AF3-611F-4A1C-ACCF-BF903B7C7014}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6A063AF3-611F-4A1C-ACCF-BF903B7C7014}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6A063AF3-611F-4A1C-ACCF-BF903B7C7014}.Debug|x64.ActiveCfg = Debug|Any CPU
{6A063AF3-611F-4A1C-ACCF-BF903B7C7014}.Debug|x64.Build.0 = Debug|Any CPU
{6A063AF3-611F-4A1C-ACCF-BF903B7C7014}.Debug|x86.ActiveCfg = Debug|Any CPU
{6A063AF3-611F-4A1C-ACCF-BF903B7C7014}.Debug|x86.Build.0 = Debug|Any CPU
{6A063AF3-611F-4A1C-ACCF-BF903B7C7014}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6A063AF3-611F-4A1C-ACCF-BF903B7C7014}.Release|Any CPU.Build.0 = Release|Any CPU
{6A063AF3-611F-4A1C-ACCF-BF903B7C7014}.Release|x64.ActiveCfg = Release|Any CPU
{6A063AF3-611F-4A1C-ACCF-BF903B7C7014}.Release|x64.Build.0 = Release|Any CPU
{6A063AF3-611F-4A1C-ACCF-BF903B7C7014}.Release|x86.ActiveCfg = Release|Any CPU
{6A063AF3-611F-4A1C-ACCF-BF903B7C7014}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{C6A43FDF-C609-40BB-B598-87F0BF7B944B} = {0655AF84-E578-409F-AB0E-B47E0D2F6814}
{E9FF2716-EF30-4180-879B-E8AB979ACFF3} = {0655AF84-E578-409F-AB0E-B47E0D2F6814}
{9ADD82F9-E0B2-4263-8573-151F673BB33F} = {0655AF84-E578-409F-AB0E-B47E0D2F6814}
{77402142-54E5-4E64-8F9E-BCAAC2CD0E8D} = {807ADB1F-FED4-4A56-82D2-F08F1FB7C886}
{D13FE092-1D11-4545-A322-9F06BCDAC0FD} = {0655AF84-E578-409F-AB0E-B47E0D2F6814}
{5564C20B-BFF4-4A2A-BDF2-C7427E93E993} = {0655AF84-E578-409F-AB0E-B47E0D2F6814}
{56E76D56-4CCC-401F-B25D-9AB41D58A10A} = {0655AF84-E578-409F-AB0E-B47E0D2F6814}
{93D6C094-5A3A-4DFA-B52B-605FDFFB6094} = {807ADB1F-FED4-4A56-82D2-F08F1FB7C886}
{6A063AF3-611F-4A1C-ACCF-BF903B7C7014} = {0655AF84-E578-409F-AB0E-B47E0D2F6814}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {FAE1656D-226F-4B4B-8C33-615D7E632B26}


+ 0
- 22
src/JT808.Protocol.Extensions.JT1078.Test/JT808.Protocol.Extensions.JT1078.Test.csproj View File

@@ -1,22 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\JT808.Protocol.Extensions.JT1078\JT808.Protocol.Extensions.JT1078.csproj" />
</ItemGroup>

</Project>

+ 0
- 91
src/JT808.Protocol.Extensions.JT1078.Test/JT808LocationAttach.cs View File

@@ -1,91 +0,0 @@
using JT808.Protocol.Extensions.JT1078.MessageBody;
using JT808.Protocol.Interfaces;
using JT808.Protocol.MessageBody;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Reflection;
using Xunit;

namespace JT808.Protocol.Extensions.JT1078.Test
{
public class JT808LocationAttach
{
JT808Serializer JT808Serializer;

public JT808LocationAttach()
{
IServiceCollection serviceDescriptors1 = new ServiceCollection();
serviceDescriptors1.AddJT808Configure(new DefaultGlobalConfig())
.AddJT1078Configure();
var ServiceProvider1 = serviceDescriptors1.BuildServiceProvider();
var defaultConfig = ServiceProvider1.GetRequiredService<DefaultGlobalConfig>();
JT808Serializer = new JT808Serializer(defaultConfig);
}
[Fact]
public void Test1()
{
JT808_0x0200 jT808UploadLocationRequest = new JT808_0x0200
{
AlarmFlag = 1,
Altitude = 40,
GPSTime = DateTime.Parse("2018-07-15 10:10:10"),
Lat = 12222222,
Lng = 132444444,
Speed = 60,
Direction = 0,
StatusFlag = 2,
JT808LocationAttachData = new Dictionary<byte, JT808_0x0200_BodyBase>()
};
jT808UploadLocationRequest.JT808LocationAttachData.Add(0x14, new JT808_0x0200_0x14
{
VideoRelateAlarm = 100
});
jT808UploadLocationRequest.JT808LocationAttachData.Add(0x15, new JT808_0x0200_0x15
{
VideoSignalLoseAlarmStatus = 100
});
jT808UploadLocationRequest.JT808LocationAttachData.Add(0x16, new JT808_0x0200_0x16
{
VideoSignalOcclusionAlarmStatus = 100
});
jT808UploadLocationRequest.JT808LocationAttachData.Add(0x17, new JT808_0x0200_0x17
{
StorageFaultAlarmStatus = 100
});
jT808UploadLocationRequest.JT808LocationAttachData.Add(0x18, new JT808_0x0200_0x18
{
AbnormalDrivingBehaviorAlarmType = 100,
FatigueLevel = 88
});
var hex = JT808Serializer.Serialize(jT808UploadLocationRequest).ToHexString();
Assert.Equal("000000010000000200BA7F0E07E4F11C0028003C0000180715101010140400000064150400000064160400000064170200641803006458", hex);
}

[Fact]
public void Test2()
{
byte[] bodys = "000000010000000200BA7F0E07E4F11C0028003C0000180715101010140400000064150400000064160400000064170200641803006458".ToHexBytes();
JT808_0x0200 jT808UploadLocationRequest = JT808Serializer.Deserialize<JT808_0x0200>(bodys);
Assert.Equal(1u, jT808UploadLocationRequest.AlarmFlag);
Assert.Equal(DateTime.Parse("2018-07-15 10:10:10"), jT808UploadLocationRequest.GPSTime);
Assert.Equal(12222222, jT808UploadLocationRequest.Lat);
Assert.Equal(132444444, jT808UploadLocationRequest.Lng);
Assert.Equal(60, jT808UploadLocationRequest.Speed);
Assert.Equal(2u, jT808UploadLocationRequest.StatusFlag);
Assert.Equal(100u, ((JT808_0x0200_0x14)jT808UploadLocationRequest.JT808LocationAttachData[0x14]).VideoRelateAlarm);
Assert.Equal(100u, ((JT808_0x0200_0x15)jT808UploadLocationRequest.JT808LocationAttachData[0x15]).VideoSignalLoseAlarmStatus);
Assert.Equal(100u, ((JT808_0x0200_0x16)jT808UploadLocationRequest.JT808LocationAttachData[0x16]).VideoSignalOcclusionAlarmStatus);
Assert.Equal(100u, ((JT808_0x0200_0x17)jT808UploadLocationRequest.JT808LocationAttachData[0x17]).StorageFaultAlarmStatus);
Assert.Equal(100u, ((JT808_0x0200_0x18)jT808UploadLocationRequest.JT808LocationAttachData[0x18]).AbnormalDrivingBehaviorAlarmType);
Assert.Equal(88, ((JT808_0x0200_0x18)jT808UploadLocationRequest.JT808LocationAttachData[0x18]).FatigueLevel);
}

[Fact]
public void Test3()
{
byte[] bodys = "000000010000000200BA7F0E07E4F11C0028003C0000180715101010140400000064150400000064160400000064170200641803006458".ToHexBytes();
string json = JT808Serializer.Analyze<JT808_0x0200>(bodys);
}
}
}

+ 0
- 114
src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x0200Test.cs View File

@@ -1,114 +0,0 @@
using JT808.Protocol.Extensions.JT1078.MessageBody;
using JT808.Protocol.Extensions.JT1078.Enums;
using JT808.Protocol.MessageBody;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;

namespace JT808.Protocol.Extensions.JT1078.Test
{
public class JT808_0x0200Test
{
JT808Serializer JT808Serializer;
public JT808_0x0200Test()
{
IServiceCollection serviceDescriptors1 = new ServiceCollection();
serviceDescriptors1
.AddJT808Configure()
.AddJT1078Configure();
var ServiceProvider1 = serviceDescriptors1.BuildServiceProvider();
var defaultConfig = ServiceProvider1.GetRequiredService<IJT808Config>();
JT808Serializer = defaultConfig.GetSerializer();
}

[Fact]
public void Test_0x14_1()
{
JT808_0x0200 jT808UploadLocationRequest = new JT808_0x0200
{
AlarmFlag = 1,
Altitude = 40,
GPSTime = DateTime.Parse("2020-01-31 20:20:20"),
Lat = 12222222,
Lng = 132444444,
Speed = 60,
Direction = 0,
StatusFlag = 2,
JT808LocationAttachData = new Dictionary<byte, JT808_0x0200_BodyBase>()
};
jT808UploadLocationRequest.JT808LocationAttachData.Add(JT808_JT1078_Constants.JT808_0X0200_0x14, new JT808_0x0200_0x14
{
VideoRelateAlarm = (uint)(VideoRelateAlarmType.视频信号遮挡报警 | VideoRelateAlarmType.其他视频设备故障报警)
});
var hex = JT808Serializer.Serialize(jT808UploadLocationRequest).ToHexString();
Assert.Equal("000000010000000200BA7F0E07E4F11C0028003C000020013120202014040000000A", hex);
}

[Fact]
public void Test_0x14_2()
{
byte[] bodys = "000000010000000200BA7F0E07E4F11C0028003C000020013120202014040000000A".ToHexBytes();
JT808_0x0200 jT808UploadLocationRequest = JT808Serializer.Deserialize<JT808_0x0200>(bodys);
Assert.Equal((uint)1, jT808UploadLocationRequest.AlarmFlag);
Assert.Equal(DateTime.Parse("2020-01-31 20:20:20"), jT808UploadLocationRequest.GPSTime);
Assert.Equal(12222222, jT808UploadLocationRequest.Lat);
Assert.Equal(132444444, jT808UploadLocationRequest.Lng);
Assert.Equal(60, jT808UploadLocationRequest.Speed);
Assert.Equal((uint)2, jT808UploadLocationRequest.StatusFlag);
Assert.Equal((uint)(VideoRelateAlarmType.视频信号遮挡报警 | VideoRelateAlarmType.其他视频设备故障报警), ((JT808_0x0200_0x14)jT808UploadLocationRequest.JT808LocationAttachData[JT808_JT1078_Constants.JT808_0X0200_0x14]).VideoRelateAlarm);
}

[Fact]
public void Test_0x14_3()
{
byte[] bodys = "000000010000000200BA7F0E07E4F11C0028003C000020013120202014040000000A".ToHexBytes();
string json = JT808Serializer.Analyze<JT808_0x0200>(bodys);
}

[Fact]
public void Test_0x15_1()
{
JT808_0x0200 jT808UploadLocationRequest = new JT808_0x0200
{
AlarmFlag = 1,
Altitude = 40,
GPSTime = DateTime.Parse("2020-01-31 20:20:20"),
Lat = 12222222,
Lng = 132444444,
Speed = 60,
Direction = 0,
StatusFlag = 2,
JT808LocationAttachData = new Dictionary<byte, JT808_0x0200_BodyBase>()
};
jT808UploadLocationRequest.JT808LocationAttachData.Add(JT808_JT1078_Constants.JT808_0X0200_0x15, new JT808_0x0200_0x15
{
VideoSignalLoseAlarmStatus=3
});
var hex = JT808Serializer.Serialize(jT808UploadLocationRequest).ToHexString();
Assert.Equal("000000010000000200BA7F0E07E4F11C0028003C0000200131202020150400000003", hex);
}

[Fact]
public void Test_0x15_2()
{
byte[] bodys = "000000010000000200BA7F0E07E4F11C0028003C0000200131202020150400000003".ToHexBytes();
JT808_0x0200 jT808UploadLocationRequest = JT808Serializer.Deserialize<JT808_0x0200>(bodys);
Assert.Equal((uint)1, jT808UploadLocationRequest.AlarmFlag);
Assert.Equal(DateTime.Parse("2020-01-31 20:20:20"), jT808UploadLocationRequest.GPSTime);
Assert.Equal(12222222, jT808UploadLocationRequest.Lat);
Assert.Equal(132444444, jT808UploadLocationRequest.Lng);
Assert.Equal(60, jT808UploadLocationRequest.Speed);
Assert.Equal((uint)2, jT808UploadLocationRequest.StatusFlag);
Assert.Equal(3u, ((JT808_0x0200_0x15)jT808UploadLocationRequest.JT808LocationAttachData[JT808_JT1078_Constants.JT808_0X0200_0x15]).VideoSignalLoseAlarmStatus);
}

[Fact]
public void Test_0x15_3()
{
byte[] bodys = "000000010000000200BA7F0E07E4F11C0028003C0000200131202020150400000003".ToHexBytes();
string json = JT808Serializer.Analyze<JT808_0x0200>(bodys);
}
}
}

+ 0
- 65
src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x1003Test.cs View File

@@ -1,65 +0,0 @@
using JT808.Protocol.Extensions.JT1078.MessageBody;
using JT808.Protocol.Interfaces;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;

namespace JT808.Protocol.Extensions.JT1078.Test
{
public class JT808_0x1003Test
{
JT808Serializer JT808Serializer;
public JT808_0x1003Test()
{
IServiceCollection serviceDescriptors1 = new ServiceCollection();
serviceDescriptors1
.AddJT808Configure()
.AddJT1078Configure();
var ServiceProvider1 = serviceDescriptors1.BuildServiceProvider();
var defaultConfig = ServiceProvider1.GetRequiredService<IJT808Config>();
JT808Serializer = defaultConfig.GetSerializer();
}

[Fact]
public void Test1()
{
JT808_0x1003 jT808_0x1003 = new JT808_0x1003()
{
AudioFrameLength = 1,
EnterAudioChannelsNumber = 2,
EnterAudioEncoding = 3,
EnterAudioSampleDigits = 4,
EnterAudioSampleRate = 5,
IsSupportedAudioOutput = 1,
VideoEncoding = 6,
TerminalSupportedMaxNumberOfAudioPhysicalChannels = 7,
TerminalSupportedMaxNumberOfVideoPhysicalChannels = 8
};
var hex = JT808Serializer.Serialize(jT808_0x1003).ToHexString();
Assert.Equal("03020504000101060708", hex);
}

[Fact]
public void Test2()
{
JT808_0x1003 jT808_0x1003 = JT808Serializer.Deserialize<JT808_0x1003>("03020504000101060708".ToHexBytes());
Assert.Equal(1,jT808_0x1003.AudioFrameLength);
Assert.Equal(2, jT808_0x1003.EnterAudioChannelsNumber);
Assert.Equal(3, jT808_0x1003.EnterAudioEncoding);
Assert.Equal(4, jT808_0x1003.EnterAudioSampleDigits);
Assert.Equal(5, jT808_0x1003.EnterAudioSampleRate);
Assert.Equal(1, jT808_0x1003.IsSupportedAudioOutput);
Assert.Equal(6, jT808_0x1003.VideoEncoding);
Assert.Equal(7, jT808_0x1003.TerminalSupportedMaxNumberOfAudioPhysicalChannels);
Assert.Equal(8, jT808_0x1003.TerminalSupportedMaxNumberOfVideoPhysicalChannels);
}
[Fact]
public void Test3()
{
var json = JT808Serializer.Analyze<JT808_0x1003>("03020504000101060708".ToHexBytes());
}
}
}

+ 0
- 66
src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x1005Test.cs View File

@@ -1,66 +0,0 @@
using JT808.Protocol.Extensions.JT1078.MessageBody;
using JT808.Protocol.Interfaces;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;

namespace JT808.Protocol.Extensions.JT1078.Test
{
public class JT808_0x1005Test
{
JT808Serializer JT808Serializer;
public JT808_0x1005Test()
{
IServiceCollection serviceDescriptors1 = new ServiceCollection();
serviceDescriptors1
.AddJT808Configure()
.AddJT1078Configure();
var ServiceProvider1 = serviceDescriptors1.BuildServiceProvider();
var defaultConfig = ServiceProvider1.GetRequiredService<IJT808Config>();
JT808Serializer = defaultConfig.GetSerializer();

Newtonsoft.Json.JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() =>
{
//日期类型默认格式化处理
return new Newtonsoft.Json.JsonSerializerSettings
{
DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat,
DateFormatString = "yyyy-MM-dd HH:mm:ss"
};
});
}

[Fact]
public void Test1()
{
JT808_0x1005 jT808_0x1005 = new JT808_0x1005()
{
BeginTime=Convert.ToDateTime("2019-07-16 10:20:01"),
EndTime= Convert.ToDateTime("2019-07-16 10:25:02"),
GettingOffNumber=1,
GettingOnNumber=1
};
var hex = JT808Serializer.Serialize(jT808_0x1005).ToHexString();
Assert.Equal("19071610200119071610250200010001", hex);
}

[Fact]
public void Test2()
{
var jT808_0x1005 = JT808Serializer.Deserialize<JT808_0x1005>("19071610200119071610250200010001".ToHexBytes());
Assert.Equal(Convert.ToDateTime("2019-07-16 10:20:01"),jT808_0x1005.BeginTime);
Assert.Equal(Convert.ToDateTime("2019-07-16 10:25:02"),jT808_0x1005.EndTime);
Assert.Equal(1, jT808_0x1005.GettingOffNumber);
Assert.Equal(1, jT808_0x1005.GettingOnNumber);
}
[Fact]
public void Test3()
{
var json = JT808Serializer.Analyze<JT808_0x1005>("19071610200119071610250200010001".ToHexBytes());
}
}
}

+ 0
- 141
src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x1205Test.cs View File

@@ -1,141 +0,0 @@
using JT808.Protocol.Extensions.JT1078.MessageBody;
using JT808.Protocol.Interfaces;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;
using System.Linq;

namespace JT808.Protocol.Extensions.JT1078.Test
{
public class JT808_0x1205Test
{
JT808Serializer JT808Serializer;
public JT808_0x1205Test()
{
IServiceCollection serviceDescriptors1 = new ServiceCollection();
serviceDescriptors1
.AddJT808Configure()
.AddJT1078Configure();
var ServiceProvider1 = serviceDescriptors1.BuildServiceProvider();
var defaultConfig = ServiceProvider1.GetRequiredService<IJT808Config>();
JT808Serializer = defaultConfig.GetSerializer();

Newtonsoft.Json.JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() =>
{
//日期类型默认格式化处理
return new Newtonsoft.Json.JsonSerializerSettings
{
DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat,
DateFormatString = "yyyy-MM-dd HH:mm:ss"
};
});
}

[Fact]
public void Test1()
{
JT808_0x1205 jT808_0x1205 = new JT808_0x1205()
{
MsgNum = 1,
AVResouceTotal = 2,
AVResouces = new List<JT808_0x1205_AVResouce> {
new JT808_0x1205_AVResouce{
AlarmFlag=1,
AVResourceType=2,
BeginTime=Convert.ToDateTime("2019-07-16 10:20:01"),
EndTime=Convert.ToDateTime("2019-07-16 10:25:01"),
FileSize=3,
LogicChannelNo=4,
MemoryType=5,
StreamType=6
},
new JT808_0x1205_AVResouce{
AlarmFlag=11,
AVResourceType=21,
BeginTime=Convert.ToDateTime("2019-07-16 11:20:01"),
EndTime=Convert.ToDateTime("2019-07-16 11:25:02"),
FileSize=31,
LogicChannelNo=41,
MemoryType=51,
StreamType=61
}
}
};
var hex = JT808Serializer.Serialize(jT808_0x1205).ToHexString();
Assert.Equal("0001000000020419071610200119071610250100000000000000010206050000000329190716112001190716112502000000000000000B153D330000001F", hex);
}

[Fact]
public void Test2()
{
var jT808_0x1205 = JT808Serializer.Deserialize<JT808_0x1205>("0001000000020419071610200119071610250100000000000000010206050000000329190716112001190716112502000000000000000B153D330000001F".ToHexBytes());
Assert.Equal(1, jT808_0x1205.MsgNum);
Assert.Equal(2u, jT808_0x1205.AVResouceTotal);

Assert.Equal(1u, jT808_0x1205.AVResouces[0].AlarmFlag);
Assert.Equal(2, jT808_0x1205.AVResouces[0].AVResourceType);
Assert.Equal(Convert.ToDateTime("2019-07-16 10:20:01"),jT808_0x1205.AVResouces[0].BeginTime);
Assert.Equal(Convert.ToDateTime("2019-07-16 10:25:01"),jT808_0x1205.AVResouces[0].EndTime);
Assert.Equal(3u, jT808_0x1205.AVResouces[0].FileSize);
Assert.Equal(4, jT808_0x1205.AVResouces[0].LogicChannelNo);
Assert.Equal(5, jT808_0x1205.AVResouces[0].MemoryType);
Assert.Equal(6, jT808_0x1205.AVResouces[0].StreamType);

Assert.Equal(11u, jT808_0x1205.AVResouces[1].AlarmFlag);
Assert.Equal(21, jT808_0x1205.AVResouces[1].AVResourceType);
Assert.Equal(Convert.ToDateTime("2019-07-16 11:20:01"),jT808_0x1205.AVResouces[1].BeginTime);
Assert.Equal(Convert.ToDateTime("2019-07-16 11:25:02"),jT808_0x1205.AVResouces[1].EndTime);
Assert.Equal(31u, jT808_0x1205.AVResouces[1].FileSize);
Assert.Equal(41, jT808_0x1205.AVResouces[1].LogicChannelNo);
Assert.Equal(51, jT808_0x1205.AVResouces[1].MemoryType);
Assert.Equal(61, jT808_0x1205.AVResouces[1].StreamType);
}
[Fact]
public void Test3()
{
var json = JT808Serializer.Analyze<JT808_0x1205>("000100000002041907161020011907161025010000000102060500000003291907161120011907161125020000000B153D330000001F".ToHexBytes());
}

[Fact]
public void Test4()
{
var data1 = JT808Serializer.HeaderDeserialize("7E120523A204066657506200EB00020001015A00000023012012191042052012191050190000000000000000000101064446D10120121910221720121910420500000000000000000001010F1FE8EB0120121910023420121910221700000000000000000001010F182D5C0120121909471120121910015500000000000000000001010B38F2430120121909274020121909471100000000000000000001010F056DB40120121909080920121909274000000000000000000001010F0724380120121908483820121909080900000000000000000001010F0530AB0120121908290720121908483800000000000000000001010F05896C0120121908093720121908290700000000000000000001010F02CD3B0120121907500520121908093700000000000000000001010F056FEF0120121907303420121907500500000000000000000001010F043C3401201219072541201219073034000000000000000000010103C26C5F0120121907061120121907254100000000000000000001010F03F0C10120121906464220121907061100000000000000000001010F02F6330120121906271220121906464200000000000000000001010F02E43B0120121906074220121906271200000000000000000001010F033D670120121905481120121906074200000000000000000001010F088BF20120121905284120121905481100000000000000000001010F03F9FE0120121905091020121905284100000000000000000001010F05B1040120121904494020121905091000000000000000000001010F02B3540120121904301020121904494000000000000000000001010F0417B00120121904103920121904301000000000000000000001010F0538970120121903510820121904103900000000000000000001010F054E9E0120121903313820121903510800000000000000000001010F016ECB0120121903120820121903313800000000000000000001010F0333C00120121902523820121903120700000000000000000001010F029D230120121902330720121902523700000000000000000001010F0354E40120121902133720121902330700000000000000000001010F03303D0120121901540720121902133700000000000000000001010F04981E0120121901343720121901540700000000000000000001010F02AD940120121901150820121901343700000000000000000001010EFFD7CF0120121900553720121901150800000000000000000001010F07D9330120121900360720121900553700000000000000000001010F040E740C7E".ToHexBytes());
var data2 = JT808Serializer.HeaderDeserialize("7E1205203804066657506200EC000200020120121900163320121900360700000000000000000001010F0CE4CD0120121900002220121900163300000000000000000001010C6F9E7B5D7E".ToHexBytes());
var realBody = data1.Bodies.Concat(data2.Bodies).ToArray();
var result = JT808Serializer.Deserialize<JT808_0x1205>(realBody);
}


[Fact]
public void Test5()
{
var data1 = JT808Serializer.Deserialize("7E120523A204066657506200EB00020001015A00000023012012191042052012191050190000000000000000000101064446D10120121910221720121910420500000000000000000001010F1FE8EB0120121910023420121910221700000000000000000001010F182D5C0120121909471120121910015500000000000000000001010B38F2430120121909274020121909471100000000000000000001010F056DB40120121909080920121909274000000000000000000001010F0724380120121908483820121909080900000000000000000001010F0530AB0120121908290720121908483800000000000000000001010F05896C0120121908093720121908290700000000000000000001010F02CD3B0120121907500520121908093700000000000000000001010F056FEF0120121907303420121907500500000000000000000001010F043C3401201219072541201219073034000000000000000000010103C26C5F0120121907061120121907254100000000000000000001010F03F0C10120121906464220121907061100000000000000000001010F02F6330120121906271220121906464200000000000000000001010F02E43B0120121906074220121906271200000000000000000001010F033D670120121905481120121906074200000000000000000001010F088BF20120121905284120121905481100000000000000000001010F03F9FE0120121905091020121905284100000000000000000001010F05B1040120121904494020121905091000000000000000000001010F02B3540120121904301020121904494000000000000000000001010F0417B00120121904103920121904301000000000000000000001010F0538970120121903510820121904103900000000000000000001010F054E9E0120121903313820121903510800000000000000000001010F016ECB0120121903120820121903313800000000000000000001010F0333C00120121902523820121903120700000000000000000001010F029D230120121902330720121902523700000000000000000001010F0354E40120121902133720121902330700000000000000000001010F03303D0120121901540720121902133700000000000000000001010F04981E0120121901343720121901540700000000000000000001010F02AD940120121901150820121901343700000000000000000001010EFFD7CF0120121900553720121901150800000000000000000001010F07D9330120121900360720121900553700000000000000000001010F040E740C7E".ToHexBytes());
var data2 = JT808Serializer.Deserialize("7E1205203804066657506200EC000200020120121900163320121900360700000000000000000001010F0CE4CD0120121900002220121900163300000000000000000001010C6F9E7B5D7E".ToHexBytes());
var realBody = data1.SubDataBodies.Concat(data2.SubDataBodies).ToArray();
var result = JT808Serializer.Deserialize<JT808_0x1205>(realBody);
}

[Fact]
public void Test6()
{
var pack1 = JT808Serializer.Deserialize("7E120523A204066657506200EB00020001015A00000023012012191042052012191050190000000000000000000101064446D10120121910221720121910420500000000000000000001010F1FE8EB0120121910023420121910221700000000000000000001010F182D5C0120121909471120121910015500000000000000000001010B38F2430120121909274020121909471100000000000000000001010F056DB40120121909080920121909274000000000000000000001010F0724380120121908483820121909080900000000000000000001010F0530AB0120121908290720121908483800000000000000000001010F05896C0120121908093720121908290700000000000000000001010F02CD3B0120121907500520121908093700000000000000000001010F056FEF0120121907303420121907500500000000000000000001010F043C3401201219072541201219073034000000000000000000010103C26C5F0120121907061120121907254100000000000000000001010F03F0C10120121906464220121907061100000000000000000001010F02F6330120121906271220121906464200000000000000000001010F02E43B0120121906074220121906271200000000000000000001010F033D670120121905481120121906074200000000000000000001010F088BF20120121905284120121905481100000000000000000001010F03F9FE0120121905091020121905284100000000000000000001010F05B1040120121904494020121905091000000000000000000001010F02B3540120121904301020121904494000000000000000000001010F0417B00120121904103920121904301000000000000000000001010F0538970120121903510820121904103900000000000000000001010F054E9E0120121903313820121903510800000000000000000001010F016ECB0120121903120820121903313800000000000000000001010F0333C00120121902523820121903120700000000000000000001010F029D230120121902330720121902523700000000000000000001010F0354E40120121902133720121902330700000000000000000001010F03303D0120121901540720121902133700000000000000000001010F04981E0120121901343720121901540700000000000000000001010F02AD940120121901150820121901343700000000000000000001010EFFD7CF0120121900553720121901150800000000000000000001010F07D9330120121900360720121900553700000000000000000001010F040E740C7E".ToHexBytes());
var pack2 = JT808Serializer.Deserialize("7E1205203804066657506200EC000200020120121900163320121900360700000000000000000001010F0CE4CD0120121900002220121900163300000000000000000001010C6F9E7B5D7E".ToHexBytes());
var realBody = pack1.SubDataBodies.Concat(pack2.SubDataBodies).ToArray();
var result = JT808Serializer.Analyze(pack1.Header.MsgId,realBody);
}

[Fact]
public void Test7()
{
var pack1 = JT808Serializer.Deserialize("7E120523A204066657506200EB00020001015A00000023012012191042052012191050190000000000000000000101064446D10120121910221720121910420500000000000000000001010F1FE8EB0120121910023420121910221700000000000000000001010F182D5C0120121909471120121910015500000000000000000001010B38F2430120121909274020121909471100000000000000000001010F056DB40120121909080920121909274000000000000000000001010F0724380120121908483820121909080900000000000000000001010F0530AB0120121908290720121908483800000000000000000001010F05896C0120121908093720121908290700000000000000000001010F02CD3B0120121907500520121908093700000000000000000001010F056FEF0120121907303420121907500500000000000000000001010F043C3401201219072541201219073034000000000000000000010103C26C5F0120121907061120121907254100000000000000000001010F03F0C10120121906464220121907061100000000000000000001010F02F6330120121906271220121906464200000000000000000001010F02E43B0120121906074220121906271200000000000000000001010F033D670120121905481120121906074200000000000000000001010F088BF20120121905284120121905481100000000000000000001010F03F9FE0120121905091020121905284100000000000000000001010F05B1040120121904494020121905091000000000000000000001010F02B3540120121904301020121904494000000000000000000001010F0417B00120121904103920121904301000000000000000000001010F0538970120121903510820121904103900000000000000000001010F054E9E0120121903313820121903510800000000000000000001010F016ECB0120121903120820121903313800000000000000000001010F0333C00120121902523820121903120700000000000000000001010F029D230120121902330720121902523700000000000000000001010F0354E40120121902133720121902330700000000000000000001010F03303D0120121901540720121902133700000000000000000001010F04981E0120121901343720121901540700000000000000000001010F02AD940120121901150820121901343700000000000000000001010EFFD7CF0120121900553720121901150800000000000000000001010F07D9330120121900360720121900553700000000000000000001010F040E740C7E".ToHexBytes());
var pack2 = JT808Serializer.Deserialize("7E1205203804066657506200EC000200020120121900163320121900360700000000000000000001010F0CE4CD0120121900002220121900163300000000000000000001010C6F9E7B5D7E".ToHexBytes());
var realBody = pack1.SubDataBodies.Concat(pack2.SubDataBodies).ToArray();
var result = JT808Serializer.AnalyzeJsonBuffer(pack1.Header.MsgId, realBody);
string json = Encoding.UTF8.GetString(result);
}
}
}

+ 0
- 62
src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x1206Test.cs View File

@@ -1,62 +0,0 @@
using JT808.Protocol.Extensions.JT1078.MessageBody;
using JT808.Protocol.Interfaces;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;

namespace JT808.Protocol.Extensions.JT1078.Test
{
public class JT808_0x1206Test
{
JT808Serializer JT808Serializer;
public JT808_0x1206Test()
{
IServiceCollection serviceDescriptors1 = new ServiceCollection();
serviceDescriptors1
.AddJT808Configure()
.AddJT1078Configure();
var ServiceProvider1 = serviceDescriptors1.BuildServiceProvider();
var defaultConfig = ServiceProvider1.GetRequiredService<IJT808Config>();
JT808Serializer = defaultConfig.GetSerializer();

Newtonsoft.Json.JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() =>
{
//日期类型默认格式化处理
return new Newtonsoft.Json.JsonSerializerSettings
{
DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat,
DateFormatString = "yyyy-MM-dd HH:mm:ss"
};
});
}

[Fact]
public void Test1()
{
JT808_0x1206 jT808_0x1206 = new JT808_0x1206()
{
MsgNum=1,
Result=1
};
var hex = JT808Serializer.Serialize(jT808_0x1206).ToHexString();
Assert.Equal("000101", hex);
}

[Fact]
public void Test2()
{
var jT808_0x1206 = JT808Serializer.Deserialize<JT808_0x1206>("000101".ToHexBytes());
Assert.Equal(1, jT808_0x1206.MsgNum);
Assert.Equal(1, jT808_0x1206.Result);
}
[Fact]
public void Test3()
{
var jT808_0x1206 = JT808Serializer.Analyze<JT808_0x1206>("000101".ToHexBytes());
}
}
}

+ 0
- 300
src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x8103CustomId.cs View File

@@ -1,300 +0,0 @@
using JT808.Protocol.Enums;
using JT808.Protocol.Extensions.JT1078.MessageBody;
using JT808.Protocol.Interfaces;
using JT808.Protocol.MessageBody;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using Xunit;

namespace JT808.Protocol.Extensions.JT1078.Test
{
public class JT808_0x8103CustomId
{
JT808Serializer JT808Serializer;

public JT808_0x8103CustomId()
{
IServiceCollection serviceDescriptors1 = new ServiceCollection();
serviceDescriptors1.AddJT808Configure(new DefaultGlobalConfig())
.AddJT1078Configure();
var ServiceProvider1 = serviceDescriptors1.BuildServiceProvider();
var defaultConfig = ServiceProvider1.GetRequiredService<DefaultGlobalConfig>();
JT808Serializer = new JT808Serializer(defaultConfig);
}
[Fact]
public void Test1()
{
JT808Package jT808Package = new JT808Package
{
Header = new JT808Header
{
MsgId = JT808MsgId.设置终端参数.ToUInt16Value(),
ManualMsgNum = 10,
TerminalPhoneNo = "123456789",
},
Bodies = new JT808_0x8103
{
ParamList = new List<JT808_0x8103_BodyBase> {
new JT808_0x8103_0x0075 {
AudioOutputEnabled=1,
OSD=2,
RTS_EncodeMode=3,
RTS_KF_Interval=4,
RTS_Resolution=5,
RTS_Target_CodeRate=6,
RTS_Target_FPS=7,
StreamStore_EncodeMode=8,
StreamStore_KF_Interval=9,
StreamStore_Resolution=10,
StreamStore_Target_CodeRate=11,
StreamStore_Target_FPS=12
},
new JT808_0x8103_0x0076 {
AudioChannelTotal=1,
AVChannelTotal=2,
VudioChannelTotal=3,
ParamLength=27,
AVChannelRefTables=new List<JT808_0x8103_0x0076_AVChannelRefTable>{
new JT808_0x8103_0x0076_AVChannelRefTable{
ChannelType =0,
IsConnectCloudPlat =1,
LogicChannelNo =2,
PhysicalChannelNo =3 },
new JT808_0x8103_0x0076_AVChannelRefTable{
ChannelType =4,
IsConnectCloudPlat =5,
LogicChannelNo =6,
PhysicalChannelNo =7 },
new JT808_0x8103_0x0076_AVChannelRefTable{
ChannelType =8,
IsConnectCloudPlat =9,
LogicChannelNo =10,
PhysicalChannelNo =11 },
new JT808_0x8103_0x0076_AVChannelRefTable{
ChannelType =12,
IsConnectCloudPlat =13,
LogicChannelNo =14,
PhysicalChannelNo =15 },
new JT808_0x8103_0x0076_AVChannelRefTable{
ChannelType =16,
IsConnectCloudPlat =17,
LogicChannelNo =18,
PhysicalChannelNo =19 },
new JT808_0x8103_0x0076_AVChannelRefTable{
ChannelType =20,
IsConnectCloudPlat =21,
LogicChannelNo =22,
PhysicalChannelNo =23 }
}
},
new JT808_0x8103_0x0077{
NeedSetChannelTotal=2,
ParamLength=43,
SignalChannels=new List<JT808_0x8103_0x0077_SignalChannel>{
new JT808_0x8103_0x0077_SignalChannel{
LogicChannelNo =1,
OSD =2,
RTS_EncodeMode =3,
RTS_KF_Interval =4,
RTS_Resolution =5,
RTS_Target_CodeRate =6,
RTS_Target_FPS =7,
StreamStore_EncodeMode =8,
StreamStore_KF_Interval =9,
StreamStore_Resolution =10,
StreamStore_Target_CodeRate=11,
StreamStore_Target_FPS =12
},
new JT808_0x8103_0x0077_SignalChannel{
LogicChannelNo=1,
OSD =2,
RTS_EncodeMode =3,
RTS_KF_Interval =4,
RTS_Resolution =5,
RTS_Target_CodeRate =6,
RTS_Target_FPS =7,
StreamStore_EncodeMode =8,
StreamStore_KF_Interval =9,
StreamStore_Resolution =10,
StreamStore_Target_CodeRate=11,
StreamStore_Target_FPS =12
}
}
},
new JT808_0x8103_0x0079{
BeginMinute=1,
Duration =2,
StorageThresholds =3
},
new JT808_0x8103_0x007A{
AlarmShielding=1
},
new JT808_0x8103_0x007B{
NuclearLoadNumber=1,
FatigueThreshold =2
},
new JT808_0x8103_0x007C{
SleepWakeMode=1,
TimerWakeDaySet =2,
WakeConditionType =3,
TimerWakeDayParamter=new JT808_0x8103_0x007C_TimerWakeDayParamter{
TimePeriod1CloseTime="12",
TimePeriod1WakeTime="23",
TimePeriod2CloseTime="34",
TimePeriod2WakeTime="45",
TimePeriod3CloseTime="56",
TimePeriod3WakeTime="67",
TimePeriod4CloseTime="78",
TimePeriod4WakeTime="89",
TimerWakeEnableFlag=10
}
}
}
}
};
var hex = JT808Serializer.Serialize(jT808Package).ToHexString();
Assert.Equal("7E8103009C000123456789000A070000007515030500040700000006080A00090C0000000B000201000000761B02010303020001070604050B0A08090F0E0C0D1312101117161415000000772B0201030500040700000006080A00090C0000000B000201030500040700000006080A00090C0000000B000200000079030302010000007A04000000010000007B0201020000007C140103020A00230012004500340067005600890078587E", hex);
}

[Fact]
public void Test2()
{
byte[] bytes = "7E8103009C000123456789000A070000007515030500040700000006080A00090C0000000B000201000000761B02010303020001070604050B0A08090F0E0C0D1312101117161415000000772B0201030500040700000006080A00090C0000000B000201030500040700000006080A00090C0000000B000200000079030302010000007A04000000010000007B0201020000007C140103020A00230012004500340067005600890078587E".ToHexBytes();
JT808Package jT808_0X8103 = JT808Serializer.Deserialize(bytes);
Assert.Equal(JT808MsgId.设置终端参数.ToUInt16Value(), jT808_0X8103.Header.MsgId);
Assert.Equal(10, jT808_0X8103.Header.MsgNum);
Assert.Equal("123456789", jT808_0X8103.Header.TerminalPhoneNo);

JT808_0x8103 jT808_0x8103 = (JT808_0x8103)jT808_0X8103.Bodies;
foreach (var item in jT808_0x8103.ParamList)
{
switch (item)
{
case JT808_0x8103_0x0075 jT808_0x8103_0x0075:
Assert.Equal(1,jT808_0x8103_0x0075.AudioOutputEnabled);
Assert.Equal(2,jT808_0x8103_0x0075.OSD);
Assert.Equal(3,jT808_0x8103_0x0075.RTS_EncodeMode);
Assert.Equal(4,jT808_0x8103_0x0075.RTS_KF_Interval);
Assert.Equal(5,jT808_0x8103_0x0075.RTS_Resolution);
Assert.Equal(6u,jT808_0x8103_0x0075.RTS_Target_CodeRate);
Assert.Equal(7,jT808_0x8103_0x0075.RTS_Target_FPS);
Assert.Equal(8,jT808_0x8103_0x0075.StreamStore_EncodeMode);
Assert.Equal(9,jT808_0x8103_0x0075.StreamStore_KF_Interval);
Assert.Equal(10,jT808_0x8103_0x0075.StreamStore_Resolution);
Assert.Equal(11u,jT808_0x8103_0x0075.StreamStore_Target_CodeRate);
Assert.Equal(12u,jT808_0x8103_0x0075.StreamStore_Target_FPS);
break;
case JT808_0x8103_0x0076 jT808_0x8103_0x0076:
Assert.Equal(1,jT808_0x8103_0x0076.AudioChannelTotal);
Assert.Equal(2, jT808_0x8103_0x0076.AVChannelTotal);
Assert.Equal(3,jT808_0x8103_0x0076.VudioChannelTotal);
Assert.Equal(27,jT808_0x8103_0x0076.ParamLength);
Assert.Equal(0,jT808_0x8103_0x0076.AVChannelRefTables[0].ChannelType);
Assert.Equal(1,jT808_0x8103_0x0076.AVChannelRefTables[0].IsConnectCloudPlat);
Assert.Equal(2,jT808_0x8103_0x0076.AVChannelRefTables[0].LogicChannelNo);
Assert.Equal(3,jT808_0x8103_0x0076.AVChannelRefTables[0].PhysicalChannelNo);

Assert.Equal(4,jT808_0x8103_0x0076.AVChannelRefTables[1].ChannelType);
Assert.Equal(5,jT808_0x8103_0x0076.AVChannelRefTables[1].IsConnectCloudPlat);
Assert.Equal(6,jT808_0x8103_0x0076.AVChannelRefTables[1].LogicChannelNo);
Assert.Equal(7,jT808_0x8103_0x0076.AVChannelRefTables[1].PhysicalChannelNo);

Assert.Equal(8,jT808_0x8103_0x0076.AVChannelRefTables[2].ChannelType);
Assert.Equal(9,jT808_0x8103_0x0076.AVChannelRefTables[2].IsConnectCloudPlat);
Assert.Equal(10,jT808_0x8103_0x0076.AVChannelRefTables[2].LogicChannelNo);
Assert.Equal(11,jT808_0x8103_0x0076.AVChannelRefTables[2].PhysicalChannelNo);

Assert.Equal(12,jT808_0x8103_0x0076.AVChannelRefTables[3].ChannelType);
Assert.Equal(13,jT808_0x8103_0x0076.AVChannelRefTables[3].IsConnectCloudPlat);
Assert.Equal(14,jT808_0x8103_0x0076.AVChannelRefTables[3].LogicChannelNo);
Assert.Equal(15,jT808_0x8103_0x0076.AVChannelRefTables[3].PhysicalChannelNo);

Assert.Equal(16,jT808_0x8103_0x0076.AVChannelRefTables[4].ChannelType);
Assert.Equal(17,jT808_0x8103_0x0076.AVChannelRefTables[4].IsConnectCloudPlat);
Assert.Equal(18,jT808_0x8103_0x0076.AVChannelRefTables[4].LogicChannelNo);
Assert.Equal(19,jT808_0x8103_0x0076.AVChannelRefTables[4].PhysicalChannelNo);

Assert.Equal(20,jT808_0x8103_0x0076.AVChannelRefTables[5].ChannelType);
Assert.Equal(21,jT808_0x8103_0x0076.AVChannelRefTables[5].IsConnectCloudPlat);
Assert.Equal(22,jT808_0x8103_0x0076.AVChannelRefTables[5].LogicChannelNo);
Assert.Equal(23,jT808_0x8103_0x0076.AVChannelRefTables[5].PhysicalChannelNo);
break;
case JT808_0x8103_0x0077 jT808_0x8103_0x0077:
Assert.Equal(2,jT808_0x8103_0x0077.NeedSetChannelTotal);
Assert.Equal(43,jT808_0x8103_0x0077.ParamLength);

Assert.Equal(1,jT808_0x8103_0x0077.SignalChannels[0].LogicChannelNo);
Assert.Equal(2,jT808_0x8103_0x0077.SignalChannels[0].OSD);
Assert.Equal(3,jT808_0x8103_0x0077.SignalChannels[0].RTS_EncodeMode);
Assert.Equal(4,jT808_0x8103_0x0077.SignalChannels[0].RTS_KF_Interval);
Assert.Equal(5,jT808_0x8103_0x0077.SignalChannels[0].RTS_Resolution);
Assert.Equal(6u,jT808_0x8103_0x0077.SignalChannels[0].RTS_Target_CodeRate);
Assert.Equal(7,jT808_0x8103_0x0077.SignalChannels[0].RTS_Target_FPS);
Assert.Equal(8,jT808_0x8103_0x0077.SignalChannels[0].StreamStore_EncodeMode);
Assert.Equal(9,jT808_0x8103_0x0077.SignalChannels[0].StreamStore_KF_Interval);
Assert.Equal(10,jT808_0x8103_0x0077.SignalChannels[0].StreamStore_Resolution);
Assert.Equal(11u,jT808_0x8103_0x0077.SignalChannels[0].StreamStore_Target_CodeRate);
Assert.Equal(12,jT808_0x8103_0x0077.SignalChannels[0].StreamStore_Target_FPS);

Assert.Equal(1,jT808_0x8103_0x0077.SignalChannels[1].LogicChannelNo);
Assert.Equal(2,jT808_0x8103_0x0077.SignalChannels[1].OSD);
Assert.Equal(3,jT808_0x8103_0x0077.SignalChannels[1].RTS_EncodeMode);
Assert.Equal(4,jT808_0x8103_0x0077.SignalChannels[1].RTS_KF_Interval);
Assert.Equal(5,jT808_0x8103_0x0077.SignalChannels[1].RTS_Resolution);
Assert.Equal(6u,jT808_0x8103_0x0077.SignalChannels[1].RTS_Target_CodeRate);
Assert.Equal(7,jT808_0x8103_0x0077.SignalChannels[1].RTS_Target_FPS);
Assert.Equal(8,jT808_0x8103_0x0077.SignalChannels[1].StreamStore_EncodeMode);
Assert.Equal(9,jT808_0x8103_0x0077.SignalChannels[1].StreamStore_KF_Interval);
Assert.Equal(10,jT808_0x8103_0x0077.SignalChannels[1].StreamStore_Resolution);
Assert.Equal(11u,jT808_0x8103_0x0077.SignalChannels[1].StreamStore_Target_CodeRate);
Assert.Equal(12,jT808_0x8103_0x0077.SignalChannels[1].StreamStore_Target_FPS);

break;
case JT808_0x8103_0x0079 jT808_0x8103_0x0079:
Assert.Equal(1,jT808_0x8103_0x0079.BeginMinute);
Assert.Equal(2,jT808_0x8103_0x0079.Duration);
Assert.Equal(3,jT808_0x8103_0x0079.StorageThresholds);
break;
case JT808_0x8103_0x007A jT808_0x8103_0x007A:
Assert.Equal(1u,jT808_0x8103_0x007A.AlarmShielding);
break;
case JT808_0x8103_0x007B jT808_0x8103_0x007B:
Assert.Equal(1,jT808_0x8103_0x007B.NuclearLoadNumber);
Assert.Equal(2,jT808_0x8103_0x007B.FatigueThreshold);
break;
case JT808_0x8103_0x007C jT808_0x8103_0x007C:
Assert.Equal(1,jT808_0x8103_0x007C.SleepWakeMode);
Assert.Equal(2,jT808_0x8103_0x007C.TimerWakeDaySet);
Assert.Equal(3,jT808_0x8103_0x007C.WakeConditionType);
Assert.Equal("12", jT808_0x8103_0x007C.TimerWakeDayParamter.TimePeriod1CloseTime);
Assert.Equal("23",jT808_0x8103_0x007C.TimerWakeDayParamter.TimePeriod1WakeTime);
Assert.Equal("34",jT808_0x8103_0x007C.TimerWakeDayParamter.TimePeriod2CloseTime);
Assert.Equal("45",jT808_0x8103_0x007C.TimerWakeDayParamter.TimePeriod2WakeTime);
Assert.Equal("56",jT808_0x8103_0x007C.TimerWakeDayParamter.TimePeriod3CloseTime);
Assert.Equal("67",jT808_0x8103_0x007C.TimerWakeDayParamter.TimePeriod3WakeTime);
Assert.Equal("78",jT808_0x8103_0x007C.TimerWakeDayParamter.TimePeriod4CloseTime);
Assert.Equal("89", jT808_0x8103_0x007C.TimerWakeDayParamter.TimePeriod4WakeTime);
Assert.Equal(10,jT808_0x8103_0x007C.TimerWakeDayParamter.TimerWakeEnableFlag);
break;
default:
break;
}
}
}

[Fact]
public void Test3()
{
byte[] bytes = "7E8103009C000123456789000A070000007515030500040700000006080A00090C0000000B000201000000761B02010303020001070604050B0A08090F0E0C0D1312101117161415000000772B0201030500040700000006080A00090C0000000B000201030500040700000006080A00090C0000000B000200000079030302010000007A04000000010000007B0201020000007C140103020A00230012004500340067005600890078587E".ToHexBytes();
var jT808_0X8103 = JT808Serializer.Analyze(bytes);
}
}
class DefaultGlobalConfig : GlobalConfigBase
{
public override string ConfigId { protected set; get; } = "Default";
}
}

+ 0
- 101
src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x9101Test.cs View File

@@ -1,101 +0,0 @@
using JT808.Protocol.Extensions.JT1078.MessageBody;
using JT808.Protocol.Interfaces;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;

namespace JT808.Protocol.Extensions.JT1078.Test
{
public class JT808_0x9101Test
{
JT808Serializer JT808Serializer;
public JT808_0x9101Test()
{
IServiceCollection serviceDescriptors1 = new ServiceCollection();
serviceDescriptors1
.AddJT808Configure()
.AddJT1078Configure();
var ServiceProvider1 = serviceDescriptors1.BuildServiceProvider();
var defaultConfig = ServiceProvider1.GetRequiredService<IJT808Config>();
JT808Serializer = defaultConfig.GetSerializer();
}

[Fact]
public void Test1()
{
JT808_0x9101 jT808_0X9101 = new JT808_0x9101();
jT808_0X9101.ServerIp = "127.0.0.1";
jT808_0X9101.TcpPort = 1888;
jT808_0X9101.UdpPort = 0;
jT808_0X9101.ChannelNo= 1;
jT808_0X9101.DataType= 1;
jT808_0X9101.StreamType= 1;
var hex = JT808Serializer.Serialize(jT808_0X9101).ToHexString();
Assert.Equal("093132372E302E302E3107600000010101", hex);
}

[Fact]
public void Test2()
{
JT808_0x9101 jT808_0X9101= JT808Serializer.Deserialize<JT808_0x9101>("093132372E302E302E3107600000010101".ToHexBytes());
Assert.Equal("127.0.0.1", jT808_0X9101.ServerIp);
Assert.Equal(9, jT808_0X9101.ServerIpLength);
Assert.Equal(1888, jT808_0X9101.TcpPort);
Assert.Equal(0, jT808_0X9101.UdpPort);
Assert.Equal(1, jT808_0X9101.ChannelNo);
Assert.Equal(1, jT808_0X9101.DataType);
Assert.Equal(1, jT808_0X9101.StreamType);
}

[Fact]
public void Test3()
{
JT808Package jT808Package = new JT808Package();
JT808Header header = new JT808Header();
header.MsgId = 0x9101;
header.MsgNum = 1;
header.TerminalPhoneNo = "12345679810";
jT808Package.Header = header;
JT808_0x9101 jT808_0X9101 = new JT808_0x9101();
jT808_0X9101.ServerIp = "127.0.0.1";
jT808_0X9101.TcpPort = 1888;
jT808_0X9101.UdpPort = 0;
jT808_0X9101.ChannelNo = 1;
jT808_0X9101.DataType = 1;
jT808_0X9101.StreamType = 1;
jT808Package.Bodies = jT808_0X9101;
var hex = JT808Serializer.Serialize(jT808Package).ToHexString();
Assert.Equal("7E910100110123456798100001093132372E302E302E31076000000101014C7E", hex);
//7E910100110123456798100001093132372E302E302E31076000000101014C7E
}

[Fact]
public void Test4()
{
var jT808_0X9101 = JT808Serializer.Analyze<JT808_0x9101>("093132372E302E302E3107600000010101".ToHexBytes());
}

[Fact]
public void Test5()
{
JT808Package jT808Package = new JT808Package();
JT808Header header = new JT808Header();
header.MsgId = 0x9101;
header.MsgNum = 1;
header.TerminalPhoneNo = "";
jT808Package.Header = header;
JT808_0x9101 jT808_0X9101 = new JT808_0x9101();
jT808_0X9101.ServerIp = "";
jT808_0X9101.TcpPort = 1078;
jT808_0X9101.UdpPort = 0;
jT808_0X9101.ChannelNo = 3;
jT808_0X9101.DataType = 1;
jT808_0X9101.StreamType = 1;
jT808Package.Bodies = jT808_0X9101;
var hex = JT808Serializer.Serialize(jT808Package).ToHexString();
}
}
}

+ 0
- 73
src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x9102Test.cs View File

@@ -1,73 +0,0 @@
using JT808.Protocol.Extensions.JT1078.MessageBody;
using JT808.Protocol.Interfaces;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;
using Microsoft.Extensions.Logging;

namespace JT808.Protocol.Extensions.JT1078.Test
{
public class JT808_0x9102Test
{
JT808Serializer JT808Serializer;
public JT808_0x9102Test()
{
IServiceCollection serviceDescriptors1 = new ServiceCollection();
serviceDescriptors1
.AddJT808Configure()
.AddJT1078Configure();
var ServiceProvider1 = serviceDescriptors1.BuildServiceProvider();
var defaultConfig = ServiceProvider1.GetRequiredService<IJT808Config>();
JT808Serializer = defaultConfig.GetSerializer();
}

[Fact]
public void Test1()
{
JT808_0x9102 jT808_0X9102 = new JT808_0x9102();
jT808_0X9102.ChannelNo = 1;
jT808_0X9102.ControlCmd = 1;
jT808_0X9102.CloseAVData = 0;
jT808_0X9102.StreamType = 0;
var hex = JT808Serializer.Serialize(jT808_0X9102).ToHexString();
Assert.Equal("01010000", hex);
}

[Fact]
public void Test2()
{
JT808_0x9102 jT808_0X9102 = JT808Serializer.Deserialize<JT808_0x9102>("01010000".ToHexBytes());
Assert.Equal(1, jT808_0X9102.ChannelNo);
Assert.Equal(1, jT808_0X9102.ControlCmd);
Assert.Equal(0, jT808_0X9102.CloseAVData);
Assert.Equal(0, jT808_0X9102.StreamType);
}

[Fact]
public void Test3()
{
JT808Package jT808Package = new JT808Package();
JT808Header header = new JT808Header();
header.MsgId = 0x9102;
header.ManualMsgNum = 1;
header.TerminalPhoneNo = "12345679810";
jT808Package.Header = header;
JT808_0x9102 jT808_0X9102 = new JT808_0x9102();
jT808_0X9102.ChannelNo = 1;
jT808_0X9102.ControlCmd = 1;
jT808_0X9102.CloseAVData = 0;
jT808_0X9102.StreamType = 0;
jT808Package.Bodies = jT808_0X9102;
var hex = JT808Serializer.Serialize(jT808Package).ToHexString();
//7E910200040123456798100001010100001E7E
Assert.Equal("7E910200040123456798100001010100001E7E", hex);
}
[Fact]
public void Test4()
{
var jT808_0rX9102 = JT808Serializer.Analyze<JT808_0x9102>("01010000".ToHexBytes());
}
}
}

+ 0
- 62
src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x9105Test.cs View File

@@ -1,62 +0,0 @@
using JT808.Protocol.Extensions.JT1078.MessageBody;
using JT808.Protocol.Interfaces;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace JT808.Protocol.Extensions.JT1078.Test
{
public class JT808_0x9105Test
{
JT808Serializer JT808Serializer;
public JT808_0x9105Test()
{
IServiceCollection serviceDescriptors1 = new ServiceCollection();
serviceDescriptors1
.AddJT808Configure()
.AddJT1078Configure();
var ServiceProvider1 = serviceDescriptors1.BuildServiceProvider();
var defaultConfig = ServiceProvider1.GetRequiredService<IJT808Config>();
JT808Serializer = defaultConfig.GetSerializer();

Newtonsoft.Json.JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() =>
{
//日期类型默认格式化处理
return new Newtonsoft.Json.JsonSerializerSettings
{
DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat,
DateFormatString = "yyyy-MM-dd HH:mm:ss"
};
});
}

[Fact]
public void Test1()
{
JT808_0x9105 jT808_0x9105 = new JT808_0x9105()
{
ChannelNo=1,
DropRate=2
};
var hex = JT808Serializer.Serialize(jT808_0x9105).ToHexString();
Assert.Equal("0102", hex);
}

[Fact]
public void Test2()
{
var jT808_0x9105 = JT808Serializer.Deserialize<JT808_0x9105>("0102".ToHexBytes());
Assert.Equal(1, jT808_0x9105.ChannelNo);
Assert.Equal(2, jT808_0x9105.DropRate);
}
[Fact]
public void Test3()
{
var jT808_0x9105 = JT808Serializer.Analyze<JT808_0x9105>("0102".ToHexBytes());
}
}
}

+ 0
- 82
src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x9201Test.cs View File

@@ -1,82 +0,0 @@
using JT808.Protocol.Extensions.JT1078.MessageBody;
using JT808.Protocol.Interfaces;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace JT808.Protocol.Extensions.JT1078.Test
{
public class JT808_0x9201Test
{
JT808Serializer JT808Serializer;
public JT808_0x9201Test()
{
IServiceCollection serviceDescriptors1 = new ServiceCollection();
serviceDescriptors1
.AddJT808Configure()
.AddJT1078Configure();
var ServiceProvider1 = serviceDescriptors1.BuildServiceProvider();
var defaultConfig = ServiceProvider1.GetRequiredService<IJT808Config>();
JT808Serializer = defaultConfig.GetSerializer();

Newtonsoft.Json.JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() =>
{
//日期类型默认格式化处理
return new Newtonsoft.Json.JsonSerializerSettings
{
DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat,
DateFormatString = "yyyy-MM-dd HH:mm:ss"
};
});
}

[Fact]
public void Test1()
{
JT808_0x9201 jT808_0x9201 = new JT808_0x9201()
{
ChannelNo = 1,
MediaType = 2,
BeginTime = Convert.ToDateTime("2019-07-16 10:10:10"),
EndTime = Convert.ToDateTime("2019-07-16 10:10:10"),
PlaySpeed=3,
MemoryType=5,
PlaybackWay=6,
ServerIp="127.0.0.1",
ServerIpLength=9,
StreamType=7,
TcpPort=80,
UdpPort=8080
};
var hex = JT808Serializer.Serialize(jT808_0x9201).ToHexString();
Assert.Equal("093132372E302E302E3100501F90010207050603190716101010190716101010", hex);
}

[Fact]
public void Test2()
{
var jT808_0x9201 = JT808Serializer.Deserialize<JT808_0x9201>("093132372E302E302E3100501F90010207050603190716101010190716101010".ToHexBytes());
Assert.Equal(1, jT808_0x9201.ChannelNo);
Assert.Equal(2, jT808_0x9201.MediaType);
Assert.Equal(Convert.ToDateTime("2019-07-16 10:10:10"), jT808_0x9201.BeginTime);
Assert.Equal(Convert.ToDateTime("2019-07-16 10:10:10"), jT808_0x9201.EndTime);
Assert.Equal(3, jT808_0x9201.PlaySpeed);
Assert.Equal(5, jT808_0x9201.MemoryType);
Assert.Equal(6, jT808_0x9201.PlaybackWay);
Assert.Equal("127.0.0.1", jT808_0x9201.ServerIp);
Assert.Equal(9, jT808_0x9201.ServerIpLength);
Assert.Equal(7, jT808_0x9201.StreamType);
Assert.Equal(80, jT808_0x9201.TcpPort);
Assert.Equal(8080, jT808_0x9201.UdpPort);
}
[Fact]
public void Test3()
{
var jT808_0x9201 = JT808Serializer.Analyze<JT808_0x9201>("093132372E302E302E3100501F90010207050603190716101010190716101010".ToHexBytes());
}
}
}

+ 0
- 66
src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x9202Test.cs View File

@@ -1,66 +0,0 @@
using JT808.Protocol.Extensions.JT1078.MessageBody;
using JT808.Protocol.Interfaces;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace JT808.Protocol.Extensions.JT1078.Test
{
public class JT808_0x9202Test
{
JT808Serializer JT808Serializer;
public JT808_0x9202Test()
{
IServiceCollection serviceDescriptors1 = new ServiceCollection();
serviceDescriptors1
.AddJT808Configure()
.AddJT1078Configure();
var ServiceProvider1 = serviceDescriptors1.BuildServiceProvider();
var defaultConfig = ServiceProvider1.GetRequiredService<IJT808Config>();
JT808Serializer = defaultConfig.GetSerializer();

Newtonsoft.Json.JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() =>
{
//日期类型默认格式化处理
return new Newtonsoft.Json.JsonSerializerSettings
{
DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat,
DateFormatString = "yyyy-MM-dd HH:mm:ss"
};
});
}

[Fact]
public void Test1()
{
JT808_0x9202 jT808_0x9202 = new JT808_0x9202()
{
ChannelNo=1,
DragPlayPosition=Convert.ToDateTime("2019-07-16 10:10:10"),
PlaySpeed=2,
PlayControl=3
};
var hex = JT808Serializer.Serialize(jT808_0x9202).ToHexString();
Assert.Equal("010302190716101010", hex);
}

[Fact]
public void Test2()
{
var jT808_0x9202 = JT808Serializer.Deserialize<JT808_0x9202>("010302190716101010".ToHexBytes());
Assert.Equal(1, jT808_0x9202.ChannelNo);
Assert.Equal(Convert.ToDateTime("2019-07-16 10:10:10"), jT808_0x9202.DragPlayPosition);
Assert.Equal(2, jT808_0x9202.PlaySpeed);
Assert.Equal(3, jT808_0x9202.PlayControl);
}
[Fact]
public void Test3()
{
var jT808_0x9202 = JT808Serializer.Analyze<JT808_0x9202>("010302190716101010".ToHexBytes());
}
}
}

+ 0
- 72
src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x9205Test.cs View File

@@ -1,72 +0,0 @@
using JT808.Protocol.Extensions.JT1078.MessageBody;
using JT808.Protocol.Interfaces;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace JT808.Protocol.Extensions.JT1078.Test
{
public class JT808_0x9205Test
{
JT808Serializer JT808Serializer;
public JT808_0x9205Test()
{
IServiceCollection serviceDescriptors1 = new ServiceCollection();
serviceDescriptors1
.AddJT808Configure()
.AddJT1078Configure();
var ServiceProvider1 = serviceDescriptors1.BuildServiceProvider();
var defaultConfig = ServiceProvider1.GetRequiredService<IJT808Config>();
JT808Serializer = defaultConfig.GetSerializer();

Newtonsoft.Json.JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() =>
{
//日期类型默认格式化处理
return new Newtonsoft.Json.JsonSerializerSettings
{
DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat,
DateFormatString = "yyyy-MM-dd HH:mm:ss"
};
});
}

[Fact]
public void Test1()
{
JT808_0x9205 jT808_0x9205 = new JT808_0x9205()
{
AlarmFlag=1,
MediaType=2,
BeginTime= Convert.ToDateTime("2019-07-16 10:10:10"),
EndTime= Convert.ToDateTime("2019-07-16 10:10:11"),
ChannelNo=3,
MemoryType=4,
StreamType =5
};
var hex = JT808Serializer.Serialize(jT808_0x9205).ToHexString();
Assert.Equal("031907161010101907161010110000000000000001020504", hex);
}

[Fact]
public void Test2()
{
var jT808_0x9205 = JT808Serializer.Deserialize<JT808_0x9205>("031907161010101907161010110000000000000001020504".ToHexBytes());
Assert.Equal(1u, jT808_0x9205.AlarmFlag);
Assert.Equal(2, jT808_0x9205.MediaType);
Assert.Equal(Convert.ToDateTime("2019-07-16 10:10:10"), jT808_0x9205.BeginTime);
Assert.Equal(Convert.ToDateTime("2019-07-16 10:10:11"), jT808_0x9205.EndTime);
Assert.Equal(3, jT808_0x9205.ChannelNo);
Assert.Equal(4, jT808_0x9205.MemoryType);
Assert.Equal(5, jT808_0x9205.StreamType);
}
[Fact]
public void Test3()
{
var jT808_0x9205 = JT808Serializer.Analyze<JT808_0x9205>("031907161010101907161010110000000000000001020504".ToHexBytes());
}
}
}

+ 0
- 92
src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x9206Test.cs View File

@@ -1,92 +0,0 @@
using JT808.Protocol.Extensions.JT1078.MessageBody;
using JT808.Protocol.Interfaces;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace JT808.Protocol.Extensions.JT1078.Test
{
public class JT808_0x9206Test
{
JT808Serializer JT808Serializer;
public JT808_0x9206Test()
{
IServiceCollection serviceDescriptors1 = new ServiceCollection();
serviceDescriptors1
.AddJT808Configure()
.AddJT1078Configure();
var ServiceProvider1 = serviceDescriptors1.BuildServiceProvider();
var defaultConfig = ServiceProvider1.GetRequiredService<IJT808Config>();
JT808Serializer = defaultConfig.GetSerializer();

Newtonsoft.Json.JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() =>
{
//日期类型默认格式化处理
return new Newtonsoft.Json.JsonSerializerSettings
{
DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat,
DateFormatString = "yyyy-MM-dd HH:mm:ss"
};
});
}

[Fact]
public void Test1()
{
JT808_0x9206 jT808_0x9206 = new JT808_0x9206()
{
AlarmFlag=1,
MediaType=2,
BeginTime= Convert.ToDateTime("2019-07-16 10:10:10"),
EndTime= Convert.ToDateTime("2019-07-16 10:10:11"),
ChannelNo=3,
StreamType =5,
FileUploadPath ="D://1112",
FileUploadPathLength=8,
MemoryPositon=4,
Password="123456",
PasswordLength=6,
Port=808,
ServerIp="127.0.0.1",
ServerIpLength=9,
TaskExcuteCondition=7,
UserName="tk",
UserNameLength=2
};
var hex = JT808Serializer.Serialize(jT808_0x9206).ToHexString();
Assert.Equal("093132372E302E302E31032802746B0631323334353608443A2F2F31313132031907161010101907161010110000000102050407", hex);
}

[Fact]
public void Test2()
{
var jT808_0x9206 = JT808Serializer.Deserialize<JT808_0x9206>("093132372E302E302E31032802746B0631323334353608443A2F2F31313132031907161010101907161010110000000102050407".ToHexBytes());
Assert.Equal(1u, jT808_0x9206.AlarmFlag);
Assert.Equal(2, jT808_0x9206.MediaType);
Assert.Equal(Convert.ToDateTime("2019-07-16 10:10:10"), jT808_0x9206.BeginTime);
Assert.Equal(Convert.ToDateTime("2019-07-16 10:10:11"), jT808_0x9206.EndTime);
Assert.Equal(3, jT808_0x9206.ChannelNo);
Assert.Equal(5, jT808_0x9206.StreamType);
Assert.Equal("D://1112", jT808_0x9206.FileUploadPath);
Assert.Equal(8, jT808_0x9206.FileUploadPathLength);
Assert.Equal(4, jT808_0x9206.MemoryPositon);
Assert.Equal("123456", jT808_0x9206.Password);
Assert.Equal(6, jT808_0x9206.PasswordLength);
Assert.Equal(808, jT808_0x9206.Port);
Assert.Equal("127.0.0.1", jT808_0x9206.ServerIp);
Assert.Equal(9, jT808_0x9206.ServerIpLength);
Assert.Equal(7, jT808_0x9206.TaskExcuteCondition);
Assert.Equal("tk", jT808_0x9206.UserName);
Assert.Equal(2, jT808_0x9206.UserNameLength);
}
[Fact]
public void Test3()
{
var jT808_0x9206 = JT808Serializer.Analyze<JT808_0x9206>("093132372E302E302E31032802746B0631323334353608443A2F2F31313132031907161010101907161010110000000102050407".ToHexBytes());
}
}
}

+ 0
- 62
src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x9207Test.cs View File

@@ -1,62 +0,0 @@
using JT808.Protocol.Extensions.JT1078.MessageBody;
using JT808.Protocol.Interfaces;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace JT808.Protocol.Extensions.JT1078.Test
{
public class JT808_0x9207Test
{
JT808Serializer JT808Serializer;
public JT808_0x9207Test()
{
IServiceCollection serviceDescriptors1 = new ServiceCollection();
serviceDescriptors1
.AddJT808Configure()
.AddJT1078Configure();
var ServiceProvider1 = serviceDescriptors1.BuildServiceProvider();
var defaultConfig = ServiceProvider1.GetRequiredService<IJT808Config>();
JT808Serializer = defaultConfig.GetSerializer();

Newtonsoft.Json.JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() =>
{
//日期类型默认格式化处理
return new Newtonsoft.Json.JsonSerializerSettings
{
DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat,
DateFormatString = "yyyy-MM-dd HH:mm:ss"
};
});
}

[Fact]
public void Test1()
{
JT808_0x9207 jT808_0x9207 = new JT808_0x9207()
{
MgsNum=1,
UploadControl=2
};
var hex = JT808Serializer.Serialize(jT808_0x9207).ToHexString();
Assert.Equal("000102", hex);
}

[Fact]
public void Test2()
{
var jT808_0x9207 = JT808Serializer.Deserialize<JT808_0x9207>("000102".ToHexBytes());
Assert.Equal(1, jT808_0x9207.MgsNum);
Assert.Equal(2, jT808_0x9207.UploadControl);
}
[Fact]
public void Test3()
{
var jT808_0x9207 = JT808Serializer.Analyze<JT808_0x9207>("000102".ToHexBytes());
}
}
}

+ 0
- 65
src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x9301Test.cs View File

@@ -1,65 +0,0 @@
using JT808.Protocol.Extensions.JT1078.MessageBody;
using JT808.Protocol.Interfaces;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace JT808.Protocol.Extensions.JT1078.Test
{
public class JT808_0x9301Test
{
JT808Serializer JT808Serializer;
public JT808_0x9301Test()
{
IServiceCollection serviceDescriptors1 = new ServiceCollection();
serviceDescriptors1
.AddJT808Configure()
.AddJT1078Configure();
var ServiceProvider1 = serviceDescriptors1.BuildServiceProvider();
var defaultConfig = ServiceProvider1.GetRequiredService<IJT808Config>();
JT808Serializer = defaultConfig.GetSerializer();

Newtonsoft.Json.JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() =>
{
//日期类型默认格式化处理
return new Newtonsoft.Json.JsonSerializerSettings
{
DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat,
DateFormatString = "yyyy-MM-dd HH:mm:ss"
};
});
}

[Fact]
public void Test1()
{
JT808_0x9301 jT808_0x9301 = new JT808_0x9301()
{
ChannelNo=1,
Speed=2,
Direction=3
};
var hex = JT808Serializer.Serialize(jT808_0x9301).ToHexString();
Assert.Equal("010302", hex);
}

[Fact]
public void Test2()
{
var jT808_0x9301 = JT808Serializer.Deserialize<JT808_0x9301>("010302".ToHexBytes());
Assert.Equal(1, jT808_0x9301.ChannelNo);
Assert.Equal(2, jT808_0x9301.Speed);
Assert.Equal(3, jT808_0x9301.Direction);
}
[Fact]
public void Test3()
{
var jT808_0x9301 = JT808Serializer.Analyze<JT808_0x9301>("010302".ToHexBytes());

}
}
}

+ 0
- 63
src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x9302Test.cs View File

@@ -1,63 +0,0 @@
using JT808.Protocol.Extensions.JT1078.MessageBody;
using JT808.Protocol.Interfaces;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace JT808.Protocol.Extensions.JT1078.Test
{
public class JT808_0x9302Test
{
JT808Serializer JT808Serializer;
public JT808_0x9302Test()
{
IServiceCollection serviceDescriptors1 = new ServiceCollection();
serviceDescriptors1
.AddJT808Configure()
.AddJT1078Configure();
var ServiceProvider1 = serviceDescriptors1.BuildServiceProvider();
var defaultConfig = ServiceProvider1.GetRequiredService<IJT808Config>();
JT808Serializer = defaultConfig.GetSerializer();

Newtonsoft.Json.JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() =>
{
//日期类型默认格式化处理
return new Newtonsoft.Json.JsonSerializerSettings
{
DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat,
DateFormatString = "yyyy-MM-dd HH:mm:ss"
};
});
}

[Fact]
public void Test1()
{
JT808_0x9302 jT808_0x9302 = new JT808_0x9302()
{
LogicChannelNo=1,
FocusAdjustmentDirection=2
};
var hex = JT808Serializer.Serialize(jT808_0x9302).ToHexString();
Assert.Equal("0102", hex);
}

[Fact]
public void Test2()
{
var jT808_0x9302 = JT808Serializer.Deserialize<JT808_0x9302>("0102".ToHexBytes());
Assert.Equal(1, jT808_0x9302.LogicChannelNo);
Assert.Equal(2, jT808_0x9302.FocusAdjustmentDirection);
}
[Fact]
public void Test3()
{
var jT808_0x9302 = JT808Serializer.Analyze<JT808_0x9302>("0102".ToHexBytes());

}
}
}

+ 0
- 63
src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x9303Test.cs View File

@@ -1,63 +0,0 @@
using JT808.Protocol.Extensions.JT1078.MessageBody;
using JT808.Protocol.Interfaces;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace JT808.Protocol.Extensions.JT1078.Test
{
public class JT808_0x9303Test
{
JT808Serializer JT808Serializer;
public JT808_0x9303Test()
{
IServiceCollection serviceDescriptors1 = new ServiceCollection();
serviceDescriptors1
.AddJT808Configure()
.AddJT1078Configure();
var ServiceProvider1 = serviceDescriptors1.BuildServiceProvider();
var defaultConfig = ServiceProvider1.GetRequiredService<IJT808Config>();
JT808Serializer = defaultConfig.GetSerializer();

Newtonsoft.Json.JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() =>
{
//日期类型默认格式化处理
return new Newtonsoft.Json.JsonSerializerSettings
{
DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat,
DateFormatString = "yyyy-MM-dd HH:mm:ss"
};
});
}

[Fact]
public void Test1()
{
JT808_0x9303 jT808_0x9303 = new JT808_0x9303()
{
ChannelNo=1,
IrisAdjustment=2
};
var hex = JT808Serializer.Serialize(jT808_0x9303).ToHexString();
Assert.Equal("0102", hex);
}

[Fact]
public void Test2()
{
var jT808_0x9303 = JT808Serializer.Deserialize<JT808_0x9303>("0102".ToHexBytes());
Assert.Equal(1, jT808_0x9303.ChannelNo);
Assert.Equal(2, jT808_0x9303.IrisAdjustment);
}
[Fact]
public void Test3()
{
var jT808_0x9303 = JT808Serializer.Analyze<JT808_0x9303>("0102".ToHexBytes());

}
}
}

+ 0
- 63
src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x9304Test.cs View File

@@ -1,63 +0,0 @@
using JT808.Protocol.Extensions.JT1078.MessageBody;
using JT808.Protocol.Interfaces;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace JT808.Protocol.Extensions.JT1078.Test
{
public class JT808_0x9304Test
{
JT808Serializer JT808Serializer;
public JT808_0x9304Test()
{
IServiceCollection serviceDescriptors1 = new ServiceCollection();
serviceDescriptors1
.AddJT808Configure()
.AddJT1078Configure();
var ServiceProvider1 = serviceDescriptors1.BuildServiceProvider();
var defaultConfig = ServiceProvider1.GetRequiredService<IJT808Config>();
JT808Serializer = defaultConfig.GetSerializer();

Newtonsoft.Json.JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() =>
{
//日期类型默认格式化处理
return new Newtonsoft.Json.JsonSerializerSettings
{
DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat,
DateFormatString = "yyyy-MM-dd HH:mm:ss"
};
});
}

[Fact]
public void Test1()
{
JT808_0x9304 jT808_0x9304 = new JT808_0x9304()
{
ChannelNo=1,
StartOrStop=2
};
var hex = JT808Serializer.Serialize(jT808_0x9304).ToHexString();
Assert.Equal("0102", hex);
}

[Fact]
public void Test2()
{
var jT808_0x9304 = JT808Serializer.Deserialize<JT808_0x9304>("0102".ToHexBytes());
Assert.Equal(1, jT808_0x9304.ChannelNo);
Assert.Equal(2, jT808_0x9304.StartOrStop);
}
[Fact]
public void Test3()
{
var jT808_0x9304 = JT808Serializer.Analyze<JT808_0x9304>("0102".ToHexBytes());

}
}
}

+ 0
- 56
src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x9305Test.cs View File

@@ -1,56 +0,0 @@
using JT808.Protocol.Extensions.JT1078.MessageBody;
using JT808.Protocol.Interfaces;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace JT808.Protocol.Extensions.JT1078.Test
{
public class JT808_0x9305Test
{
JT808Serializer JT808Serializer;
public JT808_0x9305Test()
{
IServiceCollection serviceDescriptors1 = new ServiceCollection();
serviceDescriptors1
.AddJT808Configure()
.AddJT1078Configure();
var ServiceProvider1 = serviceDescriptors1.BuildServiceProvider();
var defaultConfig = ServiceProvider1.GetRequiredService<IJT808Config>();
JT808Serializer = defaultConfig.GetSerializer();

Newtonsoft.Json.JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() =>
{
//日期类型默认格式化处理
return new Newtonsoft.Json.JsonSerializerSettings
{
DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat,
DateFormatString = "yyyy-MM-dd HH:mm:ss"
};
});
}

[Fact]
public void Test1()
{
JT808_0x9305 jT808_0x9305 = new JT808_0x9305()
{
ChannelNo=1,
StartOrStop=2
};
var hex = JT808Serializer.Serialize(jT808_0x9305).ToHexString();
Assert.Equal("0102", hex);
}

[Fact]
public void Test2()
{
var jT808_0x9305 = JT808Serializer.Analyze<JT808_0x9305>("0102".ToHexBytes());

}
}
}

+ 0
- 63
src/JT808.Protocol.Extensions.JT1078.Test/JT808_0x9306Test.cs View File

@@ -1,63 +0,0 @@
using JT808.Protocol.Extensions.JT1078.MessageBody;
using JT808.Protocol.Interfaces;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace JT808.Protocol.Extensions.JT1078.Test
{
public class JT808_0x9306Test
{
JT808Serializer JT808Serializer;
public JT808_0x9306Test()
{
IServiceCollection serviceDescriptors1 = new ServiceCollection();
serviceDescriptors1
.AddJT808Configure()
.AddJT1078Configure();
var ServiceProvider1 = serviceDescriptors1.BuildServiceProvider();
var defaultConfig = ServiceProvider1.GetRequiredService<IJT808Config>();
JT808Serializer = defaultConfig.GetSerializer();

Newtonsoft.Json.JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() =>
{
//日期类型默认格式化处理
return new Newtonsoft.Json.JsonSerializerSettings
{
DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat,
DateFormatString = "yyyy-MM-dd HH:mm:ss"
};
});
}

[Fact]
public void Test1()
{
JT808_0x9306 jT808_0x9306 = new JT808_0x9306()
{
ChannelNo=1,
ChangeMultipleControl=2
};
var hex = JT808Serializer.Serialize(jT808_0x9306).ToHexString();
Assert.Equal("0102", hex);
}

[Fact]
public void Test2()
{
var jT808_0x9306 = JT808Serializer.Deserialize<JT808_0x9306>("0102".ToHexBytes());
Assert.Equal(1, jT808_0x9306.ChannelNo);
Assert.Equal(2, jT808_0x9306.ChangeMultipleControl);
}
[Fact]
public void Test3()
{
var jT808_0x9306 = JT808Serializer.Analyze<JT808_0x9306>("0102".ToHexBytes());

}
}
}

+ 0
- 20
src/JT808.Protocol.Extensions.JT1078/DependencyInjectionExtensions.cs View File

@@ -1,20 +0,0 @@
using JT808.Protocol.Extensions.JT1078.Enums;
using JT808.Protocol.Extensions.JT1078.MessageBody;
using JT808.Protocol.Interfaces;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

namespace JT808.Protocol.Extensions.JT1078
{
public static class DependencyInjectionExtensions
{
public static IJT808Builder AddJT1078Configure(this IJT808Builder jT808Builder)
{
jT808Builder.Config.Register(Assembly.GetExecutingAssembly());
return jT808Builder;
}
}
}

+ 0
- 28
src/JT808.Protocol.Extensions.JT1078/Enums/JT808_JT1078_MsgId.cs View File

@@ -1,28 +0,0 @@
namespace JT808.Protocol.Extensions.JT1078.Enums
{
#pragma warning disable CS1591 // 缺少对公共可见类型或成员的 XML 注释
public enum JT808_JT1078_MsgId:ushort

{
终端上传音视频属性 = 0x1003,
终端上传乘客流量 = 0x1005,
终端上传音视频资源列表 = 0x1205,
文件上传完成通知 = 0x1206,
查询终端音视频属性 = 0x9003,
实时音视频传输请求 = 0x9101,
音视频实时传输控制 = 0x9102,
实时音视频传输状态通知 = 0x9105,
平台下发远程录像回放请求 = 0x9201,
平台下发远程录像回放控制 = 0x9202,
查询资源列表 = 0x9205,
文件上传指令 = 0x9206,
文件上传控制 = 0x9207,
云台旋转 = 0x9301,
云台调整焦距控制 = 0x9302,
云台调整光圈控制 = 0x9303,
云台雨刷控制 = 0x9304,
红外补光控制 = 0x9305,
云台变倍控制 = 0x9306
}
#pragma warning restore CS1591 // 缺少对公共可见类型或成员的 XML 注释
}

+ 0
- 18
src/JT808.Protocol.Extensions.JT1078/Enums/VideoRelateAlarmType.cs View File

@@ -1,18 +0,0 @@
using System;

namespace JT808.Protocol.Extensions.JT1078.Enums
{
[Flags]
#pragma warning disable CS1591 // 缺少对公共可见类型或成员的 XML 注释
public enum VideoRelateAlarmType:uint
{
视频信号丢失报警=0,
视频信号遮挡报警=2,
存储单元故障报警=4,
其他视频设备故障报警=8,
客车超员报警=16,
异常驾驶行为报警=32,
特殊报警录像达到存储阈值报警=64,
}
#pragma warning restore CS1591 // 缺少对公共可见类型或成员的 XML 注释
}

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

@@ -1,35 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net5.0;</TargetFrameworks>
<LangVersion>8.0</LangVersion>
<Copyright>Copyright 2019.</Copyright>
<Authors>SmallChi(Koike)</Authors>
<PackageId>JT808.Protocol.Extensions.JT1078</PackageId>
<Product>JT808.Protocol.Extensions.JT1078</Product>
<Description>基于JT808协议、GB808协议扩展的视频消息协议</Description>
<PackageReleaseNotes>基于JT808协议、GB808协议扩展的视频消息协议</PackageReleaseNotes>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<RepositoryUrl>https://github.com/SmallChi/JT1078</RepositoryUrl>
<PackageProjectUrl>https://github.com/SmallChi/JT1078</PackageProjectUrl>
<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.5</Version>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<DocumentationFile>JT808.Protocol.Extensions.JT1078.xml</DocumentationFile>
</PropertyGroup>

<ItemGroup>
<None Include="..\..\LICENSE">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
</ItemGroup>

<ItemGroup>
<PackageReference Include="JT808" Version="2.3.6" />
</ItemGroup>


</Project>

+ 0
- 1289
src/JT808.Protocol.Extensions.JT1078/JT808.Protocol.Extensions.JT1078.xml
File diff suppressed because it is too large
View File


+ 0
- 59
src/JT808.Protocol.Extensions.JT1078/JT808_JT1078_Constants.cs View File

@@ -1,59 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace JT808.Protocol.Extensions.JT1078
{
public static class JT808_JT1078_Constants
{
/// <summary>
/// 视频相关报警
/// </summary>
public const byte JT808_0X0200_0x14 = 0x14;
/// <summary>
/// 视频信号丢失报警状态
/// </summary>
public const byte JT808_0X0200_0x15 = 0x15;
/// <summary>
/// 视频信号遮挡报警状态
/// </summary>
public const byte JT808_0X0200_0x16 = 0x16;
/// <summary>
/// 存储器故障报警状态
/// </summary>
public const byte JT808_0X0200_0x17 = 0x17;
/// <summary>
/// 异常驾驶行为报警详细描述
/// </summary>
public const byte JT808_0X0200_0x18 = 0x18;

/// <summary>
/// 音视频参数设置
/// </summary>
public const uint JT808_0X8103_0x0075 = 0x0075;
/// <summary>
/// 音视频通道列表设置
/// </summary>
public const uint JT808_0X8103_0x0076 = 0x0076;
/// <summary>
/// 单独视频通道参数设置
/// </summary>
public const uint JT808_0X8103_0x0077 = 0x0077;
/// <summary>
/// 特殊报警录像参数设置
/// </summary>
public const uint JT808_0X8103_0x0079 = 0x0079;
/// <summary>
/// 视频相关报警屏蔽字
/// </summary>
public const uint JT808_0X8103_0x007A = 0x007A;
/// <summary>
/// 图像分析报警参数设置
/// </summary>
public const uint JT808_0X8103_0x007B = 0x007B;
/// <summary>
/// 终端休眠模式唤醒设置
/// </summary>
public const uint JT808_0X8103_0x007C = 0x007C;
}
}

+ 0
- 65
src/JT808.Protocol.Extensions.JT1078/MessageBody/JT808_0x0200_0x14.cs View File

@@ -1,65 +0,0 @@
using JT808.Protocol.Formatters;
using JT808.Protocol.MessageBody;
using JT808.Protocol.MessagePack;
using JT808.Protocol.Interfaces;
using System.Text.Json;
using JT808.Protocol.Extensions.JT1078.Enums;
using System.Linq;

namespace JT808.Protocol.Extensions.JT1078.MessageBody
{
/// <summary>
/// 视频相关报警
/// 0x0200_0x14
/// </summary>
public class JT808_0x0200_0x14 : JT808_0x0200_BodyBase, IJT808MessagePackFormatter<JT808_0x0200_0x14>,IJT808Analyze
{
public override byte AttachInfoId { get; set; } = 0x14;
/// <summary>
/// 数据 长度
/// </summary>
public override byte AttachInfoLength { get; set; } = 4;
/// <summary>
/// 视频相关报警
/// <see cref="JT808.Protocol.Extensions.JT1078.Enums.VideoRelateAlarmType"/>
/// </summary>
public uint VideoRelateAlarm { get; set; }

public void Analyze(ref JT808MessagePackReader reader, Utf8JsonWriter writer, IJT808Config config)
{
JT808_0x0200_0x14 value = new JT808_0x0200_0x14();
value.AttachInfoId = reader.ReadByte();
writer.WriteNumber($"[{value.AttachInfoId.ReadNumber()}]附加信息Id", value.AttachInfoId);
value.AttachInfoLength = reader.ReadByte();
writer.WriteNumber($"[{value.AttachInfoLength.ReadNumber()}]附加信息长度", value.AttachInfoLength);
value.VideoRelateAlarm = reader.ReadUInt32();
writer.WriteNumber($"[{value.VideoRelateAlarm.ReadNumber()}]视频相关报警", value.VideoRelateAlarm);
var videoRelateAlarmFlags = JT808EnumExtensions.GetEnumTypes<VideoRelateAlarmType>(value.VideoRelateAlarm, 32);
if (videoRelateAlarmFlags.Any())
{
writer.WriteStartArray("视频报警集合");
foreach (var item in videoRelateAlarmFlags)
{
writer.WriteStringValue(item.ToString());
}
writer.WriteEndArray();
}
}

public JT808_0x0200_0x14 Deserialize(ref JT808MessagePackReader reader, IJT808Config config)
{
JT808_0x0200_0x14 value = new JT808_0x0200_0x14();
value.AttachInfoId = reader.ReadByte();
value.AttachInfoLength = reader.ReadByte();
value.VideoRelateAlarm = reader.ReadUInt32();
return value;
}

public void Serialize(ref JT808MessagePackWriter writer, JT808_0x0200_0x14 value, IJT808Config config)
{
writer.WriteByte(value.AttachInfoId);
writer.WriteByte(value.AttachInfoLength);
writer.WriteUInt32(value.VideoRelateAlarm);
}
}
}

+ 0
- 69
src/JT808.Protocol.Extensions.JT1078/MessageBody/JT808_0x0200_0x15.cs View File

@@ -1,69 +0,0 @@
using JT808.Protocol.Formatters;
using JT808.Protocol.Interfaces;
using JT808.Protocol.MessageBody;
using JT808.Protocol.MessagePack;
using System;
using System.Text.Json;

namespace JT808.Protocol.Extensions.JT1078.MessageBody
{
/// <summary>
/// 视频信号丢失报警状态
/// 0x0200_0x15
/// </summary>
public class JT808_0x0200_0x15 : JT808_0x0200_BodyBase, IJT808MessagePackFormatter<JT808_0x0200_0x15>, IJT808Analyze
{
public override byte AttachInfoId { get; set; } = 0x15;
/// <summary>
/// 数据 长度
/// </summary>
public override byte AttachInfoLength { get; set; } = 4;
/// <summary>
/// 视频信号丢失报警状态
/// </summary>
public uint VideoSignalLoseAlarmStatus { get; set; }

public void Analyze(ref JT808MessagePackReader reader, Utf8JsonWriter writer, IJT808Config config)
{
JT808_0x0200_0x15 value = new JT808_0x0200_0x15();
value.AttachInfoId = reader.ReadByte();
writer.WriteNumber($"[{value.AttachInfoId.ReadNumber()}]附加信息Id", value.AttachInfoId);
value.AttachInfoLength = reader.ReadByte();
writer.WriteNumber($"[{value.AttachInfoLength.ReadNumber()}]附加信息长度", value.AttachInfoLength);
value.VideoSignalLoseAlarmStatus = reader.ReadUInt32();
writer.WriteNumber($"[{value.VideoSignalLoseAlarmStatus.ReadNumber()}]视频信号丢失报警状态", value.VideoSignalLoseAlarmStatus);
var videoSignalLoseAlarmStatusSpan = Convert.ToString(value.VideoSignalLoseAlarmStatus, 2).PadLeft(32, '0').AsSpan();
writer.WriteStartArray("视频信号丢失报警状态集合");
int index = 0;
foreach (var item in videoSignalLoseAlarmStatusSpan)
{
if (item == '1')
{
writer.WriteStringValue($"{index}通道视频信号丢失");
}
else
{
writer.WriteStringValue($"{index}通道视频正常");
}
index++;
}
writer.WriteEndArray();
}

public JT808_0x0200_0x15 Deserialize(ref JT808MessagePackReader reader, IJT808Config config)
{
JT808_0x0200_0x15 value = new JT808_0x0200_0x15();
value.AttachInfoId = reader.ReadByte();
value.AttachInfoLength = reader.ReadByte();
value.VideoSignalLoseAlarmStatus = reader.ReadUInt32();
return value;
}

public void Serialize(ref JT808MessagePackWriter writer, JT808_0x0200_0x15 value, IJT808Config config)
{
writer.WriteByte(value.AttachInfoId);
writer.WriteByte(value.AttachInfoLength);
writer.WriteUInt32(value.VideoSignalLoseAlarmStatus);
}
}
}

+ 0
- 69
src/JT808.Protocol.Extensions.JT1078/MessageBody/JT808_0x0200_0x16.cs View File

@@ -1,69 +0,0 @@
using JT808.Protocol.Formatters;
using JT808.Protocol.Interfaces;
using JT808.Protocol.MessageBody;
using JT808.Protocol.MessagePack;
using System;
using System.Text.Json;

namespace JT808.Protocol.Extensions.JT1078.MessageBody
{
/// <summary>
/// 视频信号遮挡报警状态
/// 0x0200_0x16
/// </summary>
public class JT808_0x0200_0x16 : JT808_0x0200_BodyBase, IJT808MessagePackFormatter<JT808_0x0200_0x16>, IJT808Analyze
{
public override byte AttachInfoId { get; set; } = 0x16;
/// <summary>
/// 数据 长度
/// </summary>
public override byte AttachInfoLength { get; set; } = 4;
/// <summary>
/// 视频信号遮挡报警状态
/// </summary>
public uint VideoSignalOcclusionAlarmStatus { get; set; }

public void Analyze(ref JT808MessagePackReader reader, Utf8JsonWriter writer, IJT808Config config)
{
JT808_0x0200_0x16 value = new JT808_0x0200_0x16();
value.AttachInfoId = reader.ReadByte();
writer.WriteNumber($"[{value.AttachInfoId.ReadNumber()}]附加信息Id", value.AttachInfoId);
value.AttachInfoLength = reader.ReadByte();
writer.WriteNumber($"[{value.AttachInfoLength.ReadNumber()}]附加信息长度", value.AttachInfoLength);
value.VideoSignalOcclusionAlarmStatus = reader.ReadUInt32();
writer.WriteNumber($"[{value.VideoSignalOcclusionAlarmStatus.ReadNumber()}]视频信号遮挡报警状态", value.VideoSignalOcclusionAlarmStatus);
var videoSignalOcclusionAlarmStatusSpan = Convert.ToString(value.VideoSignalOcclusionAlarmStatus, 2).PadLeft(32, '0').AsSpan();
writer.WriteStartArray("视频信号遮挡报警状态集合");
int index = 0;
foreach (var item in videoSignalOcclusionAlarmStatusSpan)
{
if (item == '1')
{
writer.WriteStringValue($"{index}通道视频信号遮挡");
}
else
{
writer.WriteStringValue($"{index}通道视频正常");
}
index++;
}
writer.WriteEndArray();
}

public JT808_0x0200_0x16 Deserialize(ref JT808MessagePackReader reader, IJT808Config config)
{
JT808_0x0200_0x16 value = new JT808_0x0200_0x16();
value.AttachInfoId = reader.ReadByte();
value.AttachInfoLength = reader.ReadByte();
value.VideoSignalOcclusionAlarmStatus = reader.ReadUInt32();
return value;
}

public void Serialize(ref JT808MessagePackWriter writer, JT808_0x0200_0x16 value, IJT808Config config)
{
writer.WriteByte(value.AttachInfoId);
writer.WriteByte(value.AttachInfoLength);
writer.WriteUInt32(value.VideoSignalOcclusionAlarmStatus);
}
}
}

+ 0
- 83
src/JT808.Protocol.Extensions.JT1078/MessageBody/JT808_0x0200_0x17.cs View File

@@ -1,83 +0,0 @@
using JT808.Protocol.Formatters;
using JT808.Protocol.Interfaces;
using JT808.Protocol.MessageBody;
using JT808.Protocol.MessagePack;
using System;
using System.Text.Json;

namespace JT808.Protocol.Extensions.JT1078.MessageBody
{
/// <summary>
/// 存储器故障报警状态
/// 0x0200_0x17
/// </summary>
public class JT808_0x0200_0x17 : JT808_0x0200_BodyBase, IJT808MessagePackFormatter<JT808_0x0200_0x17>, IJT808Analyze
{
public override byte AttachInfoId { get; set; } = 0x17;
/// <summary>
/// 数据 长度
/// </summary>
public override byte AttachInfoLength { get; set; } = 2;
/// <summary>
/// 存储器故障报警状态
/// </summary>
public ushort StorageFaultAlarmStatus{ get; set; }

public void Analyze(ref JT808MessagePackReader reader, Utf8JsonWriter writer, IJT808Config config)
{
JT808_0x0200_0x17 value = new JT808_0x0200_0x17();
value.AttachInfoId = reader.ReadByte();
writer.WriteNumber($"[{value.AttachInfoId.ReadNumber()}]附加信息Id", value.AttachInfoId);
value.AttachInfoLength = reader.ReadByte();
writer.WriteNumber($"[{value.AttachInfoLength.ReadNumber()}]附加信息长度", value.AttachInfoLength);
value.StorageFaultAlarmStatus = reader.ReadUInt16();
writer.WriteNumber($"[{value.StorageFaultAlarmStatus.ReadNumber()}]存储器故障报警状态", value.StorageFaultAlarmStatus);
var storageFaultAlarmStatusSpan = Convert.ToString(value.StorageFaultAlarmStatus, 2).PadLeft(16, '0').AsSpan();
writer.WriteStartArray("存储器故障报警状态集合");
int index = 0;
foreach (var item in storageFaultAlarmStatusSpan)
{
if (index < 4)
{
if (item == '1')
{
writer.WriteStringValue($"{index}灾备存储装置故障");
}
else
{
writer.WriteStringValue($"{index}灾备存储装置正常");
}
}
else
{
if (item == '1')
{
writer.WriteStringValue($"{index}主存储器故障");
}
else
{
writer.WriteStringValue($"{index}主存储器正常");
}
}
index++;
}
writer.WriteEndArray();
}

public JT808_0x0200_0x17 Deserialize(ref JT808MessagePackReader reader, IJT808Config config)
{
JT808_0x0200_0x17 value = new JT808_0x0200_0x17();
value.AttachInfoId = reader.ReadByte();
value.AttachInfoLength = reader.ReadByte();
value.StorageFaultAlarmStatus = reader.ReadUInt16();
return value;
}

public void Serialize(ref JT808MessagePackWriter writer, JT808_0x0200_0x17 value, IJT808Config config)
{
writer.WriteByte(value.AttachInfoId);
writer.WriteByte(value.AttachInfoLength);
writer.WriteUInt16(value.StorageFaultAlarmStatus);
}
}
}

+ 0
- 90
src/JT808.Protocol.Extensions.JT1078/MessageBody/JT808_0x0200_0x18.cs View File

@@ -1,90 +0,0 @@
using JT808.Protocol.Formatters;
using JT808.Protocol.Interfaces;
using JT808.Protocol.MessageBody;
using JT808.Protocol.MessagePack;
using System;
using System.Text.Json;

namespace JT808.Protocol.Extensions.JT1078.MessageBody
{
/// <summary>
/// 异常驾驶行为报警详细描述
/// 0x0200_0x18
/// </summary>
public class JT808_0x0200_0x18 : JT808_0x0200_BodyBase, IJT808MessagePackFormatter<JT808_0x0200_0x18>, IJT808Analyze
{
public override byte AttachInfoId { get; set; } = 0x18;
/// <summary>
/// 数据 长度
/// </summary>
public override byte AttachInfoLength { get; set; } = 3;
/// <summary>
/// 异常驾驶行为报警类型
/// </summary>
public ushort AbnormalDrivingBehaviorAlarmType{ get; set; }
/// <summary>
/// 疲劳程度
/// </summary>
public byte FatigueLevel { get; set; }

public void Analyze(ref JT808MessagePackReader reader, Utf8JsonWriter writer, IJT808Config config)
{
JT808_0x0200_0x18 value = new JT808_0x0200_0x18();
value.AttachInfoId = reader.ReadByte();
writer.WriteNumber($"[{value.AttachInfoId.ReadNumber()}]附加信息Id", value.AttachInfoId);
value.AttachInfoLength = reader.ReadByte();
writer.WriteNumber($"[{value.AttachInfoLength.ReadNumber()}]附加信息长度", value.AttachInfoLength);
value.AbnormalDrivingBehaviorAlarmType = reader.ReadUInt16();
writer.WriteNumber($"[{value.AbnormalDrivingBehaviorAlarmType.ReadNumber()}]异常驾驶行为报警类型", value.AbnormalDrivingBehaviorAlarmType);
writer.WriteStartArray("视频信号遮挡报警状态集合");
var abnormalDrivingBehaviorAlarmTypeSpan = Convert.ToString(value.AbnormalDrivingBehaviorAlarmType, 2).PadLeft(16, '0').AsSpan();
int index = 0;
foreach (var item in abnormalDrivingBehaviorAlarmTypeSpan)
{
string tmpResult = item == '1' ? "有" : "无";
if (index == 0)
{
writer.WriteStringValue($"[bit{index}疲劳]_{tmpResult}");
}
else if (index == 1)
{
writer.WriteStringValue($"[bit{index}打电话]_{tmpResult}");
}
else if (index == 2)
{
writer.WriteStringValue($"[bit{index}抽烟]_{tmpResult}");
}
else if (index>=3 && index<=10)
{
writer.WriteStringValue($"[bit{index}保留]_{tmpResult}");
}
else
{
writer.WriteStringValue($"[bit{index}自定义]_{tmpResult}");
}
index++;
}
writer.WriteEndArray();
value.FatigueLevel = reader.ReadByte();
writer.WriteNumber($"[{value.FatigueLevel.ReadNumber()}]疲劳程度", value.FatigueLevel);
}

public JT808_0x0200_0x18 Deserialize(ref JT808MessagePackReader reader, IJT808Config config)
{
JT808_0x0200_0x18 value = new JT808_0x0200_0x18();
value.AttachInfoId = reader.ReadByte();
value.AttachInfoLength = reader.ReadByte();
value.AbnormalDrivingBehaviorAlarmType = reader.ReadUInt16();
value.FatigueLevel = reader.ReadByte();
return value;
}

public void Serialize(ref JT808MessagePackWriter writer, JT808_0x0200_0x18 value, IJT808Config config)
{
writer.WriteByte(value.AttachInfoId);
writer.WriteByte(value.AttachInfoLength);
writer.WriteUInt16(value.AbnormalDrivingBehaviorAlarmType);
writer.WriteByte(value.FatigueLevel);
}
}
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save