use of org.red5.codec.IStreamCodecInfo in project red5-server-common by Red5.
the class ClientBroadcastStream method dispatchEvent.
/**
* Dispatches event
*
* @param event
* Event to dispatch
*/
public void dispatchEvent(IEvent event) {
if (event instanceof IRTMPEvent && !closed.get()) {
switch(event.getType()) {
case STREAM_CONTROL:
case STREAM_DATA:
// create the event
IRTMPEvent rtmpEvent;
try {
rtmpEvent = (IRTMPEvent) event;
} catch (ClassCastException e) {
log.error("Class cast exception in event dispatch", e);
return;
}
int eventTime = rtmpEvent.getTimestamp();
// verify and / or set source type
if (rtmpEvent.getSourceType() != Constants.SOURCE_TYPE_LIVE) {
rtmpEvent.setSourceType(Constants.SOURCE_TYPE_LIVE);
}
/*
* if (log.isTraceEnabled()) { // If this is first packet save its timestamp; expect it is // absolute? no matter: it's never used! if (firstPacketTime == -1) { firstPacketTime =
* rtmpEvent.getTimestamp(); log.trace(String.format("CBS=@%08x: rtmpEvent=%s creation=%s firstPacketTime=%d", System.identityHashCode(this), rtmpEvent.getClass().getSimpleName(),
* creationTime, firstPacketTime)); } else { log.trace(String.format("CBS=@%08x: rtmpEvent=%s creation=%s firstPacketTime=%d timestamp=%d", System.identityHashCode(this),
* rtmpEvent.getClass().getSimpleName(), creationTime, firstPacketTime, eventTime)); } }
*/
// get the buffer only once per call
IoBuffer buf = null;
if (rtmpEvent instanceof IStreamData && (buf = ((IStreamData<?>) rtmpEvent).getData()) != null) {
bytesReceived += buf.limit();
}
// get stream codec
IStreamCodecInfo codecInfo = getCodecInfo();
StreamCodecInfo info = null;
if (codecInfo instanceof StreamCodecInfo) {
info = (StreamCodecInfo) codecInfo;
}
// log.trace("Stream codec info: {}", info);
if (rtmpEvent instanceof AudioData) {
// log.trace("Audio: {}", eventTime);
IAudioStreamCodec audioStreamCodec = null;
if (checkAudioCodec) {
// dont try to read codec info from 0 length audio packets
if (buf.limit() > 0) {
audioStreamCodec = AudioCodecFactory.getAudioCodec(buf);
if (info != null) {
info.setAudioCodec(audioStreamCodec);
}
checkAudioCodec = false;
}
} else if (codecInfo != null) {
audioStreamCodec = codecInfo.getAudioCodec();
}
if (audioStreamCodec != null) {
audioStreamCodec.addData(buf);
}
if (info != null) {
info.setHasAudio(true);
}
} else if (rtmpEvent instanceof VideoData) {
// log.trace("Video: {}", eventTime);
IVideoStreamCodec videoStreamCodec = null;
if (checkVideoCodec) {
videoStreamCodec = VideoCodecFactory.getVideoCodec(buf);
if (info != null) {
info.setVideoCodec(videoStreamCodec);
}
checkVideoCodec = false;
} else if (codecInfo != null) {
videoStreamCodec = codecInfo.getVideoCodec();
}
if (videoStreamCodec != null) {
videoStreamCodec.addData(buf, eventTime);
}
if (info != null) {
info.setHasVideo(true);
}
} else if (rtmpEvent instanceof Invoke) {
// event / stream listeners will not be notified of invokes
return;
} else if (rtmpEvent instanceof Notify) {
Notify notifyEvent = (Notify) rtmpEvent;
String action = notifyEvent.getAction();
// }
if ("onMetaData".equals(action)) {
// store the metadata
try {
// log.debug("Setting metadata");
setMetaData(notifyEvent.duplicate());
} catch (Exception e) {
log.warn("Metadata could not be duplicated for this stream", e);
}
}
}
// update last event time
if (eventTime > latestTimeStamp) {
latestTimeStamp = eventTime;
}
// notify event listeners
checkSendNotifications(event);
// note this timestamp is set in event/body but not in the associated header
try {
// route to live
if (livePipe != null) {
// create new RTMP message, initialize it and push through pipe
RTMPMessage msg = RTMPMessage.build(rtmpEvent, eventTime);
livePipe.pushMessage(msg);
} else if (log.isDebugEnabled()) {
log.debug("Live pipe was null, message was not pushed");
}
} catch (IOException err) {
stop();
}
// notify listeners about received packet
if (rtmpEvent instanceof IStreamPacket) {
for (IStreamListener listener : getStreamListeners()) {
try {
listener.packetReceived(this, (IStreamPacket) rtmpEvent);
} catch (Exception e) {
log.error("Error while notifying listener {}", listener, e);
if (listener instanceof RecordingListener) {
sendRecordFailedNotify(e.getMessage());
}
}
}
}
break;
default:
}
} else {
log.debug("Event was of wrong type or stream is closed ({})", closed);
}
}
use of org.red5.codec.IStreamCodecInfo in project red5-server-common by Red5.
the class PlayEngine method playLive.
/**
* Performs the processes needed for live streams. The following items are sent if they exist:
* <ul>
* <li>Metadata</li>
* <li>Decoder configurations (ie. AVC codec)</li>
* <li>Most recent keyframe</li>
* </ul>
*
* @throws IOException
*/
private final void playLive() throws IOException {
// change state
subscriberStream.setState(StreamState.PLAYING);
IMessageInput in = msgInReference.get();
IMessageOutput out = msgOutReference.get();
if (in != null && out != null) {
// get the stream so that we can grab any metadata and decoder configs
IBroadcastStream stream = (IBroadcastStream) ((IBroadcastScope) in).getClientBroadcastStream();
// prevent an NPE when a play list is created and then immediately flushed
int ts = 0;
if (stream != null) {
Notify metaData = stream.getMetaData();
// check for metadata to send
if (metaData != null) {
ts = metaData.getTimestamp();
log.debug("Metadata is available");
RTMPMessage metaMsg = RTMPMessage.build(metaData, metaData.getTimestamp());
sendMessage(metaMsg);
} else {
log.debug("No metadata available");
}
IStreamCodecInfo codecInfo = stream.getCodecInfo();
log.debug("Codec info: {}", codecInfo);
if (codecInfo instanceof StreamCodecInfo) {
StreamCodecInfo info = (StreamCodecInfo) codecInfo;
// handle video codec with configuration
IVideoStreamCodec videoCodec = info.getVideoCodec();
log.debug("Video codec: {}", videoCodec);
if (videoCodec != null) {
// check for decoder configuration to send
IoBuffer config = videoCodec.getDecoderConfiguration();
if (config != null) {
log.debug("Decoder configuration is available for {}", videoCodec.getName());
VideoData conf = new VideoData(config, true);
log.debug("Pushing video decoder configuration");
sendMessage(RTMPMessage.build(conf, ts));
}
// check for keyframes to send
FrameData[] keyFrames = videoCodec.getKeyframes();
for (FrameData keyframe : keyFrames) {
log.debug("Keyframe is available");
VideoData video = new VideoData(keyframe.getFrame(), true);
log.debug("Pushing keyframe");
sendMessage(RTMPMessage.build(video, ts));
}
} else {
log.debug("No video decoder configuration available");
}
// handle audio codec with configuration
IAudioStreamCodec audioCodec = info.getAudioCodec();
log.debug("Audio codec: {}", audioCodec);
if (audioCodec != null) {
// check for decoder configuration to send
IoBuffer config = audioCodec.getDecoderConfiguration();
if (config != null) {
log.debug("Decoder configuration is available for {}", audioCodec.getName());
AudioData conf = new AudioData(config.asReadOnlyBuffer());
log.debug("Pushing audio decoder configuration");
sendMessage(RTMPMessage.build(conf, ts));
}
} else {
log.debug("No audio decoder configuration available");
}
}
}
} else {
throw new IOException(String.format("A message pipe is null - in: %b out: %b", (msgInReference == null), (msgOutReference == null)));
}
configsDone = true;
}
use of org.red5.codec.IStreamCodecInfo in project red5-server by Red5.
the class ServerStream method saveAs.
/**
* {@inheritDoc}
*/
public void saveAs(String name, boolean isAppend) throws IOException {
// one recording listener at a time via this entry point
if (recordingListener == null) {
IScope scope = getScope();
// create a recording listener
IRecordingListener listener = (IRecordingListener) ScopeUtils.getScopeService(scope, IRecordingListener.class, RecordingListener.class);
// initialize the listener
if (listener.init(scope, name, isAppend)) {
// get decoder info if it exists for the stream
IStreamCodecInfo codecInfo = getCodecInfo();
log.debug("Codec info: {}", codecInfo);
if (codecInfo instanceof StreamCodecInfo) {
StreamCodecInfo info = (StreamCodecInfo) codecInfo;
IVideoStreamCodec videoCodec = info.getVideoCodec();
log.debug("Video codec: {}", videoCodec);
if (videoCodec != null) {
// check for decoder configuration to send
IoBuffer config = videoCodec.getDecoderConfiguration();
if (config != null) {
log.debug("Decoder configuration is available for {}", videoCodec.getName());
VideoData videoConf = new VideoData(config.asReadOnlyBuffer());
try {
log.debug("Setting decoder configuration for recording");
listener.getFileConsumer().setVideoDecoderConfiguration(videoConf);
} finally {
videoConf.release();
}
}
} else {
log.debug("Could not initialize stream output, videoCodec is null.");
}
IAudioStreamCodec audioCodec = info.getAudioCodec();
log.debug("Audio codec: {}", audioCodec);
if (audioCodec != null) {
// check for decoder configuration to send
IoBuffer config = audioCodec.getDecoderConfiguration();
if (config != null) {
log.debug("Decoder configuration is available for {}", audioCodec.getName());
AudioData audioConf = new AudioData(config.asReadOnlyBuffer());
try {
log.debug("Setting decoder configuration for recording");
listener.getFileConsumer().setAudioDecoderConfiguration(audioConf);
} finally {
audioConf.release();
}
}
} else {
log.debug("No decoder configuration available, audioCodec is null.");
}
}
// set as primary listener
recordingListener = new WeakReference<>(listener);
// add as a listener
addStreamListener(listener);
// start the listener thread
listener.start();
} else {
log.warn("Recording listener failed to initialize for stream: {}", name);
}
} else {
log.info("Recording listener already exists for stream: {}", name);
}
}
use of org.red5.codec.IStreamCodecInfo in project red5-server-common by Red5.
the class ClientBroadcastStream method saveAs.
/**
* Save broadcasted stream.
*
* @param name
* Stream name
* @param isAppend
* Append mode
* @throws IOException
* File could not be created/written to
*/
public void saveAs(String name, boolean isAppend) throws IOException {
// log.debug("SaveAs - name: {} append: {}", name, isAppend);
// get connection to check if client is still streaming
IStreamCapableConnection conn = getConnection();
if (conn == null) {
throw new IOException("Stream is no longer connected");
}
// one recording listener at a time via this entry point
if (recordingListener == null) {
// XXX Paul: Revisit this section to allow for implementation of custom IRecordingListener
// IRecordingListener listener = (IRecordingListener) ScopeUtils.getScopeService(conn.getScope(), IRecordingListener.class, RecordingListener.class, false);
// create a recording listener
IRecordingListener listener = new RecordingListener();
// initialize the listener
if (listener.init(conn, name, isAppend)) {
// get decoder info if it exists for the stream
IStreamCodecInfo codecInfo = getCodecInfo();
// log.debug("Codec info: {}", codecInfo);
if (codecInfo instanceof StreamCodecInfo) {
StreamCodecInfo info = (StreamCodecInfo) codecInfo;
IVideoStreamCodec videoCodec = info.getVideoCodec();
// log.debug("Video codec: {}", videoCodec);
if (videoCodec != null) {
// check for decoder configuration to send
IoBuffer config = videoCodec.getDecoderConfiguration();
if (config != null) {
// log.debug("Decoder configuration is available for {}", videoCodec.getName());
VideoData videoConf = new VideoData(config.asReadOnlyBuffer());
try {
// log.debug("Setting decoder configuration for recording");
listener.getFileConsumer().setVideoDecoderConfiguration(videoConf);
} finally {
videoConf.release();
}
}
} else {
log.debug("Could not initialize stream output, videoCodec is null.");
}
IAudioStreamCodec audioCodec = info.getAudioCodec();
// log.debug("Audio codec: {}", audioCodec);
if (audioCodec != null) {
// check for decoder configuration to send
IoBuffer config = audioCodec.getDecoderConfiguration();
if (config != null) {
// log.debug("Decoder configuration is available for {}", audioCodec.getName());
AudioData audioConf = new AudioData(config.asReadOnlyBuffer());
try {
// log.debug("Setting decoder configuration for recording");
listener.getFileConsumer().setAudioDecoderConfiguration(audioConf);
} finally {
audioConf.release();
}
}
} else {
log.debug("No decoder configuration available, audioCodec is null.");
}
}
// set as primary listener
recordingListener = new WeakReference<IRecordingListener>(listener);
// add as a listener
addStreamListener(listener);
// start the listener thread
listener.start();
} else {
log.warn("Recording listener failed to initialize for stream: {}", name);
}
} else {
log.debug("Recording listener already exists for stream: {} auto record enabled: {}", name, automaticRecording);
}
}
Aggregations