Capture video using webcam in Java

2019-04-07 02:06发布

I am trying to capture video screenshot from a java application. I have donwloaded the sarxos/webcam-capture library. I have add to my project the executable jar. It is a little bit mess. I want to capture video from a simple javafx interface that I have created. The issue is that after installing the lib and slf4 then it required to install also xuggle. I add xuggle in the path and my code is the following:

File file = new File("output.ts");

IMediaWriter writer = ToolFactory.makeWriter(file.getName());
Dimension size = WebcamResolution.QVGA.getSize();

writer.addVideoStream(0, 0, ICodec.ID.CODEC_ID_H264, size.width, size.height);

Webcam webcam = Webcam.getDefault();
webcam.setViewSize(size);
webcam.open(true);

long start = System.currentTimeMillis();

for (int i = 0; i < 50; i++) {

    System.out.println("Capture frame " + i);

    BufferedImage image = ConverterFactory.convertToType(webcam.getImage(), BufferedImage.TYPE_3BYTE_BGR);
    IConverter converter = ConverterFactory.createConverter(image, IPixelFormat.Type.YUV420P);

    IVideoPicture frame = converter.toPicture(image, (System.currentTimeMillis() - start) * 1000);
    frame.setKeyFrame(i == 0);
    frame.setQuality(0);

    writer.encodeVideo(0, frame);

    // 10 FPS
    Thread.sleep(100);
}

writer.close();

System.out.println("Video recorded in file: " + file.getAbsolutePath());

However I am receiving the following:

Caused by: java.lang.UnsatisfiedLinkError: no xuggle-ferry in java.library.path

EDIT2 I also tried the jxcapture library. I add in my project all the necessary libs I run the following code: enter link description here, the code worked fine I manage to store the video, however in the end I am receiving the following error:

8614 [JNIWrapper.ShutdownHook] ERROR com.jniwrapper.NativeResourceCollector - com.jniwrapper.FunctionExecutionException: Callback parameter types or their count are not correct at com.jniwrapper.Function.invokeVirtualFunc(Native Method)

Any idea what this error is about?? What is JNIWrapper.ShutdownHook? I tried the code in 3 different machines and this is happened just to one of them? How can I handle this exception?

EDIT3: I tried @whitesite proposal EDIT3. The gui started and I have two buttons start and stop the start button opened the camera and when I tried to stop I received the following:

java.lang.NullPointerException: Pointer address of argument 0 is NULL. at org.bytedeco.javacpp.opencv_videoio$VideoWriter.write(Native Method) at org.bytedeco.javacv.OpenCVFrameRecorder.record(OpenCVFrameRecorder.java:105) at Test1.lambda$0(Test1.java:52) at java.lang.Thread.run(Unknown Source)

2条回答
霸刀☆藐视天下
2楼-- · 2019-04-07 02:28

Ok, that's what I got using this JavaCV library and their examples:

public class Test extends Application {

public void start(Stage primaryStage) throws Exception {

    OpenCVFrameGrabber capture = OpenCVFrameGrabber.createDefault(0);
    capture.start();

    OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
    Java2DFrameConverter javaConverter = new Java2DFrameConverter();

    VBox root = new VBox();
    Canvas canvas = new Canvas();
    canvas.setHeight(capture.getImageHeight());
    canvas.setWidth(capture.getImageWidth());
    root.getChildren().add(canvas);
    Scene scene = new Scene(root, capture.getImageWidth(), capture.getImageHeight());

    primaryStage.setTitle("Live video");
    primaryStage.setScene(scene);
    primaryStage.show();

    Thread videoProcessor = new Thread(() -> {
        File output = new File("C:/Work/test.avi");
        OpenCVFrameRecorder recorder = new OpenCVFrameRecorder(output, capture.getImageWidth(), capture.getImageHeight());
        try {
            recorder.setVideoCodec(opencv_videoio.CV_FOURCC((byte) 'M', (byte) 'J', (byte) 'P', (byte) 'G'));
            recorder.start();
            while (true) {
                if(Thread.currentThread().isInterrupted()){
                    break;
                }
                Frame frame = capture.grab();
                Platform.runLater(()->{
                    BufferedImage image = javaConverter.getBufferedImage(frame, 1.0, false, null);
                    canvas.getGraphicsContext2D().drawImage(SwingFXUtils.toFXImage(image, null),0,0);
                });
                recorder.record(frame);
            }
            recorder.stop();
            capture.release();
            recorder.release();
        } catch (Exception e) {
            e.printStackTrace();
        }
    });

    primaryStage.setOnCloseRequest(e->{
        videoProcessor.interrupt();
    });

    videoProcessor.start();

}

public static void main(String[] args) throws Exception {
    launch(args);
}

}

It captures video from web cam and translates it live and in the same time writes to file. You need to include their library in classpath using maven or manual installation and also all the jars from binary zip archive. Maybe you don't need all of them, but I did't dig deep.
You can play with settings and investigate examples and sources. From what I've seen it's pretty powerful library.
Edit
Just video processing part:

Thread videoProcessor = new Thread(() -> {
        OpenCVFrameGrabber capture = null;
        FrameRecorder recorder = null;
        try {

            File output = new File("C:/Work/test2.avi");
            capture = OpenCVFrameGrabber.createDefault(0);
            capture.start();
            recorder = FrameRecorder.createDefault(output, capture.getImageWidth(), capture.getImageHeight());
            recorder.setFrameRate(8);
            recorder.setVideoCodec(opencv_videoio.CV_FOURCC((byte) 'M', (byte) 'J', (byte) 'P', (byte) 'G'));
            recorder.start();
            long l = System.currentTimeMillis();
            while (true) {
                if(Thread.currentThread().isInterrupted()){
                    break;
                }
                recorder.record(capture.grab());

            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                recorder.stop();
                capture.release();
                recorder.release();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });

You need to start process videoProcessor.start() somewhere and then interrupt it to stop recording videoProcessor.interrupt(). You might also need to set proper recorder frame rate to adjust it to your camera fps.
Edit 2
Code to output available devices:

int n = org.bytedeco.javacpp.videoInputLib.videoInput.listDevices();
for (int i = 0; i < n; i++) {
    System.out.println(i + " = " + org.bytedeco.javacpp.videoInputLib.videoInput.getDeviceName(i));
}  

Edit 3
If webcam-capture works, than you can use it to capture images and use javaCV to record these images into videofile (pretty much like exapmle in youe question, just javaCV instead of xuggler). This is a small javafx app, which has two buttons: 'Start' starts the videoProcessing thread to capture video and 'Stop' interrupts this thread:

import com.github.sarxos.webcam.Webcam;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import org.bytedeco.javacpp.opencv_videoio;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.bytedeco.javacv.OpenCVFrameRecorder;


import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.File;

public class Test1 extends Application {

public void start(Stage primaryStage) throws Exception {

    final double FPS = 25;
    final int WIDTH = 640;
    final int HEIGHT = 480;
    Webcam webcam = Webcam.getDefault();
    webcam.setViewSize(new Dimension(WIDTH, HEIGHT));

    Java2DFrameConverter javaConverter = new Java2DFrameConverter();

    VBox root = new VBox();
    Button b1 = new Button("Start");
    Button b2 = new Button("Stop");

    root.getChildren().addAll(b1, b2);
    Scene scene = new Scene(root, 300,200);
    primaryStage.setTitle("Test");
    primaryStage.setScene(scene);

    Runnable r = () -> {
        File output = new File("C:/Work/test.avi");
        OpenCVFrameRecorder recorder = new OpenCVFrameRecorder(output, WIDTH, HEIGHT);
        recorder.setFrameRate(FPS);
        try {
            recorder.setVideoCodec(opencv_videoio.CV_FOURCC((byte) 'M', (byte) 'J', (byte) 'P', (byte) 'G'));
            recorder.start();
            webcam.open();
            while (true) {
                if(Thread.currentThread().isInterrupted()){
                    break;
                }
                BufferedImage image = webcam.getImage();
                recorder.record(javaConverter.getFrame(image));
                try {
                    Thread.sleep(1000 / (long)FPS);
                } catch (InterruptedException ie) {
                    break;
                }
            }
            recorder.stop();
            recorder.release();
            webcam.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    };

    b1.setOnAction(e->{
        Thread t = new Thread(r);
        t.start();
        b2.setOnAction(e2->t.interrupt());
    });

    primaryStage.show();
}

public static void main(String[] args) throws Exception {
    launch(args);
}

}
查看更多
够拽才男人
3楼-- · 2019-04-07 02:39

You are missing slf4-api-ver.jar in your classpath. However adding just the api will not be enough you will also need a provider like slf4j-simple-ver.jar. The latest available are version 1.7.21 and can be downloaded from here http://www.slf4j.org/download.html

查看更多
登录 后发表回答