반응형

JMF의 Control중에서 Spec상에서는 FrameRateControl을 통해서 framerate를 변경할수 있도록 되어 있다. Framerate를 변경하는 코드는 다음과 같은데..
-------------------------------------------------------------------------------
Control control = recordProcessor.getControl("javax.media.control.FrameRateControl");
if ( control != null &&
     control instanceof javax.media.control.FrameRateControl )
      ((javax.media.control.FrameRateControl)control).setFrameRate(15.0f);
-------------------------------------------------------------------------------
실제로 setFrameRate를 하게 되면 -1이 리턴하여 변경이 되지 않는다. 

이전에 보았던 Customized Push BufferStream의 구현Customized DataSource를 만들어 보자 를 참고하여 framerate를 감소시켜서  RTP로 전송하는 프로그램을 만들어 보도록 하겠다.

참고를 해야 하는 소스 파일은
http://java.sun.com/products/java-media/jmf/2.1.1/solutions/LiveData.html
의 DataSource.java 및 LiveStream.java 그리고
http://www.exactfutures.com/vid2jpg.zip
의 vid2jpg 클래스들
http://java.sun.com/products/java-media/jmf/2.1.1/solutions/VideoTransmit.html
의 VideoTransmit.java
가 참고 되어야 한다.

1. vid2jpg.java의 분석
 [DataSourceHandler 내부 클래스 분석]
 - vid2jpg 클래스에서는 DataSourceHandler라는 내부 클래스가 존재한다. 이 클래스는 BufferTransferHandler를 구현한 클래스로 BufferTransferHandler는 PushBufferStream의 callback에 해당한다. PushBufferStream은 push될 data가 가능할 경우 notify를 할 필요가 있다.
 PushBufferStream의 setTransferHandler 메소드를 이용하여 Handler클래스를 등록하고 Handler에 transferData(PushBufferStream stream) 함수를 구현(Override?)하여 데이터를 가져와서 처리 가능하다
DataSourceHandler의 주요한 코드는 다음과 같다.
private void setSource(DataSource source) throws IncompatibleSourceException 의
    pushStrms = ((PushBufferDataSource) source).getStreams();
    pushStrms[0].setTransferHandler(this);
public void transferData(PushBufferStream stream)
    stream.read(readBuffer);
   // Just in case contents of data object changed by some other thread
   Buffer inBuffer = (Buffer)(readBuffer.clone());
   useFrameData(inBuffer); (이 메소드는 vid2jpg의 메소드 이다)

DataSourceHandler의 주요한 기능은 DataSourceHandler.setSource 메소드로 설정된 데이터 소스에 대해서 데이터가 준비가 되면 해당 데이터를 읽어서 Buffer에 세팅하고 이 Buffer를 가지고 vid2jpg의 userFrameData에서 처리하도록 하게 하는 것이다.

[vid2jpg]분석
1. Program Start
public static void main(String[] args)
   new vid2jpg("미디어 소스 위치");

2. vid2jpg 생성자
 public vid2jpg(String path)
  if((ml = new MediaLocator(args)) == null) [미디어 로케이터 설정]
  if(!open(ml)) [vid2jpg::open 호출]
 
3. vid2jpg::open 메소드
private boolean open(MediaLocator ml)
   p = Manager.createProcessor(ml); [Processor 생성]
   p.addControllerListener(this); [Listener 등록]
   p.configure(); [Processor의 Configure상태로 전이]
   p.setContentDescriptor(new ContentDescriptor(ContentDescriptor.RAW));
       [컨텐츠를 RAW TYPE으로 설정]
   TrackControl tc[] = p.getTrackControls(); [Track을 가져옴]
    tc[i].setFormat(new RGBFormat(null, -1, Format.byteArray, -1.0F, 24, 3, 2, 1));
       [ Video Format에 대해서 RAW/RGB Format으로 설정함]
   p.realize(); [ Processor를 Realize 상태로 전이 ]
   DataSource ods = p.getDataOutput();
   handler = new DataSourceHandler(); [DataSourceHandler를 생성]
   handler.setSource(ods);  [ DataSourceHandler에 DataSource 등록]
   handler.start(); [ DataSourceHandler를 Start ]
   p.prefetch(); [ Processor를 Prefetch 상태로 전이]
   p.start(); [ Processor를 Start]

- 3번까지 하게 되면 지정한 미디어 소스에서 데이터를 가져 오게 되고(DataSource) 이 데이터가 읽혀질때마나 handler(DataSourceHandler의 transferData가 호출되게 된다. 이때 transferData는 vid2jpg의 useFrameData를 호출하여 읽혀진 Buffer를 전달한다.

4. useFrameData
 private void useFrameData(Buffer inBuffer)
  countFr++;
  printDataInfo(inBuffer) [inBuffer의 info 출력]
  if(inBuffer.getData()!=null) // vfw://0 can deliver nulls [데이터를 가져와서]
    if(outvid==null)outvid = new int[imgWidth*imgHeight];
    outdataBuffer(outvid,(byte[])inBuffer.getData()); [출력할 형태로 변환하고]
    setImage(outvid); [panel에 출력
    jpeg포멧으로 파일 저장하는 코드 [jpeg파일로 저장]

 - 4번에서 주목해야될 내용은 전달되는 각 프레임을 하나하나 제어가 가능하다는 것이다. 따라서 프레임 레이트를 감소 시키려면 useFrameData에 전달된 프레임중 일부를 누락시켜서 다른 DataSource로 전달하면 FrameRate를 줄일수 있다.

다음 포스트에 계속

반응형

+ Recent posts