コード例 #1
0
        // RTSP Messages are OPTIONS, DESCRIBE, SETUP, PLAY etc
        private void RtspMessageReceived(object sender, Rtsp.RtspChunkEventArgs e)
        {
            RtspResponse message = e.Message as RtspResponse;

            if (message.OriginalRequest == null)
            {
                return;
            }

            Logger.Info("Received " + message.OriginalRequest.ToString());

            if (message.OriginalRequest is RtspRequestOptions)
            {
                ProcessOptionsRequest(message);
            }
            else if (message.OriginalRequest is RtspRequestDescribe)
            {
                ProcessDescribeRequest(message);
            }
            else if (message.OriginalRequest is RtspRequestSetup)
            {
                ProcessSetupRequest(message);
            }
            else if (message.OriginalRequest is RtspRequestPlay)
            {
                ProcessPlayRequest(message);
            }
        }
コード例 #2
0
        public void RtpDataReceived(object sender, Rtsp.RtspChunkEventArgs chunkEventArgs)
        {
            try
            {
                RtspData rtpData = chunkEventArgs.Message as RtspData;

                if (IsRtcpGoodbye(rtpData))
                {
                    HandleRtcpGoodbye();
                }

                // Check which channel the Data was received on.
                // eg the Video Channel, the Video Control Channel (RTCP)
                // In the future would also check the Audio Channel and Audio Control Channel
                if (rtpData.Channel == videoRTCPChannel)
                {
                    Logger.Info("Received a RTCP message on channel " + rtpData.Channel);
                    return;
                }

                if (rtpData.Channel == videoDataChannel)
                {
                    ProcessRTPVideo(chunkEventArgs);
                }
            }
            catch (Exception e)
            {
                Logger.Info(e.ToString());
                rtspErrorSubject.OnNext(e.Message);
            }
        }
コード例 #3
0
        /// <summary>
        /// Raises the <see cref="E:DataReceived"/> event.
        /// </summary>
        /// <param name="rtspChunkEventArgs">The <see cref="Rtsp.RtspChunkEventArgs"/> instance containing the event data.</param>
        protected void OnDataReceived(Rtsp.RtspChunkEventArgs rtspChunkEventArgs)
        {
            EventHandler <Rtsp.RtspChunkEventArgs> handler = DataReceived;

            if (handler != null)
            {
                handler(this, rtspChunkEventArgs);
            }
        }
コード例 #4
0
        private void ProcessRTPVideo(Rtsp.RtspChunkEventArgs e)
        {
            // Received some Video Data on the correct channel.

            // RTP Packet Header
            // 0 - Version, P, X, CC, M, PT and Sequence Number
            //32 - Timestamp
            //64 - SSRC
            //96 - CSRCs (optional)
            //nn - Extension ID and Length
            //nn - Extension header

            int  rtpVersion        = (e.Message.Data[0] >> 6);
            int  rtpPadding        = (e.Message.Data[0] >> 5) & 0x01;
            int  rtpRxtension      = (e.Message.Data[0] >> 4) & 0x01;
            int  rtpCSRCCount      = (e.Message.Data[0] >> 0) & 0x0F;
            int  rtpMarker         = (e.Message.Data[1] >> 7) & 0x01;
            int  rtpPayloadType    = (e.Message.Data[1] >> 0) & 0x7F;
            uint rtpSequenceNumber = ((uint)e.Message.Data[2] << 8) + (uint)(e.Message.Data[3]);
            uint rtpTimestamp      = ((uint)e.Message.Data[4] << 24) + (uint)(e.Message.Data[5] << 16) + (uint)(e.Message.Data[6] << 8) + (uint)(e.Message.Data[7]);
            uint rtpSSRC           = ((uint)e.Message.Data[8] << 24) + (uint)(e.Message.Data[9] << 16) + (uint)(e.Message.Data[10] << 8) + (uint)(e.Message.Data[11]);

            int rtpPayloadStart = 4                     // V,P,M,SEQ
                                  + 4                   // time stamp
                                  + 4                   // ssrc
                                  + (4 * rtpCSRCCount); // zero or more csrcs

            if (rtpRxtension == 1)
            {
                uint rtpExtensionId   = ((uint)e.Message.Data[rtpPayloadStart + 0] << 8) + (uint)(e.Message.Data[rtpPayloadStart + 1] << 0);
                uint rtpExtensionSize = ((uint)e.Message.Data[rtpPayloadStart + 2] << 8) + (uint)(e.Message.Data[rtpPayloadStart + 3] << 0) * 4; // units of extension_size is 4-bytes
                rtpPayloadStart += 4 + (int)rtpExtensionSize;                                                                                    // extension header and extension payload
            }

            //Logger.Info("RTP Data"
            //                   + " V=" + rtpVersion
            //                   + " P=" + rtpPadding
            //                   + " X=" + rtpRxtension
            //                   + " CC=" + rtpCSRCCount
            //                   + " M=" + rtpMarker
            //                   + " PT=" + rtpPayloadType
            //                   + " Seq=" + rtpSequenceNumber
            //                   + " Time (MS)=" + rtpTimestamp / 90 // convert from 90kHZ clock to ms
            //                   + " SSRC=" + rtpSSRC
            //                   + " Size=" + e.Message.Data.Length);

            // Check the payload type in the RTP packet matches the Payload Type value from the SDP
            if (videoPayloadType > 0 && rtpPayloadType != videoPayloadType)
            {
                Logger.Info("Ignoring this RTP payload: " + rtpPayloadType);
                return; // ignore this data
            }

            byte[] rtp_payload = new byte[e.Message.Data.Length - rtpPayloadStart];          // payload with RTP header removed
            Array.Copy(e.Message.Data, rtpPayloadStart, rtp_payload, 0, rtp_payload.Length); // copy payload
            chunkReadySubject.OnNext(rtp_payload);
        }
コード例 #5
0
        public void RtpDataReceived(object sender, Rtsp.RtspChunkEventArgs e)
        {
            RtspData rtpData = e.Message as RtspData;

            // Check which channel the Data was received on.
            // eg the Video Channel, the Video Control Channel (RTCP)
            // In the future would also check the Audio Channel and Audio Control Channel
            if (rtpData.Channel == videoRTCPChannel)
            {
                Logger.Info("Received a RTCP message on channel " + rtpData.Channel);
                return;
            }

            if (rtpData.Channel == videoDataChannel)
            {
                ProcessRTPVideo(e);
            }
        }
コード例 #6
0
        // RTSP Messages are OPTIONS, DESCRIBE, SETUP, PLAY etc
        private void RtspMessageReceived(object sender, Rtsp.RtspChunkEventArgs chunkEventArgs)
        {
            RtspResponse message = chunkEventArgs.Message as RtspResponse;

            if (message?.OriginalRequest == null)
            {
                return;
            }

            Logger.Info("Received " + message.OriginalRequest);

            try
            {
                if (message.OriginalRequest is RtspRequestOptions)
                {
                    ProcessOptionsRequest(message);
                }
                else if (message.OriginalRequest is RtspRequestDescribe)
                {
                    ProcessDescribeRequest(message);
                }
                else if (message.OriginalRequest is RtspRequestSetup)
                {
                    ProcessSetupRequest(message);
                }
                else if (message.OriginalRequest is RtspRequestPlay)
                {
                    ProcessPlayRequest(message);
                }
            }
            catch (Exception e)
            {
                Logger.Info(e.ToString());
                rtspErrorSubject.OnNext("RTSP error occured.");
            }
        }
コード例 #7
0
ファイル: RTSPClient.cs プロジェクト: winkmichael/SharpRTSP
        // RTSP Messages are OPTIONS, DESCRIBE, SETUP, PLAY etc
        private void Rtsp_MessageReceived(object sender, Rtsp.RtspChunkEventArgs e)
        {
            Rtsp.Messages.RtspResponse message = e.Message as Rtsp.Messages.RtspResponse;

            Console.WriteLine("Received " + message.OriginalRequest.ToString());

            // Check if the Message has an Authenticate header. If so we update the 'realm' and 'nonce'
            if (message.Headers.ContainsKey(RtspHeaderNames.WWWAuthenticate))
            {
                String www_authenticate = message.Headers[RtspHeaderNames.WWWAuthenticate];

                // Parse www_authenticate
                // EG:   Digest realm="AXIS_WS_ACCC8E3A0A8F", nonce="000057c3Y810622bff50b36005eb5efeae118626a161bf", stale=FALSE
                string[] items = www_authenticate.Split(new char[] { ',', ' ' });
                foreach (string item in items)
                {
                    // Split on the = symbol and load in
                    string[] parts = item.Split(new char[] { '=' });
                    if (parts.Count() >= 2 && parts[0].Trim().Equals("realm"))
                    {
                        realm = parts[1].Trim(new char[] { ' ', '\"' }); // trim space and quotes
                    }
                    else if (parts.Count() >= 2 && parts[0].Trim().Equals("nonce"))
                    {
                        nonce = parts[1].Trim(new char[] { ' ', '\"' }); // trim space and quotes
                    }
                }

                Console.WriteLine("WWW Authorize parsed for " + realm + " " + nonce);
            }


            // If we get a reply to OPTIONS and CSEQ is 1 (which was our first command), then send the DESCRIBE
            // If we fer a reply to OPTIONS and CSEQ is not 1, it must have been a keepalive command
            if (message.OriginalRequest != null && message.OriginalRequest is Rtsp.Messages.RtspRequestOptions)
            {
                if (message.CSeq == 1)
                {
                    // Start a Timer to send an OPTIONS command (for keepalive) every 20 seconds
                    keepalive_timer          = new System.Timers.Timer();
                    keepalive_timer.Elapsed += Timer_Elapsed;
                    keepalive_timer.Interval = 20 * 1000;
                    keepalive_timer.Enabled  = true;

                    // send the DESCRIBE. First time around we have no WWW-Authorise
                    Rtsp.Messages.RtspRequest describe_message = new Rtsp.Messages.RtspRequestDescribe();
                    describe_message.RtspUri = new Uri(url);
                    rtsp_client.SendMessage(describe_message);
                }
                else
                {
                    // do nothing
                }
            }


            // If we get a reply to DESCRIBE (which was our second command), then prosess SDP and send the SETUP
            if (message.OriginalRequest != null && message.OriginalRequest is Rtsp.Messages.RtspRequestDescribe)
            {
                // Got a reply for DESCRIBE

                // First time we send DESCRIBE we will not have the authorization Nonce so we
                // handle the Unauthorized 401 error here and send a new DESCRIBE message

                if (message.IsOk == false)
                {
                    Console.WriteLine("Got Error in DESCRIBE Reply " + message.ReturnCode + " " + message.ReturnMessage);

                    if (message.ReturnCode == 401 && (message.OriginalRequest.Headers.ContainsKey(RtspHeaderNames.Authorization) == false))
                    {
                        // Error 401 - Unauthorized, but the request did not use Authorizarion.

                        if (username == null || password == null)
                        {
                            // we do nothave a username or password. Abort
                            return;
                        }
                        // Send a new DESCRIBE with authorization
                        String digest_authorization = GenerateDigestAuthorization(username, password,
                                                                                  realm, nonce, url, "DESCRIBE");

                        Rtsp.Messages.RtspRequest describe_message = new Rtsp.Messages.RtspRequestDescribe();
                        describe_message.RtspUri = new Uri(url);
                        if (digest_authorization != null)
                        {
                            describe_message.Headers.Add(RtspHeaderNames.Authorization, digest_authorization);
                        }
                        rtsp_client.SendMessage(describe_message);
                        return;
                    }
                    else if (message.ReturnCode == 401 && (message.OriginalRequest.Headers.ContainsKey(RtspHeaderNames.Authorization) == true))
                    {
                        // Authorization failed
                        return;
                    }
                    else
                    {
                        // some other error
                        return;
                    }
                }

                // Examine the SDP

                Console.Write(System.Text.Encoding.UTF8.GetString(message.Data));

                Rtsp.Sdp.SdpFile sdp_data;
                using (StreamReader sdp_stream = new StreamReader(new MemoryStream(message.Data)))
                {
                    sdp_data = Rtsp.Sdp.SdpFile.Read(sdp_stream);
                }

                // Process each 'Media' Attribute in the SDP (each sub-stream)

                for (int x = 0; x < sdp_data.Medias.Count; x++)
                {
                    bool audio = (sdp_data.Medias[x].MediaType == Rtsp.Sdp.Media.MediaTypes.audio);
                    bool video = (sdp_data.Medias[x].MediaType == Rtsp.Sdp.Media.MediaTypes.video);

                    if (video && video_payload != -1)
                    {
                        continue;                               // have already matched an video payload
                    }
                    if (audio && audio_payload != -1)
                    {
                        continue;                               // have already matched an audio payload
                    }
                    if (audio || video)
                    {
                        // search the attributes for control, rtpmap and fmtp
                        // (fmtp only applies to video)
                        String control             = "";   // the "track" or "stream id"
                        Rtsp.Sdp.AttributFmtp fmtp = null; // holds SPS and PPS in base64 (h264 video)
                        foreach (Rtsp.Sdp.Attribut attrib in sdp_data.Medias[x].Attributs)
                        {
                            if (attrib.Key.Equals("control"))
                            {
                                String sdp_control = attrib.Value;
                                if (sdp_control.ToLower().StartsWith("rtsp://"))
                                {
                                    control = sdp_control; //absolute path
                                }
                                else
                                {
                                    control = url + "/" + sdp_control; // relative path
                                }
                            }
                            if (attrib.Key.Equals("fmtp"))
                            {
                                fmtp = attrib as Rtsp.Sdp.AttributFmtp;
                            }
                            if (attrib.Key.Equals("rtpmap"))
                            {
                                Rtsp.Sdp.AttributRtpMap rtpmap = attrib as Rtsp.Sdp.AttributRtpMap;

                                // Check if the Codec Used (EncodingName) is one we support
                                String[] valid_video_codecs = { "H264" };
                                String[] valid_audio_codecs = { "PCMA", "PCMU" };

                                if (video && Array.IndexOf(valid_video_codecs, rtpmap.EncodingName) >= 0)
                                {
                                    // found a valid codec
                                    video_codec   = rtpmap.EncodingName;
                                    video_payload = sdp_data.Medias[x].PayloadType;
                                }
                                if (audio && Array.IndexOf(valid_audio_codecs, rtpmap.EncodingName) >= 0)
                                {
                                    audio_codec   = rtpmap.EncodingName;
                                    audio_payload = sdp_data.Medias[x].PayloadType;
                                }
                            }
                        }

                        // If the rtpmap contains H264 then split the fmtp to get the sprop-parameter-sets which hold the SPS and PPS in base64
                        if (video && video_codec.Contains("H264") && fmtp != null)
                        {
                            var param   = Rtsp.Sdp.H264Parameters.Parse(fmtp.FormatParameter);
                            var sps_pps = param.SpropParameterSets;
                            if (sps_pps.Count() >= 2)
                            {
                                byte[] sps = sps_pps[0];
                                byte[] pps = sps_pps[1];
                                if (Received_SPS_PPS != null)
                                {
                                    Received_SPS_PPS(sps, pps);
                                }
                            }
                        }

                        // Send the SETUP RTSP command if we have a matching Payload Decoder
                        if (video && video_payload == -1)
                        {
                            continue;
                        }
                        if (audio && audio_payload == -1)
                        {
                            continue;
                        }

                        RtspTransport transport    = null;
                        int           data_channel = 0;
                        int           rtcp_channel = 0;

                        if (rtp_transport == RTP_TRANSPORT.TCP)
                        {
                            // Server interleaves the RTP packets over the RTSP connection
                            // Example for TCP mode (RTP over RTSP)   Transport: RTP/AVP/TCP;interleaved=0-1
                            if (video)
                            {
                                video_data_channel = 0;
                                video_rtcp_channel = 1;
                                data_channel       = video_data_channel;
                                rtcp_channel       = video_rtcp_channel;
                            }
                            if (audio)
                            {
                                audio_data_channel = 2;
                                audio_rtcp_channel = 3;
                                data_channel       = audio_data_channel;
                                rtcp_channel       = audio_rtcp_channel;
                            }
                            transport = new RtspTransport()
                            {
                                LowerTransport = RtspTransport.LowerTransportType.TCP,
                                Interleaved    = new PortCouple(data_channel, rtcp_channel), // Eg Channel 0 for video. Channel 1 for RTCP status reports
                            };
                        }
                        if (rtp_transport == RTP_TRANSPORT.UDP)
                        {
                            // Server sends the RTP packets to a Pair of UDP Ports (one for data, one for rtcp control messages)
                            // Example for UDP mode                   Transport: RTP/AVP;unicast;client_port=8000-8001
                            if (video)
                            {
                                video_data_channel = video_udp_pair.data_port;     // Used in DataReceived event handler
                                video_rtcp_channel = video_udp_pair.control_port;  // Used in DataReceived event handler
                                data_channel       = video_data_channel;
                                rtcp_channel       = video_rtcp_channel;
                            }
                            if (audio)
                            {
                                audio_data_channel = audio_udp_pair.data_port;     // Used in DataReceived event handler
                                audio_rtcp_channel = audio_udp_pair.control_port;  // Used in DataReceived event handler
                                data_channel       = audio_data_channel;
                                rtcp_channel       = audio_rtcp_channel;
                            }
                            transport = new RtspTransport()
                            {
                                LowerTransport = RtspTransport.LowerTransportType.UDP,
                                IsMulticast    = false,
                                ClientPort     = new PortCouple(data_channel, rtcp_channel), // a Channel for data (video or audio). a Channel for RTCP status reports
                            };
                        }
                        if (rtp_transport == RTP_TRANSPORT.MULTICAST)
                        {
                            // Server sends the RTP packets to a Pair of UDP ports (one for data, one for rtcp control messages)
                            // using Multicast Address and Ports that are in the reply to the SETUP message
                            // Example for MULTICAST mode     Transport: RTP/AVP;multicast
                            if (video)
                            {
                                video_data_channel = 0; // we get this information in the SETUP message reply
                                video_rtcp_channel = 0; // we get this information in the SETUP message reply
                            }
                            if (audio)
                            {
                                audio_data_channel = 0; // we get this information in the SETUP message reply
                                audio_rtcp_channel = 0; // we get this information in the SETUP message reply
                            }
                            transport = new RtspTransport()
                            {
                                LowerTransport = RtspTransport.LowerTransportType.UDP,
                                IsMulticast    = true
                            };
                        }

                        // Add authorization (if there is a username and password)
                        String digest_authorization = GenerateDigestAuthorization(username, password,
                                                                                  realm, nonce, url, "SETUP");

                        // Send SETUP
                        Rtsp.Messages.RtspRequestSetup setup_message = new Rtsp.Messages.RtspRequestSetup();
                        setup_message.RtspUri = new Uri(control);
                        setup_message.AddTransport(transport);
                        if (digest_authorization != null)
                        {
                            setup_message.Headers.Add("Authorization", digest_authorization);
                        }
                        rtsp_client.SendMessage(setup_message);
                    }
                }
            }


            // If we get a reply to SETUP (which was our third command), then process and then send PLAY
            if (message.OriginalRequest != null && message.OriginalRequest is Rtsp.Messages.RtspRequestSetup)
            {
                // Got Reply to SETUP
                if (message.IsOk == false)
                {
                    Console.WriteLine("Got Error in SETUP Reply " + message.ReturnCode + " " + message.ReturnMessage);
                    return;
                }

                Console.WriteLine("Got reply from Setup. Session is " + message.Session);

                session = message.Session; // Session value used with Play, Pause, Teardown

                // Check the Transport header
                if (message.Headers.ContainsKey(RtspHeaderNames.Transport))
                {
                    RtspTransport transport = RtspTransport.Parse(message.Headers[RtspHeaderNames.Transport]);

                    // Check if Transport header includes Multicast
                    if (transport.IsMulticast)
                    {
                        String multicast_address = transport.Destination;
                        video_data_channel = transport.Port.First;
                        video_rtcp_channel = transport.Port.Second;

                        // Create the Pair of UDP Sockets in Multicast mode
                        video_udp_pair = new Rtsp.UDPSocket(multicast_address, video_data_channel, multicast_address, video_rtcp_channel);
                        video_udp_pair.DataReceived += Rtp_DataReceived;
                        video_udp_pair.Start();

                        // TODO - Need to set audio_udp_pair
                    }
                }

                // Send PLAY
                Rtsp.Messages.RtspRequest play_message = new Rtsp.Messages.RtspRequestPlay();
                play_message.RtspUri = new Uri(url);
                play_message.Session = session;
                rtsp_client.SendMessage(play_message);
            }

            // If we get a reply to PLAY (which was our fourth command), then we should have video being received
            if (message.OriginalRequest != null && message.OriginalRequest is Rtsp.Messages.RtspRequestPlay)
            {
                // Got Reply to PLAY
                if (message.IsOk == false)
                {
                    Console.WriteLine("Got Error in PLAY Reply " + message.ReturnCode + " " + message.ReturnMessage);
                    return;
                }

                Console.WriteLine("Got reply from Play  " + message.Command);
            }
        }
コード例 #8
0
ファイル: RTSPClient.cs プロジェクト: winkmichael/SharpRTSP
        int rtp_count = 0; // used for statistics
        // RTP packet (or RTCP packet) has been received.
        public void Rtp_DataReceived(object sender, Rtsp.RtspChunkEventArgs e)
        {
            Rtsp.Messages.RtspData data_received = e.Message as Rtsp.Messages.RtspData;

            // Check which channel the Data was received on.
            // eg the Video Channel, the Video Control Channel (RTCP)
            // the Audio Channel or the Audio Control Channel (RTCP)

            if (data_received.Channel == video_rtcp_channel || data_received.Channel == audio_rtcp_channel)
            {
                Console.WriteLine("Received a RTCP message on channel " + data_received.Channel);

                // RTCP Packet
                // - Version, Padding and Receiver Report Count
                // - Packet Type
                // - Length
                // - SSRC
                // - payload

                // There can be multiple RTCP packets transmitted together. Loop ever each one

                long packetIndex = 0;
                while (packetIndex < e.Message.Data.Length)
                {
                    int  rtcp_version = (e.Message.Data[packetIndex + 0] >> 6);
                    int  rtcp_padding = (e.Message.Data[packetIndex + 0] >> 5) & 0x01;
                    int  rtcp_reception_report_count = (e.Message.Data[packetIndex + 0] & 0x1F);
                    byte rtcp_packet_type            = e.Message.Data[packetIndex + 1];                                        // Values from 200 to 207
                    uint rtcp_length = ((uint)e.Message.Data[packetIndex + 2] << 8) + (uint)(e.Message.Data[packetIndex + 3]); // number of 32 bit words
                    uint rtcp_ssrc   = ((uint)e.Message.Data[packetIndex + 4] << 24) + (uint)(e.Message.Data[packetIndex + 5] << 16)
                                       + (uint)(e.Message.Data[packetIndex + 6] << 8) + (uint)(e.Message.Data[packetIndex + 7]);

                    // 200 = SR = Sender Report
                    // 201 = RR = Receiver Report
                    // 202 = SDES = Source Description
                    // 203 = Bye = Goodbye
                    // 204 = APP = Application Specific Method
                    // 207 = XR = Extended Reports

                    Console.WriteLine("RTCP Data. PacketType=" + rtcp_packet_type
                                      + " SSRC=" + rtcp_ssrc);

                    if (rtcp_packet_type == 200)
                    {
                        // Send a Receiver Report
                        try
                        {
                            byte[] rtcp_receiver_report = new byte[8];
                            int    version     = 2;
                            int    paddingBit  = 0;
                            int    reportCount = 0;                                     // an empty report
                            int    packetType  = 201;                                   // Receiver Report
                            int    length      = (rtcp_receiver_report.Length / 4) - 1; // num 32 bit words minus 1
                            rtcp_receiver_report[0] = (byte)((version << 6) + (paddingBit << 5) + reportCount);
                            rtcp_receiver_report[1] = (byte)(packetType);
                            rtcp_receiver_report[2] = (byte)((length >> 8) & 0xFF);
                            rtcp_receiver_report[3] = (byte)((length >> 0) & 0XFF);
                            rtcp_receiver_report[4] = (byte)((ssrc >> 24) & 0xFF);
                            rtcp_receiver_report[5] = (byte)((ssrc >> 16) & 0xFF);
                            rtcp_receiver_report[6] = (byte)((ssrc >> 8) & 0xFF);
                            rtcp_receiver_report[7] = (byte)((ssrc >> 0) & 0xFF);

                            if (rtp_transport == RTP_TRANSPORT.TCP)
                            {
                                // Send it over via the RTSP connection
                                rtsp_client.SendData(video_rtcp_channel, rtcp_receiver_report);
                            }
                            if (rtp_transport == RTP_TRANSPORT.UDP || rtp_transport == RTP_TRANSPORT.MULTICAST)
                            {
                                // Send it via a UDP Packet
                                Console.WriteLine("TODO - Need to implement RTCP over UDP");
                            }
                        }
                        catch
                        {
                            Console.WriteLine("Error writing RTCP packet");
                        }
                    }

                    packetIndex = packetIndex + ((rtcp_length + 1) * 4);
                }
                return;
            }

            if (data_received.Channel == video_data_channel || data_received.Channel == audio_data_channel)
            {
                // Received some Video or Audio Data on the correct channel.

                // RTP Packet Header
                // 0 - Version, P, X, CC, M, PT and Sequence Number
                //32 - Timestamp
                //64 - SSRC
                //96 - CSRCs (optional)
                //nn - Extension ID and Length
                //nn - Extension header

                int  rtp_version         = (e.Message.Data[0] >> 6);
                int  rtp_padding         = (e.Message.Data[0] >> 5) & 0x01;
                int  rtp_extension       = (e.Message.Data[0] >> 4) & 0x01;
                int  rtp_csrc_count      = (e.Message.Data[0] >> 0) & 0x0F;
                int  rtp_marker          = (e.Message.Data[1] >> 7) & 0x01;
                int  rtp_payload_type    = (e.Message.Data[1] >> 0) & 0x7F;
                uint rtp_sequence_number = ((uint)e.Message.Data[2] << 8) + (uint)(e.Message.Data[3]);
                uint rtp_timestamp       = ((uint)e.Message.Data[4] << 24) + (uint)(e.Message.Data[5] << 16) + (uint)(e.Message.Data[6] << 8) + (uint)(e.Message.Data[7]);
                uint rtp_ssrc            = ((uint)e.Message.Data[8] << 24) + (uint)(e.Message.Data[9] << 16) + (uint)(e.Message.Data[10] << 8) + (uint)(e.Message.Data[11]);

                int rtp_payload_start = 4                       // V,P,M,SEQ
                                        + 4                     // time stamp
                                        + 4                     // ssrc
                                        + (4 * rtp_csrc_count); // zero or more csrcs

                uint rtp_extension_id   = 0;
                uint rtp_extension_size = 0;
                if (rtp_extension == 1)
                {
                    rtp_extension_id   = ((uint)e.Message.Data[rtp_payload_start + 0] << 8) + (uint)(e.Message.Data[rtp_payload_start + 1] << 0);
                    rtp_extension_size = ((uint)e.Message.Data[rtp_payload_start + 2] << 8) + (uint)(e.Message.Data[rtp_payload_start + 3] << 0) * 4; // units of extension_size is 4-bytes
                    rtp_payload_start += 4 + (int)rtp_extension_size;                                                                                 // extension header and extension payload
                }

                Console.WriteLine("RTP Data"
                                  + " V=" + rtp_version
                                  + " P=" + rtp_padding
                                  + " X=" + rtp_extension
                                  + " CC=" + rtp_csrc_count
                                  + " M=" + rtp_marker
                                  + " PT=" + rtp_payload_type
                                  + " Seq=" + rtp_sequence_number
                                  + " Time (MS)=" + rtp_timestamp / 90  // convert from 90kHZ clock to ms
                                  + " SSRC=" + rtp_ssrc
                                  + " Size=" + e.Message.Data.Length);


                // Check the payload type in the RTP packet matches the Payload Type value from the SDP
                if (data_received.Channel == video_data_channel && rtp_payload_type != video_payload)
                {
                    Console.WriteLine("Ignoring this Video RTP payload");
                    return; // ignore this data
                }

                // Check the payload type in the RTP packet matches the Payload Type value from the SDP
                else if (data_received.Channel == audio_data_channel && rtp_payload_type != audio_payload)
                {
                    Console.WriteLine("Ignoring this Audio RTP payload");
                    return; // ignore this data
                }
                else if (data_received.Channel == video_data_channel &&
                         rtp_payload_type >= 96 && rtp_payload_type <= 127 &&
                         video_codec.Equals("H264"))
                {
                    // H264 RTP Packet

                    // If rtp_marker is '1' then this is the final transmission for this packet.
                    // If rtp_marker is '0' we need to accumulate data with the same timestamp

                    // ToDo - Check Timestamp
                    // Add the RTP packet to the tempoary_rtp list until we have a complete 'Frame'

                    byte[] rtp_payload = new byte[e.Message.Data.Length - rtp_payload_start];                 // payload with RTP header removed
                    System.Array.Copy(e.Message.Data, rtp_payload_start, rtp_payload, 0, rtp_payload.Length); // copy payload

                    List <byte[]> nal_units = h264Payload.Process_H264_RTP_Packet(rtp_payload, rtp_marker);   // this will cache the Packets until there is a Frame

                    if (nal_units == null)
                    {
                        // we have not passed in enough RTP packets to make a Frame of video
                    }
                    else
                    {
                        // we have a frame of NAL Units. Write them to the file
                        if (Received_NALs != null)
                        {
                            Received_NALs(nal_units);
                        }
                    }
                }
                else if (data_received.Channel == audio_data_channel && (rtp_payload_type == 0 || rtp_payload_type == 8 || audio_codec.Equals("PCMA") || audio_codec.Equals("PCMU")))
                {
                    // G711 PCMA or G711 PCMU
                    byte[] rtp_payload = new byte[e.Message.Data.Length - rtp_payload_start];                 // payload with RTP header removed
                    System.Array.Copy(e.Message.Data, rtp_payload_start, rtp_payload, 0, rtp_payload.Length); // copy payload

                    List <byte[]> audio_frames = g711Payload.Process_G711_RTP_Packet(rtp_payload, rtp_marker);

                    if (audio_frames == null)
                    {
                        // some error
                    }
                    else
                    {
                        // Write the audio frames to the file
                        if (Received_G711 != null)
                        {
                            Received_G711(audio_codec, audio_frames);
                        }
                    }
                }
                else if (data_received.Channel == video_data_channel && rtp_payload_type == 26)
                {
                    Console.WriteLine("No parser has been written for JPEG RTP packets. Please help write one");
                    return; // ignore this data
                }
                else
                {
                    Console.WriteLine("No parser for RTP payload " + rtp_payload_type);
                }
            }
        }
コード例 #9
0
ファイル: RTSPClient.cs プロジェクト: dragonk1988/SharpRTSP
        // RTSP Messages are OPTIONS, DESCRIBE, SETUP, PLAY etc
        private void Rtsp_MessageReceived(object sender, Rtsp.RtspChunkEventArgs e)
        {
            Rtsp.Messages.RtspResponse message = e.Message as Rtsp.Messages.RtspResponse;

            Console.WriteLine("Received " + message.OriginalRequest.ToString());

            // If message has a 401 - Unauthorised Error, then we re-send the message with Authorization
            // using the most recently received 'realm' and 'nonce'
            if (message.IsOk == false)
            {
                Console.WriteLine("Got Error in RTSP Reply " + message.ReturnCode + " " + message.ReturnMessage);

                if (message.ReturnCode == 401 && (message.OriginalRequest.Headers.ContainsKey(RtspHeaderNames.Authorization) == true))
                {
                    // the authorization failed.
                    Stop();
                    return;
                }

                // Check if the Reply has an Authenticate header.
                if (message.ReturnCode == 401 && message.Headers.ContainsKey(RtspHeaderNames.WWWAuthenticate))
                {
                    // Process the WWW-Authenticate header
                    // EG:   Basic realm="AProxy"
                    // EG:   Digest realm="AXIS_WS_ACCC8E3A0A8F", nonce="000057c3Y810622bff50b36005eb5efeae118626a161bf", stale=FALSE

                    String   www_authenticate = message.Headers[RtspHeaderNames.WWWAuthenticate];
                    string[] items            = www_authenticate.Split(new char[] { ',', ' ' });

                    foreach (string item in items)
                    {
                        if (item.ToLower().Equals("basic"))
                        {
                            auth_type = "Basic";
                        }
                        else if (item.ToLower().Equals("digest"))
                        {
                            auth_type = "Digest";
                        }
                        else
                        {
                            // Split on the = symbol and update the realm and nonce
                            string[] parts = item.Split(new char[] { '=' }, 2);                          // max 2 parts in the results array
                            if (parts.Count() >= 2 && parts[0].Trim().Equals("realm"))
                            {
                                realm = parts[1].Trim(new char[] { ' ', '\"' }); // trim space and quotes
                            }
                            else if (parts.Count() >= 2 && parts[0].Trim().Equals("nonce"))
                            {
                                nonce = parts[1].Trim(new char[] { ' ', '\"' }); // trim space and quotes
                            }
                        }
                    }

                    Console.WriteLine("WWW Authorize parsed for " + auth_type + " " + realm + " " + nonce);
                }

                RtspMessage resend_message = message.OriginalRequest.Clone() as RtspMessage;

                if (auth_type != null)
                {
                    AddAuthorization(resend_message, username, password, auth_type, realm, nonce, url);
                }

                rtsp_client.SendMessage(resend_message);

                return;
            }


            // If we get a reply to OPTIONS then start the Keepalive Timer and send DESCRIBE
            if (message.OriginalRequest != null && message.OriginalRequest is Rtsp.Messages.RtspRequestOptions)
            {
                if (keepalive_timer == null)
                {
                    // Start a Timer to send an OPTIONS command (for keepalive) every 20 seconds
                    keepalive_timer          = new System.Timers.Timer();
                    keepalive_timer.Elapsed += Timer_Elapsed;
                    keepalive_timer.Interval = 20 * 1000;
                    keepalive_timer.Enabled  = true;

                    // Send DESCRIBE
                    Rtsp.Messages.RtspRequest describe_message = new Rtsp.Messages.RtspRequestDescribe();
                    describe_message.RtspUri = new Uri(url);
                    if (auth_type != null)
                    {
                        AddAuthorization(describe_message, username, password, auth_type, realm, nonce, url);
                    }
                    rtsp_client.SendMessage(describe_message);
                }
                else
                {
                    // do nothing
                }
            }


            // If we get a reply to DESCRIBE (which was our second command), then prosess SDP and send the SETUP
            if (message.OriginalRequest != null && message.OriginalRequest is Rtsp.Messages.RtspRequestDescribe)
            {
                // Got a reply for DESCRIBE
                if (message.IsOk == false)
                {
                    Console.WriteLine("Got Error in DESCRIBE Reply " + message.ReturnCode + " " + message.ReturnMessage);
                    return;
                }

                // Examine the SDP

                Console.Write(System.Text.Encoding.UTF8.GetString(message.Data));

                Rtsp.Sdp.SdpFile sdp_data;
                using (StreamReader sdp_stream = new StreamReader(new MemoryStream(message.Data)))
                {
                    sdp_data = Rtsp.Sdp.SdpFile.Read(sdp_stream);
                }

                // RTP and RTCP 'channels' are used in TCP Interleaved mode (RTP over RTSP)
                int next_free_rtp_channel  = 0;
                int next_free_rtcp_channel = 1;

                // Process each 'Media' Attribute in the SDP (each sub-stream)

                for (int x = 0; x < sdp_data.Medias.Count; x++)
                {
                    bool audio = (sdp_data.Medias[x].MediaType == Rtsp.Sdp.Media.MediaTypes.audio);
                    bool video = (sdp_data.Medias[x].MediaType == Rtsp.Sdp.Media.MediaTypes.video);

                    if (video && video_payload != -1)
                    {
                        continue;                               // have already matched an video payload
                    }
                    if (audio && audio_payload != -1)
                    {
                        continue;                               // have already matched an audio payload
                    }
                    if (audio || video)
                    {
                        // search the attributes for control, rtpmap and fmtp
                        // (fmtp only applies to video)
                        String control             = "";   // the "track" or "stream id"
                        Rtsp.Sdp.AttributFmtp fmtp = null; // holds SPS and PPS in base64 (h264 video)
                        foreach (Rtsp.Sdp.Attribut attrib in sdp_data.Medias[x].Attributs)
                        {
                            if (attrib.Key.Equals("control"))
                            {
                                String sdp_control = attrib.Value;
                                if (sdp_control.ToLower().StartsWith("rtsp://"))
                                {
                                    control = sdp_control; //absolute path
                                }
                                else
                                {
                                    control = url + "/" + sdp_control; // relative path
                                }
                            }
                            if (attrib.Key.Equals("fmtp"))
                            {
                                fmtp = attrib as Rtsp.Sdp.AttributFmtp;
                            }
                            if (attrib.Key.Equals("rtpmap"))
                            {
                                Rtsp.Sdp.AttributRtpMap rtpmap = attrib as Rtsp.Sdp.AttributRtpMap;

                                // Check if the Codec Used (EncodingName) is one we support
                                String[] valid_video_codecs = { "H264" };
                                String[] valid_audio_codecs = { "PCMA", "PCMU", "AMR" };

                                if (video && Array.IndexOf(valid_video_codecs, rtpmap.EncodingName) >= 0)
                                {
                                    // found a valid codec
                                    video_codec   = rtpmap.EncodingName;
                                    video_payload = sdp_data.Medias[x].PayloadType;
                                }
                                if (audio && Array.IndexOf(valid_audio_codecs, rtpmap.EncodingName) >= 0)
                                {
                                    audio_codec   = rtpmap.EncodingName;
                                    audio_payload = sdp_data.Medias[x].PayloadType;
                                }
                            }
                        }

                        // If the rtpmap contains H264 then split the fmtp to get the sprop-parameter-sets which hold the SPS and PPS in base64
                        if (video && video_codec.Contains("H264") && fmtp != null)
                        {
                            var param   = Rtsp.Sdp.H264Parameters.Parse(fmtp.FormatParameter);
                            var sps_pps = param.SpropParameterSets;
                            if (sps_pps.Count() >= 2)
                            {
                                byte[] sps = sps_pps[0];
                                byte[] pps = sps_pps[1];
                                if (Received_SPS_PPS != null)
                                {
                                    Received_SPS_PPS(sps, pps);
                                }
                            }
                        }

                        // Send the SETUP RTSP command if we have a matching Payload Decoder
                        if (video && video_payload == -1)
                        {
                            continue;
                        }
                        if (audio && audio_payload == -1)
                        {
                            continue;
                        }

                        RtspTransport transport = null;

                        if (rtp_transport == RTP_TRANSPORT.TCP)
                        {
                            // Server interleaves the RTP packets over the RTSP connection
                            // Example for TCP mode (RTP over RTSP)   Transport: RTP/AVP/TCP;interleaved=0-1
                            if (video)
                            {
                                video_data_channel = next_free_rtp_channel;
                                video_rtcp_channel = next_free_rtcp_channel;
                            }
                            if (audio)
                            {
                                audio_data_channel = next_free_rtp_channel;
                                audio_rtcp_channel = next_free_rtcp_channel;
                            }
                            transport = new RtspTransport()
                            {
                                LowerTransport = RtspTransport.LowerTransportType.TCP,
                                Interleaved    = new PortCouple(next_free_rtp_channel, next_free_rtcp_channel), // Eg Channel 0 for RTP video data. Channel 1 for RTCP status reports
                            };

                            next_free_rtp_channel  += 2;
                            next_free_rtcp_channel += 2;
                        }
                        if (rtp_transport == RTP_TRANSPORT.UDP)
                        {
                            int rtp_port  = 0;
                            int rtcp_port = 0;
                            // Server sends the RTP packets to a Pair of UDP Ports (one for data, one for rtcp control messages)
                            // Example for UDP mode                   Transport: RTP/AVP;unicast;client_port=8000-8001
                            if (video)
                            {
                                video_data_channel = video_udp_pair.data_port;     // Used in DataReceived event handler
                                video_rtcp_channel = video_udp_pair.control_port;  // Used in DataReceived event handler
                                rtp_port           = video_udp_pair.data_port;
                                rtcp_port          = video_udp_pair.control_port;
                            }
                            if (audio)
                            {
                                audio_data_channel = audio_udp_pair.data_port;     // Used in DataReceived event handler
                                audio_rtcp_channel = audio_udp_pair.control_port;  // Used in DataReceived event handler
                                rtp_port           = audio_udp_pair.data_port;
                                rtcp_port          = audio_udp_pair.control_port;
                            }
                            transport = new RtspTransport()
                            {
                                LowerTransport = RtspTransport.LowerTransportType.UDP,
                                IsMulticast    = false,
                                ClientPort     = new PortCouple(rtp_port, rtcp_port), // a UDP Port for data (video or audio). a UDP Port for RTCP status reports
                            };
                        }
                        if (rtp_transport == RTP_TRANSPORT.MULTICAST)
                        {
                            // Server sends the RTP packets to a Pair of UDP ports (one for data, one for rtcp control messages)
                            // using Multicast Address and Ports that are in the reply to the SETUP message
                            // Example for MULTICAST mode     Transport: RTP/AVP;multicast
                            if (video)
                            {
                                video_data_channel = 0; // we get this information in the SETUP message reply
                                video_rtcp_channel = 0; // we get this information in the SETUP message reply
                            }
                            if (audio)
                            {
                                audio_data_channel = 0; // we get this information in the SETUP message reply
                                audio_rtcp_channel = 0; // we get this information in the SETUP message reply
                            }
                            transport = new RtspTransport()
                            {
                                LowerTransport = RtspTransport.LowerTransportType.UDP,
                                IsMulticast    = true
                            };
                        }

                        // Generate SETUP messages
                        Rtsp.Messages.RtspRequestSetup setup_message = new Rtsp.Messages.RtspRequestSetup();
                        setup_message.RtspUri = new Uri(control);
                        setup_message.AddTransport(transport);
                        if (auth_type != null)
                        {
                            AddAuthorization(setup_message, username, password, auth_type, realm, nonce, url);
                        }

                        // Add SETUP message to list of mesages to send
                        setup_messages.Add(setup_message);
                    }
                }
                // Send the FIRST SETUP message and remove it from the list of Setup Messages
                rtsp_client.SendMessage(setup_messages[0]);
                setup_messages.RemoveAt(0);
            }


            // If we get a reply to SETUP (which was our third command), then we
            // (i) check if we have any more SETUP commands to send out (eg if we are doing SETUP for Video and Audio)
            // (ii) send a PLAY command if all the SETUP command have been sent
            if (message.OriginalRequest != null && message.OriginalRequest is Rtsp.Messages.RtspRequestSetup)
            {
                // Got Reply to SETUP
                if (message.IsOk == false)
                {
                    Console.WriteLine("Got Error in SETUP Reply " + message.ReturnCode + " " + message.ReturnMessage);
                    return;
                }

                Console.WriteLine("Got reply from Setup. Session is " + message.Session);

                session = message.Session; // Session value used with Play, Pause, Teardown and and additional Setups

                // Check the Transport header
                if (message.Headers.ContainsKey(RtspHeaderNames.Transport))
                {
                    RtspTransport transport = RtspTransport.Parse(message.Headers[RtspHeaderNames.Transport]);

                    // Check if Transport header includes Multicast
                    if (transport.IsMulticast)
                    {
                        String multicast_address = transport.Destination;
                        video_data_channel = transport.Port.First;
                        video_rtcp_channel = transport.Port.Second;

                        // Create the Pair of UDP Sockets in Multicast mode
                        video_udp_pair = new Rtsp.UDPSocket(multicast_address, video_data_channel, multicast_address, video_rtcp_channel);
                        video_udp_pair.DataReceived += Rtp_DataReceived;
                        video_udp_pair.Start();

                        // TODO - Need to set audio_udp_pair
                    }
                }


                // Check if we have another SETUP command to send, then remote it from the list
                if (setup_messages.Count > 0)
                {
                    // send the next SETUP message, after adding in the 'session'
                    Rtsp.Messages.RtspRequestSetup next_setup = setup_messages[0];
                    next_setup.Session = session;
                    rtsp_client.SendMessage(next_setup);

                    setup_messages.RemoveAt(0);
                }

                else
                {
                    // Send PLAY
                    Rtsp.Messages.RtspRequest play_message = new Rtsp.Messages.RtspRequestPlay();
                    play_message.RtspUri = new Uri(url);
                    play_message.Session = session;
                    if (auth_type != null)
                    {
                        AddAuthorization(play_message, username, password, auth_type, realm, nonce, url);
                    }
                    rtsp_client.SendMessage(play_message);
                }
            }

            // If we get a reply to PLAY (which was our fourth command), then we should have video being received
            if (message.OriginalRequest != null && message.OriginalRequest is Rtsp.Messages.RtspRequestPlay)
            {
                // Got Reply to PLAY
                if (message.IsOk == false)
                {
                    Console.WriteLine("Got Error in PLAY Reply " + message.ReturnCode + " " + message.ReturnMessage);
                    return;
                }

                Console.WriteLine("Got reply from Play  " + message.Command);
            }
        }
コード例 #10
0
ファイル: example.cs プロジェクト: zhc341272/SharpRTSP
        private void Rtsp_client_DataReceived(object sender, Rtsp.RtspChunkEventArgs e)
        {
            // RTP Packet Header
            // 0 - Version, P, X, CC, M, PT and Sequence Number
            //32 - Timestamp
            //64 - SSRC
            //96 - CSRCs (optional)
            //nn - Extension ID and Length
            //nn - Extension header

            int  rtp_version         = (e.Message.Data[0] >> 6);
            int  rtp_padding         = (e.Message.Data[0] >> 5) & 0x01;
            int  rtp_extension       = (e.Message.Data[0] >> 4) & 0x01;
            int  rtp_csrc_count      = (e.Message.Data[0] >> 0) & 0x0F;
            int  rtp_marker          = (e.Message.Data[1] >> 7) & 0x01;
            int  rtp_payload_type    = (e.Message.Data[1] >> 0) & 0x7F;
            uint rtp_sequence_number = ((uint)e.Message.Data[2] << 8) + (uint)(e.Message.Data[3]);
            uint rtp_timestamp       = ((uint)e.Message.Data[4] << 24) + (uint)(e.Message.Data[5] << 16) + (uint)(e.Message.Data[6] << 8) + (uint)(e.Message.Data[7]);
            uint rtp_ssrc            = ((uint)e.Message.Data[8] << 24) + (uint)(e.Message.Data[9] << 16) + (uint)(e.Message.Data[10] << 8) + (uint)(e.Message.Data[11]);

            int rtp_payload_start = 4                       // V,P,M,SEQ
                                    + 4                     // time stamp
                                    + 4                     // ssrc
                                    + (4 * rtp_csrc_count); // zero or more csrcs

            uint rtp_extension_id   = 0;
            uint rtp_extension_size = 0;

            if (rtp_extension == 1)
            {
                rtp_extension_id   = ((uint)e.Message.Data[rtp_payload_start + 0] << 8) + (uint)(e.Message.Data[rtp_payload_start + 1] << 0);
                rtp_extension_size = ((uint)e.Message.Data[rtp_payload_start + 2] << 8) + (uint)(e.Message.Data[rtp_payload_start + 3] << 0);
                rtp_payload_start += 4 + (int)rtp_extension_size;  // extension header and extension payload
            }

            Console.WriteLine("RTP Data"
                              + " V=" + rtp_version
                              + " P=" + rtp_padding
                              + " X=" + rtp_extension
                              + " CC=" + rtp_csrc_count
                              + " M=" + rtp_marker
                              + " PT=" + rtp_payload_type
                              + " Seq=" + rtp_sequence_number
                              + " Time=" + rtp_timestamp
                              + " SSRC=" + rtp_ssrc
                              + " Size=" + e.Message.Data.Length);


            if (rtp_payload_type != video_payload)
            {
                Console.WriteLine("Ignoring this RTP payload");
                return; // ignore this data
            }


            // If rtp_marker is '1' then this is the final transmission for this packet.
            // If rtp_marker is '0' we need to accumulate data with the same timestamp


            // ToDo - Check Timestamp
            // ToDo - could avoid a copy if there is only one RTP frame for the data (temp list is zero)

            // Add to the tempoary_rtp List

            byte[] rtp_payload = new byte[e.Message.Data.Length - rtp_payload_start];                 // payload with RTP header removed
            System.Array.Copy(e.Message.Data, rtp_payload_start, rtp_payload, 0, rtp_payload.Length); // copy payload
            temporary_rtp_payloads.Add(rtp_payload);

            if (rtp_marker == 1)
            {
                // Process the RTP frame
                Process_RTP_Frame(temporary_rtp_payloads);
                temporary_rtp_payloads.Clear();
            }
        }
コード例 #11
0
ファイル: example.cs プロジェクト: zhc341272/SharpRTSP
        private void Rtsp_client_MessageReceived(object sender, Rtsp.RtspChunkEventArgs e)
        {
            Console.WriteLine("Message Received " + e.ToString());

            Rtsp.Messages.RtspResponse message = e.Message as Rtsp.Messages.RtspResponse;

            Console.WriteLine("Received " + message.OriginalRequest.ToString());

            if (message.OriginalRequest != null && message.OriginalRequest is Rtsp.Messages.RtspRequestOptions)
            {
                // send the Describe
                Rtsp.Messages.RtspRequest describe_message = new Rtsp.Messages.RtspRequestDescribe();
                describe_message.RtspUri = new Uri(url);
                rtsp_client.SendMessage(describe_message);
            }

            if (message.OriginalRequest != null && message.OriginalRequest is Rtsp.Messages.RtspRequestDescribe)
            {
                // Got a reply for DESCRIBE
                // Examine the SDP

                Console.Write(System.Text.Encoding.UTF8.GetString(message.Data));

                Rtsp.Sdp.SdpFile sdp_data;
                using (StreamReader sdp_stream = new StreamReader(new MemoryStream(message.Data)))
                {
                    sdp_data = Rtsp.Sdp.SdpFile.Read(sdp_stream);
                }


                // Process each 'Media' Attribute in the SDP.
                // If the attribute is for Video, then carry out a SETUP and a PLAY

                for (int x = 0; x < sdp_data.Medias.Count; x++)
                {
                    if (sdp_data.Medias[x].GetMediaType() == Rtsp.Sdp.Media.MediaType.video)
                    {
                        // seach the atributes for control, fmtp and rtpmap
                        String control = ""; // the "track" or "stream id"
                        String fmtp    = ""; // holds SPS and PPS
                        String rtpmap  = ""; // holds Payload format, eg 96 often used with H264 as first dynamic payload value
                        foreach (Rtsp.Sdp.Attribut attrib in sdp_data.Medias[x].Attributs)
                        {
                            if (attrib.Key.Equals("control"))
                            {
                                control = attrib.Value;
                            }
                            if (attrib.Key.Equals("fmtp"))
                            {
                                fmtp = attrib.Value;
                            }
                            if (attrib.Key.Equals("rtpmap"))
                            {
                                rtpmap = attrib.Value;
                            }
                        }

                        String[] split_rtpmap = rtpmap.Split(' ');
                        video_payload = 0;
                        bool result = Int32.TryParse(split_rtpmap[0], out video_payload);


                        // Transport: RTP/AVP;unicast;client_port=8000-8001
                        // Transport: RTP/AVP/TCP;interleaved=0-1

                        Rtsp.Messages.RtspRequest setup_message = new Rtsp.Messages.RtspRequestSetup();
                        setup_message.RtspUri = new Uri(url + "/" + control);
                        setup_message.AddHeader("Transport: RTP/AVP/TCP;interleaved=0");
                        rtsp_client.SendMessage(setup_message);
                    }
                }
            }

            if (message.OriginalRequest != null && message.OriginalRequest is Rtsp.Messages.RtspRequestSetup)
            {
                // Got Reply to SETUP
                Console.WriteLine("Got reply from Setup. Session is " + message.Session);

                String session = message.Session; // Session value used with Play, Pause, Teardown

                Rtsp.Messages.RtspRequest play_message = new Rtsp.Messages.RtspRequestPlay();
                play_message.RtspUri = new Uri(url);
                play_message.Session = session;
//                play_message.Timeout = 65;
                rtsp_client.SendMessage(play_message);
            }

            if (message.OriginalRequest != null && message.OriginalRequest is Rtsp.Messages.RtspRequestPlay)
            {
                // Got Reply to PLAU
                Console.WriteLine("Got reply from Play  " + message.Command);
            }
        }
コード例 #12
0
        // RTSP Messages are OPTIONS, DESCRIBE, SETUP, PLAY etc
        private void Rtsp_MessageReceived(object sender, Rtsp.RtspChunkEventArgs e)
        {
            Rtsp.Messages.RtspResponse message = e.Message as Rtsp.Messages.RtspResponse;

            Console.WriteLine("Received " + message.OriginalRequest.ToString());

            // If we get a reply to OPTIONS and CSEQ is 1 (which was our first command), then send the DESCRIBE
            // If we fer a reply to OPTIONS and CSEQ is not 1, it must have been a keepalive command
            if (message.OriginalRequest != null && message.OriginalRequest is Rtsp.Messages.RtspRequestOptions)
            {
                if (message.CSeq == 1)
                {
                    // Start a Timer to send an OPTIONS command (for keepalive) every 20 seconds
                    keepalive_timer          = new System.Timers.Timer();
                    keepalive_timer.Elapsed += Timer_Elapsed;
                    keepalive_timer.Interval = 20 * 1000;
                    keepalive_timer.Enabled  = true;

                    // send the Describe
                    Rtsp.Messages.RtspRequest describe_message = new Rtsp.Messages.RtspRequestDescribe();
                    describe_message.RtspUri = new Uri(url);
                    rtsp_client.SendMessage(describe_message);
                }
                else
                {
                    // do nothing
                }
            }


            // If we get a reply to DESCRIBE (which was our second command), then prosess SDP and send the SETUP
            if (message.OriginalRequest != null && message.OriginalRequest is Rtsp.Messages.RtspRequestDescribe)
            {
                // Got a reply for DESCRIBE
                // Examine the SDP

                Console.Write(System.Text.Encoding.UTF8.GetString(message.Data));

                Rtsp.Sdp.SdpFile sdp_data;
                using (StreamReader sdp_stream = new StreamReader(new MemoryStream(message.Data)))
                {
                    sdp_data = Rtsp.Sdp.SdpFile.Read(sdp_stream);
                }

                // Process each 'Media' Attribute in the SDP (each sub-stream)
                // If the attribute is for Video, then carry out a SETUP and a PLAY
                // Only do this for the first Video attribute in case there is more than one in the SDP

                for (int x = 0; x < sdp_data.Medias.Count; x++)
                {
                    if (sdp_data.Medias[x].GetMediaType() == Rtsp.Sdp.Media.MediaType.video)
                    {
                        // We only want the first video sub-stream
                        if (video_payload == -1)
                        {
                            // seach the atributes for control, fmtp and rtpmap
                            String control = "";                   // the "track" or "stream id"
                            Rtsp.Sdp.AttributFmtp   fmtp   = null; // holds SPS and PPS in base64
                            Rtsp.Sdp.AttributRtpMap rtpmap = null; // holds Payload format, eg 96 often used with H264 as first dynamic payload value
                            foreach (Rtsp.Sdp.Attribut attrib in sdp_data.Medias[x].Attributs)
                            {
                                if (attrib.Key.Equals("control"))
                                {
                                    control = attrib.Value;
                                }
                                if (attrib.Key.Equals("fmtp"))
                                {
                                    fmtp = attrib as Rtsp.Sdp.AttributFmtp;
                                }
                                if (attrib.Key.Equals("rtpmap"))
                                {
                                    rtpmap = attrib as Rtsp.Sdp.AttributRtpMap;
                                }
                            }

                            // Split the fmtp to get the sprop-parameter-sets which hold the SPS and PPS in base64
                            if (fmtp != null)
                            {
                                var param   = Rtsp.Sdp.H264Parameters.Parse(fmtp.FormatParameter);
                                var sps_pps = param.SpropParameterSets;
                                if (sps_pps.Count > 0)
                                {
                                    video_sps = sps_pps[0];
                                }
                                if (sps_pps.Count > 1)
                                {
                                    video_pps = sps_pps[1];
                                }
                                Output_NAL(sps_pps); // output SPS and PPS
                            }



                            // Split the rtpmap to get the Payload Type
                            video_payload = 0;
                            if (rtpmap != null)
                            {
                                video_payload = rtpmap.PayloadNumber;
                            }


                            Rtsp.Messages.RtspRequestSetup setup_message = new Rtsp.Messages.RtspRequestSetup();
                            setup_message.RtspUri = new Uri(url + "/" + control);

                            RtspTransport transport = null;
                            if (rtp_transport == RTP_TRANSPORT.TCP)
                            {
                                // Server interleaves the RTP packets over the RTSP connection
                                // Example for TCP mode (RTP over RTSP)   Transport: RTP/AVP/TCP;interleaved=0-1
                                video_data_channel = 0;  // Used in DataReceived event handler
                                video_rtcp_channel = 1;  // Used in DataReceived event handler
                                transport          = new RtspTransport()
                                {
                                    LowerTransport = RtspTransport.LowerTransportType.TCP,
                                    Interleaved    = new PortCouple(video_data_channel, video_rtcp_channel), // Channel 0 for video. Channel 1 for RTCP status reports
                                };
                            }
                            if (rtp_transport == RTP_TRANSPORT.UDP)
                            {
                                // Server sends the RTP packets to a Pair of UDP Ports (one for data, one for rtcp control messages)
                                // Example for UDP mode                   Transport: RTP/AVP;unicast;client_port=8000-8001
                                video_data_channel = udp_pair.data_port;     // Used in DataReceived event handler
                                video_rtcp_channel = udp_pair.control_port;  // Used in DataReceived event handler
                                transport          = new RtspTransport()
                                {
                                    LowerTransport = RtspTransport.LowerTransportType.UDP,
                                    IsMulticast    = false,
                                    ClientPort     = new PortCouple(video_data_channel, video_rtcp_channel), // a Channel for video. a Channel for RTCP status reports
                                };
                            }
                            if (rtp_transport == RTP_TRANSPORT.MULTICAST)
                            {
                                // Server sends the RTP packets to a Pair of UDP ports (one for data, one for rtcp control messages)
                                // using Multicast Address and Ports that are in the reply to the SETUP message
                                // Example for MULTICAST mode     Transport: RTP/AVP;multicast
                                video_data_channel = 0; // we get this information in the SETUP message reply
                                video_rtcp_channel = 0; // we get this information in the SETUP message reply
                                transport          = new RtspTransport()
                                {
                                    LowerTransport = RtspTransport.LowerTransportType.UDP,
                                    IsMulticast    = true
                                };
                            }
                            setup_message.AddTransport(transport);

                            rtsp_client.SendMessage(setup_message);
                        }
                    }
                }
            }


            // If we get a reply to SETUP (which was our third command), then process then send PLAY
            if (message.OriginalRequest != null && message.OriginalRequest is Rtsp.Messages.RtspRequestSetup)
            {
                // Got Reply to SETUP
                Console.WriteLine("Got reply from Setup. Session is " + message.Session);

                session = message.Session; // Session value used with Play, Pause, Teardown

                // Check the Transport header
                if (message.Headers.ContainsKey(RtspHeaderNames.Transport))
                {
                    RtspTransport transport = RtspTransport.Parse(message.Headers[RtspHeaderNames.Transport]);

                    // Check if Transport header includes Multicast
                    if (transport.IsMulticast)
                    {
                        String multicast_address = transport.Destination;
                        video_data_channel = transport.Port.First;
                        video_rtcp_channel = transport.Port.Second;

                        // Create the Pair of UDP Sockets in Multicast mode
                        udp_pair = new UDPSocket(multicast_address, video_data_channel, multicast_address, video_rtcp_channel);
                        udp_pair.DataReceived += Rtp_DataReceived;
                        udp_pair.Start();
                    }
                }

                Rtsp.Messages.RtspRequest play_message = new Rtsp.Messages.RtspRequestPlay();
                play_message.RtspUri = new Uri(url);
                play_message.Session = session;
                rtsp_client.SendMessage(play_message);
            }

            // If we get a reply to PLAY (which was our fourth command), then we should have video being received
            if (message.OriginalRequest != null && message.OriginalRequest is Rtsp.Messages.RtspRequestPlay)
            {
                // Got Reply to PLAY
                Console.WriteLine("Got reply from Play  " + message.Command);
            }
        }
コード例 #13
0
        int rtp_count = 0; // used for statistics
        // RTP packet (or RTCP packet) has been received.
        public void Rtp_DataReceived(object sender, Rtsp.RtspChunkEventArgs e)
        {
            Rtsp.Messages.RtspData data_received = e.Message as Rtsp.Messages.RtspData;

            // Check which channel the Data was received on.
            // eg the Video Channel, the Video Control Channel (RTCP)
            // In the future would also check the Audio Channel and Audio Control Channel

            if (data_received.Channel == video_rtcp_channel)
            {
                Console.WriteLine("Received a RTCP message on channel " + data_received.Channel);
                return;
            }

            if (data_received.Channel == video_data_channel)
            {
                // Received some Video Data on the correct channel.

                // RTP Packet Header
                // 0 - Version, P, X, CC, M, PT and Sequence Number
                //32 - Timestamp
                //64 - SSRC
                //96 - CSRCs (optional)
                //nn - Extension ID and Length
                //nn - Extension header

                int  rtp_version         = (e.Message.Data[0] >> 6);
                int  rtp_padding         = (e.Message.Data[0] >> 5) & 0x01;
                int  rtp_extension       = (e.Message.Data[0] >> 4) & 0x01;
                int  rtp_csrc_count      = (e.Message.Data[0] >> 0) & 0x0F;
                int  rtp_marker          = (e.Message.Data[1] >> 7) & 0x01;
                int  rtp_payload_type    = (e.Message.Data[1] >> 0) & 0x7F;
                uint rtp_sequence_number = ((uint)e.Message.Data[2] << 8) + (uint)(e.Message.Data[3]);
                uint rtp_timestamp       = ((uint)e.Message.Data[4] << 24) + (uint)(e.Message.Data[5] << 16) + (uint)(e.Message.Data[6] << 8) + (uint)(e.Message.Data[7]);
                uint rtp_ssrc            = ((uint)e.Message.Data[8] << 24) + (uint)(e.Message.Data[9] << 16) + (uint)(e.Message.Data[10] << 8) + (uint)(e.Message.Data[11]);

                int rtp_payload_start = 4                       // V,P,M,SEQ
                                        + 4                     // time stamp
                                        + 4                     // ssrc
                                        + (4 * rtp_csrc_count); // zero or more csrcs

                uint rtp_extension_id   = 0;
                uint rtp_extension_size = 0;
                if (rtp_extension == 1)
                {
                    rtp_extension_id   = ((uint)e.Message.Data[rtp_payload_start + 0] << 8) + (uint)(e.Message.Data[rtp_payload_start + 1] << 0);
                    rtp_extension_size = ((uint)e.Message.Data[rtp_payload_start + 2] << 8) + (uint)(e.Message.Data[rtp_payload_start + 3] << 0) * 4; // units of extension_size is 4-bytes
                    rtp_payload_start += 4 + (int)rtp_extension_size;                                                                                 // extension header and extension payload
                }

                Console.WriteLine("RTP Data"
                                  + " V=" + rtp_version
                                  + " P=" + rtp_padding
                                  + " X=" + rtp_extension
                                  + " CC=" + rtp_csrc_count
                                  + " M=" + rtp_marker
                                  + " PT=" + rtp_payload_type
                                  + " Seq=" + rtp_sequence_number
                                  + " Time (MS)=" + rtp_timestamp / 90  // convert from 90kHZ clock to ms
                                  + " SSRC=" + rtp_ssrc
                                  + " Size=" + e.Message.Data.Length);

                String msg = "RTP Data " + rtp_count++
                             + " V=" + rtp_version
                             + " P=" + rtp_padding
                             + " X=" + rtp_extension
                             + " CC=" + rtp_csrc_count
                             + " M=" + rtp_marker
                             + " PT=" + rtp_payload_type
                             //             + " Seq=" + rtp_sequence_number
                             //             + " Time=" + rtp_timestamp
                             //             + " SSRC=" + rtp_ssrc
                             + " Size=" + e.Message.Data.Length;
                fs2.WriteLine(msg);
                fs2.Flush();


                // Check the payload type in the RTP packet matches the Payload Type value from the SDP
                if (rtp_payload_type != video_payload)
                {
                    Console.WriteLine("Ignoring this RTP payload");
                    return; // ignore this data
                }


                // If rtp_marker is '1' then this is the final transmission for this packet.
                // If rtp_marker is '0' we need to accumulate data with the same timestamp

                // ToDo - Check Timestamp
                // ToDo - Could avoid a copy if there is only one RTP frame for the data (temp list is zero)

                // Add the RTP packet to the tempoary_rtp list

                byte[] rtp_payload = new byte[e.Message.Data.Length - rtp_payload_start];                 // payload with RTP header removed
                System.Array.Copy(e.Message.Data, rtp_payload_start, rtp_payload, 0, rtp_payload.Length); // copy payload
                temporary_rtp_payloads.Add(rtp_payload);

                if (rtp_marker == 1)
                {
                    // End Marker is set. Process the RTP frame
                    Process_RTP_Frame(temporary_rtp_payloads);
                    temporary_rtp_payloads.Clear();
                }
            }
        }
コード例 #14
0
        int rtp_count = 0; // used for statistics
        // RTP packet (or RTCP packet) has been received.
        public void Rtp_DataReceived(object sender, Rtsp.RtspChunkEventArgs e)
        {
            Rtsp.Messages.RtspData data_received = e.Message as Rtsp.Messages.RtspData;

            // Check which channel the Data was received on.
            // eg the Video Channel, the Video Control Channel (RTCP)
            // In the future would also check the Audio Channel and Audio Control Channel

            if (data_received.Channel == video_rtcp_channel)
            {
                Console.WriteLine("Received a RTCP message on channel " + data_received.Channel);
                return;
            }

            if (data_received.Channel == video_data_channel)
            {
                // Received some Video Data on the correct channel.

                // RTP Packet Header
                // 0 - Version, P, X, CC, M, PT and Sequence Number
                //32 - Timestamp
                //64 - SSRC
                //96 - CSRCs (optional)
                //nn - Extension ID and Length
                //nn - Extension header

                int  rtp_version         = (e.Message.Data[0] >> 6);
                int  rtp_padding         = (e.Message.Data[0] >> 5) & 0x01;
                int  rtp_extension       = (e.Message.Data[0] >> 4) & 0x01;
                int  rtp_csrc_count      = (e.Message.Data[0] >> 0) & 0x0F;
                int  rtp_marker          = (e.Message.Data[1] >> 7) & 0x01;
                int  rtp_payload_type    = (e.Message.Data[1] >> 0) & 0x7F;
                uint rtp_sequence_number = ((uint)e.Message.Data[2] << 8) + (uint)(e.Message.Data[3]);
                uint rtp_timestamp       = ((uint)e.Message.Data[4] << 24) + (uint)(e.Message.Data[5] << 16) + (uint)(e.Message.Data[6] << 8) + (uint)(e.Message.Data[7]);
                uint rtp_ssrc            = ((uint)e.Message.Data[8] << 24) + (uint)(e.Message.Data[9] << 16) + (uint)(e.Message.Data[10] << 8) + (uint)(e.Message.Data[11]);

                int rtp_payload_start = 4                       // V,P,M,SEQ
                                        + 4                     // time stamp
                                        + 4                     // ssrc
                                        + (4 * rtp_csrc_count); // zero or more csrcs

                uint rtp_extension_id   = 0;
                uint rtp_extension_size = 0;
                if (rtp_extension == 1)
                {
                    rtp_extension_id   = ((uint)e.Message.Data[rtp_payload_start + 0] << 8) + (uint)(e.Message.Data[rtp_payload_start + 1] << 0);
                    rtp_extension_size = ((uint)e.Message.Data[rtp_payload_start + 2] << 8) + (uint)(e.Message.Data[rtp_payload_start + 3] << 0) * 4; // units of extension_size is 4-bytes
                    rtp_payload_start += 4 + (int)rtp_extension_size;                                                                                 // extension header and extension payload
                }

                Console.WriteLine("RTP Data"
                                  + " V=" + rtp_version
                                  + " P=" + rtp_padding
                                  + " X=" + rtp_extension
                                  + " CC=" + rtp_csrc_count
                                  + " M=" + rtp_marker
                                  + " PT=" + rtp_payload_type
                                  + " Seq=" + rtp_sequence_number
                                  + " Time (MS)=" + rtp_timestamp / 90  // convert from 90kHZ clock to ms
                                  + " SSRC=" + rtp_ssrc
                                  + " Size=" + e.Message.Data.Length);

                String msg = "RTP Data " + rtp_count++
                             + " V=" + rtp_version
                             + " P=" + rtp_padding
                             + " X=" + rtp_extension
                             + " CC=" + rtp_csrc_count
                             + " M=" + rtp_marker
                             + " PT=" + rtp_payload_type
                             //             + " Seq=" + rtp_sequence_number
                             //             + " Time=" + rtp_timestamp
                             //             + " SSRC=" + rtp_ssrc
                             + " Size=" + e.Message.Data.Length;
                if (fs2 != null)
                {
                    fs2.WriteLine(msg);
                }
                if (fs2 != null)
                {
                    fs2.Flush();
                }


                // Check the payload type in the RTP packet matches the Payload Type value from the SDP
                if (rtp_payload_type != video_payload)
                {
                    Console.WriteLine("Ignoring this RTP payload");
                    return; // ignore this data
                }

                if (rtp_payload_type >= 96 && rtp_payload_type <= 127 && video_codec.Equals("H264"))
                {
                    // H264 RTP Packet

                    // If rtp_marker is '1' then this is the final transmission for this packet.
                    // If rtp_marker is '0' we need to accumulate data with the same timestamp

                    // ToDo - Check Timestamp
                    // Add the RTP packet to the tempoary_rtp list until we have a complete 'Frame'

                    byte[] rtp_payload = new byte[e.Message.Data.Length - rtp_payload_start];                 // payload with RTP header removed
                    System.Array.Copy(e.Message.Data, rtp_payload_start, rtp_payload, 0, rtp_payload.Length); // copy payload

                    List <byte[]> nal_units = h264Payload.Process_H264_RTP_Packet(rtp_payload, rtp_marker);   // this will cache the Packets until there is a Frame

                    if (nal_units == null)
                    {
                        // we have not passed in enough RTP packets to make a Frame of video
                    }
                    else
                    {
                        // we have a frame of NAL Units. Write them to the file
                        Output_NAL(nal_units);
                    }
                }

                else if (rtp_payload_type == 26)
                {
                    Console.WriteLine("No parser for JPEG RTP packets");
                }
                else
                {
                    Console.WriteLine("No parser for this RTP payload");
                }
            }
        }
コード例 #15
0
ファイル: Program.cs プロジェクト: jjbott/SharpRTSP
        // RTSP Messages are OPTIONS, DESCRIBE, SETUP, PLAY etc
        private void Rtsp_MessageReceived(object sender, Rtsp.RtspChunkEventArgs e)
        {
            Rtsp.Messages.RtspResponse message = e.Message as Rtsp.Messages.RtspResponse;

            Console.WriteLine("Received " + message.OriginalRequest.ToString());

            // Check if the Message has an Authenticate header. If so we update the 'realm' and 'nonce'
            if (message.Headers.ContainsKey(RtspHeaderNames.WWWAuthenticate))
            {
                String www_authenticate = message.Headers[RtspHeaderNames.WWWAuthenticate];

                var authHeader = AuthenticationHeaderValue.Parse(www_authenticate);
                authorizationScheme = authHeader.Scheme;

                var authParams = authHeader.Parameter
                                 .Split(',')
                                 .Select(p => p.Split('='))
                                 .ToDictionary(p => p[0].Trim(' ', '"'), p => p[1].Trim(' ', '"'));

                // For now, assuming auth scheme is either Basic or Digest
                realm = authParams["realm"];

                if (authorizationScheme == "Digest")
                {
                    nonce = authParams["nonce"];
                }

                Console.WriteLine("WWW Authorize parsed for " + realm + " " + nonce ?? "<NULL>");
            }


            // If we get a reply to OPTIONS and CSEQ is 1 (which was our first command), then send the DESCRIBE
            // If we fer a reply to OPTIONS and CSEQ is not 1, it must have been a keepalive command
            if (message.OriginalRequest != null && message.OriginalRequest is Rtsp.Messages.RtspRequestOptions)
            {
                if (message.CSeq == 1)
                {
                    // Start a Timer to send an OPTIONS command (for keepalive) every 20 seconds
                    keepalive_timer          = new System.Timers.Timer();
                    keepalive_timer.Elapsed += Timer_Elapsed;
                    keepalive_timer.Interval = 20 * 1000;
                    keepalive_timer.Enabled  = true;

                    // send the DESCRIBE. First time around we have no WWW-Authorise
                    Rtsp.Messages.RtspRequest describe_message = new Rtsp.Messages.RtspRequestDescribe();
                    describe_message.RtspUri = new Uri(url);
                    rtsp_client.SendMessage(describe_message);
                }
                else
                {
                    // do nothing
                }
            }


            // If we get a reply to DESCRIBE (which was our second command), then prosess SDP and send the SETUP
            if (message.OriginalRequest != null && message.OriginalRequest is Rtsp.Messages.RtspRequestDescribe)
            {
                // Got a reply for DESCRIBE

                // First time we send DESCRIBE we will not have the authorization Nonce so we
                // handle the Unauthorized 401 error here and send a new DESCRIBE message

                if (message.IsOk == false)
                {
                    Console.WriteLine("Got Error in DESCRIBE Reply " + message.ReturnCode + " " + message.ReturnMessage);

                    if (message.ReturnCode == 401 && (message.OriginalRequest.Headers.ContainsKey(RtspHeaderNames.Authorization) == false))
                    {
                        // Error 401 - Unauthorized, but the request did not use Authorizarion.

                        if (username == null || password == null)
                        {
                            // we do nothave a username or password. Abort
                            return;
                        }
                        // Send a new DESCRIBE with authorization
                        String authorization = GenerateAuthorization("DESCRIBE");

                        Rtsp.Messages.RtspRequest describe_message = new Rtsp.Messages.RtspRequestDescribe();
                        describe_message.RtspUri = new Uri(url);
                        if (authorization != null)
                        {
                            describe_message.Headers.Add(RtspHeaderNames.Authorization, authorization);
                        }
                        rtsp_client.SendMessage(describe_message);
                        return;
                    }
                    else if (message.ReturnCode == 401 && (message.OriginalRequest.Headers.ContainsKey(RtspHeaderNames.Authorization) == true))
                    {
                        // Authorization failed
                        return;
                    }
                    else
                    {
                        // some other error
                        return;
                    }
                }

                // Examine the SDP

                Console.Write(System.Text.Encoding.UTF8.GetString(message.Data));

                Rtsp.Sdp.SdpFile sdp_data;
                using (StreamReader sdp_stream = new StreamReader(new MemoryStream(message.Data)))
                {
                    sdp_data = Rtsp.Sdp.SdpFile.Read(sdp_stream);
                }

                // Process each 'Media' Attribute in the SDP (each sub-stream)
                // If the attribute is for Video, then carry out a SETUP and a PLAY
                // Only do this for the first Video attribute in case there is more than one in the SDP

                for (int x = 0; x < sdp_data.Medias.Count; x++)
                {
                    if (sdp_data.Medias[x].MediaType == Rtsp.Sdp.Media.MediaTypes.video)
                    {
                        // We only want the first video sub-stream
                        if (video_payload == -1)
                        {
                            video_payload = sdp_data.Medias[x].PayloadType;

                            // search the attributes for control, fmtp and rtpmap
                            String control = "";                   // the "track" or "stream id"
                            Rtsp.Sdp.AttributFmtp   fmtp   = null; // holds SPS and PPS in base64 (h264)
                            Rtsp.Sdp.AttributRtpMap rtpmap = null; // custom payload (>=96) details
                            foreach (Rtsp.Sdp.Attribut attrib in sdp_data.Medias[x].Attributs)
                            {
                                if (attrib.Key.Equals("control"))
                                {
                                    String sdp_control = attrib.Value;
                                    if (sdp_control.ToLower().StartsWith("rtsp://"))
                                    {
                                        control = sdp_control; //absolute path
                                    }
                                    else
                                    {
                                        control = url + "/" + sdp_control; // relative path
                                    }
                                }
                                if (attrib.Key.Equals("fmtp"))
                                {
                                    fmtp = attrib as Rtsp.Sdp.AttributFmtp;
                                }
                                if (attrib.Key.Equals("rtpmap"))
                                {
                                    rtpmap = attrib as Rtsp.Sdp.AttributRtpMap;
                                }
                            }

                            // If the rtpmap contains H264 then split the fmtp to get the sprop-parameter-sets which hold the SPS and PPS in base64
                            if (rtpmap != null && rtpmap.Value.Contains("H264") && fmtp != null)
                            {
                                video_codec = "H264";
                                var param   = Rtsp.Sdp.H264Parameters.Parse(fmtp.FormatParameter);
                                var sps_pps = param.SpropParameterSets;
                                if (sps_pps.Count() >= 2)
                                {
                                    byte[] sps = sps_pps[0];
                                    byte[] pps = sps_pps[1];
                                    Output_SPS_PPS(sps, pps); // output SPS and PPS
                                }
                            }

                            RtspTransport transport = null;
                            if (rtp_transport == RTP_TRANSPORT.TCP)
                            {
                                // Server interleaves the RTP packets over the RTSP connection
                                // Example for TCP mode (RTP over RTSP)   Transport: RTP/AVP/TCP;interleaved=0-1
                                video_data_channel = 0;  // Used in DataReceived event handler
                                video_rtcp_channel = 1;  // Used in DataReceived event handler
                                transport          = new RtspTransport()
                                {
                                    LowerTransport = RtspTransport.LowerTransportType.TCP,
                                    Interleaved    = new PortCouple(video_data_channel, video_rtcp_channel), // Channel 0 for video. Channel 1 for RTCP status reports
                                };
                            }
                            if (rtp_transport == RTP_TRANSPORT.UDP)
                            {
                                // Server sends the RTP packets to a Pair of UDP Ports (one for data, one for rtcp control messages)
                                // Example for UDP mode                   Transport: RTP/AVP;unicast;client_port=8000-8001
                                video_data_channel = udp_pair.data_port;     // Used in DataReceived event handler
                                video_rtcp_channel = udp_pair.control_port;  // Used in DataReceived event handler
                                transport          = new RtspTransport()
                                {
                                    LowerTransport = RtspTransport.LowerTransportType.UDP,
                                    IsMulticast    = false,
                                    ClientPort     = new PortCouple(video_data_channel, video_rtcp_channel), // a Channel for video. a Channel for RTCP status reports
                                };
                            }
                            if (rtp_transport == RTP_TRANSPORT.MULTICAST)
                            {
                                // Server sends the RTP packets to a Pair of UDP ports (one for data, one for rtcp control messages)
                                // using Multicast Address and Ports that are in the reply to the SETUP message
                                // Example for MULTICAST mode     Transport: RTP/AVP;multicast
                                video_data_channel = 0; // we get this information in the SETUP message reply
                                video_rtcp_channel = 0; // we get this information in the SETUP message reply
                                transport          = new RtspTransport()
                                {
                                    LowerTransport = RtspTransport.LowerTransportType.UDP,
                                    IsMulticast    = true
                                };
                            }

                            // Add authorization (if there is a username and password)
                            String digest_authorization = GenerateAuthorization("SETUP");

                            // Send SETUP
                            Rtsp.Messages.RtspRequestSetup setup_message = new Rtsp.Messages.RtspRequestSetup();
                            setup_message.RtspUri = new Uri(control);
                            setup_message.AddTransport(transport);
                            if (digest_authorization != null)
                            {
                                setup_message.Headers.Add("Authorization", digest_authorization);
                            }
                            rtsp_client.SendMessage(setup_message);
                        }
                    }
                }
            }


            // If we get a reply to SETUP (which was our third command), then process and then send PLAY
            if (message.OriginalRequest != null && message.OriginalRequest is Rtsp.Messages.RtspRequestSetup)
            {
                // Got Reply to SETUP
                if (message.IsOk == false)
                {
                    Console.WriteLine("Got Error in SETUP Reply " + message.ReturnCode + " " + message.ReturnMessage);
                    return;
                }

                Console.WriteLine("Got reply from Setup. Session is " + message.Session);

                session = message.Session; // Session value used with Play, Pause, Teardown

                // Check the Transport header
                if (message.Headers.ContainsKey(RtspHeaderNames.Transport))
                {
                    RtspTransport transport = RtspTransport.Parse(message.Headers[RtspHeaderNames.Transport]);

                    // Check if Transport header includes Multicast
                    if (transport.IsMulticast)
                    {
                        String multicast_address = transport.Destination;
                        video_data_channel = transport.Port.First;
                        video_rtcp_channel = transport.Port.Second;

                        // Create the Pair of UDP Sockets in Multicast mode
                        udp_pair = new UDPSocket(multicast_address, video_data_channel, multicast_address, video_rtcp_channel);
                        udp_pair.DataReceived += Rtp_DataReceived;
                        udp_pair.Start();
                    }
                }

                // Send PLAY
                Rtsp.Messages.RtspRequest play_message = new Rtsp.Messages.RtspRequestPlay();
                play_message.RtspUri = new Uri(url);
                play_message.Session = session;
                rtsp_client.SendMessage(play_message);
            }

            // If we get a reply to PLAY (which was our fourth command), then we should have video being received
            if (message.OriginalRequest != null && message.OriginalRequest is Rtsp.Messages.RtspRequestPlay)
            {
                // Got Reply to PLAY
                if (message.IsOk == false)
                {
                    Console.WriteLine("Got Error in PLAY Reply " + message.ReturnCode + " " + message.ReturnMessage);
                    return;
                }

                Console.WriteLine("Got reply from Play  " + message.Command);
            }
        }