package com.aimmac23.node;
import java.io.File;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
public class VideoRecordController {
private static final Logger log = Logger.getLogger(RecordVideoCallable.class.getSimpleName());
private ThreadPoolExecutor executor;
RecordVideoCallable currentCallable;
private Future<File> currentFuture;
private final int targetFramerate;
private ScreenshotSource screenshotSource;
public VideoRecordController() {
executor = new ThreadPoolExecutor(1, 1, 1, TimeUnit.MINUTES, new ArrayBlockingQueue<Runnable>(5));
executor.setThreadFactory(new RecorderThreadFactory());
executor.prestartAllCoreThreads();
String framerateString = System.getProperty("video.framerate", "15");
String xvfbLocationString = System.getProperty("video.xvfbscreen", null);
File xvfbLocation = null;
if(xvfbLocationString != null) {
File xvfbDirectory = new File(xvfbLocationString);
File xvfbFile = new File(xvfbDirectory, "Xvfb_screen0");
if(!xvfbFile.exists()) {
throw new IllegalStateException("Xvfb Screen location not found: " + xvfbFile);
}
else if(!xvfbFile.isFile()) {
throw new IllegalStateException("Xvfb Screen location is not a file: " + xvfbFile);
}
else {
xvfbLocation = xvfbFile;
}
}
else {
xvfbLocation = null;
}
targetFramerate = Integer.parseInt(framerateString);
log.info("Will attempt to record at " + targetFramerate + " frames per second - adjust this value " +
" by setting -Dvideo.framerate=<value>");
try {
if(xvfbLocation != null) {
screenshotSource = new XvfbFileScreenshotSource(xvfbLocation);
log.info("Using Xvfb acceleration");
}
else {
screenshotSource = new RobotScreenshotSource();
}
screenshotSource.doStartupSanityChecks();
}
catch(Exception e) {
throw new IllegalStateException("Could not create screenshot source for video encoder", e);
}
}
public void startRecording() throws Exception {
if(currentCallable != null) {
throw new IllegalStateException("Video recording currently in progress, cannot record again");
}
currentCallable = new RecordVideoCallable(targetFramerate, screenshotSource);
currentFuture = executor.submit(currentCallable);
}
public File stopRecording() throws Exception {
if(currentCallable == null) {
throw new IllegalStateException("Video recording not currently in progress, cannot stop!");
}
// sleep for half a second, to make sure we catch the end of the test
// XXX: Do we really need this?
Thread.sleep(500);
currentCallable.stopRecording();
currentCallable = null;
return currentFuture.get();
}
public void resetRecording() {
// if we are currently recording, stop
if(currentCallable != null) {
currentCallable.stopRecording();
currentCallable = null;
log.info("Stopped recording due to resetRecording being called");
}
else {
log.info("resetRecording called but not recording - nothing to do");
}
}
class RecorderThreadFactory implements ThreadFactory {
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setDaemon(true);
thread.setName("VideoRecordingThread");
return thread;
}
}
}