@@ -330,3 +330,4 @@ ASALocalRun/ | |||||
.mfractor/ | .mfractor/ | ||||
/src/JT1078.Flv.Test/H264/JT1078_3.txt | /src/JT1078.Flv.Test/H264/JT1078_3.txt | ||||
/src/JT1078.Flv.Test/H264/JT1078_4.txt | /src/JT1078.Flv.Test/H264/JT1078_4.txt | ||||
/src/JT1078.Flv.Test/H264/JT1078_5.txt |
@@ -8,6 +8,7 @@ using System.IO; | |||||
using System.Linq; | using System.Linq; | ||||
using JT1078.Protocol.Enums; | using JT1078.Protocol.Enums; | ||||
using JT1078.Flv.H264; | using JT1078.Flv.H264; | ||||
using JT1078.Flv.MessagePack; | |||||
namespace JT1078.Flv.Test | namespace JT1078.Flv.Test | ||||
{ | { | ||||
@@ -208,5 +209,67 @@ namespace JT1078.Flv.Test | |||||
fileStream?.Dispose(); | fileStream?.Dispose(); | ||||
} | } | ||||
} | } | ||||
[Fact] | |||||
public void FlvEncoder_Test_5() | |||||
{ | |||||
FileStream fileStream = null; | |||||
Flv.H264.H264Decoder decoder = new Flv.H264.H264Decoder(); | |||||
List<H264NALU> h264NALULs = new List<H264NALU>(); | |||||
FlvEncoder encoder = new FlvEncoder(); | |||||
try | |||||
{ | |||||
var filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_5.flv"); | |||||
var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_5.txt")); | |||||
if (File.Exists(filepath)) | |||||
{ | |||||
File.Delete(filepath); | |||||
} | |||||
JT1078Package Package = null; | |||||
foreach (var line in lines) | |||||
{ | |||||
var data = line.Split(','); | |||||
var bytes = data[6].ToHexBytes(); | |||||
JT1078Package package = JT1078Serializer.Deserialize(bytes); | |||||
Package = JT1078Serializer.Merge(package); | |||||
if (Package != null) | |||||
{ | |||||
var tmp = decoder.ParseNALU(Package); | |||||
if (tmp != null && tmp.Count > 0) | |||||
{ | |||||
h264NALULs = h264NALULs.Concat(tmp).ToList(); | |||||
} | |||||
} | |||||
} | |||||
var tmp1 = h264NALULs.Where(w => w.NALUHeader.NalUnitType == 7).ToList(); | |||||
List<SPSInfo> tmpSpss = new List<SPSInfo>(); | |||||
foreach (var item in tmp1) | |||||
{ | |||||
ExpGolombReader expGolombReader = new ExpGolombReader(item.RawData); | |||||
tmpSpss.Add(expGolombReader.ReadSPS()); | |||||
} | |||||
fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write); | |||||
var totalPage = (h264NALULs.Count + 10 - 1) / 10; | |||||
for (var i = 0; i < totalPage; i++) | |||||
{ | |||||
var flv2 = encoder.CreateFlvFrame(h264NALULs.Skip(i * 10).Take(10).ToList()); | |||||
if (flv2.Length != 0) | |||||
{ | |||||
fileStream.Write(flv2); | |||||
} | |||||
} | |||||
} | |||||
catch (Exception ex) | |||||
{ | |||||
Assert.Throws<Exception>(() => { }); | |||||
} | |||||
finally | |||||
{ | |||||
fileStream?.Close(); | |||||
fileStream?.Dispose(); | |||||
} | |||||
} | |||||
} | } | ||||
} | } |
@@ -8,27 +8,21 @@ | |||||
</head> | </head> | ||||
<body> | <body> | ||||
<video muted="muted" webkit-playsinline="true" autoplay="true" id="player"></video> | <video muted="muted" webkit-playsinline="true" autoplay="true" id="player"></video> | ||||
<video muted="muted" webkit-playsinline="true" autoplay="true" id="player2"></video> | |||||
<script> | <script> | ||||
if (flvjs.isSupported()) { | if (flvjs.isSupported()) { | ||||
var player = document.getElementById('player'); | var player = document.getElementById('player'); | ||||
var flvPlayer = flvjs.createPlayer({ | var flvPlayer = flvjs.createPlayer({ | ||||
type: 'flv', | type: 'flv', | ||||
url: "jt1078_3.flv" | |||||
url: "jt1078_5.flv" | |||||
}); | }); | ||||
var width, height, flag; | |||||
flvPlayer.attachMediaElement(player); | flvPlayer.attachMediaElement(player); | ||||
flvPlayer.on(flvjs.Events.SCRIPTDATA_ARRIVED, (e) => { | |||||
console.log(e); | |||||
}); | |||||
flvPlayer.load(); | flvPlayer.load(); | ||||
flvPlayer.play(); | flvPlayer.play(); | ||||
var player2 = document.getElementById('player2'); | |||||
var flvPlayer2 = flvjs.createPlayer({ | |||||
type: 'flv', | |||||
url: "jt1078_4.flv" | |||||
}); | |||||
flvPlayer2.attachMediaElement(player2); | |||||
flvPlayer2.load(); | |||||
flvPlayer2.play(); | |||||
} | } | ||||
</script> | </script> | ||||
</body> | </body> |
@@ -7,6 +7,7 @@ | |||||
<ItemGroup> | <ItemGroup> | ||||
<None Remove="H264\JT1078_3.rar" /> | <None Remove="H264\JT1078_3.rar" /> | ||||
<None Remove="H264\JT1078_4.rar" /> | <None Remove="H264\JT1078_4.rar" /> | ||||
<None Remove="H264\JT1078_5.rar" /> | |||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
@@ -39,6 +40,9 @@ | |||||
<None Update="H264\JT1078_4.txt"> | <None Update="H264\JT1078_4.txt"> | ||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> | <CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||||
</None> | </None> | ||||
<None Update="H264\JT1078_5.txt"> | |||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> | |||||
</None> | |||||
</ItemGroup> | </ItemGroup> | ||||
</Project> | </Project> |
@@ -17,6 +17,7 @@ namespace JT1078.Flv | |||||
private const uint PreviousTagSizeFixedLength = 4; | private const uint PreviousTagSizeFixedLength = 4; | ||||
private static readonly ConcurrentDictionary<string, uint> PreviousTagSizeDict; | private static readonly ConcurrentDictionary<string, uint> PreviousTagSizeDict; | ||||
private static readonly ConcurrentDictionary<string, bool> FrameInitDict; | private static readonly ConcurrentDictionary<string, bool> FrameInitDict; | ||||
private static readonly ConcurrentDictionary<string, SPSInfo> VideoSPSDict; | |||||
private static readonly Flv.H264.H264Decoder H264Decoder; | private static readonly Flv.H264.H264Decoder H264Decoder; | ||||
static FlvEncoder() | static FlvEncoder() | ||||
{ | { | ||||
@@ -24,6 +25,7 @@ namespace JT1078.Flv | |||||
VideoFlvHeaderBuffer = VideoFlvHeader.ToArray().ToArray(); | VideoFlvHeaderBuffer = VideoFlvHeader.ToArray().ToArray(); | ||||
PreviousTagSizeDict = new ConcurrentDictionary<string, uint>(); | PreviousTagSizeDict = new ConcurrentDictionary<string, uint>(); | ||||
FrameInitDict = new ConcurrentDictionary<string, bool>(); | FrameInitDict = new ConcurrentDictionary<string, bool>(); | ||||
VideoSPSDict = new ConcurrentDictionary<string, SPSInfo>(); | |||||
H264Decoder = new Flv.H264.H264Decoder(); | H264Decoder = new Flv.H264.H264Decoder(); | ||||
} | } | ||||
/// <summary> | /// <summary> | ||||
@@ -32,7 +34,7 @@ namespace JT1078.Flv | |||||
/// <param name="sps">NalUnitType->7</param> | /// <param name="sps">NalUnitType->7</param> | ||||
/// <param name="pps">NalUnitType->8</param> | /// <param name="pps">NalUnitType->8</param> | ||||
/// <returns></returns> | /// <returns></returns> | ||||
public byte[] CreateFlvFirstFrame(H264NALU sps, H264NALU pps) | |||||
public byte[] CreateFlvFirstFrame(H264NALU sps, H264NALU pps,bool isSendFlvHeader=true,uint previousTagSize=0) | |||||
{ | { | ||||
byte[] buffer = FlvArrayPool.Rent(65535); | byte[] buffer = FlvArrayPool.Rent(65535); | ||||
int currentMarkPosition = 0; | int currentMarkPosition = 0; | ||||
@@ -40,16 +42,18 @@ namespace JT1078.Flv | |||||
try | try | ||||
{ | { | ||||
FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer); | FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer); | ||||
//flv header | |||||
flvMessagePackWriter.WriteArray(VideoFlvHeaderBuffer); | |||||
if (isSendFlvHeader) | |||||
{ | |||||
//flv header | |||||
flvMessagePackWriter.WriteArray(VideoFlvHeaderBuffer); | |||||
} | |||||
//SPS -> 7 | //SPS -> 7 | ||||
ExpGolombReader h264GolombReader = new ExpGolombReader(sps.RawData); | ExpGolombReader h264GolombReader = new ExpGolombReader(sps.RawData); | ||||
var spsInfo = h264GolombReader.ReadSPS(); | var spsInfo = h264GolombReader.ReadSPS(); | ||||
currentMarkPosition = flvMessagePackWriter.GetCurrentPosition(); | currentMarkPosition = flvMessagePackWriter.GetCurrentPosition(); | ||||
//flv body script tag | //flv body script tag | ||||
CreateScriptTagFrame(ref flvMessagePackWriter, spsInfo.width, spsInfo.height); | |||||
CreateScriptTagFrame(ref flvMessagePackWriter, spsInfo.width, spsInfo.height, previousTagSize); | |||||
nextMarkPosition = flvMessagePackWriter.GetCurrentPosition(); | nextMarkPosition = flvMessagePackWriter.GetCurrentPosition(); | ||||
//flv body video tag | //flv body video tag | ||||
@@ -78,10 +82,10 @@ namespace JT1078.Flv | |||||
FlvArrayPool.Return(buffer); | FlvArrayPool.Return(buffer); | ||||
} | } | ||||
} | } | ||||
private void CreateScriptTagFrame(ref FlvMessagePackWriter flvMessagePackWriter, int width, int height,double frameRate = 25d) | |||||
private void CreateScriptTagFrame(ref FlvMessagePackWriter flvMessagePackWriter, int width, int height,uint previousTagSize, double frameRate = 25d) | |||||
{ | { | ||||
//flv body PreviousTagSize awalys 0 | //flv body PreviousTagSize awalys 0 | ||||
flvMessagePackWriter.WriteUInt32(0); | |||||
flvMessagePackWriter.WriteUInt32(previousTagSize); | |||||
//flv body script tag | //flv body script tag | ||||
//flv body tag header | //flv body tag header | ||||
FlvTags flvTags = new FlvTags(); | FlvTags flvTags = new FlvTags(); | ||||
@@ -141,7 +145,7 @@ namespace JT1078.Flv | |||||
public static uint LastFrameInterval = 0; | public static uint LastFrameInterval = 0; | ||||
private void CreateVideoTagOtherFrame(ref FlvMessagePackWriter flvMessagePackWriter, uint previousTagSize, H264NALU nALU, H264NALU sps, H264NALU pps,H264NALU sei) | |||||
private void CreateVideoTagOtherFrame(ref FlvMessagePackWriter flvMessagePackWriter, uint previousTagSize, H264NALU nALU) | |||||
{ | { | ||||
//flv body PreviousTagSize | //flv body PreviousTagSize | ||||
flvMessagePackWriter.WriteUInt32(previousTagSize); | flvMessagePackWriter.WriteUInt32(previousTagSize); | ||||
@@ -156,38 +160,18 @@ namespace JT1078.Flv | |||||
flvTags.VideoTagsData.VideoData = new AvcVideoPacke(); | flvTags.VideoTagsData.VideoData = new AvcVideoPacke(); | ||||
flvTags.VideoTagsData.VideoData.CompositionTime = 0; | flvTags.VideoTagsData.VideoData.CompositionTime = 0; | ||||
flvTags.VideoTagsData.VideoData.AvcPacketType = AvcPacketType.Raw; | flvTags.VideoTagsData.VideoData.AvcPacketType = AvcPacketType.Raw; | ||||
flvTags.VideoTagsData.VideoData.MultiData = new List<byte[]>(); | |||||
LastFrameInterval += nALU.LastFrameInterval; | LastFrameInterval += nALU.LastFrameInterval; | ||||
flvTags.Timestamp = LastFrameInterval; | flvTags.Timestamp = LastFrameInterval; | ||||
if (nALU.NALUHeader.NalUnitType == 5) | if (nALU.NALUHeader.NalUnitType == 5) | ||||
{ | { | ||||
flvTags.VideoTagsData.FrameType = FrameType.KeyFrame; | flvTags.VideoTagsData.FrameType = FrameType.KeyFrame; | ||||
if (sps!=null && pps != null) | |||||
{ | |||||
//flvTags.VideoTagsData.VideoData.MultiData.Add(sps.RawData); | |||||
//flvTags.VideoTagsData.VideoData.MultiData.Add(pps.RawData); | |||||
flvTags.VideoTagsData.VideoData.MultiData.Add(nALU.RawData); | |||||
} | |||||
else | |||||
{ | |||||
//if (sei != null) | |||||
//{ | |||||
// flvTags.VideoTagsData.VideoData.MultiData.Add(sei.RawData); | |||||
//} | |||||
flvTags.VideoTagsData.VideoData.MultiData.Add(nALU.RawData); | |||||
} | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
flvTags.VideoTagsData.FrameType = FrameType.InterFrame; | flvTags.VideoTagsData.FrameType = FrameType.InterFrame; | ||||
//if (sei != null) | |||||
//{ | |||||
// flvTags.VideoTagsData.VideoData.MultiData.Add(sei.RawData); | |||||
//} | |||||
flvTags.VideoTagsData.VideoData.MultiData.Add(nALU.RawData); | |||||
} | } | ||||
flvTags.VideoTagsData.VideoData.Data = nALU.RawData; | |||||
flvMessagePackWriter.WriteFlvTag(flvTags); | flvMessagePackWriter.WriteFlvTag(flvTags); | ||||
} | } | ||||
public byte[] CreateFlvFrame(List<H264NALU> nALUs, int minimumLength = 65535) | public byte[] CreateFlvFrame(List<H264NALU> nALUs, int minimumLength = 65535) | ||||
@@ -204,10 +188,22 @@ namespace JT1078.Flv | |||||
if (sps!=null && pps != null) | if (sps!=null && pps != null) | ||||
{ | { | ||||
string key = sps.GetKey(); | string key = sps.GetKey(); | ||||
if (!FrameInitDict.ContainsKey(key)) | |||||
ExpGolombReader h264GolombReader = new ExpGolombReader(sps.RawData); | |||||
var spsInfo = h264GolombReader.ReadSPS(); | |||||
if(VideoSPSDict.TryGetValue(key,out var spsInfoCache)) | |||||
{ | |||||
if(spsInfoCache.height!= spsInfo.height && spsInfoCache.width!= spsInfo.width) | |||||
{ | |||||
uint previousTagSize = 0; | |||||
PreviousTagSizeDict.TryGetValue(key, out previousTagSize); | |||||
flvMessagePackWriter.WriteArray(CreateFlvFirstFrame(sps, pps,false, previousTagSize)); | |||||
VideoSPSDict.TryUpdate(key, spsInfo, spsInfo); | |||||
} | |||||
} | |||||
else | |||||
{ | { | ||||
flvMessagePackWriter.WriteArray(CreateFlvFirstFrame(sps, pps)); | flvMessagePackWriter.WriteArray(CreateFlvFirstFrame(sps, pps)); | ||||
FrameInitDict.TryAdd(key, true); | |||||
VideoSPSDict.TryAdd(key, spsInfo); | |||||
} | } | ||||
} | } | ||||
foreach (var naln in nALUs.Where(w=> w.NALUHeader.NalUnitType != 7 && w.NALUHeader.NalUnitType != 8 && w.NALUHeader.NalUnitType != 6)) | foreach (var naln in nALUs.Where(w=> w.NALUHeader.NalUnitType != 7 && w.NALUHeader.NalUnitType != 8 && w.NALUHeader.NalUnitType != 6)) | ||||
@@ -216,7 +212,7 @@ namespace JT1078.Flv | |||||
if (PreviousTagSizeDict.TryGetValue(key, out uint previousTagSize)) | if (PreviousTagSizeDict.TryGetValue(key, out uint previousTagSize)) | ||||
{ | { | ||||
currentMarkPosition = flvMessagePackWriter.GetCurrentPosition(); | currentMarkPosition = flvMessagePackWriter.GetCurrentPosition(); | ||||
CreateVideoTagOtherFrame(ref flvMessagePackWriter, previousTagSize, naln,sps, pps, sei); | |||||
CreateVideoTagOtherFrame(ref flvMessagePackWriter, previousTagSize, naln); | |||||
nextMarkPosition = flvMessagePackWriter.GetCurrentPosition(); | nextMarkPosition = flvMessagePackWriter.GetCurrentPosition(); | ||||
uint tmpPreviousTagSize = (uint)(nextMarkPosition - currentMarkPosition - PreviousTagSizeFixedLength); | uint tmpPreviousTagSize = (uint)(nextMarkPosition - currentMarkPosition - PreviousTagSizeFixedLength); | ||||
PreviousTagSizeDict.TryUpdate(key, tmpPreviousTagSize, previousTagSize); | PreviousTagSizeDict.TryUpdate(key, tmpPreviousTagSize, previousTagSize); | ||||
@@ -21,7 +21,7 @@ namespace JT1078.Flv.MessagePack | |||||
Word = 0; | Word = 0; | ||||
BitsAvailable = 0; | BitsAvailable = 0; | ||||
} | } | ||||
public (byte profileIdc,byte levelIdc,uint profileCompat,int width, int height) ReadSPS() | |||||
public SPSInfo ReadSPS() | |||||
{ | { | ||||
int sarScale = 1; | int sarScale = 1; | ||||
uint frameCropLeftOffset=0; | uint frameCropLeftOffset=0; | ||||
@@ -153,7 +153,7 @@ namespace JT1078.Flv.MessagePack | |||||
} | } | ||||
int width= (int)((((picWidthInMbsMinus1 + 1) * 16) - frameCropLeftOffset * 2 - frameCropRightOffset * 2) * sarScale); | int width= (int)((((picWidthInMbsMinus1 + 1) * 16) - frameCropLeftOffset * 2 - frameCropRightOffset * 2) * sarScale); | ||||
int height = (int)(((2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16) - ((frameMbsOnlyFlag == 1U ? 2 : 4) * (frameCropTopOffset + frameCropBottomOffset))); | int height = (int)(((2 - frameMbsOnlyFlag) * (picHeightInMapUnitsMinus1 + 1) * 16) - ((frameMbsOnlyFlag == 1U ? 2 : 4) * (frameCropTopOffset + frameCropBottomOffset))); | ||||
return (profileIdc, levelIdc, profileCompat,width, height); | |||||
return new SPSInfo { profileIdc= profileIdc, levelIdc= levelIdc, profileCompat= profileCompat, width= width, height= height }; | |||||
} | } | ||||
public void LoadWord() | public void LoadWord() | ||||
{ | { | ||||
@@ -310,4 +310,13 @@ namespace JT1078.Flv.MessagePack | |||||
} | } | ||||
} | } | ||||
} | } | ||||
public struct SPSInfo | |||||
{ | |||||
public byte profileIdc { get; set; } | |||||
public byte levelIdc { get; set; } | |||||
public uint profileCompat { get; set; } | |||||
public int width { get; set; } | |||||
public int height { get; set; } | |||||
} | |||||
} | } |
@@ -85,19 +85,6 @@ namespace JT1078.Flv.MessagePack | |||||
else if(videoPacke.AvcPacketType == AvcPacketType.Raw) | else if(videoPacke.AvcPacketType == AvcPacketType.Raw) | ||||
{ | { | ||||
WriteUInt24(videoPacke.CompositionTime); | WriteUInt24(videoPacke.CompositionTime); | ||||
//One or more NALUs | |||||
//WriteArray(new byte[] {0,0,0,1}); | |||||
if (videoPacke.MultiData != null) | |||||
{ | |||||
foreach(var item in videoPacke.MultiData) | |||||
{ | |||||
if (item != null && item.Length > 0) | |||||
{ | |||||
WriteInt32(item.Length); | |||||
WriteArray(item); | |||||
} | |||||
} | |||||
} | |||||
if (videoPacke.Data != null && videoPacke.Data.Length>0) | if (videoPacke.Data != null && videoPacke.Data.Length>0) | ||||
{ | { | ||||
WriteInt32(videoPacke.Data.Length); | WriteInt32(videoPacke.Data.Length); | ||||
@@ -121,19 +108,10 @@ namespace JT1078.Flv.MessagePack | |||||
//reserved(6bits)+LengthSizeMinusOne(2bits) | //reserved(6bits)+LengthSizeMinusOne(2bits) | ||||
WriteByte(0xFF); | WriteByte(0xFF); | ||||
WriteByte((byte)configurationRecord.NumOfSequenceParameterSets); | WriteByte((byte)configurationRecord.NumOfSequenceParameterSets); | ||||
WriteUInt16((ushort)(configurationRecord.SPSBuffer.Length)); | WriteUInt16((ushort)(configurationRecord.SPSBuffer.Length)); | ||||
//WriteUInt16((ushort)(configurationRecord.SPSBuffer.Length + 4)); | |||||
//WriteArray(new byte[] { 0, 0, 0, 1 }); | |||||
WriteArray(configurationRecord.SPSBuffer); | WriteArray(configurationRecord.SPSBuffer); | ||||
WriteByte(configurationRecord.NumOfPictureParameterSets); | WriteByte(configurationRecord.NumOfPictureParameterSets); | ||||
WriteUInt16((ushort)(configurationRecord.PPSBuffer.Length)); | WriteUInt16((ushort)(configurationRecord.PPSBuffer.Length)); | ||||
//WriteUInt16((ushort)(configurationRecord.PPSBuffer.Length+4)); | |||||
//WriteArray(new byte[] { 0, 0, 0, 1 }); | |||||
WriteArray(configurationRecord.PPSBuffer); | WriteArray(configurationRecord.PPSBuffer); | ||||
} | } | ||||
} | } | ||||
@@ -14,7 +14,5 @@ namespace JT1078.Flv.Metadata | |||||
public AVCDecoderConfigurationRecord AVCDecoderConfiguration { get; set; } | public AVCDecoderConfigurationRecord AVCDecoderConfiguration { get; set; } | ||||
public byte[] Data { get; set; } | public byte[] Data { get; set; } | ||||
public List<byte[]> MultiData { get; set; } | |||||
} | } | ||||
} | } |
@@ -24,40 +24,22 @@ namespace JT1078.Protocol.MessagePack | |||||
} | } | ||||
public void WriteUInt16(ushort value) | public void WriteUInt16(ushort value) | ||||
{ | { | ||||
var span = writer.Free; | |||||
span[0] = (byte)(value >> 8); | |||||
span[1] = (byte)value; | |||||
BinaryPrimitives.WriteUInt16BigEndian(writer.Free, value); | |||||
writer.Advance(2); | writer.Advance(2); | ||||
} | } | ||||
public void WriteInt32(int value) | public void WriteInt32(int value) | ||||
{ | { | ||||
var span = writer.Free; | |||||
span[0] = (byte)(value >> 24); | |||||
span[1] = (byte)(value >> 16); | |||||
span[2] = (byte)(value >> 8); | |||||
span[3] = (byte)value; | |||||
BinaryPrimitives.WriteInt32BigEndian(writer.Free, value); | |||||
writer.Advance(4); | writer.Advance(4); | ||||
} | } | ||||
public void WriteUInt64(ulong value) | public void WriteUInt64(ulong value) | ||||
{ | { | ||||
var span = writer.Free; | |||||
span[0] = (byte)(value >> 56); | |||||
span[1] = (byte)(value >> 48); | |||||
span[2] = (byte)(value >> 40); | |||||
span[3] = (byte)(value >> 32); | |||||
span[4] = (byte)(value >> 24); | |||||
span[5] = (byte)(value >> 16); | |||||
span[6] = (byte)(value >> 8); | |||||
span[7] = (byte)value; | |||||
BinaryPrimitives.WriteUInt64BigEndian(writer.Free, value); | |||||
writer.Advance(8); | writer.Advance(8); | ||||
} | } | ||||
public void WriteUInt32(uint value) | public void WriteUInt32(uint value) | ||||
{ | { | ||||
var span = writer.Free; | |||||
span[0] = (byte)(value >> 24); | |||||
span[1] = (byte)(value >> 16); | |||||
span[2] = (byte)(value >> 8); | |||||
span[3] = (byte)value; | |||||
BinaryPrimitives.WriteUInt32BigEndian(writer.Free, value); | |||||
writer.Advance(4); | writer.Advance(4); | ||||
} | } | ||||
public void WriteArray(ReadOnlySpan<byte> src) | public void WriteArray(ReadOnlySpan<byte> src) | ||||