Quellcode durchsuchen

fmp4-1.0.0-preview1

master
SmallChi(Koike) vor 4 Jahren
Ursprung
Commit
07e1acbe21
17 geänderte Dateien mit 278 neuen und 327 gelöschten Zeilen
  1. +4
    -0
      src/JT1078.AV.Benchmark/JT1078.AV.Benchmark.csproj
  2. +132
    -0
      src/JT1078.AV.Benchmark/JT1078AVEncoderContext.cs
  3. +0
    -76
      src/JT1078.AV.Benchmark/JT1078FlvEncoderContext.cs
  4. +1
    -1
      src/JT1078.AV.Benchmark/Program.cs
  5. +0
    -2
      src/JT1078.FMp4.Test/H264/mux.min.js
  6. +0
    -47
      src/JT1078.FMp4.Test/JT1078ToFMp4Box_Test.cs
  7. +58
    -79
      src/JT1078.FMp4/FMp4Encoder.cs
  8. +1
    -3
      src/JT1078.FMp4/JT1078.FMp4.csproj
  9. +6
    -7
      src/JT1078.FMp4/JT1078.FMp4.xml
  10. +3
    -0
      src/JT1078.Flv/FlvEncoder.cs
  11. +5
    -0
      src/JT1078.Flv/JT1078.Flv.xml
  12. +6
    -6
      src/JT1078.Hls.Test/TS_Package_Test.cs
  13. +1
    -1
      src/JT1078.Hls/JT1078.Hls.csproj
  14. +24
    -0
      src/JT1078.Hls/JT1078.Hls.xml
  15. +30
    -17
      src/JT1078.Hls/M3U8FileManage.cs
  16. +7
    -4
      src/JT1078.Hls/TSEncoder.cs
  17. +0
    -84
      src/JT1078.Protocol.Benchmark/JT1078FlvEncoderContext.cs

+ 4
- 0
src/JT1078.AV.Benchmark/JT1078.AV.Benchmark.csproj Datei anzeigen

@@ -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 Datei anzeigen

@@ -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));
}
}
}

+ 0
- 76
src/JT1078.AV.Benchmark/JT1078FlvEncoderContext.cs Datei anzeigen

@@ -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));
}
}
}

+ 1
- 1
src/JT1078.AV.Benchmark/Program.cs Datei anzeigen

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

+ 0
- 2
src/JT1078.FMp4.Test/H264/mux.min.js
Datei-Diff unterdrückt, da er zu groß ist
Datei anzeigen


+ 0
- 47
src/JT1078.FMp4.Test/JT1078ToFMp4Box_Test.cs Datei anzeigen

@@ -482,53 +482,6 @@ namespace JT1078.FMp4.Test
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]
public void tkhd_width_height_test()
{


+ 58
- 79
src/JT1078.FMp4/FMp4Encoder.cs Datei anzeigen

@@ -30,6 +30,24 @@ namespace JT1078.FMp4
/// </summary>
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>
/// 编码ftyp盒子
/// </summary>
@@ -66,7 +84,7 @@ namespace JT1078.FMp4
/// <returns></returns>
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);
try
{
@@ -84,7 +102,7 @@ namespace JT1078.FMp4
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;
@@ -126,8 +144,8 @@ namespace JT1078.FMp4
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;
@@ -142,13 +160,11 @@ namespace JT1078.FMp4
}
}

uint sn = 1;

/// <summary>
/// 编码其他视频数据盒子
/// </summary>
/// <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);
FMp4MessagePackWriter writer = new FMp4MessagePackWriter(buffer);
@@ -158,9 +174,14 @@ namespace JT1078.FMp4
List<byte[]> rawdatas = new List<byte[]>();
uint iSize = 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];
if (string.IsNullOrEmpty(key))
{
key = nalu.GetKey();
}
rawdatas.Add(nalu.RawData);
if (nalu.DataType == Protocol.Enums.JT1078DataType.视频I帧)
{
@@ -181,32 +202,44 @@ namespace JT1078.FMp4
SampleSize = (uint)(nalu.RawData.Length + nalu.StartCodePrefix.Length),
});
}
if(i== (nalus.Count - 1))
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();
//todo:SequenceNumber
movieFragmentBox.MovieFragmentHeaderBox.SequenceNumber = sn++;
movieFragmentBox.MovieFragmentHeaderBox.SequenceNumber = trackInfo.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 = 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 = 0x1010000;
movieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleFlags = DefaultSampleFlags;
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
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.ToBuffer(ref writer);
var mediaDataBox = new MediaDataBox();
mediaDataBox.Data = rawdatas;
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; }
}
}
}

+ 1
- 3
src/JT1078.FMp4/JT1078.FMp4.csproj Datei anzeigen

@@ -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>


+ 6
- 7
src/JT1078.FMp4/JT1078.FMp4.xml Datei anzeigen

@@ -1320,6 +1320,11 @@
ref: https://www.w3.org/TR/mse-byte-stream-format-isobmff/#movie-fragment-relative-addressing
</summary>
</member>
<member name="M:JT1078.FMp4.FMp4Encoder.#ctor">
<summary>
</summary>
</member>
<member name="M:JT1078.FMp4.FMp4Encoder.EncoderFtypBox">
<summary>
编码ftyp盒子
@@ -1332,13 +1337,7 @@
</summary>
<returns></returns>
</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>


+ 3
- 0
src/JT1078.Flv/FlvEncoder.cs Datei anzeigen

@@ -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();


+ 5
- 0
src/JT1078.Flv/JT1078.Flv.xml Datei anzeigen

@@ -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头


+ 6
- 6
src/JT1078.Hls.Test/TS_Package_Test.cs Datei anzeigen

@@ -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);


+ 1
- 1
src/JT1078.Hls/JT1078.Hls.csproj Datei anzeigen

@@ -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.0</Version>
<Version>1.1.0-preview3</Version>
<SignAssembly>false</SignAssembly>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<PackageLicenseFile>LICENSE</PackageLicenseFile>


+ 24
- 0
src/JT1078.Hls/JT1078.Hls.xml Datei anzeigen

@@ -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>
停止观看直播时清零数据
@@ -273,6 +292,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


+ 30
- 17
src/JT1078.Hls/M3U8FileManage.cs Datei anzeigen

@@ -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,8 +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);
//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
@@ -62,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);
@@ -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>
/// 停止观看直播时清零数据


+ 7
- 4
src/JT1078.Hls/TSEncoder.cs Datei anzeigen

@@ -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 Datei anzeigen

@@ -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));
}
}
}

Laden…
Abbrechen
Speichern