From e95cb4c3915b087a2277ca6c09e9b47f5eb04927 Mon Sep 17 00:00:00 2001
From: "SmallChi(Koike)" <564952747@qq.com>
Date: Sun, 19 Dec 2021 21:29:27 +0800
Subject: [PATCH] =?UTF-8?q?1.=E5=8D=87=E7=BA=A7net6=202.=E5=AE=8C=E5=96=84?=
=?UTF-8?q?fmp4=E7=BC=96=E7=A0=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.github/workflows/dotnetcore.yml | 2 +-
.../JT1078.AV.Benchmark.csproj | 6 +-
.../JT1078AVEncoderContext.cs | 23 +--
src/JT1078.FMp4.Test/JT1078.FMp4.Test.csproj | 9 +-
src/JT1078.FMp4.Test/JT1078ToFMp4Box_Test.cs | 120 +-------------
.../Boxs/TrackFragmentHeaderBox.cs | 2 +-
src/JT1078.FMp4/FMp4Constants.cs | 27 ++++
src/JT1078.FMp4/FMp4Encoder.cs | 147 +++++++++++-------
src/JT1078.FMp4/JT1078.FMp4.csproj | 4 +-
src/JT1078.FMp4/JT1078.FMp4.xml | 43 ++++-
src/JT1078.Flv.Test/JT1078.Flv.Test.csproj | 6 +-
src/JT1078.Flv/JT1078.Flv.csproj | 6 +-
src/JT1078.Hls.Test/JT1078.Hls.Test.csproj | 8 +-
src/JT1078.Hls/JT1078.Hls.csproj | 6 +-
.../JT1078.Protocol.Benchmark.csproj | 6 +-
.../H264/H264DecoderTest.cs | 1 -
.../JT1078.Protocol.Test.csproj | 6 +-
src/JT1078.Protocol/H264/H264Decoder.cs | 1 -
src/JT1078.Protocol/H264/H264NALU.cs | 6 -
src/JT1078.Protocol/H264/NALUHeader.cs | 3 +
src/JT1078.Protocol/JT1078.Protocol.csproj | 14 +-
src/JT1078.Protocol/JT1078.Protocol.xml | 6 -
.../JT1078.SignalR.Test.csproj | 13 +-
.../Properties/launchSettings.json | 12 ++
.../Services/ToWebSocketService.cs | 61 ++------
src/JT1078.SignalR.Test/Startup.cs | 2 +
.../wwwroot}/index.html | 0
.../wwwroot}/signalr.min.js | 0
28 files changed, 235 insertions(+), 305 deletions(-)
create mode 100644 src/JT1078.SignalR.Test/Properties/launchSettings.json
rename src/{JT1078.FMp4.Test/H264 => JT1078.SignalR.Test/wwwroot}/index.html (100%)
rename src/{JT1078.FMp4.Test/H264 => JT1078.SignalR.Test/wwwroot}/signalr.min.js (100%)
diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml
index 16bd507..599839c 100644
--- a/.github/workflows/dotnetcore.yml
+++ b/.github/workflows/dotnetcore.yml
@@ -12,7 +12,7 @@ jobs:
- name: Setup .NET Core
uses: actions/setup-dotnet@master
with:
- dotnet-version: 5.0.100
+ dotnet-version: 6.0.100
- name: dotnet info
run: dotnet --info
- name: dotnet restore
diff --git a/src/JT1078.AV.Benchmark/JT1078.AV.Benchmark.csproj b/src/JT1078.AV.Benchmark/JT1078.AV.Benchmark.csproj
index 3be58ac..4514a7f 100644
--- a/src/JT1078.AV.Benchmark/JT1078.AV.Benchmark.csproj
+++ b/src/JT1078.AV.Benchmark/JT1078.AV.Benchmark.csproj
@@ -2,11 +2,11 @@
Exe
- net5.0
+ net6.0
-
-
+
+
diff --git a/src/JT1078.AV.Benchmark/JT1078AVEncoderContext.cs b/src/JT1078.AV.Benchmark/JT1078AVEncoderContext.cs
index 8d17f76..7814f6f 100644
--- a/src/JT1078.AV.Benchmark/JT1078AVEncoderContext.cs
+++ b/src/JT1078.AV.Benchmark/JT1078AVEncoderContext.cs
@@ -72,24 +72,6 @@ namespace JT1078.AV.Benchmark
break;
}
List 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(nalus);
- segmentFlag = true;
- nalus.Clear();
- }
- nalus.Add(nalu);
- }
- }
}
}
@@ -117,7 +99,8 @@ namespace JT1078.AV.Benchmark
{
for (var i = 0; i < N; i++)
{
- var buffer = fmp4Encoder.OtherVideoBox(FMp4H264NALUs);
+ //todo:OtherVideoBox
+ //var buffer = fmp4Encoder.OtherVideoBox(FMp4H264NALUs);
}
}
}
@@ -126,7 +109,7 @@ namespace JT1078.AV.Benchmark
{
public JT1078AVEncoderConfig()
{
- AddJob(Job.Default.WithGcServer(false).WithToolchain(CsProjCoreToolchain.NetCoreApp50).WithPlatform(Platform.AnyCpu));
+ AddJob(Job.Default.WithGcServer(false).WithToolchain(CsProjCoreToolchain.NetCoreApp60).WithPlatform(Platform.AnyCpu));
}
}
}
diff --git a/src/JT1078.FMp4.Test/JT1078.FMp4.Test.csproj b/src/JT1078.FMp4.Test/JT1078.FMp4.Test.csproj
index cd08fb6..0ec67af 100644
--- a/src/JT1078.FMp4.Test/JT1078.FMp4.Test.csproj
+++ b/src/JT1078.FMp4.Test/JT1078.FMp4.Test.csproj
@@ -1,19 +1,19 @@
- net5.0
+ net6.0
false
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
@@ -39,9 +39,6 @@
Always
-
-
- Always
diff --git a/src/JT1078.FMp4.Test/JT1078ToFMp4Box_Test.cs b/src/JT1078.FMp4.Test/JT1078ToFMp4Box_Test.cs
index 14d1bbe..9a42c52 100644
--- a/src/JT1078.FMp4.Test/JT1078ToFMp4Box_Test.cs
+++ b/src/JT1078.FMp4.Test/JT1078ToFMp4Box_Test.cs
@@ -438,107 +438,11 @@ namespace JT1078.FMp4.Test
[Fact]
public void Test4()
- {
- FMp4Encoder fMp4Encoder = new FMp4Encoder();
- H264Decoder h264Decoder = new H264Decoder();
- var packages = ParseNALUTests();
- 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 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 nalus = new List();
- foreach (var package in packages)
- {
- List 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 nalus = new List();
- foreach (var package in packages)
- {
- List 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.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");
+ var filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_7_3.mp4");
if (File.Exists(filepath))
{
File.Delete(filepath);
@@ -551,38 +455,30 @@ namespace JT1078.FMp4.Test
var iPackage = packages.FirstOrDefault(f => f.Label3.DataType == JT1078DataType.视频I帧);
var iNalus = h264Decoder.ParseNALU(iPackage);
//判断第一帧是否关键帧
- var moov = fMp4Encoder.VideoMoovBox(
+ var moov = fMp4Encoder.MoovBox(
iNalus.FirstOrDefault(f => f.NALUHeader.NalUnitType == NalUnitType.SPS),
iNalus.FirstOrDefault(f => f.NALUHeader.NalUnitType == NalUnitType.PPS));
fileStream.Write(moov);
-
- List nalus = new List();
+ List tmp = new List();
foreach (var package in packages)
{
- List h264NALUs = h264Decoder.ParseNALU(package);
if (package.Label3.DataType == Protocol.Enums.JT1078DataType.视频I帧)
{
- if (nalus.Count > 0)
+ if (tmp.Count>0)
{
fileStream.Write(fMp4Encoder.StypBox());
- var otherBuffer = fMp4Encoder.OtherVideoBox(nalus);
+ var otherBuffer = fMp4Encoder.OtherVideoBox(tmp);
fileStream.Write(otherBuffer);
- nalus.Clear();
+ tmp.Clear();
}
}
- nalus = nalus.Concat(h264NALUs).ToList();
- }
- if (nalus.Count > 0)
- {
- var otherBuffer = fMp4Encoder.OtherVideoBox(nalus);
- fileStream.Write(otherBuffer);
- nalus.Clear();
+ tmp.Add(package);
}
fileStream.Close();
}
[Fact]
- public void Test6_2()
+ public void Test4_2()
{
var filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_7.h264");
if (File.Exists(filepath))
diff --git a/src/JT1078.FMp4/Boxs/TrackFragmentHeaderBox.cs b/src/JT1078.FMp4/Boxs/TrackFragmentHeaderBox.cs
index 55e7e62..f185006 100644
--- a/src/JT1078.FMp4/Boxs/TrackFragmentHeaderBox.cs
+++ b/src/JT1078.FMp4/Boxs/TrackFragmentHeaderBox.cs
@@ -49,7 +49,7 @@ namespace JT1078.FMp4
public uint DefaultSampleSize { get; set; }
///
/// TFHD_FLAG_DEFAULT_FLAGS
- /// MOV_AUDIO == handler_type ? 0x02000000 : (0x00010000| 0x01000000);
+ /// MOV_AUDIO == handler_type ? TFHD_FLAG_AUDIO_TPYE : TFHD_FLAG_VIDEO_TPYE;
///
public uint DefaultSampleFlags { get; set; }
#endregion
diff --git a/src/JT1078.FMp4/FMp4Constants.cs b/src/JT1078.FMp4/FMp4Constants.cs
index a3dc2ea..b98c160 100644
--- a/src/JT1078.FMp4/FMp4Constants.cs
+++ b/src/JT1078.FMp4/FMp4Constants.cs
@@ -18,6 +18,25 @@ namespace JT1078.FMp4
///
public static readonly DateTime UTCBaseTime = new DateTime(1904, 1, 1);
///
+ /// fmp4 FLAG_SEGMENT
+ ///
+ public const int FLAG_SEGMENT = 0x00000002;
+ ///
+ /// key frame
+ ///
+
+ public const int AV_FLAG_KEYFREAME = 0x0001;
+ ///
+ /// I frame
+ ///
+
+ public const int TREX_FLAG_SAMPLE_DEPENDS_ON_I_PICTURE = 0x02000000;
+ ///
+ /// p b frame
+ ///
+
+ public const int TREX_FLAG_SAMPLE_DEPENDS_ON_NOT_I_PICTURE = 0x01000000;
+ ///
/// TKHD_FLAG_ENABLED
///
public const int TKHD_FLAG_ENABLED = 0x000001;
@@ -38,6 +57,14 @@ namespace JT1078.FMp4
///
public const int TFHD_FLAG_SAMPLE_DESCRIPTION_INDEX = 0x00000002;
///
+ /// TFHD_FLAG_AUDIO_TPYE
+ ///
+ public const int TFHD_FLAG_AUDIO_TPYE = 0x02000000;
+ ///
+ /// TFHD_FLAG_VIDEO_TPYE
+ ///
+ public const int TFHD_FLAG_VIDEO_TPYE = (0x00010000| 0x01000000);
+ ///
/// TFHD_FLAG_SAMPLE_DUR
///
public const int TFHD_FLAG_DEFAULT_DURATION = 0x00000008;
diff --git a/src/JT1078.FMp4/FMp4Encoder.cs b/src/JT1078.FMp4/FMp4Encoder.cs
index 6c613db..016c9a0 100644
--- a/src/JT1078.FMp4/FMp4Encoder.cs
+++ b/src/JT1078.FMp4/FMp4Encoder.cs
@@ -19,28 +19,36 @@ namespace JT1078.FMp4
/// ftyp
/// moov
/// styp 1
+ /// sidx 1
/// moof 1
/// mdat 1
/// ...
/// styp n
+ /// sidx n
/// moof n
/// mdat n
- /// mfra
/// ref: https://www.w3.org/TR/mse-byte-stream-format-isobmff/#movie-fragment-relative-addressing
///
public class FMp4Encoder
{
Dictionary 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 TfhdFlags = FMp4Constants.TFHD_FLAG_DEFAULT_BASE_IS_MOOF |
+ FMp4Constants.TFHD_FLAG_DEFAULT_SIZE|
+ FMp4Constants.TFHD_FLAG_SAMPLE_DESCRIPTION_INDEX|
+ FMp4Constants.TFHD_FLAG_DEFAULT_FLAGS;
+
+ const uint TrunFlags = FMp4Constants.TRUN_FLAG_DATA_OFFSET_PRESENT|
+ FMp4Constants.TRUN_FLAG_FIRST_SAMPLE_FLAGS_PRESENT|
+ FMp4Constants.TRUN_FLAG_SAMPLE_DURATION_PRESENT|
+ FMp4Constants.TRUN_FLAG_SAMPLE_SIZE_PRESENT;
+
const uint SampleDescriptionIndex = 1;
+
const uint TrackID = 1;
+ H264Decoder h264Decoder = new H264Decoder();
+
///
///
///
@@ -61,13 +69,15 @@ namespace JT1078.FMp4
{
//ftyp
FileTypeBox fileTypeBox = new FileTypeBox();
- fileTypeBox.MajorBrand = "isom";
- fileTypeBox.MinorVersion = "\0\0\u0002\0";
+ fileTypeBox.MajorBrand = "msdh";
+ fileTypeBox.MinorVersion = "\0\0\0\0";
fileTypeBox.CompatibleBrands.Add("isom");
- fileTypeBox.CompatibleBrands.Add("iso2");
- fileTypeBox.CompatibleBrands.Add("avc1");
- fileTypeBox.CompatibleBrands.Add("mp41");
+ fileTypeBox.CompatibleBrands.Add("mp42");
+ fileTypeBox.CompatibleBrands.Add("msdh");
+ fileTypeBox.CompatibleBrands.Add("msix");
+ // default‐base is‐moof flag
fileTypeBox.CompatibleBrands.Add("iso5");
+ // styp
fileTypeBox.CompatibleBrands.Add("iso6");
fileTypeBox.ToBuffer(ref writer);
var data = writer.FlushAndGetArray();
@@ -83,7 +93,7 @@ namespace JT1078.FMp4
/// 编码moov盒子
///
///
- public byte[] VideoMoovBox(in H264NALU sps, in H264NALU pps)
+ public byte[] MoovBox(in H264NALU sps, in H264NALU pps)
{
byte[] buffer = FMp4ArrayPool.Rent(sps.RawData.Length + pps.RawData.Length + 1024);
FMp4MessagePackWriter writer = new FMp4MessagePackWriter(buffer);
@@ -112,7 +122,6 @@ 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 = 1000;
movieBox.TrackBox.MediaBox.MediaHeaderBox.Duration = 0;
movieBox.TrackBox.MediaBox.HandlerBox = new HandlerBox();
@@ -173,7 +182,7 @@ namespace JT1078.FMp4
try
{
SegmentTypeBox stypTypeBox = new SegmentTypeBox();
- stypTypeBox.MajorBrand = "isom";
+ stypTypeBox.MajorBrand = "msdh";
stypTypeBox.MinorVersion = "\0\0\0\0";
stypTypeBox.CompatibleBrands.Add("isom");
stypTypeBox.CompatibleBrands.Add("mp42");
@@ -193,19 +202,22 @@ namespace JT1078.FMp4
///
/// 编码其他视频数据盒子
+ /// 注意:固定I帧解析
+ /// I P P P P I P P P P I P P P P
+ /// todo:50ms或者一个关键帧进行切片
+ /// todo:优化编码
///
///
- public byte[] OtherVideoBox(in List nalus)
+ public byte[] OtherVideoBox(in List nalus)
{
- byte[] buffer = FMp4ArrayPool.Rent(nalus.Sum(s => s.RawData.Length + s.StartCodePrefix.Length) + 4096);
+ byte[] buffer = FMp4ArrayPool.Rent(nalus.Sum(s => s.Bodies.Length) + 4096);
FMp4MessagePackWriter writer = new FMp4MessagePackWriter(buffer);
try
{
var truns = new List();
- List rawdatas = new List();
- uint iSize = 0;
- ulong lastTimestamp = 0;
string key = string.Empty;
+ ulong timestamp = 0;
+ uint subsegmentDuration=0;
for (var i = 0; i < nalus.Count; i++)
{
var nalu = nalus[i];
@@ -213,46 +225,44 @@ namespace JT1078.FMp4
{
key = nalu.GetKey();
}
- rawdatas.Add(nalu.RawData);
- if (nalu.DataType == Protocol.Enums.JT1078DataType.视频I帧)
+ uint duration = 0;
+ if (timestamp>0)
{
- 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),
- });
+ duration=(uint)(nalu.Timestamp-timestamp);
}
- if (i == (nalus.Count - 1))
+ truns.Add(new TrackRunBox.TrackRunInfo()
{
- lastTimestamp = nalu.Timestamp;
- }
+ SampleDuration = duration,
+ SampleSize = (uint)(nalu.Bodies.Length),
+ });
+ subsegmentDuration+=duration;
+ timestamp=nalu.Timestamp;
}
- if (TrackInfos.TryGetValue(key, out TrackInfo trackInfo))
+ if (!TrackInfos.TryGetValue(key, out TrackInfo trackInfo))
{
- if (trackInfo.SN == uint.MaxValue)
- {
- trackInfo.SN = 1;
- }
- trackInfo.SN++;
+ trackInfo = new TrackInfo { SN = 1, DTS = 0, SubsegmentDuration=0 };
+ TrackInfos.Add(key, trackInfo);
}
- else
+ if (trackInfo.SN == uint.MaxValue)
{
- trackInfo = new TrackInfo { SN = 1, DTS = 0 };
- TrackInfos.Add(key, trackInfo);
+ trackInfo.SN = 1;
}
+ trackInfo.SN++;
+ SegmentIndexBox segmentIndexBox = new SegmentIndexBox(1);
+ segmentIndexBox.ReferenceID = 1;
+ segmentIndexBox.EarliestPresentationTime = trackInfo.SubsegmentDuration;
+ segmentIndexBox.SegmentIndexs = new List()
+ {
+ new SegmentIndexBox.SegmentIndex
+ {
+ SubsegmentDuration=subsegmentDuration
+ }
+ };
+
+ segmentIndexBox.ToBuffer(ref writer);
+
+ var current1 = writer.GetCurrentPosition();
+ //moof
var movieFragmentBox = new MovieFragmentBox();
movieFragmentBox.MovieFragmentHeaderBox = new MovieFragmentHeaderBox();
movieFragmentBox.MovieFragmentHeaderBox.SequenceNumber = trackInfo.SN;
@@ -260,23 +270,39 @@ namespace JT1078.FMp4
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.TrackFragmentHeaderBox.DefaultSampleFlags = FMp4Constants.TFHD_FLAG_VIDEO_TPYE;
movieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox = new TrackFragmentBaseMediaDecodeTimeBox();
- movieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox.BaseMediaDecodeTime = trackInfo.DTS;
- trackInfo.DTS += (ulong)(truns.Count * DefaultSampleDuration);
+ movieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox.BaseMediaDecodeTime = trackInfo.SubsegmentDuration;
+ trackInfo.SubsegmentDuration+=subsegmentDuration;
TrackInfos[key] = trackInfo;
//trun
- movieFragmentBox.TrackFragmentBox.TrackRunBox = new TrackRunBox(flags: TrunFlags);
- movieFragmentBox.TrackFragmentBox.TrackRunBox.FirstSampleFlags = FirstSampleFlags;
+ movieFragmentBox.TrackFragmentBox.TrackRunBox = new TrackRunBox(1, flags: TrunFlags);
+ movieFragmentBox.TrackFragmentBox.TrackRunBox.FirstSampleFlags = FMp4Constants.TREX_FLAG_SAMPLE_DEPENDS_ON_I_PICTURE;
movieFragmentBox.TrackFragmentBox.TrackRunBox.TrackRunInfos = truns;
movieFragmentBox.ToBuffer(ref writer);
-
+ //mdat
var mediaDataBox = new MediaDataBox();
- mediaDataBox.Data = rawdatas;
+ mediaDataBox.Data=new List();
+ foreach(var nalu in nalus)
+ {
+ List h264NALUs = h264Decoder.ParseNALU(nalu);
+ if (h264NALUs!=null)
+ {
+ foreach(var n in h264NALUs)
+ {
+ mediaDataBox.Data.Add(n.RawData);
+ }
+ }
+ }
mediaDataBox.ToBuffer(ref writer);
+ var current2 = writer.GetCurrentPosition();
+ foreach (var postion in segmentIndexBox.ReferencedSizePositions)
+ {
+ writer.WriteUInt32Return((uint)(current2 - current1), postion);
+ }
+
var data = writer.FlushAndGetArray();
return data;
}
@@ -290,6 +316,7 @@ namespace JT1078.FMp4
{
public uint SN { get; set; }
public ulong DTS { get; set; }
+ public ulong SubsegmentDuration { get; set; }
}
}
}
diff --git a/src/JT1078.FMp4/JT1078.FMp4.csproj b/src/JT1078.FMp4/JT1078.FMp4.csproj
index 841bb84..4cd9189 100644
--- a/src/JT1078.FMp4/JT1078.FMp4.csproj
+++ b/src/JT1078.FMp4/JT1078.FMp4.csproj
@@ -1,8 +1,8 @@
- netstandard2.0;netstandard2.1;net5.0;
- 8.0
+ net6.0
+ 10.0
Copyright 2019.
SmallChi(Koike)
JT1078.FMp4
diff --git a/src/JT1078.FMp4/JT1078.FMp4.xml b/src/JT1078.FMp4/JT1078.FMp4.xml
index 0c58fb6..1da81b3 100644
--- a/src/JT1078.FMp4/JT1078.FMp4.xml
+++ b/src/JT1078.FMp4/JT1078.FMp4.xml
@@ -983,7 +983,7 @@
TFHD_FLAG_DEFAULT_FLAGS
- MOV_AUDIO == handler_type ? 0x02000000 : (0x00010000| 0x01000000);
+ MOV_AUDIO == handler_type ? TFHD_FLAG_AUDIO_TPYE : TFHD_FLAG_VIDEO_TPYE;
@@ -1222,6 +1222,26 @@
+
+
+ fmp4 FLAG_SEGMENT
+
+
+
+
+ key frame
+
+
+
+
+ I frame
+
+
+
+
+ p b frame
+
+
TKHD_FLAG_ENABLED
@@ -1247,6 +1267,16 @@
TFHD_FLAG_SAMPLE_DESC
+
+
+ TFHD_FLAG_AUDIO_TPYE
+
+
+
+
+ TFHD_FLAG_VIDEO_TPYE
+
+
TFHD_FLAG_SAMPLE_DUR
@@ -1310,13 +1340,14 @@
ftyp
moov
styp 1
+ sidx 1
moof 1
mdat 1
...
styp n
+ sidx n
moof n
mdat n
- mfra
ref: https://www.w3.org/TR/mse-byte-stream-format-isobmff/#movie-fragment-relative-addressing
@@ -1331,7 +1362,7 @@
-
+
编码moov盒子
@@ -1343,9 +1374,13 @@
-
+
编码其他视频数据盒子
+ 注意:固定I帧解析
+ I P P P P I P P P P I P P P P
+ todo:50ms或者一个关键帧进行切片
+ todo:优化编码
diff --git a/src/JT1078.Flv.Test/JT1078.Flv.Test.csproj b/src/JT1078.Flv.Test/JT1078.Flv.Test.csproj
index 884e4f6..86f2a7d 100644
--- a/src/JT1078.Flv.Test/JT1078.Flv.Test.csproj
+++ b/src/JT1078.Flv.Test/JT1078.Flv.Test.csproj
@@ -1,17 +1,17 @@
- net5.0
+ net6.0
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/src/JT1078.Flv/JT1078.Flv.csproj b/src/JT1078.Flv/JT1078.Flv.csproj
index e31f26a..a4bbe54 100644
--- a/src/JT1078.Flv/JT1078.Flv.csproj
+++ b/src/JT1078.Flv/JT1078.Flv.csproj
@@ -1,8 +1,8 @@
- netstandard2.0;netstandard2.1;net5.0;
- 8.0
+ net6.0
+ 10.0
Copyright 2019.
SmallChi(Koike)
JT1078.Flv
@@ -35,6 +35,6 @@
-
+
diff --git a/src/JT1078.Hls.Test/JT1078.Hls.Test.csproj b/src/JT1078.Hls.Test/JT1078.Hls.Test.csproj
index 7ecdf8d..00eb0f7 100644
--- a/src/JT1078.Hls.Test/JT1078.Hls.Test.csproj
+++ b/src/JT1078.Hls.Test/JT1078.Hls.Test.csproj
@@ -1,7 +1,7 @@
- net5.0
+ net6.0
false
@@ -15,14 +15,14 @@
-
-
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/src/JT1078.Hls/JT1078.Hls.csproj b/src/JT1078.Hls/JT1078.Hls.csproj
index 92fd5c9..37da138 100644
--- a/src/JT1078.Hls/JT1078.Hls.csproj
+++ b/src/JT1078.Hls/JT1078.Hls.csproj
@@ -1,8 +1,8 @@
- netstandard2.0;netstandard2.1;net5.0;
- 8.0
+ net6.0
+ 10.0
Copyright 2019.
SmallChi(Koike)
JT1078.Hls
@@ -31,7 +31,7 @@
-
+
diff --git a/src/JT1078.Protocol.Benchmark/JT1078.Protocol.Benchmark.csproj b/src/JT1078.Protocol.Benchmark/JT1078.Protocol.Benchmark.csproj
index 2b04df4..b05c7e4 100644
--- a/src/JT1078.Protocol.Benchmark/JT1078.Protocol.Benchmark.csproj
+++ b/src/JT1078.Protocol.Benchmark/JT1078.Protocol.Benchmark.csproj
@@ -2,15 +2,15 @@
Exe
- net5.0
+ net6.0
true
-
-
+
+
diff --git a/src/JT1078.Protocol.Test/H264/H264DecoderTest.cs b/src/JT1078.Protocol.Test/H264/H264DecoderTest.cs
index 25d1456..00aa8ee 100644
--- a/src/JT1078.Protocol.Test/H264/H264DecoderTest.cs
+++ b/src/JT1078.Protocol.Test/H264/H264DecoderTest.cs
@@ -135,7 +135,6 @@ namespace JT1078.Protocol.Test.H264
nALUs = nALUs.Concat(nalus).ToList();
}
}
- var a = nALUs.Count(c => !c.Slice);
}
}
}
diff --git a/src/JT1078.Protocol.Test/JT1078.Protocol.Test.csproj b/src/JT1078.Protocol.Test/JT1078.Protocol.Test.csproj
index 3edd26f..291f022 100644
--- a/src/JT1078.Protocol.Test/JT1078.Protocol.Test.csproj
+++ b/src/JT1078.Protocol.Test/JT1078.Protocol.Test.csproj
@@ -1,14 +1,14 @@
- net5.0
+ net6.0
false
-
-
+
+
all
diff --git a/src/JT1078.Protocol/H264/H264Decoder.cs b/src/JT1078.Protocol/H264/H264Decoder.cs
index 2b192e9..d67ed35 100644
--- a/src/JT1078.Protocol/H264/H264Decoder.cs
+++ b/src/JT1078.Protocol/H264/H264Decoder.cs
@@ -134,7 +134,6 @@ 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)
{
diff --git a/src/JT1078.Protocol/H264/H264NALU.cs b/src/JT1078.Protocol/H264/H264NALU.cs
index 5da6351..f85ee7f 100644
--- a/src/JT1078.Protocol/H264/H264NALU.cs
+++ b/src/JT1078.Protocol/H264/H264NALU.cs
@@ -40,12 +40,6 @@ namespace JT1078.Protocol.H264
/// 当数据类型为01000时,则没有该字段
///
public ulong Timestamp { get; set; }
-
- ///
- /// 是否切片 0x80
- /// H264 NALU slice first_mb_in_slice
- ///
- public bool Slice { get; set; }
///
/// 数据体
///
diff --git a/src/JT1078.Protocol/H264/NALUHeader.cs b/src/JT1078.Protocol/H264/NALUHeader.cs
index 682c014..05370b2 100644
--- a/src/JT1078.Protocol/H264/NALUHeader.cs
+++ b/src/JT1078.Protocol/H264/NALUHeader.cs
@@ -11,16 +11,19 @@ namespace JT1078.Protocol.H264
ForbiddenZeroBit = (value & 0x80) >> 7;
NalRefIdc = (value & 0x60) >> 5;
NalUnitType = (NalUnitType)(value & 0x1f);
+ KeyFrame=NalUnitType== NalUnitType.IDR;
}
public NALUHeader(ReadOnlySpan value)
{
ForbiddenZeroBit = (value[0] & 0x80) >> 7;
NalRefIdc = (value[0] & 0x60) >> 5;
NalUnitType = (NalUnitType)(value[0] & 0x1f);
+ KeyFrame=NalUnitType== NalUnitType.IDR;
}
public int ForbiddenZeroBit { get; set; }
public int NalRefIdc { get; set; }
public NalUnitType NalUnitType { get; set; }
+ public bool KeyFrame { get; set; }
}
public enum NalUnitType : int
diff --git a/src/JT1078.Protocol/JT1078.Protocol.csproj b/src/JT1078.Protocol/JT1078.Protocol.csproj
index f4c10e9..e2551a9 100644
--- a/src/JT1078.Protocol/JT1078.Protocol.csproj
+++ b/src/JT1078.Protocol/JT1078.Protocol.csproj
@@ -1,8 +1,8 @@
- netstandard2.0;netstandard2.1;net5.0;
- 8.0
+ net6.0
+ 10.0
Copyright 2019.
SmallChi(Koike)
JT1078
@@ -21,12 +21,6 @@
JT1078.Protocol.xml
-
-
-
-
-
-
@@ -37,8 +31,4 @@
-
-
-
-
diff --git a/src/JT1078.Protocol/JT1078.Protocol.xml b/src/JT1078.Protocol/JT1078.Protocol.xml
index a2ee901..9b03473 100644
--- a/src/JT1078.Protocol/JT1078.Protocol.xml
+++ b/src/JT1078.Protocol/JT1078.Protocol.xml
@@ -176,12 +176,6 @@
当数据类型为01000时,则没有该字段
-
-
- 是否切片 0x80
- H264 NALU slice first_mb_in_slice
-
-
数据体
diff --git a/src/JT1078.SignalR.Test/JT1078.SignalR.Test.csproj b/src/JT1078.SignalR.Test/JT1078.SignalR.Test.csproj
index 9860de1..c82ee2d 100644
--- a/src/JT1078.SignalR.Test/JT1078.SignalR.Test.csproj
+++ b/src/JT1078.SignalR.Test/JT1078.SignalR.Test.csproj
@@ -1,9 +1,14 @@
- net5.0
+ net6.0
+
+
+
+
+
@@ -26,5 +31,11 @@
Always
+
+ Always
+
+
+ Always
+
diff --git a/src/JT1078.SignalR.Test/Properties/launchSettings.json b/src/JT1078.SignalR.Test/Properties/launchSettings.json
new file mode 100644
index 0000000..3859d38
--- /dev/null
+++ b/src/JT1078.SignalR.Test/Properties/launchSettings.json
@@ -0,0 +1,12 @@
+{
+ "profiles": {
+ "JT1078.SignalR.Test": {
+ "commandName": "Project",
+ "launchBrowser": true,
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ },
+ "applicationUrl": "http://localhost:5000/"
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/JT1078.SignalR.Test/Services/ToWebSocketService.cs b/src/JT1078.SignalR.Test/Services/ToWebSocketService.cs
index 36c465f..d14ca94 100644
--- a/src/JT1078.SignalR.Test/Services/ToWebSocketService.cs
+++ b/src/JT1078.SignalR.Test/Services/ToWebSocketService.cs
@@ -52,20 +52,11 @@ namespace JT1078.SignalR.Test.Services
public void a()
{
List packages = new List();
- //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);
@@ -75,61 +66,31 @@ namespace JT1078.SignalR.Test.Services
}
}
List first = new List();
- //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(
+ var moov = fMp4Encoder.MoovBox(
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 filter = new List() { NalUnitType.SEI,NalUnitType.SPS,NalUnitType.PPS,NalUnitType.AUD};
- List nalus = new List();
+ List tmp = new List();
+ //缓存组包到下一个I帧
foreach (var package in packages)
{
- List 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 (package.Label3.DataType == Protocol.Enums.JT1078DataType.视频I帧)
{
- if (nalu.Slice)
- {
- //H264 NALU slice first_mb_in_slice
- nalus.Add(nalu);
- }
- else
+ if (tmp.Count>0)
{
- if (nalus.Count > 0)
- {
- q.Add(fMp4Encoder.StypBox());
- var otherBuffer = fMp4Encoder.OtherVideoBox(nalus);
- q.Add(otherBuffer);
- nalus.Clear();
- }
- nalus.Add(nalu);
+ List buffer = new List();
+ buffer.Add(fMp4Encoder.StypBox());
+ buffer.Add(fMp4Encoder.OtherVideoBox(tmp));
+ q.Add(buffer.SelectMany(s => s).ToArray());
+ tmp.Clear();
}
}
+ tmp.Add(package);
}
}
diff --git a/src/JT1078.SignalR.Test/Startup.cs b/src/JT1078.SignalR.Test/Startup.cs
index 0e70236..0a47cbd 100644
--- a/src/JT1078.SignalR.Test/Startup.cs
+++ b/src/JT1078.SignalR.Test/Startup.cs
@@ -50,6 +50,8 @@ namespace JT1078.SignalR.Test
{
app.UseDeveloperExceptionPage();
}
+ app.UseDefaultFiles();
+ app.UseStaticFiles();
app.UseRouting();
app.UseCors("CorsPolicy");
app.UseAuthorization();
diff --git a/src/JT1078.FMp4.Test/H264/index.html b/src/JT1078.SignalR.Test/wwwroot/index.html
similarity index 100%
rename from src/JT1078.FMp4.Test/H264/index.html
rename to src/JT1078.SignalR.Test/wwwroot/index.html
diff --git a/src/JT1078.FMp4.Test/H264/signalr.min.js b/src/JT1078.SignalR.Test/wwwroot/signalr.min.js
similarity index 100%
rename from src/JT1078.FMp4.Test/H264/signalr.min.js
rename to src/JT1078.SignalR.Test/wwwroot/signalr.min.js