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
댓글 달기