public void GotVideoRtp(IPEndPoint remoteEndPoint, uint ssrc, uint seqnum, uint timestamp, int payloadID, bool marker, byte[] payload)
        {
            //logger.LogDebug($"rtp video, seqnum {seqnum}, ts {timestamp}, marker {marker}, payload {payload.Length}.");
            if (_currVideoFramePosn + payload.Length >= _currVideoFrame.Length)
            {
                // Something has gone very wrong. Clear the buffer.
                _currVideoFramePosn = 0;
            }

            // New frames must have the VP8 Payload Descriptor Start bit set.
            // The tracking of the current video frame position is to deal with a VP8 frame being split across multiple RTP packets
            // as per https://tools.ietf.org/html/rfc7741#section-4.4.
            if (_currVideoFramePosn > 0 || (payload[0] & 0x10) > 0)
            {
                RtpVP8Header vp8Header = RtpVP8Header.GetVP8Header(payload);

                Buffer.BlockCopy(payload, vp8Header.Length, _currVideoFrame, _currVideoFramePosn, payload.Length - vp8Header.Length);
                _currVideoFramePosn += payload.Length - vp8Header.Length;

                if (marker)
                {
                    DateTime startTime = DateTime.Now;

                    List <byte[]> decodedFrames = _vp8Decoder.Decode(_currVideoFrame, _currVideoFramePosn, out var width, out var height);

                    if (decodedFrames == null)
                    {
                        logger.LogWarning("VPX decode of video sample failed.");
                    }
                    else
                    {
                        foreach (var decodedFrame in decodedFrames)
                        {
                            byte[] rgb = PixelConverter.I420toRGB(decodedFrame, (int)width, (int)height);
                            //Console.WriteLine($"VP8 decode took {DateTime.Now.Subtract(startTime).TotalMilliseconds}ms.");
                            OnVideoSinkDecodedSample(rgb, width, height, (int)(width * 3));
                        }
                    }

                    _currVideoFramePosn = 0;
                }
            }
            else
            {
                logger.LogWarning("Discarding RTP packet, VP8 header Start bit not set.");
                logger.LogWarning($"rtp video, seqnum {seqnum}, ts {timestamp}, marker {marker}, payload {payload.Length}.");
            }
        }
        public static RtpVP8Header GetVP8Header(byte[] rtpPayload)
        {
            RtpVP8Header vp8Header = new RtpVP8Header();
            int          payloadHeaderStartIndex = 1;

            // First byte of payload descriptor.
            vp8Header.ExtendedControlBitsPresent = ((rtpPayload[0] >> 7) & 0x01) == 1;
            vp8Header.StartOfVP8Partition        = ((rtpPayload[0] >> 4) & 0x01) == 1;
            vp8Header._length = 1;

            // Is second byte being used.
            if (vp8Header.ExtendedControlBitsPresent)
            {
                vp8Header.IsPictureIDPresent = ((rtpPayload[1] >> 7) & 0x01) == 1;
                vp8Header._length            = 2;
                payloadHeaderStartIndex      = 2;
            }

            // Is the picture ID being used.
            if (vp8Header.IsPictureIDPresent)
            {
                if (((rtpPayload[2] >> 7) & 0x01) == 1)
                {
                    // The Picture ID is using two bytes.
                    vp8Header._length       = 4;
                    payloadHeaderStartIndex = 4;
                    vp8Header.PictureID     = BitConverter.ToUInt16(rtpPayload, 2);
                }
                else
                {
                    // The picture ID is using one byte.
                    vp8Header.PictureID     = rtpPayload[2];
                    vp8Header._length       = 3;
                    payloadHeaderStartIndex = 3;
                }
            }

            vp8Header._payloadDescriptorLength = payloadHeaderStartIndex;

            return(vp8Header);
        }