public void AddTag(FlvTag tag) { Tags.Add(tag); if (tag.TimeStamp >= target) { FinallizeFile(); } }
private void _WriteTagData(byte[] data) { int toRead = Math.Min(data.Length, (currentTag.TagSize - (int)_data.Position)); _data.Write(data, 0, toRead); if ((int)_data.Position == currentTag.TagSize) { currentTag.Data = _data.ToArray(); _data.SetLength(0); // reset data buffer _TagCreated(currentTag); currentTag = null; _AddBytes(data.Skip(toRead).ToArray()); } }
public void FinallizeFile() { try { if (!Directory.Exists(Path.GetDirectoryName(path))) { Directory.CreateDirectory(Path.GetDirectoryName(path)); } using (var fs = new FileStream(path, FileMode.CreateNew, FileAccess.ReadWrite)) { fs.Write(FlvStreamProcessor.FLV_HEADER_BYTES, 0, FlvStreamProcessor.FLV_HEADER_BYTES.Length); fs.Write(new byte[] { 0, 0, 0, 0, }, 0, 4); Header.Meta["duration"] = (Tags[Tags.Count - 1].TimeStamp - Tags[0].TimeStamp) / 1000d; Header.Meta["lasttimestamp"] = (Tags[Tags.Count - 1].TimeStamp - Tags[0].TimeStamp); var t = new FlvTag { TagType = TagType.DATA, Data = Header.ToBytes() }; t.WriteTo(fs); int offset = Tags[0].TimeStamp; HTags.ForEach(tag => tag.WriteTo(fs)); Tags.ForEach(tag => tag.WriteTo(fs, offset)); logger.Info("剪辑已保存:{0}", Path.GetFileName(path)); fs.Close(); } Tags.Clear(); } catch (Exception ex) { logger.Error(ex, "保存剪辑文件时出错"); } ClipFinalized?.Invoke(this, new ClipFinalizedArgs() { ClipProcessor = this }); }
private void _ParseTag(byte[] data) { _buffer.Position = 0; _buffer.SetLength(0); byte[] b = new byte[4]; _buffer.Write(data, 0, data.Length); long dataLen = _buffer.Position; _buffer.Position = 0; FlvTag tag = new FlvTag(); // Previous Tag Size _buffer.Read(b, 0, 4); b = new byte[4]; // TagType UI8 tag.TagType = (TagType)_buffer.ReadByte(); // Debug.Write(string.Format("Tag Type: {0}\n", tag.TagType)); // DataSize UI24 _buffer.Read(b, 1, 3); tag.TagSize = BitConverter.ToInt32(b.ToBE(), 0); // Timestamp UI24 _buffer.Read(b, 1, 3); // TimestampExtended UI8 _buffer.Read(b, 0, 1); tag.TimeStamp = BitConverter.ToInt32(b.ToBE(), 0); // StreamID UI24 _buffer.Read(tag.StreamId, 0, 3); currentTag = tag; byte[] rest = _buffer.GetBuffer().Skip((int)_buffer.Position).Take((int)(dataLen - _buffer.Position)).ToArray(); _buffer.Position = 0; _AddBytes(rest); }
private void _TagCreated(FlvTag tag) { if (Metadata == null) { if (tag.TagType == TagType.DATA) { _fs?.Write(FLV_HEADER_BYTES, 0, FLV_HEADER_BYTES.Length); _fs?.Write(new byte[] { 0, 0, 0, 0, }, 0, 4); Metadata = FlvMetadata.Parse(tag.Data); // TODO: 添加录播姬标记、录制信息 tag.Data = Metadata.ToBytes(); tag.WriteTo(_fs); } else { throw new Exception("onMetaData not found"); } } else { if (!hasOffset) { if (tag.TagType == TagType.VIDEO) { TagVideoCount++; if (TagVideoCount < 2) { logger.Trace("第一个 Video Tag 时间戳 {0} ms", tag.TimeStamp); HTags.Add(tag); } else { BaseTimeStamp = tag.TimeStamp; hasOffset = true; logger.Trace("重设时间戳 {0} 毫秒", BaseTimeStamp); } } else if (tag.TagType == TagType.AUDIO) { TagAudioCount++; if (TagAudioCount < 2) { logger.Trace("第一个 Audio Tag 时间戳 {0} ms", tag.TimeStamp); HTags.Add(tag); } else { BaseTimeStamp = tag.TimeStamp; hasOffset = true; logger.Trace("重设时间戳 {0} 毫秒", BaseTimeStamp); } } } if (hasOffset) { tag.TimeStamp -= BaseTimeStamp; // 修复时间戳 if (tag.TimeStamp < 0) { tag.TimeStamp = 0; } MaxTimeStamp = Math.Max(MaxTimeStamp, tag.TimeStamp); } else { tag.TimeStamp = 0; } // 如果没有禁用 Clip 功能 if (!_noClip) { Tags.Add(tag); // Clip 缓存 // 移除过旧的数据 if (MaxTimeStamp - LasttimeRemovedTimestamp > 800) { LasttimeRemovedTimestamp = MaxTimeStamp; int max_remove_index = Tags.FindLastIndex(x => x.IsVideoKeyframe && ((MaxTimeStamp - x.TimeStamp) > (Clip_Past * SEC_TO_MS))); if (max_remove_index > 0) { Tags.RemoveRange(0, max_remove_index); } // Tags.RemoveRange(0, max_remove_index + 1 - 1); // 给将来的备注:这里是故意 + 1 - 1 的,因为要保留选中的那个关键帧, + 1 就把关键帧删除了 } } // 写入硬盘 tag.WriteTo(_fs); TagProcessed?.Invoke(this, new TagProcessedArgs() { Tag = tag }); } // if (Metadata == null) else }