1 / 32

Java Media Framework

Java Media Framework. RTP 를 이용한 데이터 송/수신. Java Media Framework. Live media broadcast 또는 video conference 를 인터넷이나 인트라넷에서 수행하기위해서 Real-time 으로 미디어 데이터를 전송해야 한다 . 이러한 조건을 만족하기 위해서 Real-time Transport Protocol 이 소개되는 것이고, 네트워크를 통한 미디어 데이터의 송/수신을 위해 JMF 에서는 RTP 를 지원한다.

irving
Download Presentation

Java Media Framework

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Java Media Framework RTP를 이용한 데이터 송/수신

  2. Java Media Framework • Live media broadcast 또는 video conference를 인터넷이나 인트라넷에서 수행하기위해서 Real-time으로 미디어 데이터를 전송해야 한다. • 이러한 조건을 만족하기 위해서Real-time Transport Protocol이 소개되는 것이고, 네트워크를 통한 미디어 데이터의 송/수신을 위해 JMF에서는 RTP를 지원한다.

  3. Protocol for Streaming Media • 실시간 전송에서는 높은 대역폭(bandwidth)를 요구한다. HTTP나 FTP는 TCP기반의 프로토콜이다. TCP프로토콜은 안정적인 데이터 전송과 low bandwidth, high network error환경에 적합한 프로토콜이다. • 그래서 스트리밍 데이터의 전송에서는 TCP와는 다른 프로토콜을 이용하게 되었고, 일반적으로 UDP프로토콜을 사용한다. • UDP는 Unreliable프로토콜로서 수신단측에서의 데이터 수신에 대한 보장을 하지 않는다. TCP와 마찬가지로 UDP역시 일반적인 Transport Layer의 통신 프로토콜이다. • 오디오나 비디오와 같은 스트리밍 데이터전송에 대한 인터넷 표준으로 RTP를 이용하게 되었고, RTP는 IEEE RFC 1889로 규정되어 있다. RTP는 UDP에 기반을 두고 있다.

  4. 용어 정리 • RTP Session • RTP를 이용해서 통신을 수행하는 애플리케이션들의 집합을 말한다. Session은 네트워크 어드레스와 전송포트의 쌍으로 이루어져 있다. 포트하나는 미디어 데이터를 위해 이용되고, 다른 포트하나는 RTCP데이터의 제어를 위해 이용된다. • Participants • 세션에 참여하고 있는 단일 컴퓨터, 호스트, 또는 user를 말한다. 즉, 통신상에 참여하는 모든 참여자라고 볼 수 있다. 각각의 Participants는 데이터를 전송하는 Sender의 역할을 하기도 하고, 데이터를 수신하는 Receiver의 역할을 하기도 한다.

  5. 용어정리 • Session Manager • RTP Session들간의 통제 역할을 하고 session에 참가한 participants에 대한 추적과 관리, 전송되어지는 스트림에 대한 관리 기능을 수행한다. • 세션의 상태정보를 관리하고 RTCP control channel을 취급하며 Sender, Receiver를 위한 RTCP를 지원한다. • 작성한 애플리케이션의 초기화, 세션에 참여, 연결을 해제 할 때는 애플리케이션에 의해서 생성된 각각의 스트림을 제거, 전체 세션을 닫는 기능을 수행한다. • 참고 : • 각각의 미디어 데이터들은 서로 다른 세션을 통해서 전송된다. 다시 말하면 화상회의 시스템이라고 하면 영상과 음성이 각각 별도의 세션을 통해 전송된다는 것이다. 세션이 분리되면, Participants들이 어떤 세션의 미디어를 선택 할지를 가능하게 한다. 네트워크의 대역폭이 넓다면 모든 영상과 음성을 수신받고, 대역폭이 좁다면 음성만 받는 방법도 가능하다.

  6. 네트워크를 통한 RTP 데이터의 수신

  7. 네트워크를 통한 RTP 데이터의 수신 • 네트워크를 통해 전달되는 RTP 데이터는 일단 Session Manager에 의해 세션별로 분리가 되어서 별도의 데이터 소스들로 분리가 된다. 만약 수신단에서 저장을 하고자 한다면 데이터 소스를 프로세서로 넘기고 프로세서의 출력을 다시 데이터 소스로 만들고, 그것을 데이터 싱크로 넘긴후 데이터 싱크에서 저장하면된다 • 수신단에서 수신받은 데이터를 플레이 하고자 하는 경우에는 Session Manager에서 나오는 데이터 소스를 Player에게 넘겨주면 화면으로 볼 수가 있다. • 또 다른 가능성은 Session Manager를 통해서 나온 데이터 소스를 아무런 가공도 하지 않고 단순히 저장하기 위해 바로 DataSink로 넘겨서 저장하는 방법이다.

  8. 네트워크를 통한 RTP 데이터의 송신 • 데이터 송신을 위해 데이터 획득을 해야한다. 데이터는 하드디스크에 저장된 파일이나 캡쳐를 통한 오디오/비디오 미디어 데이터도 가능하다. 이러한 데이터는 DataSource로 보내어 지고 데이터 가공을 위해서 Processor를 거친후 나온 DataSource를 Session Manager를 통해 네트워크로 전송하거나 DataSink를 통해 파일로 저장할 수 있다.

  9. RTP Events • RTP와 관련된 이벤트는 javax.media.rtp.event패키지에 정의되어 있다. 이벤트의 등록과 처리는 우선 RTP 리스너를 구현해야 하고, Session Manager를 이용해서 RTP 리스너를 등록하면 된다. • SessionListener(세션의 상태 변화 감지) • NewParticipantsEvent : 세션에 새로운 participants가 참여하는 것을 알려준다. • LocalCollisionEvent : participants의 동기화 소스가 이미 사용중임을 알려줌 • SendStreamListener(전송될 RTP stream의 상태 변화 감지) • NewSendStreamEvent : local participants에 의해 새로운 send stream이 생성될 때 • Active/InactiveSendStreamEvent : send stream의 생성에 이용된 DataSource의 전송이 시작/중지 되었을 때 • LocalPayloadChangeEvent : send stream의 포맷이 변화되었을 때

  10. RTP Events • ReceiveStreamListener(수신될 RTP stream의 상태변화 감지) • NewReceiveStreamEvent : 새로운 receive stream이 생성되었을때 • Active/InactiveReceiveStreamEvent : 데이터 전송의 시작/중단시에 • TimeoutEvent : 데이터 전송이 Time out되는 경우 • RemotePayloadChangedEvent : receive 스트림의 포맷 변경시 • ApplicationEvent : RTCP APP 패킷이 수신되었을 때 • StreamMappedEvent : 이전에 제대로 처리되지 못한 Orphaned ReceiveStream이 participants와 연결되었을 때 • RemoteListener(원격 participants로부터 수신된 이벤트 혹은 RTP control Message에 대한 감지) • ReceiveReportEvent • SenderReportEvent • RemoteCollisionEvent

  11. RTP Session Manager를 이용한 수신 • 수신과정 • Session Manager를 통해 스트림 수신 • ReceiveStreamListener에서 스트림 수신시 이벤트 발생 • 수신된 스트림에서 DataSource를 획득 • 획득한 DataSource를 이용해서 Player생성 • Session Manager 생성과 초기화 • SessionManager RTPMgr = new com.sun.media.rtp.RTPSessionMgr(); • RTPMgr.initSession(localaddr, userDesc, 0.05, 0.25); • RTPMgr.startSession(destAddress, 1, null); • ReceiveStreamListener를 등록 • RTPMgr.addReceiveStreamListener(this);

  12. RTP Session Manager를 이용한 수신 • 새로운 스트림이 수신 되었을때 • 스트림에서 DataSource를 획득 • ReceiveStream stream = ((NewReceiveStreamEvent)ev).getReceiveStream(); • DataSource dsource = stream.getDataSource(); • 획득한 DataSource에서 Player생성 • player = Manager.createPlayer(dsource); • player.addControllerListener(this); • player.start();

  13. RTP Session Manager를 이용한 송신 • 송신 과정 • 캡쳐 디바이스나 파일을 이용해서 DataSource생성 • DataSource를 이용해서 Processor생성 • Processor에서 조작(포맷변환, 인코딩)된 DataSource생성 • Session Manager생성, 초기화 • SendStream생성, 송신 • 캡쳐 디바이스를 이용해서 DataSource생성 • Vector captureDevices = CaptureDeviceManager.getDeviceList(new VideoFormat(VideoFormat.YUV)); • CaptureDeviceInfo cdi = (CaptureDeviceInfo)captureDevices.firstElement(); • DataSource dSource = Manager.createDataSource(cdi.getLocator());

  14. RTP Session Manager를 이용한 송신 • DataSource를 이용해서 Processor생성 • Processor processor = Manager.createProcessor(dSource); • Processor에서의 인코딩과 DataSource획득 • 비디오 트랙을 획득 • TrackControl tracks[] = processor.getTrackControls(); • JPEG로 인코딩 (H.261, H.263, MPEG 등도 가능) • VideoFormat jpegFormat = new VideoFormat(VideoFormat.JPEG_RTP); • tracks[i].setFormat( jpegFormat); • 인코딩 된 DataSource를 획득 • DataSource ds = processor.getDataOutput();

  15. RTP Session Manager를 이용한 송신 • Session Manager 생성,초기화 • SessionManager rtpMgrs = new com.sun.media.rtp.RTPSessionMgr(); • rtpMgrs.initSession(localAddr, userDesc, 0.05, 0.25); • rtpMgrs.startSession(destAddr, 1, null); • SendStream 생성,전송 • sendStream = rtpMgrs.createSendStream(ds, 0); • sendStream.start();

  16. Player의 Start와 Close • Player의 생성단계 • Unrealized → Realzing → Realized → Prefetching → Prefetched → Started • Realized, Prefetched된 후에 Start가능 • RealizeCompleteEvent • PrefetchCompleteEvent • 위의 두 메시지는 Realized, Prefetched 돼 됐을 때 발생 • Player를 Close시킬때 • stop() → deallocate() → close() 단계를 거쳐 close

  17. Processor의 Start와 Close • Processor는 Player를 상속 받음 • Processor의 생성단계 • Unrealized → Configuring → Configured → Realzing → Realized → Prefetching → Prefetched → Started • Player생성 단계에서 Configuring, Configured 추가 • ConfigureCompleteEvent 추가 • Processor도 Player와 같은 방법으로 Close

  18. DataSink를 이용한 저장 • 스트림에서 획득한 DataSource를 이용하여 Processor를 생성 • Processor에서 파일타입을 설정 • Processor에서 getDataOutput()을 이용, 변환된 DataSource를 획득 • 획득한 DataSourcce를 이용해서 DataSink를 생성 • 예) • p.setContentDescriptor(new FileTypeDescriptor(FileTypeDescriptor.WAVE)); DataSink sink; MediaLocator dest = new MediaLocator("file://newfile.wav"); try { sink = Manager.createDataSink(p.getDataOutput(), dest); sink.open(); sink.start(); } catch (Exception e) {}

  19. 송신측 프로그램(파일 재생, 화상 캡쳐 전송) StateHelper sh; private SessionManager rtpMgrs; TextField status = new TextField(); MenuBar mb = new MenuBar(); Menu fileMenu = new Menu("File"); MenuItem openFile = new MenuItem("Open File"); MenuItem openCap = new MenuItem("Open Capture"); MenuItem exit_ = new MenuItem("Exit"); public DataTransmitApp2() { setLayout(new BorderLayout()); add("North", status); fileMenu.add(openFile); fileMenu.add(openCap); fileMenu.addSeparator(); fileMenu.add(exit_); mb.add(fileMenu); setMenuBar(mb); openFile.addActionListener(this); openCap.addActionListener(this); exit_.addActionListener(this); status.setEnabled(false); } import java.awt.*; import java.io.*; import java.awt.event.*; import java.applet.Applet; import java.util.*; import java.net.*; import javax.media.*; import javax.media.rtp.*; import javax.media.rtp.rtcp.*; import com.sun.media.rtp.*; import javax.media.format.*; import javax.media.protocol.*; import javax.media.control.TrackControl; import javax.media.rtp.rtcp.SourceDescription; public class DataTransmitApp2 extends Frame implements ActionListener { Player player; Processor processor; ControllerHandler controllerHandler = new ControllerHandler(); CaptureDeviceInfo cdi; DataSource dSource; DataSource dSource2; DataSink dSink;

  20. 송신측 프로그램(파일 재생, 화상 캡쳐 전송) try { //캡쳐 장치의 위치 정보를 이용해서 DataSource생성 dSource = Manager.createDataSource(cdi.getLocator()); //캡쳐한 영상을 플레이 하기 위해 복제 dSource = Manager.createCloneableDataSource(dSource); dSource2 = ((SourceCloneable)dSource).createClone(); }catch(NoDataSourceException e) { System.err.println("NoDataSource"); }catch(IOException e) { System.err.println("IOException"); } try { //DataSource를 이용해서 Processor생성 processor = Manager.createProcessor(dSource); //processor의 상태 전환을 도와 주는 클래스 인스턴스 생성 sh = new StateHelper(processor); }catch(NoProcessorException e) { System.err.println("NoProcessor"); }catch(IOException e) { System.err.println("IOException "+e); } private void openFile(String mediaFile) { File file = new File(mediaFile); String strFile = "file:///"+file.getPath(); try { URL mediaURL = new URL(strFile); layer = Manager.createPlayer(mediaURL); player.addControllerListener(controllerHandler); player.realize(); }catch(Exception e) { System.out.println("Get Exception "+e); } } private void openCapture() { //비디오 캡쳐장치의 정보를 검색해서 벡터에 저장 Vector captureDevices = CaptureDeviceManager.getDeviceList(new VideoFormat(VideoFormat.YUV)); if(captureDevices.size() > 0) { //검색된 캡쳐 장치를 선택 cdi = (CaptureDeviceInfo)captureDevices.firstElement(); }

  21. 송신측 프로그램(파일 재생, 화상 캡쳐 전송) //인코딩 할 포맷을 정한다 VideoFormat jpegFormat = new VideoFormat(VideoFormat.JPEG_RTP); //포맷 변환.... if(tracks[i].setFormat( jpegFormat) == null) { System.out.println("SetFormat Fail"); System.exit(0); } programmed = true; } else { tracks[i].setEnabled(false); } } if(!programmed) { System.err.println( "Couldn't find video track"); } if(!sh.realize(10000)) //프로세서를 realize 단계로 전환시키고 realize 완료 확인 위해 10초까지 대기 { System.err.println("Not Realized"); } //포맷이 변환된 DataSource를 획득 DataSource ds = processor.getDataOutput(); if(ds == null) { System.err.println("Data Source is null"); } //프로세서를 configure 단계로 전환시키고 configure 완료 확인 위해 10초까지 대기 if(!sh.configure(10000)) { System.err.println("Not configured"); } processor.setContentDescriptor(new ContentDescriptor(ContentDescriptor.RAW_RTP)); //ContentDescriptor 설정 //프로세서에서 트랙을 획득 : 오디오 및 비디오 TrackControl tracks[] = processor.getTrackControls(); if(tracks == null || tracks.length < 1) { System.err.println("Couldn't find tracks in processor"); } //인코딩을 확이하기 위한 플래그 boolean programmed = false; for(int i = 0 ; i < tracks.length ; i++) { //획득한 트랙들의 포맷을 확인 Format format = tracks[i].getFormat(); //비디오 포맷일 경우 if (tracks[i].isEnabled() && format instanceof VideoFormat && !programmed) {

  22. 송신측 프로그램(파일 재생, 화상 캡쳐 전송) for(int i = 0 ; i < userDesc.length ; i++) { if(i == 0) { userDesc[i] = new SourceDescription(SourceDescription.SOURCE_DESC_EMAIL, "jaxal@korea.com", 1, false); continue; } if(i == 1) { userDesc[i] = new SourceDescription(SourceDescription.SOURCE_DESC_NAME, "jaxal", 1, false); continue; } if(i == 2) { userDesc[i] = new SourceDescription(SourceDescription.SOURCE_DESC_CNAME, rtpMgrs.generateCNAME(), 1, false); continue; } try { //전송과 동시에 자신도 볼 수 있게 플레이어 생성 player = Manager.createPlayer(dSource2); player.addControllerListener(controllerHandler); player.realize(); }catch(NoPlayerException e) { System.err.println("NoPlayerException"); }catch(IOException e) { System.err.println("IOExcption "+e); } //SessionManager를 생성 rtpMgrs = new RTPSessionMgr(); SessionAddress localAddr, destAddr; InetAddress ipAddr; SendStream sendStream; int port; SourceDescription srcDesList[]; SourceDescription userDesc[] = new SourceDescription[4];

  23. 송신측 프로그램(파일 재생, 화상 캡쳐 전송) class ControllerHandler implements ControllerListener { public synchronized void controllerUpdate(ControllerEvent e) { if(e instanceof RealizeCompleteEvent) { player.prefetch(); } else if(e instanceof PrefetchCompleteEvent) { Component comp; if((comp = player.getVisualComponent()) != null) { add("Center", comp); } if((comp = player.getControlPanelComponent()) != null) { add("South", comp); } player.start(); validate(); repaint(); } } } if(i == 3) { userDesc[i] = new SourceDescription(SourceDescription.SOURCE_DESC_TOOL, "JMF 2.1", 1, false); continue; } } try { localAddr = new SessionAddress(); port = 30000; ipAddr = InetAddress.getByName("224.119.252.80"); destAddr = new SessionAddress(ipAddr, port, ipAddr, port+1); //세션을 초기화 한다 rtpMgrs.initSession(localAddr, userDesc, 0.05, 0.25); rtpMgrs.startSession(destAddr, 1, null); //SendStream을 생성하고 전송시작 sendStream = rtpMgrs.createSendStream(ds, 0); sendStream.start(); }catch(Exception e) { System.err.println("Transmit "+e); } }

  24. 송신측 프로그램(파일 재생, 화상 캡쳐 전송) private void ClosePlayer( ) { if ( player != null ) { player.stop(); player.deallocate(); player.close(); player = null; removeAll(); } } public static void main(String args[]) { DataTransmitApp2 dta = new DataTransmitApp2(); dta.setSize(200, 250); dta.setVisible(true); dta.addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){System.exit(0);}}); } } public void actionPerformed(ActionEvent e) { if(e.getSource() == openFile) { if(processor != null) { sh.close(); } ClosePlayer(); FileDialog fileDlg = new FileDialog(this, "Select File"); fileDlg.setVisible(true); openFile(fileDlg.getDirectory()+fileDlg.getFile()); } else if(e.getSource() == openCap) { ClosePlayer(); openCapture(); processor.start(); } else if(e.getSource() == exit_) { System.exit(0); } }

  25. 수신 측 프로그램(ReceiveStream2클래스를 이용) protected JMenuBar createMenuBar() { final JMenuBar menuBar = new JMenuBar(); JMenu mFile = new JMenu("File"); mFile.setMnemonic('f'); JMenuItem item = new JMenuItem("Video Save"); item.setMnemonic('v'); ActionListener itemEvent = new ActionListener() { public void actionPerformed(ActionEvent e) { VideoReceive.this.repaint(); if(m_chooser.showSaveDialog(VideoReceive.this) != JFileChooser.APPROVE_OPTION) { return; } rau.sinkStart(m_chooser.getSelectedFile()); } }; item.addActionListener(itemEvent); mFile.add(item); import java.awt.*; import java.io.*; import javax.swing.*; import java.awt.event.*; class ReceiveApp2extends JFrame { JPanel panelVideo = new JPanel(new BorderLayout()); JPanel panelCenter = new JPanel(new GridLayout(1,2)); ReceiveStream2 rau = new ReceiveStream2(); JFileChooser m_chooser; public ReceiveApp2() { super("Video Receiver"); setSize(200, 250); JMenuBar menuBar = createMenuBar(); setJMenuBar(menuBar); m_chooser = new JFileChooser(); m_chooser.setCurrentDirectory(new File(".")); panelVideo.add(rau); panelCenter.add(panelVideo); getContentPane().setLayout(new BorderLayout()); getContentPane().add("Center", panelCenter); getContentPane().add("North", new JLabel(" ")); }

  26. 수신 측 프로그램(ReceiveStream2클래스를 이용) public static void main(String args[]) { ReceiveApp2 mr = new ReceiveApp2(); mr.setVisible(true); mr.rau.StartSessionManager("224.119.252.80", 30000); mr.setVisible(true); mr.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e){ System.exit(0);}}); } } item = new JMenuItem("Exit"); item.setMnemonic('x'); itemEvent = new ActionListener() { public void actionPerformed(ActionEvent e) { rau.sink.close(); System.exit(0); } }; item.addActionListener(itemEvent); mFile.add(item); menuBar.add(mFile); return menuBar; }

  27. 수신 측 프로그램 (화상수신 , 재생 , 저장) DataSink sink; String m_filePath; public ReceiveStream2() { setLayout(new BorderLayout()); } public synchronized void controllerUpdate(ControllerEvent ce) { Player pla = null; Controller control = (Controller)ce.getSource(); if(control instanceof Player) { pla = (Player)ce.getSource(); } import java.awt.*; import java.awt.event.*; import java.io.*; import java.net.*; import java.util.*; import javax.swing.*; import javax.media.*; import javax.media.control.*; import javax.media.rtp.*; import javax.media.rtp.rtcp.*; import javax.media.rtp.event.*; import javax.media.protocol.*; import javax.media.format.*; import javax.media.bean.playerbean.*; import com.sun.media.ui.*; public class ReceiveStream2 extends Jpanel implements ControllerListener, ReceiveStreamListener { static final int VIDEO_SAVE = 100; Player player; DataSource dSource; DataSource dSource2;

  28. 수신 측 프로그램 (화상수신 , 재생 , 저장) //ReceiveStream에서 DataSource획득 try { //획득한 DataSource로 플레이어 생성 pl = Manager.createPlayer(dSource); }catch(NoPlayerException e) { //status.setText("NoPlayerException"); System.err.println(e); }catch(IOException e) { //status.setText("IOException"); System.err.println(e); } pl.addControllerListener(this); if(ce instanceof RealizeCompleteEvent) { Component comp; if((comp = pla.getVisualComponent()) != null) { add("Center", comp); } if((comp=pla.getControlPanelComponent()) != null) { add("South", comp); } validate(); } } public void update(ReceiveStreamEvent ev) { Player pl = null; //새로운 스트림이 수신 되었을때 if(ev instanceof NewReceiveStreamEvent) { //ReceiveStream을 생성 ReceiveStream stream = ((NewReceiveStreamEvent)ev) .getReceiveStream();

  29. 수신 측 프로그램 (화상수신 , 재생 , 저장) SessionAddress destAddress = new SessionAddress(destaddr, port, destaddr, port+1); SourceDescription userDesc[] = new SourceDescription[4]; for(int i = 0 ; i < userDesc.length ; i++) { if(i == 0) { userDesc[i] = new SourceDescription (SourceDescription.SOURCE_DESC_EMAIL, "jaxal@korea.com", 1, false); continue; } if(i == 1) { userDesc[i] = new SourceDescription (SourceDescription.SOURCE_DESC_NAME, "jaxal", 1, false); continue; } if(i == 2) { userDesc[i] = new SourceDescription (SourceDescription.SOURCE_DESC_CNAME, RTPMgr.generateCNAME(), 1, false); continue; } //플레이어 스타트 pl.start(); } } //Session Manager를 생성 public SessionManager StartSessionManager (String destAddr, int port) { InetAddress destaddr = null; SessionManager RTPMgr = new com.sun.media.rtp.RTPSessionMgr(); //ReceiveStreamListener를 등록 RTPMgr.addReceiveStreamListener(this); SessionAddress localaddr = new SessionAddress(); try { destaddr=InetAddress.getByName(destAddr); }catch(UnknownHostException e) { //status.setText("UnknownHostException"); System.err.println(e); }

  30. 수신 측 프로그램 (화상수신 , 재생 , 저장) //파일로 저장하기 위한 초기화 public void sinkStart(File selected) { Processor processor = null; StateHelper sh = null; try { processor = Manager.createProcessor(dSource); sh = new StateHelper(processor); }catch(Exception e) { System.err.println(e); } if(!sh.configure(10000)) { System.err.println("configure fail"); } processor.setContentDescriptor (new FileTypeDescriptor (FileTypeDescriptor.MSVIDEO)); if(!sh.realize(10000)) { System.err.println("realize fail"); System.exit(0); } if(i == 3) { userDesc[i] = new SourceDescription (SourceDescription.SOURCE_DESC_TOOL, "JMF 2.1", 1, false); continue; } } try { //Session Manager초기화 RTPMgr.initSession(localaddr, userDesc, 0.05, 0.25); RTPMgr.startSession(destAddress, 1, null); }catch(SessionManagerException e) { //status.setText("SessionManagerException “ // + e); System.err.println(e); }catch(IOException e) { //status.setText("IOException "+e); System.err.println(e); } return RTPMgr; }

  31. 수신 측 프로그램 (화상수신 , 재생 , 저장) try { sink.start(); }catch(Exception e) { System.err.println(e); System.exit(0); } sh.palyToEndOfMedia(30000); sh.close(); sink.close(); } } DataSource ds = processor.getDataOutput(); try { MediaLocator media = new MediaLocator("file:///"+selected.getPath()); sink = Manager.createDataSink(ds, media); sink.open(); System.out.println("Saving........"); }catch(Exception e) { System.err.println("Sink Exception "+e); } StreamWriterControl swc = (StreamWriterControl)processor.getContRol ("javax.media.control.StreamWriterControl"); if(swc != null) { swc.setStreamSizeLimit(5000000); }

  32. JMF 익히기 • 예제 실행 • Jdk1.2.1 이상, jmf2.1 이상 설치 • 예제 복사: Information, Java의 JMFex • 송신측 >JavacDataTransmitApp2.java >Java DataTransmitApp2 • 수신측 >javac ReceiveApp2.java >java ReceiveApp2 예외발생시 클래스 패스 확인바람 • 실습 • 예제에 음성데이터의 전송과 수신 기능 추가 • 예제에 Processor 와 DataSink를 이용하여 수신한 데이터(오디오 및 비디오)를 파일로 저장 • 위에서 저장한 파일을 Play시키면서 실시간으로 전송하는 기능 추가 • http://java.sun.com/products/java-media/jmf/2.1.1/guide • http://java.sun.com/products/java-media/jmf/2.1.1/apidocs참조

More Related