接收端
import java.applet.Applet; import java.awt.Button; import java.awt.Component; import java.awt.TextField; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.net.InetAddress; import javax.media.ControllerEvent; import javax.media.ControllerListener; import javax.media.Player; import javax.media.RealizeCompleteEvent; import javax.media.control.BufferControl; import javax.media.protocol.DataSource; import javax.media.rtp.Participant; import javax.media.rtp.RTPControl; import javax.media.rtp.RTPManager; import javax.media.rtp.ReceiveStream; import javax.media.rtp.ReceiveStreamListener; import javax.media.rtp.SessionAddress; import javax.media.rtp.SessionListener; import javax.media.rtp.event.ByeEvent; import javax.media.rtp.event.NewParticipantEvent; import javax.media.rtp.event.NewReceiveStreamEvent; import javax.media.rtp.event.ReceiveStreamEvent; import javax.media.rtp.event.SessionEvent; import javax.media.rtp.event.StreamMappedEvent; // 头一段时间做jmf程序,要把截获的视频流,潜入到网页中,并播放; // 在网上找了很多例子,是弹出 frame 框形式的,没有做成嵌入到 applet 里面, // 自己做了一个嵌入到 applet 里面的。也就是把播放器嵌入到 applet 里面, // 而不是弹出一个 Frame 框,并且定义了两个按钮;一个启动,一个停止;以下是源码; // 解压码是:xuedijiujiu 这是个客户端 applet 程序程序,实现视频的接受和播放; // 服务器端可以用JMStudio来辅助调试; 程序仅供研究 public class AudioVideoReceiver extends Applet implements ControllerListener, ReceiveStreamListener, SessionListener, Runnable { private static final long serialVersionUID = -5570418604643606114L; RTPManager rtpManager = null; Player player = null; boolean dataReceived = false; // 是否接收到数据的标志 Object dataSync = new Object(); // 专门用于锁的对象 Component component1; Component component2; Button btnStartVideo; Button btnStopVideo; TextField tfServerIP; public void init() { this.setLayout(null); // 添加两个按钮,并注册相应的事件! btnStartVideo = new Button("start"); btnStartVideo.setBounds(10, 350, 80, 20); btnStartVideo.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (player == null) { Thread t = new Thread(AudioVideoReceiver.this); t.start(); System.out.println("thread start"); } } }); this.add(btnStartVideo); // ----------------------------------------------------- btnStopVideo = new Button("stop"); btnStopVideo.setBounds(150, 350, 80, 20); btnStopVideo.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (player != null) { remove(component1); remove(component2); } stopVideo(); System.out.println("thread stop"); } }); this.add(btnStopVideo); this.setSize(350, 380); } protected boolean initialize() { try { rtpManager = RTPManager.newInstance(); // 为每一个RTP会话产生一个RTP管理器 rtpManager.addSessionListener(this); // 添加会话监听 rtpManager.addReceiveStreamListener(this); // 添加接收到数据的监听 // 特别注意的地方:不能将本地地址设置为“127.0.0.1”,必须要实际的ip地址!! // InetAddress ipAddress = InetAddress.getByName("224.224.123.123"); // 接收广播 InetAddress ipAddress = InetAddress.getByName("172.17.21.170"); // 接收单播 SessionAddress localAddress = null; SessionAddress targetAddress = null; // 说明:当 ip 地址为“224.224.123.123”的时候,属于组播(亦称广播,能被多个接收端接收) // 当 ip 地址为“110.52.206.144”的时候,属于单播,会自动跳到 else 分支中去!! if (ipAddress.isMulticastAddress()) { // 对于组播,本地和目的地的IP地址相同,均采用组播地址 System.out.println("is MulticastAddress()"); localAddress = new SessionAddress(ipAddress, 22222); targetAddress = new SessionAddress(ipAddress, 22222); } else { System.out.println("is Not MulticastAddress()"); localAddress = new SessionAddress(InetAddress.getLocalHost(), 8888); // 用本机IP地址和端口号构造源会话地址 targetAddress = new SessionAddress(ipAddress, 3000); // 用目的机(发送端)的IP地址和端口号构造目的会话地址 } rtpManager.initialize(localAddress); // 将本机会话地址给RTP管理器 BufferControl bc = (BufferControl)rtpManager.getControl("javax.media.control.BufferControl"); if (bc != null) { bc.setBufferLength(350); // 设置缓冲区大小(也可以使用其他值) } rtpManager.addTarget(targetAddress); // 加入目的会话地址 } catch (Exception e) { System.err.println("Cannot create the RTP Session: " + e.getMessage()); return false; } // 等待数据到达 long then = System.currentTimeMillis(); long waitingPeriod = 6000; // 最多等待60秒 try { synchronized (dataSync) { // 等待上面所设定的时间 while (!dataReceived && System.currentTimeMillis() - then < waitingPeriod) { if (!dataReceived) { System.err.println(" - Waiting for RTP data to arrive..."); } dataSync.wait(1000); } } } catch (Exception e) { e.printStackTrace(); } if (!dataReceived) { // 在设定的时间内没有等到数据 System.err.println("No RTP data was received."); player.close(); player.stop(); return false; } return true; } public void start() { if (player != null) { player.start(); } } public void stopVideo() { if (player != null) { player.close(); player = null; } if (rtpManager != null) { rtpManager.removeTargets("Closing session from RTPReceive"); rtpManager.dispose(); // 关闭RTP会话管理器 rtpManager = null; } } public void destroy() { if (player != null) { player.close(); player = null; } if (rtpManager != null) { rtpManager.removeTargets("Closing session from RTPReceive"); rtpManager.dispose(); // 关闭RTP会话管理器 rtpManager = null; } } public synchronized void controllerUpdate(ControllerEvent event) { if (event instanceof RealizeCompleteEvent) { if ((component1 = player.getVisualComponent()) != null) { this.add(component1); } component1.setBounds(10, 10, 300, 300); if ((component2 = player.getControlPanelComponent()) != null) { this.add(component2); } component2.setBounds(10, 310, 300, 20); validate(); System.out.println("palyer"); } } public synchronized void update(ReceiveStreamEvent evt) { @SuppressWarnings("unused") RTPManager mgr = (RTPManager) evt.getSource(); Participant participant = evt.getParticipant(); // 得到加入者(发送者) ReceiveStream stream = evt.getReceiveStream(); // 得到接收到的数据流 if (evt instanceof NewReceiveStreamEvent) { // 接收到新的数据流 try { stream = ((NewReceiveStreamEvent) evt).getReceiveStream(); // 得到新数据流 DataSource ds = stream.getDataSource(); // 得到数据源 RTPControl ctl = (RTPControl) ds .getControl("javax.media.rtp.RTPControl"); // 得到RTP控制器 if (ctl != null) { System.err.println("Recevied new RTP stream: " + ctl.getFormat()); // 得到接收数据的格式 } else { System.err.println("Recevied new RTP stream"); } if (participant == null) { System.err.println("The sender of this stream had yet to be identified."); } else { System.err.println("The stream comes from: " + participant.getCNAME()); } player = javax.media.Manager.createPlayer(ds); // 通过数据源构造一个媒体播放器 if (player == null) { return; } player.addControllerListener(this); // 给播放器添加控制器监听 player.realize(); synchronized (dataSync) { dataReceived = true; dataSync.notifyAll(); } } catch (Exception e) { System.err.println("NewReceiveStreamEvent exception" + e.getMessage()); return; } } else if (evt instanceof StreamMappedEvent) { // 数据流映射事件 if (stream != null && stream.getDataSource() != null) { DataSource ds = stream.getDataSource(); RTPControl ctl = (RTPControl)ds.getControl("javax.media.rtp.RTPControl"); System.err.println(" - The previously unidentified stream "); if (ctl != null) { System.err.println(" " + ctl.getFormat()); // 得到格式 } System.err.println(" had now been identified as sent by: " + participant.getCNAME()); } } else if (evt instanceof ByeEvent) { // 数据接收完毕 System.err.println(" - Got /'bye/' from: " + participant.getCNAME()); if (player != null) { player.close(); // 关闭播放窗口 } } } public synchronized void update(SessionEvent evt) { if (evt instanceof NewParticipantEvent) { Participant p = ((NewParticipantEvent) evt).getParticipant(); System.err.println(" - A new participant had just joined: " + p.getCNAME()); } } public void run() { this.initialize(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } player.start(); } }
import javax.media.rtp.*; import javax.media.*; import javax.media.protocol.*; import javax.media.control.FormatControl; import javax.media.control.TrackControl; import javax.media.format.*; import java.io.IOException; import java.net.InetAddress; import java.util.*; // 很漂亮的一个音视频信号发送端的程序!接收端可用JMStudio来代替(Open RTP Session选项)! public class AudioVideoSender { private CaptureDeviceInfo captureVideoDevice = null; private CaptureDeviceInfo captureAudioDevice = null; private DataSource videoDataSource = null; private DataSource audioDataSource = null; private Processor videoProcessor = null; private Processor audioProcessor = null; private RTPManager videortpManager = null; private RTPManager audiortpManager = null; private SendStream videoRtpstream = null; private SendStream audioRtpstream = null; private SessionAddress remoteAddress1 = null; private SessionAddress remoteAddress2 = null; @SuppressWarnings({ "unused", "unchecked" }) private Vector sendplayerlist = new Vector(); @SuppressWarnings("unused") private boolean terminatedbyClose_sender = false; // 以下两个在配置数据源的时候要用到! private DataSource ds = null; private TrackControl[] track = null; // 该方法用于获取 "视频" 和 "音频" 捕获设备的 CaptureDeviceInfo 信息对象! private void getDeviceInfo() { // ①获取视频捕获设备的 CaptureDeviceInfo 对象! Vector<?> deviceList = null; deviceList = CaptureDeviceManager.getDeviceList(null); for (int i = 0; i < deviceList.size(); i++) { captureVideoDevice = (CaptureDeviceInfo) deviceList.elementAt(i); String name = captureVideoDevice.getName(); if (name.startsWith("vfw:")) { break; } } // ②获取音频捕获设备的 CaptureDeviceInfo 对象! deviceList = null; // 清空 deviceList deviceList = CaptureDeviceManager.getDeviceList(new AudioFormat("linear", 8000, 8, 1)); if (deviceList.size() > 0) { captureAudioDevice = (CaptureDeviceInfo) deviceList.elementAt(0); } else { // 如果找不到支持linear, 8000 Hz, 8 bit, stereo audio这些条件的音频设备的话就退出! System.err.println("Device initializing failure!"); System.exit(-1); } } // 为视频捕获设备创建一个视频处理器,如果不能创建的话就退出 private void setVideoDataSource() throws Exception { ds = Manager.createDataSource(captureVideoDevice.getLocator()); videoProcessor = Manager.createProcessor(ds); videoProcessor.configure(); // 阻塞在这里直到配置完成 while (true) { if (videoProcessor.getState() == Processor.Configured) { break; } } videoProcessor.setContentDescriptor(new ContentDescriptor(ContentDescriptor.RAW)); track = videoProcessor.getTrackControls(); //getTrackControls() 方法的返回值类型: TrackControl[] boolean encodingOk = false; // 将 track 设置成我们想要的 track,不想要的 track 统统 disable 掉! for (int i = 0; i < track.length; i++) { if (!encodingOk && track[i] instanceof FormatControl) { if (((FormatControl) track[i]).setFormat(new VideoFormat( VideoFormat.JPEG_RTP)) == null) { track[i].setEnabled(false); // 将不可用的(除VideoFormat.JPEG_RTP以外的)磁道全部设为不可用! } else { encodingOk = true; } } else { // 我们不能将磁道设置为 .GSM 格式,因此 disable 它! track[i].setEnabled(false); } } videoProcessor.realize(); // 阻塞直到完成视频处理器的实现! while (true) { if (videoProcessor.getState() == Processor.Realized) { break; } } try { videoDataSource = videoProcessor.getDataOutput(); } catch (NotRealizedError e) { System.exit(-1); // 不能成功配置视频数据源的话下面肯定进行不下去,直接退出 } System.out.println("videoDataSource is ready!"); } // 为音频捕获设备创建一个音频处理器,如果不能创建就退出程序 private void setAudioDataSource() throws Exception { ds = Manager.createDataSource(captureAudioDevice.getLocator()); audioProcessor = Manager.createProcessor(ds); audioProcessor.configure(); // 阻塞直到完成音频处理器的配置! while (true) { if (audioProcessor.getState() == Processor.Configured) { break; } } audioProcessor.setContentDescriptor(new ContentDescriptor(ContentDescriptor.RAW)); track = audioProcessor.getTrackControls(); boolean encodingOk = false; for (int i = 0; i < track.length; i++) { if (!encodingOk && (track[i] instanceof FormatControl)) { if (((FormatControl) track[i]).setFormat(new AudioFormat( AudioFormat.ULAW_RTP, 8000, 8, 1)) == null) { track[i].setEnabled(false); } else { encodingOk = true; } } else { track[i].setEnabled(false); } } audioProcessor.realize(); while (true) { if (audioProcessor.getState() == Processor.Realized) { break; } } try { audioDataSource = audioProcessor.getDataOutput(); } catch (NotRealizedError e) { System.exit(-1); } System.out.println("audioDataSource is ready!"); } // 开始传送视频和音频数据! public void transmitStart(String targetAddress, String targetPort) { videortpManager = RTPManager.newInstance(); audiortpManager = RTPManager.newInstance(); SessionAddress localAddress1 = null; SessionAddress localAddress2 = null; // create the local endpoint for the local interface on any local port localAddress1 = new SessionAddress(); localAddress2 = new SessionAddress(); try { videortpManager.initialize(localAddress1); audiortpManager.initialize(localAddress2); } catch (Exception e) { e.printStackTrace(); } // specify the remote endpoint of this unicast session try { InetAddress ipAddress = InetAddress.getByName(targetAddress); remoteAddress1 = new SessionAddress(ipAddress, Integer.parseInt(targetPort)); videortpManager.addTarget(remoteAddress1); remoteAddress2 = new SessionAddress(ipAddress, Integer.parseInt(targetPort) + 2); audiortpManager.addTarget(remoteAddress2); System.out.println(); System.out.println("data address " + localAddress1.getDataAddress()); System.out.println("contorl address " + localAddress1.getControlAddress()); System.out.println("data port " + localAddress1.getDataPort()); System.out.println("control port " + localAddress1.getControlPort()); System.out.println(); System.out.println("data address " + localAddress2.getDataAddress()); System.out.println("contorl address " + localAddress2.getControlAddress()); System.out.println("data port " + localAddress2.getDataPort()); System.out.println("control port " + localAddress2.getControlPort()); System.out.println(); videoRtpstream = videortpManager.createSendStream(videoDataSource, 0); audioRtpstream = audiortpManager.createSendStream(audioDataSource, 0); videoProcessor.start(); audioProcessor.start(); videoRtpstream.start(); audioRtpstream.start(); } catch (Exception e) { e.printStackTrace(); } } // 停止传送视频和音频数据! public void transmitStop() throws IOException, InvalidSessionAddressException { videoRtpstream.stop(); videoRtpstream.close(); videoProcessor.stop(); audioRtpstream.stop(); audioRtpstream.close(); audioProcessor.close(); // close the connection if no longer needed. videortpManager.removeTarget(remoteAddress1, "client disconnected."); audiortpManager.removeTarget(remoteAddress2, "client disconnected."); // call dispose at the end of the life-cycle of this RTPManager so // it is prepared to be garbage-collected. videortpManager.dispose(); audiortpManager.dispose(); System.out.println("Now releasing the resource!"); videoProcessor.deallocate(); audioProcessor.deallocate(); videoDataSource.disconnect(); audioDataSource.disconnect(); } public AudioVideoSender() throws Exception { // 初始化音视频捕获设备并为传输做好准备 this.getDeviceInfo(); this.setVideoDataSource(); this.setAudioDataSource(); } public static void main(String[] args) { try { AudioVideoSender tc = new AudioVideoSender(); tc.transmitStart("172.17.21.152", "8888"); } catch(Exception e) { e.printStackTrace(); } } }