From a476ecc7227c44bdeb21693644faff4dbf395c6a Mon Sep 17 00:00:00 2001 From: Jonathan Cobb Date: Sat, 12 Dec 2020 11:07:02 -0500 Subject: [PATCH] add support for trim operation --- src/main/java/jvcl/model/JAsset.java | 4 +- src/main/java/jvcl/op/TrimOperation.java | 96 +++++++++++++++++++++++ src/test/java/javicle/test/BasicTest.java | 6 +- src/test/resources/tests/test_trim.json | 19 +++++ utils/cobbzilla-utils | 2 +- 5 files changed, 122 insertions(+), 5 deletions(-) create mode 100644 src/test/resources/tests/test_trim.json diff --git a/src/main/java/jvcl/model/JAsset.java b/src/main/java/jvcl/model/JAsset.java index a5f5ef8..15feb60 100644 --- a/src/main/java/jvcl/model/JAsset.java +++ b/src/main/java/jvcl/model/JAsset.java @@ -82,7 +82,9 @@ public class JAsset { } - public boolean destIsDirectory() { return new File(dest).isDirectory(); } + public boolean destIsDirectory() { + return hasDest() && (dest.endsWith("/") || new File(dest).isDirectory()); + } public File destDirectory() { return mkdirOrDie(new File(dest.endsWith("/") ? dest.substring(0, dest.length()-1) : dest)); } diff --git a/src/main/java/jvcl/op/TrimOperation.java b/src/main/java/jvcl/op/TrimOperation.java index 31a2d8f..f5a71aa 100644 --- a/src/main/java/jvcl/op/TrimOperation.java +++ b/src/main/java/jvcl/op/TrimOperation.java @@ -1,14 +1,110 @@ package jvcl.op; +import jvcl.model.JAsset; +import jvcl.model.JFileExtension; import jvcl.model.JOperation; import jvcl.service.AssetManager; import jvcl.service.JOperator; import jvcl.service.Toolbox; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.cobbzilla.util.handlebars.HandlebarsUtil; +import java.io.File; +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.Map; + +import static jvcl.model.JAsset.json2asset; +import static jvcl.service.Toolbox.getDuration; +import static org.cobbzilla.util.daemon.ZillaRuntime.die; +import static org.cobbzilla.util.daemon.ZillaRuntime.empty; +import static org.cobbzilla.util.io.FileUtil.*; +import static org.cobbzilla.util.json.JsonUtil.json; +import static org.cobbzilla.util.system.CommandShell.execScript; + +@Slf4j public class TrimOperation implements JOperator { + public static final String TRIM_TEMPLATE + = "{{ffmpeg}} -i {{{source.path}}} -ss {{startSeconds}} {{#exists interval}}-t {{interval}} {{/exists}}{{{output.path}}}"; + @Override public void operate(JOperation op, Toolbox toolbox, AssetManager assetManager) { + final TrimConfig config = json(json(op.getPerform()), TrimConfig.class); + final JAsset source = assetManager.resolve(config.getTrim()); + + final JAsset output = json2asset(op.getCreates()); + output.mergeFormat(source.getFormat()); + + final JFileExtension formatType = output.getFormat().getFileExtension(); + + if (source.hasList()) { + if (output.hasDest()) { + if (!output.destIsDirectory()) die("operate: dest is not a directory: "+output.getDest()); + } + assetManager.addOperationArrayAsset(output); + for (JAsset asset : source.getList()) { + final JAsset subOutput = new JAsset(output); + final File defaultOutfile = assetManager.assetPath(op, asset, formatType, new Object[]{config}); + final File outfile; + if (output.hasDest()) { + outfile = new File(output.destDirectory(), basename(appendToFileNameBeforeExt(asset.getPath(), "_"+config.shortString()))); + } else { + outfile = defaultOutfile; + } + subOutput.setPath(abs(outfile)); + trim(config, asset, subOutput, toolbox, assetManager); + } + } else { + if (output.hasDest() && output.destExists()) { + log.info("operate: dest exists, not trimming: "+output.getDest()); + } else { + trim(config, source, output, toolbox, assetManager); + } + } + } + + private void trim(TrimConfig config, + JAsset source, + JAsset output, + Toolbox toolbox, + AssetManager assetManager) { + if (output.destExists()) { + log.info("trim: dest exists: "+output.getDest()); + return; + } + final Map ctx = new HashMap<>(); + ctx.put("ffmpeg", toolbox.getFfmpeg()); + ctx.put("source", source); + ctx.put("output", output); + + final BigDecimal startTime = config.getStartTime(); + ctx.put("startSeconds", startTime); + if (config.hasEnd()) ctx.put("interval", config.getEndTime().subtract(startTime)); + final String script = HandlebarsUtil.apply(toolbox.getHandlebars(), TRIM_TEMPLATE, ctx); + + log.debug("operate: running script: "+script); + final String scriptOutput = execScript(script); + log.debug("operate: command output: "+scriptOutput); + assetManager.addOperationAssetSlice(output, output); } + @NoArgsConstructor @EqualsAndHashCode + private static class TrimConfig { + @Getter @Setter private String trim; + + @Getter @Setter private String start; + public BigDecimal getStartTime() { return empty(start) ? BigDecimal.ZERO : getDuration(start); } + + @Getter @Setter private String end; + public boolean hasEnd() { return !empty(end); } + public BigDecimal getEndTime() { return getDuration(end); } + + public String shortString() { return "trim_"+getStart()+(hasEnd() ? "_"+getEnd() : ""); } + public String toString() { return trim+"_"+getStart()+(hasEnd() ? "_"+getEnd() : ""); } + } } diff --git a/src/test/java/javicle/test/BasicTest.java b/src/test/java/javicle/test/BasicTest.java index a3b41f2..ffd9904 100644 --- a/src/test/java/javicle/test/BasicTest.java +++ b/src/test/java/javicle/test/BasicTest.java @@ -13,9 +13,9 @@ import static org.cobbzilla.util.io.StreamUtil.stream2file; public class BasicTest { - @Test public void testSplit() { runSpec("tests/test_split.json"); } - - @Test public void testConcat() { runSpec("tests/test_concat.json"); } + @Test public void testSplit () { runSpec("tests/test_split.json"); } + @Test public void testConcat () { runSpec("tests/test_concat.json"); } + @Test public void testTrim () { runSpec("tests/test_trim.json"); } private void runSpec(String specPath) { @Cleanup("delete") final File specFile = stream2file(loadResourceAsStream(specPath)); diff --git a/src/test/resources/tests/test_trim.json b/src/test/resources/tests/test_trim.json new file mode 100644 index 0000000..796d733 --- /dev/null +++ b/src/test/resources/tests/test_trim.json @@ -0,0 +1,19 @@ +{ + "assets": [ + { "name": "vid1_splits", "path": "src/test/resources/outputs/vid1_splits_*.mp4" } + ], + "operations": [ + { + "operation": "trim", // name of the operation + "creates": { + "name": "vid1_trims", + "dest": "src/test/resources/outputs/trims/" + }, + "perform": { + "trim": "vid1_splits", // trim these source assets + "start": "1s", // cropped region starts here, default is zero + "end": "6s" // cropped region ends here, default is end of video + } + } + ] +} diff --git a/utils/cobbzilla-utils b/utils/cobbzilla-utils index 9f3bc57..64ef780 160000 --- a/utils/cobbzilla-utils +++ b/utils/cobbzilla-utils @@ -1 +1 @@ -Subproject commit 9f3bc574b0e9fc99b41b381116ff37a9b8844eaf +Subproject commit 64ef7809a0b7c8a2c34311092d606c75df36a9a7