@@ -2,11 +2,15 @@ package jvc.main; | |||
import jvc.model.JSpec; | |||
import jvc.model.operation.JValidationResult; | |||
import jvc.service.AssetManager; | |||
import jvc.service.JOperationValidationFailure; | |||
import jvc.service.JvcEngine; | |||
import jvc.service.Toolbox; | |||
import org.cobbzilla.util.main.BaseMain; | |||
import java.util.List; | |||
import static org.cobbzilla.util.daemon.ZillaRuntime.empty; | |||
public class Jvc extends BaseMain<JvcOptions> { | |||
@@ -31,10 +35,23 @@ public class Jvc extends BaseMain<JvcOptions> { | |||
final AssetManager assetManager = new AssetManager(toolbox, getOptions().scratchDir()); | |||
final JvcEngine opEngine = new JvcEngine(toolbox, assetManager, noExec); | |||
opEngine.runSpec(spec); | |||
try { | |||
opEngine.runSpec(spec); | |||
printCompleted(opEngine); | |||
} catch (JOperationValidationFailure e) { | |||
printCompleted(opEngine); | |||
final List<JValidationResult> results = e.getResults(); | |||
err(">>> jvc: operation (index="+e.getOperation().execIndex()+") failed: "); | |||
for (JValidationResult r : results) { | |||
err(r.toString()); | |||
} | |||
} | |||
} | |||
final int opCount = spec.getOperations().length; | |||
err(">>> jvc: completed " + opCount + " operation"+(opCount>1?"s":"")); | |||
private void printCompleted(JvcEngine opEngine) { | |||
final int opCount = opEngine.getCompleted().size(); | |||
err(">>> jvc: completed " + opCount + " operation" + (opCount > 1 ? "s" : "")); | |||
} | |||
} |
@@ -286,12 +286,12 @@ public class JAsset implements JsObjectView { | |||
@Override public Object toJs() { return new JAssetJs(this); } | |||
public static class JAssetJs { | |||
public Integer duration; | |||
public Double duration; | |||
public Integer width; | |||
public Integer height; | |||
public JAssetJs (JAsset asset) { | |||
final BigDecimal d = asset.duration(); | |||
this.duration = d == null ? null : d.intValue(); | |||
this.duration = d == null ? null : d.doubleValue(); | |||
final BigDecimal w = asset.width(); | |||
this.width = w == null ? null : w.intValue(); | |||
@@ -1,5 +1,6 @@ | |||
package jvc.model.operation; | |||
import com.fasterxml.jackson.annotation.JsonIgnore; | |||
import com.fasterxml.jackson.annotation.JsonTypeInfo; | |||
import com.fasterxml.jackson.databind.JsonNode; | |||
import jvc.model.JAsset; | |||
@@ -32,12 +33,17 @@ public abstract class JOperation { | |||
@Getter @Setter private String operation; | |||
@Getter @Setter private JsonNode creates; | |||
@Getter @Setter private JValidation[] validate; | |||
@Getter @Setter private boolean noExec = false; | |||
@Getter @Setter private JValidation[] validate; | |||
public boolean hasValidate() { return !empty(validate); } | |||
@Getter @Setter private String comment; | |||
public boolean hasComment () { return !empty(comment); } | |||
@JsonIgnore @Getter @Setter private Integer execIndex; | |||
public String execIndex() { return execIndex != null ? ""+execIndex : "(null)"; } | |||
public String hash(JAsset[] sources) { return hash(sources, null); } | |||
public String hash(JAsset[] sources, Object[] args) { | |||
@@ -6,13 +6,25 @@ import org.cobbzilla.util.javascript.JsEngine; | |||
import java.util.Map; | |||
import static jvc.service.Toolbox.evalBoolean; | |||
import static org.cobbzilla.util.daemon.ZillaRuntime.empty; | |||
public class JValidation { | |||
@Getter @Setter private String comment; | |||
@Getter @Setter private String test; | |||
@Getter @Setter private String comment; | |||
public boolean hasComment () { return !empty(comment); } | |||
public JValidationResult eval(Map<String, Object> ctx, JsEngine js) { | |||
try { | |||
return new JValidationResult(this, evalBoolean(test, ctx, js)); | |||
} catch (Exception e) { | |||
return new JValidationResult(this, e); | |||
} | |||
} | |||
public boolean eval(Map<String, Object> ctx, JsEngine js) { | |||
return js.evaluateBoolean(test, ctx); | |||
@Override public String toString() { | |||
return (hasComment() ? getComment() + " - " : "") + "TEST=" + getTest(); | |||
} | |||
} |
@@ -0,0 +1,41 @@ | |||
package jvc.model.operation; | |||
import lombok.AllArgsConstructor; | |||
import lombok.Getter; | |||
import lombok.Setter; | |||
import static org.cobbzilla.util.daemon.ZillaRuntime.shortError; | |||
@AllArgsConstructor | |||
public class JValidationResult { | |||
public JValidationResult(JValidation validation, boolean pass) { | |||
this.validation = validation; | |||
this.pass = pass; | |||
} | |||
public JValidationResult(JValidation validation, Exception e) { | |||
this.validation = validation; | |||
this.pass = false; | |||
this.exception = e; | |||
} | |||
@Getter private final JValidation validation; | |||
@Getter private final boolean pass; | |||
public boolean passed () { return pass; } | |||
public boolean failed () { return !passed(); } | |||
@Getter @Setter private Exception exception; | |||
public boolean hasException () { return exception != null; } | |||
@Override public String toString () { | |||
return validation.toString()+" : " | |||
+ (passed() | |||
? "PASS" | |||
: hasException() | |||
? shortError(exception) | |||
: "FAIL"); | |||
} | |||
} |
@@ -2,7 +2,6 @@ package jvc.operation; | |||
import jvc.model.JAsset; | |||
import org.cobbzilla.util.javascript.JsEngine; | |||
import org.cobbzilla.util.javascript.StandardJsEngine; | |||
import java.math.BigDecimal; | |||
import java.util.Map; | |||
@@ -23,7 +22,7 @@ public interface HasWidthAndHeight { | |||
default BigDecimal getHeight(Map<String, Object> ctx, JsEngine js) { return evalBig(getHeight(), ctx, js); } | |||
default void setProportionalWidthAndHeight(Map<String, Object> ctx, | |||
StandardJsEngine js, | |||
JsEngine js, | |||
JAsset asset) { | |||
if (hasWidth()) { | |||
final BigDecimal width = getWidth(ctx, js); | |||
@@ -3,7 +3,7 @@ package jvc.operation.exec; | |||
import jvc.model.operation.JSingleOperationContext; | |||
import jvc.operation.AdjustSpeedOperation; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.cobbzilla.util.javascript.StandardJsEngine; | |||
import org.cobbzilla.util.javascript.JsEngine; | |||
import java.math.BigDecimal; | |||
import java.util.Map; | |||
@@ -34,7 +34,7 @@ public class AdjustSpeedExec extends SingleOrMultiSourceExecBase<AdjustSpeedOper | |||
@Override protected void addCommandContext(AdjustSpeedOperation op, | |||
JSingleOperationContext opCtx, | |||
Map<String, Object> ctx) { | |||
final StandardJsEngine js = opCtx.toolbox.getJs(); | |||
final JsEngine js = opCtx.toolbox.getJs(); | |||
final BigDecimal factor = op.getFactor(ctx, js); | |||
ctx.put(op.getAudio().name(), true); | |||
@@ -31,7 +31,7 @@ public class ConcatExec extends ExecBase<ConcatOperation> { | |||
// output combined result | |||
+ "-map \"[v]\" -map \"[a]\" -y {{{output.path}}}"; | |||
@Override public void operate(ConcatOperation op, Toolbox toolbox, AssetManager assetManager) { | |||
@Override public Map<String, Object> operate(ConcatOperation op, Toolbox toolbox, AssetManager assetManager) { | |||
final JMultiOperationContext opCtx = op.getMultiInputContext(assetManager, toolbox); | |||
final List<JAsset> sources = opCtx.sources; | |||
@@ -40,7 +40,7 @@ public class ConcatExec extends ExecBase<ConcatOperation> { | |||
final File defaultOutfile = assetManager.assetPath(op, sources, formatType); | |||
final File path = resolveOutputPath(output, defaultOutfile); | |||
if (path == null) return; | |||
if (path == null) return null; | |||
output.setPath(abs(path)); | |||
final Map<String, Object> ctx = new HashMap<>(); | |||
@@ -53,6 +53,7 @@ public class ConcatExec extends ExecBase<ConcatOperation> { | |||
final String scriptOutput = exec(script, op.isNoExec()); | |||
log.debug("operate: command output: "+scriptOutput); | |||
assetManager.addOperationAsset(output); | |||
return ctx; | |||
} | |||
} |
@@ -21,7 +21,7 @@ import static org.cobbzilla.util.system.CommandShell.execScript; | |||
@Slf4j | |||
public abstract class ExecBase<OP extends JOperation> { | |||
public abstract void operate(OP operation, Toolbox toolbox, AssetManager assetManager); | |||
public abstract Map<String, Object> operate(OP operation, Toolbox toolbox, AssetManager assetManager); | |||
protected String renderScript(Toolbox toolbox, Map<String, Object> ctx, String template) { | |||
return HandlebarsUtil.apply(toolbox.getHandlebars(), template, ctx); | |||
@@ -8,7 +8,7 @@ import jvc.operation.KenBurnsOperation; | |||
import jvc.service.AssetManager; | |||
import jvc.service.Toolbox; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.cobbzilla.util.javascript.StandardJsEngine; | |||
import org.cobbzilla.util.javascript.JsEngine; | |||
import java.io.File; | |||
import java.math.BigDecimal; | |||
@@ -39,7 +39,7 @@ public class KenBurnsExec extends ExecBase<KenBurnsOperation> { | |||
+ "s={{width}}x{{height}}" | |||
+ "\" -y {{{output.path}}}"; | |||
@Override public void operate(KenBurnsOperation op, Toolbox toolbox, AssetManager assetManager) { | |||
@Override public Map<String, Object> operate(KenBurnsOperation op, Toolbox toolbox, AssetManager assetManager) { | |||
final JSingleOperationContext opCtx = op.getSingleInputContext(assetManager, toolbox); | |||
final JAsset source = opCtx.source; | |||
@@ -48,10 +48,10 @@ public class KenBurnsExec extends ExecBase<KenBurnsOperation> { | |||
final File defaultOutfile = assetManager.assetPath(op, source, formatType); | |||
final File path = resolveOutputPath(output, defaultOutfile); | |||
if (path == null) return; | |||
if (path == null) return null; | |||
output.setPath(abs(path)); | |||
final StandardJsEngine js = toolbox.getJs(); | |||
final JsEngine js = toolbox.getJs(); | |||
final Map<String, Object> ctx = initialContext(toolbox, source); | |||
ctx.put("output", output); | |||
ctx.put("width", op.getWidth(ctx, js)); | |||
@@ -96,6 +96,7 @@ public class KenBurnsExec extends ExecBase<KenBurnsOperation> { | |||
final String scriptOutput = exec(script, op.isNoExec()); | |||
log.debug("operate: command output: "+scriptOutput); | |||
assetManager.addOperationAsset(output); | |||
return ctx; | |||
} | |||
} |
@@ -3,7 +3,7 @@ package jvc.operation.exec; | |||
import jvc.model.operation.JSingleOperationContext; | |||
import jvc.operation.LetterboxOperation; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.cobbzilla.util.javascript.StandardJsEngine; | |||
import org.cobbzilla.util.javascript.JsEngine; | |||
import java.util.Map; | |||
@@ -33,7 +33,7 @@ public class LetterboxExec extends SingleOrMultiSourceExecBase<LetterboxOperatio | |||
if (!op.hasWidth() || !op.hasHeight()) { | |||
die("operate: both width and height must be set"); | |||
} | |||
final StandardJsEngine js = opCtx.toolbox.getJs(); | |||
final JsEngine js = opCtx.toolbox.getJs(); | |||
ctx.put("width", op.getWidth(ctx, js).intValue()); | |||
ctx.put("height", op.getHeight(ctx, js).intValue()); | |||
@@ -9,7 +9,7 @@ import jvc.service.Toolbox; | |||
import lombok.Cleanup; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.cobbzilla.util.io.TempDir; | |||
import org.cobbzilla.util.javascript.StandardJsEngine; | |||
import org.cobbzilla.util.javascript.JsEngine; | |||
import java.io.File; | |||
import java.math.BigDecimal; | |||
@@ -38,7 +38,7 @@ public class MergeAudioExec extends SingleOrMultiSourceExecBase<MergeAudioOperat | |||
@Override | |||
protected void addCommandContext(MergeAudioOperation op, JSingleOperationContext opCtx, Map<String, Object> ctx) { | |||
final JAsset audio = opCtx.assetManager.resolve(op.getInsert()); | |||
final StandardJsEngine js = opCtx.toolbox.getJs(); | |||
final JsEngine js = opCtx.toolbox.getJs(); | |||
final BigDecimal insertAt = op.getAt(ctx, js); | |||
ctx.put("start", insertAt); | |||
@@ -7,7 +7,7 @@ import jvc.operation.OverlayOperation; | |||
import jvc.service.AssetManager; | |||
import jvc.service.Toolbox; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.cobbzilla.util.javascript.StandardJsEngine; | |||
import org.cobbzilla.util.javascript.JsEngine; | |||
import java.io.File; | |||
import java.math.BigDecimal; | |||
@@ -24,7 +24,7 @@ public class OverlayExec extends ExecBase<OverlayOperation> { | |||
+ "[0:v][1v] overlay={{{overlayFilterConfig}}} " | |||
+ "\" -y {{{output.path}}}"; | |||
@Override public void operate(OverlayOperation op, Toolbox toolbox, AssetManager assetManager) { | |||
@Override public Map<String, Object> operate(OverlayOperation op, Toolbox toolbox, AssetManager assetManager) { | |||
final JSingleOperationContext opCtx = op.getSingleInputContext(assetManager, toolbox); | |||
final JAsset source = opCtx.source; | |||
@@ -36,10 +36,10 @@ public class OverlayExec extends ExecBase<OverlayOperation> { | |||
final File defaultOutfile = assetManager.assetPath(op, source, formatType); | |||
final File path = resolveOutputPath(output, defaultOutfile); | |||
if (path == null) return; | |||
if (path == null) return null; | |||
output.setPath(abs(path)); | |||
final StandardJsEngine js = toolbox.getJs(); | |||
final JsEngine js = toolbox.getJs(); | |||
final Map<String, Object> ctx = initialContext(toolbox, source); | |||
ctx.put("overlay", overlaySource); | |||
@@ -58,6 +58,7 @@ public class OverlayExec extends ExecBase<OverlayOperation> { | |||
final String scriptOutput = exec(script, op.isNoExec()); | |||
log.debug("operate: command output: "+scriptOutput); | |||
assetManager.addOperationAsset(output); | |||
return ctx; | |||
} | |||
private String buildOverlayFilter(OverlayOperation op, | |||
@@ -65,7 +66,7 @@ public class OverlayExec extends ExecBase<OverlayOperation> { | |||
JAsset overlaySource, | |||
OverlayOperation.OverlayConfig overlay, | |||
Map<String, Object> ctx, | |||
StandardJsEngine js) { | |||
JsEngine js) { | |||
final StringBuilder b = new StringBuilder(); | |||
final BigDecimal startTime = overlay.getStartTime(ctx, js); | |||
final BigDecimal endTime = overlay.hasEndTime() ? overlay.getEndTime(ctx, js) : overlaySource.duration(); | |||
@@ -4,6 +4,7 @@ import jvc.model.JAsset; | |||
import jvc.model.operation.JSingleOperationContext; | |||
import jvc.operation.ScaleOperation; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.cobbzilla.util.javascript.JsEngine; | |||
import org.cobbzilla.util.javascript.StandardJsEngine; | |||
import java.math.BigDecimal; | |||
@@ -22,7 +23,7 @@ public class ScaleExec extends SingleOrMultiSourceExecBase<ScaleOperation> { | |||
@Override protected void addCommandContext(ScaleOperation op, | |||
JSingleOperationContext opCtx, | |||
Map<String, Object> ctx) { | |||
final StandardJsEngine js = opCtx.toolbox.getJs(); | |||
final JsEngine js = opCtx.toolbox.getJs(); | |||
final JAsset source = opCtx.source; | |||
if (op.hasFactor()) { | |||
final BigDecimal factor = op.getFactor(ctx, js); | |||
@@ -17,19 +17,19 @@ import static org.cobbzilla.util.io.FileUtil.*; | |||
@Slf4j | |||
public abstract class SingleOrMultiSourceExecBase<OP extends JSingleSourceOperation> extends ExecBase<OP> { | |||
@Override public void operate(OP op, Toolbox toolbox, AssetManager assetManager) { | |||
@Override public Map<String, Object> operate(OP op, Toolbox toolbox, AssetManager assetManager) { | |||
final JSingleOperationContext opCtx = op.getSingleInputContext(assetManager, toolbox); | |||
final JAsset source = opCtx.source; | |||
final JAsset output = opCtx.output; | |||
final JFileExtension formatType = opCtx.formatType; | |||
final Map<String, Object> ctx = initialContext(toolbox, source); | |||
addCommandContext(op, opCtx, ctx); | |||
operate(op, toolbox, assetManager, source, output, formatType, ctx); | |||
return operate(op, toolbox, assetManager, source, output, formatType, ctx); | |||
} | |||
protected void addCommandContext(OP op, JSingleOperationContext opCtx, Map<String, Object> ctx) {} | |||
protected void operate(OP op, Toolbox toolbox, AssetManager assetManager, JAsset source, JAsset output, JFileExtension formatType, Map<String, Object> ctx) { | |||
protected Map<String, Object> operate(OP op, Toolbox toolbox, AssetManager assetManager, JAsset source, JAsset output, JFileExtension formatType, Map<String, Object> ctx) { | |||
if (source.hasList()) { | |||
if (output.hasDest()) { | |||
if (!output.destIsDirectory()) die("operate: dest is not a directory: "+output.getDest()); | |||
@@ -43,7 +43,7 @@ public abstract class SingleOrMultiSourceExecBase<OP extends JSingleSourceOperat | |||
outfile = new File(output.destDirectory(), basename(appendToFileNameBeforeExt(asset.getPath(), "_"+op.shortString()))); | |||
if (outfile.exists()) { | |||
log.info("operate: dest exists: "+abs(outfile)); | |||
return; | |||
return ctx; | |||
} | |||
} else { | |||
outfile = defaultOutfile; | |||
@@ -55,11 +55,12 @@ public abstract class SingleOrMultiSourceExecBase<OP extends JSingleSourceOperat | |||
} else { | |||
final File defaultOutfile = assetManager.assetPath(op, source, formatType); | |||
final File path = resolveOutputPath(output, defaultOutfile); | |||
if (path == null) return; | |||
if (path == null) return null; | |||
output.setPath(abs(path)); | |||
process(ctx, op, source, output, output, toolbox, assetManager); | |||
assetManager.addOperationAsset(output); | |||
} | |||
return ctx; | |||
} | |||
protected abstract String getProcessTemplate(); | |||
@@ -23,7 +23,7 @@ public class SplitExec extends ExecBase<SplitOperation> { | |||
public static final String SPLIT_TEMPLATE | |||
= "{{ffmpeg}} -i {{{source.path}}} -ss {{startSeconds}} -t {{interval}} -y {{{output.path}}}"; | |||
@Override public void operate(SplitOperation op, Toolbox toolbox, AssetManager assetManager) { | |||
@Override public Map<String, Object> operate(SplitOperation op, Toolbox toolbox, AssetManager assetManager) { | |||
final JSingleOperationContext opCtx = op.getSingleInputContext(assetManager, toolbox); | |||
final JAsset source = opCtx.source; | |||
@@ -49,7 +49,7 @@ public class SplitExec extends ExecBase<SplitOperation> { | |||
outfile = sliceFile(output, formatType, i, incr); | |||
} else { | |||
die("dest exists and is not a directory: "+output.getDest()); | |||
return; | |||
return null; | |||
} | |||
} | |||
} else { | |||
@@ -77,6 +77,7 @@ public class SplitExec extends ExecBase<SplitOperation> { | |||
assetManager.addOperationAssetSlice(output, slice); | |||
} | |||
log.info("operate: completed"); | |||
return ctx; | |||
} | |||
private File sliceFile(JAsset output, JFileExtension formatType, BigDecimal i, BigDecimal incr) { | |||
@@ -5,7 +5,7 @@ import jvc.operation.TrimOperation; | |||
import jvc.service.AssetManager; | |||
import jvc.service.Toolbox; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.cobbzilla.util.javascript.StandardJsEngine; | |||
import org.cobbzilla.util.javascript.JsEngine; | |||
import java.math.BigDecimal; | |||
import java.util.Map; | |||
@@ -28,7 +28,7 @@ public class TrimExec extends SingleOrMultiSourceExecBase<TrimOperation> { | |||
JAsset subOutput, | |||
Toolbox toolbox, | |||
AssetManager assetManager) { | |||
final StandardJsEngine js = toolbox.getJs(); | |||
final JsEngine js = toolbox.getJs(); | |||
final BigDecimal startTime = op.getStartTime(ctx, js); | |||
ctx.put("startSeconds", startTime); | |||
if (op.hasEndTime()) ctx.put("interval", op.getEndTime(ctx, js).subtract(startTime)); | |||
@@ -0,0 +1,16 @@ | |||
package jvc.service; | |||
import jvc.model.operation.JOperation; | |||
import jvc.model.operation.JValidationResult; | |||
import lombok.AllArgsConstructor; | |||
import lombok.Getter; | |||
import java.util.List; | |||
@AllArgsConstructor | |||
public class JOperationValidationFailure extends RuntimeException { | |||
@Getter private final JOperation operation; | |||
@Getter private final List<JValidationResult> results; | |||
} |
@@ -2,9 +2,16 @@ package jvc.service; | |||
import jvc.model.JSpec; | |||
import jvc.model.operation.JOperation; | |||
import jvc.model.operation.JValidationResult; | |||
import jvc.operation.exec.ExecBase; | |||
import lombok.Getter; | |||
import org.cobbzilla.util.javascript.JsEngine; | |||
import java.util.ArrayList; | |||
import java.util.Arrays; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.stream.Collectors; | |||
public class JvcEngine { | |||
@@ -12,6 +19,8 @@ public class JvcEngine { | |||
private final AssetManager assetManager; | |||
@Getter private final boolean noExec; | |||
@Getter private final List<JOperation> completed = new ArrayList<>(); | |||
public JvcEngine(Toolbox toolbox, AssetManager assetManager, boolean noExec) { | |||
this.toolbox = toolbox; | |||
this.assetManager = assetManager; | |||
@@ -24,7 +33,24 @@ public class JvcEngine { | |||
} | |||
private void runOp(JOperation op) { | |||
op.setNoExec(noExec).getExec().operate(op, toolbox, assetManager); | |||
final ExecBase<JOperation> exec = op | |||
.setExecIndex(completed.size()) | |||
.setNoExec(noExec) | |||
.getExec(); | |||
final Map<String, Object> ctx = exec.operate(op, toolbox, assetManager); | |||
if (op.hasValidate()) { | |||
final JsEngine js = toolbox.getJs(); | |||
final List<JValidationResult> results = Arrays.stream(op.getValidate()) | |||
.map(v -> v.eval(ctx, js)) | |||
.collect(Collectors.toList()); | |||
if (results.stream().anyMatch(JValidationResult::failed)) { | |||
throw new JOperationValidationFailure(op, results); | |||
} | |||
} | |||
completed.add(op); | |||
} | |||
} |
@@ -39,7 +39,7 @@ public class Toolbox { | |||
@Getter(lazy=true) private final Handlebars handlebars = initHandlebars(); | |||
@Getter(lazy=true) private final StandardJsEngine js = new StandardJsEngine(); | |||
@Getter(lazy=true) private final JsEngine js = new StandardJsEngine(); | |||
public static String eval(String val, Map<String, Object> ctx, JsEngine js) { | |||
final Map<String, Object> jsCtx = Toolbox.jsContext(ctx); | |||
@@ -51,6 +51,15 @@ public class Toolbox { | |||
} | |||
} | |||
public static boolean evalBoolean(String val, Map<String, Object> ctx, JsEngine js) { | |||
final Map<String, Object> jsCtx = Toolbox.jsContext(ctx); | |||
try { | |||
return js.evaluateBoolean(val, jsCtx); | |||
} catch (Exception e) { | |||
return die("eval: error evaluating: '"+val+"': "+shortError(e)); | |||
} | |||
} | |||
public static BigDecimal evalBig(String val, Map<String, Object> ctx, JsEngine js) { | |||
return big(eval(val, ctx, js)); | |||
} | |||
@@ -14,7 +14,11 @@ | |||
"creates": "v2", | |||
"source": "vid2", | |||
"start": "10", | |||
"end": "30" | |||
"end": "30", | |||
"validate": [{ | |||
"comment": "expect output to be about 20 seconds long, give or take 0.1 seconds", | |||
"test": "is_within(output.duration, 20, 0.1)" | |||
}] | |||
}, | |||
// create 20 seconds of silent audio, combine with input video, produce silent video output. | |||
{ | |||
@@ -22,7 +26,11 @@ | |||
"creates": "v2_silent", // output asset name | |||
"source": "v2", // main video asset | |||
"channelLayout": "stereo", // optional channel layout, usually 'mono' or 'stereo'. Default is 'stereo' | |||
"samplingRate": 48000 // optional sampling rate, in Hz. default is 48000 | |||
"samplingRate": 48000, // optional sampling rate, in Hz. default is 48000 | |||
"validate": [{ | |||
"comment": "expect output to be about 20 seconds long, give or take 0.1 seconds", | |||
"test": "is_within(output.duration, 20, 0.1)" | |||
}] | |||
} | |||
] | |||
} |
@@ -1 +1 @@ | |||
Subproject commit 8cdea3ac79f5d890ba765665624c981990076c98 | |||
Subproject commit f87d3b74f46775143dfffd2182e43eb91f94a0b7 |