/** * 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() { } }