Browse Source

WIP. adding ken burns operation.

master
Jonathan Cobb 3 years ago
parent
commit
7dcd5510be
27 changed files with 278 additions and 124 deletions
  1. +35
    -16
      README.md
  2. +6
    -0
      src/main/java/jvcl/main/JvclOptions.java
  3. +1
    -1
      src/main/java/jvcl/model/JSpec.java
  4. +18
    -0
      src/main/java/jvcl/model/operation/JMultiOperationContext.java
  5. +36
    -0
      src/main/java/jvcl/model/operation/JMultiSourceOperation.java
  6. +2
    -1
      src/main/java/jvcl/model/operation/JOperation.java
  7. +14
    -0
      src/main/java/jvcl/model/operation/JOperationContextBase.java
  8. +18
    -0
      src/main/java/jvcl/model/operation/JSingleOperationContext.java
  9. +24
    -0
      src/main/java/jvcl/model/operation/JSingleSourceOperation.java
  10. +2
    -24
      src/main/java/jvcl/operation/ConcatOperation.java
  11. +18
    -0
      src/main/java/jvcl/operation/KenBurnsOperation.java
  12. +2
    -3
      src/main/java/jvcl/operation/OverlayOperation.java
  13. +2
    -4
      src/main/java/jvcl/operation/SplitOperation.java
  14. +3
    -16
      src/main/java/jvcl/operation/TrimOperation.java
  15. +6
    -22
      src/main/java/jvcl/operation/exec/ConcatExec.java
  16. +1
    -1
      src/main/java/jvcl/operation/exec/ExecBase.java
  17. +36
    -0
      src/main/java/jvcl/operation/exec/KenBurnsExec.java
  18. +8
    -8
      src/main/java/jvcl/operation/exec/OverlayExec.java
  19. +6
    -13
      src/main/java/jvcl/operation/exec/SplitExec.java
  20. +9
    -8
      src/main/java/jvcl/operation/exec/TrimExec.java
  21. +1
    -1
      src/main/java/jvcl/service/AssetManager.java
  22. +1
    -1
      src/main/java/jvcl/service/OperationEngine.java
  23. +1
    -1
      src/main/java/jvcl/service/json/JOperationFactory.java
  24. +1
    -1
      src/test/resources/tests/test_concat.jvcl
  25. +24
    -0
      src/test/resources/tests/test_ken_burns.jvcl
  26. +2
    -2
      src/test/resources/tests/test_split.jvcl
  27. +1
    -1
      src/test/resources/tests/test_trim.jvcl

+ 35
- 16
README.md View File

@@ -136,8 +136,11 @@ Concatenate audio/video assets together into one asset
### trim
Trim audio/video; crop a section of an asset, becomes a new asset

### scale
Scale a video asset from one size to another

### overlay
Overlay one audio or video file onto another
Overlay one asset onto another

### ken-burns
For transforming still images into video via a fade-pan (aka Ken Burns) effect
@@ -171,38 +174,41 @@ Here is a complex example using multiple assets and operations.
"name": "vid3",
"path": "https://archive.org/download/gov.archives.arc.49442/gov.archives.arc.49442_512kb.mp4",
"dest": "src/test/resources/sources/"
},

// Image URL
{
"name": "img1",
"path": "https://live.staticflickr.com/65535/48159911972_01efa0e5ea_b.jpg",
"dest": "src/test/resources/sources/"
}
],
"operations": [
{
"operation": "split", // name of the operation,
"operation": "split", // name of the operation
"creates": "vid1_split_%", // assets it creates, the '%' will be replaced with a counter
"split": "vid1", // split this source asset
"source": "vid1", // split this source asset
"interval": "10" // split every ten seconds
},
{
"operation": "concat", // name of the operation,
"operation": "concat", // name of the operation
"creates": "recombined_vid1", // assets it creates, the '%' will be replaced with a counter
"concat": ["vid1_split"] // recombine all split assets
"source": ["vid1_split"] // recombine all split assets
},
{
"operation": "concat", // name of the operation,
"operation": "concat", // name of the operation
"creates": "combined_vid", // asset it creates, can be referenced later
"concat": ["vid1", "vid2"] // operation-specific: this says, concatenate these named assets
"source": ["vid1", "vid2"] // operation-specific: this says, concatenate these named assets
},
{
"operation": "concat", // name of the operation,
"operation": "concat", // name of the operation
"creates": "combined_vid", // the asset it creates, can be referenced later
"concat": ["vid1", "vid2"] // operation-specific: this says, concatenate these named assets
"source": ["vid1", "vid2"] // operation-specific: this says, concatenate these named assets
},
{
"operation": "overlay", // name of the operation,
"creates": {
"name": "overlay1", // asset it creates
"width": "1920", // output width in pixels. default is source width
"height": "1024" // output height in pixes. default is source height
},
"main": "combined_vid1", // main video asset
"operation": "overlay", // name of the operation
"creates": "overlay1", // asset it creates
"source": "combined_vid1", // main video asset
"start": "30", // when (on the main video timeline) to begin showing the overlay. default is 0 (beginning)
"end": "60", // when (on the main video timeline) to stop showing the overlay. default is to play the entire overlay
"overlay": {
@@ -214,6 +220,19 @@ Here is a complex example using multiple assets and operations.
"x": "source.width / 2", // horizontal overlay position on main video. default is 0
"y": "source.height / 2" // vertical overlay position on main video. default is 0
}
},
{
"operation": "ken-burns", // name of the operation
"creates": "ken1", // asset it creates
"source": "img1", // source image
"zoom": "1.3", // zoom level, from 1 to 10
"duration": "5", // how long the resulting video will be
"start": "0", // when to start zooming, default is 0
"end": "duration", // when to end zooming, default is duration
"x": "source.width * 0.6", // pan to this x-position
"y": "source.height * 0.4", // pan to this y-position
"width": "1024", // width of output video
"height": "768" // height of output video
}
]
}


+ 6
- 0
src/main/java/jvcl/main/JvclOptions.java View File

@@ -48,4 +48,10 @@ public class JvclOptions extends BaseMainOptions {
@Getter @Setter private File scratchDir = null;
public File scratchDir() { return scratchDir == null ? new TempDir() : scratchDir; }

public static final String USAGE_NO_EXEC = "Don't run anything, instead print out commands that would have been run";
public static final String OPT_NO_EXEC = "-n";
public static final String LONGOPT_NO_EXEC = "--no-exec";
@Option(name=OPT_NO_EXEC, aliases=LONGOPT_NO_EXEC, usage=USAGE_NO_EXEC)
@Getter @Setter private boolean noExec = false;

}

+ 1
- 1
src/main/java/jvcl/model/JSpec.java View File

@@ -1,6 +1,6 @@
package jvcl.model;

import lombok.AllArgsConstructor;
import jvcl.model.operation.JOperation;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;


+ 18
- 0
src/main/java/jvcl/model/operation/JMultiOperationContext.java View File

@@ -0,0 +1,18 @@
package jvcl.model.operation;

import jvcl.model.JAsset;
import jvcl.model.JFileExtension;
import lombok.NoArgsConstructor;

import java.util.List;

@NoArgsConstructor
public class JMultiOperationContext extends JOperationContextBase {

public List<JAsset> sources;

public JMultiOperationContext(List<JAsset> sources, JAsset output, JFileExtension formatType) {
super(output, formatType);
this.sources = sources;
}
}

+ 36
- 0
src/main/java/jvcl/model/operation/JMultiSourceOperation.java View File

@@ -0,0 +1,36 @@
package jvcl.model.operation;

import jvcl.model.JAsset;
import jvcl.model.JFileExtension;
import jvcl.service.AssetManager;
import lombok.Getter;
import lombok.Setter;

import java.util.List;

import static jvcl.model.JAsset.flattenAssetList;
import static jvcl.model.JAsset.json2asset;
import static org.cobbzilla.util.daemon.ZillaRuntime.die;
import static org.cobbzilla.util.daemon.ZillaRuntime.empty;

public abstract class JMultiSourceOperation extends JOperation {

@Getter @Setter private String[] sources;

public JMultiOperationContext getMultiInputContext(AssetManager assetManager) {
// validate sources
final List<JAsset> sources = flattenAssetList(assetManager.resolve(getSources()));
if (empty(sources)) die("operate: no sources");

// create output object
final JAsset output = json2asset(getCreates());

// if any format settings are missing, use settings from first source
output.mergeFormat(sources.get(0).getFormat());

// set the path, check if output asset already exists
final JFileExtension formatType = output.getFormat().getFileExtension();

return new JMultiOperationContext(sources, output, formatType);
}
}

src/main/java/jvcl/model/JOperation.java → src/main/java/jvcl/model/operation/JOperation.java View File

@@ -1,7 +1,8 @@
package jvcl.model;
package jvcl.model.operation;

import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.JsonNode;
import jvcl.model.JAsset;
import jvcl.operation.exec.ExecBase;
import lombok.Getter;
import lombok.NoArgsConstructor;

+ 14
- 0
src/main/java/jvcl/model/operation/JOperationContextBase.java View File

@@ -0,0 +1,14 @@
package jvcl.model.operation;

import jvcl.model.JAsset;
import jvcl.model.JFileExtension;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;

@NoArgsConstructor @AllArgsConstructor
public class JOperationContextBase {

public JAsset output;
public JFileExtension formatType;

}

+ 18
- 0
src/main/java/jvcl/model/operation/JSingleOperationContext.java View File

@@ -0,0 +1,18 @@
package jvcl.model.operation;

import jvcl.model.JAsset;
import jvcl.model.JFileExtension;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;

@NoArgsConstructor @AllArgsConstructor
public class JSingleOperationContext extends JOperationContextBase {
public JAsset source;

public JSingleOperationContext(JAsset source, JAsset output, JFileExtension formatType) {
super(output, formatType);
this.source = source;
}

}

+ 24
- 0
src/main/java/jvcl/model/operation/JSingleSourceOperation.java View File

@@ -0,0 +1,24 @@
package jvcl.model.operation;

import jvcl.model.JAsset;
import jvcl.model.JFileExtension;
import jvcl.service.AssetManager;
import lombok.Getter;
import lombok.Setter;

import static jvcl.model.JAsset.json2asset;

public class JSingleSourceOperation extends JOperation {

@Getter @Setter private String source;

public JSingleOperationContext getSingleInputContext(AssetManager assetManager) {
final JAsset source = assetManager.resolve(getSource());
final JAsset output = json2asset(getCreates());
output.mergeFormat(source.getFormat());
final JFileExtension formatType = output.getFormat().getFileExtension();

return new JSingleOperationContext(source, output, formatType);
}

}

+ 2
- 24
src/main/java/jvcl/operation/ConcatOperation.java View File

@@ -1,29 +1,7 @@
package jvcl.operation;

import jvcl.model.JAsset;
import jvcl.model.JFileExtension;
import jvcl.model.JOperation;
import jvcl.service.AssetManager;
import jvcl.service.Toolbox;
import lombok.Getter;
import lombok.Setter;
import jvcl.model.operation.JMultiSourceOperation;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static jvcl.model.JAsset.flattenAssetList;
import static jvcl.model.JAsset.json2asset;
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.system.CommandShell.execScript;

@Slf4j
public class ConcatOperation extends JOperation {

@Getter @Setter private String[] concat;

}
public class ConcatOperation extends JMultiSourceOperation {}

+ 18
- 0
src/main/java/jvcl/operation/KenBurnsOperation.java View File

@@ -0,0 +1,18 @@
package jvcl.operation;

import jvcl.model.operation.JSingleSourceOperation;
import lombok.Getter;
import lombok.Setter;

public class KenBurnsOperation extends JSingleSourceOperation {

@Getter @Setter private String zoom;
@Getter @Setter private String duration;
@Getter @Setter private String width;
@Getter @Setter private String height;
@Getter @Setter private String x;
@Getter @Setter private String y;
@Getter @Setter private String start;
@Getter @Setter private String end;

}

+ 2
- 3
src/main/java/jvcl/operation/OverlayOperation.java View File

@@ -1,6 +1,6 @@
package jvcl.operation;

import jvcl.model.JOperation;
import jvcl.model.operation.JSingleSourceOperation;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
@@ -16,9 +16,8 @@ import static org.cobbzilla.util.daemon.ZillaRuntime.big;
import static org.cobbzilla.util.daemon.ZillaRuntime.empty;

@Slf4j
public class OverlayOperation extends JOperation {
public class OverlayOperation extends JSingleSourceOperation {

@Getter @Setter private String source;
@Getter @Setter private OverlayConfig overlay;

@Getter @Setter private String start;


+ 2
- 4
src/main/java/jvcl/operation/SplitOperation.java View File

@@ -1,7 +1,7 @@
package jvcl.operation;

import jvcl.model.JAsset;
import jvcl.model.JOperation;
import jvcl.model.operation.JSingleSourceOperation;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
@@ -12,9 +12,7 @@ import static jvcl.service.Toolbox.getDuration;
import static org.cobbzilla.util.daemon.ZillaRuntime.empty;

@Slf4j
public class SplitOperation extends JOperation {

@Getter @Setter private String split;
public class SplitOperation extends JSingleSourceOperation {

@Getter @Setter private String interval;
public BigDecimal getIntervalIncr() { return getDuration(interval); }


+ 3
- 16
src/main/java/jvcl/operation/TrimOperation.java View File

@@ -1,30 +1,17 @@
package jvcl.operation;

import jvcl.model.JAsset;
import jvcl.model.JFileExtension;
import jvcl.model.JOperation;
import jvcl.service.AssetManager;
import jvcl.service.Toolbox;
import jvcl.model.operation.JSingleSourceOperation;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

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.system.CommandShell.execScript;

@Slf4j
public class TrimOperation extends JOperation {

@Getter @Setter private String trim;
public class TrimOperation extends JSingleSourceOperation {

@Getter @Setter private String start;
public BigDecimal getStartTime() { return empty(start) ? BigDecimal.ZERO : getDuration(start); }
@@ -34,6 +21,6 @@ public class TrimOperation extends JOperation {
public BigDecimal getEndTime() { return getDuration(end); }

public String shortString() { return "trim_"+getStart()+(hasEnd() ? "_"+getEnd() : ""); }
public String toString() { return trim+"_"+getStart()+(hasEnd() ? "_"+getEnd() : ""); }
public String toString() { return getSource()+"_"+getStart()+(hasEnd() ? "_"+getEnd() : ""); }

}

+ 6
- 22
src/main/java/jvcl/operation/exec/ConcatExec.java View File

@@ -2,6 +2,7 @@ package jvcl.operation.exec;

import jvcl.model.JAsset;
import jvcl.model.JFileExtension;
import jvcl.model.operation.JMultiOperationContext;
import jvcl.operation.ConcatOperation;
import jvcl.service.AssetManager;
import jvcl.service.Toolbox;
@@ -12,22 +13,12 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static jvcl.model.JAsset.flattenAssetList;
import static jvcl.model.JAsset.json2asset;
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.system.CommandShell.execScript;

@Slf4j
public class ConcatExec extends ExecBase<ConcatOperation> {

public static final String CONCAT_RECODE_TEMPLATE_OLD
// concat inputs
= "{{ffmpeg}} -f concat{{#each sources}} -i {{{this.path}}}{{/each}} "
// safely with copy codec
+ "-safe 0 -c copy {{{output.path}}}";

public static final String CONCAT_RECODE_TEMPLATE_1
// list inputs
= "{{ffmpeg}} {{#each sources}} -i {{{this.path}}}{{/each}} "
@@ -39,22 +30,15 @@ public class ConcatExec extends ExecBase<ConcatOperation> {
+ "concat=n={{sources.length}}:v=1:a=1 [v] [a]\" "

// output combined result
+ "-map \"[v]\" -map \"[a]\" {{{output.path}}}";
+ "-map \"[v]\" -map \"[a]\" -y {{{output.path}}}";

@Override public void operate(ConcatOperation op, Toolbox toolbox, AssetManager assetManager) {

// validate sources
final List<JAsset> sources = flattenAssetList(assetManager.resolve(op.getConcat()));
if (empty(sources)) die("operate: no sources");

// create output object
final JAsset output = json2asset(op.getCreates());

// if any format settings are missing, use settings from first source
output.mergeFormat(sources.get(0).getFormat());
final JMultiOperationContext opCtx = op.getMultiInputContext(assetManager);
final List<JAsset> sources = opCtx.sources;
final JAsset output = opCtx.output;
final JFileExtension formatType = opCtx.formatType;

// set the path, check if output asset already exists
final JFileExtension formatType = output.getFormat().getFileExtension();
final File defaultOutfile = assetManager.assetPath(op, sources, formatType);
final File path = resolveOutputPath(output, defaultOutfile);
if (path == null) return;


+ 1
- 1
src/main/java/jvcl/operation/exec/ExecBase.java View File

@@ -1,7 +1,7 @@
package jvcl.operation.exec;

import jvcl.model.JAsset;
import jvcl.model.JOperation;
import jvcl.model.operation.JOperation;
import jvcl.service.AssetManager;
import jvcl.service.Toolbox;
import lombok.extern.slf4j.Slf4j;


+ 36
- 0
src/main/java/jvcl/operation/exec/KenBurnsExec.java View File

@@ -0,0 +1,36 @@
package jvcl.operation.exec;


import jvcl.model.JAsset;
import jvcl.model.JFileExtension;
import jvcl.model.operation.JSingleOperationContext;
import jvcl.operation.KenBurnsOperation;
import jvcl.service.AssetManager;
import jvcl.service.Toolbox;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class KenBurnsExec extends ExecBase<KenBurnsOperation> {

public static final String KEN_BURNS_TEMPLATE
= "{{{ffmpeg}}} -i {{{source.path}}} -filter_complex \""
+ "scale={{expr width '*' 16}}x{{expr height '*' 16}}, "
+ "zoompan="
+ "z='min(zoom*{{zoomIncrementFactor}},{{zoom}})':"
+ "d={{duration}}:"
+ "x='if(gte(zoom,{{zoom}}),x,x+{{deltaX}}/a)':"
+ "y='if(gte(zoom,{{zoom}}),y,y+{{deltaY}})':"
+ "s={{width}}x{{height}}"
+ "\" -y {{{output.path}}}";

@Override public void operate(KenBurnsOperation op, Toolbox toolbox, AssetManager assetManager) {

final JSingleOperationContext opCtx = op.getSingleInputContext(assetManager);
final JAsset source = opCtx.source;
final JAsset output = opCtx.output;
final JFileExtension formatType = opCtx.formatType;


}

}

+ 8
- 8
src/main/java/jvcl/operation/exec/OverlayExec.java View File

@@ -2,6 +2,7 @@ package jvcl.operation.exec;

import jvcl.model.JAsset;
import jvcl.model.JFileExtension;
import jvcl.model.operation.JSingleOperationContext;
import jvcl.operation.OverlayOperation;
import jvcl.service.AssetManager;
import jvcl.service.Toolbox;
@@ -14,7 +15,6 @@ import java.util.HashMap;
import java.util.Map;

import static java.math.RoundingMode.HALF_EVEN;
import static jvcl.model.JAsset.json2asset;
import static org.cobbzilla.util.daemon.ZillaRuntime.big;
import static org.cobbzilla.util.io.FileUtil.abs;
import static org.cobbzilla.util.system.CommandShell.execScript;
@@ -26,17 +26,17 @@ public class OverlayExec extends ExecBase<OverlayOperation> {
= "ffmpeg -i {{{source.path}}} -i {{{overlay.path}}} -filter_complex \""
+ "[1:v] setpts=PTS-STARTPTS+(1/TB){{#exists width}}, scale={{width}}x{{height}}{{/exists}} [1v]; "
+ "[0:v][1v] overlay={{{overlayFilterConfig}}} "
+ "\" {{{output.path}}}";
+ "\" -y {{{output.path}}}";

@Override public void operate(OverlayOperation op, Toolbox toolbox, AssetManager assetManager) {
final JAsset source = assetManager.resolve(op.getSource());
final OverlayOperation.OverlayConfig overlay = op.getOverlay();
final JAsset overlaySource = assetManager.resolve(overlay.getSource());

final JAsset output = json2asset(op.getCreates());
output.mergeFormat(source.getFormat());
final JSingleOperationContext opCtx = op.getSingleInputContext(assetManager);
final JAsset source = opCtx.source;
final JAsset output = opCtx.output;
final JFileExtension formatType = opCtx.formatType;

final JFileExtension formatType = output.getFormat().getFileExtension();
final OverlayOperation.OverlayConfig overlay = op.getOverlay();
final JAsset overlaySource = assetManager.resolve(overlay.getSource());

final File defaultOutfile = assetManager.assetPath(op, source, formatType);
final File path = resolveOutputPath(output, defaultOutfile);


+ 6
- 13
src/main/java/jvcl/operation/exec/SplitExec.java View File

@@ -2,6 +2,7 @@ package jvcl.operation.exec;

import jvcl.model.JAsset;
import jvcl.model.JFileExtension;
import jvcl.model.operation.JSingleOperationContext;
import jvcl.operation.SplitOperation;
import jvcl.service.AssetManager;
import jvcl.service.Toolbox;
@@ -12,7 +13,6 @@ import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

import static jvcl.model.JAsset.json2asset;
import static org.cobbzilla.util.daemon.ZillaRuntime.die;
import static org.cobbzilla.util.io.FileUtil.abs;
import static org.cobbzilla.util.io.FileUtil.mkdirOrDie;
@@ -22,21 +22,14 @@ import static org.cobbzilla.util.system.CommandShell.execScript;
public class SplitExec extends ExecBase<SplitOperation> {

public static final String SPLIT_TEMPLATE
= "{{ffmpeg}} -i {{{source.path}}} -ss {{startSeconds}} -t {{interval}} {{{output.path}}}";
= "{{ffmpeg}} -i {{{source.path}}} -ss {{startSeconds}} -t {{interval}} -y {{{output.path}}}";

@Override public void operate(SplitOperation op, Toolbox toolbox, AssetManager assetManager) {

final JAsset source = assetManager.resolve(op.getSplit());

// create output object
final JAsset output = json2asset(op.getCreates());

// if any format settings are missing, use settings from source
output.mergeFormat(source.getFormat());
assetManager.addOperationArrayAsset(output);

// get format type
final JFileExtension formatType = output.getFormat().getFileExtension();
final JSingleOperationContext opCtx = op.getSingleInputContext(assetManager);
final JAsset source = opCtx.source;
final JAsset output = opCtx.output;
final JFileExtension formatType = opCtx.formatType;

final Map<String, Object> ctx = new HashMap<>();
ctx.put("ffmpeg", toolbox.getFfmpeg());


+ 9
- 8
src/main/java/jvcl/operation/exec/TrimExec.java View File

@@ -2,6 +2,7 @@ package jvcl.operation.exec;

import jvcl.model.JAsset;
import jvcl.model.JFileExtension;
import jvcl.model.operation.JSingleOperationContext;
import jvcl.operation.TrimOperation;
import jvcl.service.AssetManager;
import jvcl.service.Toolbox;
@@ -12,7 +13,6 @@ import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

import static jvcl.model.JAsset.json2asset;
import static org.cobbzilla.util.daemon.ZillaRuntime.die;
import static org.cobbzilla.util.io.FileUtil.*;
import static org.cobbzilla.util.system.CommandShell.execScript;
@@ -21,16 +21,17 @@ import static org.cobbzilla.util.system.CommandShell.execScript;
public class TrimExec extends ExecBase<TrimOperation> {

public static final String TRIM_TEMPLATE
= "{{ffmpeg}} -i {{{source.path}}} -ss {{startSeconds}} {{#exists interval}}-t {{interval}} {{/exists}}{{{output.path}}}";
= "{{ffmpeg}} -i {{{source.path}}} " +
"-ss {{startSeconds}} " +
"{{#exists interval}}-t {{interval}} {{/exists}}" +
"-y {{{output.path}}}";

@Override public void operate(TrimOperation op, Toolbox toolbox, AssetManager assetManager) {

final JAsset source = assetManager.resolve(op.getTrim());

final JAsset output = json2asset(op.getCreates());
output.mergeFormat(source.getFormat());

final JFileExtension formatType = output.getFormat().getFileExtension();
final JSingleOperationContext opCtx = op.getSingleInputContext(assetManager);
final JAsset source = opCtx.source;
final JAsset output = opCtx.output;
final JFileExtension formatType = opCtx.formatType;

if (source.hasList()) {
if (output.hasDest()) {


+ 1
- 1
src/main/java/jvcl/service/AssetManager.java View File

@@ -2,7 +2,7 @@ package jvcl.service;

import jvcl.model.JAsset;
import jvcl.model.JFileExtension;
import jvcl.model.JOperation;
import jvcl.model.operation.JOperation;
import org.cobbzilla.util.handlebars.HandlebarsUtil;

import java.io.File;


+ 1
- 1
src/main/java/jvcl/service/OperationEngine.java View File

@@ -1,6 +1,6 @@
package jvcl.service;

import jvcl.model.JOperation;
import jvcl.model.operation.JOperation;

public class OperationEngine {



+ 1
- 1
src/main/java/jvcl/service/json/JOperationFactory.java View File

@@ -4,7 +4,7 @@ import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.deser.DeserializationProblemHandler;
import com.fasterxml.jackson.databind.jsontype.TypeIdResolver;
import jvcl.model.JOperation;
import jvcl.model.operation.JOperation;
import jvcl.operation.exec.ExecBase;

import java.io.IOException;


+ 1
- 1
src/test/resources/tests/test_concat.jvcl View File

@@ -9,7 +9,7 @@
"name": "combined_vid",
"dest": "src/test/resources/outputs/combined.mp4"
},
"concat": ["vid1_splits[1..]"]
"sources": ["vid1_splits[1..]"]
}
]
}

+ 24
- 0
src/test/resources/tests/test_ken_burns.jvcl View File

@@ -0,0 +1,24 @@
{
"assets": [
{
"name": "img1",
"path": "https://live.staticflickr.com/65535/48159911972_01efa0e5ea_b.jpg",
"dest": "src/test/resources/sources/"
}
],
"operations": [
{
"operation": "ken-burns", // name of the operation
"creates": "ken1", // asset it creates
"source": "img1", // source image
"zoom": "1.3", // zoom level, from 1 to 10
"duration": "5", // how long the resulting video will be
"start": "0", // when to start zooming, default is 0
"end": "duration", // when to end zooming, default is duration
"x": "source.width * 0.6", // pan to this x-position
"y": "source.height * 0.4", // pan to this y-position
"width": "1024", // width of output video
"height": "768" // height of output video
}
]
}

+ 2
- 2
src/test/resources/tests/test_split.jvcl View File

@@ -18,8 +18,8 @@
"name": "vid1_splits",
"dest": "src/test/resources/outputs/"
},
"split": "vid1", // split this source asset
"interval": "10", // split every ten seconds
"source": "vid1", // split this source asset
"interval": "10", // split every ten seconds
"start": "65", // start one minute and five seconds into the video
"end": "100" // end 100 seconds into the video
}


+ 1
- 1
src/test/resources/tests/test_trim.jvcl View File

@@ -9,7 +9,7 @@
"name": "vid1_trims",
"dest": "src/test/resources/outputs/trims/"
},
"trim": "vid1_splits", // trim these source assets
"source": "vid1_splits", // trim these source assets
"start": "1", // cropped region starts here, default is zero
"end": "6" // cropped region ends here, default is end of video
}


Loading…
Cancel
Save