/// <summary> /// Decodes RTMP packet header. /// </summary> /// <param name="context">RTMP protocol state.</param> /// <param name="lastHeader">Previous header.</param> /// <param name="stream">Buffer to be decoded.</param> /// <returns>Decoded RTMP header.</returns> public static RtmpHeader DecodeHeader(RtmpContext context, RtmpHeader lastHeader, ByteBuffer stream) { byte headerByte = stream.Get(); int headerValue; int byteCount = 1; if ((headerByte & 0x3f) == 0) { // Two byte header headerValue = ((int)headerByte & 0xff) << 8 | ((int)stream.Get() & 0xff); byteCount = 2; } else if ((headerByte & 0x3f) == 1) { // Three byte header headerValue = ((int)headerByte & 0xff) << 16 | ((int)stream.Get() & 0xff) << 8 | ((int)stream.Get() & 0xff); byteCount = 3; } else { // Single byte header headerValue = (int)headerByte & 0xff; byteCount = 1; } byte channelId = DecodeChannelId(headerValue, byteCount); byte headerSize = DecodeHeaderSize(headerValue, byteCount); RtmpHeader header = new RtmpHeader(); header.ChannelId = channelId; header.IsTimerRelative = (HeaderType)headerSize != HeaderType.HeaderNew; if ((HeaderType)headerSize != HeaderType.HeaderNew && lastHeader == null) { #if !SILVERLIGHT if (log.IsErrorEnabled) log.Error(string.Format("Last header null not new, headerSize: {0}, channelId {1}", headerSize, channelId)); #endif lastHeader = new RtmpHeader(); lastHeader.ChannelId = channelId; lastHeader.IsTimerRelative = (HeaderType)headerSize != HeaderType.HeaderNew; } #if !SILVERLIGHT if (log.IsDebugEnabled) log.Debug(__Res.GetString(__Res.Rtmp_DecodeHeader, Enum.GetName(typeof(HeaderType), (HeaderType)headerSize))); #endif switch ((HeaderType)headerSize) { case HeaderType.HeaderNew: header.Timer = stream.ReadUInt24();// ReadUnsignedMediumInt(); header.Size = stream.ReadUInt24();// ReadMediumInt(); header.DataType = stream.Get(); header.StreamId = stream.ReadReverseInt(); break; case HeaderType.HeaderSameSource: header.Timer = stream.ReadUInt24();// ReadUnsignedMediumInt(); header.Size = stream.ReadUInt24();// ReadMediumInt(); header.DataType = stream.Get(); header.StreamId = lastHeader.StreamId; break; case HeaderType.HeaderTimerChange: header.Timer = stream.ReadUInt24();//ReadUnsignedMediumInt(); header.Size = lastHeader.Size; header.DataType = lastHeader.DataType; header.StreamId = lastHeader.StreamId; break; case HeaderType.HeaderContinue: header.Timer = lastHeader.Timer; header.Size = lastHeader.Size; header.DataType = lastHeader.DataType; header.StreamId = lastHeader.StreamId; header.IsTimerRelative = lastHeader.IsTimerRelative; break; default: #if !SILVERLIGHT log.Error("Unexpected header size: " + headerSize); #endif return null; } if (header.Timer >= 0xffffff) { //Extended timestamp header.Timer = stream.GetInt(); } return header; }