Improve thumbnail creation
All checks were successful
Build and push container / Build-Docker-Container (push) Successful in 5m44s
All checks were successful
Build and push container / Build-Docker-Container (push) Successful in 5m44s
This commit is contained in:
parent
a45b809a99
commit
444e42c091
@ -85,6 +85,7 @@ public class VideoBase {
|
||||
private static void loadLibrary() {
|
||||
library = Library.load(Path.of(config.getLibraryPath()), config.isReadOnly());
|
||||
ThumbnailCreator.clearCache();
|
||||
ThumbnailCreator.createThumbnails();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -157,7 +157,7 @@ public class LibraryAPI implements EndpointCollection {
|
||||
return;
|
||||
}
|
||||
|
||||
BufferedImage thumbnail = ThumbnailCreator.createThumbnail(video);
|
||||
BufferedImage thumbnail = ThumbnailCreator.getThumbnail(video);
|
||||
if(thumbnail == null) {
|
||||
ctx.respond(HttpStatusCodes.NOT_FOUND_404, new TextResponse("No thumbnail found"));
|
||||
return;
|
||||
|
@ -8,8 +8,10 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
@ -19,33 +21,34 @@ import me.mrletsplay.videobase.library.Video;
|
||||
|
||||
public class ThumbnailCreator {
|
||||
|
||||
private static Map<String, BufferedImage> cachedThumbnails = new HashMap<>();
|
||||
private static Map<String, BufferedImage> cachedThumbnails = new ConcurrentHashMap<>();
|
||||
private static ExecutorService executorService = Executors.newFixedThreadPool(10);
|
||||
|
||||
public static void clearCache() {
|
||||
cachedThumbnails.clear();
|
||||
}
|
||||
|
||||
public static void createThumbnails() {
|
||||
for(Video v : VideoBase.getLibrary().getVideos()) {
|
||||
executorService.submit(() -> createThumbnail(v));
|
||||
}
|
||||
}
|
||||
|
||||
public static BufferedImage createThumbnail(Video video) {
|
||||
if(cachedThumbnails.containsKey(video.getId())) {
|
||||
return cachedThumbnails.get(video.getId());
|
||||
}
|
||||
|
||||
String cachePath = VideoBase.getConfig().getCachePath();
|
||||
Path thumbnailFile = null;
|
||||
Path thumbnailFile = cachePath == null ? null : Path.of(cachePath).resolve("thumbnails").resolve(video.getId() + ".png").toAbsolutePath();
|
||||
|
||||
if(cachePath != null) {
|
||||
thumbnailFile = Path.of(cachePath).resolve("thumbnails").resolve(video.getId() + ".png").toAbsolutePath();
|
||||
if(thumbnailFile != null && Files.isRegularFile(thumbnailFile)) {
|
||||
try(InputStream in = Files.newInputStream(thumbnailFile)) {
|
||||
BufferedImage thumbnail = ImageIO.read(in);
|
||||
if(thumbnail == null) return null;
|
||||
|
||||
try {
|
||||
if(Files.exists(thumbnailFile)) {
|
||||
try(InputStream in = Files.newInputStream(thumbnailFile)) {
|
||||
BufferedImage thumbnail = ImageIO.read(in);
|
||||
if(thumbnail == null) return null;
|
||||
|
||||
cachedThumbnails.put(video.getId(), thumbnail);
|
||||
return thumbnail;
|
||||
}
|
||||
}
|
||||
cachedThumbnails.put(video.getId(), thumbnail);
|
||||
return thumbnail;
|
||||
} catch (IOException e) {
|
||||
VideoBase.LOGGER.warn("Failed to load thumbnail", e);
|
||||
return null;
|
||||
@ -54,8 +57,8 @@ public class ThumbnailCreator {
|
||||
|
||||
ProcessBuilder ffmpegBuilder = new ProcessBuilder("ffmpeg",
|
||||
"-i", video.getPath().toAbsolutePath().toString(),
|
||||
"-vf", "thumbnail",
|
||||
"-vf", "scale=960:540:force_original_aspect_ratio=decrease,pad=960:540:-1:-1:color=black",
|
||||
"-r", "0.5",
|
||||
"-vf", "thumbnail,scale=960:540:force_original_aspect_ratio=decrease,pad=960:540:-1:-1:color=black",
|
||||
"-frames:v", "1",
|
||||
"-f", "image2pipe",
|
||||
"-vcodec", "png",
|
||||
@ -69,18 +72,18 @@ public class ThumbnailCreator {
|
||||
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
|
||||
byte[] buf = new byte[1024];
|
||||
int len;
|
||||
while(System.currentTimeMillis() - start < 1000
|
||||
&& (len = ffmpeg.getInputStream().read(buf)) > 0) {
|
||||
while(System.currentTimeMillis() - start < 60000
|
||||
&& (len = ffmpeg.getInputStream().read(buf)) != -1) {
|
||||
bOut.write(buf, 0, len);
|
||||
}
|
||||
|
||||
ffmpeg.waitFor(10, TimeUnit.SECONDS);
|
||||
ffmpeg.waitFor(60, TimeUnit.SECONDS);
|
||||
if(ffmpeg.isAlive()) {
|
||||
VideoBase.LOGGER.warn("ffmpeg didn't exit after 10 seconds, destroying");
|
||||
VideoBase.LOGGER.warn("Video " + video.getId() + ": ffmpeg didn't exit after 60 seconds, destroying");
|
||||
ffmpeg.destroy();
|
||||
|
||||
if(!ffmpeg.waitFor(10, TimeUnit.SECONDS)) {
|
||||
VideoBase.LOGGER.warn("ffmpeg didn't exit 10 seconds after destroying, destroying forcibly");
|
||||
if(!ffmpeg.waitFor(60, TimeUnit.SECONDS)) {
|
||||
VideoBase.LOGGER.warn("Video " + video.getId() + ": ffmpeg didn't exit 60 seconds after destroying, destroying forcibly");
|
||||
ffmpeg.destroyForcibly();
|
||||
}
|
||||
|
||||
@ -97,14 +100,17 @@ public class ThumbnailCreator {
|
||||
}
|
||||
}
|
||||
|
||||
VideoBase.LOGGER.debug("Created thumbnail for video at " + video.getPath());
|
||||
cachedThumbnails.put(video.getId(), thumbnail);
|
||||
return thumbnail;
|
||||
} catch (InterruptedException | IOException e) {
|
||||
VideoBase.LOGGER.warn("Failed to create thumbnail", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static BufferedImage getThumbnail(Video video) {
|
||||
return cachedThumbnails.get(video.getId());
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user