diff --git a/src/JT1078.FMp4.Test/JT1078ToFMp4Box_Test.cs b/src/JT1078.FMp4.Test/JT1078ToFMp4Box_Test.cs index f9333e7..5cfa354 100644 --- a/src/JT1078.FMp4.Test/JT1078ToFMp4Box_Test.cs +++ b/src/JT1078.FMp4.Test/JT1078ToFMp4Box_Test.cs @@ -4,6 +4,7 @@ using JT1078.FMp4.Samples; using JT1078.Protocol; using JT1078.Protocol.Extensions; using JT1078.Protocol.H264; +using JT1078.Protocol.MessagePack; using System; using System.Buffers.Binary; using System.Collections.Generic; @@ -166,6 +167,269 @@ namespace JT1078.FMp4.Test fileStream.Close(); } + [Fact] + public void Test2() + { + var jT1078Package = ParseNALUTest(); + H264Decoder decoder = new H264Decoder(); + var nalus = decoder.ParseNALU(jT1078Package); + var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 7); + //SPS + spsNALU.RawData = decoder.DiscardEmulationPreventionBytes(spsNALU.RawData); + var ppsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 8); + ppsNALU.RawData = decoder.DiscardEmulationPreventionBytes(ppsNALU.RawData); + FMp4MessagePackWriter writer = new FMp4MessagePackWriter(new byte[65535]); + //ftyp + FileTypeBox fileTypeBox = new FileTypeBox(); + fileTypeBox.MajorBrand = "isom"; + fileTypeBox.MinorVersion = "\0\0\u0002\0"; + fileTypeBox.CompatibleBrands.Add("isom"); + fileTypeBox.CompatibleBrands.Add("iso6"); + fileTypeBox.CompatibleBrands.Add("iso2"); + fileTypeBox.CompatibleBrands.Add("avc1"); + fileTypeBox.CompatibleBrands.Add("mp41"); + //moov + MovieBox movieBox = new MovieBox(); + movieBox.MovieHeaderBox = new MovieHeaderBox(0, 0); + movieBox.MovieHeaderBox.CreationTime = 0; + movieBox.MovieHeaderBox.ModificationTime = 0; + movieBox.MovieHeaderBox.Duration = 0; + movieBox.MovieHeaderBox.Timescale = 1000; + movieBox.MovieHeaderBox.NextTrackID = 2; + movieBox.TrackBox = new TrackBox(); + 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.Duration = 0; + movieBox.TrackBox.TrackHeaderBox.TrackIsAudio = false; + movieBox.TrackBox.TrackHeaderBox.Width = 352; + movieBox.TrackBox.TrackHeaderBox.Height = 288; + movieBox.TrackBox.MediaBox = new MediaBox(); + 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.Duration = 0; + movieBox.TrackBox.MediaBox.HandlerBox = new HandlerBox(); + movieBox.TrackBox.MediaBox.HandlerBox.HandlerType = HandlerType.vide; + movieBox.TrackBox.MediaBox.HandlerBox.Name = "VideoHandler"; + movieBox.TrackBox.MediaBox.MediaInformationBox = new MediaInformationBox(); + movieBox.TrackBox.MediaBox.MediaInformationBox.VideoMediaHeaderBox = new VideoMediaHeaderBox(); + movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox = new DataInformationBox(); + movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox.DataReferenceBox = new DataReferenceBox(); + movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox.DataReferenceBox.DataEntryBoxes = new List(); + movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox.DataReferenceBox.DataEntryBoxes.Add(new DataEntryUrlBox(1)); + movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox = new SampleTableBox(); + movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox = new SampleDescriptionBox(movieBox.TrackBox.MediaBox.HandlerBox.HandlerType); + movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox.SampleEntries = new List(); + AVC1SampleEntry avc1 = new AVC1SampleEntry(); + avc1.AVCConfigurationBox = new AVCConfigurationBox(); + //h264 + avc1.Width = (ushort)movieBox.TrackBox.TrackHeaderBox.Width; + avc1.Height = (ushort)movieBox.TrackBox.TrackHeaderBox.Height; + avc1.AVCConfigurationBox.AVCLevelIndication = 20; + avc1.AVCConfigurationBox.AVCProfileIndication = 77; + avc1.AVCConfigurationBox.PPSs = new List() { ppsNALU.RawData }; + avc1.AVCConfigurationBox.SPSs = new List() { spsNALU.RawData }; + avc1.AVCConfigurationBox.ProfileCompatibility = 0; + movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox.SampleEntries.Add(avc1); + movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.TimeToSampleBox = new TimeToSampleBox(); + movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleToChunkBox = new SampleToChunkBox(); + movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleSizeBox = new SampleSizeBox(); + movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.ChunkOffsetBox = new ChunkOffsetBox(); + movieBox.MovieExtendsBox = new MovieExtendsBox(); + movieBox.MovieExtendsBox.TrackExtendsBoxs = new List(); + TrackExtendsBox trex = new TrackExtendsBox(); + trex.TrackID = 1; + trex.DefaultSampleDescriptionIndex = 1; + trex.DefaultSampleDuration = 0; + trex.DefaultSampleSize = 0; + trex.DefaultSampleFlags = 0; + movieBox.MovieExtendsBox.TrackExtendsBoxs.Add(trex); + fileTypeBox.ToBuffer(ref writer); + movieBox.ToBuffer(ref writer); + + //fragment moof n + List moofs = new List(); + ulong moofOffset = (ulong)writer.GetCurrentPosition(); + FragmentBox fragmentBox = new FragmentBox(); + fragmentBox.MovieFragmentBox = new MovieFragmentBox(); + fragmentBox.MovieFragmentBox.MovieFragmentHeaderBox = new MovieFragmentHeaderBox(); + fragmentBox.MovieFragmentBox.MovieFragmentHeaderBox.SequenceNumber = 1; + fragmentBox.MovieFragmentBox.TrackFragmentBox = new TrackFragmentBox(); + fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox = new TrackFragmentHeaderBox(0x39); + fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.TrackID = 1; + fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.BaseDataOffset = moofOffset; + fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleDuration = 48000; + fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleSize = (uint)jT1078Package.Bodies.Length; + fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleFlags = 0x1010000; + fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox = new TrackFragmentBaseMediaDecodeTimeBox(); + fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox.BaseMediaDecodeTime = 0; + //trun + fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox = new TrackRunBox(flags: 0x5); + fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox.FirstSampleFlags = 0; + fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox.TrackRunInfos = new List(); + fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox.TrackRunInfos.Add(new TrackRunBox.TrackRunInfo()); + fragmentBox.MediaDataBox = new MediaDataBox(); + fragmentBox.MediaDataBox.Data = nalus.Select(s => s.RawData).ToList(); + moofs.Add(fragmentBox); + foreach(var moof in moofs) + { + moof.ToBuffer(ref writer); + } + //mfra + MovieFragmentRandomAccessBox movieFragmentRandomAccessBox = new MovieFragmentRandomAccessBox(); + //mfra->tfra + movieFragmentRandomAccessBox.TrackFragmentRandomAccessBox = new TrackFragmentRandomAccessBox(1); + movieFragmentRandomAccessBox.TrackFragmentRandomAccessBox.TrackID = 0x01; + movieFragmentRandomAccessBox.TrackFragmentRandomAccessBox.TrackFragmentRandomAccessInfos = new List(); + TrackFragmentRandomAccessBox.TrackFragmentRandomAccessInfo trackFragmentRandomAccessInfo1 = new TrackFragmentRandomAccessBox.TrackFragmentRandomAccessInfo(); + trackFragmentRandomAccessInfo1.Time = 0; + trackFragmentRandomAccessInfo1.MoofOffset = moofOffset; + trackFragmentRandomAccessInfo1.TrafNumber = 0x01; + trackFragmentRandomAccessInfo1.TrunNumber = 0x01; + trackFragmentRandomAccessInfo1.SampleNumber = 0x01; + movieFragmentRandomAccessBox.TrackFragmentRandomAccessBox.TrackFragmentRandomAccessInfos.Add(trackFragmentRandomAccessInfo1); + //mfra->mfro + movieFragmentRandomAccessBox.MovieFragmentRandomAccessOffsetBox = new MovieFragmentRandomAccessOffsetBox(0); + movieFragmentRandomAccessBox.ToBuffer(ref writer); + var buffer = writer.FlushAndGetArray(); + + var filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_2.mp4"); + if (File.Exists(filepath)) + { + File.Delete(filepath); + } + using var fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write); + fileStream.Write(buffer); + fileStream.Close(); + } + + [Fact] + public void Test3() + { + H264Decoder decoder = new H264Decoder(); + var packages = ParseNALUTests(); + //10M + FMp4MessagePackWriter writer = new FMp4MessagePackWriter(new byte[10 * 1024 * 1024]); + var filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_3.mp4"); + if (File.Exists(filepath)) + { + File.Delete(filepath); + } + using var fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write); + var jT1078Package = packages.FirstOrDefault(); + var nalus = decoder.ParseNALU(jT1078Package); + var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 7); + //SPS + spsNALU.RawData = decoder.DiscardEmulationPreventionBytes(spsNALU.RawData); + var ppsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 8); + ppsNALU.RawData = decoder.DiscardEmulationPreventionBytes(ppsNALU.RawData); + ExpGolombReader h264GolombReader = new ExpGolombReader(spsNALU.RawData); + var spsInfo = h264GolombReader.ReadSPS(); + //ftyp + FileTypeBox fileTypeBox = new FileTypeBox(); + fileTypeBox.MajorBrand = "isom"; + fileTypeBox.MinorVersion = "\0\0\u0002\0"; + fileTypeBox.CompatibleBrands.Add("isom"); + fileTypeBox.CompatibleBrands.Add("iso6"); + fileTypeBox.CompatibleBrands.Add("iso2"); + fileTypeBox.CompatibleBrands.Add("avc1"); + fileTypeBox.CompatibleBrands.Add("mp41"); + //moov + MovieBox movieBox = new MovieBox(); + movieBox.MovieHeaderBox = new MovieHeaderBox(0, 0); + movieBox.MovieHeaderBox.CreationTime = 0; + movieBox.MovieHeaderBox.ModificationTime = 0; + movieBox.MovieHeaderBox.Duration = 0; + movieBox.MovieHeaderBox.Timescale = 1000; + movieBox.MovieHeaderBox.NextTrackID = 2; + movieBox.TrackBox = new TrackBox(); + 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.Duration = 0; + movieBox.TrackBox.TrackHeaderBox.TrackIsAudio = false; + movieBox.TrackBox.TrackHeaderBox.Width = (uint)spsInfo.width; + movieBox.TrackBox.TrackHeaderBox.Height = (uint)spsInfo.height; + movieBox.TrackBox.MediaBox = new MediaBox(); + 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.Duration = 0; + movieBox.TrackBox.MediaBox.HandlerBox = new HandlerBox(); + movieBox.TrackBox.MediaBox.HandlerBox.HandlerType = HandlerType.vide; + movieBox.TrackBox.MediaBox.HandlerBox.Name = "VideoHandler"; + movieBox.TrackBox.MediaBox.MediaInformationBox = new MediaInformationBox(); + movieBox.TrackBox.MediaBox.MediaInformationBox.VideoMediaHeaderBox = new VideoMediaHeaderBox(); + movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox = new DataInformationBox(); + movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox.DataReferenceBox = new DataReferenceBox(); + movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox.DataReferenceBox.DataEntryBoxes = new List(); + movieBox.TrackBox.MediaBox.MediaInformationBox.DataInformationBox.DataReferenceBox.DataEntryBoxes.Add(new DataEntryUrlBox(1)); + movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox = new SampleTableBox(); + movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox = new SampleDescriptionBox(movieBox.TrackBox.MediaBox.HandlerBox.HandlerType); + movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox.SampleEntries = new List(); + AVC1SampleEntry avc1 = new AVC1SampleEntry(); + avc1.AVCConfigurationBox = new AVCConfigurationBox(); + //h264 + avc1.Width = (ushort)movieBox.TrackBox.TrackHeaderBox.Width; + avc1.Height = (ushort)movieBox.TrackBox.TrackHeaderBox.Height; + avc1.AVCConfigurationBox.AVCLevelIndication = spsInfo.levelIdc; + avc1.AVCConfigurationBox.AVCProfileIndication = spsInfo.profileIdc; + avc1.AVCConfigurationBox.ProfileCompatibility = (byte)spsInfo.profileCompat; + avc1.AVCConfigurationBox.PPSs = new List() { ppsNALU.RawData }; + avc1.AVCConfigurationBox.SPSs = new List() { spsNALU.RawData }; + movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox.SampleEntries.Add(avc1); + movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.TimeToSampleBox = new TimeToSampleBox(); + movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleToChunkBox = new SampleToChunkBox(); + movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleSizeBox = new SampleSizeBox(); + movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.ChunkOffsetBox = new ChunkOffsetBox(); + movieBox.MovieExtendsBox = new MovieExtendsBox(); + movieBox.MovieExtendsBox.TrackExtendsBoxs = new List(); + TrackExtendsBox trex = new TrackExtendsBox(); + trex.TrackID = 1; + trex.DefaultSampleDescriptionIndex = 1; + trex.DefaultSampleDuration = 0; + trex.DefaultSampleSize = 0; + trex.DefaultSampleFlags = 0; + movieBox.MovieExtendsBox.TrackExtendsBoxs.Add(trex); + fileTypeBox.ToBuffer(ref writer); + movieBox.ToBuffer(ref writer); + //fragment moof n + foreach (var package in packages) + { + ulong moofOffset = (ulong)writer.GetCurrentPosition(); + var package_nalus = decoder.ParseNALU(package); + FragmentBox fragmentBox = new FragmentBox(); + fragmentBox.MovieFragmentBox = new MovieFragmentBox(); + fragmentBox.MovieFragmentBox.MovieFragmentHeaderBox = new MovieFragmentHeaderBox(); + fragmentBox.MovieFragmentBox.MovieFragmentHeaderBox.SequenceNumber = package.SN; + fragmentBox.MovieFragmentBox.TrackFragmentBox = new TrackFragmentBox(); + fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox = new TrackFragmentHeaderBox(0x39); + fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.TrackID = 1; + fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.BaseDataOffset = moofOffset; + fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleDuration = 48000; + fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleSize = (uint)package.Bodies.Length; + fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentHeaderBox.DefaultSampleFlags = 0x1010000; + fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox = new TrackFragmentBaseMediaDecodeTimeBox(); + fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackFragmentBaseMediaDecodeTimeBox.BaseMediaDecodeTime = package.Timestamp; + //trun + fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox = new TrackRunBox(flags: 0x5); + fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox.FirstSampleFlags = 0; + fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox.TrackRunInfos = new List(); + fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox.TrackRunInfos.Add(new TrackRunBox.TrackRunInfo()); + fragmentBox.MediaDataBox = new MediaDataBox(); + fragmentBox.MediaDataBox.Data = package_nalus.Select(s => s.RawData).ToList(); + fragmentBox.ToBuffer(ref writer); + } + var buffer = writer.FlushAndGetArray(); + fileStream.Write(buffer); + fileStream.Close(); + } + [Fact] public void tkhd_width_height_test() { @@ -233,5 +497,25 @@ namespace JT1078.FMp4.Test } return Package; } + + public List ParseNALUTests() + { + List packages = new List(); + var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "jt1078_3.txt")); + int mergeBodyLength = 0; + foreach (var line in lines) + { + 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); + } + } + return packages; + } } } diff --git a/src/JT1078.FMp4/Boxs/MovieFragmentBox.cs b/src/JT1078.FMp4/Boxs/MovieFragmentBox.cs index ae7708c..d5837ae 100644 --- a/src/JT1078.FMp4/Boxs/MovieFragmentBox.cs +++ b/src/JT1078.FMp4/Boxs/MovieFragmentBox.cs @@ -38,6 +38,12 @@ namespace JT1078.FMp4 TrackFragmentBox.ToBuffer(ref writer); } End(ref writer); + var trunOffsetPosition = writer.GetTrunOffsetPosition(); + if (trunOffsetPosition > 0) + { + writer.WriteInt32Return(writer.GetCurrentPosition() - SizePosition + 8, trunOffsetPosition); + writer.ClearTrunOffsetPosition(); + } } } } diff --git a/src/JT1078.FMp4/Boxs/MovieFragmentRandomAccessBox.cs b/src/JT1078.FMp4/Boxs/MovieFragmentRandomAccessBox.cs index 65dd2b1..1ad7359 100644 --- a/src/JT1078.FMp4/Boxs/MovieFragmentRandomAccessBox.cs +++ b/src/JT1078.FMp4/Boxs/MovieFragmentRandomAccessBox.cs @@ -38,6 +38,12 @@ namespace JT1078.FMp4 MovieFragmentRandomAccessOffsetBox.ToBuffer(ref writer); } End(ref writer); + var mfraSizePosition = writer.GetMfraSizePositionn(); + if (mfraSizePosition > 0) + { + writer.WriteInt32Return(writer.GetCurrentPosition() - SizePosition, mfraSizePosition); + writer.ClearMfraSizePosition(); + } } } } diff --git a/src/JT1078.FMp4/Boxs/MovieFragmentRandomAccessOffsetBox.cs b/src/JT1078.FMp4/Boxs/MovieFragmentRandomAccessOffsetBox.cs index 105ad7e..21829ac 100644 --- a/src/JT1078.FMp4/Boxs/MovieFragmentRandomAccessOffsetBox.cs +++ b/src/JT1078.FMp4/Boxs/MovieFragmentRandomAccessOffsetBox.cs @@ -28,7 +28,17 @@ namespace JT1078.FMp4 { Start(ref writer); WriterFullBoxToBuffer(ref writer); - writer.WriteUInt32(MfraSize); + if (MfraSize > 0) + { + //人工 + writer.WriteUInt32(MfraSize); + } + else + { + //程序自动计算 + writer.CreateMfraSizePosition(); + writer.Skip(4, out _); + } End(ref writer); } } diff --git a/src/JT1078.FMp4/Boxs/TrackRunBox.cs b/src/JT1078.FMp4/Boxs/TrackRunBox.cs index b91dacb..d572d42 100644 --- a/src/JT1078.FMp4/Boxs/TrackRunBox.cs +++ b/src/JT1078.FMp4/Boxs/TrackRunBox.cs @@ -52,7 +52,17 @@ namespace JT1078.FMp4 } if((Flags & FMp4Constants.TRUN_FLAG_DATA_OFFSET_PRESENT) > 0) { - writer.WriteInt32(DataOffset); + if (DataOffset > 0) + { + //人工 + writer.WriteInt32(DataOffset); + } + else + { + //程序自动计算 + writer.CreateTrunOffsetPosition(); + writer.Skip(4, out _); + } } if ((Flags & FMp4Constants.TRUN_FLAG_FIRST_SAMPLE_FLAGS_PRESENT) > 0) { diff --git a/src/JT1078.FMp4/JT1078.FMp4.xml b/src/JT1078.FMp4/JT1078.FMp4.xml index 8a049a0..239227a 100644 --- a/src/JT1078.FMp4/JT1078.FMp4.xml +++ b/src/JT1078.FMp4/JT1078.FMp4.xml @@ -986,7 +986,7 @@ 可选的 用来表示和该moof配套的mdat中实际数据内容距moof开头有多少byte - 相当于就是 moof.byteLength + mdat.headerSize + 相当于就是 moof.byteLength + mdat.headerSize(8) @@ -1250,6 +1250,11 @@ 盒子类型 + + + + + diff --git a/src/JT1078.FMp4/MessagePack/FMp4MessagePackWriter.cs b/src/JT1078.FMp4/MessagePack/FMp4MessagePackWriter.cs index ddeab4e..573159a 100644 --- a/src/JT1078.FMp4/MessagePack/FMp4MessagePackWriter.cs +++ b/src/JT1078.FMp4/MessagePack/FMp4MessagePackWriter.cs @@ -9,9 +9,16 @@ namespace JT1078.FMp4.MessagePack public ref struct FMp4MessagePackWriter { private FMp4BufferWriter writer; + + private int TrunDataOffsetPosition; + + private int MfraSizePosition; + public FMp4MessagePackWriter(Span buffer) { this.writer = new FMp4BufferWriter(buffer); + TrunDataOffsetPosition = 0; + MfraSizePosition = 0; } public byte[] FlushAndGetArray() { @@ -90,7 +97,6 @@ namespace JT1078.FMp4.MessagePack tmp.CopyTo(writer.Free); writer.Advance(count); } - public void WriteUInt16Return(ushort value, int position) { BinaryPrimitives.WriteUInt16BigEndian(writer.Written.Slice(position, 2), value); @@ -113,6 +119,36 @@ namespace JT1078.FMp4.MessagePack return writer.WrittenCount; } + public void CreateTrunOffsetPosition() + { + TrunDataOffsetPosition = writer.WrittenCount; + } + + public int GetTrunOffsetPosition() + { + return TrunDataOffsetPosition; + } + + public void ClearTrunOffsetPosition() + { + TrunDataOffsetPosition = 0; + } + + public void CreateMfraSizePosition() + { + MfraSizePosition = writer.WrittenCount; + } + + public int GetMfraSizePositionn() + { + return MfraSizePosition; + } + + public void ClearMfraSizePosition() + { + MfraSizePosition = 0; + } + /// /// ref /// diff --git a/src/JT1078.FMp4/Mp4Box.cs b/src/JT1078.FMp4/Mp4Box.cs index f85faff..db71de7 100644 --- a/src/JT1078.FMp4/Mp4Box.cs +++ b/src/JT1078.FMp4/Mp4Box.cs @@ -52,8 +52,10 @@ namespace JT1078.FMp4 ///// int(8)[16] ///// //public string UserType { get; set; } - - private int sizePosition; + /// + /// + /// + public int SizePosition; /// /// @@ -61,7 +63,7 @@ namespace JT1078.FMp4 /// public void Start(ref FMp4MessagePackWriter writer) { - writer.Skip(FixedSizeLength, out sizePosition); + writer.Skip(FixedSizeLength, out SizePosition); writer.WriteASCII(BoxType); } @@ -71,7 +73,7 @@ namespace JT1078.FMp4 /// public void End(ref FMp4MessagePackWriter writer) { - writer.WriteUInt32Return((uint)(writer.GetCurrentPosition() - sizePosition), sizePosition); + writer.WriteUInt32Return((uint)(writer.GetCurrentPosition() - SizePosition), SizePosition); } } }