ATS-812: PoC FFmpeg (experimental) - add duration (in addition to timeOffset) to enable video/audio trim

- only set default frames num (1) if target is a supported image format (note: currently configured for jpg and png)
This commit is contained in:
Jan Vonka
2022-01-06 18:05:10 +00:00
parent 9f18bd5936
commit ec5a813cd8
7 changed files with 71 additions and 7 deletions

View File

@@ -38,6 +38,8 @@ import java.io.File;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
import static org.alfresco.transformer.util.RequestParamMap.FRAMES_NUM;
/** /**
* Controller for the FFmpeg transformer. * Controller for the FFmpeg transformer.
* *
@@ -67,6 +69,14 @@ public class FFmpegController extends AbstractTransformerController
FFmpegController FFmpegController
.class); .class);
public static final String PREFIX_IMAGE = "image/";
public static final String FILE_EXT_PNG = "png";
public static final String FILE_EXT_JPG = "jpg";
public static final String FILE_EXT_JPEG = "jpeg";
private static final int DEFAULT_FRAMES_NUM_1 = 1;
@Value("${transform.core.ffmpeg.exe}") @Value("${transform.core.ffmpeg.exe}")
private String execPath; private String execPath;
@@ -117,6 +127,34 @@ public class FFmpegController extends AbstractTransformerController
public void transformImpl(String transformName, String sourceMimetype, String targetMimetype, public void transformImpl(String transformName, String sourceMimetype, String targetMimetype,
Map<String, String> transformOptions, File sourceFile, File targetFile) Map<String, String> transformOptions, File sourceFile, File targetFile)
{ {
// TODO PoC FFmpeg - initially "single frame" for image target
if (isTargetImage(targetMimetype, targetFile))
{
transformOptions.put(FRAMES_NUM, Integer.toString(DEFAULT_FRAMES_NUM_1));
}
commandExecutor.transform(sourceMimetype, targetMimetype, transformOptions, sourceFile, targetFile); commandExecutor.transform(sourceMimetype, targetMimetype, transformOptions, sourceFile, targetFile);
} }
// TODO PoC FFmpeg - refactor and enhance (for configured / supported image formats etc)
private boolean isTargetImage(String targetMimetype, File targetFile)
{
if ((targetMimetype != null) && (targetMimetype.startsWith(PREFIX_IMAGE)))
{
return true;
}
if (targetFile != null) {
String[] split = targetFile.getName().split("\\.");
if (split.length > 0) {
String ext = split[split.length - 1];
return (FILE_EXT_JPEG.equalsIgnoreCase(ext) ||
FILE_EXT_JPG.equalsIgnoreCase(ext) ||
FILE_EXT_PNG.equalsIgnoreCase(ext));
}
}
return false;
}
} }

View File

@@ -11,6 +11,7 @@
<tr><td><div style="text-align:right">testDelay</div></td><td><input type="text" name="testDelay" value="" /></td></tr> <tr><td><div style="text-align:right">testDelay</div></td><td><input type="text" name="testDelay" value="" /></td></tr>
<tr><td><div style="text-align:right">timeOffset</div></td><td><input type="text" name="timeOffset" value="" /></td></tr> <tr><td><div style="text-align:right">timeOffset</div></td><td><input type="text" name="timeOffset" value="" /></td></tr>
<tr><td><div style="text-align:right">duration</div></td><td><input type="text" name="duration" value="" /></td></tr>
<tr><td></td><td><input type="submit" value="Transform" /></td></tr> <tr><td></td><td><input type="submit" value="Transform" /></td></tr>
</table> </table>

View File

@@ -1,7 +1,8 @@
{ {
"transformOptions": { "transformOptions": {
"ffmpegOptions": [ "ffmpegOptions": [
{"value": {"name": "timeOffset"}} {"value": {"name": "timeOffset"}},
{"value": {"name": "duration"}}
] ]
}, },
"transformers": [ "transformers": [

View File

@@ -37,6 +37,8 @@ import java.util.StringJoiner;
public final class FFmpegOptionsBuilder public final class FFmpegOptionsBuilder
{ {
private String timeOffset; private String timeOffset;
private String duration;
private Integer framesNum; private Integer framesNum;
// TODO PoC - add other FFmpeg transform options ... // TODO PoC - add other FFmpeg transform options ...
@@ -54,6 +56,12 @@ public final class FFmpegOptionsBuilder
return this; return this;
} }
public FFmpegOptionsBuilder withDuration(final String duration)
{
this.duration = duration;
return this;
}
public String build() public String build()
{ {
StringJoiner args = new StringJoiner(" "); StringJoiner args = new StringJoiner(" ");
@@ -68,6 +76,11 @@ public final class FFmpegOptionsBuilder
args.add("-frames:v "+framesNum); args.add("-frames:v "+framesNum);
} }
if (duration != null)
{
args.add("-t "+duration);
}
return args.toString(); return args.toString();
} }

View File

@@ -33,8 +33,8 @@ import java.io.File;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import static org.alfresco.transformer.util.RequestParamMap.TIMEOUT; import static org.alfresco.transformer.util.RequestParamMap.*;
import static org.alfresco.transformer.util.RequestParamMap.TIME_OFFSET; import static org.alfresco.transformer.util.Util.stringToInteger;
import static org.alfresco.transformer.util.Util.stringToLong; import static org.alfresco.transformer.util.Util.stringToLong;
/** /**
@@ -78,7 +78,9 @@ public class FFmpegCommandExecutor extends AbstractCommandExecutor
RuntimeExec runtimeExec = new RuntimeExec(); RuntimeExec runtimeExec = new RuntimeExec();
Map<String, String[]> commandsAndArguments = new HashMap<>(); Map<String, String[]> commandsAndArguments = new HashMap<>();
// TODO PoC for FFmpeg - check against Gytheio: -y SPLIT:${sourceOptions} -i ${source} SPLIT:${targetOptions} ${target} // TODO PoC for FFmpeg
// - for now, current options are all target options (ie. after -i)
// - check against Gytheio: -y SPLIT:${sourceOptions} -i ${source} SPLIT:${targetOptions} ${target}
commandsAndArguments.put(".*", commandsAndArguments.put(".*",
new String[]{EXE, "-y", "-i", "${source}", "SPLIT:${options}", "${target}"}); new String[]{EXE, "-y", "-i", "${source}", "SPLIT:${options}", "${target}"});
@@ -113,11 +115,17 @@ public class FFmpegCommandExecutor extends AbstractCommandExecutor
String timeOffset = transformOptions.get(TIME_OFFSET); String timeOffset = transformOptions.get(TIME_OFFSET);
if (timeOffset != null) if (timeOffset != null)
{ {
// TODO check target mimetype (to be supported image formats) for "single frame" option
optionsBuilder.withTimeOffset(transformOptions.get(TIME_OFFSET)); optionsBuilder.withTimeOffset(transformOptions.get(TIME_OFFSET));
optionsBuilder.withFramesNum(FRAMES_NUM_1);
} }
String duration = transformOptions.get(DURATION);
if (duration != null)
{
optionsBuilder.withDuration(transformOptions.get(DURATION));
}
optionsBuilder.withFramesNum(stringToInteger(transformOptions.get(FRAMES_NUM)));
final String options = optionsBuilder.build(); final String options = optionsBuilder.build();
Long timeout = stringToLong(transformOptions.get(TIMEOUT)); Long timeout = stringToLong(transformOptions.get(TIMEOUT));

View File

@@ -1,7 +1,8 @@
{ {
"transformOptions": { "transformOptions": {
"ffmpegOptions": [ "ffmpegOptions": [
{"value": {"name": "timeOffset"}} {"value": {"name": "timeOffset"}},
{"value": {"name": "duration"}}
] ]
}, },
"transformers": [ "transformers": [

View File

@@ -75,4 +75,6 @@ public interface RequestParamMap
// TODO PoC for FFmpeg // TODO PoC for FFmpeg
String TIME_OFFSET = "timeOffset"; String TIME_OFFSET = "timeOffset";
String DURATION = "duration";
String FRAMES_NUM = "framesNum";
} }