2012-07-05 1 views
3

Java 응용 프로그램을 사용하여 화면을 녹화하고 있습니다. 나는 Robot을 사용하여 스크린 샷을 여러 장 찍고 임시 폴더에 저장 한 다음 JpegImagesToMovie.java를 사용하여 QuickTime 동영상 파일로 빌드합니다.녹화 화면 Java 디스크 속도

내가 겪고있는 문제는 20fps로 실행되도록 스크립트를 개발 했음에도 불구하고 약 5fps 만 달성한다는 것입니다. 디스크에 이미지를 저장하는 데 너무 오래 걸리므로 나머지 스크립트를 유지하고 있다는 점에서 디스크 속도까지 추적했습니다.

다음으로, BufferedImages의 배열에 이미지를 저장 한 다음 레코딩이 멈추고 프레임 속도를 수정하면 스크립트를 수정하지만 레코딩 할 때 Java에서 메모리가 빠르게 소모됩니다 초 녹음).

아무도 아이디어를 가지고 있거나 경험 한 적이 없습니까? 내가 생각할 수있는 한 가지 해결책은 JPEG 이미지의 압축을 높이는 방법이 있지만이 작업을 수행하는 방법이 확실하지 않다는 것입니다.

도움이 될 것입니다.

+2

하는을 20fps를 얻으려면, 당신은 아마 드라이브 – millimoose

+0

에 폭파 JPEG 파일 대신 실제 비디오 코덱을 사용해야에서 보이는 스크린 레코더 [몬테 미디어 라이브러리] (http://www.randelshofer.ch/monte/)는 20 FPS로 전체 화면 (1920x1080px) 비디오 캡처를 수행 할 수 있습니다. JMF를 사용하여 MOV 또는 AVI에 직접 인코딩합니다. –

+0

내가 원했던 것처럼 보인다! 퇴근 후 집에 돌아와보고 할 때 놀 것입니다. – camerongray

답변

3

여러 스레드에서 처리하는 것이 좋습니다. 하나의 스레드는 스크린 샷을 촬영하는 데 전념 할 수 있으며 다른 많은 스레드는 디스크에 쓸 수 있습니다. 디스크에 기록하는 것은 CPU를 많이 사용하는 작업이 아니기 때문에 여러 파일을 동시에 실행할 수 있으며 각 파일은 서로 다른 파일에 기록됩니다. 다음 프로그램은 512M 힙 크기와 내 컴퓨터에서 잘 작동 :

import javax.imageio.ImageIO; 
import java.awt.*; 
import java.awt.image.BufferedImage; 
import java.io.File; 
import java.io.IOException; 
import java.util.Date; 
import java.util.Timer; 
import java.util.TimerTask; 
import java.util.concurrent.*; 
import java.util.concurrent.atomic.AtomicInteger; 

public class ImageWritingMain 
{ 
    public static void main(String[] args) throws Exception 
    { 
    // a queue 
    final BlockingQueue<BufferedImage> queue = 
     new LinkedBlockingQueue<BufferedImage>(); 

    // schedule a thread to take 20 images per second and put them in 
    // the queue 
    int fps = 20; 
    final ScreenShotRecorder recorder = 
     new ScreenShotRecorder(new Robot(), queue); 
    Timer timer = new Timer(); 
    timer.scheduleAtFixedRate(recorder, 0, (1000L/fps)); 

    // make a directory to hold the screenshot images 
    String id = new Date().toString().replace(' ', '-').replace(':', '-'); 
    File imageDir = new File("images-" + id); 
    imageDir.mkdirs(); 

    // start 10 threads, and each thread reads from the queue and 
    // writes the image to a file 
    int nWriterThreads = 10; 
    ExecutorService threadPool = Executors.newFixedThreadPool(nWriterThreads); 
    for (int i = 0; i < nWriterThreads; i++) 
    { 
     ImageWriter task = new ImageWriter(queue, imageDir); 
     threadPool.submit(task); 
    } 
    System.out.println("Started all threads .."); 

    // wait as long as you want the program to run (1 minute, for example) ... 
    Thread.sleep(60 * 1000L); 
    // .. and shutdown the threads 
    System.out.println("Shutting down all threads"); 
    threadPool.shutdownNow(); 
    timer.cancel(); 

    if (! queue.isEmpty()) 
    { 
     System.out.println("Writing " + queue.size() + " remaining images"); 
     // write the remaining images to disk in the main thread 
     ImageWriter writer = new ImageWriter(queue, imageDir); 
     BufferedImage img = null; 
     while ((img = queue.poll()) != null) 
     { 
     writer.writeImageToFile(img); 
     } 
    } 
    } 
} 

class ScreenShotRecorder extends TimerTask 
{ 
    private static final Rectangle screenRect = 
     new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()); 
    private static final AtomicInteger counter = new AtomicInteger(); 
    private final Robot robot; 
    private final BlockingQueue<BufferedImage> imageQueue; 

    ScreenShotRecorder(Robot robot, BlockingQueue<BufferedImage> imageQueue) 
    { 
    this.robot = robot; 
    this.imageQueue = imageQueue; 
    } 

    @Override 
    public void run() 
    { 
    try 
    { 
     BufferedImage image = robot.createScreenCapture(screenRect); 
     imageQueue.put(image); 
     System.out.println(Thread.currentThread() + 
      ": Took screenshot #" + counter.incrementAndGet()); 
    } 
    catch (InterruptedException e) 
    { 
     System.out.println("Finishing execution of " + Thread.currentThread()); 
     return; 
    } 
    catch (Exception e) 
    { 
     e.printStackTrace(); 
    } 
    } 
} 

class ImageWriter implements Runnable 
{ 
    private static final AtomicInteger counter = new AtomicInteger(); 
    private final BlockingQueue<BufferedImage> imageQueue; 
    private final File dir; 

    ImageWriter(BlockingQueue<BufferedImage> imageQueue, File dir) 
    { 
    this.imageQueue = imageQueue; 
    this.dir = dir; 
    } 

    @Override 
    public void run() 
    { 
    while (true) 
    { 
     try 
     { 
     BufferedImage image = imageQueue.take(); 
     writeImageToFile(image); 
     } 
     catch (InterruptedException e) 
     { 
     System.out.println("Finishing execution of " + Thread.currentThread()); 
     return; 
     } 
     catch (Exception e) 
     { 
     e.printStackTrace(); 
     } 
    } 
    } 

    public void writeImageToFile(BufferedImage image) throws IOException 
    { 
    File file = new File(dir, "screenshot-" + counter.incrementAndGet()); 
    ImageIO.write(image, "JPG", file); 
    System.out.println(Thread.currentThread() + 
     ": Wrote " + file.getCanonicalPath()); 
    } 
} 
1

밀리 모스라고합니다. 어쩌면 좀 더 많은 메모리를주기 위해 JPEG의 해상도를 낮출 수는 있지만 비디오 코덱을 사용해야 할 것입니다. 또한 마우스를 움직일 때만 기록 할 처리기를 만들거나 JPEG로 녹음하려는 경우 입력 할 수 있습니다.

+0

코덱에 대한 아이디어는 유망하지만, 자바 나 다른 언어로는 다루지 않았다. 만약 당신이 큰 도움이 될 링크 나 포인터를 줄 수 있다면! 코덱 경로를 따라 가면 여전히 로봇을 사용하고 있습니까? 아니면 다른 것을 사용해야합니까? 마지막으로, 나는이 응용 프로그램을 초보자 용 사용자에게 배포 할 계획을 갖고 있습니다 (웹 스타트도 고려 중입니다). 그래서 컴퓨터에 추가 소프트웨어를 설치하지 않고도 응용 프로그램 내에 모든 것을 포함시켜야합니다. 지속적인 도움을 보내 주셔서 감사합니다. – camerongray

+0

죄송합니다. 실제로 코덱을 사용하지 않아서 그들에 대해 많이 알지 못합니다. 스크린 샷을 찍고 비디오로 변환하는 것은 매우 많은 메모리를 필요로한다는 것을 알고 있습니다. 나는 그들에 대해 읽고 그것에 대해 새로운 질문을하는 것이 좋습니다. –