@@ -12,10 +12,14 @@ | |||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
<ProjectReference Include="..\JT1078.Flv\JT1078.Flv.csproj" /> | <ProjectReference Include="..\JT1078.Flv\JT1078.Flv.csproj" /> | ||||
<ProjectReference Include="..\JT1078.FMp4\JT1078.FMp4.csproj" /> | |||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
<None Include="..\..\doc\video\jt1078_1.txt" Link="jt1078_1.txt"> | <None Include="..\..\doc\video\jt1078_1.txt" Link="jt1078_1.txt"> | ||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> | <CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||||
</None> | </None> | ||||
<None Include="..\..\doc\video\jt1078_3.txt" Link="jt1078_3.txt"> | |||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> | |||||
</None> | |||||
</ItemGroup> | </ItemGroup> | ||||
</Project> | </Project> |
@@ -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.EncoderOtherVideoBox(FMp4H264NALUs); | |||||
} | |||||
} | |||||
} | |||||
public class JT1078AVEncoderConfig : ManualConfig | |||||
{ | |||||
public JT1078AVEncoderConfig() | |||||
{ | |||||
AddJob(Job.Default.WithGcServer(false).WithToolchain(CsProjCoreToolchain.NetCoreApp50).WithPlatform(Platform.AnyCpu)); | |||||
} | |||||
} | |||||
} |
@@ -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 == NalUnitType.SPS); | |||||
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)); | |||||
} | |||||
} | |||||
} |
@@ -8,7 +8,7 @@ namespace JT1078.AV.Benchmark | |||||
{ | { | ||||
static void Main(string[] args) | static void Main(string[] args) | ||||
{ | { | ||||
Summary summary = BenchmarkRunner.Run<JT1078FlvEncoderContext>(); | |||||
Summary summary = BenchmarkRunner.Run<JT1078AVEncoderContext>(); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -482,53 +482,6 @@ namespace JT1078.FMp4.Test | |||||
fileStream.Close(); | 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.EncoderFtypBox(); | |||||
fileStream.Write(ftyp); | |||||
var iNalus = h264Decoder.ParseNALU(packages[0]); | |||||
//判断第一帧是否关键帧 | |||||
var moov = fMp4Encoder.EncoderMoovBox( | |||||
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.EncoderOtherVideoBox(nalus); | |||||
fileStream.Write(otherBuffer); | |||||
nalus.Clear(); | |||||
} | |||||
} | |||||
nalus = nalus.Concat(h264NALUs).ToList(); | |||||
} | |||||
if (nalus.Count > 0) | |||||
{ | |||||
var otherBuffer = fMp4Encoder.EncoderOtherVideoBox(nalus); | |||||
fileStream.Write(otherBuffer); | |||||
nalus.Clear(); | |||||
} | |||||
fileStream.Close(); | |||||
} | |||||
[Fact] | [Fact] | ||||
public void tkhd_width_height_test() | public void tkhd_width_height_test() | ||||
{ | { | ||||
@@ -30,6 +30,24 @@ namespace JT1078.FMp4 | |||||
/// </summary> | /// </summary> | ||||
public class FMp4Encoder | public class FMp4Encoder | ||||
{ | { | ||||
Dictionary<string, TrackInfo> TrackInfos; | |||||
const uint DefaultSampleDuration = 48000u; | |||||
const uint DefaultSampleFlags = 0x1010000; | |||||
const uint FirstSampleFlags = 33554432; | |||||
const uint TfhdFlags = 0x2003a; | |||||
const uint TrunFlags = 0x205; | |||||
const uint SampleDescriptionIndex = 1; | |||||
const uint TrackID = 1; | |||||
/// <summary> | |||||
/// | |||||
/// </summary> | |||||
public FMp4Encoder() | |||||
{ | |||||
TrackInfos = new Dictionary<string, TrackInfo>(StringComparer.OrdinalIgnoreCase); | |||||
} | |||||
/// <summary> | /// <summary> | ||||
/// 编码ftyp盒子 | /// 编码ftyp盒子 | ||||
/// </summary> | /// </summary> | ||||
@@ -66,7 +84,7 @@ namespace JT1078.FMp4 | |||||
/// <returns></returns> | /// <returns></returns> | ||||
public byte[] EncoderMoovBox(in H264NALU sps, in H264NALU pps) | public byte[] EncoderMoovBox(in H264NALU sps, in H264NALU pps) | ||||
{ | { | ||||
byte[] buffer = FMp4ArrayPool.Rent(sps.RawData.Length+ pps.RawData.Length + 1024); | |||||
byte[] buffer = FMp4ArrayPool.Rent(sps.RawData.Length + pps.RawData.Length + 1024); | |||||
FMp4MessagePackWriter writer = new FMp4MessagePackWriter(buffer); | FMp4MessagePackWriter writer = new FMp4MessagePackWriter(buffer); | ||||
try | try | ||||
{ | { | ||||
@@ -84,7 +102,7 @@ namespace JT1078.FMp4 | |||||
movieBox.TrackBox.TrackHeaderBox = new TrackHeaderBox(0, 3); | movieBox.TrackBox.TrackHeaderBox = new TrackHeaderBox(0, 3); | ||||
movieBox.TrackBox.TrackHeaderBox.CreationTime = 0; | movieBox.TrackBox.TrackHeaderBox.CreationTime = 0; | ||||
movieBox.TrackBox.TrackHeaderBox.ModificationTime = 0; | movieBox.TrackBox.TrackHeaderBox.ModificationTime = 0; | ||||
movieBox.TrackBox.TrackHeaderBox.TrackID = 1; | |||||
movieBox.TrackBox.TrackHeaderBox.TrackID = TrackID; | |||||
movieBox.TrackBox.TrackHeaderBox.Duration = 0; | movieBox.TrackBox.TrackHeaderBox.Duration = 0; | ||||
movieBox.TrackBox.TrackHeaderBox.TrackIsAudio = false; | movieBox.TrackBox.TrackHeaderBox.TrackIsAudio = false; | ||||
movieBox.TrackBox.TrackHeaderBox.Width = (uint)spsInfo.width; | movieBox.TrackBox.TrackHeaderBox.Width = (uint)spsInfo.width; | ||||
@@ -126,8 +144,8 @@ namespace JT1078.FMp4 | |||||
movieBox.MovieExtendsBox = new MovieExtendsBox(); | movieBox.MovieExtendsBox = new MovieExtendsBox(); | ||||
movieBox.MovieExtendsBox.TrackExtendsBoxs = new List<TrackExtendsBox>(); | movieBox.MovieExtendsBox.TrackExtendsBoxs = new List<TrackExtendsBox>(); | ||||
TrackExtendsBox trex = new TrackExtendsBox(); | TrackExtendsBox trex = new TrackExtendsBox(); | ||||
trex.TrackID = 1; | |||||
trex.DefaultSampleDescriptionIndex = 1; | |||||
trex.TrackID = TrackID; | |||||
trex.DefaultSampleDescriptionIndex = SampleDescriptionIndex; | |||||
trex.DefaultSampleDuration = 0; | trex.DefaultSampleDuration = 0; | ||||
trex.DefaultSampleSize = 0; | trex.DefaultSampleSize = 0; | ||||
trex.DefaultSampleFlags = 0; | trex.DefaultSampleFlags = 0; | ||||
@@ -142,13 +160,11 @@ namespace JT1078.FMp4 | |||||
} | } | ||||
} | } | ||||
uint sn = 1; | |||||
/// <summary> | /// <summary> | ||||
/// 编码其他视频数据盒子 | /// 编码其他视频数据盒子 | ||||
/// </summary> | /// </summary> | ||||
/// <returns></returns> | /// <returns></returns> | ||||
public byte[] EncoderOtherVideoBox(List<H264NALU> nalus) | |||||
public byte[] EncoderOtherVideoBox(in List<H264NALU> nalus) | |||||
{ | { | ||||
byte[] buffer = FMp4ArrayPool.Rent(nalus.Sum(s => s.RawData.Length + s.StartCodePrefix.Length) + 4096); | byte[] buffer = FMp4ArrayPool.Rent(nalus.Sum(s => s.RawData.Length + s.StartCodePrefix.Length) + 4096); | ||||
FMp4MessagePackWriter writer = new FMp4MessagePackWriter(buffer); | FMp4MessagePackWriter writer = new FMp4MessagePackWriter(buffer); | ||||
@@ -158,9 +174,14 @@ namespace JT1078.FMp4 | |||||
List<byte[]> rawdatas = new List<byte[]>(); | List<byte[]> rawdatas = new List<byte[]>(); | ||||
uint iSize = 0; | uint iSize = 0; | ||||
ulong lastTimestamp = 0; | ulong lastTimestamp = 0; | ||||
for (var i=0; i<nalus.Count;i++ ) | |||||
string key = string.Empty; | |||||
for (var i = 0; i < nalus.Count; i++) | |||||
{ | { | ||||
var nalu = nalus[i]; | var nalu = nalus[i]; | ||||
if (string.IsNullOrEmpty(key)) | |||||
{ | |||||
key = nalu.GetKey(); | |||||
} | |||||
rawdatas.Add(nalu.RawData); | rawdatas.Add(nalu.RawData); | ||||
if (nalu.DataType == Protocol.Enums.JT1078DataType.视频I帧) | if (nalu.DataType == Protocol.Enums.JT1078DataType.视频I帧) | ||||
{ | { | ||||
@@ -181,32 +202,44 @@ namespace JT1078.FMp4 | |||||
SampleSize = (uint)(nalu.RawData.Length + nalu.StartCodePrefix.Length), | SampleSize = (uint)(nalu.RawData.Length + nalu.StartCodePrefix.Length), | ||||
}); | }); | ||||
} | } | ||||
if(i== (nalus.Count - 1)) | |||||
if (i == (nalus.Count - 1)) | |||||
{ | { | ||||
lastTimestamp = nalu.Timestamp; | 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(); | var movieFragmentBox = new MovieFragmentBox(); | ||||
movieFragmentBox.MovieFragmentHeaderBox = new MovieFragmentHeaderBox(); | movieFragmentBox.MovieFragmentHeaderBox = new MovieFragmentHeaderBox(); | ||||
//todo:SequenceNumber | |||||
movieFragmentBox.MovieFragmentHeaderBox.SequenceNumber = sn++; | |||||
movieFragmentBox.MovieFragmentHeaderBox.SequenceNumber = trackInfo.SN; | |||||
movieFragmentBox.TrackFragmentBox = new TrackFragmentBox(); | movieFragmentBox.TrackFragmentBox = new TrackFragmentBox(); | ||||
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox = new TrackFragmentHeaderBox(0x2003a); | |||||
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.TrackID = 1; | |||||
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.SampleDescriptionIndex = 1; | |||||
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleDuration = 48000; | |||||
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.DefaultSampleSize = truns[0].SampleSize; | ||||
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleFlags = 0x1010000; | |||||
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleFlags = DefaultSampleFlags; | |||||
movieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox = new TrackFragmentBaseMediaDecodeTimeBox(); | movieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox = new TrackFragmentBaseMediaDecodeTimeBox(); | ||||
movieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox.BaseMediaDecodeTime = lastTimestamp * 1000; | |||||
movieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox.BaseMediaDecodeTime = trackInfo.DTS; | |||||
trackInfo.DTS += (ulong)(truns.Count * DefaultSampleDuration); | |||||
TrackInfos[key] = trackInfo; | |||||
//trun | //trun | ||||
movieFragmentBox.TrackFragmentBox.TrackRunBox = new TrackRunBox(flags: 0x205); | |||||
movieFragmentBox.TrackFragmentBox.TrackRunBox.FirstSampleFlags = 33554432; | |||||
movieFragmentBox.TrackFragmentBox.TrackRunBox = new TrackRunBox(flags: TrunFlags); | |||||
movieFragmentBox.TrackFragmentBox.TrackRunBox.FirstSampleFlags = FirstSampleFlags; | |||||
movieFragmentBox.TrackFragmentBox.TrackRunBox.TrackRunInfos = truns; | movieFragmentBox.TrackFragmentBox.TrackRunBox.TrackRunInfos = truns; | ||||
movieFragmentBox.ToBuffer(ref writer); | movieFragmentBox.ToBuffer(ref writer); | ||||
var mediaDataBox = new MediaDataBox(); | var mediaDataBox = new MediaDataBox(); | ||||
mediaDataBox.Data = rawdatas; | mediaDataBox.Data = rawdatas; | ||||
mediaDataBox.ToBuffer(ref writer); | mediaDataBox.ToBuffer(ref writer); | ||||
@@ -220,64 +253,10 @@ namespace JT1078.FMp4 | |||||
} | } | ||||
} | } | ||||
/// <summary> | |||||
/// 编码其他视频数据盒子 | |||||
/// </summary> | |||||
/// <returns></returns> | |||||
public byte[] EncoderOtherVideoBox(List<H264NALU> nalus,List<byte[]>samples, List<uint> sampleSizes,uint firstSize,ulong lastTimestamp) | |||||
struct TrackInfo | |||||
{ | { | ||||
byte[] buffer = FMp4ArrayPool.Rent(nalus.Sum(s => s.RawData.Length + s.StartCodePrefix.Length) + 4096); | |||||
FMp4MessagePackWriter writer = new FMp4MessagePackWriter(buffer); | |||||
try | |||||
{ | |||||
var lastNalu = nalus.Last(); | |||||
int iSize = nalus.Where(w => w.DataType == Protocol.Enums.JT1078DataType.视频I帧) | |||||
.Sum(s => s.RawData.Length + s.StartCodePrefix.Length); | |||||
List<int> sizes = new List<int>(); | |||||
sizes.Add(iSize); | |||||
sizes = sizes.Concat(nalus.Where(w => w.DataType != Protocol.Enums.JT1078DataType.视频I帧) | |||||
.Select(s => s.RawData.Length + s.StartCodePrefix.Length).ToList()) | |||||
.ToList(); | |||||
var movieFragmentBox = new MovieFragmentBox(); | |||||
movieFragmentBox.MovieFragmentHeaderBox = new MovieFragmentHeaderBox(); | |||||
movieFragmentBox.MovieFragmentHeaderBox.SequenceNumber = sn++; | |||||
movieFragmentBox.TrackFragmentBox = new TrackFragmentBox(); | |||||
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox = new TrackFragmentHeaderBox(0x2003a); | |||||
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.TrackID = 1; | |||||
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.SampleDescriptionIndex = 1; | |||||
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleDuration = 48000; | |||||
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleSize = firstSize; | |||||
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleFlags = 0x1010000; | |||||
movieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox = new TrackFragmentBaseMediaDecodeTimeBox(); | |||||
movieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox.BaseMediaDecodeTime = lastTimestamp * 1000; | |||||
//trun | |||||
movieFragmentBox.TrackFragmentBox.TrackRunBox = new TrackRunBox(flags: 0x205); | |||||
movieFragmentBox.TrackFragmentBox.TrackRunBox.FirstSampleFlags = 33554432; | |||||
movieFragmentBox.TrackFragmentBox.TrackRunBox.TrackRunInfos = new List<TrackRunBox.TrackRunInfo>(); | |||||
foreach (var size in sizes) | |||||
{ | |||||
movieFragmentBox.TrackFragmentBox.TrackRunBox.TrackRunInfos.Add(new TrackRunBox.TrackRunInfo() | |||||
{ | |||||
SampleSize = (uint)size, | |||||
}); | |||||
} | |||||
movieFragmentBox.ToBuffer(ref writer); | |||||
var mediaDataBox = new MediaDataBox(); | |||||
mediaDataBox.Data = nalus.Select(s => s.RawData).ToList(); | |||||
mediaDataBox.ToBuffer(ref writer); | |||||
var data = writer.FlushAndGetArray(); | |||||
return data; | |||||
} | |||||
finally | |||||
{ | |||||
FMp4ArrayPool.Return(buffer); | |||||
} | |||||
public uint SN { get; set; } | |||||
public ulong DTS { get; set; } | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -27,9 +27,7 @@ | |||||
<PackagePath></PackagePath> | <PackagePath></PackagePath> | ||||
</None> | </None> | ||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | |||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | <ItemGroup> | ||||
<ProjectReference Include="..\JT1078.Protocol\JT1078.Protocol.csproj" /> | <ProjectReference Include="..\JT1078.Protocol\JT1078.Protocol.csproj" /> | ||||
</ItemGroup> | </ItemGroup> | ||||
@@ -1320,6 +1320,11 @@ | |||||
ref: https://www.w3.org/TR/mse-byte-stream-format-isobmff/#movie-fragment-relative-addressing | ref: https://www.w3.org/TR/mse-byte-stream-format-isobmff/#movie-fragment-relative-addressing | ||||
</summary> | </summary> | ||||
</member> | </member> | ||||
<member name="M:JT1078.FMp4.FMp4Encoder.#ctor"> | |||||
<summary> | |||||
</summary> | |||||
</member> | |||||
<member name="M:JT1078.FMp4.FMp4Encoder.EncoderFtypBox"> | <member name="M:JT1078.FMp4.FMp4Encoder.EncoderFtypBox"> | ||||
<summary> | <summary> | ||||
编码ftyp盒子 | 编码ftyp盒子 | ||||
@@ -1332,13 +1337,7 @@ | |||||
</summary> | </summary> | ||||
<returns></returns> | <returns></returns> | ||||
</member> | </member> | ||||
<member name="M:JT1078.FMp4.FMp4Encoder.EncoderOtherVideoBox(System.Collections.Generic.List{JT1078.Protocol.H264.H264NALU})"> | |||||
<summary> | |||||
编码其他视频数据盒子 | |||||
</summary> | |||||
<returns></returns> | |||||
</member> | |||||
<member name="M:JT1078.FMp4.FMp4Encoder.EncoderOtherVideoBox(System.Collections.Generic.List{JT1078.Protocol.H264.H264NALU},System.Collections.Generic.List{System.Byte[]},System.Collections.Generic.List{System.UInt32},System.UInt32,System.UInt64)"> | |||||
<member name="M:JT1078.FMp4.FMp4Encoder.EncoderOtherVideoBox(System.Collections.Generic.List{JT1078.Protocol.H264.H264NALU}@)"> | |||||
<summary> | <summary> | ||||
编码其他视频数据盒子 | 编码其他视频数据盒子 | ||||
</summary> | </summary> | ||||
@@ -40,6 +40,9 @@ namespace JT1078.Flv | |||||
readonly H264Decoder h264Decoder; | readonly H264Decoder h264Decoder; | ||||
readonly AudioCodecFactory audioCodecFactory; | readonly AudioCodecFactory audioCodecFactory; | ||||
//public FlvEncoder(int sampleRate = 8000, int channels = 1, int sampleBit = 16, bool adts = false) | //public FlvEncoder(int sampleRate = 8000, int channels = 1, int sampleBit = 16, bool adts = false) | ||||
/// <summary> | |||||
/// | |||||
/// </summary> | |||||
public FlvEncoder() | public FlvEncoder() | ||||
{ | { | ||||
audioCodecFactory = new AudioCodecFactory(); | audioCodecFactory = new AudioCodecFactory(); | ||||
@@ -181,6 +181,11 @@ | |||||
4、<see cref="M:JT1078.Flv.FlvEncoder.EncoderAudioTag(JT1078.Protocol.JT1078Package,System.Boolean)"/>第二个参数传true | 4、<see cref="M:JT1078.Flv.FlvEncoder.EncoderAudioTag(JT1078.Protocol.JT1078Package,System.Boolean)"/>第二个参数传true | ||||
</summary> | </summary> | ||||
</member> | </member> | ||||
<member name="M:JT1078.Flv.FlvEncoder.#ctor"> | |||||
<summary> | |||||
</summary> | |||||
</member> | |||||
<member name="M:JT1078.Flv.FlvEncoder.EncoderFlvHeader(System.Boolean,System.Boolean)"> | <member name="M:JT1078.Flv.FlvEncoder.EncoderFlvHeader(System.Boolean,System.Boolean)"> | ||||
<summary> | <summary> | ||||
编码flv头 | 编码flv头 | ||||
@@ -90,13 +90,13 @@ namespace JT1078.Hls.Test | |||||
JT1078Package fullpackage = JT1078Serializer.Merge(package); | JT1078Package fullpackage = JT1078Serializer.Merge(package); | ||||
if (fullpackage != null) | if (fullpackage != null) | ||||
{ | { | ||||
var sdt = tSEncoder.CreateSDT(fullpackage); | |||||
var sdt = tSEncoder.CreateSDT(); | |||||
string sdtHEX = sdt.ToHexString(); | string sdtHEX = sdt.ToHexString(); | ||||
fileStream.Write(sdt); | fileStream.Write(sdt); | ||||
var pat = tSEncoder.CreatePAT(fullpackage); | |||||
var pat = tSEncoder.CreatePAT(); | |||||
string patHEX = pat.ToHexString(); | string patHEX = pat.ToHexString(); | ||||
fileStream.Write(pat); | fileStream.Write(pat); | ||||
var pmt = tSEncoder.CreatePMT(fullpackage); | |||||
var pmt = tSEncoder.CreatePMT(); | |||||
fileStream.Write(pmt); | fileStream.Write(pmt); | ||||
var pes = tSEncoder.CreatePES(fullpackage); | var pes = tSEncoder.CreatePES(fullpackage); | ||||
fileStream.Write(pes); | fileStream.Write(pes); | ||||
@@ -139,13 +139,13 @@ namespace JT1078.Hls.Test | |||||
{ | { | ||||
if (isNeedFirstHeadler) | if (isNeedFirstHeadler) | ||||
{ | { | ||||
var sdt = tSEncoder.CreateSDT(fullpackage); | |||||
var sdt = tSEncoder.CreateSDT(); | |||||
string sdtHEX = sdt.ToHexString(); | string sdtHEX = sdt.ToHexString(); | ||||
fileStream.Write(sdt); | fileStream.Write(sdt); | ||||
var pat = tSEncoder.CreatePAT(fullpackage); | |||||
var pat = tSEncoder.CreatePAT(); | |||||
string patHEX = pat.ToHexString(); | string patHEX = pat.ToHexString(); | ||||
fileStream.Write(pat); | fileStream.Write(pat); | ||||
var pmt = tSEncoder.CreatePMT(fullpackage); | |||||
var pmt = tSEncoder.CreatePMT(); | |||||
fileStream.Write(pmt); | fileStream.Write(pmt); | ||||
var pes = tSEncoder.CreatePES(fullpackage, 18888); | var pes = tSEncoder.CreatePES(fullpackage, 18888); | ||||
fileStream.Write(pes); | fileStream.Write(pes); | ||||
@@ -14,7 +14,7 @@ | |||||
<licenseUrl>https://github.com/SmallChi/JT1078/blob/master/LICENSE</licenseUrl> | <licenseUrl>https://github.com/SmallChi/JT1078/blob/master/LICENSE</licenseUrl> | ||||
<license>https://github.com/SmallChi/JT1078/blob/master/LICENSE</license> | <license>https://github.com/SmallChi/JT1078/blob/master/LICENSE</license> | ||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> | <GeneratePackageOnBuild>false</GeneratePackageOnBuild> | ||||
<Version>1.1.0.0</Version> | |||||
<Version>1.1.0-preview3</Version> | |||||
<SignAssembly>false</SignAssembly> | <SignAssembly>false</SignAssembly> | ||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance> | <PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance> | ||||
<PackageLicenseFile>LICENSE</PackageLicenseFile> | <PackageLicenseFile>LICENSE</PackageLicenseFile> | ||||
@@ -96,6 +96,19 @@ | |||||
m3u8文件管理 | m3u8文件管理 | ||||
</summary> | </summary> | ||||
</member> | </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)"> | <member name="M:JT1078.Hls.M3U8FileManage.CreateTsData(JT1078.Protocol.JT1078Package)"> | ||||
<summary> | <summary> | ||||
生成ts和m3u8文件 | 生成ts和m3u8文件 | ||||
@@ -132,6 +145,12 @@ | |||||
<param name="key">终端号_通道号(用作目录)</param> | <param name="key">终端号_通道号(用作目录)</param> | ||||
<param name="data">文件内容</param> | <param name="data">文件内容</param> | ||||
</member> | </member> | ||||
<member name="M:JT1078.Hls.M3U8FileManage.AppendM3U8End"> | |||||
<summary> | |||||
添加结束标识 | |||||
直播流用不到 | |||||
</summary> | |||||
</member> | |||||
<member name="M:JT1078.Hls.M3U8FileManage.Clear(System.String,System.Int32)"> | <member name="M:JT1078.Hls.M3U8FileManage.Clear(System.String,System.Int32)"> | ||||
<summary> | <summary> | ||||
停止观看直播时清零数据 | 停止观看直播时清零数据 | ||||
@@ -273,6 +292,11 @@ | |||||
4.PES | 4.PES | ||||
</summary> | </summary> | ||||
</member> | </member> | ||||
<member name="M:JT1078.Hls.TSEncoder.#ctor"> | |||||
<summary> | |||||
</summary> | |||||
</member> | |||||
<member name="P:JT1078.Hls.TS_AdaptationInfo.PCRIncluded"> | <member name="P:JT1078.Hls.TS_AdaptationInfo.PCRIncluded"> | ||||
<summary> | <summary> | ||||
取0x50表示包含PCR或0x40表示不包含PCR | 取0x50表示包含PCR或0x40表示不包含PCR | ||||
@@ -19,15 +19,28 @@ namespace JT1078.Hls | |||||
public class M3U8FileManage | public class M3U8FileManage | ||||
{ | { | ||||
private TSEncoder tSEncoder; | private TSEncoder tSEncoder; | ||||
public readonly M3U8Option m3U8Option; | |||||
private M3U8Option m3U8Option; | |||||
ConcurrentDictionary<string, TsFileInfo> curTsFileInfoDic = new ConcurrentDictionary<string, TsFileInfo>();//当前文件信息 | ConcurrentDictionary<string, TsFileInfo> curTsFileInfoDic = new ConcurrentDictionary<string, TsFileInfo>();//当前文件信息 | ||||
ConcurrentDictionary<string, Queue<TsFileInfo>> tsFileInfoQueueDic = new ConcurrentDictionary<string, Queue<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) | public M3U8FileManage(M3U8Option m3U8Option, TSEncoder tSEncoder) | ||||
{ | { | ||||
this.tSEncoder = tSEncoder; | this.tSEncoder = tSEncoder; | ||||
this.m3U8Option = m3U8Option; | this.m3U8Option = m3U8Option; | ||||
} | } | ||||
/// <summary> | /// <summary> | ||||
/// 生成ts和m3u8文件 | /// 生成ts和m3u8文件 | ||||
/// </summary> | /// </summary> | ||||
@@ -35,8 +48,8 @@ namespace JT1078.Hls | |||||
public void CreateTsData(JT1078Package jt1078Package) | public void CreateTsData(JT1078Package jt1078Package) | ||||
{ | { | ||||
string key = jt1078Package.GetKey(); | string key = jt1078Package.GetKey(); | ||||
string hlsFileDirectory = m3U8Option.HlsFileDirectory; | |||||
string m3u8FileName = Path.Combine(hlsFileDirectory, key, m3U8Option.M3U8FileName); | |||||
//string hlsFileDirectory = m3U8Option.HlsFileDirectory; | |||||
//string m3u8FileName = Path.Combine(hlsFileDirectory, key, m3U8Option.M3U8FileName); | |||||
var buff = TSArrayPool.Rent(jt1078Package.Bodies.Length + 1024); | var buff = TSArrayPool.Rent(jt1078Package.Bodies.Length + 1024); | ||||
TSMessagePackWriter tSMessagePackWriter = new TSMessagePackWriter(buff); | TSMessagePackWriter tSMessagePackWriter = new TSMessagePackWriter(buff); | ||||
try | try | ||||
@@ -62,11 +75,11 @@ namespace JT1078.Hls | |||||
curTsFileInfo.IsCreateTsFile = false; | curTsFileInfo.IsCreateTsFile = false; | ||||
curTsFileInfo.TsFirst1078PackageTimeStamp = jt1078Package.Timestamp; | curTsFileInfo.TsFirst1078PackageTimeStamp = jt1078Package.Timestamp; | ||||
curTsFileInfo.FileName = $"{curTsFileInfo.TsFileSerialNo}.ts"; | curTsFileInfo.FileName = $"{curTsFileInfo.TsFileSerialNo}.ts"; | ||||
var sdt = tSEncoder.CreateSDT(jt1078Package); | |||||
var sdt = tSEncoder.CreateSDT(); | |||||
tSMessagePackWriter.WriteArray(sdt); | tSMessagePackWriter.WriteArray(sdt); | ||||
var pat = tSEncoder.CreatePAT(jt1078Package); | |||||
var pat = tSEncoder.CreatePAT(); | |||||
tSMessagePackWriter.WriteArray(pat); | tSMessagePackWriter.WriteArray(pat); | ||||
var pmt = tSEncoder.CreatePMT(jt1078Package); | |||||
var pmt = tSEncoder.CreatePMT(); | |||||
tSMessagePackWriter.WriteArray(pmt); | tSMessagePackWriter.WriteArray(pmt); | ||||
var pes = tSEncoder.CreatePES(jt1078Package); | var pes = tSEncoder.CreatePES(jt1078Package); | ||||
tSMessagePackWriter.WriteArray(pes); | tSMessagePackWriter.WriteArray(pes); | ||||
@@ -170,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> | /// <summary> | ||||
/// 停止观看直播时清零数据 | /// 停止观看直播时清零数据 | ||||
@@ -36,12 +36,15 @@ namespace JT1078.Hls | |||||
//todo:音频同步 | //todo:音频同步 | ||||
//private Dictionary<string, byte> AudioCounter = new Dictionary<string, byte>(); | //private Dictionary<string, byte> AudioCounter = new Dictionary<string, byte>(); | ||||
/// <summary> | |||||
/// | |||||
/// </summary> | |||||
public TSEncoder() | public TSEncoder() | ||||
{ | { | ||||
VideoCounter = new Dictionary<string, byte>(StringComparer.OrdinalIgnoreCase); | 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); | byte[] buffer = TSArrayPool.Rent(minBufferSize); | ||||
try | try | ||||
@@ -85,7 +88,7 @@ namespace JT1078.Hls | |||||
TSArrayPool.Return(buffer); | TSArrayPool.Return(buffer); | ||||
} | } | ||||
} | } | ||||
public byte[] CreatePAT(JT1078Package jt1078Package, int minBufferSize = 188) | |||||
public byte[] CreatePAT(int minBufferSize = 188) | |||||
{ | { | ||||
byte[] buffer = TSArrayPool.Rent(minBufferSize); | byte[] buffer = TSArrayPool.Rent(minBufferSize); | ||||
try | try | ||||
@@ -111,7 +114,7 @@ namespace JT1078.Hls | |||||
TSArrayPool.Return(buffer); | TSArrayPool.Return(buffer); | ||||
} | } | ||||
} | } | ||||
public byte[] CreatePMT(JT1078Package jt1078Package, int minBufferSize = 188) | |||||
public byte[] CreatePMT(int minBufferSize = 188) | |||||
{ | { | ||||
byte[] buffer = TSArrayPool.Rent(minBufferSize); | byte[] buffer = TSArrayPool.Rent(minBufferSize); | ||||
try | try | ||||
@@ -139,7 +142,7 @@ namespace JT1078.Hls | |||||
TSArrayPool.Return(buffer); | TSArrayPool.Return(buffer); | ||||
} | } | ||||
} | } | ||||
public byte[] CreatePES(JT1078Package jt1078Package, int minBufferSize = 1024) | |||||
public byte[] CreatePES(in JT1078Package jt1078Package, int minBufferSize = 1024) | |||||
{ | { | ||||
//将1078一帧的数据拆分成一小段一小段的PES包 | //将1078一帧的数据拆分成一小段一小段的PES包 | ||||
byte[] buffer = TSArrayPool.Rent(jt1078Package.Bodies.Length + minBufferSize); | byte[] buffer = TSArrayPool.Rent(jt1078Package.Bodies.Length + minBufferSize); | ||||
@@ -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 == NalUnitType.SPS); | |||||
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)); | |||||
} | |||||
} | |||||
} |