Пример #1
0
        public bool Parse(byte[] h264Stream)
        {
            profile     = 0;
            level       = 0;
            refFrames   = 0;
            currrentPos = 0;
            buffer      = h264Stream;

            byte[] nal = new byte[0];
            while (nal != null)
            {
                nal = ReadNALUnit();
                if (nal != null)
                {
                    NALUnit nu = NALUnit.Read(nal);
                    if (nu.Type == NALUnitType.SequenceParameterSet)
                    {
                        SeqParameterSet param = SeqParameterSet.Read(nu.Data);
                        if (Enum.IsDefined(typeof(H264HeaderProfile), param.profile_idc) == true)
                        {
                            profile   = param.profile_idc;
                            level     = param.level_idc;
                            refFrames = param.num_ref_frames;
                            return(true);
                        }
                    }
                }
            }

            return(false);
        }
Пример #2
0
 private NALUnit[] ReadNALUnitArray(MemoryStream stream, int cnt)
 {
     return(Enumerable.Range(0, cnt)
            .Select(_ => {
         var len = stream.ReadUInt16BE();
         return NALUnit.ReadFrom(stream, len);
     })
            .ToArray());
 }
Пример #3
0
 private void NALUnitAudioAdd(NALUnit cNALUnit)
 {
     if (cNALUnit.nStart + cNALUnit.nBytesQty > _cStream.nBytesBuffered)
     {
         _cStream.Cache(cNALUnit.nStart + cNALUnit.nBytesQty - _cStream.nBytesBuffered);
     }
     lock (_cSyncRoot)
         _aAudioNALs.Add(cNALUnit);
 }
Пример #4
0
            public static NALUnit Read(byte[] nalData)
            {
                int nalu   = nalData[0] & 0xFF;
                int refIdc = (nalu >> 5) & 0x03;
                int type   = nalu & 0x1F;

                if (Enum.IsDefined(typeof(NALUnitType), type) == false)
                {
                    type = 0;
                }

                NALUnit nal = new NALUnit();

                nal.Type   = (NALUnitType)type;
                nal.RefIDC = refIdc;
                nal.Data   = new byte[nalData.Length - 1];
                Array.Copy(nalData, 1, nal.Data, 0, nal.Data.Length);
                return(nal);
            }
Пример #5
0
        private void NALUnitVideoAdd(NALUnit cNALUnit)
        {
            if (cNALUnit.nStart + cNALUnit.nBytesQty > _cStream.nBytesBuffered)
            {
                _cStream.Cache(cNALUnit.nStart + cNALUnit.nBytesQty - _cStream.nBytesBuffered);
            }
            double nProgress = 0;

            lock (_cSyncRoot)
            {
                _aVideoNALs.Add(cNALUnit);
                if (cNALUnit.bFrameStart)
                {
                    _nFramesBuffered++;
                    if (_bAudioFrameNeeded)
                    {
                        if (1 < (nProgress = (double)(_nFramesBuffered - _nCurrentFrameVideo) / (_nBufferSeconds * 25)))
                        {
                            nProgress = 1;
                        }
                        ReportGetSampleProgress(nProgress);
                    }
                }
            }
            if (0.9 < nProgress)
            {
                if (_bAudioFrameNeeded)
                {
                    GetSampleAsync(MediaStreamType.Audio);
                }
                if (_bVideoFrameNeeded)
                {
                    GetSampleAsync(MediaStreamType.Video);
                }
            }
        }
Пример #6
0
            private void OnAVCBody(RTMPMessage msg, bool keyframe)
            {
                var pts = msg.Timestamp - Math.Max(0, ptsBase);
                var cts = msg.Body.Skip(2).Take(3).Aggregate(0, (r, v) => (r << 8) | v);

                if (cts >= 0x800000)
                {
                    cts = 0x1000000 - cts;
                }
                var dts = pts;

                pts = pts + cts;
                var access_unit_delimiter = false;
                var idr           = false;
                var nalbytestream = new MemoryStream();
                int units         = 0;

                using (nalbytestream)
                    using (var body = new MemoryStream(msg.Body, 0, msg.Body.Length)) {
                        body.Seek(5, SeekOrigin.Begin);
                        while (body.Position < body.Length)
                        {
                            var len  = body.ReadBytes(nalSizeLen).Aggregate(0, (r, v) => (r << 8) | v);
                            var nalu = NALUnit.ReadFrom(body, len);
                            if (nalu.NALUnitType == 9)
                            {
                                access_unit_delimiter = true;
                            }
                            if (!access_unit_delimiter)
                            {
                                NALUnit.WriteToByteStream(nalbytestream, NALUnit.AccessUnitDelimiter);
                                access_unit_delimiter = true;
                            }
                            if (nalu.NALUnitType == 5)
                            {
                                idr = true;
                                foreach (var unit in sps)
                                {
                                    NALUnit.WriteToByteStream(nalbytestream, unit);
                                }
                                foreach (var unit in pps)
                                {
                                    NALUnit.WriteToByteStream(nalbytestream, unit);
                                }
                                foreach (var unit in spsExt)
                                {
                                    NALUnit.WriteToByteStream(nalbytestream, unit);
                                }
                            }
                            NALUnit.WriteToByteStream(nalbytestream, nalu);
                            units += 1;
                        }
                    }
                var pes = new PESPacket(
                    0xE0,
                    TSTimeStamp.FromMilliseconds(pts),
                    TSTimeStamp.FromMilliseconds(dts),
                    nalbytestream.ToArray()
                    );
                var pes_packet = new MemoryStream();

                using (pes_packet) {
                    PESPacket.WriteTo(pes_packet, pes);
                }
                writer.WriteTSPackets(
                    VideoPID,
                    msg.IsKeyFrame() || idr,
                    idr ? (TSTimeStamp?)TSTimeStamp.FromMilliseconds(dts) : null,
                    pes_packet.ToArray()
                    );
            }
Пример #7
0
 public static void WriteToByteStream(Stream s, NALUnit unit)
 {
     s.Write(WritePrefix, 0, WritePrefix.Length);
     s.WriteByte((byte)((unit.NALRefIdc << 5) | (unit.NALUnitType & 0x1F)));
     s.Write(unit.Payload, 0, unit.Payload.Length);
 }
Пример #8
0
		private void NALUnitParse()
        {
			//3. NumBytesInNALunit is set equal to the number of bytes starting with the byte at the current position in the byte
			//stream up to and including the last byte that precedes the location of any of the following:
			//– A subsequent byte-aligned three-byte sequence equal to 0x000000,
			//– A subsequent byte-aligned three-byte sequence equal to 0x000001,
			//– The end of the byte stream, as determined by unspecified means.
			//4. NumBytesInNALunit bytes are removed from the bitstream and the current position in the byte stream is
			//advanced by NumBytesInNALunit bytes. This sequence of bytes is nal_unit( NumBytesInNALunit ) and is
			//decoded using the NAL unit decoding process.

			//5. When the current position in the byte stream is not at the end of the byte stream (as determined by unspecified
			//means) and the next bytes in the byte stream do not start with a three-byte sequence equal to 0x000001 and the
			//next bytes in the byte stream do not start with a four byte sequence equal to 0x00000001, the decoder extracts
			//and discards each trailing_zero_8bits syntax element, moving the current position in the byte stream forward
			//one byte at a time, until the current position in the byte stream is such that the next bytes in the byte stream form
			//the four-byte sequence 0x00000001 or the end of the byte stream has been encountered (as determined by
			//unspecified means).
			NALUnit cNALUnitAudio = null;
			NALUnit cNALUnitVideo = new NALUnit();
			cNALUnitVideo.nStart = _cStream.Position - 3;
			
			bool bNALStart = false;
			byte nStepVideo = 0, nStepAudio = 0;
			int nByte = 0;

			//_cStream.ReadByte();
			//int nByteType = _cStream.ReadByte();
			//if (0 > nByteType)
			//    throw new Exception();
			while (true)
			{
				if (_cStream.Position >= nDataSize + nDataStart || 0 > (nByte = _cStream.ReadByte()))
					throw new Exception();

				if (0x00 == nByte)
				{
					nStepAudio = 0;
					nStepVideo++;
					if (2 < nStepVideo)
						bNALStart = true;
				}
				else if (0x01 == nByte)
				{
					nStepAudio = 0;
					if (1 < nStepVideo)
						bNALStart = true;
					else
						nStepVideo = 0;
				}
				else
				{
					nStepVideo = 0;
					if (0xFF == nByte)
						nStepAudio = 1;
					else if (0xFB == nByte && 1 == nStepAudio)
						nStepAudio++;
					else if (_nAudioMP3ControlByte == nByte && 2 == nStepAudio)
						nStepAudio++;
					else if ((0x64 == nByte || 0x44 == nByte) && 3 == nStepAudio)
					{
						long nPosition = _cStream.Position;
						_cStream.Position += _cMP3WaveFormat.BlockSize - 4;
						nByte = _cStream.ReadByte();
						if ((0 == nByte && 0 == _cStream.ReadByte() && 0 == _cStream.ReadByte()) || (0xFF == nByte && 0xFB == _cStream.ReadByte() && _nAudioMP3ControlByte == _cStream.ReadByte()))
						{
							if (null != cNALUnitVideo)
							{
								cNALUnitVideo.nBytesQty = nPosition - cNALUnitVideo.nStart - 4;
								cNALUnitVideo.bFrameStart = true;
								NALUnitVideoAdd(cNALUnitVideo);
								lock (_cSyncRoot)
									_aFramesOffsets.Add(new FrameOffset(_aAudioNALs.Count + 1, _aVideoNALs.Count));
								cNALUnitVideo = null;
							}
							cNALUnitAudio = new NALUnit();
							cNALUnitAudio.nStart = nPosition - 4;
							cNALUnitAudio.nBytesQty = (long)_cMP3WaveFormat.BlockSize;
							NALUnitAudioAdd(cNALUnitAudio);
							_cStream.Position -= 3;
						}
						else
							_cStream.Position = nPosition;
						nStepAudio = 0;
					}
					else
						nStepAudio = 0;
				}
				if (bNALStart)
				{
					if (null != cNALUnitVideo)
					{
						cNALUnitVideo.nBytesQty = _cStream.Position - cNALUnitVideo.nStart - 2;
						NALUnitVideoAdd(cNALUnitVideo);
					}
					return;
				}
			}
		}
Пример #9
0
		private void NALUnitAudioAdd(NALUnit cNALUnit)
		{
			if (cNALUnit.nStart + cNALUnit.nBytesQty > _cStream.nBytesBuffered)
				_cStream.Cache(cNALUnit.nStart + cNALUnit.nBytesQty - _cStream.nBytesBuffered);
			lock (_cSyncRoot)
				_aAudioNALs.Add(cNALUnit);
		}
Пример #10
0
		private void NALUnitVideoAdd(NALUnit cNALUnit)
		{
			if (cNALUnit.nStart + cNALUnit.nBytesQty > _cStream.nBytesBuffered)
				_cStream.Cache(cNALUnit.nStart + cNALUnit.nBytesQty - _cStream.nBytesBuffered);
			double nProgress = 0;
			lock (_cSyncRoot)
			{
				_aVideoNALs.Add(cNALUnit);
				if (cNALUnit.bFrameStart)
				{
					_nFramesBuffered++;
					if (_bAudioFrameNeeded)
					{
						if (1 < (nProgress = (double)(_nFramesBuffered - _nCurrentFrameVideo) / (_nBufferSeconds * 25)))
							nProgress = 1;
						ReportGetSampleProgress(nProgress);
					}
				}
			}
			if (0.9 < nProgress)
			{
				if (_bAudioFrameNeeded)
					GetSampleAsync(MediaStreamType.Audio);
				if (_bVideoFrameNeeded)
					GetSampleAsync(MediaStreamType.Video);
			}
		}
Пример #11
0
        public override MediaFrame Depacketize(RtpPacket pkt)
        {
            MediaFrame frame = null;

            if (pkt.Sequence != (lastSequence + 1))
            {
                logger.Warn("Bad sequence " + lastSequence + " != " + pkt.Sequence);
                // TODO:
                // Добавляем в буфер и пытаемся упорядочить
            }

            lastSequence = pkt.Sequence;
            bool newTimestampSequence = false;
            var  timestamp            = pkt.Timestamp;

            if (timestamp != RtpConst.NoTimestamp && timestamp != lastTimestamp)
            {
                if (lastTimestamp != RtpConst.NoTimestamp)
                {
                    var diff = (timestamp - lastTimestamp);
                    if (diff < 0)
                    { // TODO:
                    }

                    unwrappedTimestamp += diff;
                }

                lastTimestamp        = timestamp;
                newTimestampSequence = true;

                // logger.Warn(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ");
            }

            if (newTimestampSequence)
            { // группируем по временным меткам
              // т.е сервер должен передавать данные с правильным вр.метками иначе работать не будет...

                if (naluBuffer.Count > 0)
                {
                    var firstNalu = naluBuffer[0];

                    // все вр.метки должны быть одинаковые...
                    var naluTimestamp = firstNalu.timestamp;

                    var dataBuffer  = new List <byte[]>();
                    int totalLength = 0;
                    foreach (var nal in naluBuffer)
                    {
                        if (naluTimestamp != nal.timestamp)
                        {
                            logger.Warn("naluTimstamp  != nal.timestamp");
                        }

                        var data = nal.data;
                        dataBuffer.Add(data);
                        totalLength += data.Length;
                    }

                    //var dataBuffer = naluBuffer.Select(n => n.data);
                    //var totalLength = dataBuffer.Sum(n => n.Length);

                    var nalUnitData = new byte[totalLength];
                    int offset      = 0;
                    foreach (var data in dataBuffer)
                    {
                        Array.Copy(data, 0, nalUnitData, offset, data.Length);
                        offset += data.Length;
                    }

                    var naluTime = (naluTimestamp / (double)ClockRate);

                    frame = new MediaFrame
                    {
                        Data = nalUnitData,
                        Time = naluTime,
                    };

                    naluBuffer.Clear();
                }
            }

            if (naluBuffer.Count > 256)
            {
                if (timestamp == RtpConst.NoTimestamp || lastTimestamp == RtpConst.NoTimestamp ||
                    timestamp == 0 || lastTimestamp == 0)
                {// если не удается получить правильные вр.метки - сбрасываем буфер
                 // т.к декодировать не сгруппированные данные не все декодеры могу...

                    logger.Error("No valid timestamp received; drop buffer");
                    naluBuffer.Clear();
                }
            }

            NALUnit nalUnit = null;

            byte[] payload = pkt.Payload.ToArray();
            if (payload != null && payload.Length > 0)
            {
                nalUnit = ParseH264Payload(payload, unwrappedTimestamp);
            }

            if (nalUnit != null)
            {
                naluBuffer.Add(nalUnit);
            }

            return(frame);

            //if (data != null)
            //{
            //    frame = new MediaFrame
            //    {
            //        Data = data,
            //        Time = monotonicTime,
            //    };
            //}

            //return frame;
        }
Пример #12
0
        protected override void GetSampleAsync(MediaStreamType eMediaStreamType)
        {
            Dictionary <MediaSampleAttributeKeys, string> emptyDict = new Dictionary <MediaSampleAttributeKeys, string>();
            MediaStreamSample cMediaStreamSample = null;
            NALUnit           cNALUnit           = null;

            lock (_cSyncRoot)
            {
                if (!_bCached && _nCurrentFrameVideo >= _nFramesBuffered)
                {
                    this.ReportGetSampleProgress(0);
                    if (MediaStreamType.Audio == eMediaStreamType)
                    {
                        _bAudioFrameNeeded = true;
                    }
                    else
                    {
                        _bVideoFrameNeeded = true;
                    }
                    return;
                }
                if (MediaStreamType.Audio == eMediaStreamType)
                {
                    _bAudioFrameNeeded = false;
                }
                else
                {
                    _bVideoFrameNeeded = false;
                }
            }
            if (eMediaStreamType == MediaStreamType.Audio)
            {
                try
                {
                    lock (_cSyncRoot)
                    {
                        if (0 < _aAudioNALs.Count && _aAudioNALs.Count > _nFrameOffsetAudio)
                        {
                            cNALUnit = _aAudioNALs[_nFrameOffsetAudio++];
                        }
                    }
                    if (null != cNALUnit)
                    {
                        cMediaStreamSample = new MediaStreamSample(_cMediaStreamAudioDescription, new MemoryStream(_cStream.Read(cNALUnit.nStart, cNALUnit.nBytesQty)), 0, cNALUnit.nBytesQty, (long)(_nCurrentFrameAudio * _nSampleDuration), emptyDict);                         //(long)(_nCurrentFrameAudio * _nSampleDuration)
                        _nCurrentFrameAudio++;
                    }
                }
                catch { }
                if (null == cMediaStreamSample)
                {
                    cMediaStreamSample = new MediaStreamSample(_cMediaStreamAudioDescription, null, 0, 0, 0, emptyDict);
                }
            }
            else
            {
                try
                {
                    lock (_cSyncRoot)
                        if (0 < _aVideoNALs.Count && _aVideoNALs.Count > _nFrameOffsetVideo)
                        {
                            cNALUnit = _aVideoNALs[_nFrameOffsetVideo++];
                        }
                    if (null != cNALUnit)
                    {
                        cMediaStreamSample = new MediaStreamSample(_cMediaStreamVideoDescription, new MemoryStream(_cStream.Read(cNALUnit.nStart, cNALUnit.nBytesQty)), 0, cNALUnit.nBytesQty, (long)(_nCurrentFrameVideo * _nFrameDuration), emptyDict);                         //(long)(_nCurrentFrameVideo * _nFrameDuration)
                    }
                    if (null == cNALUnit || cNALUnit.bFrameStart)
                    {
                        _nCurrentFrameVideo++;
                    }
                }
                catch { }
                if (null == cMediaStreamSample)
                {
                    cMediaStreamSample = new MediaStreamSample(_cMediaStreamVideoDescription, null, 0, 0, 0, emptyDict);
                }
            }
            this.ReportGetSampleCompleted(cMediaStreamSample);
        }
Пример #13
0
        private void NALUnitParse()
        {
            //3. NumBytesInNALunit is set equal to the number of bytes starting with the byte at the current position in the byte
            //stream up to and including the last byte that precedes the location of any of the following:
            //– A subsequent byte-aligned three-byte sequence equal to 0x000000,
            //– A subsequent byte-aligned three-byte sequence equal to 0x000001,
            //– The end of the byte stream, as determined by unspecified means.
            //4. NumBytesInNALunit bytes are removed from the bitstream and the current position in the byte stream is
            //advanced by NumBytesInNALunit bytes. This sequence of bytes is nal_unit( NumBytesInNALunit ) and is
            //decoded using the NAL unit decoding process.

            //5. When the current position in the byte stream is not at the end of the byte stream (as determined by unspecified
            //means) and the next bytes in the byte stream do not start with a three-byte sequence equal to 0x000001 and the
            //next bytes in the byte stream do not start with a four byte sequence equal to 0x00000001, the decoder extracts
            //and discards each trailing_zero_8bits syntax element, moving the current position in the byte stream forward
            //one byte at a time, until the current position in the byte stream is such that the next bytes in the byte stream form
            //the four-byte sequence 0x00000001 or the end of the byte stream has been encountered (as determined by
            //unspecified means).
            NALUnit cNALUnitAudio = null;
            NALUnit cNALUnitVideo = new NALUnit();

            cNALUnitVideo.nStart = _cStream.Position - 3;

            bool bNALStart = false;
            byte nStepVideo = 0, nStepAudio = 0;
            int  nByte = 0;

            //_cStream.ReadByte();
            //int nByteType = _cStream.ReadByte();
            //if (0 > nByteType)
            //    throw new Exception();
            while (true)
            {
                if (_cStream.Position >= nDataSize + nDataStart || 0 > (nByte = _cStream.ReadByte()))
                {
                    throw new Exception();
                }

                if (0x00 == nByte)
                {
                    nStepAudio = 0;
                    nStepVideo++;
                    if (2 < nStepVideo)
                    {
                        bNALStart = true;
                    }
                }
                else if (0x01 == nByte)
                {
                    nStepAudio = 0;
                    if (1 < nStepVideo)
                    {
                        bNALStart = true;
                    }
                    else
                    {
                        nStepVideo = 0;
                    }
                }
                else
                {
                    nStepVideo = 0;
                    if (0xFF == nByte)
                    {
                        nStepAudio = 1;
                    }
                    else if (0xFB == nByte && 1 == nStepAudio)
                    {
                        nStepAudio++;
                    }
                    else if (_nAudioMP3ControlByte == nByte && 2 == nStepAudio)
                    {
                        nStepAudio++;
                    }
                    else if ((0x64 == nByte || 0x44 == nByte) && 3 == nStepAudio)
                    {
                        long nPosition = _cStream.Position;
                        _cStream.Position += _cMP3WaveFormat.BlockSize - 4;
                        nByte              = _cStream.ReadByte();
                        if ((0 == nByte && 0 == _cStream.ReadByte() && 0 == _cStream.ReadByte()) || (0xFF == nByte && 0xFB == _cStream.ReadByte() && _nAudioMP3ControlByte == _cStream.ReadByte()))
                        {
                            if (null != cNALUnitVideo)
                            {
                                cNALUnitVideo.nBytesQty   = nPosition - cNALUnitVideo.nStart - 4;
                                cNALUnitVideo.bFrameStart = true;
                                NALUnitVideoAdd(cNALUnitVideo);
                                lock (_cSyncRoot)
                                    _aFramesOffsets.Add(new FrameOffset(_aAudioNALs.Count + 1, _aVideoNALs.Count));
                                cNALUnitVideo = null;
                            }
                            cNALUnitAudio           = new NALUnit();
                            cNALUnitAudio.nStart    = nPosition - 4;
                            cNALUnitAudio.nBytesQty = (long)_cMP3WaveFormat.BlockSize;
                            NALUnitAudioAdd(cNALUnitAudio);
                            _cStream.Position -= 3;
                        }
                        else
                        {
                            _cStream.Position = nPosition;
                        }
                        nStepAudio = 0;
                    }
                    else
                    {
                        nStepAudio = 0;
                    }
                }
                if (bNALStart)
                {
                    if (null != cNALUnitVideo)
                    {
                        cNALUnitVideo.nBytesQty = _cStream.Position - cNALUnitVideo.nStart - 2;
                        NALUnitVideoAdd(cNALUnitVideo);
                    }
                    return;
                }
            }
        }