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 Picure 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); }
/// <summary> /// Render a video RTP packet received from a remote party. /// </summary> /// <param name="rtpPacket">The RTP packet containing the video payload.</param> private void RenderVideo(RTPPacket rtpPacket) { if ((rtpPacket.Payload[0] & 0x10) > 0) { RtpVP8Header vp8Header = RtpVP8Header.GetVP8Header(rtpPacket.Payload); Buffer.BlockCopy(rtpPacket.Payload, vp8Header.Length, _currVideoFrame, _currVideoFramePosn, rtpPacket.Payload.Length - vp8Header.Length); _currVideoFramePosn += rtpPacket.Payload.Length - vp8Header.Length; if (rtpPacket.Header.MarkerBit == 1) { unsafe { fixed(byte *p = _currVideoFrame) { uint width = 0, height = 0; byte[] i420 = null; //Console.WriteLine($"Attempting vpx decode {_currVideoFramePosn} bytes."); int decodeResult = _vpxDecoder.Decode(p, _currVideoFramePosn, ref i420, ref width, ref height); if (decodeResult != 0) { Console.WriteLine("VPX decode of video sample failed."); } else { if (OnVideoSampleReady != null) { fixed(byte *r = i420) { byte[] bmp = null; int stride = 0; int convRes = _imgConverter.ConvertYUVToRGB(r, VideoSubTypesEnum.I420, (int)width, (int)height, VideoSubTypesEnum.BGR24, ref bmp, ref stride); if (convRes == 0) { //fixed (byte* s = bmp) //{ // System.Drawing.Bitmap bmpImage = new System.Drawing.Bitmap((int)width, (int)height, stride, System.Drawing.Imaging.PixelFormat.Format24bppRgb, (IntPtr)s); //} OnVideoSampleReady(bmp, width, height, stride); } else { Log.LogWarning("Pixel format conversion of decoded sample failed."); } } } } } } _currVideoFramePosn = 0; } } else { Log.LogWarning("Discarding RTP packet, VP8 header Start bit not set."); Log.LogWarning($"rtp video, seqnum {rtpPacket.Header.SequenceNumber}, ts {rtpPacket.Header.Timestamp}, marker {rtpPacket.Header.MarkerBit}, payload {rtpPacket.Payload.Length}, payload[0-5] {rtpPacket.Payload.HexStr(5)}."); } }