/**
* Copyright (c) 2008 - 2014 Smaxe Ltd (www.smaxe.com).
* All rights reserved.
*/
import com.smaxe.logger.ILogger;
import com.smaxe.logger.support.Loggers;
import com.smaxe.uv.client.rtsp.IMessageInterceptor;
import com.smaxe.uv.client.rtsp.IPresentation;
import com.smaxe.uv.client.rtsp.IVideo;
import com.smaxe.uv.client.rtsp.RtspClient;
import com.smaxe.uv.client.rtsp.RtspPlaySession;
import com.smaxe.uv.client.rtsp.RtspRequest;
import com.smaxe.uv.client.rtsp.RtspResponse;
import com.smaxe.uv.client.rtsp.video.AbstractVideo;
import com.smaxe.uv.client.rtsp.video.DispatcherVideo;
import com.smaxe.uv.media.core.IVideoDecoder;
import com.smaxe.uv.media.core.MediaTrackInfo;
import com.smaxe.uv.media.core.VideoFrame;
import com.smaxe.uv.media.java.swing.JVideoScreen;
import com.smaxe.uv.media.sdk.IMediaSdk;
import com.smaxe.uv.media.sdk.MediaSdkFactory;
import com.smaxe.uv.stream.MediaData;
import com.smaxe.uv.stream.MediaDataFactory;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
/**
* <code>ExMediaSdkPlayRealtimeVideoOnlyRtspStream</code> - {@link IMediaSdk} example
* that plays real-time video-only RTSP/RTP stream.
* <p> Note:
*
* @author Andrei Sochirca
* @see <a href="http://www.smaxe.com/product.jsf?id=juv-media-sdk" target="_blank">JUV Media SDK</a>
* @see <a href="http://www.smaxe.com/product.jsf?id=juv-rtsp-client" target="_blank">JUV RTSP/RTP Client</a>
*/
public final class ExMediaSdkPlayRealtimeVideoOnlyRtspStream extends Object
{
/**
* Entry point.
*
* @param args
* @throws Exception
*/
public static void main(final String[] args) throws Exception
{
// NOTE:
// Evaluation version has some limitations:
// - video decoder watermarks frames (and blacks it sometimes)
final String url = args.length == 0 ? "rtsp://184.72.239.149/vod/mp4:BigBuckBunny_175k.mov" : args[0];
final IMediaSdk mediaSdk = MediaSdkFactory.getMediaSdk();
final JVideoScreen videoScreen = new JVideoScreen();
final JButton start = new JButton(new AbstractAction("Play")
{
private final static long serialVersionUID = -3538347901572402162L;
public void actionPerformed(final ActionEvent e)
{
new Thread(new Runnable()
{
public void run()
{
final RtspPlayer player = new RtspPlayer();
player.play(url, new DispatcherVideo(new Video(mediaSdk, videoScreen)));
}
}, "ExMediaSdkPlayRealtimeVideoOnlyRtspStream-Player").start();
}
});
final JFrame frame = new JFrame();
frame.getContentPane().setLayout(new BorderLayout());
frame.getContentPane().add(videoScreen, BorderLayout.CENTER);
frame.getContentPane().add(start, BorderLayout.SOUTH);
frame.pack();
frame.setTitle(url);
frame.setVisible(true);
}
/**
* <code>RtspPlayer</code> - RTSP Player.
*/
public final static class RtspPlayer extends Object
{
/**
* <code>MessageInterceptor</code> - {@link IMessageInterceptor} implementation.
*/
private final class MessageInterceptor extends Object implements IMessageInterceptor
{
/**
* Constructor.
*/
public MessageInterceptor()
{
}
// IMessageInterceptor implementation
public RtspRequest onRequest(final String source, final RtspRequest request)
{
logger.log(ILogger.DEBUG, "onRequest", null /*t*/, source, request);
return request;
}
public RtspResponse onResponse(final String source, final RtspResponse response)
{
logger.log(ILogger.DEBUG, "onResponse", null /*t*/, source, response);
return response;
}
}
// fields
// beans
private ILogger logger = Loggers.createSoLogger(ILogger.DEBUG, "Logger");
// state
private IPresentation presentation = null;
private volatile boolean disconnected = false;
private volatile String disconnectionReason = null;
/**
* Constructor.
*/
public RtspPlayer()
{
}
/**
* Sets logger.
*
* @param logger
*/
public void setLogger(final ILogger logger)
{
this.logger = logger == null ? Loggers.createNullLogger() : logger;
}
/**
* Returns playing presentation.
*
* @return playing presentation
*/
public IPresentation getPresentation()
{
return presentation;
}
/**
* Checks if playing.
*
* @return <code>true</code> if playing; otherwise <code>false</code>
*/
public boolean isPlaying()
{
return !disconnected;
}
/**
* Plays the stream.
* <p> Note:
* <br> - The method blocks until the player connection is closed, so run it
* in a separate thread.
*
* @param url rtmp url
* @param video video
* @param udpPort UDP port to use
*/
public void play(final String url, final IVideo video)
{
final RtspClient client = new RtspClient();
try
{
client.configuration().put(RtspClient.Configuration.DATAGRAM_JITTER_BUFFER_MARGIN, 16 /*packets*/);
client.configuration().put(RtspClient.Configuration.DATAGRAM_SO_ENABLE_CONFIGURATION, true);
client.configuration().put(RtspClient.Configuration.DATAGRAM_SO_RCVBUF, 64 * 1024);
client.configuration().put(RtspClient.Configuration.MESSAGE_INTERCEPTOR, new MessageInterceptor());
client.connect(url);
if (presentation == null)
{
presentation = client.describe(url);
System.out.println("Presentation: " + presentation);
}
presentation = RtspClient.createPartOfPresentationVideoOnly(presentation);
final RtspPlaySession session = client.createPlaySession(presentation);
if (!RtspClient.isOK(session.setup(22222)))
{
session.setup();
}
session.play(video);
while (!disconnected)
{
try
{
Thread.sleep(100);
}
catch (Exception e) {/*ignore*/}
}
session.teardown();
}
catch (Exception e)
{
logger.log(ILogger.ERROR, "RTSP/RTP exception", e);
}
finally
{
client.close(disconnectionReason);
}
}
/**
* Stops stream playback.
*
* @param reason
*/
public void stop(final String reason)
{
disconnectionReason = reason;
disconnected = true;
}
}
/**
* <code>Video</code>
*/
private final static class Video extends AbstractVideo implements IVideo
{
// fields
private final IMediaSdk mediaSdk;
private final JVideoScreen videoScreen;
// state
private IVideoDecoder videoDecoder;
/**
* Constructor.
*
* @param mediaSdk
* @param videoScreen
*/
public Video(final IMediaSdk mediaSdk, final JVideoScreen videoScreen)
{
this.mediaSdk = mediaSdk;
this.videoScreen = videoScreen;
}
// IVideo implementation
@Override
public void onMediaData(final MediaTrackInfo track, final MediaData data)
{
System.out.println("onMediaData: " + track + " " + data);
if (track.type != MediaTrackInfo.VIDEO) return;
if (videoDecoder == null)
{
videoDecoder = mediaSdk.getMediaCodecSdk().createVideoDecoder(track.codec, track.codecConfig, null);
}
videoDecoder.decodeFrame(data.timestamp, MediaDataFactory.getMediaDataPayload(data), new IVideoDecoder.CallbackAdapter()
{
@Override
public void onDecodedFrame(final VideoFrame frame)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
videoScreen.setFrame(frame);
}
});
}
@Override
public void onException(final Object tag, final Exception e)
{
e.printStackTrace();
}
});
}
}
/**
* Constructor.
*/
private ExMediaSdkPlayRealtimeVideoOnlyRtspStream()
{
}
}