📄 videotransmitnat.java
字号:
/*
* 程序员杨龙:本视频会议服务器端代码:根据自己定义的协议:能构穿透nat 需要java jmf框架
* 我开放源代码是为了更好的让java这门程序艺术更好的发展:您可以研究代码,您可以自己使用
* 但是不要使用在商业用途上 让我们更好的把开源事业在中国做下去
* 2008年 3月 杨龙 完成服务器端的框架
* 信箱 :y_flash@163.com
* QQ:274797328
* www.0351soft.com www.lx08.com
*/
package ytp.javaserver.server;
/**
*
* @author Administrator
*/
import java.io.*;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.SocketException;
import javax.media.*;
import javax.media.protocol.*;
import javax.media.protocol.DataSource;
import javax.media.format.*;
import javax.media.control.TrackControl;
import javax.media.rtp.*;
import javax.media.rtp.rtcp.*;
public class VideoTransmitNat {
// Input MediaLocator
// Can be a file or http or capture source
private MediaLocator locator;
private String ipAddress;
private String port;
private String ipData;
private String portData;
private String ipCon;
private String portCon;
private Processor processor = null;
private Processor proCone = null;
private DataSink rtptransmitter = null;
private DataSource dataOutput = null;
private int portBase;
private RTPManager rtpMgrs[];
public VideoTransmitNat(MediaLocator locator,
String ipAddressData,
String portData,
String ipCon,
String portCon,
Format format) {
this.locator = locator;
this.ipAddress = ipAddress;
this.port = port;
this.ipData = ipAddressData;
this.ipCon = ipCon;
this.portData = portData;
this.portCon = portCon;
}
/**
* Starts the transmission. Returns null if transmission started ok.
* Otherwise it returns a string with the reason why the setup failed.
*/
public synchronized String start() {
String result;
// Create a processor for the specified media locator
// and program it to output JPEG/RTP
result = createProcessor();
if (result != null)
return result;
// Create an RTP session to transmit the output of the
// processor to the specified IP address and port no.
result = createTransmitter();
if (result != null) {
processor.close();
processor = null;
return result;
}
// Start the transmission
processor.start();
return null;
}
/**
* Stops the transmission if already started
*/
public void stop() {
synchronized (this) {
if (processor != null) {
processor.stop();
processor.close();
processor = null;
for (int i = 0; i < rtpMgrs.length; i++) {
rtpMgrs[i].removeTargets( "Session ended.");
rtpMgrs[i].dispose();
}
}
}
}
private String createProcessor() {
if (locator == null)
return "Locator is null";
DataSource ds;
DataSource clone;
try {
ds = javax.media.Manager.createDataSource(locator);
} catch (Exception e) {
return "Couldn't create DataSource";
}
// Try to create a processor to handle the input media locator
try {
processor = javax.media.Manager.createProcessor(ds);
} catch (NoProcessorException npe) {
return "Couldn't create processor";
} catch (IOException ioe) {
return "IOException creating processor";
}
// Wait for it to configure
boolean result = waitForState(processor, Processor.Configured);
if (result == false)
return "Couldn't configure processor";
// Get the tracks from the processor
TrackControl [] tracks = processor.getTrackControls();
// Do we have atleast one track?
if (tracks == null || tracks.length < 1)
return "Couldn't find tracks in processor";
// Set the output content descriptor to RAW_RTP
// This will limit the supported formats reported from
// Track.getSupportedFormats to only valid RTP formats.
ContentDescriptor cd = new ContentDescriptor(ContentDescriptor.RAW_RTP);
processor.setContentDescriptor(cd);
Format supported[];
Format chosen;
boolean atLeastOneTrack = false;
// Program the tracks.
for (int i = 0; i < tracks.length; i++) {
Format format = tracks[i].getFormat();
if (tracks[i].isEnabled()) {
supported = tracks[i].getSupportedFormats();
// We've set the output content to the RAW_RTP.
// So all the supported formats should work with RTP.
// We'll just pick the first one.
if (supported.length > 0) {
if (supported[0] instanceof AudioFormat) {
// For video formats, we should double check the
// sizes since not all formats work in all sizes.
chosen = tracks[i].getFormat();
} else
chosen = supported[0];
tracks[i].setFormat(chosen);
System.err.println("Track " + i + " is set to transmit as:");
System.err.println(" " + chosen);
atLeastOneTrack = true;
} else
tracks[i].setEnabled(false);
} else
tracks[i].setEnabled(false);
}
if (!atLeastOneTrack)
return "Couldn't set any of the tracks to a valid RTP format";
// Realize the processor. This will internally create a flow
// graph and attempt to create an output datasource for JPEG/RTP
// audio frames.
result = waitForState(processor, Controller.Realized);
if (result == false)
return "Couldn't realize processor";
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//++ Set the JPEG quality to .5.
//++ setJPEGQuality(processor, 0.5f);
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Get the output data source of the processor
dataOutput = processor.getDataOutput();
return null;
}
/**
* Use the RTPManager API to create sessions for each media
* track of the processor.
*/
private String createTransmitter() {
// Cheated. Should have checked the type.
PushBufferDataSource pbds = (PushBufferDataSource)dataOutput;
PushBufferStream pbss[] = pbds.getStreams();
rtpMgrs = new RTPManager[pbss.length];
SendStream sendStream;
int port;
SourceDescription srcDesList[];
for (int i = 0; i < pbss.length; i++) {
try {
rtpMgrs[i] = RTPManager.newInstance();
port = portBase + 2*i;
// Initialize the RTPManager with the RTPSocketAdapter
SessionAddress romoto = new SessionAddress();
romoto.setDataHostAddress(InetAddress.getByName(this.ipData));
romoto.setDataPort(Integer.parseInt(this.portData));
romoto.setControlHostAddress(InetAddress.getByName(this.ipData));
romoto.setControlPort(Integer.parseInt(this.portCon));
SessionAddress local = new SessionAddress(InetAddress.getLocalHost(),port);
rtpMgrs[i].initialize(local);
rtpMgrs[i].addTarget(romoto);
//这个地方应该加入远程地址的Inetaddress
System.err.println( "Created RTP session: " + ipAddress + " " + port);
sendStream = rtpMgrs[i].createSendStream(dataOutput, i);
sendStream.start();
} catch (Exception e) {
return e.getMessage();
}
}
return null;
}
/****************************************************************
* Convenience methods to handle processor's state changes.
****************************************************************/
private Integer stateLock = new Integer(0);
private boolean failed = false;
Integer getStateLock() {
return stateLock;
}
void setFailed() {
failed = true;
}
private synchronized boolean waitForState(Processor p, int state) {
p.addControllerListener(new StateListener());
failed = false;
// Call the required method on the processor
if (state == Processor.Configured) {
p.configure();
} else if (state == Processor.Realized) {
p.realize();
}
// Wait until we get an event that confirms the
// success of the method, or a failure event.
// See StateListener inner class
while (p.getState() < state && !failed) {
synchronized (getStateLock()) {
try {
getStateLock().wait();
} catch (InterruptedException ie) {
return false;
}
}
}
if (failed)
return false;
else
return true;
}
/****************************************************************
* Inner Classes
****************************************************************/
class StateListener implements ControllerListener {
public void controllerUpdate(ControllerEvent ce) {
// If there was an error during configure or
// realize, the processor will be closed
if (ce instanceof ControllerClosedEvent)
setFailed();
// All controller events, send a notification
// to the waiting thread in waitForState method.
if (ce instanceof ControllerEvent) {
synchronized (getStateLock()) {
getStateLock().notifyAll();
}
}
}
}
/****************************************************************
* Sample Usage for AVTransmit3 class
****************************************************************/
public static void main(String [] args) {
// We need three parameters to do the transmission
// For example,
// java AVTransmit3 file:/C:/media/test.mov 129.130.131.132 42050
/* if (args.length < 3) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -