コード例 #1
0
            public List <RtspFrame> ProcessData(byte[] buf, int length, RtpSession session)
            {
                List <RtspFrame> frames = new List <RtspFrame>();
                int offset = 0;
                int pos    = 0;

                while (true)
                {
                    if (offset >= length)
                    {
                        logger.Debug("!!!!!!!!!!!!!!!!!!! " + offset + " >= " + length);

                        break;
                        //return;
                    }

                    if (tcpBufferOffset > 0)
                    {// если остались не обработанные данные
                        int len     = length - offset;
                        int newSize = tcpBufferOffset + len;

                        byte[] newBuf = new byte[newSize];

                        Array.Copy(tcpBuffer, 0, newBuf, 0, tcpBufferOffset);

                        Array.Copy(buf, offset, newBuf, tcpBufferOffset, len);

                        tcpBufferOffset = 0;

                        // Debug.WriteLine("ProcessTcpBuffer newSize " + newSize);

                        buf    = newBuf;
                        length = newSize;
                    }

                    if (streamState == RtspStreamState.WaitDollar ||
                        streamState == RtspStreamState.ReadHeader ||
                        streamState == RtspStreamState.ReadContent)
                    {
                        for (int i = offset; i < length; i++)
                        {
                            char ch = (char)buf[i];
                            if (ch == '$')
                            {
                                //Console.WriteLine("Find dollar at pos: " + i);

                                streamState = RtspStreamState.ReadId;
                                pos         = i + 1; //header
                                rtspFrame   = new RtspFrame();

                                break;
                            }
                        }
                    }

                    if (streamState == RtspStreamState.ReadId)
                    {// идентификатор 1 байт
                        int len = length - pos;
                        if (len > 0)
                        {
                            rtspFrame.Id = buf[pos];
                            //Console.WriteLine("ID: " + rtspFrame.Id + " pos: " + pos);

                            pos++;

                            streamState = RtspStreamState.ReadLen;
                        }
                        else
                        { // буфер закончился выходим
                            break;
                        }
                    }

                    if (streamState == RtspStreamState.ReadLen)
                    {// длина пакета с данными 2 байта
                        int len = length - pos;

                        if (len > 1)
                        {
                            //int frameLength = BitConverter.ToInt16(buf, pos);

                            int frameLength = BigEndian.ReadInt16(buf, pos);

                            if (frameLength <= 0)
                            {
                                logger.Warn("frameLength " + frameLength);
                                //TODO:
                                //...
                            }

                            rtspFrame.Init(frameLength);

                            //Console.WriteLine("frameLength: " + frameLength + " pos: " + pos);

                            pos += 2;

                            streamState = RtspStreamState.ReadPkt;
                        }
                        else
                        {// сохраняем в буффер то что есть и выходим
                         // Debug.WriteLine(len + " < " + 2);

                            Array.Copy(buf, pos, tcpBuffer, tcpBufferOffset, len);

                            tcpBufferOffset += len;
                            //...
                            break;
                        }
                    }

                    if (streamState == RtspStreamState.ReadPkt)
                    {
                        if (rtspFrame != null && rtspFrame.Length > 0)
                        {
                            // сколькоданных в буфере
                            int bufToRead = length - pos;

                            int bytesAdded = rtspFrame.AddData(buf, pos, bufToRead);
                            pos += bytesAdded;

                            if (rtspFrame.BytesToRead == 0)
                            {// все данные прочитаны
                             // client.ProcessRtspFrame(rtspFrame);
                             //Console.WriteLine(rtspFrame.ToString());

                                var       rtpData   = rtspFrame.Data;
                                RtpPacket rtpPacket = RtpPacket.Create(rtpData, rtpData.Length, session);

                                // OnRtpPacketReceived(rtpPacket);

                                frames.Add(rtspFrame);

                                // переходим в режим ожидания доллара
                                streamState = RtspStreamState.WaitDollar;

                                // читаем следующий rtsp frame
                                rtspFrame = null;
                            }

                            if (pos < length)
                            {
                                //ProcessTcpBuffer(buf, pos, length);
                                offset = pos;
                                continue;
                            }

                            break;
                            // return;
                        }
                    }

                    {  // понять что это за данные пока не удалось копируем в буфер
                        int bufToRead = length - offset;

                        Array.Copy(buf, offset, tcpBuffer, tcpBufferOffset, bufToRead);

                        tcpBufferOffset += bufToRead;

                        logger.Debug("Array.Copy tcpBufferOffset " + tcpBufferOffset);

                        break;
                    }
                }

                return(frames);
            }
コード例 #2
0
ファイル: RtpSession.cs プロジェクト: wwj229/ScreenStreamer
        unsafe private NALUnit ParseH264Payload(byte[] payload, long timestamp)
        {
            if (payload == null)
            {
                return(null);
            }

            int payloadLength = payload.Length;

            if (payloadLength == 0)
            {
                logger.Warn("payloadLength == 0");
                return(null);
            }


            // RFC6184 Section 6 Packetization Mode:
            // 0 or not present: Single NAL mode (Only nals from 1-23 are allowed) - All receivers MUST support this mode.
            // 1: Non-interleaved Mode: 1-23, 24 (STAP-A), 28 (FU-A) are allowed. - This mode SHOULD be supported
            // 2: Interleaved Mode: 25 (STAP-B), 26 (MTAP16), 27 (MTAP24), 28 (FU-A), and 29 (FU-B) are allowed. - Some receivers MAY support this mode

            /*
             * 7.1.  Single NAL Unit and Non-Interleaved Mode
             *
             * The receiver includes a receiver buffer to compensate for
             * transmission delay jitter.  The receiver stores incoming packets in
             * reception order into the receiver buffer.  Packets are de-packetized
             * in RTP sequence number order.  If a de-packetized packet is a single
             * NAL unit packet, the NAL unit contained in the packet is passed
             * directly to the decoder.  If a de-packetized packet is an STAP-A, the
             * NAL units contained in the packet are passed to the decoder in the
             * order in which they are encapsulated in the packet.  For all the FU-A
             * packets containing fragments of a single NAL unit, the de-packetized
             * fragments are concatenated in their sending order to recover the NAL
             * unit, which is then passed to the decoder.
             */

            /*
             *  Type Name
             *     0[unspecified]
             *     1 Coded slice
             *     2 Data Partition A
             *     3 Data Partition B
             *     4 Data Partition C
             *     5 IDR(Instantaneous Decoding Refresh) Picture
             *     6 SEI(Supplemental Enhancement Information)
             *     7 SPS(Sequence Parameter Set)
             *     8 PPS(Picture Parameter Set)
             *     9 Access Unit Delimiter
             *    10 EoS(End of Sequence)
             *    11 EoS(End of Stream)
             *    12 Filter Data
             *  13 - 23[extended]
             *  24 - 31[unspecified]
             */

            byte firstByte = payload[0];
            byte unitType  = (byte)(firstByte & 0x1f);

            //logger.Verb("unitType " + unitType + " "+ timestamp);

            if (unitType >= 1 && unitType <= 23) // в одном пакете - один NAL unit ()
            {                                    // Single NAL Unit Packet
             /*
              *   0                   1                   2                   3
              *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
              +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
              |F|NRI|  Type   |                                               |
              +-+-+-+-+-+-+-+-+                                               |
              |                                                               |
              |               Bytes 2..n of a single NAL unit                 |
              |                                                               |
              |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
              |                               :...OPTIONAL RTP padding        |
              */


                //logger.Debug("unitType = " + unitType);
                int    size    = startSequence.Length + payloadLength;
                byte[] nalData = new byte[size];

                int offset = 0;

                Array.Copy(startSequence, 0, nalData, offset, startSequence.Length);
                offset += startSequence.Length;

                Array.Copy(payload, 0, nalData, offset, payloadLength);
                offset += payloadLength;

                //if (unitType == 1)
                //{// Coded slice of a non-IDR picture
                //    //logger.Verb("--------------------- " + arrival);
                //    // return nalData;
                //}
                //else if (unitType == 5)
                //{// IDR(Instantaneous Decoding Refresh) Picture
                //    ////logger.Verb(" ========================== isIFrame =============================== " + arrival);
                //    //return nalUnit;
                //}
                //else if (unitType == 6)
                //{//Supplemental enhancement information (SEI)

                //}
                //else if (unitType == 7)
                //{// Sequence parameter set

                //}
                //else if (unitType == 8)
                //{// Picture parameter set

                //}
                //else if (unitType == 9)
                //{ //Access unit delimiter
                //    //return nalData;
                //}

                iFrameFlag = (unitType == 5);

                return(new NALUnit
                {
                    data = nalData,
                    timestamp = timestamp,
                    type = unitType,
                    iFrame = iFrameFlag,
                });
            }
            else if (unitType == 28) // фрагментированный пакет (FU-A)
            {
                /* RFC6184 5.8.Fragmentation Units(FUs)
                 *   0                   1                   2                   3
                 *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
                 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                 | FU indicator  |   FU header   |                               |
                 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               |
                 |                                                               |
                 |                         FU payload                            |
                 |                                                               |
                 |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                 |                               :...OPTIONAL RTP padding        |
                 */

                //logger.Debug("unitType = " + unitType);
                if (payloadLength > 1)
                {
                    byte fuHeader = payload[1];
                    byte startBit = (byte)(fuHeader >> 7);
                    byte endBit   = (byte)((fuHeader & 0x40) >> 6);
                    //byte forbiddenBit = (byte)((fuHeader & 0x40) >> 7);

                    byte nalUnitType = (byte)(fuHeader & 0x1f); // идентификатор пакета

                    int payloadDataOffset = 2;                  // смещение 2 байта

                    payloadLength -= payloadDataOffset;

                    int flags = (nalUnitType == 5) ? 1 : 0;

                    int fuSize = (startBit == 1) ? (payloadLength + startSequence.Length + 1) : payloadLength;
                    int offset = 0;

                    byte[] fuBytes = new byte[fuSize];

                    if (startBit == 1) //начало фрагмента
                    {
                        iFrameFlag = (nalUnitType == 5 && ((fuHeader & 0x80) == 128));
                        //if (iFrameFlag)
                        //{
                        //    logger.Verb(" ========================== isIFrame =============================== ");
                        //}

                        Array.Copy(startSequence, fuBytes, startSequence.Length);
                        offset += startSequence.Length;

                        fuBytes[offset] = (byte)((firstByte & 0xe0) | nalUnitType);
                        offset++;
                    }

                    Array.Copy(payload, payloadDataOffset, fuBytes, offset, payloadLength);
                    offset += payloadLength;

                    payloadBuffer.Add(fuBytes);

                    if (endBit == 1)
                    {
                        var totalLength = payloadBuffer.Sum(n => n.Length);
                        var nalData     = new byte[totalLength];

                        int bufferOffset = 0;
                        foreach (var buf in payloadBuffer)
                        {// TODO: убрать копирование в промежуточный буфер
                            Array.Copy(buf, 0, nalData, bufferOffset, buf.Length);
                            bufferOffset += buf.Length;
                        }
                        payloadBuffer.Clear();

                        //logger.Verb("--------------------- " + arrival);
                        return(new NALUnit
                        {
                            data = nalData,
                            timestamp = timestamp,
                            type = nalUnitType,
                            iFrame = iFrameFlag
                        });
                    }
                }
            }
            else if (unitType == 24) // этот режим может понадобится для приема данных от сторонних RTSP серверов
            {                        // STAP-A (one packet, multiple nals)
                /*
                 *  0                   1                   2                   3
                 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
                 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                 |                          RTP Header                           |
                 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                 |STAP-A NAL HDR |         NALU 1 Size           | NALU 1 HDR    |
                 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                 |                         NALU 1 Data                           |
                 |  :                                                               :
                 +               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                 |               | NALU 2 Size                   | NALU 2 HDR    |
                 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                 |                         NALU 2 Data                           |
                 |  :                                                               :
                 |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                 |                               :...OPTIONAL RTP padding        |
                 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                 */
                List <byte[]> nals = new List <byte[]>(16);

                int naluPointer = 1; //STAP-A NAL HDR
                while (naluPointer < payload.Length - 1)
                {
                    int naluSize = BigEndian.ReadInt16(payload, naluPointer); //NALU 1 Size
                    naluPointer += 2;

                    if (naluSize > (payload.Length - naluPointer))
                    {
                        logger.Error("naluSize > (payload.Length - naluPointer) ");
                    }

                    byte[] nal = new byte[naluSize + startSequence.Length];
                    Array.Copy(startSequence, nal, startSequence.Length);

                    Array.Copy(payload, naluPointer, nal, startSequence.Length, naluSize); //NALU 1 HDR +  NALU 1 Data

                    naluPointer += naluSize;
                    nals.Add(nal);
                }

                var totalLength = nals.Sum(n => n.Length);
                var nalData     = new byte[totalLength];
                {
                    int offset = 0;
                    foreach (var buf in nals)
                    {
                        Array.Copy(buf, 0, nalData, offset, buf.Length);
                        offset += buf.Length;
                    }
                }
                return(new NALUnit
                {
                    data = nalData,
                    timestamp = timestamp,
                    type = unitType,
                });
            }
            if (unitType == 25 || unitType == 26 || unitType == 27 || unitType == 29) // Interleaved Mode
            {                                                                         // Не нужно
                throw new InvalidOperationException("Not supported unit type " + unitType);
            }

            if (unitType == 0 || unitType == 30 || unitType == 31) // reserved
            {                                                      // эти пакеты приходить не должны!
                throw new InvalidOperationException("Invalid packet. Reserved unit type " + unitType);
            }

            return(null);
        }