jmf 강좌..

|

jmf

JavaStudy Techtips Translation

Java Developer Connection SM (JDC) 테크 팁 ,2 19, 2002.

이 팁은  Java TM 2 SDK, Standard Edition, v 1.3 를 사용하여 개발되었습니다.

문서의 원문은 Tech Tips 에 있습니다.


  JDC Tech Tips ::::: 테크 팁

 PLAYING AUDIO AND VIDEO WITH THE JAVA MEDIA FRAMEWORK

 JMF(Java Media Framework)로 오디오와 비디오 재생하기


 

 


이 준 호 [technavy@hanmail.net]
자바스터디 네트워크 [http://javastudy.co.kr]

 

Core Java2 플랫폼 라이브러리를 사용하면 GIF, JPEG, PNG 형식의 이미지를 화면에 나타낼 있다. Core Java2 플랫폼 라이브러리는 GIF89A 형식의 에니메이션 이미지도 부분적으로 지원하며, WAV, AU, MIDI, AIFF 형식의 오디오 파일들도 재생할 있다. Core Java2 플랫폼 라이브러리의 이런 지원에 만족할 수도 있지만, 비디오 재생용 AVI 파일이나 오디오 재생을 위한 MP3 파일들과 같은 미디어 형식들을 처리할 필요가 있다면, JMF(Java Media Framework) API 필요하다.

JMF API 오디오, 비디오의 재생 스트림 처리, 캡쳐를 지원하며, 각기 다른 형식의 미디어를 처리하기 위한 일련의 인코더와 디코더를 제공하고, 새로운 미디어 형식에 대한 지원을 추가할 있는 플러그 방식의 아키텍쳐를 제공한다.

Java Media Framework 최신 버전(JMF 2.1.1a) 여기에서 구할 있다. JMF 플랫폼에 의존적인 , 플랫폼에 독립적인 두가지 형태로 제공된다. 솔라리스(Solaris) 윈도우즈(Windows) 플랫폼에 의존적인 것은 (Sun)에서 제공하며, 리눅스(Linux)용은 블랙다운(Blackdown:http://blackdown.org/)에서 구할 있다.

썬에서 제공하는 플랫폼에 의존적인 형태의 JMF 네이티브 라이브러리를 사용해서 Java Sound API 오디오 기능을 지원한다. 그러나, 플랫폼 독립적인 형태의 JMF 이런 기능을 지원하지 않는다. JMF 인스톨한 후에는 JMF 라이브러리를 사용하기 위한 환경을 만들어야 한다. 플랫폼에 의존적인 형태의 JMF 인스톨 했다면, jmf.jar sound.jar classpath 추가하고 JMF lib 디렉토리를 path 추가한다. 플랫폼 독립적인 형태의 JMF에서는 jmf.jar classpath 추가하기만 하면 된다.

리눅스용 JMF 설치는 세가지 형태가 있으며, 오디오와 비디오 모두를 지원한다. 리눅스에서의 JMF 설치에 대한 보다 자세한 정보는 Java Media Framework for Linux에서 구할 있다.

JMF 라이브러리를 이용하면 간단하게 미디어 파일을 재생할 있다. 이때 사용되는 주요 클래스는 Manager Player이다. Manager Player 반환하는 여러개의 createPlayer() 라는 메소드를 가지고 있다. Manager 이용하여 Player 생성하면, Player 미디어 파일을 재생한다. 아래 코드는 간단한 오디오 재생 방법을 보여준다.

  Player player = Manager.createPlayer(resource);

  player.play();

                           

코드에서 createPlayer() 메소드에게 넘겨주는 resource Datasource, MediaLocator, URL 세가지 한가지 형태를 가진다. 세가지는 각각 미디어를 규정하는 방식을 나타낸다. Datasource 프로토콜 핸들러를 나타내며, MediaLocator 미디어의 내용을, URL 미디어의 위치정보를 나타낸다. 대개 URL 사용하는 것이 가장 간단하다. 예를 들어, 하드디스크에 있는 파일을 재생하려면 간단하게 있다.

  1. File 클래스의 toURL() 메소드를 사용해서 파일에 대한 URL 정보를 얻어낸다.

  2. 1번에서 얻어낸 URL createPlayer()에게 넘긴다.

  3. play() 메소드를 사용해서 파일을 재생한다.

                            

  URL url = file.toURL();

  Player player = Manager.createPlayer(url);

  player.play();

                           

위와 같은 과정으로 비디오 재생은 충분치 않다. 어떤 비디오 파일에 대해 play() 메소드를 호출하는 것은 좋아하는 비디오를 TV 꺼놓고 관람하는 것과 비슷하다. 소리는 들을 있지만, 영상은 없다. 영상을 보기 위해서는 ControllerListener 등록하는 것과 같은 추가 작업이 필요하다.

Player Controller 타입이며, controller ControllerListener 등록해 주어야 한다. ControllerListener public void controllerUpdate(ControllerEvent event) 라는 한개의 메소드를 가지고 있다. 메소드를 사용하면, 언제 비디오 파일의 재생이 끝나는지, 오디오 파일이 언제 메모리로 로드되었는지, 미디어 재생이 언제 시작되었고, 언제 끝났는지 등의 다양한 이벤트의 발생 시점을 있다.

이런 이벤트들을 처리하기 위해서 ControllerAdapter 클래스를 사용한다. ControllerAdapter 클래스는 30 이상의 메소드를 가지고 있는데, 이들 각각은 세부적으로 구분된 controller 이벤트들에 대해 반응하며, 스텁 메소드로 전달된다. 보통 어떤 이벤트를 다룰려면, ControllerAdapter 클래스를 상속해서 해당 이벤트를 처리하는 메소드를 오버라이드 한다. ControllerAdapter 사용하지 않고 이벤트를 처리하려면, controllerUpdate 메소드에서 인자로 넘어온 event 대해 instanceof 사용하여 원하는 이벤트인지 검증해야 한다.

이벤트들 RealizeCompleteEvent 특히 중요하다. 이벤트가 발생하면, ControllerAdapter realizeComplete 메소드로 제어권을 넘긴다. 메소드를 오버라이드 해서 비디오 재생을 위해 필요한 영상 표시 컴포넌트와 오디오, 비디오의 컨트롤 패널 컴포넌트를 얻을 있다. 컨트롤 패널을 이용하면, 오디오의 볼륨을 조절하거나 비디오 재생을 시작하거나 멈추게 있다. 아래 코드는 각각의 컴포넌트를 얻어낸 그것들을 화면에 표시하는 방법을 보여주고 있다.

  Component vc = player.getVisualComponent();

  if (vc != null) {

      contentPane.add(vc, BorderLayout.CENTER);

  }

  Component cpc = player.getControlPanelComponent();

  if (cpc != null) {

      contentPane.add(cpc, BorderLayout.SOUTH);

  }

                           

아래 예제 프로그램은 지금까지 설명했던 모든 것들을 보여준다. 예제 프로그램에서는 버튼이 사용되는데, 버튼은 어떤 파일을 재생할 것인지를 선택하기 위해 JFileChooser 화면에 표시한다. 파일이 선택되면, 파일 재생을 위한 player 얻어내고, 파일을 재생한다. 이때, 화면에 표시될 영상 표시용 컴포넌트를 얻어낸다. JMF 관련된 코드는 모두 load() 메소드에 있으며, load() 메소드 이외의 코드들은 단지 GUI 처리하기 위한 것들이다.

프로그램이 다른 player 시작하기 전에 이전 player 멈추게 하는지에 대해 궁금해 할지도 모르겠다. 새로운 Player 객체를 생성하기 위해서는 Manager.createPlayer(url) 호출하는데, 이때, 이전 player 반드시 멈추게 해야 한다. 그렇지 않으면, 새로 생성된 비디오 재생 player 사운드 트랙을 들으면서 바로 전에 재생 시켰던 MP3 음악을 동시에 듣게 것이다. 만약, 비디오를 보다가 오디오를 재생하려면 비디오 재생을 위한 영상 표시 컴포넌트를 제거해야 한다. 그렇지 않으면, 새로 재생시킨 오디오를 들으면서 이전의 비디오 영상을 보게될 것이다.

  import javax.swing.*;

  import javax.media.*;

  import java.awt.*;

  import java.awt.event.*;

  import java.net.*;

  import java.io.*;

 

  public class PlayVideo extends JFrame {

    Player player;

    Component center;

    Component south;

 

    public PlayVideo() {

      setDefaultCloseOperation(EXIT_ON_CLOSE);

      JButton button = new JButton("Select File");

      ActionListener listener =

        new ActionListener() {

          public void actionPerformed(ActionEvent event) {

            JFileChooser chooser = new JFileChooser(".");

            int status = chooser.showOpenDialog(PlayVideo.this);

            if (status == JFileChooser.APPROVE_OPTION) {

              File file = chooser.getSelectedFile();

              try {

                load(file);

              } catch (Exception e) {

                System.err.println("Try again: " + e);

              }

            }

          }

        };

      button.addActionListener(listener);

      getContentPane().add(button, BorderLayout.NORTH);

      pack();

      show();

    }

 

    public void load(final File file) throws Exception {

      URL url = file.toURL();

      final Container contentPane = getContentPane();

      if (player != null) {

        player.stop();

      }

      player = Manager.createPlayer(url);

      ControllerListener listener =

        new ControllerAdapter() {

          public void realizeComplete(RealizeCompleteEvent event) {

            Component vc = player.getVisualComponent();

            if (vc != null) {

              contentPane.add(vc, BorderLayout.CENTER);

              center = vc;

            } else {

              if (center != null) {

                contentPane.remove(center);

                contentPane.validate();

              }

            }

            Component cpc = player.getControlPanelComponent();

            if (cpc != null) {

              contentPane.add(cpc, BorderLayout.SOUTH);

              south = cpc;

            } else {

              if (south != null) {

                contentPane.remove(south);

                contentPane.validate();

              }

            }

            pack();

            setTitle(file.getName());

          }

        };

      player.addControllerListener(listener);

      player.start();

    }

 

    public static void main(String args[]) {

      PlayVideo pv = new PlayVideo();

    }

  }

                           

JMF 관한 보다 자세한 정보는 Java Media Framework API Guide에서 얻을 있다.

▒▒▒ 해군으로 군복무중이신 준호님이 번역한 팁입니다. ▒▒▒   교정 : 이종훈(dicajohn@javastudy.co.kr)

 

▒▒▒ 이준호님 커멘트 : 안녕하세요. 이준호 라고 합니다.

현재 군복무 중인데, 자바에 관심이 있어서 공부도 할겸 JDC 테크 팁 한글화에 참여하고 있습니다.

막막해서 JMF API GUIDE 를 봤는데 배보다 배꼽이 더 크더군요. -_-;

JavaStudy Techtips Translation list

 

 

 

 

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

import java.io.*;

import javax.media.*;

import javax.media.protocol.*;

 

public class MediaPlayer extends JFrame implements ActionListener, ControllerListener{

 private JPanel contentPanel;

 private Component controlComponent;

 private Component visualComponent;

 private Player player;

 

 public MediaPlayer(String title) {

  super(title);

 

  /* 열기 메뉴 추가 */

  JMenuBar menuBar = new JMenuBar();

  JPopupMenu.setDefaultLightWeightPopupEnabled(false);

  JMenu menu = new JMenu("파일");

  JMenuItem item = new JMenuItem("열기");

  item.setActionCommand("open");

  item.addActionListener(this);

  menu.add(item);

  menuBar.add(menu);

 

  /*메뉴바 설정 */

  setJMenuBar(menuBar);

 

  setSize(200, 200);

  setVisible(true);

 }

 

 /* Player를 만들고, 리스너를 등록한다. */

 public void makePlayer(String filePath) {

  MediaLocator locator = new MediaLocator(filePath);

  try {

   /* DataSource 생성 */

   DataSource dataSource = Manager.createDataSource(locator);

 

   /* 현재 동작중인 Player가 있다면 닫는다. */

   if(player != null) {

    player.close();

   }

 

   /* Player 생성 */

   player = Manager.createPlayer(dataSource);

 

   /* 리스너 등록 */

   player.addControllerListener(this);

  }catch(IOException e){

   System.out.println(e);

  }catch(NoDataSourceException e) {

   System.out.println("DataSource를 만들 수 없습니다.");

  }catch(NoPlayerException e) {

   System.out.println("Player를 만들 수 없습니다.");

  }

 }

 

 /* Player의 상태변경 감지 */

 public synchronized void controllerUpdate(ControllerEvent e) {

  /* Player Realized 상태일 때 컴포넌트를 프레임에 추가한다. */

  if(e instanceof RealizeCompleteEvent ) {

   contentPanel = new JPanel(new BorderLayout());

 

   /* 기본 조정 컴포넌트 */

   controlComponent = player.getControlPanelComponent();

   if(controlComponent != null) {

    contentPanel.add(controlComponent, BorderLayout.SOUTH);

   }

 

   /* Visual 컴포넌트 */

   visualComponent = player.getVisualComponent();

   if(visualComponent != null) {

    contentPanel.add(visualComponent, BorderLayout.CENTER);

   }

 

   /* 프레임에 컴포넌트 추가 */

   setContentPane(contentPanel);

   pack();

  }

 }

 

 public void actionPerformed(ActionEvent e) {

  /* 열기 메뉴를 선택했을 경우 */

  if(e.getActionCommand().equals("open")) {

   FileDialog dialog = new FileDialog(this, "파일열기", FileDialog.LOAD);

   dialog.show();

 

   if(dialog.getFile() != null) {

    String filePath = "file:/" + dialog.getDirectory() + dialog.getFile();

 

    /* Player를 만들고, 재생시키다. */

    makePlayer(filePath);

    player.start();

   }

  }

 }

 

    public static void main(String[] args) {

  MediaPlayer player = new MediaPlayer("Media Player");

  player.addWindowListener(new WindowAdapter() {

   public void windowClosing(WindowEvent e) {

    System.exit(0);

   }

  });

 

  /* Look & Feel 변경 */

  try {

   UIManager.setLookAndFeel(

             "com.sun.java.swing.plaf.windows.WindowsLookAndFeel");

   SwingUtilities.updateComponentTreeUI(player);

  }catch(Exception e) {

   System.out.println(e);

  }

 }

}// end class MediaPlayer

'Document' 카테고리의 다른 글

JUnit  (0) 2008.08.04
SWT 실행파일 배포  (0) 2008.07.25
Web Editor  (0) 2008.07.25
AWT[2/2]  (0) 2008.07.25
AWT[1/2]  (0) 2008.07.25
And