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; // Payload header only on first packet in frame. if (vp8Header.StartOfVP8Partition) { byte s0 = (byte)((rtpPayload[payloadHeaderStartIndex] >> 5) & 0x07); vp8Header.ShowFrame = (byte)((rtpPayload[payloadHeaderStartIndex] >> 4) & 0x01) == 1; vp8Header.IsKeyFrame = (rtpPayload[payloadHeaderStartIndex] & 0x01) == 0; byte s1 = rtpPayload[payloadHeaderStartIndex + 1]; byte s2 = rtpPayload[payloadHeaderStartIndex + 2]; vp8Header.FirstPartitionSize = s0 + (8 * s1) + (2048 * s2); vp8Header._length += 3; } return(vp8Header); }
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; // Payload header only on first packet in frame. if (vp8Header.StartOfVP8Partition) { byte s0 = (byte)((rtpPayload[payloadHeaderStartIndex] >> 5) & 0x07); vp8Header.ShowFrame = (byte)((rtpPayload[payloadHeaderStartIndex] >> 4) & 0x01) == 1; vp8Header.IsKeyFrame = (rtpPayload[payloadHeaderStartIndex] & 0x01) == 0; byte s1 = rtpPayload[payloadHeaderStartIndex + 1]; byte s2 = rtpPayload[payloadHeaderStartIndex + 2]; vp8Header.FirstPartitionSize = s0 + (8 * s1) + (2048 * s2); vp8Header._length += 3; } return vp8Header; }
public byte[] GetFramePayload() { List <byte> payload = new List <byte>(); foreach (var rtpPacket in _packets.OrderBy(x => x.Header.SequenceNumber)) { if (FrameType == FrameTypesEnum.VP8) { var vp8Header = RTPVP8Header.GetVP8Header(rtpPacket.Payload); payload.AddRange(rtpPacket.Payload.Skip(vp8Header.PayloadDescriptorLength)); } else { payload.AddRange(rtpPacket.Payload); } } return(payload.ToArray()); }
private static void SendRTPFromVP8FramesFile(string file) { try { StreamReader sr = new StreamReader(file); List<string> samples = new List<string>(); while (!sr.EndOfStream) { string sample = sr.ReadLine(); samples.Add(sample); //Console.WriteLine(sample); //string[] sampleFields = sample.Split(','); //RTPVP8Header frameVP8Header = RTPVP8Header.GetVP8Header(Convert.FromBase64String(sampleFields[0])); //byte[] rtpPaylaod = Convert.FromBase64String(sampleFields[1]); //Console.WriteLine((frameVP8Header.IsKeyFrame) ? "K" : "." + " " + frameVP8Header.FirstPartitionSize + " " + rtpPaylaod.Length + "."); } sr.Close(); logger.Debug(samples.Count + " encoded samples loaded."); //_newRTPReceiverSRTP = new SRTPManaged(Convert.FromBase64String(_sourceSRTPKey)); //_newRTPReceiverSRTP = new SRTPManaged(); int sampleIndex = 0; while (true) { if (_webRTCClients.Count != 0) { var sampleItem = samples[sampleIndex]; string[] sampleFields = sampleItem.Split(','); RTPVP8Header frameVP8Header = RTPVP8Header.GetVP8Header(Convert.FromBase64String(sampleFields[0])); byte[] sample = Convert.FromBase64String(sampleFields[1]); if (frameVP8Header.IsKeyFrame) { Console.WriteLine("Key frame."); } lock (_webRTCClients) { foreach (var client in _webRTCClients.Where(x => x.STUNExchangeComplete)) { try { if (client.LastTimestamp == 0) { client.LastTimestamp = RTSPSession.DateTimeToNptTimestamp32(DateTime.Now); } for (int index = 0; index * RTP_MAX_PAYLOAD < sample.Length; index++) { int offset = (index == 0) ? 0 : (index * RTP_MAX_PAYLOAD); int payloadLength = (offset + RTP_MAX_PAYLOAD < sample.Length) ? RTP_MAX_PAYLOAD : sample.Length - offset; RTPVP8Header packetVP8Header = new RTPVP8Header() { ExtendedControlBitsPresent = true, IsPictureIDPresent = true, ShowFrame = true, }; if (index == 0) { packetVP8Header.StartOfVP8Partition = true; //packetVP8Header.FirstPartitionSize = frameVP8Header.FirstPartitionSize; packetVP8Header.IsKeyFrame = frameVP8Header.IsKeyFrame; packetVP8Header.PictureID = (frameVP8Header.IsKeyFrame) ? (byte)0x00 : frameVP8Header.PictureID; } byte[] vp8HeaderBytes = packetVP8Header.GetBytes(); RTPPacket rtpPacket = new RTPPacket(packetVP8Header.Length + payloadLength + SRTP_AUTH_KEY_LENGTH); rtpPacket.Header.SyncSource = client.SSRC; rtpPacket.Header.SequenceNumber = client.SequenceNumber++; rtpPacket.Header.Timestamp = client.LastTimestamp; rtpPacket.Header.MarkerBit = ((offset + payloadLength) >= sample.Length) ? 1 : 0; rtpPacket.Header.PayloadType = 100; Buffer.BlockCopy(vp8HeaderBytes, 0, rtpPacket.Payload, 0, packetVP8Header.Length); Buffer.BlockCopy(sample, offset, rtpPacket.Payload, packetVP8Header.Length, payloadLength); var rtpBuffer = rtpPacket.GetBytes(); _webRTCReceiverClient.Send(rtpBuffer, rtpBuffer.Length - SRTP_AUTH_KEY_LENGTH, _wiresharpEP); int rtperr = client.SrtpContext.ProtectRTP(rtpBuffer, rtpBuffer.Length - SRTP_AUTH_KEY_LENGTH); if (rtperr != 0) { logger.Debug("New RTP packet protect result " + rtperr + "."); } logger.Debug("Sending RTP " + sample.Length + " bytes to " + client.SocketAddress + ", timestamp " + client.LastTimestamp + ", marker " + rtpPacket.Header.MarkerBit + "."); _webRTCReceiverClient.Send(rtpBuffer, rtpBuffer.Length, client.SocketAddress); } client.LastTimestamp += TIMESTAMP_SPACING; } catch (Exception sendExcp) { logger.Error("SendRTPFromVP8FramesFile exception sending to " + client.SocketAddress + ". " + sendExcp.Message); } } } sampleIndex++; if (sampleIndex >= samples.Count - 1) { sampleIndex = 0; } Thread.Sleep(30); } } } catch (Exception excp) { Console.WriteLine("Exception SendRTPFromVP8FramesFile. " + excp); } }