JMF视频音频通信( 图+源码 )
最近由于做山寨QQ视频聊天的需要,做了一个视频通信窗口组件。现在分享一下供大家学习……
原创文章,转载请标明出处!谢谢!
工程文件下载地址:http://download.****.net/source/3378150
本文地址: http://mzhx-com.iteye.com/blog/1098698
效果图如下:
三个类 源代码如下:
package vidioPlay;
import java.awt.Dimension;
import java.io.IOException;
import java.net.InetAddress;
import java.util.Vector;
import javax.media.CaptureDeviceInfo;
import javax.media.Codec;
import javax.media.Control;
import javax.media.Controller;
import javax.media.ControllerClosedEvent;
import javax.media.ControllerEvent;
import javax.media.ControllerListener;
import javax.media.Format;
import javax.media.IncompatibleSourceException;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.NoProcessorException;
import javax.media.Owned;
import javax.media.Player;
import javax.media.Processor;
import javax.media.cdm.CaptureDeviceManager;
import javax.media.control.QualityControl;
import javax.media.control.TrackControl;
import javax.media.format.AudioFormat;
import javax.media.format.VideoFormat;
import javax.media.protocol.ContentDescriptor;
import javax.media.protocol.DataSource;
import javax.media.protocol.PushBufferDataSource;
import javax.media.protocol.PushBufferStream;
import javax.media.protocol.SourceCloneable;
import javax.media.rtp.RTPManager;
import javax.media.rtp.SendStream;
import javax.media.rtp.SessionAddress;
import javax.media.rtp.rtcp.SourceDescription;
import javax.swing.JFrame;
public class MediaTransmit {
private String ipAddress;
private int portBase;
private MediaLocator audioLocator = null, vedioLocator = null;
private Processor audioProcessor = null;
private Processor videoProcessor = null;
private DataSource audioDataLocal = null, videoDataLocal = null;
private DataSource audioDataOutput = null, videoDataOutput = null;
private RTPManager rtpMgrs[];
private DataSource mediaData = null;
private DataSource dataLocalClone = null;
private PlayPane playFrame;
public MediaTransmit(String ipAddress, String pb) {
this.ipAddress = ipAddress;
Integer integer = Integer.valueOf(pb);
if (integer != null) {
this.portBase = integer.intValue();
}
// /////////////////////////////////////////////
playFrame = new PlayPane();
JFrame jf = new JFrame("视频实例");
jf.add(playFrame);
jf.pack();
jf.setLocationRelativeTo(null);
jf.setDefaultCloseOperation(3);
jf.setVisible(true);
// ////////////////////////////////////////////
Vector<CaptureDeviceInfo> video = CaptureDeviceManager
.getDeviceList(new VideoFormat(null));
Vector<CaptureDeviceInfo> audio = CaptureDeviceManager
.getDeviceList(new AudioFormat(AudioFormat.LINEAR, 44100, 16, 2));
// MediaLocator mediaLocator = new
// MediaLocator("file:/C:/纯音乐 - 忧伤还是快乐.mp3");
if (audio != null && audio.size() > 0) {
audioLocator = ((CaptureDeviceInfo) audio.get(0)).getLocator();
if ((audioProcessor = createProcessor(audioLocator)) != null) {
audioDataLocal = mediaData;
audioDataOutput = audioProcessor.getDataOutput();
}
} else {
System.out.println("******错误:没有检测到您的音频采集设备!!!");
}
// /////////////////////////////////////////////////////////
if (video != null && video.size() > 0) {
vedioLocator = ((CaptureDeviceInfo) video.get(0)).getLocator();
if ((videoProcessor = createProcessor(vedioLocator)) != null) {
videoDataLocal = mediaData;
videoDataOutput = videoProcessor.getDataOutput();
}
} else {
System.out.println("******错误:没有检测到您的视频设备!!!");
}
// /////////////////////////////////////////////////////////
final DataSource[] dataSources = new DataSource[2];
dataSources[0] = audioDataLocal;
dataSources[1] = videoDataLocal;
try {
DataSource dsLocal = Manager.createMergingDataSource(dataSources);
playFrame.localPlay(dsLocal);
} catch (IncompatibleSourceException e) {
e.printStackTrace();
return;
}
// ////////////////////////////////////////////////远程传输
dataSources[1] = audioDataOutput;
dataSources[0] = videoDataOutput;
try {
DataSource dsoutput = Manager.createMergingDataSource(dataSources);
createTransmitter(dsoutput);
} catch (IncompatibleSourceException e) {
e.printStackTrace();
return;
}
audioProcessor.start();
videoProcessor.start();
}
private Processor createProcessor(MediaLocator locator) {
Processor processor = null;
if (locator == null)
return null;
// 通过设备定位器得到数据源,
try {
mediaData = Manager.createDataSource(locator);
// 创建可克隆数据源
mediaData = Manager.createCloneableDataSource(mediaData);
// 克隆数据源,用于传输到远程
dataLocalClone = ((SourceCloneable) mediaData).createClone();
} catch (Exception e) {
e.printStackTrace();
return null;
}
try {
processor = javax.media.Manager.createProcessor(dataLocalClone);
} catch (NoProcessorException npe) {
npe.printStackTrace();
return null;
} catch (IOException ioe) {
return null;
}
boolean result = waitForState(processor, Processor.Configured);
if (result == false)
return null;
TrackControl[] tracks = processor.getTrackControls();
if (tracks == null || tracks.length < 1)
return null;
ContentDescriptor cd = new ContentDescriptor(ContentDescriptor.RAW_RTP);
processor.setContentDescriptor(cd);
Format supportedFormats[];
Format chosen;
boolean atLeastOneTrack = false;
for (int i = 0; i < tracks.length; i++) {
if (tracks[i].isEnabled()) {
supportedFormats = tracks[i].getSupportedFormats();
if (supportedFormats.length > 0) {
if (supportedFormats[0] instanceof VideoFormat) {
chosen = checkForVideoSizes(tracks[i].getFormat(),
supportedFormats[0]);
} else
chosen = supportedFormats[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 null;
result = waitForState(processor, Controller.Realized);
if (result == false)
return null;
setJPEGQuality(processor, 0.5f);
return processor;
}
private String createTransmitter(DataSource dataOutput) {
PushBufferDataSource pbds = (PushBufferDataSource) dataOutput;
PushBufferStream pbss[] = pbds.getStreams();
System.out.println("pbss.length:" + pbss.length);
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;
SessionAddress localAddr = new SessionAddress(
InetAddress.getLocalHost(), port);
SessionAddress destAddr = new SessionAddress(
InetAddress.getByName(ipAddress), port);
rtpMgrs[i].initialize(localAddr);
rtpMgrs[i].addTarget(destAddr);
System.out.println("Created RTP session: "
+ InetAddress.getLocalHost() + " " + port);
sendStream = rtpMgrs[i].createSendStream(dataOutput, i);
sendStream.start();
} catch (Exception e) {
e.printStackTrace();
return e.getMessage();
}
}
return null;
}
Format checkForVideoSizes(Format original, Format supported) {
int width, height;
Dimension size = ((VideoFormat) original).getSize();
Format jpegFmt = new Format(VideoFormat.JPEG_RTP);
Format h263Fmt = new Format(VideoFormat.H263_RTP);
if (supported.matches(jpegFmt)) {
width = (size.width % 8 == 0 ? size.width
: (int) (size.width / 8) * 8);
height = (size.height % 8 == 0 ? size.height
: (int) (size.height / 8) * 8);
} else if (supported.matches(h263Fmt)) {
if (size.width < 128) {
width = 128;
height = 96;
} else if (size.width < 176) {
width = 176;
height = 144;
} else {
width = 352;
height = 288;
}
} else {
return supported;
}
return (new VideoFormat(null, new Dimension(width, height),
Format.NOT_SPECIFIED, null, Format.NOT_SPECIFIED))
.intersects(supported);
}
void setJPEGQuality(Player p, float val) {
Control cs[] = p.getControls();
QualityControl qc = null;
VideoFormat jpegFmt = new VideoFormat(VideoFormat.JPEG);
for (int i = 0; i < cs.length; i++) {
if (cs[i] instanceof QualityControl && cs[i] instanceof Owned) {
Object owner = ((Owned) cs[i]).getOwner();
if (owner instanceof Codec) {
Format fmts[] = ((Codec) owner)
.getSupportedOutputFormats(null);
for (int j = 0; j < fmts.length; j++) {
if (fmts[j].matches(jpegFmt)) {
qc = (QualityControl) cs[i];
qc.setQuality(val);
System.err.println("- Setting quality to " + val
+ " on " + qc);
break;
}
}
}
if (qc != null)
break;
}
}
}
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;
if (state == Processor.Configured) {
p.configure();
} else if (state == Processor.Realized) {
p.realize();
}
while (p.getState() < state && !failed) {
synchronized (getStateLock()) {
try {
getStateLock().wait();
} catch (InterruptedException ie) {
return false;
}
}
}
if (failed)
return false;
else
return true;
}
class StateListener implements ControllerListener {
public void controllerUpdate(ControllerEvent ce) {
if (ce instanceof ControllerClosedEvent)
setFailed();
if (ce instanceof ControllerEvent) {
synchronized (getStateLock()) {
getStateLock().notifyAll();
}
}
}
}
public static void main(String[] args) {
String[] strs = { "localhost", "9994" };
new MediaTransmit(strs[0], strs[1]);
}
}
package vidioPlay;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Panel;
import java.net.InetAddress;
import java.util.Vector;
import javax.media.ControllerErrorEvent;
import javax.media.ControllerEvent;
import javax.media.ControllerListener;
import javax.media.Player;
import javax.media.RealizeCompleteEvent;
import javax.media.bean.playerbean.MediaPlayer;
import javax.media.control.BufferControl;
import javax.media.format.FormatChangeEvent;
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.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.RemotePayloadChangeEvent;
import javax.media.rtp.event.SessionEvent;
import javax.media.rtp.event.StreamMappedEvent;
import javax.swing.JFrame;
import net.sf.fmj.media.rtp.RTPSocketAdapter;
public class MediaReceive implements ReceiveStreamListener, SessionListener,
ControllerListener {
String sessions[] = null;
RTPManager mgrs[] = null;
boolean dataReceived = false;
Object dataSync = new Object();
private PlayPane playFrame;
public MediaReceive(String sessions[]) {
this.sessions = sessions;
}
protected void initialize() {
playFrame = new PlayPane();
JFrame jf = new JFrame("视频实例");
jf.add(playFrame);
jf.pack();
jf.setLocationRelativeTo(null);
jf.setDefaultCloseOperation(3);
jf.setVisible(true);
try {
// 每一个session对应一个RTPManager
mgrs = new RTPManager[sessions.length];
// 创建播放窗口的向量vector
SessionLabel session = null;
// Open the RTP sessions.
// 针对每一个会话对象进行ip、port和ttl的解析
for (int i = 0; i < sessions.length; i++) {
// Parse the session addresses.
// 进行会话对象的解析,得到ip、port和ttl
try {
session = new SessionLabel(sessions[i]);
} catch (IllegalArgumentException e) {
System.err
.println("Failed to parse the session address given: "
+ sessions[i]);
// return false;
}
System.err.println(" - Open RTP session for: addr: "
+ session.addr + " port: " + session.port + " ttl: "
+ session.ttl);
// 这对本条会话对象创建RTPManager
mgrs[i] = (RTPManager) RTPManager.newInstance();
mgrs[i].addSessionListener(this);
mgrs[i].addReceiveStreamListener(this);
// Initialize the RTPManager with the RTPSocketAdapter
// 将本机ip和端口号加入RTP会话管理
System.out.println("session.addr:" + session.addr);
mgrs[i].initialize(new RTPSocketAdapter(InetAddress
.getByName(session.addr), session.port, session.ttl));
BufferControl bc = (BufferControl) mgrs[i]
.getControl("javax.media.control.BufferControl");
if (bc != null)
bc.setBufferLength(350);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Close the players and the session managers.
*/
protected void close() {
// close the RTP session.
for (int i = 0; i < mgrs.length; i++) {
if (mgrs[i] != null) {
mgrs[i].removeTargets("Closing session from AVReceive3");
mgrs[i].dispose();
mgrs[i] = null;
}
}
}
/**
* SessionListener.
*/
@SuppressWarnings("deprecation")
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);
}
}
/**
* ReceiveStreamListener
*/
public synchronized void update(ReceiveStreamEvent evt) {
RTPManager mgr = (RTPManager) evt.getSource();
Participant participant = evt.getParticipant(); // could be null.
ReceiveStream stream = evt.getReceiveStream(); // could be null.
if (evt instanceof RemotePayloadChangeEvent) {
System.err.println(" - Received an RTP PayloadChangeEvent.");
System.err.println("Sorry, cannot handle payload change.");
// System.exit(0);
}
else if (evt instanceof NewReceiveStreamEvent) {
System.out.println("evt instanceof NewReceiveStreamEvent");
try {
stream = ((NewReceiveStreamEvent) evt).getReceiveStream();
final DataSource data = stream.getDataSource();
// Find out the formats.
RTPControl ctl = (RTPControl) data
.getControl("javax.media.rtp.RTPControl");
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());
}
// create a player by passing datasource to the Media Manager
new Thread() {
public void run() {
playFrame.remotePlay(data);
}
}.start();
// Player p = javax.media.Manager.createPlayer(data);
// if (p == null)
// return;
//
// p.addControllerListener(this);
// p.realize();
// PlayerWindow pw = new PlayerWindow(p, stream);
// playerWindows.addElement(pw);
// Notify intialize() that a new stream had arrived.
synchronized (dataSync) {
dataReceived = true;
dataSync.notifyAll();
}
} catch (Exception e) {
System.err.println("NewReceiveStreamEvent exception "
+ e.getMessage());
return;
}
}
else if (evt instanceof StreamMappedEvent) {
System.out.println("evt instanceof StreamMappedEvent");
stream = ((StreamMappedEvent) evt).getReceiveStream();
if (stream != null && stream.getDataSource() != null) {
DataSource ds = stream.getDataSource();
// Find out the formats.
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());
System.out.println("ds == null" + (ds == null));
}
}
else if (evt instanceof ByeEvent) {
System.err.println(" - Got \"bye\" from: "
+ participant.getCNAME());
}
}
/**
* ControllerListener for the Players.
*/
public synchronized void controllerUpdate(ControllerEvent ce) {
Player p = (Player) ce.getSourceController();
if (p == null)
return;
}
/**
* A utility class to parse the session addresses.
*/
class SessionLabel {
public String addr = null;
public int port;
public int ttl = 1;
SessionLabel(String session) throws IllegalArgumentException {
int off;
String portStr = null, ttlStr = null;
if (session != null && session.length() > 0) {
while (session.length() > 1 && session.charAt(0) == '/') {
session = session.substring(1);
}
off = session.indexOf('/');
if (off == -1) {
if (!session.equals(""))
addr = session;
} else {
addr = session.substring(0, off);
session = session.substring(off + 1);
off = session.indexOf('/');
if (off == -1) {
if (!session.equals(""))
portStr = session;
} else {
portStr = session.substring(0, off);
session = session.substring(off + 1);
off = session.indexOf('/');
if (off == -1) {
if (!session.equals(""))
ttlStr = session;
} else {
ttlStr = session.substring(0, off);
}
}
}
}
if (addr == null)
throw new IllegalArgumentException();
if (portStr != null) {
try {
Integer integer = Integer.valueOf(portStr);
if (integer != null)
port = integer.intValue();
} catch (Throwable t) {
throw new IllegalArgumentException();
}
} else
throw new IllegalArgumentException();
if (ttlStr != null) {
try {
Integer integer = Integer.valueOf(ttlStr);
if (integer != null)
ttl = integer.intValue();
} catch (Throwable t) {
throw new IllegalArgumentException();
}
}
}
}
public static void main(String argv[]) {
String[] strs = { "125.221.165.126/9994", "125.221.165.126/9996" };
MediaReceive avReceive = new MediaReceive(strs);
avReceive.initialize();
}
}
package vidioPlay;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import javax.media.ControllerEvent;
import javax.media.ControllerListener;
import javax.media.DataSink;
import javax.media.NoPlayerException;
import javax.media.Player;
import javax.media.Processor;
import javax.media.protocol.DataSource;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JPanel;
public class PlayPane extends JPanel {
private ImageIcon videoReqIcon = new ImageIcon("videoReq.jpg");
private ImageIcon VideolocalIcon = new ImageIcon("localVideo.jpg");
private boolean isViewBigPlaying = false;
private boolean isViewSmallPlaying = false;
private JPanel viewBigPane;
private JPanel viewSmallPane;
private JPanel controlPane;
private JButton closeButton;
private boolean localPlay = false;
private boolean remotePlay = false;
private DataSource localData;
private DataSource remoteData;
private boolean isViewRun = true;
private boolean isShow = true;
//
private Player localPlayer = null;
private Player remotePlayer = null;
//
private Processor videotapeProcessor = null;
private Player videotapePlayer = null;
private DataSink videotapeFileWriter;
public PlayPane() {
this.setLayout(new BorderLayout());
// 视图面板
viewBigPane = new JPanel() {
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (!isViewBigPlaying) {
g.drawImage(videoReqIcon.getImage(), 1, 1,
videoReqIcon.getIconWidth(),
videoReqIcon.getIconHeight(), null);
g.drawRect(getSmallPlayRec().x - 1,
getSmallPlayRec().y - 1,
getSmallPlayRec().width + 1,
getSmallPlayRec().height + 1);
} else {
}
}
};
viewBigPane.setBackground(Color.black);
this.add(viewBigPane, BorderLayout.CENTER);
viewBigPane.setLayout(null);
// ///////////////////////////////
viewSmallPane = new JPanel() {
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (!isViewSmallPlaying) {
g.drawImage(VideolocalIcon.getImage(), 0, 0, null);
} else {
}
}
};
viewSmallPane.setBounds(getSmallPlayRec());
viewBigPane.add(viewSmallPane);
viewSmallPane.setLayout(null);
// 控制面板组件
closeButton = new JButton("挂断");
controlPane = new JPanel();
controlPane.setLayout(new FlowLayout(FlowLayout.RIGHT, 0, 0));
controlPane.add(closeButton);
this.add(controlPane, BorderLayout.SOUTH);
closeButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (localPlayer != null) {
localPlayer.stop();
}
if (remotePlayer != null) {
remotePlayer.stop();
}
if (videotapePlayer != null) {
videotapePlayer.stop();
}
if (videotapeProcessor != null) {
videotapeProcessor.stop();
}
if (videotapeFileWriter != null) {
try {
videotapeFileWriter.stop();
videotapeFileWriter.close();
} catch (IOException e1) {
}
}
}
});
// this.setMinimumSize(new Dimension(videoReqIcon.getIconWidth()+2,
// 241));
// this.setPreferredSize(new Dimension(videoReqIcon.getIconWidth()+2,
// 241));
}
public Dimension getMinimumSize() {
System.out
.println("controlPane.getHeight():" + controlPane.getHeight());
return new Dimension(videoReqIcon.getIconWidth() + 2,
videoReqIcon.getIconHeight() + controlPane.getHeight());
}
public Dimension getPreferredSize() {
System.out
.println("controlPane.getHeight():" + controlPane.getHeight());
return new Dimension(videoReqIcon.getIconWidth() + 2,
videoReqIcon.getIconHeight()
+ controlPane.getPreferredSize().height);
}
public void localPlay(DataSource dataSource) {
this.setLocalData(dataSource);
try {
localPlayer = javax.media.Manager.createPlayer(dataSource);
localPlayer.addControllerListener(new ControllerListener() {
public void controllerUpdate(ControllerEvent e) {
if (e instanceof javax.media.RealizeCompleteEvent) {
Component comp = null;
comp = localPlayer.getVisualComponent();
if (comp != null) {
// 将可视容器加到窗体上
comp.setBounds(0, 0, VideolocalIcon.getIconWidth(),
VideolocalIcon.getIconHeight());
viewSmallPane.add(comp);
}
viewBigPane.validate();
}
}
});
localPlayer.start();
localPlay = true;
} catch (NoPlayerException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
private Rectangle getSmallPlayRec() {
int bigShowWidth = videoReqIcon.getIconWidth();
int bigShowHeight = videoReqIcon.getIconHeight();
int smallShowWidth = VideolocalIcon.getIconWidth();
int smallShowHeight = VideolocalIcon.getIconHeight();
return new Rectangle(bigShowWidth - smallShowWidth - 2, bigShowHeight
- smallShowHeight - 2, smallShowWidth, smallShowHeight);
}
public void remotePlay(DataSource dataSource) {
this.setLocalData(dataSource);
remotePlay = true;
try {
remotePlayer = javax.media.Manager.createPlayer(dataSource);
remotePlayer.addControllerListener(new ControllerListener() {
public void controllerUpdate(ControllerEvent e) {
if (e instanceof javax.media.RealizeCompleteEvent) {
Component comp;
if ((comp = remotePlayer.getVisualComponent()) != null) {
// 将可视容器加到窗体上
comp.setBounds(1, 1, videoReqIcon.getIconWidth(),
videoReqIcon.getIconHeight());
viewBigPane.add(comp);
}
viewBigPane.validate();
}
}
});
remotePlayer.start();
remotePlay = true;
} catch (NoPlayerException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
public void closeViewUI() {
isShow = false;
}
public boolean isViewRunning() {
return isViewRun;
}
public boolean isShowing() {
return isShow;
}
public void localReady() {
localPlay = true;
}
public void remoteReady() {
remotePlay = true;
}
public boolean isRemotePlay() {
return remotePlay;
}
public void setRemotePlay(boolean remotePlay) {
this.remotePlay = remotePlay;
}
public DataSource getRemoteData() {
return remoteData;
}
public void setRemoteData(DataSource remoteData) {
this.remoteData = remoteData;
}
public boolean isLocalPlay() {
return localPlay;
}
public void setLocalPlay(boolean localPlay) {
this.localPlay = localPlay;
}
public DataSource getLocalData() {
return localData;
}
public void setLocalData(DataSource localData) {
this.localData = localData;
}
}
之后操作如下:
1、安装JMF软件(如果不想安装,就请阅读我转载一篇文章):
2、新建工程将源代码加入工程src下
3、导入第三方包jmf.jar,和fmj.jar(如果网上找不到,请加入该群83945749)
4、运行的时候先运行MediaTransmit类,后运行MediaReceive类