예제 #1
0
        private static byte[] PacketizeSingleNAL(Span <byte> raw_nal, UInt32 rtp_timestamp)
        {
            // Put the whole NAL into one RTP packet.
            // Note some receivers will have maximum buffers and be unable to handle large RTP packets.
            // Also with RTP over RTSP there is a limit of 65535 bytes for the RTP packet.

            byte[] rtp_packet = new byte[RTPPacketUtil.HeaderLength + raw_nal.Length];             // 12 is header size when there are no CSRCs or extensions
            // Create an single RTP fragment
            bool rtp_marker = (raw_nal[0] & 0x1F) <= 5;

            RTPPacketUtil.WriteHeader(rtp_packet, rtp_version, rtp_padding, rtp_extension, rtp_csrc_count, rtp_marker, rtp_payload_type);

            UInt32 empty_sequence_id = 0;

            RTPPacketUtil.WriteSequenceNumber(rtp_packet, empty_sequence_id);

            RTPPacketUtil.WriteTS(rtp_packet, rtp_timestamp);

            UInt32 empty_ssrc = 0;

            RTPPacketUtil.WriteSSRC(rtp_packet, empty_ssrc);

            // Now append the raw NAL
            raw_nal.CopyTo(new Span <byte>(rtp_packet, 12, raw_nal.Length));

            return(rtp_packet);
        }
예제 #2
0
        private static void PacketizeNAL_FUA(ref List <byte[]> rtp_packets, Span <byte> raw_nal, UInt32 rtp_timestamp)
        {
            int start_bit = 1;
            int end_bit   = 0;

            // consume first byte of the raw_nal. It is used in the FU header
            byte first_byte = raw_nal[0];

            raw_nal = raw_nal.Slice(1);

            while (raw_nal.Length > 0)
            {
                int payload_size = Math.Min(RTPPacketUtil.MaxPayloadSize - 2, raw_nal.Length);

                if (raw_nal.Length - payload_size == 0)
                {
                    end_bit = 1;
                }
                //for FU-A the marker is set when this is the last RTP packet
                bool rtp_marker = end_bit == 1;

                byte[] rtp_packet = new byte[RTPPacketUtil.HeaderLength + 2 + payload_size];                 // 2 bytes for FU-A header.

                RTPPacketUtil.WriteHeader(rtp_packet, rtp_version, rtp_padding, rtp_extension, rtp_csrc_count, rtp_marker, rtp_payload_type);

                UInt32 empty_sequence_id = 0;
                RTPPacketUtil.WriteSequenceNumber(rtp_packet, empty_sequence_id);

                RTPPacketUtil.WriteTS(rtp_packet, rtp_timestamp);

                UInt32 empty_ssrc = 0;
                RTPPacketUtil.WriteSSRC(rtp_packet, empty_ssrc);

                // Now append the Fragmentation Header (with Start and End marker) and part of the raw_nal
                byte f_bit = 0;
                byte nri   = (byte)((first_byte >> 5) & 0x03); // Part of the 1st byte of the Raw NAL (NAL Reference ID)
                byte type  = 28;                               // FU-A Fragmentation

                rtp_packet[12] = (byte)((f_bit << 7) + (nri << 5) + type);
                rtp_packet[13] = (byte)((start_bit << 7) + (end_bit << 6) + (0 << 5) + (first_byte & 0x1F));

                raw_nal.Slice(0, payload_size).CopyTo(new Span <byte>(rtp_packet, 14, payload_size));

                raw_nal = raw_nal.Slice(payload_size);

                rtp_packets.Add(rtp_packet);

                start_bit = 0;
            }
        }
예제 #3
0
        //TODO: reimplement these using Memory and Span<byte>

        public static List <byte[]> PacketizeSamples(Memory <byte> samples, ulong tsMs)
        {
            List <byte[]> rtp_packets = new List <byte[]>();

            Span <byte> smp    = samples.Span;
            double      diffTs = 0;

            while (smp.Length > 0)
            {
                int dataLen = smp.Length > RTPPacketUtil.MaxPayloadSize ? RTPPacketUtil.MaxPayloadSize : smp.Length;

                byte[]      packet     = new byte[dataLen + RTPPacketUtil.HeaderLength];
                Span <byte> packetData = new Span <byte>(packet, RTPPacketUtil.HeaderLength, dataLen);

                for (int i = 0; i < dataLen; i += 2)
                {
                    packetData[i]     = smp[i + 1];
                    packetData[i + 1] = smp[i];
                }

                RTPPacketUtil.WriteHeader(packet, rtp_version, rtp_padding, rtp_extension, rtp_csrc_count, false, rtp_payload_type);

                UInt32 empty_sequence_id = 0;
                RTPPacketUtil.WriteSequenceNumber(packet, empty_sequence_id);

                RTPPacketUtil.WriteTS(packet, (UInt32)((tsMs + diffTs) * 48));

                UInt32 empty_ssrc = 0;
                RTPPacketUtil.WriteSSRC(packet, empty_ssrc);

                rtp_packets.Add(packet);

                smp     = smp.Slice(dataLen);
                diffTs += AudiolenRtpPackeMs;
            }

            return(rtp_packets);
        }
예제 #4
0
        void PushRtspData(StreamKind stream, List <byte[]> rtp_packets, ulong tsMsec)
        {
            int s = (int)stream;

            lock (rtsp_list)
            {
                // Go through each RTSP connection and output the NAL on the Video Session
                foreach (RTSPConnection connection in rtsp_list.ToArray())                 // ToArray makes a temp copy of the list.
                // This lets us delete items in the foreach
                // eg when there is Write Error
                {
                    // Only process Sessions in Play Mode
                    if (connection.play == false)
                    {
                        continue;
                    }
#if DEBUG && LOG
                    String connection_type = "";
                    if (connection[s].client_transport.LowerTransport == Rtsp.Messages.RtspTransport.LowerTransportType.TCP)
                    {
                        connection_type = "TCP";
                    }
                    if (connection[s].client_transport.LowerTransport == Rtsp.Messages.RtspTransport.LowerTransportType.UDP &&
                        connection[s].client_transport.IsMulticast == false)
                    {
                        connection_type = "UDP";
                    }
                    if (connection[s].client_transport.LowerTransport == Rtsp.Messages.RtspTransport.LowerTransportType.UDP &&
                        connection[s].client_transport.IsMulticast == true)
                    {
                        connection_type = "Multicast";
                    }
                    Console.WriteLine($"[{stream}] Sending video session {connection[s].session_id} {connection_type} Timestamp(ms)={tsMsec} Sequence={connection[s].sequence_number}");
#endif

                    // There could be more than 1 RTP packet (if the data is fragmented)
                    Boolean write_error = false;
                    foreach (byte[] rtp_packet in rtp_packets)
                    {
                        // Add the specific data for each transmission
                        RTPPacketUtil.WriteSequenceNumber(rtp_packet, connection[s].sequence_number);
                        connection[s].sequence_number++;

                        // Add the specific SSRC for each transmission
                        RTPPacketUtil.WriteSSRC(rtp_packet, connection.ssrc);

                        //if (stream == StreamKind.Video) bin.Write(rtp_packet);

                        // Send as RTP over RTSP (Interleaved)
                        if (connection[s].transport_reply.LowerTransport == Rtsp.Messages.RtspTransport.LowerTransportType.TCP)
                        {
                            int    video_channel = connection[s].transport_reply.Interleaved.First;                          // second is for RTCP status messages)
                            object state         = new object();
                            try
                            {
                                // send the whole NAL. With RTP over RTSP we do not need to Fragment the NAL (as we do with UDP packets or Multicast)
                                //session.listener.BeginSendData(video_channel, rtp_packet, new AsyncCallback(session.listener.EndSendData), state);
                                connection.listener.SendData(video_channel, rtp_packet);
                            }
                            catch
                            {
                                Console.WriteLine($"[{stream}] Error writing to listener " + connection.listener.RemoteAdress);
                                write_error = true;
                                break;                                 // exit out of foreach loop
                            }
                        }

                        // Send as RTP over UDP
                        if (connection[s].transport_reply.LowerTransport == Rtsp.Messages.RtspTransport.LowerTransportType.UDP && connection[s].transport_reply.IsMulticast == false)
                        {
                            try
                            {
                                // send the whole NAL. ** We could fragment the RTP packet into smaller chuncks that fit within the MTU
                                // Send to the IP address of the Client
                                // Send to the UDP Port the Client gave us in the SETUP command
                                connection[s].udp_pair.Write_To_Data_Port(rtp_packet, connection.client_hostname, connection[s].client_transport.ClientPort.First);
                            }
                            catch (Exception e)
                            {
                                Console.WriteLine($"[{stream}] UDP Write Exception " + e.ToString());
                                Console.WriteLine($"[{stream}] Error writing to listener " + connection.listener.RemoteAdress);
                                write_error = true;
                                break;                                 // exit out of foreach loop
                            }
                        }

                        // TODO. Add Multicast
                    }
                    if (write_error)
                    {
                        Console.WriteLine($"[{stream}] Removing session " + connection[s].session_id + " due to write error");
                        connection.sessions[s].Close();
                        rtsp_list.Remove(connection);
                        connection.Dispose();
                    }
                }
            }
        }