Обрезка BufferedImage для использования в Xuggle encodeVideo

У меня есть приложение для захвата видео с экрана и сохранения в файл. Я даю пользователю возможность выбирать между размером видео 480, 720 и полноэкранным. 480 будет записывать в маленьком поле на экране, 720 будет записывать в большем поле, и, конечно же, «во весь экран» будет записывать в еще большем поле. Однако это полноэкранное окно НЕ является фактическим разрешением экрана. Это размер окна приложения, который составляет около 1700x800. Video Tool отлично работает с параметрами 480 и 720, а также будет работать, если "Full Screen" заменен на весь экран с разрешением 1920x1080.

Мой вопрос: разрешены ли только определенные размеры? Должно ли оно соответствовать определенному соотношению сторон или иметь «приемлемое» разрешение? Мой код, приведенный ниже, изменен из файла xuggle CaptureScreenToFile.java (местоположение проблемы указано в комментариях):

    public void run() {
        try {
            String parent = "Videos";
            String outFile = parent + "example" + ".mp4";
            file = new File(outFile);

            // This is the robot for taking a snapshot of the screen.  It's part of Java AWT
            final Robot robot = new Robot();
            final Rectangle customResolution = where;  //defined resolution (custom record size - in this case, 1696x813)

            final Toolkit toolkit = Toolkit.getDefaultToolkit();
            final Rectangle fullResolution = new Rectangle(toolkit.getScreenSize());  //full resolution (1920x1080)

            // First, let's make a IMediaWriter to write the file.
            final IMediaWriter writer = ToolFactory.makeWriter(outFile);

            writer.setForceInterleave(false);  

            // We tell it we're going to add one video stream, with id 0,
            // at position 0, and that it will have a fixed frame rate of
            // FRAME_RATE.    
            writer.addVideoStream(0, 0, FRAME_RATE, customResolution.width, customResolution.height);  //if I use fullResolution, it works just fine - but captures more of the screen than I want.

            // Now, we're going to loop
            long startTime = System.nanoTime();
            while (recording) {    
                // take the screen shot
                BufferedImage screen = robot.createScreenCapture(fullResolution);  //tried capturing using customResolution, but did not work.  Instead, this captures full screen, then tries to trim it below (also does not work).
                // convert to the right image type
                BufferedImage bgrScreen = convertToType(screen, BufferedImage.TYPE_3BYTE_BGR);  //Do I need to convert after trimming?

                BufferedImage trimmedScreen = bgrScreen.getSubimage((int)customResolution.getX(), (int)customResolution.getY(), (int)customResolution.getWidth(), (int)customResolution.getHeight());

                // encode the image
                try{
                    //~~~~Problem is this line of code!~~~~  Error noted below.
                    writer.encodeVideo(0, trimmedScreen, System.nanoTime() - startTime, TimeUnit.NANOSECONDS);  //tried using trimmedScreen and bgrScreen
                } catch (Exception e) {
                    e.printStackTrace();
                }

                // sleep for framerate milliseconds
                Thread.sleep((long) (1000 / FRAME_RATE.getDouble()));

            }
            // Finally we tell the writer to close and write the trailer if
            // needed
            writer.close();
        } catch (Throwable e) {
            System.err.println("an error occurred: " + e.getMessage());
        }
    }

    public static BufferedImage convertToType(BufferedImage sourceImage, int targetType) {
        BufferedImage image;

        // if the source image is already the target type, return the source image
        if (sourceImage.getType() == targetType)
            image = sourceImage;
        // otherwise create a new image of the target type and draw the new image
        else {
            image = new BufferedImage(sourceImage.getWidth(), sourceImage.getHeight(), targetType);
            image.getGraphics().drawImage(sourceImage, 0, 0, null);
        }

        return image;
    }

Ошибка: java.lang.RuntimeException: не удалось открыть поток com.xuggle.xuggler.IStream@2834912 [индекс: 0; идентификатор: 0; streamcoder: com.xuggle.xuggler.IStreamCoder@2992432 [codec = com.xuggle.xuggler. ICodec @ 2930320 [type = CODEC_TYPE_VIDEO; id = CODEC_ID_H264; name = libx264;]; временная база = 1/50; частота кадров = 0/0; тип пикселя = YUV420P; ширина = 1696; высота = 813;]; частота кадров: 0 / 0; временная шкала: 1/90000; направление: OUTBOUND;]: операция не разрешена

Примечание. Файл успешно создан, но имеет нулевой размер и не может быть открыт проигрывателем Windows Media со следующим текстом ошибки: Проигрыватель Windows Media не может воспроизвести файл. Проигрыватель может не поддерживать тип файла или кодек, который использовался для сжатия файла.

Простите за многословный вопрос. Мне интересно узнать, ЧТО и ПОЧЕМУ, а не просто решение. Так что, если кто-нибудь может объяснить, почему это не работает, или указать мне на материал, который может помочь, я был бы признателен. Спасибо!


person Tarm    schedule 11.02.2016    source источник
comment
постарайтесь иметь размерность четных чисел 1696x812   -  person gpasch    schedule 12.02.2016
comment
Вау, это действительно было так просто. Так что, видимо, все работало нормально, просто нужна была логика, чтобы избежать нечетных чисел в измерениях. Спасибо за помощь, если поставите как ответ, то отмечу за вас.   -  person Tarm    schedule 12.02.2016


Ответы (1)


Постарайтесь, чтобы размерность четных чисел была 1696х812.

person gpasch    schedule 12.02.2016