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