Explorar el Código

add support for spec-level variables

master
Jonathan Cobb hace 3 años
padre
commit
98c47671d9
Se han modificado 12 ficheros con 60 adiciones y 21 borrados
  1. +2
    -0
      src/main/java/jvc/model/JSpec.java
  2. +11
    -5
      src/main/java/jvc/model/JsObjectView.java
  3. +6
    -3
      src/main/java/jvc/model/operation/JOperation.java
  4. +1
    -0
      src/main/java/jvc/operation/exec/AdjustSpeedExec.java
  5. +25
    -2
      src/main/java/jvc/operation/exec/ExecBase.java
  6. +1
    -1
      src/main/java/jvc/operation/exec/KenBurnsExec.java
  7. +1
    -1
      src/main/java/jvc/operation/exec/OverlayExec.java
  8. +1
    -1
      src/main/java/jvc/operation/exec/SingleOrMultiSourceExecBase.java
  9. +1
    -1
      src/main/java/jvc/operation/exec/SplitExec.java
  10. +3
    -3
      src/main/java/jvc/service/JvcEngine.java
  11. +0
    -2
      src/test/resources/tests/test_overlay.jvc
  12. +8
    -2
      src/test/resources/tests/test_scale.jvc

+ 2
- 0
src/main/java/jvc/model/JSpec.java Ver fichero

@@ -5,10 +5,12 @@ import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import org.cobbzilla.util.collection.NameAndValue;


@NoArgsConstructor @Accessors(chain=true) @NoArgsConstructor @Accessors(chain=true)
public class JSpec { public class JSpec {


@Getter @Setter private NameAndValue[] vars;
@Getter @Setter private JAsset[] assets; @Getter @Setter private JAsset[] assets;
@Getter @Setter private JOperation[] operations; @Getter @Setter private JOperation[] operations;
@Getter @Setter private JArtifact[] artifacts; @Getter @Setter private JArtifact[] artifacts;


+ 11
- 5
src/main/java/jvc/model/JsObjectView.java Ver fichero

@@ -1,10 +1,12 @@
package jvc.model; package jvc.model;


import jvc.model.js.JAssetJs;

import java.util.Collection; import java.util.Collection;
import java.util.stream.Collectors; import java.util.stream.Collectors;


import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
import static org.cobbzilla.util.daemon.ZillaRuntime.empty;
import static org.cobbzilla.util.daemon.ZillaRuntime.*;


public interface JsObjectView { public interface JsObjectView {


@@ -16,13 +18,17 @@ public interface JsObjectView {
&& (((Collection) value).iterator().next() instanceof JsObjectView); && (((Collection) value).iterator().next() instanceof JsObjectView);
} }


static <T extends JsObjectView> Collection<T> toJs(Collection<T> values) {
static <T extends JsObjectView> Collection<JAssetJs> toJs(Collection<T> values) {
if (empty(values)) { if (empty(values)) {
return emptyList(); return emptyList();
} else { } else {
return values.stream()
.map(v -> (T) v.toJs())
.collect(Collectors.toList());
try {
return values.stream()
.map(v -> (JAssetJs) v.toJs())
.collect(Collectors.toList());
} catch (Exception e) {
return die("toJs: "+shortError(e));
}
} }
} }




+ 6
- 3
src/main/java/jvc/model/operation/JOperation.java Ver fichero

@@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import jvc.model.JAsset; import jvc.model.JAsset;
import jvc.model.JSpec;
import jvc.operation.exec.ExecBase; import jvc.operation.exec.ExecBase;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
@@ -50,9 +51,11 @@ public abstract class JOperation {
return hashOf(operation, json(this), sources, args); return hashOf(operation, json(this), sources, args);
} }


private static final Map<Class<? extends JOperation>, ExecBase<?>> execMap = new HashMap<>();
public <OP extends JOperation> ExecBase<OP> getExec() {
return (ExecBase<OP>) execMap.computeIfAbsent(getClass(), c -> instantiate(getOperationExecClass(getClass())));
private static final Map<String, ExecBase<?>> execMap = new HashMap<>();
public <OP extends JOperation> ExecBase<OP> getExec(JSpec spec) {
final String cacheKey = hashOf(getClass().getName(), spec.getVars());
return (ExecBase<OP>) execMap.computeIfAbsent(cacheKey,
c -> ((ExecBase<?>) instantiate(getOperationExecClass(getClass()))).setSpec(spec));
} }


public String shortString() { return safeShellArg(operation+"_"+sha256_hex(json(this))); } public String shortString() { return safeShellArg(operation+"_"+sha256_hex(json(this))); }


+ 1
- 0
src/main/java/jvc/operation/exec/AdjustSpeedExec.java Ver fichero

@@ -1,5 +1,6 @@
package jvc.operation.exec; package jvc.operation.exec;


import jvc.model.JSpec;
import jvc.model.operation.JSingleOperationContext; import jvc.model.operation.JSingleOperationContext;
import jvc.operation.AdjustSpeedOperation; import jvc.operation.AdjustSpeedOperation;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;


+ 25
- 2
src/main/java/jvc/operation/exec/ExecBase.java Ver fichero

@@ -1,11 +1,16 @@
package jvc.operation.exec; package jvc.operation.exec;


import jvc.model.JAsset; import jvc.model.JAsset;
import jvc.model.JSpec;
import jvc.model.JStreamType; import jvc.model.JStreamType;
import jvc.model.operation.JOperation; import jvc.model.operation.JOperation;
import jvc.service.AssetManager; import jvc.service.AssetManager;
import jvc.service.Toolbox; import jvc.service.Toolbox;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.cobbzilla.util.collection.NameAndValue;
import org.cobbzilla.util.handlebars.HandlebarsUtil; import org.cobbzilla.util.handlebars.HandlebarsUtil;


import java.io.File; import java.io.File;
@@ -15,13 +20,22 @@ import java.util.Map;


import static jvc.service.Toolbox.jsContext; import static jvc.service.Toolbox.jsContext;
import static org.cobbzilla.util.daemon.ZillaRuntime.die; import static org.cobbzilla.util.daemon.ZillaRuntime.die;
import static org.cobbzilla.util.daemon.ZillaRuntime.empty;
import static org.cobbzilla.util.io.FileUtil.abs; import static org.cobbzilla.util.io.FileUtil.abs;
import static org.cobbzilla.util.io.FileUtil.basename; import static org.cobbzilla.util.io.FileUtil.basename;
import static org.cobbzilla.util.system.CommandShell.execScript; import static org.cobbzilla.util.system.CommandShell.execScript;


@Slf4j
@Slf4j @Accessors(chain=true)
public abstract class ExecBase<OP extends JOperation> { public abstract class ExecBase<OP extends JOperation> {


@Getter @Setter private JSpec spec;

public NameAndValue[] getVars () {
return spec == null || empty(spec.getVars())
? NameAndValue.EMPTY_ARRAY
: spec.getVars();
}

public abstract Map<String, Object> 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) { protected String renderScript(Toolbox toolbox, Map<String, Object> ctx, String template) {
@@ -43,10 +57,19 @@ public abstract class ExecBase<OP extends JOperation> {
} }
} }


protected Map<String, Object> initialContext(Toolbox toolbox, JAsset source) {
protected Map<String, Object> initialContext(Toolbox toolbox, JAsset source, NameAndValue[] vars) {
final Map<String, Object> ctx = new HashMap<>(); final Map<String, Object> ctx = new HashMap<>();
ctx.put("ffmpeg", toolbox.getFfmpeg()); ctx.put("ffmpeg", toolbox.getFfmpeg());
ctx.put("source", source); ctx.put("source", source);
if (!empty(vars)) {
for (NameAndValue var : vars) {
final String name = var.getName();
if (ctx.containsKey(name)) {
log.warn("initialContext: spec variable "+ name +" will mask existing value: "+ctx.get(name));
}
ctx.put(name, var.getValue());
}
}
return ctx; return ctx;
} }




+ 1
- 1
src/main/java/jvc/operation/exec/KenBurnsExec.java Ver fichero

@@ -57,7 +57,7 @@ public class KenBurnsExec extends ExecBase<KenBurnsOperation> {
output.setPath(abs(path)); output.setPath(abs(path));


final JsEngine js = toolbox.getJs(); final JsEngine js = toolbox.getJs();
final Map<String, Object> ctx = initialContext(toolbox, source);
final Map<String, Object> ctx = initialContext(toolbox, source, getVars());
ctx.put("output", output); ctx.put("output", output);
ctx.put("width", op.getWidth(ctx, js)); ctx.put("width", op.getWidth(ctx, js));
ctx.put("height", op.getHeight(ctx, js)); ctx.put("height", op.getHeight(ctx, js));


+ 1
- 1
src/main/java/jvc/operation/exec/OverlayExec.java Ver fichero

@@ -40,7 +40,7 @@ public class OverlayExec extends ExecBase<OverlayOperation> {
output.setPath(abs(path)); output.setPath(abs(path));


final JsEngine js = toolbox.getJs(); final JsEngine js = toolbox.getJs();
final Map<String, Object> ctx = initialContext(toolbox, source);
final Map<String, Object> ctx = initialContext(toolbox, source, getVars());
ctx.put("overlay", overlaySource); ctx.put("overlay", overlaySource);


ctx.put("mainStart", op.getStartTime(ctx, js)); ctx.put("mainStart", op.getStartTime(ctx, js));


+ 1
- 1
src/main/java/jvc/operation/exec/SingleOrMultiSourceExecBase.java Ver fichero

@@ -22,7 +22,7 @@ public abstract class SingleOrMultiSourceExecBase<OP extends JSingleSourceOperat
final JAsset source = opCtx.source; final JAsset source = opCtx.source;
final JAsset output = opCtx.output; final JAsset output = opCtx.output;
final JStreamType streamType = opCtx.streamType; final JStreamType streamType = opCtx.streamType;
final Map<String, Object> ctx = initialContext(toolbox, source);
final Map<String, Object> ctx = initialContext(toolbox, source, getVars());
addCommandContext(op, opCtx, ctx); addCommandContext(op, opCtx, ctx);
return operate(op, toolbox, assetManager, source, output, streamType, ctx); return operate(op, toolbox, assetManager, source, output, streamType, ctx);
} }


+ 1
- 1
src/main/java/jvc/operation/exec/SplitExec.java Ver fichero

@@ -31,7 +31,7 @@ public class SplitExec extends ExecBase<SplitOperation> {
final JStreamType streamType = opCtx.streamType; final JStreamType streamType = opCtx.streamType;


final JsEngine js = toolbox.getJs(); final JsEngine js = toolbox.getJs();
final Map<String, Object> ctx = initialContext(toolbox, source);
final Map<String, Object> ctx = initialContext(toolbox, source, getVars());


assetManager.addOperationArrayAsset(output); assetManager.addOperationArrayAsset(output);
final BigDecimal incr = op.getIntervalIncr(ctx, js); final BigDecimal incr = op.getIntervalIncr(ctx, js);


+ 3
- 3
src/main/java/jvc/service/JvcEngine.java Ver fichero

@@ -31,15 +31,15 @@ public class JvcEngine {


public void runSpec(JSpec spec) { public void runSpec(JSpec spec) {
Arrays.stream(spec.getAssets()).forEach(assetManager::defineAsset); Arrays.stream(spec.getAssets()).forEach(assetManager::defineAsset);
Arrays.stream(spec.getOperations()).forEach(this::runOp);
Arrays.stream(spec.getOperations()).forEach(op -> runOp(spec, op));
} }


private void runOp(JOperation op) {
private void runOp(JSpec spec, JOperation op) {


final ExecBase<JOperation> exec = op final ExecBase<JOperation> exec = op
.setExecIndex(completed.size()) .setExecIndex(completed.size())
.setNoExec(noExec) .setNoExec(noExec)
.getExec();
.getExec(spec);


final Map<String, Object> ctx = exec.operate(op, toolbox, assetManager); final Map<String, Object> ctx = exec.operate(op, toolbox, assetManager);
if (ctx == null) { if (ctx == null) {


+ 0
- 2
src/test/resources/tests/test_overlay.jvc Ver fichero

@@ -42,8 +42,6 @@
"operation": "overlay", // name of the operation "operation": "overlay", // name of the operation
"creates": { "creates": {
"name": "overlay1", // name of the output asset "name": "overlay1", // name of the output asset
"width": "1920", // output width in pixels. default is source width
"height": "1024", // output height in pixes. default is source height
"dest": "src/test/resources/outputs/overlay/" "dest": "src/test/resources/outputs/overlay/"
}, },
"source": "v1", // main video asset "source": "v1", // main video asset


+ 8
- 2
src/test/resources/tests/test_scale.jvc Ver fichero

@@ -1,4 +1,8 @@
{ {
"vars": [
{"name": "out_width", "value": "1024"},
{"name": "out_height", "value": "768"}
],
"assets": [ "assets": [
// wildcard matches multiple files, vid1_splits becomes a "list" asset. resolution is 320x240 // wildcard matches multiple files, vid1_splits becomes a "list" asset. resolution is 320x240
{ "name": "vid1_splits", "path": "src/test/resources/outputs/vid1_splits_*.mp4" } { "name": "vid1_splits", "path": "src/test/resources/outputs/vid1_splits_*.mp4" }
@@ -8,8 +12,10 @@
"operation": "scale", // name of the operation "operation": "scale", // name of the operation
"creates": "scaled_test1", // output asset name "creates": "scaled_test1", // output asset name
"source": "vid1_splits[3]", // scale this source asset "source": "vid1_splits[3]", // scale this source asset
"width": "1024", // width of scaled asset. if omitted and height is present, width will be proportional
"height": "768", // height of scaled asset. if omitted and width is present, height will be proportional
"width": "out_width", // width of scaled asset. if omitted and height is present, width will be proportional
// here we reference the `out_width` variable defined above in the `vars` array
"height": "out_height", // height of scaled asset. if omitted and width is present, height will be proportional
// here we reference the `out_height` variable defined above in the `vars` array
"validate": [{ "validate": [{
"comment": "expect output resolution of 1024x768", "comment": "expect output resolution of 1024x768",
"test": "output.width === 1024 && output.height === 768" "test": "output.width === 1024 && output.height === 768"


Cargando…
Cancelar
Guardar