示例#1
0
		static ByteBuffer EncodeVideoData(RtmpContext context, VideoData videoData) {
			ByteBuffer output = videoData.Data;
			return output;
		}
示例#2
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();
					}
				}
			}
		}
示例#3
0
		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;
				}
			}
		}
示例#4
0
		internal void RaiseNetStreamVideo(VideoData videoData) {
			if (_netStreamVideoHandler != null) {
				_netStreamVideoHandler(this, new NetStreamVideoEventArgs(videoData));
			}
		}
示例#5
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;
			}
		}