static ByteBuffer EncodeVideoData(RtmpContext context, VideoData videoData) { ByteBuffer output = videoData.Data; return output; }
/// <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(); } } } }
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; } } }
internal void RaiseNetStreamVideo(VideoData videoData) { if (_netStreamVideoHandler != null) { _netStreamVideoHandler(this, new NetStreamVideoEventArgs(videoData)); } }
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; } }