public void EXPGolombReaderTest() { for (var i = 0; i < N; i++) { ExpGolombReader h264GolombReader = new ExpGolombReader(SPSNALu.RawData); h264GolombReader.ReadSPS(); } }
public void ParseNALUTest2() { JT1078Package Package = null; var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "jt1078_1.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; Package = JT1078Serializer.Merge(package); } H264Decoder decoder = new H264Decoder(); var nalus = decoder.ParseNALU(Package); Assert.Equal(4, nalus.Count); //SPS -> 7 var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 7); Assert.NotNull(spsNALU); spsNALU.RawData = decoder.DiscardEmulationPreventionBytes(spsNALU.RawData); //"Z00AFJWoWCWQ" var spsRawDataHex = JsonConvert.SerializeObject(spsNALU.RawData); ExpGolombReader h264GolombReader = new ExpGolombReader(spsNALU.RawData); //(77, 20, 0, 352, 288) var spsInfo = h264GolombReader.ReadSPS(); Assert.Equal(77, spsInfo.profileIdc); Assert.Equal(20, spsInfo.levelIdc); Assert.Equal(0u, spsInfo.profileCompat); Assert.Equal(288, spsInfo.height); Assert.Equal(352, spsInfo.width); //PPS -> 8 var ppsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 8); Assert.NotNull(ppsNALU); //IDR -> 5 关键帧 var idrNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 5); Assert.NotNull(idrNALU); //SEI -> 6 var seiNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 6); Assert.NotNull(seiNALU); }
/// <summary> /// 编码首帧视频,即videoTag[0] /// <para> /// 注意:本方法已写入<see cref="previousTagSize"/> /// </para> /// </summary> /// <param name="sps"></param> /// <param name="pps"></param> /// <param name="sei"></param> /// <returns></returns> public byte[] EncoderFirstVideoTag(H264NALU sps, H264NALU pps, H264NALU sei) { byte[] buffer = FlvArrayPool.Rent(2048); try { FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer); var rawData = h264Decoder.DiscardEmulationPreventionBytes(sps.RawData); ExpGolombReader h264GolombReader = new ExpGolombReader(rawData); SPSInfo spsInfo = h264GolombReader.ReadSPS(); //flv body video tag //flv body tag header FlvTags flvTags = new FlvTags { Type = TagType.Video, Timestamp = (uint)sps.Timestamp, TimestampExt = 0, StreamId = 0, //flv body tag body VideoTagsData = new VideoTags() }; flvTags.VideoTagsData.FrameType = FrameType.KeyFrame; flvTags.VideoTagsData.VideoData = new AvcVideoPacke { AvcPacketType = AvcPacketType.SequenceHeader, CompositionTime = 0 }; AVCDecoderConfigurationRecord aVCDecoderConfigurationRecord = new AVCDecoderConfigurationRecord { AVCProfileIndication = spsInfo.profileIdc, ProfileCompatibility = (byte)spsInfo.profileCompat, AVCLevelIndication = spsInfo.levelIdc, NumOfPictureParameterSets = 1, PPSBuffer = pps.RawData, SPSBuffer = sps.RawData }; flvTags.VideoTagsData.VideoData.AVCDecoderConfiguration = aVCDecoderConfigurationRecord; flvMessagePackWriter.WriteUInt32(previousTagSize); flvMessagePackWriter.WriteFlvTag(flvTags); var data = flvMessagePackWriter.FlushAndGetArray(); previousTagSize = (uint)(flvTags.DataSize + 11); return(data); } finally { FlvArrayPool.Return(buffer); } }
/// <summary> /// /// </summary> /// <param name="sps">NalUnitType->7</param> /// <param name="pps">NalUnitType->8</param> /// <returns></returns> public byte[] CreateFlvFirstFrame(H264NALU sps, H264NALU pps) { byte[] buffer = FlvArrayPool.Rent(65535); int currentMarkPosition = 0; int nextMarkPosition = 0; try { FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer); //flv header flvMessagePackWriter.WriteArray(VideoFlvHeaderBuffer); //SPS -> 7 ExpGolombReader h264GolombReader = new ExpGolombReader(sps.RawData); var spsInfo = h264GolombReader.ReadSPS(); currentMarkPosition = flvMessagePackWriter.GetCurrentPosition(); //flv body script tag CreateScriptTagFrame(ref flvMessagePackWriter, spsInfo.width, spsInfo.height); nextMarkPosition = flvMessagePackWriter.GetCurrentPosition(); //flv body video tag uint scriptTagFramePreviousTagSize = (uint)(nextMarkPosition - currentMarkPosition - PreviousTagSizeFixedLength); AVCDecoderConfigurationRecord aVCDecoderConfigurationRecord = new AVCDecoderConfigurationRecord(); aVCDecoderConfigurationRecord.AVCProfileIndication = spsInfo.profileIdc; aVCDecoderConfigurationRecord.ProfileCompatibility = (byte)spsInfo.profileCompat; aVCDecoderConfigurationRecord.AVCLevelIndication = spsInfo.levelIdc; aVCDecoderConfigurationRecord.NumOfPictureParameterSets = 1; aVCDecoderConfigurationRecord.PPSBuffer = pps.RawData; aVCDecoderConfigurationRecord.SPSBuffer = sps.RawData; currentMarkPosition = flvMessagePackWriter.GetCurrentPosition(); CreateVideoTag0Frame(ref flvMessagePackWriter, scriptTagFramePreviousTagSize, aVCDecoderConfigurationRecord); nextMarkPosition = flvMessagePackWriter.GetCurrentPosition(); //flv body video tag 0 uint videoTag0PreviousTagSize = (uint)(nextMarkPosition - currentMarkPosition - PreviousTagSizeFixedLength); //cache PreviousTagSize PreviousTagSizeDict.AddOrUpdate(sps.GetKey(), videoTag0PreviousTagSize, (a, b) => videoTag0PreviousTagSize); return(flvMessagePackWriter.FlushAndGetArray()); } finally { FlvArrayPool.Return(buffer); } }
public void Test1() { ExpGolombReader h264GolombReader = new ExpGolombReader(new byte[] { 103, 77, 0, 20, 149, 168, 88, 37, 144, 0 }); var result = h264GolombReader.ReadSPS(); Assert.Equal(77, result.profileIdc); Assert.Equal(0u, result.profileCompat); Assert.Equal(20, result.levelIdc); Assert.Equal(352, result.width); Assert.Equal(288, result.height); //profileIdc 77 //profileCompat 0 //levelIdc 20 //picOrderCntType 2 //picWidthInMbsMinus1 21 //picHeightInMapUnitsMinus1 17 //frameMbsOnlyFlag 1 //width 352 //height 288 }
/// <summary> /// Identify NAL unit types and pass on the NALU, trackId, presentation and decode timestamps /// for the NALUs to the next stream component. /// Also, preprocess caption and sequence parameter NALUs. /// 常用Nalu_type: /// 0x67 (0 11 00111) SPS 非常重要 type = 7 /// 0x68 (0 11 01000) PPS 非常重要 type = 8 /// 0x65 (0 11 00101) IDR帧 关键帧(非常重要) type = 5 /// 0x61 (0 11 00001) I帧 重要 type = 1 非IDR的I帧不大常见 /// 0x41 (0 10 00001) P帧 重要 type = 1 /// 0x01 (0 00 00001) B帧 不重要 type = 1 /// 0x06 (0 00 00110) SEI 不重要 type = 6 /// <see cref="https://blog.csdn.net/huibailingyu/article/details/42879573"/> /// </summary> /// <param name="h264NALU"></param> /// <returns></returns> private void NALUTypeFilter(H264NALU h264NALU) { switch (h264NALU.NALUHeader.NalUnitType) { //IPB帧 case 1: break; //IDR case 5: break; //SEI case 6: h264NALU.RawData = DiscardEmulationPreventionBytes(h264NALU.RawData); break; //SPS case 7: h264NALU.RawData = DiscardEmulationPreventionBytes(h264NALU.RawData); ExpGolombReader h264GolombReader = new ExpGolombReader(h264NALU.RawData); var spsInfo = h264GolombReader.ReadSPS(); break; //PPS case 8: break; //AUD case 9: break; } }
public void 测试主次码流切换() { FileStream fileStream = null; H264Decoder decoder = new H264Decoder(); List <H264NALU> h264NALULs = new List <H264NALU>(); FlvEncoder encoder = new FlvEncoder(); try { var filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_5.flv"); var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_5.txt")); if (File.Exists(filepath)) { File.Delete(filepath); } JT1078Package Package = null; foreach (var line in lines) { var data = line.Split(','); var bytes = data[6].ToHexBytes(); JT1078Package package = JT1078Serializer.Deserialize(bytes); Package = JT1078Serializer.Merge(package); if (Package != null) { var tmp = decoder.ParseNALU(Package); if (tmp != null && tmp.Count > 0) { h264NALULs = h264NALULs.Concat(tmp).ToList(); } } } var tmp1 = h264NALULs.Where(w => w.NALUHeader.NalUnitType == 7).ToList(); List <SPSInfo> tmpSpss = new List <SPSInfo>(); List <ulong> times = new List <ulong>(); List <ushort> lastIFrameIntervals = new List <ushort>(); List <ushort> lastFrameIntervals = new List <ushort>(); List <int> type = new List <int>(); foreach (var item in h264NALULs) { //type.Add(item.NALUHeader.NalUnitType); times.Add(item.Timestamp); lastFrameIntervals.Add(item.LastFrameInterval); lastIFrameIntervals.Add(item.LastIFrameInterval); if (item.NALUHeader.NalUnitType == 7) { ExpGolombReader expGolombReader = new ExpGolombReader(item.RawData); tmpSpss.Add(expGolombReader.ReadSPS()); } } fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write); var totalPage = (h264NALULs.Count + 10 - 1) / 10; for (var i = 0; i < totalPage; i++) { var flv2 = encoder.CreateFlvFrame(h264NALULs.Skip(i * 10).Take(10).ToList()); if (flv2.Length != 0) { //fileStream.Write(flv2); } } } catch (Exception ex) { Assert.Throws <Exception>(() => { }); } finally { fileStream?.Close(); fileStream?.Dispose(); } }
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 <DataEntryBox>(); 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 <SampleEntry>(); 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 <byte[]>() { ppsNALU.RawData }; avc1.AVCConfigurationBox.SPSs = new List <byte[]>() { 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>(); 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 * 1000; //trun fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox = new TrackRunBox(flags: 0x5); fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox.FirstSampleFlags = 0; fragmentBox.MovieFragmentBox.TrackFragmentBox.TrackRunBox.TrackRunInfos = new List <TrackRunBox.TrackRunInfo>(); 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(); }
/// <summary> /// 编码首个视频盒子 /// </summary> /// <param name="package">jt1078完整包</param> /// <returns></returns> public byte[] EncoderFirstVideoBox(JT1078Package package) { byte[] buffer = FMp4ArrayPool.Rent(package.Bodies.Length + 4096); FMp4MessagePackWriter writer = new FMp4MessagePackWriter(new byte[10 * 1024 * 1024]); try { var nalus = h264Decoder.ParseNALU(package); var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 7); //SPS spsNALU.RawData = h264Decoder.DiscardEmulationPreventionBytes(spsNALU.RawData); var ppsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 8); ppsNALU.RawData = h264Decoder.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 <DataEntryBox>(); 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 <SampleEntry>(); 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 <byte[]>() { ppsNALU.RawData }; avc1.AVCConfigurationBox.SPSs = new List <byte[]>() { 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>(); 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); var data = writer.FlushAndGetArray(); return(data); } finally { FMp4ArrayPool.Return(buffer); } }
/// <summary> /// 编码moov盒子 /// </summary> /// <returns></returns> public byte[] EncoderMoovBox(List <H264NALU> nalus, int naluLength) { byte[] buffer = FMp4ArrayPool.Rent(naluLength + 4096); FMp4MessagePackWriter writer = new FMp4MessagePackWriter(buffer); try { var spsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 7); //SPS spsNALU.RawData = h264Decoder.DiscardEmulationPreventionBytes(spsNALU.RawData); var ppsNALU = nalus.FirstOrDefault(n => n.NALUHeader.NalUnitType == 8); ppsNALU.RawData = h264Decoder.DiscardEmulationPreventionBytes(ppsNALU.RawData); ExpGolombReader h264GolombReader = new ExpGolombReader(spsNALU.RawData); var spsInfo = h264GolombReader.ReadSPS(); //moov MovieBox movieBox = new MovieBox(); movieBox.MovieHeaderBox = new MovieHeaderBox(0, 2); movieBox.MovieHeaderBox.CreationTime = 0; movieBox.MovieHeaderBox.ModificationTime = 0; movieBox.MovieHeaderBox.Duration = 0; movieBox.MovieHeaderBox.Timescale = 1000; movieBox.MovieHeaderBox.NextTrackID = 99; 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 <DataEntryBox>(); 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 <SampleEntry>(); 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 <byte[]>() { ppsNALU.RawData }; avc1.AVCConfigurationBox.SPSs = new List <byte[]>() { spsNALU.RawData }; movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleDescriptionBox.SampleEntries.Add(avc1); movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.TimeToSampleBox = new TimeToSampleBox() { //TimeToSampleInfos=new List<TimeToSampleBox.TimeToSampleInfo> //{ // new TimeToSampleBox.TimeToSampleInfo // { // SampleCount=0, // SampleDelta=0 // } //} }; movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleToChunkBox = new SampleToChunkBox() { //SampleToChunkInfos=new List<SampleToChunkBox.SampleToChunkInfo>() //{ // new SampleToChunkBox.SampleToChunkInfo // { // } //} }; movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.SampleSizeBox = new SampleSizeBox() { //EntrySize = new List<uint>() //{ // 0 //} }; movieBox.TrackBox.MediaBox.MediaInformationBox.SampleTableBox.ChunkOffsetBox = new ChunkOffsetBox() { //ChunkOffset=new List<uint>() //{ // 0 //} }; movieBox.MovieExtendsBox = new MovieExtendsBox(); movieBox.MovieExtendsBox.TrackExtendsBoxs = new List <TrackExtendsBox>(); TrackExtendsBox trex = new TrackExtendsBox(); trex.TrackID = 1; trex.DefaultSampleDescriptionIndex = 1; trex.DefaultSampleDuration = 0; trex.DefaultSampleSize = 0; trex.DefaultSampleFlags = 0; movieBox.MovieExtendsBox.TrackExtendsBoxs.Add(trex); movieBox.ToBuffer(ref writer); var data = writer.FlushAndGetArray(); return(data); } finally { FMp4ArrayPool.Return(buffer); } }
public byte[] CreateFlvFrame(List <H264NALU> nALUs, int minimumLength = 65535) { byte[] buffer = FlvArrayPool.Rent(minimumLength); try { FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer); int currentMarkPosition = 0; int nextMarkPosition = 0; H264NALU sps = null, pps = null; SPSInfo spsInfo = new SPSInfo(); foreach (var naln in nALUs) { string key = naln.GetKey(); if (sps != null && pps != null) { if (VideoSPSDict.TryGetValue(key, out var spsInfoCache)) { if (spsInfoCache.height != spsInfo.height && spsInfoCache.width != spsInfo.width) { if (FlvFrameInfoDict.TryGetValue(key, out FlvFrameInfo flvFrameInfo)) { CreateFlvKeyFrame(ref flvMessagePackWriter, key, sps.RawData, pps.RawData, spsInfo, flvFrameInfo.PreviousTagSize); FlvFirstFrameCache.TryRemove(key, out _); FlvFirstFrameCache.TryAdd(key, flvMessagePackWriter.FlushAndGetArray()); VideoSPSDict.TryUpdate(key, spsInfo, spsInfo); flvFrameInfo.LastFrameInterval = 0; FlvFrameInfoDict.TryUpdate(key, flvFrameInfo, flvFrameInfo); } } sps = null; pps = null; } else { CreateFlvKeyFrame(ref flvMessagePackWriter, key, sps.RawData, pps.RawData, spsInfo, 0); FlvFirstFrameCache.TryAdd(key, flvMessagePackWriter.FlushAndGetArray()); VideoSPSDict.TryAdd(key, spsInfo); sps = null; pps = null; } } //7 8 6 5 1 1 1 1 7 8 6 5 1 1 1 1 1 7 8 6 5 1 1 1 1 1 switch (naln.NALUHeader.NalUnitType) { case 5: // IDR case 1: // I/P/B if (FlvFrameInfoDict.TryGetValue(key, out FlvFrameInfo flvFrameInfo)) { currentMarkPosition = flvMessagePackWriter.GetCurrentPosition(); CreateVideoTagOtherFrame(ref flvMessagePackWriter, flvFrameInfo, naln); nextMarkPosition = flvMessagePackWriter.GetCurrentPosition(); uint tmpPreviousTagSize = (uint)(nextMarkPosition - currentMarkPosition - PreviousTagSizeFixedLength); flvFrameInfo.PreviousTagSize = tmpPreviousTagSize; flvFrameInfo.LastFrameInterval += naln.LastFrameInterval; FlvFrameInfoDict.TryUpdate(key, flvFrameInfo, flvFrameInfo); } break; case 7: // sps sps = naln; var rawData = H264Decoder.DiscardEmulationPreventionBytes(naln.RawData); ExpGolombReader h264GolombReader = new ExpGolombReader(rawData); spsInfo = h264GolombReader.ReadSPS(); break; case 8: // pps pps = naln; break; case 6: //SEI break; default: break; } } return(flvMessagePackWriter.FlushAndGetArray()); } finally { FlvArrayPool.Return(buffer); } }