JMF를 이용하여 웹캠 캡쳐

narakud의 이미지

JMF를 이용하여 웹캠으로 영상을 받아 화면으로 출력하고 동시에 일정시간마다 캡쳐를 저장는 코드입니다.
흐름상 myPlayer -> FrameGrabbingControl fgc -> fgc.grabFrame() -> Buffer buffer -> BufferToImage btoi
-> Image image -> Image photo로 데이터가 흘러서 저장됩니다.
그런데 두번째인 FrameGrabbingControl에서 항상 null값이 나오더군요.
그 이유가 뭘까요...?
잘좀부탁드립니다. ㅠ

import java.awt.*;				
import java.awt.event.*;
import java.awt.image.*;		
import javax.swing.*;			
import javax.media.*;
import javax.media.protocol.*;	
import javax.media.control.*;	
import javax.media.format.*;	
import javax.media.util.*;	
import javax.imageio.*; 	
import java.util.*;				
import java.io.*;				
 
class MyFrame extends JFrame implements ControllerListener{
	Player myPlayer = null;			
	DataSource ds = null;
	Process p = null;
	CaptureDeviceInfo captureDeviceInfo = null;
	Container c = null;
	Vector deviceList = null;
	Boolean windowClosed = null;
 
	public MyFrame(){
		c = getContentPane();
		try{
			detect();
			play();
			this.setBounds(200, 200, 320, 280);
			SnapShot ss = new SnapShot();
			ss.run();
		}catch(Exception e){e.printStackTrace();}
	}
 
	public void play() throws Exception{
		ds = Manager.createDataSource(captureDeviceInfo.getLocator());
		myPlayer = Manager.createPlayer(ds);
		myPlayer.addControllerListener(this);
		if(myPlayer != null){
			myPlayer.start();
		}
	}
 
	public void detect(){
		try{
			deviceList = CaptureDeviceManager.getDeviceList(null);
			if( deviceList.size()>0 ){
				System.out.println("장치를 찾았습니다.");
				captureDeviceInfo = (CaptureDeviceInfo)deviceList.elementAt(2);
	 			System.out.println(captureDeviceInfo.getName());
			}
	 		else{
	 			System.out.println("장치가 발견되지 않았습니다.");
	 		}
		}
		catch(NullPointerException npe){npe.printStackTrace();}
	}
 
	public synchronized void controllerUpdate(ControllerEvent e){
		if(e instanceof RealizeCompleteEvent){
			Component component;
			if( (component = myPlayer.getVisualComponent()) != null ){
				c.add(component, "Center");
			}
			if( (component = myPlayer.getControlPanelComponent()) !=null ){
				c.add(component, "South");
			}
			validate();
			this.setVisible(true);
		}
	}
 
	class SnapShot extends Thread {
		public Image photo = null;
		public int shotCounter = 1;
		String path = null;
		Dimension imageSize=null;
 
		public SnapShot(){
			String name = ShotName();
			SaveImage(name);
		}
 
		public void SaveImage(String filename){
	        Image photo = grabFrameImage();
	        path = "C:\\abc\\"+filename+".jpeg";
	        if ( photo != null )
	        {
	        	try { 
	        		   File file = new File(path); 
	        		   ImageIO.write((RenderedImage) photo, "jpeg", file); 
	        		  } 
	        		  catch (Exception e)
	        		  {
	        		   e.printStackTrace(); 
	        		  } 
	        }
	        else
	        {
	            System.err.println ("Error : Could not grab frame");
	        }
	        }
 
 
		public String ShotName(){
			String shotName = null;
			String sc = null;
			  GregorianCalendar calendar = new GregorianCalendar();
			  int year  = calendar.get(Calendar.YEAR);
			  int month = calendar.get(Calendar.MONTH)+1; 
			  int date  = calendar.get(Calendar.DATE);
			  int ampm  = calendar.get(Calendar.AM_PM);
			  int hour  = calendar.get(Calendar.HOUR);
			  int min   = calendar.get(Calendar.MINUTE);
			  int sec   = calendar.get(Calendar.SECOND);
			   	if (ampm==1){
			  		hour += 12;	
 
			  	}
			   	if (hour==23){
			   		if (min==59){
			   			if(sec==59) shotCounter = 0;	
			   		}
			   	}
			   	if (shotCounter<10000){
			   		sc = "0"+Integer.toString(shotCounter);
			   		if (shotCounter<1000){
				   		sc = "0"+Integer.toString(shotCounter);
			   			if (shotCounter<100){
					   		sc = "0"+Integer.toString(shotCounter);
			   				if (shotCounter<10){
			   			   		sc = "0"+Integer.toString(shotCounter);
			   				}
			   			}
			   		}
			   	}
			   	shotName = Integer.toString(year)+Integer.toString(month)+Integer.toString(date)+"_"
			   	           +Integer.toString(hour)+Integer.toString(min)+Integer.toString(sec)+"_"+sc;
 
			return shotName;
		}
 
 
		public Buffer grabFrameBuffer ( )
	    {
	        if ( myPlayer != null )
	        {
	            FrameGrabbingControl fgc =     
                       (FrameGrabbingControl)myPlayer.getControl("javax.media.control.FrameGrabbingControl");  // 이부분에서 계속 null값만 입력받아요.
	            if ( fgc != null )
	            {
	                return ( fgc.grabFrame() );
	            }
	            else
	            {
	                System.err.println ("Error : FrameGrabbingControl is null");
	                return ( null );
	            }
	        }
	        else
	        {
	            System.err.println ("Error : Player is null");
	            return ( null );
	        }
	    }
 
	    public Image grabFrameImage ( )
	    {
	        Buffer buffer = grabFrameBuffer();
	        if ( buffer != null )
	        {
	            BufferToImage btoi = new BufferToImage((VideoFormat) buffer.getFormat());
	            if ( btoi != null )
	            {
	                Image image = btoi.createImage ( buffer );
	                if ( image != null )	
	                {
	                    return ( image );
	                }
	                else
	                {
	                    System.err.println ("Error : BufferToImage cannot convert buffer");
	                    return ( null );
	                }
	            }
	            else
	            {
	                System.err.println ("Error : cannot create BufferToImage instance");
	                return ( null );
	            }
	        }
	        else
	        {
	            System.out.println ("Error : Buffer grabbed is null");
	            return ( null );
	        }
	    }	
 
 
 
 
		public void run(){			
			try {
				for(;;){
					SnapShot mss = new SnapShot();
					Thread.sleep(10000);
					mss.shotCounter++;
					if (mss.shotCounter != 10){
						break;                     // 이 부분은 일단 10회만
					}
				} 
			}
				catch (InterruptedException e) {
					e.printStackTrace();
				}
		}
	}
}  
 
public class MyFrameTest{
	public static void main(String[] args) {
		MyFrame b = new MyFrame();
	} 
}
shint의 이미지

//
글이 길지만. 짧게 줄이면. 이미지 포맷이 안맞는거 같으니. 아래 있는 소스 떼다 붙여 써라 입니다.

//
모든 소스에는 개발자의 저작권이 있습니다. 메일로 문의해보세요.
프로그램을 악용하게 될경우. 법적 책임을 지게 되니. 조심하셔야 합니다.

//
http://docs.oracle.com/cd/E17802_01/j2se/javase/technologies/desktop/media/jmf/2.1.1/apidocs/javax/media/control/FrameGrabbingControl.html

The frame returned is in raw decoded format. The ImageConverter class can be used to convert it into Java image format.

이 프레임은 원본 그대로의 포맷으로 리턴합니다.
이미지 컨버터 클래스는 자바이미지 포맷에서 변환해서 사용할 수 있습니다.

자세한건. 아래 되는 소스를 참고해 보세요.

//JMF 설치하기 : jmf-2_1_1e-windows-i586.exe
http://blog.naver.com/kittenjun?Redirect=Log&logNo=10166055469

//자바 설치하기 : jdk-7u21-windows-i586.exe
http://jwduck.tistory.com/52

//자바 경로 설정하기
http://kin.naver.com/qna/detail.nhn?d1id=1&dirId=1040201&docId=67935948&qb=7J6Q67CUIOqyveuhnA==&enc=utf8&section=kin&rank=2&search_sort=0&spq=1

//자바 JPEG은 1.5까지만 지원해준다고 합니다. rt.jar 에 있습니다.
http://blog.naver.com/borapak?Redirect=Log&logNo=60130966180

//자바 1.5버전은 가입을 해야 다운 받을 수 있다.
http://hyunioops.tistory.com/7
http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html

//캡쳐 되는 소스
http://blog.naver.com/sdiwin2004?Redirect=Log&logNo=150121768529

//MediaPlayer
http://cafe.naver.com/gogojava/253

//참조하고 있는 rt.jar 파일 위치 찾기
http://devday.tistory.com/entry/%EC%B0%B8%EC%A1%B0%ED%95%98%EA%B3%A0-%EC%9E%88%EB%8A%94-rtjar-%ED%8C%8C%EC%9D%BC-%EC%9C%84%EC%B9%98-%EC%B0%BE%EA%B8%B0

//JMF 설치 사용
http://blog.naver.com/sdiwin2004?Redirect=Log&logNo=150121768529
http://talag.blog.me/70035948394

여기 보면. 아래와 같은 내용이 있습니다.
이미지 포맷이 입력되는것을 확인 하실 수 있습니다.

Name = DirectSoundCapture

Locator = dsound://

Output Formats---->

0. javax.media.format.AudioFormat
LINEAR, 48000.0 Hz, 16-bit, Stereo, LittleEndian, Signed
1. javax.media.format.AudioFormat
LINEAR, 48000.0 Hz, 16-bit, Mono, LittleEndian, Signed
2. javax.media.format.AudioFormat
LINEAR, 48000.0 Hz, 8-bit, Stereo, Unsigned
3. javax.media.format.AudioFormat
LINEAR, 48000.0 Hz, 8-bit, Mono, Unsigned
4. javax.media.format.AudioFormat
LINEAR, 44100.0 Hz, 16-bit, Stereo, LittleEndian, Signed
5. javax.media.format.AudioFormat
LINEAR, 44100.0 Hz, 16-bit, Mono, LittleEndian, Signed
6. javax.media.format.AudioFormat
LINEAR, 44100.0 Hz, 8-bit, Stereo, Unsigned
7. javax.media.format.AudioFormat
LINEAR, 44100.0 Hz, 8-bit, Mono, Unsigned
8. javax.media.format.AudioFormat
LINEAR, 32000.0 Hz, 16-bit, Stereo, LittleEndian, Signed
9. javax.media.format.AudioFormat
LINEAR, 32000.0 Hz, 16-bit, Mono, LittleEndian, Signed
10. javax.media.format.AudioFormat
LINEAR, 32000.0 Hz, 8-bit, Stereo, Unsigned
11. javax.media.format.AudioFormat
LINEAR, 32000.0 Hz, 8-bit, Mono, Unsigned
12. javax.media.format.AudioFormat
LINEAR, 22050.0 Hz, 16-bit, Stereo, LittleEndian, Signed
13. javax.media.format.AudioFormat
LINEAR, 22050.0 Hz, 16-bit, Mono, LittleEndian, Signed
14. javax.media.format.AudioFormat
LINEAR, 22050.0 Hz, 8-bit, Stereo, Unsigned
15. javax.media.format.AudioFormat
LINEAR, 22050.0 Hz, 8-bit, Mono, Unsigned
16. javax.media.format.AudioFormat
LINEAR, 16000.0 Hz, 16-bit, Stereo, LittleEndian, Signed
17. javax.media.format.AudioFormat
LINEAR, 16000.0 Hz, 16-bit, Mono, LittleEndian, Signed
18. javax.media.format.AudioFormat
LINEAR, 16000.0 Hz, 8-bit, Stereo, Unsigned
19. javax.media.format.AudioFormat
LINEAR, 16000.0 Hz, 8-bit, Mono, Unsigned
20. javax.media.format.AudioFormat
LINEAR, 11025.0 Hz, 16-bit, Stereo, LittleEndian, Signed
21. javax.media.format.AudioFormat
LINEAR, 11025.0 Hz, 16-bit, Mono, LittleEndian, Signed
22. javax.media.format.AudioFormat
LINEAR, 11025.0 Hz, 8-bit, Stereo, Unsigned
23. javax.media.format.AudioFormat
LINEAR, 11025.0 Hz, 8-bit, Mono, Unsigned
24. javax.media.format.AudioFormat
LINEAR, 8000.0 Hz, 16-bit, Stereo, LittleEndian, Signed
25. javax.media.format.AudioFormat
LINEAR, 8000.0 Hz, 16-bit, Mono, LittleEndian, Signed
26. javax.media.format.AudioFormat
LINEAR, 8000.0 Hz, 8-bit, Stereo, Unsigned
27. javax.media.format.AudioFormat
LINEAR, 8000.0 Hz, 8-bit, Mono, Unsigned

Name = JavaSound audio capture

Locator = javasound://44100

Output Formats---->

0. javax.media.format.AudioFormat
LINEAR, 44100.0 Hz, 16-bit, Stereo, LittleEndian, Signed
1. javax.media.format.AudioFormat
LINEAR, 44100.0 Hz, 16-bit, Mono, LittleEndian, Signed
2. javax.media.format.AudioFormat
LINEAR, 22050.0 Hz, 16-bit, Stereo, LittleEndian, Signed
3. javax.media.format.AudioFormat
LINEAR, 22050.0 Hz, 16-bit, Mono, LittleEndian, Signed
4. javax.media.format.AudioFormat
LINEAR, 11025.0 Hz, 16-bit, Stereo, LittleEndian, Signed
5. javax.media.format.AudioFormat
LINEAR, 11025.0 Hz, 16-bit, Mono, LittleEndian, Signed
6. javax.media.format.AudioFormat
LINEAR, 8000.0 Hz, 16-bit, Stereo, LittleEndian, Signed
7. javax.media.format.AudioFormat
LINEAR, 8000.0 Hz, 16-bit, Mono, LittleEndian, Signed

Name = vfw:Microsoft WDM Image Capture (Win32):0

Locator = vfw://0

Output Formats---->

0. javax.media.format.YUVFormat
YUV Video Format: Size = java.awt.Dimension[width=176,height=144] MaxDataLength = 38016 DataType = class [B yuvType = 2 StrideY = 176 StrideUV = 88 OffsetY = 0 OffsetU = 25344 OffsetV = 31680

1. javax.media.format.RGBFormat
RGB, 160x120, Length=57600, 24-bit, Masks=3:2:1, PixelStride=3, LineStride=480, Flipped
2. javax.media.format.RGBFormat
RGB, 176x144, Length=76032, 24-bit, Masks=3:2:1, PixelStride=3, LineStride=528, Flipped
3. javax.media.format.RGBFormat
RGB, 320x240, Length=230400, 24-bit, Masks=3:2:1, PixelStride=3, LineStride=960, Flipped
4. javax.media.format.RGBFormat
RGB, 352x288, Length=304128, 24-bit, Masks=3:2:1, PixelStride=3, LineStride=1056, Flipped
5. javax.media.format.RGBFormat
RGB, 640x480, Length=921600, 24-bit, Masks=3:2:1, PixelStride=3, LineStride=1920, Flipped
6. javax.media.format.YUVFormat
YUV Video Format: Size = java.awt.Dimension[width=160,height=120] MaxDataLength = 28800 DataType = class [B yuvType = 2 StrideY = 160 StrideUV = 80 OffsetY = 0 OffsetU = 19200 OffsetV = 24000

7. javax.media.format.YUVFormat
YUV Video Format: Size = java.awt.Dimension[width=320,height=240] MaxDataLength = 115200 DataType = class [B yuvType = 2 StrideY = 320 StrideUV = 160 OffsetY = 0 OffsetU = 76800 OffsetV = 96000

8. javax.media.format.YUVFormat
YUV Video Format: Size = java.awt.Dimension[width=352,height=288] MaxDataLength = 152064 DataType = class [B yuvType = 2 StrideY = 352 StrideUV = 176 OffsetY = 0 OffsetU = 101376 OffsetV = 126720

9. javax.media.format.YUVFormat
YUV Video Format: Size = java.awt.Dimension[width=640,height=480] MaxDataLength = 460800 DataType = class [B yuvType = 2 StrideY = 640 StrideUV = 320 OffsetY = 0 OffsetU = 307200 OffsetV = 384000

----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.

매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.

각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.