private void CheckCachedFrame(uint lastProcessedFrameId) { if (_cachedFrame != null && _cachedFrame.FrameId <= lastProcessedFrameId) { _cachedFrame = null; } }
private H264Frame ProcessFrameIsNotReady() { H264Frame h264Frame = null; if (_cachedFrame != null && _cachedFrame.FrameId == _nextExpectedFrameId) { h264Frame = _cachedFrame; _lastProcessedFrameId = _cachedFrame.FrameId; _nextExpectedFrameId = _lastProcessedFrameId + 1; CleanVideoDataDictionary(_lastProcessedFrameId); _cachedFrame = null; } return(h264Frame); }
public H264Frame AssembleVideoFrame(VideoData data) { uint frameId = data.FrameId; if (frameId < _lastProcessedFrameId) { if (_lastProcessedFrameId - frameId >= 120) // at 60 fps max 4 secs { // This is a fallback if the frameId gets reset at some point from the XBox // (Don't know when this exactly happens) _lastProcessedFrameId = 0; _nextExpectedFrameId = 0; _cachedFrame = null; } else { // Ignore all frames which are lower than the last processed frame id return(null); } } if (!_videoData.ContainsKey(frameId)) { if (_videoData.Count > MaxBufferedFramePacketSize) { // Avoid overflow _videoData.Clear(); } var newData = new VideoFrameData() { Flags = data.Flags, Timestamp = data.Timestamp, Data = new byte[data.TotalSize], WrittenChunks = 0 }; _videoData.Add(frameId, newData); } Buffer.BlockCopy(data.Data, 0, _videoData[frameId].Data, (int)data.Offset, data.Data.Length); _videoData[frameId].WrittenChunks++; bool isFrameReady = _videoData[frameId].WrittenChunks >= data.PacketCount; return(isFrameReady ? ProcessFrameIsReady(frameId) : ProcessFrameIsNotReady()); }
void IVideoConsumer.ConsumeVideoData(object sender, VideoDataEventArgs args) { H264Frame frame = _videoAssembler.AssembleVideoFrame(args.VideoData); if (frame == null) { return; } if (_dumpSingleFrames) { string frameFilename = $"{_fileName}.video.{frame.FrameId}.{frame.TimeStamp}.raw"; using (FileStream fs = new FileStream(frameFilename, FileMode.CreateNew)) { fs.Write(frame.RawData, 0, frame.RawData.Length); } } else { _videoFile.Write(frame.RawData, 0, frame.RawData.Length); } }
private H264Frame ProcessFrameIsReady(uint frameId) { H264Frame h264Frame = null; if (_nextExpectedFrameId == 0 || _nextExpectedFrameId == frameId) { if (!_videoData.TryGetValue(frameId, out var completeFrame)) { return(null); } _videoData.Remove(frameId); _lastProcessedFrameId = frameId; _nextExpectedFrameId = _lastProcessedFrameId + 1; CleanVideoDataDictionary(_lastProcessedFrameId); CheckCachedFrame(_lastProcessedFrameId); h264Frame = new H264Frame(completeFrame.Data, frameId, completeFrame.Timestamp, completeFrame.Flags); } else { if (_cachedFrame == null) { if (_videoData.TryGetValue(frameId, out var completeFrame)) { // Cache current ready frame because it is not expected frameId _videoData.Remove(frameId); _cachedFrame = new H264Frame(completeFrame.Data, frameId, completeFrame.Timestamp, completeFrame.Flags); } } else { if (_cachedFrame.FrameId == _nextExpectedFrameId || _cachedFrame.FrameId < frameId) { // Offer cached frame _lastProcessedFrameId = _cachedFrame.FrameId; _nextExpectedFrameId = _lastProcessedFrameId + 1; CleanVideoDataDictionary(_lastProcessedFrameId); h264Frame = _cachedFrame; _cachedFrame = null; if (_videoData.TryGetValue(frameId, out var completeFrame)) { // Cache current ready frame _videoData.Remove(frameId); _cachedFrame = new H264Frame(completeFrame.Data, frameId, completeFrame.Timestamp, completeFrame.Flags); } } else { if (!_videoData.TryGetValue(frameId, out var completeFrame)) { return(null); } _videoData.Remove(frameId); _lastProcessedFrameId = frameId; _nextExpectedFrameId = _lastProcessedFrameId + 1; CleanVideoDataDictionary(_lastProcessedFrameId); h264Frame = new H264Frame(completeFrame.Data, frameId, completeFrame.Timestamp, completeFrame.Flags); _cachedFrame = null; } } } return(h264Frame); }