public bool FeedAudioData(InputStream pData, uint dataLength, ref RTPHeader rtpHeader) { if (_audioSequence == 0) { //this is the first packet. Make sure we start with a M packet if (!rtpHeader.M) { return(true); } _audioSequence = rtpHeader.SEQ; return(true); } else { if (_audioSequence + 1 != rtpHeader.SEQ) { WARN("Missing audio packet. Wanted: {0}; got: {1} on stream: {2}", (_audioSequence + 1), rtpHeader.SEQ, Name); _audioDroppedPacketsCount++; _audioSequence = 0; return(true); } else { _audioSequence++; } } //1. Compute chunks count var chunksCount = pData.Reader.ReadUInt16(); if ((chunksCount % 16) != 0) { FATAL("Invalid AU headers length: {0}", chunksCount); return(false); } chunksCount = (ushort)(chunksCount >> 4); //3. Feed the buffer chunk by chunk var cursor = 2u + 2u * chunksCount; var rtpTs = ComputeRTP(ref rtpHeader.Timestamp, ref _audioLastRTP, ref _audioRTPRollCount); for (var i = 0; i < chunksCount; i++) { uint chunkSize; if (i != (chunksCount - 1)) { chunkSize = (uint)((pData.Reader.ReadUInt16()) >> 3); } else { chunkSize = dataLength - cursor; } uint ts = (uint)((rtpTs + (ulong)i * 1024ul) * 1000 / Capabilities.Samplerate); if ((cursor + chunkSize) > dataLength) { FATAL("Unable to feed data: cursor:{0}; chunkSize: {1}; dataLength: {2}; chunksCount: {3}", cursor, chunkSize, dataLength, chunksCount); return(false); } _audioPacketsCount++; _audioBytesCount += chunkSize; if (!FeedData(pData, chunkSize + 2, 0, chunkSize + 2, ts, true)) { FATAL("Unable to feed data"); return(false); } cursor += chunkSize; } return(true); }
public bool FeedVideoData(InputStream pData, uint dataLength, ref RTPHeader rtpHeader) { var firstByte = pData.Reader.ReadByte(); var secondByte = pData.Reader.ReadByte(); pData.Position -= 1; //1. Check the counter first if (_videoSequence == 0) { //this is the first packet. Make sure we start with a M packet if (!rtpHeader.M) { return(true); } _videoSequence = rtpHeader.SEQ; return(true); } if ((ushort)(_videoSequence + 1) != (ushort)rtpHeader.SEQ) { WARN("Missing video packet. Wanted: {0}; got: {1} on stream: {2}", (ushort)(_videoSequence + 1), rtpHeader.SEQ, Name); _currentNalu.IgnoreAll(); _videoDroppedPacketsCount++; _videoSequence = 0; return(true); } _videoSequence++; //2. get the nalu var rtpTs = ComputeRTP(ref rtpHeader.Timestamp, ref _videoLastRTP, ref _videoRTPRollCount); uint ts = (uint)(rtpTs * 1000 / Capabilities.Avc.Rate); var naluType = (byte)(firstByte & 0x1f); if (naluType <= 23) { //3. Standard NALU //FINEST("V: %08"PRIx32, rtpHeader._timestamp); _videoPacketsCount++; _videoBytesCount += dataLength; pData.Position -= 1; return(FeedData(pData, dataLength, 0, dataLength, ts, false)); } else { switch ((NaluType)naluType) { case NaluType.NALU_TYPE_FUA: if (_currentNalu.GetAvaliableByteCounts() == 0) { _currentNalu.IgnoreAll(); if (secondByte >> 7 == 0) { WARN("Bogus nalu"); _currentNalu.IgnoreAll(); _videoSequence = 0; return(true); } secondByte = (byte)((firstByte & 0xe0) | (secondByte & 0x1f)); pData.WriteByte(secondByte); pData.Position -= 1; pData.WriteTo(_currentNalu); return(true); } else { pData.Position += 1; pData.WriteTo(_currentNalu); if (((secondByte >> 6) & 0x01) == 1) { //FINEST("V: %08"PRIx32, rtpHeader._timestamp); _videoPacketsCount++; _videoBytesCount += (ulong)_currentNalu.GetAvaliableByteCounts(); if (!FeedData(_currentNalu, (uint)_currentNalu.GetAvaliableByteCounts(), 0, (uint)_currentNalu.GetAvaliableByteCounts(), ts, false)) { FATAL("Unable to feed NALU"); return(false); } _currentNalu.IgnoreAll(); } return(true); } case NaluType.NALU_TYPE_STAPA: var index = 1; while (index + 3 < dataLength) { var length = pData.Reader.ReadUInt16(); index += 2; if (index + length > dataLength) { WARN("Bogus STAP-A"); _currentNalu.IgnoreAll(); _videoSequence = 0; return(true); } _videoPacketsCount++; _videoBytesCount += length; if (!FeedData(pData, length, 0, length, ts, false)) { FATAL("Unable to feed NALU"); return(false); } index += length; } return(true); default: WARN("invalid NAL: {0}", naluType); _currentNalu.IgnoreAll(); _videoSequence = 0; return(true); } } }