基於JMF的視頻傳輸源碼(親試可行)

來源:互聯網
上載者:User

接收端

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;// 清空 deviceListdeviceList = 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 portlocalAddress1 = new SessionAddress();localAddress2 = new SessionAddress();try {videortpManager.initialize(localAddress1);audiortpManager.initialize(localAddress2);} catch (Exception e) {e.printStackTrace();}// specify the remote endpoint of this unicast sessiontry {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();}}}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.