From b8c1463b359871c9a07a249ea8fd4e73a1c20984 Mon Sep 17 00:00:00 2001 From: Jan Vonka Date: Tue, 30 Mar 2021 16:36:01 +0100 Subject: [PATCH] ATS-812: PoC FFmpeg skeleton - experiments - add PoC option to convert from mp4 to either image/png or image/png - single frame based on timeOffset param (example format "00:00:00.5") - transform option names & support mimetypes subject to change - requires detailed design + (unit) regression tests - see also MM-156 --- .../resources/templates/transformForm.html | 2 ++ .../test/resources/ffmpeg_engine_config.json | 10 ++++++- .../transformer/FFmpegOptionsBuilder.java | 27 ++++++++++++++++++- .../executors/FFmpegCommandExecutor.java | 22 +++++++++++---- .../main/resources/ffmpeg_engine_config.json | 5 +++- .../transformer/util/RequestParamMap.java | 3 +++ 6 files changed, 61 insertions(+), 8 deletions(-) diff --git a/alfresco-transform-ffmpeg/alfresco-transform-ffmpeg-boot/src/main/resources/templates/transformForm.html b/alfresco-transform-ffmpeg/alfresco-transform-ffmpeg-boot/src/main/resources/templates/transformForm.html index 1151be1e..829da15a 100644 --- a/alfresco-transform-ffmpeg/alfresco-transform-ffmpeg-boot/src/main/resources/templates/transformForm.html +++ b/alfresco-transform-ffmpeg/alfresco-transform-ffmpeg-boot/src/main/resources/templates/transformForm.html @@ -10,6 +10,8 @@
timeout
testDelay
+
timeOffset
+ diff --git a/alfresco-transform-ffmpeg/alfresco-transform-ffmpeg-boot/src/test/resources/ffmpeg_engine_config.json b/alfresco-transform-ffmpeg/alfresco-transform-ffmpeg-boot/src/test/resources/ffmpeg_engine_config.json index 446f2524..cef69ef5 100644 --- a/alfresco-transform-ffmpeg/alfresco-transform-ffmpeg-boot/src/test/resources/ffmpeg_engine_config.json +++ b/alfresco-transform-ffmpeg/alfresco-transform-ffmpeg-boot/src/test/resources/ffmpeg_engine_config.json @@ -1,12 +1,20 @@ { "transformOptions": { + "ffmpegOptions": [ + {"value": {"name": "timeOffset"}} + ] }, "transformers": [ { "transformerName": "ffmpeg", "supportedSourceAndTargetList": [ {"sourceMediaType": "video/mp4", "targetMediaType": "video/avi" }, - {"sourceMediaType": "video/mp4", "targetMediaType": "audio/mpeg" } + {"sourceMediaType": "video/mp4", "targetMediaType": "audio/mpeg" }, + {"sourceMediaType": "video/mp4", "targetMediaType": "image/png" }, + {"sourceMediaType": "video/mp4", "targetMediaType": "image/jpeg" } + ], + "transformOptions": [ + "ffmpegOptions" ] } ] diff --git a/alfresco-transform-ffmpeg/alfresco-transform-ffmpeg/src/main/java/org/alfresco/transformer/FFmpegOptionsBuilder.java b/alfresco-transform-ffmpeg/alfresco-transform-ffmpeg/src/main/java/org/alfresco/transformer/FFmpegOptionsBuilder.java index e06ce878..fdde9aa6 100644 --- a/alfresco-transform-ffmpeg/alfresco-transform-ffmpeg/src/main/java/org/alfresco/transformer/FFmpegOptionsBuilder.java +++ b/alfresco-transform-ffmpeg/alfresco-transform-ffmpeg/src/main/java/org/alfresco/transformer/FFmpegOptionsBuilder.java @@ -2,7 +2,7 @@ * #%L * Alfresco Transform Core * %% - * Copyright (C) 2005 - 2020 Alfresco Software Limited + * Copyright (C) 2005 - 2021 Alfresco Software Limited * %% * This file is part of the Alfresco software. * - @@ -36,13 +36,38 @@ import java.util.StringJoiner; // TODO PoC for FFmpeg public final class FFmpegOptionsBuilder { + private String timeOffset; + private Integer framesNum; + // TODO PoC - add FFmpeg options ... private FFmpegOptionsBuilder() {} + public FFmpegOptionsBuilder withTimeOffset(final String timeOffset) + { + this.timeOffset = timeOffset; + return this; + } + + public FFmpegOptionsBuilder withFramesNum(final Integer framesNum) + { + this.framesNum = framesNum; + return this; + } + public String build() { StringJoiner args = new StringJoiner(" "); + if (timeOffset != null) + { + args.add("-ss "+timeOffset); + } + + if (framesNum != null) + { + args.add("-frames:v "+framesNum); + } + return args.toString(); } diff --git a/alfresco-transform-ffmpeg/alfresco-transform-ffmpeg/src/main/java/org/alfresco/transformer/executors/FFmpegCommandExecutor.java b/alfresco-transform-ffmpeg/alfresco-transform-ffmpeg/src/main/java/org/alfresco/transformer/executors/FFmpegCommandExecutor.java index 2e24e794..980b245b 100644 --- a/alfresco-transform-ffmpeg/alfresco-transform-ffmpeg/src/main/java/org/alfresco/transformer/executors/FFmpegCommandExecutor.java +++ b/alfresco-transform-ffmpeg/alfresco-transform-ffmpeg/src/main/java/org/alfresco/transformer/executors/FFmpegCommandExecutor.java @@ -2,7 +2,7 @@ * #%L * Alfresco Transform Core * %% - * Copyright (C) 2005 - 2020 Alfresco Software Limited + * Copyright (C) 2005 - 2021 Alfresco Software Limited * %% * This file is part of the Alfresco software. * - @@ -33,7 +33,9 @@ import java.io.File; import java.util.HashMap; import java.util.Map; +import static org.alfresco.transformer.util.RequestParamMap.START_PAGE; import static org.alfresco.transformer.util.RequestParamMap.TIMEOUT; +import static org.alfresco.transformer.util.RequestParamMap.TIME_OFFSET; import static org.alfresco.transformer.util.Util.stringToLong; /** @@ -50,6 +52,8 @@ public class FFmpegCommandExecutor extends AbstractCommandExecutor private final String EXE; + private final int FRAMES_NUM_1 = 1; + public FFmpegCommandExecutor(String exe) { if (exe == null || exe.isEmpty()) @@ -75,7 +79,7 @@ public class FFmpegCommandExecutor extends AbstractCommandExecutor // TODO PoC for FFmpeg - check against Gytheio: -y SPLIT:${sourceOptions} -i ${source} SPLIT:${targetOptions} ${target} commandsAndArguments.put(".*", - new String[]{EXE, "-y", "-i", "SPLIT:${options}", "${source}", "${target}"}); + new String[]{EXE, "-y", "-i", "${source}", "SPLIT:${options}", "${target}"}); runtimeExec.setCommandsAndArguments(commandsAndArguments); @@ -103,9 +107,17 @@ public class FFmpegCommandExecutor extends AbstractCommandExecutor Map transformOptions, File sourceFile, File targetFile) throws TransformException { - final String options = FFmpegOptionsBuilder - .builder() - .build(); + FFmpegOptionsBuilder optionsBuilder = FFmpegOptionsBuilder.builder(); + + String timeOffset = transformOptions.get(TIME_OFFSET); + if (timeOffset != null) + { + // TODO check target mimetype (to be supported image formats) for "single frame" option + optionsBuilder.withTimeOffset(transformOptions.get(TIME_OFFSET)); + optionsBuilder.withFramesNum(FRAMES_NUM_1); + } + + final String options = optionsBuilder.build(); Long timeout = stringToLong(transformOptions.get(TIMEOUT)); diff --git a/alfresco-transform-ffmpeg/alfresco-transform-ffmpeg/src/main/resources/ffmpeg_engine_config.json b/alfresco-transform-ffmpeg/alfresco-transform-ffmpeg/src/main/resources/ffmpeg_engine_config.json index 2c0ff4b4..cef69ef5 100644 --- a/alfresco-transform-ffmpeg/alfresco-transform-ffmpeg/src/main/resources/ffmpeg_engine_config.json +++ b/alfresco-transform-ffmpeg/alfresco-transform-ffmpeg/src/main/resources/ffmpeg_engine_config.json @@ -1,6 +1,7 @@ { "transformOptions": { "ffmpegOptions": [ + {"value": {"name": "timeOffset"}} ] }, "transformers": [ @@ -8,7 +9,9 @@ "transformerName": "ffmpeg", "supportedSourceAndTargetList": [ {"sourceMediaType": "video/mp4", "targetMediaType": "video/avi" }, - {"sourceMediaType": "video/mp4", "targetMediaType": "audio/mpeg" } + {"sourceMediaType": "video/mp4", "targetMediaType": "audio/mpeg" }, + {"sourceMediaType": "video/mp4", "targetMediaType": "image/png" }, + {"sourceMediaType": "video/mp4", "targetMediaType": "image/jpeg" } ], "transformOptions": [ "ffmpegOptions" diff --git a/alfresco-transformer-base/src/main/java/org/alfresco/transformer/util/RequestParamMap.java b/alfresco-transformer-base/src/main/java/org/alfresco/transformer/util/RequestParamMap.java index 2dd44310..812ebeea 100644 --- a/alfresco-transformer-base/src/main/java/org/alfresco/transformer/util/RequestParamMap.java +++ b/alfresco-transformer-base/src/main/java/org/alfresco/transformer/util/RequestParamMap.java @@ -72,4 +72,7 @@ public interface RequestParamMap String INCLUDE_CONTENTS = "includeContents"; String NOT_EXTRACT_BOOKMARK_TEXT = "notExtractBookmarksText"; String PAGE_LIMIT = "pageLimit"; + + // TODO PoC for FFmpeg + String TIME_OFFSET = "timeOffset"; }