Приложение для удаленного рабочего стола, использующее сокеты UDP в Java - PullRequest
0 голосов
/ 14 октября 2019

Я разрабатываю своего рода приложение для удаленного рабочего стола, в котором клиент Android может отображать экран рабочего стола (и управлять им).

Проблема заключается в потоковой передаче видео. Моим решением было сделать снимки экрана с помощью класса Java Robot, изменить их размер в соответствии с разрешением целевого устройства и отправить их через DatagramPackets клиенту Android. Затем я обнаружил, что необработанные изображения должны были быть слишком большими для отправки по одному пакету UDP (потому что он занимал более 62 КБ), и поэтому я получил один из них.

IOException: Message too long

Поэтому я сжал изображения вJPEG с настройкой качества 0,25, пока я наконец не смог получить размер кадров разумно ниже 62 КБ. Но даже размер изображения иногда становится слишком большим, что приводит к тому, что кадр не отправляется. Код для этого в настоящее время:

@Override
public void run() {
    while (running) {
        try {
            BufferedImage screenshot = robot.createScreenCapture(
                    new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
            BufferedImage resizedSS = Scalr.resize(screenshot,
                    Scalr.Method.BALANCED, screenSizeX, screenSizeY);
            byte[] imageBuff = compressToJPEG(resizedSS, 0.25f);

            DatagramPacket packet = new DatagramPacket(imageBuff, imageBuff.length, address, port);
            socket.send(packet);
        } catch (IOException e) {
            LOGGER.log(Level.SEVERE, "LiveScreenSender.run: error while sending screenshot");
            e.printStackTrace();
            break;
        }
    }
}

Код для сжатия JPEG (примечание: это модифицированная версия кода, которую я нашел где-то на SO, и не до конца понимаю, как он работает)

private static byte[] compressToJPEG(BufferedImage image, float quality) throws IOException {
    ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next();
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    ImageOutputStream ios = ImageIO.createImageOutputStream(out);
    writer.setOutput(ios);

    ImageWriteParam param = writer.getDefaultWriteParam();

    // compress to a given quality
    param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
    param.setCompressionQuality(quality);

    writer.write(null, new IIOImage(image, null, null), param);

    ios.close();
    writer.dispose();

    return out.toByteArray();
}

Клиентская часть (Android) также довольно похожа

@Override
public void run() {
    while (running) {
        try {
            socket.receive(dataBuffPacket);
            if (dataBuffPacket.getLength() == 0) break;
            Bitmap bitmap = BitmapFactory.decodeByteArray(dataBuffPacket.getData(), 0, dataBuffPacket.getLength());
            onFrameReceive(bitmap);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Теперь, если длины пакетов UDP ограничены, каков обычный способ потоковой передачи живого видео с использованием UDP. Мне нужно несколько предложений, в каком направлении идти, для решения этого. Любые рекомендации библиотеки будут наиболее цениться. Насколько я видел в Интернете, большинство вопросов и блогов относятся к потоковому контенту, хранящемуся на сервере, а не к видео, генерируемому в режиме реального времени по кадрам.

Мои знания о работе в сети и воспроизведении аудио / видео довольно ограничены, поэтому я был бы признателен за хорошие уроки или ссылки на то, где я мог бы их изучить.

...