Java ImageIO写入太慢

Java ImageIO写入太慢,java,javax.imageio,Java,Javax.imageio,我正在用Java编写客户机-服务器应用程序,客户机不断地截图,并使用套接字将其发送到服务器。服务器显示这些图像,所以它是一种视频流软件 我的问题是显示的视频不是很流畅。我发现这是由于使用ImageIO ImageWriter write()方法将BuffereImage转换为JPEG格式。我制作了一个测试类,通过截取200个屏幕截图,然后进行转换来测试此转换的性能: import javax.imageio.IIOImage; import javax.imageio.ImageIO; impo

我正在用Java编写客户机-服务器应用程序,客户机不断地截图,并使用套接字将其发送到服务器。服务器显示这些图像,所以它是一种视频流软件

我的问题是显示的视频不是很流畅。我发现这是由于使用ImageIO ImageWriter write()方法将BuffereImage转换为JPEG格式。我制作了一个测试类,通过截取200个屏幕截图,然后进行转换来测试此转换的性能:

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriter;
import javax.imageio.stream.MemoryCacheImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class Main {

    public static void main(String[] args) throws IOException, InterruptedException {

        new ConversionTest().test(200);
    }

    public static class ConversionTest {

        private BlockingQueue<byte[]> convertedImages = new LinkedBlockingQueue<>();
        private BlockingQueue<BufferedImage> screenshots = new LinkedBlockingQueue<>();

        public void test(int numOfScreenshots) throws IOException, InterruptedException {
            Robot robot;
            try {
                robot = new Robot();
            } catch (AWTException e) {
                e.printStackTrace();
                return;
            }

            Toolkit defaultToolkit = Toolkit.getDefaultToolkit();
            Rectangle shotArea = new Rectangle(defaultToolkit.getScreenSize());
            for (int i = 0; i < numOfScreenshots; i++) {
                BufferedImage screenCapture = robot.createScreenCapture(shotArea);
                screenshots.add(screenCapture);
            }
            System.out.println(screenshots.size());
            
            
            ImageWriter writer =
                    ImageIO.getImageWritersByFormatName("jpeg").next();
            long timeBefore = System.nanoTime();
            for (int i = 0; i < numOfScreenshots; i++) {
                BufferedImage screenshot = screenshots.take();
                ByteArrayOutputStream bout = new ByteArrayOutputStream();
                writer.setOutput(new MemoryCacheImageOutputStream(bout));
                writer.write(new IIOImage(screenshot, null, null));
                bout.flush();
                convertedImages.add(bout.toByteArray());
            }
            long timeAfter = System.nanoTime();
            writer.dispose();
            double totalTime = (timeAfter - timeBefore) / 1000000.0 / 1000.0;
            System.out.println(numOfScreenshots + " screenshots: " + totalTime + " sec");
            System.out.println(numOfScreenshots / totalTime + " of screenshots per second.");
        }
    }
}

有可能提高这个测试代码片段的性能吗?如果是的话,我如何才能做到这一点?我想将每秒的屏幕截图数量增加到30张或更多。

18fps的java是一种不错的选择。如果您需要更高的性能,就别提java了。我只看到一些解决方法。1) 基准JPEG编码器(找到本地编码器?)2)降低图像定义,3)多线程和/或4)30 JPEG/秒通常称为视频,什么不使用视频编码器?存在。所以你可以用GIF和BMP试试。@flaxel GIF格式不适合我的情况,因为图像质量太低(并非所有颜色都正确表示),而且BMP生成的数据太多,无法通过套接字传输(我电脑上的每个屏幕截图大约6 MB,相当于每秒180 MB,每秒30帧)。它将把性能问题从转换图像转移到通过网络传输图像。在这些格式中,我认为JPEG效果最好,我想我希望使用这种格式提高转换性能。您可以做一些小事情,比如将
bout=new ByteArrayOutputStream()
置于循环之外。您当前正在创建大量可能影响性能的垃圾。此外,还可以尝试JPEG质量。但我认为最好的办法是使用某种增量压缩,也许还有动态质量。本机代码可能会快一点,使用现代硬件会更快。我认为java的18fps有点好。如果您需要更高的性能,就别提java了。我只看到一些解决方法。1) 基准JPEG编码器(找到本地编码器?)2)降低图像定义,3)多线程和/或4)30 JPEG/秒通常称为视频,什么不使用视频编码器?存在。所以你可以用GIF和BMP试试。@flaxel GIF格式不适合我的情况,因为图像质量太低(并非所有颜色都正确表示),而且BMP生成的数据太多,无法通过套接字传输(我电脑上的每个屏幕截图大约6 MB,相当于每秒180 MB,每秒30帧)。它将把性能问题从转换图像转移到通过网络传输图像。在这些格式中,我认为JPEG效果最好,我想我希望使用这种格式提高转换性能。您可以做一些小事情,比如将
bout=new ByteArrayOutputStream()
置于循环之外。您当前正在创建大量可能影响性能的垃圾。此外,还可以尝试JPEG质量。但我认为最好的办法是使用某种增量压缩,也许还有动态质量。本机代码可能会快一点,使用现代硬件会更快。
200 screenshots: 11.331018700000001 sec
17.650663660099685 of screenshots per second.