javawindowsvideocropxuggle

Cropping BufferedImage For Use in Xuggle encodeVideo


I have an application to capture video of the screen and save to a file. I give the user the ability to pick between 480, 720, and "Full Screen" video sizes. A 480 will record in a small box on the screen, 720 will record in a larger box, and of course, "Full Screen" will record in an even larger box. However, this full screen box is NOT the actual screen resolution. It is the app window size, which happens to be around 1700x800. The Video Tool works perfectly for the 480 and 720 options, and will also work if "Full Screen" is overwridden to be the entire screen of 1920x1080.

My question: Are only certain sizes allowed? Does it have to fit a certain aspect ratio, or be an "acceptable" resolution? My code, below, is modified from the xuggle CaptureScreenToFile.java file (the location of the problem is noted by comments):

    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;
    }

Error: java.lang.RuntimeException: could not open stream com.xuggle.xuggler.IStream@2834912[index:0;id:0;streamcoder:com.xuggle.xuggler.IStreamCoder@2992432[codec=com.xuggle.xuggler.ICodec@2930320[type=CODEC_TYPE_VIDEO;id=CODEC_ID_H264;name=libx264;];time base=1/50;frame rate=0/0;pixel type=YUV420P;width=1696;height=813;];framerate:0/0;timebase:1/90000;direction:OUTBOUND;]: Operation not permitted

Note: The file is successfully created, but has size of zero, and cannot be opened by Windows Media Player, with the following error text: Windows Media Player cannot play the file. The Player might not support the file type or might not support the codec that was used to compress the file.

Sorry for the wordy question. I'm interested in learning WHAT and WHY, not just a solution. So if anyone can explain why it isn't working, or point me towards material to help, I'd appreciate it. Thanks!


Solution

  • Try to have the dimension even numbers 1696x812