/// <summary> /// 编码首帧音频,即audioTag[0] /// <para> /// 注意:本方法已写入<see cref="previousTagSize"/> /// </para> /// </summary> /// <returns></returns> public byte[] EncoderFirstAudioTag(ulong timestamp) { byte[] buffer = FlvArrayPool.Rent(2048); try { FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer); //flv body audio tag //flv body tag header FlvTags flvTags = new FlvTags { Type = TagType.Audio, Timestamp = (uint)timestamp, //flv body tag body AudioTagsData = new AudioTags(AACPacketType.AudioSpecificConfig) }; flvMessagePackWriter.WriteUInt32(previousTagSize); flvMessagePackWriter.WriteFlvTag(flvTags); var data = flvMessagePackWriter.FlushAndGetArray(); previousTagSize = (uint)(flvTags.DataSize + 11); return(data); } finally { FlvArrayPool.Return(buffer); } }
/// <summary> /// 编码脚本Tag /// </summary> /// <param name="spsInfo">解析后的sps信息</param> /// <param name="hasAudio">是否有音频</param> /// <param name="frameRate">帧率 默认25d 即每秒25帧</param> /// <returns></returns> public byte[] EncoderScriptTag(SPSInfo spsInfo, bool hasAudio = false, double frameRate = 25d) { byte[] buffer = FlvArrayPool.Rent(1024); try { FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer); //flv body script tag //flv body tag header FlvTags flvTags = new FlvTags { Type = TagType.ScriptData, //flv body tag body DataTagsData = new Amf3 { Amf3Metadatas = new List <IAmf3Metadata> { new Amf3Metadata_Duration { Value = 0d }, new Amf3Metadata_VideoDataRate { Value = 0d }, new Amf3Metadata_VideoCodecId { Value = 7d }, new Amf3Metadata_FrameRate { Value = frameRate }, new Amf3Metadata_Width() { Value = spsInfo.width }, new Amf3Metadata_Height() { Value = spsInfo.height }, } } }; if (hasAudio) { flvTags.DataTagsData.Amf3Metadatas.Add(new Amf3Metadata_AudioCodecId()); flvTags.DataTagsData.Amf3Metadatas.Add(new Amf3Metadata_AudioSampleRate()); flvTags.DataTagsData.Amf3Metadatas.Add(new Amf3Metadata_AudioSampleSize()); flvTags.DataTagsData.Amf3Metadatas.Add(new Amf3Metadata_AudioStereo()); } flvMessagePackWriter.WriteFlvTag(flvTags); flvMessagePackWriter.WriteUInt32((uint)(flvTags.DataSize + 11)); return(flvMessagePackWriter.FlushAndGetArray()); } finally { FlvArrayPool.Return(buffer); } }
public byte[] CreateFlvFrame(List <H264NALU> nALUs, int minimumLength = 10240) { byte[] buffer = FlvArrayPool.Rent(minimumLength); try { FlvMessagePackWriter flvMessagePackWriter = new FlvMessagePackWriter(buffer); int currentMarkPosition = 0; int nextMarkPosition = 0; H264NALU?sps = null, pps = null; foreach (var naln in nALUs) { string key = naln.GetKey(); if (!FrameInitDict.ContainsKey(key)) { if (naln.NALUHeader.NalUnitType == 7) { naln.RawData = H264Decoder.DiscardEmulationPreventionBytes(naln.RawData); sps = naln; } else if (naln.NALUHeader.NalUnitType == 8) { pps = naln; } if (sps != null && pps != null) { flvMessagePackWriter.WriteArray(CreateFlvFirstFrame(sps, pps)); FrameInitDict.TryAdd(key, true); } else { continue; } } if (PreviousTagSizeDict.TryGetValue(key, out uint previousTagSize)) { currentMarkPosition = flvMessagePackWriter.GetCurrentPosition(); CreateVideoTagOtherFrame(ref flvMessagePackWriter, previousTagSize, naln); nextMarkPosition = flvMessagePackWriter.GetCurrentPosition(); uint tmpPreviousTagSize = (uint)(nextMarkPosition - currentMarkPosition - PreviousTagSizeFixedLength); PreviousTagSizeDict.TryUpdate(key, tmpPreviousTagSize, previousTagSize); } } return(flvMessagePackWriter.FlushAndGetArray()); } finally { FlvArrayPool.Return(buffer); } }
/// <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 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); } }