Exemplo n.º 1
0
        /// <summary>
        /// Raises the <see cref="E:MessageReceived"/> event.
        /// </summary>
        /// <param name="e">The <see cref="Mictlanix.DotNet.Rtsp.RtspChunkEventArgs"/> instance containing the event data.</param>
        protected void OnMessageReceived(RtspChunkEventArgs e)
        {
            EventHandler <RtspChunkEventArgs> handler = MessageReceived;

            if (handler != null)
            {
                handler(this, e);
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Raises the <see cref="E:DataReceived"/> event.
        /// </summary>
        /// <param name="rtspChunkEventArgs">The <see cref="Mictlanix.DotNet.Rtsp.RtspChunkEventArgs"/> instance containing the event data.</param>
        protected void OnDataReceived(RtspChunkEventArgs rtspChunkEventArgs)
        {
            EventHandler <RtspChunkEventArgs> handler = DataReceived;

            if (handler != null)
            {
                handler(this, rtspChunkEventArgs);
            }
        }
Exemplo n.º 3
0
        // RTSP Messages are OPTIONS, DESCRIBE, SETUP, PLAY etc
        void Rtsp_MessageReceived(object sender, RtspChunkEventArgs e)
        {
            var message = e.Message as RtspResponse;

            //logger.Debug ("Received " + message.OriginalRequest.Method);

            // 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)
            {
                logger.Warn("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
                            }
                        }
                    }

                    //logger.Debug ("WWW Authorize parsed for " + auth_type + " " + realm + " " + nonce);
                }

                var 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 RtspRequestOptions)
            {
                string public_methods = message.Headers [RtspHeaderNames.Public];

                SupportedMethods.Clear();

                foreach (string method in public_methods.Split(','))
                {
                    SupportedMethods.Add(method.Trim());
                }

                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 = 5 * 1000;
                    keepalive_timer.Enabled  = true;

                    // Send DESCRIBE
                    var describe_message = new RtspRequestDescribe();
                    describe_message.RtspUri = new Uri(Url);
                    describe_message.AddAccept("application/sdp");

                    if (auth_type != null)
                    {
                        AddAuthorization(describe_message, Username, Password, auth_type, realm, nonce, Url);
                    }

                    rtsp_client.SendMessage(describe_message);
                }
            }

            // 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 Mictlanix.DotNet.Rtsp.Messages.RtspRequestDescribe)
            {
                // Got a reply for DESCRIBE
                if (!message.IsOk)
                {
                    logger.Warn("Got Error in DESCRIBE Reply " + message.ReturnCode + " " + message.ReturnMessage);
                    return;
                }

                // Examine the SDP
                //logger.Debug (Encoding.UTF8.GetString (message.Data));

                Sdp.SdpFile sdp_data;
                using (var sdp_stream = new StreamReader(new MemoryStream(message.Data))) {
                    sdp_data = 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 video = (sdp_data.Medias [x].MediaType == Mictlanix.DotNet.Rtsp.Sdp.Media.MediaTypes.video);

                    if (video && video_payload != -1)
                    {
                        continue;                                                   // have already matched an video payload
                    }
                    if (video)
                    {
                        // search the attributes for control, rtpmap and fmtp
                        // (fmtp only applies to video)
                        string            control = "";               // the "track" or "stream id"
                        Sdp.FmtpAttribute fmtp    = null;             // holds SPS and PPS in base64 (h264 video)

                        foreach (var attrib in sdp_data.Medias[x].Attributs)
                        {
                            if (attrib.Key.Equals("control"))
                            {
                                string sdp_control = attrib.Value;
                                if (sdp_control.ToLower().StartsWith("rtsp://", StringComparison.Ordinal))
                                {
                                    control = sdp_control;                                     //absolute path
                                }
                                else if (message.Headers.ContainsKey(RtspHeaderNames.ContentBase))
                                {
                                    control = message.Headers [RtspHeaderNames.ContentBase] + sdp_control;                                     // relative path
                                }
                                else
                                {
                                    control = Url + "/" + sdp_control;                                     // relative path
                                }
                            }
                            if (attrib.Key.Equals("fmtp"))
                            {
                                fmtp = attrib as Sdp.FmtpAttribute;
                            }
                            if (attrib.Key.Equals("rtpmap"))
                            {
                                var rtpmap = attrib as Sdp.RtpMapAttribute;

                                // Check if the Codec Used (EncodingName) is one we support
                                string [] valid_video_codecs = { "H264" };

                                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 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   = 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];
                                ParameterSetsReceived?.Invoke(sps, pps);
                            }
                        }

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

                        // Server interleaves the RTP packets over the RTSP connection
                        // TCP mode (RTP over RTSP)   Transport: RTP/AVP/TCP;interleaved=0-1
                        video_data_channel = 0;
                        video_rtcp_channel = 1;

                        var transport = new RtspTransport()
                        {
                            LowerTransport = RtspTransport.LowerTransportType.TCP,
                            Interleaved    = new PortCouple(video_data_channel, video_rtcp_channel),                           // Eg Channel 0 for video. Channel 1 for RTCP status reports
                        };

                        // Send SETUP
                        var setup_message = new 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);
                        }

                        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 RtspRequestSetup)
            {
                // Got Reply to SETUP
                if (!message.IsOk)
                {
                    logger.Warn("Got Error in SETUP Reply " + message.ReturnCode + " " + message.ReturnMessage);
                    return;
                }

                //logger.Debug ("Got reply from SETUP Session=" + message.Session);

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

                // Send PLAY
                RtspRequest play_message = new RtspRequestPlay();
                play_message.RtspUri = new Uri(Url);
                play_message.Session = RtspSession;

                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 RtspRequestPlay)
            {
                // Got Reply to PLAY
                if (!message.IsOk)
                {
                    logger.Warn("Got Error in PLAY Reply " + message.ReturnCode + " " + message.ReturnMessage);
                    return;
                }

                //logger.Debug ("Got reply from PLAY " + message.Command);
            }
        }
Exemplo n.º 4
0
        // int rtp_count = 0; // used for statistics
        // RTP packet (or RTCP packet) has been received.
        void Rtp_DataReceived(object sender, RtspChunkEventArgs e)
        {
            var data_received = e.Message as RtspData;

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

            if (data_received.Channel == video_rtcp_channel)
            {
                //logger.Debug ("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

                    //logger.Debug ("RTCP Data. PacketType=" + rtcp_packet_type + " SSRC=" + rtcp_ssrc);

                    if (rtcp_packet_type == 200)
                    {
                        // Send a Receiver Report
                        try {
                            SendEmptyReceiverReport();
                        } catch {
                            logger.Warn("Error writing RTCP packet");
                        }
                    }

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

                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
                }

                //logger.Debug ("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 (rtp_payload_type != video_payload)
                {
                    logger.Warn("Ignoring this Video 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
                    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

                    // we have not passed in enough RTP packets to make a Frame of video
                    // we have a frame of NAL Units. Write them to the file
                    if (nal_units != null)
                    {
                        FrameReceived?.Invoke(nal_units);
                    }
                }
                else
                {
                    logger.Warn("No parser for RTP payload " + rtp_payload_type);
                }
            }
        }