接收端
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();
}
}
}