JMF를 이용하여 웹캠 캡쳐
글쓴이: narakud / 작성시간: 토, 2013/05/11 - 2:07오후
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(); } }
Forums:
이거 참고 해보세요.
//
글이 길지만. 짧게 줄이면. 이미지 포맷이 안맞는거 같으니. 아래 있는 소스 떼다 붙여 써라 입니다.
//
모든 소스에는 개발자의 저작권이 있습니다. 메일로 문의해보세요.
프로그램을 악용하게 될경우. 법적 책임을 지게 되니. 조심하셔야 합니다.
//
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§ion=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
댓글 달기