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());
        }
예제 #4
0
        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);
        }