public void PushMessage(IPipe pipe, IMessage message)
        {
		    if (message is ResetMessage) 
            {
			    _timeStamper.Reset();
            } 
            else if (message is StatusMessage) 
            {
			    StatusMessage statusMsg = message as StatusMessage;
			    _data.SendStatus(statusMsg.body as StatusASO);
		    }
            else if (message is RtmpMessage)
            {
                // Make sure chunk size has been sent
                if (!_chunkSizeSent)
                    SendChunkSize();

                RtmpMessage rtmpMsg = message as RtmpMessage;
                IRtmpEvent msg = rtmpMsg.body;

                int eventTime = msg.Timestamp;
#if !SILVERLIGHT
                if(log.IsDebugEnabled)
                    log.Debug(string.Format("Message timestamp: {0}", eventTime));
#endif
                if (eventTime < 0)
                {
#if !SILVERLIGHT
                    if (log.IsDebugEnabled)
                        log.Debug(string.Format("Message has negative timestamp: {0}", eventTime));
#endif
                    return;
                }
                byte dataType = msg.DataType;
                // Create a new header for the consumer
                RtmpHeader header = _timeStamper.GetTimeStamp(dataType, eventTime);

                switch (msg.DataType)
                {
                    case Constants.TypeStreamMetadata:
                        Notify notify = new Notify((msg as Notify).Data);
                        notify.Header = header;
                        notify.Timestamp = header.Timer;
                        _data.Write(notify);
                        break;
                    case Constants.TypeFlexStreamEnd:
                        // TODO: okay to send this also to AMF0 clients?
                        FlexStreamSend send = new FlexStreamSend((msg as Notify).Data);
                        send.Header = header;
                        send.Timestamp = header.Timer;
                        _data.Write(send);
                        break;
                    case Constants.TypeVideoData:
                        VideoData videoData = new VideoData((msg as VideoData).Data);
                        videoData.Header = header;
                        videoData.Timestamp = header.Timer;
                        _video.Write(videoData);
                        break;
                    case Constants.TypeAudioData:
                        AudioData audioData = new AudioData((msg as AudioData).Data);
                        audioData.Header = header;
                        audioData.Timestamp = header.Timer;
                        _audio.Write(audioData);
                        break;
                    case Constants.TypePing:
                        Ping ping = new Ping((msg as Ping).PingType, (msg as Ping).Value2, (msg as Ping).Value3, (msg as Ping).Value4);
                        ping.Header = header;
                        _connection.Ping(ping);
                        break;
                    case Constants.TypeBytesRead:
                        BytesRead bytesRead = new BytesRead((msg as BytesRead).Bytes);
                        bytesRead.Header = header;
                        bytesRead.Timestamp = header.Timer;
                        _connection.GetChannel((byte)2).Write(bytesRead);
                        break;
                    default:
                        _data.Write(msg);
                        break;
                }
            }
        }
예제 #2
0
 internal void RaiseNetStreamVideo(VideoData videoData)
 {
     if (_netStreamVideoHandler != null)
     {
         _netStreamVideoHandler(this, new NetStreamVideoEventArgs(videoData));
     }
 }
 static ByteBuffer EncodeVideoData(RtmpContext context, VideoData videoData)
 {
     ByteBuffer output = videoData.Data;
     return output;
 }
예제 #4
0
 public IMessage PullMessage(IPipe pipe)
 {
     lock (_syncLock)
     {
         if (_pipe != pipe)
             return null;
         if (_reader == null)
             Init();
         if (!_reader.HasMoreTags())
         {
             // TODO send OOBCM to notify EOF
             // Do not unsubscribe as this kills VOD seek while in buffer
             // this.pipe.unsubscribe(this);
             return null;
         }
         ITag tag = _reader.ReadTag();
         IRtmpEvent msg = null;
         int timestamp = tag.Timestamp;
         switch (tag.DataType)
         {
             case Constants.TypeAudioData:
                 msg = new AudioData(tag.Body);
                 break;
             case Constants.TypeVideoData:
                 msg = new VideoData(tag.Body);
                 break;
             case Constants.TypeInvoke:
                 msg = new Invoke(tag.Body);
                 break;
             case Constants.TypeNotify:
                 msg = new Notify(tag.Body);
                 break;
             case Constants.TypeFlexStreamEnd:
                 msg = new FlexStreamSend(tag.Body);
                 break;
             default:
                 log.Warn("Unexpected type " + tag.DataType);
                 msg = new Unknown(tag.DataType, tag.Body);
                 break;
         }
         msg.Timestamp = timestamp;
         RtmpMessage rtmpMsg = new RtmpMessage();
         rtmpMsg.body = msg;
         return rtmpMsg;
     }
 }
예제 #5
0
        /// <summary>
        /// Play stream
        /// </summary>
        /// <param name="item">Playlist item.</param>
        /// <param name="withReset">Send reset status before playing.</param>
        public void Play(IPlayItem item, bool withReset)
        {
            lock (this.SyncRoot)
            {
                // Can't play if state is not stopped
                if (_playlistSubscriberStream.State != State.STOPPED)
                    throw new IllegalStateException();
                if (_msgIn != null)
                {
                    _msgIn.Unsubscribe(this);
                    _msgIn = null;
                }
                // Play type determination
                // http://livedocs.adobe.com/flex/3/langref/flash/net/NetStream.html#play%28%29
                // The start time, in seconds. Allowed values are -2, -1, 0, or a positive number. 
                // The default value is -2, which looks for a live stream, then a recorded stream, 
                // and if it finds neither, opens a live stream. 
                // If -1, plays only a live stream. 
                // If 0 or a positive number, plays a recorded stream, beginning start seconds in.
                //
                // -2: live then recorded, -1: live, >=0: recorded
                int type = (int)(item.Start / 1000);
                // see if it's a published stream
                IScope thisScope = _playlistSubscriberStream.Scope;
                string itemName = item.Name;
                //check for input and type
                InputType sourceType = _providerService.LookupProviderInputType(thisScope, itemName);

                bool isPublishedStream = sourceType == InputType.Live;
                bool isFileStream = sourceType == InputType.Vod;
                bool sendNotifications = true;

                // decision: 0 for Live, 1 for File, 2 for Wait, 3 for N/A
                switch (type)
                {
                    case -2:
                        if (isPublishedStream)
                            _playDecision = 0;
                        else if (isFileStream)
                            _playDecision = 1;
                        else
                            _playDecision = 2;
                        break;
                    case -1:
                        if (isPublishedStream)
                            _playDecision = 0;
                        else
                            _playDecision = 2;
                        break;
                    default:
                        if (isFileStream)
                            _playDecision = 1;
                        break;
                }
                if (log.IsDebugEnabled)
                    log.Debug(string.Format("Play decision is {0} (0=Live, 1=File, 2=Wait, 3=N/A)", _playDecision));
                _currentItem = item;
                long itemLength = item.Length;
                switch (_playDecision)
                {
                    case 0:
                        //get source input without create
                        _msgIn = _providerService.GetLiveProviderInput(thisScope, itemName, false);
                        // Drop all frames up to the next keyframe
                        _videoFrameDropper.Reset(FrameDropperState.SEND_KEYFRAMES_CHECK);
                        if (_msgIn is IBroadcastScope)
                        {
                            // Send initial keyframe
                            IClientBroadcastStream stream = (_msgIn as IBroadcastScope).GetAttribute(Constants.BroadcastScopeStreamAttribute) as IClientBroadcastStream;
                            if (stream != null && stream.CodecInfo != null)
                            {
                                IVideoStreamCodec videoCodec = stream.CodecInfo.VideoCodec;
                                if (videoCodec != null)
                                {
                                    if (withReset)
                                    {
                                        SendReset();
                                        SendResetStatus(item);
                                        SendStartStatus(item);
                                    }
                                    sendNotifications = false;
                                    //send decoder configuration if it exists
                                    ByteBuffer config = videoCodec.GetDecoderConfiguration();
                                    if (config != null)
                                    {
                                        VideoData conf = new VideoData(config);
                                        try
                                        {
                                            conf.Timestamp = 0;
                                            RtmpMessage confMsg = new RtmpMessage();
                                            confMsg.body = conf;
                                            _msgOut.PushMessage(confMsg);
                                        }
                                        finally
                                        {
                                            //conf.release();
                                        }
                                    }
                                    //Check for a keyframe to send
                                    ByteBuffer keyFrame = videoCodec.GetKeyframe();
                                    if (keyFrame != null)
                                    {
                                        VideoData video = new VideoData(keyFrame);
                                        try
                                        {
                                            video.Timestamp = 0;
                                            RtmpMessage videoMsg = new RtmpMessage();
                                            videoMsg.body = video;
                                            _msgOut.PushMessage(videoMsg);
                                            // Don't wait for keyframe
                                            _videoFrameDropper.Reset();
                                        }
                                        finally
                                        {
                                            //video.release();
                                        }
                                    }
                                }
                            }
                        }
                        _msgIn.Subscribe(this, null);
                        break;
                    case 2:
                        //get source input with create
                        _msgIn = _providerService.GetLiveProviderInput(thisScope, itemName, true);
                        _msgIn.Subscribe(this, null);
                        _waiting = true;
                        if (type == -1 && itemLength >= 0)
                        {
                            //log.debug("Creating wait job");
                            // Wait given timeout for stream to be published
                            PlaylistSubscriberStreamJob1 job = new PlaylistSubscriberStreamJob1(this, itemName);
                            _waitLiveJob = _schedulingService.AddScheduledOnceJob(item.Length, job);
                        }
                        else if (type == -2)
                        {
                            //log.debug("Creating wait job");
                            // Wait x seconds for the stream to be published
                            PlaylistSubscriberStreamJob2 job = new PlaylistSubscriberStreamJob2(this, itemName);
                            _waitLiveJob = _schedulingService.AddScheduledOnceJob(15000, job);
                        }
                        else
                        {
                            ConnectToProvider(itemName);
                        }
                        break;
                    case 1:
                        _msgIn = _providerService.GetVODProviderInput(thisScope, itemName);
                        if (_msgIn == null)
                        {
                            SendStreamNotFoundStatus(_currentItem);
                            throw new StreamNotFoundException(itemName);
                        }
                        if (!_msgIn.Subscribe(this, null))
                        {
                            log.Error("Input source subscribe failed");
                        }
                        break;
                    default:
                        SendStreamNotFoundStatus(_currentItem);
                        throw new StreamNotFoundException(itemName);
                }
                _playlistSubscriberStream.State = State.PLAYING;
                IMessage msg = null;
                _streamOffset = 0;
                _streamStartTS = -1;
                if (_playDecision == 1)
                {
                    if (withReset)
                    {
                        ReleasePendingMessage();
                    }
                    SendVODInitCM(_msgIn, item);
                    // Don't use pullAndPush to detect IOExceptions prior to sending NetStream.Play.Start
                    if (item.Start > 0)
                    {
                        _streamOffset = SendVODSeekCM(_msgIn, (int)item.Start);
                        // We seeked to the nearest keyframe so use real timestamp now
                        if (_streamOffset == -1)
                        {
                            _streamOffset = (int)item.Start;
                        }
                    }
                    msg = _msgIn.PullMessage();
                    if (msg is RtmpMessage)
                    {
                        IRtmpEvent body = ((RtmpMessage)msg).body;
                        if (itemLength == 0)
                        {
                            // Only send first video frame
                            body = ((RtmpMessage)msg).body;
                            while (body != null && !(body is VideoData))
                            {
                                msg = _msgIn.PullMessage();
                                if (msg == null)
                                    break;
                                if (msg is RtmpMessage)
                                    body = ((RtmpMessage)msg).body;
                            }
                        }
                        if (body != null)
                        {
                            // Adjust timestamp when playing lists
                            body.Timestamp = body.Timestamp + _timestampOffset;
                        }
                    }
                }
                if (sendNotifications)
                {
                    if (withReset)
                    {
                        SendReset();
                        SendResetStatus(item);
                    }
                    SendStartStatus(item);
                    if (!withReset)
                    {
                        SendSwitchStatus();
                    }
                }
                if (msg != null)
                {
                    SendMessage((RtmpMessage)msg);
                }
                _playlistSubscriberStream.NotifyItemPlay(_currentItem, !_isPullMode);
                if (withReset)
                {
                    long currentTime = System.Environment.TickCount;
                    _playbackStart = currentTime - _streamOffset;
                    _nextCheckBufferUnderrun = currentTime + _bufferCheckInterval;
                    if (_currentItem.Length != 0)
                    {
                        EnsurePullAndPushRunning();
                    }
                }
            }
        }
예제 #6
0
 /// <summary>
 /// Initializes a new instance of the <see cref="NetStreamVideoEventArgs"/> class.
 /// </summary>
 /// <param name="videoData">The video data.</param>
 internal NetStreamVideoEventArgs(VideoData videoData)
 {
     _videoData = videoData;
 }