using JT1078.Flv.Enums; using JT1078.Flv.H264; using JT1078.Flv.MessagePack; using JT1078.Flv.Metadata; using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace JT1078.Flv { public class FlvEncoder { private static readonly FlvHeader VideoFlvHeader = new FlvHeader(true, false); private static readonly H264Decoder h264Decoder = new H264Decoder(); public byte[] FlvFirstFrame(List nALUs) { byte[] buffer = FlvArrayPool.Rent(10240); try { FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer); //flv header flvMessagePackWriter.WriteArray(VideoFlvHeader.ToArray()); //SPS -> 7 var spsNALU = nALUs.FirstOrDefault(n => n.NALUHeader.NalUnitType == 7); spsNALU.RawData = h264Decoder.DiscardEmulationPreventionBytes(spsNALU.RawData); ExpGolombReader h264GolombReader = new ExpGolombReader(spsNALU.RawData); var spsInfo = h264GolombReader.ReadSPS(); //PPS -> 8 var ppsNALU = nALUs.FirstOrDefault(n => n.NALUHeader.NalUnitType == 8); //IDR -> 5 关键帧 var idrNALU = nALUs.FirstOrDefault(n => n.NALUHeader.NalUnitType == 5); //SEI -> 6 //var seiNALU = nALUs.FirstOrDefault(n => n.NALUHeader.NalUnitType == 6); //flv body script tag var scriptTag = CreateScriptTagFrame(spsInfo.width, spsInfo.height); //flv body video tag AVCDecoderConfigurationRecord aVCDecoderConfigurationRecord = new AVCDecoderConfigurationRecord(); aVCDecoderConfigurationRecord.AVCProfileIndication = spsInfo.profileIdc; aVCDecoderConfigurationRecord.ProfileCompatibility =(byte)spsInfo.profileCompat; aVCDecoderConfigurationRecord.AVCLevelIndication = spsInfo.levelIdc; aVCDecoderConfigurationRecord.NumOfPictureParameterSets = 1; aVCDecoderConfigurationRecord.PPSBuffer = spsNALU.RawData; aVCDecoderConfigurationRecord.SPSBuffer = ppsNALU.RawData; var videoTag = CreateVideoTag0Frame((uint)scriptTag.Length, aVCDecoderConfigurationRecord); return flvMessagePackWriter.FlushAndGetArray(); } finally { FlvArrayPool.Return(buffer); } } public byte[] CreateScriptTagFrame(int width,int height) { byte[] buffer = FlvArrayPool.Rent(1024); try { FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer); //flv body PreviousTagSize awalys 0 flvMessagePackWriter.WriteUInt32(0); //flv body script tag //flv body tag header FlvTags flvTags = new FlvTags(); flvTags.Type = TagType.ScriptData; flvTags.Timestamp = 0; flvTags.TimestampExt = 0; flvTags.StreamId = 0; //flv body tag body flvTags.DataTagsData = new Amf3(); flvTags.DataTagsData.Amf3Metadatas.Add(new Amf3Metadata_Duration { Value = 0d }); flvTags.DataTagsData.Amf3Metadatas.Add(new Amf3Metadata_VideoDataRate { Value = 0d }); flvTags.DataTagsData.Amf3Metadatas.Add(new Amf3Metadata_VideoCodecId { Value = 7d }); flvTags.DataTagsData.Amf3Metadatas.Add(new Amf3Metadata_FrameRate { Value = 25d }); flvTags.DataTagsData.Amf3Metadatas.Add(new Amf3Metadata_Width { Value = width }); flvTags.DataTagsData.Amf3Metadatas.Add(new Amf3Metadata_Height { Value = height }); flvMessagePackWriter.WriteFlvTag(flvTags); return flvMessagePackWriter.FlushAndGetArray(); } finally { FlvArrayPool.Return(buffer); } } public byte[] CreateVideoTag0Frame(uint previousTagSize,AVCDecoderConfigurationRecord aVCDecoderConfigurationRecord) { byte[] buffer = FlvArrayPool.Rent(1024); try { FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer); //flv body PreviousTagSize ScriptTag flvMessagePackWriter.WriteUInt32(previousTagSize); //flv body video tag //flv body tag header FlvTags flvTags = new FlvTags(); flvTags.Type = TagType.Video; flvTags.Timestamp = 0; flvTags.TimestampExt = 0; flvTags.StreamId = 0; //flv body tag body flvTags.VideoTagsData = new VideoTags(); flvTags.VideoTagsData.FrameType = FrameType.KeyFrame; flvTags.VideoTagsData.VideoData = new AvcVideoPacke(); flvTags.VideoTagsData.VideoData.AvcPacketType = AvcPacketType.SequenceHeader; flvTags.VideoTagsData.VideoData.CompositionTime = 0; flvTags.VideoTagsData.VideoData.AVCDecoderConfiguration = aVCDecoderConfigurationRecord; flvMessagePackWriter.WriteFlvTag(flvTags); return flvMessagePackWriter.FlushAndGetArray(); } finally { FlvArrayPool.Return(buffer); } } public byte[] CreateVideoTagOtherFrame(uint previousTagSize, H264NALU nALU) { byte[] buffer = FlvArrayPool.Rent(2048); try { FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer); //flv body PreviousTagSize ScriptTag flvMessagePackWriter.WriteUInt32(previousTagSize); //flv body video tag //flv body tag header FlvTags flvTags = new FlvTags(); flvTags.Type = TagType.Video; flvTags.Timestamp = nALU.LastIFrameInterval; flvTags.TimestampExt = 0; flvTags.StreamId = 0; //flv body tag body flvTags.VideoTagsData = new VideoTags(); flvTags.VideoTagsData.FrameType = FrameType.InterFrame; flvTags.VideoTagsData.VideoData = new AvcVideoPacke(); flvTags.VideoTagsData.VideoData.AvcPacketType = AvcPacketType.Raw; flvTags.VideoTagsData.VideoData.CompositionTime = nALU.LastIFrameInterval; flvTags.VideoTagsData.VideoData.Data = nALU.RawData; flvMessagePackWriter.WriteFlvTag(flvTags); return flvMessagePackWriter.FlushAndGetArray(); } finally { FlvArrayPool.Return(buffer); } } public byte[] FlvOtherFrame() { byte[] buffer = FlvArrayPool.Rent(10240); try { FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer); #warning 目前只支持视频 // NalUnitType == 1 //flv body //flv body PreviousTagSize //flv body tag //flv body tag header //flv body tag body return flvMessagePackWriter.FlushAndGetArray(); } finally { FlvArrayPool.Return(buffer); } } } }