录制屏幕Java磁盘速度

录制屏幕Java磁盘速度,java,performance,disk,frame-rate,awtrobot,Java,Performance,Disk,Frame Rate,Awtrobot,我正在开发一个Java应用程序来记录屏幕。我使用一个机器人拍摄几个屏幕截图,将它们保存到一个临时文件夹中,然后使用JpegImagesToMovie.java将它们构建到QuickTime电影文件中 我遇到的问题是,尽管将脚本开发为以20fps的速度运行,但我只能实现5fps左右的速度。我一直在跟踪磁盘速度,因为将映像保存到磁盘所花的时间太长,这会占用脚本的其余部分 接下来,我修改了脚本,将图像存储在一个BufferedImages数组中,然后在停止录制后将其写入磁盘,从而固定了帧速率,但是在重

我正在开发一个Java应用程序来记录屏幕。我使用一个机器人拍摄几个屏幕截图,将它们保存到一个临时文件夹中,然后使用JpegImagesToMovie.java将它们构建到QuickTime电影文件中

我遇到的问题是,尽管将脚本开发为以20fps的速度运行,但我只能实现5fps左右的速度。我一直在跟踪磁盘速度,因为将映像保存到磁盘所花的时间太长,这会占用脚本的其余部分

接下来,我修改了脚本,将图像存储在一个BufferedImages数组中,然后在停止录制后将其写入磁盘,从而固定了帧速率,但是在重新编码时,Java会很快耗尽内存(录制几秒钟后)

有没有人有这样做的想法或经验。我能想到的一个解决方案是,是否有办法增加JPEG图像的压缩,但我不确定如何做到这一点


任何帮助都将不胜感激

米利穆斯说的话。也许你可以设法降低JPEG的分辨率,给你多一点内存,但你可能不得不使用视频编解码器。您也可以尝试创建一个处理程序,只在您移动鼠标时进行记录,或者如果您真的打算在JPEG中进行记录,则键入。一个线程可以专用于截图,许多其他线程可以写入磁盘。由于写入磁盘不是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());
  }
}
导入javax.imageio.imageio;
导入java.awt.*;
导入java.awt.image.buffereImage;
导入java.io.File;
导入java.io.IOException;
导入java.util.Date;
导入java.util.Timer;
导入java.util.TimerTask;
导入java.util.concurrent.*;
导入java.util.concurrent.AtomicInteger;
公共类ImageWritingMain
{
公共静态void main(字符串[]args)引发异常
{
//排队
最终阻塞队列=
新建LinkedBlockingQueue();
//安排一个线程每秒拍摄20张图像并将其放入
//排队
int fps=20;
最终屏幕截图记录器=
新屏幕快照记录器(新机器人(),队列);
定时器=新定时器();
定时定时固定速率(记录器,0,(1000L/fps));
//制作一个目录来保存屏幕截图
字符串id=new Date().toString().replace('','-').replace('':'','-');
File imageDir=新文件(“图像-”+id);
imageDir.mkdirs();
//启动10个线程,每个线程从队列和
//将图像写入文件
int nWriterThreads=10;
ExecutorService线程池=Executors.newFixedThreadPool(nWriterThreads);
for(int i=0;i
要获得20fps的速度,您可能应该使用真正的视频编解码器,而不是在硬盘上播放JPEG。在上看到的屏幕录像机可以以20fps的速度进行全屏(此处为1920x1080px)视频捕获。它使用JMF&直接编码到MOV或AVI。这看起来就像我想要的!当我下班回家汇报时,我会玩一玩。编解码器的想法听起来很有希望,但我有