public class VideoController {
static final private int WEBCAM_DEVICE_INDEX = 0;
int AUDIO_DEVICE_INDEX = 4;
Thread previewThread;
Frame capturedFrame = null;
private final int captureWidth = 1280;
private final int captureHeight = 720;
private final String filename = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss"));
FFmpegFrameRecorder recorder = new FFmpegFrameRecorder("C:/Users/jhuliano-vasconcelos/Videos/" + filename + ".avi", captureWidth, captureHeight, 2);
static final OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(WEBCAM_DEVICE_INDEX);
static boolean isGrabberActive = false;
static volatile boolean isRecording;
private int FRAME_RATE = 30;
public static void startGrabber() throws FrameGrabber.Exception {
grabber.start();
setGrabberActive(true);
}
public static void setGrabberActive(boolean isGrabberActive) { VideoController.isGrabberActive = isGrabberActive; }
public boolean isGrabberActive() { return isGrabberActive; }
public void setIsRecording(boolean isRecording) { VideoController.isRecording = isRecording; }
public void startPreview(ImageView videoView) {
stopPreview();
previewThread = new Thread(() -> {
try {
Frame capturedFrame = null;
while (!Thread.currentThread().isInterrupted() && (capturedFrame = grabber.grab()) != null) {
videoView.setImage(new JavaFXFrameConverter().convert(capturedFrame));
}
} catch (FrameGrabber.Exception e) {
throw new RuntimeException(e);
}
});
previewThread.start();
}
public void stopPreview() {
if (previewThread != null) {
previewThread.interrupt();
try {
previewThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
previewThread = null;
}
}
Thread recordAudio = new Thread(() -> {
AudioFormat audioFormat = new AudioFormat(44100.0F, 16, 2, true, false);
Mixer.Info[] minfoSet = AudioSystem.getMixerInfo();
Mixer mixer = AudioSystem.getMixer(minfoSet[AUDIO_DEVICE_INDEX]);
DataLine.Info dataLineInfo = new DataLine.Info(TargetDataLine.class, audioFormat);
try {
TargetDataLine line = (TargetDataLine)AudioSystem.getLine(dataLineInfo);
line.open(audioFormat);
line.start();
int sampleRate = (int) audioFormat.getSampleRate();
int numChannels = audioFormat.getChannels();
int audioBufferSize = sampleRate * numChannels;
byte[] audioBytes = new byte[audioBufferSize];
ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(1);
exec.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
try {
int nBytesRead = 0;
while (nBytesRead == 0) {
nBytesRead = line.read(audioBytes, 0, line.available());
}
int nSamplesRead = nBytesRead / 2;
short[] samples = new short[nSamplesRead];
ByteBuffer.wrap(audioBytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(samples);
ShortBuffer sBuff = ShortBuffer.wrap(samples, 0, nSamplesRead);
recorder.recordSamples(sampleRate, numChannels, sBuff);
}
catch (org.bytedeco.javacv.FrameRecorder.Exception e) {
e.printStackTrace();
}
}
}, 0, (long) 1000 / FRAME_RATE, TimeUnit.MILLISECONDS);
}
catch (LineUnavailableException e1) {
e1.printStackTrace();
}
});
public void setupVideoRecorder() throws FFmpegFrameRecorder.Exception {
int GOP_LENGTH_IN_FRAMES = 60;
recorder.setInterleaved(true);
recorder.setVideoOption("tune", "zerolatency");
recorder.setVideoOption("preset", "ultrafast");
recorder.setVideoOption("crf", "28");
recorder.setVideoBitrate(2000000);
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
recorder.setFormat("avi");
recorder.setFrameRate(FRAME_RATE);
recorder.setGopSize(GOP_LENGTH_IN_FRAMES);
recorder.setAudioOption("crf", "0");
recorder.setAudioQuality(0);
recorder.setAudioBitrate(192000);
recorder.setSampleRate(44100);
recorder.setAudioChannels(2);
recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
recorder.start();
}
Thread recordThread = new Thread(() -> {
try {
long startTime = 0;
long videoTS = 0;
while (!isRecording) Thread.onSpinWait();
setupVideoRecorder();
recordAudio.start();
while ((capturedFrame = grabber.grab()) != null && isRecording) {
if (startTime == 0)
startTime = System.currentTimeMillis();
videoTS = 1000 * (System.currentTimeMillis() - startTime);
if (videoTS > recorder.getTimestamp())
recorder.setTimestamp(videoTS);
recorder.record(capturedFrame);
}
} catch (FFmpegFrameRecorder.Exception | FrameGrabber.Exception e) {
throw new RuntimeException(e);
}
});
public void startRecording() throws FrameGrabber.Exception, FFmpegFrameRecorder.Exception, InterruptedException {
recordThread.start();
}
public void stopRecording() throws FrameRecorder.Exception, FrameGrabber.Exception {
isRecording = false; // Signal recording thread to stop
recordAudio.interrupt();
recordThread.interrupt();
// Wait for the threads to finish
try {
recordThread.join();
recordAudio.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
recorder.stop();
recorder.release();
recorder = null;
}
}