Browse Source

add adjust-speed operation, refactor

master
Jonathan Cobb 4 years ago
parent
commit
b2c37e32b7
24 changed files with 241 additions and 130 deletions
  1. +4
    -0
      README.md
  2. +43
    -0
      bin/jspeed
  3. +10
    -0
      docs/complex_example.md
  4. +8
    -2
      src/main/java/jvc/model/operation/JMultiOperationContext.java
  5. +3
    -2
      src/main/java/jvc/model/operation/JMultiSourceOperation.java
  6. +4
    -0
      src/main/java/jvc/model/operation/JOperationContextBase.java
  7. +8
    -2
      src/main/java/jvc/model/operation/JSingleOperationContext.java
  8. +3
    -2
      src/main/java/jvc/model/operation/JSingleSourceOperation.java
  9. +29
    -0
      src/main/java/jvc/operation/AdjustSpeedOperation.java
  10. +4
    -16
      src/main/java/jvc/operation/exec/AddSilenceExec.java
  11. +50
    -0
      src/main/java/jvc/operation/exec/AdjustSpeedExec.java
  12. +1
    -1
      src/main/java/jvc/operation/exec/ConcatExec.java
  13. +7
    -0
      src/main/java/jvc/operation/exec/ExecBase.java
  14. +2
    -5
      src/main/java/jvc/operation/exec/KenBurnsExec.java
  15. +4
    -20
      src/main/java/jvc/operation/exec/LetterboxExec.java
  16. +6
    -18
      src/main/java/jvc/operation/exec/MergeAudioExec.java
  17. +2
    -5
      src/main/java/jvc/operation/exec/OverlayExec.java
  18. +3
    -18
      src/main/java/jvc/operation/exec/RemoveTrackExec.java
  19. +4
    -16
      src/main/java/jvc/operation/exec/ScaleExec.java
  20. +15
    -2
      src/main/java/jvc/operation/exec/SingleOrMultiSourceExecBase.java
  21. +2
    -5
      src/main/java/jvc/operation/exec/SplitExec.java
  22. +0
    -16
      src/main/java/jvc/operation/exec/TrimExec.java
  23. +1
    -0
      src/test/java/jvc/test/BasicTest.java
  24. +28
    -0
      src/test/resources/tests/test_adjust_speed.jvc

+ 4
- 0
README.md View File

@@ -106,6 +106,10 @@ test suite.
### [add-silence](src/test/resources/tests/test_add_silence.jvc) ### [add-silence](src/test/resources/tests/test_add_silence.jvc)
Add a silent audio track to a video asset. Add a silent audio track to a video asset.


### [adjust-speed](src/test/resources/tests/test_adjust_speed.jvc)
Speed up or slow down a video asset. Sound can be silenced, played at
regular speed, or sped up along with the video.

### [concat](src/test/resources/tests/test_concat.jvc) ### [concat](src/test/resources/tests/test_concat.jvc)
Concatenate audio/video assets together into one asset. Concatenate audio/video assets together into one asset.




+ 43
- 0
bin/jspeed View File

@@ -0,0 +1,43 @@
#!/bin/bash
#
# Adjust the speed of a video, optionally adjusting the audio as well.
#
# Usage:
#
# jspeed in-file out-file speed-factor [audio-speed]
#
# in-file : input video file
# out-file : write output file here
# speed-factor : factor=1 is unchanged, factor>1 is faster, factor<1 is slower
# audio-speed : can be: silent (default), unchanged, or match
#
# Note: if audio-speed is match, then speed-factor must be between 0.5 and 100
#
SCRIPT="${0}"
SCRIPT_DIR="$(cd "$(dirname "${SCRIPT}")" && pwd)"
. "${SCRIPT_DIR}"/jvc_common

IN_FILE="${1?no video-file provided}"
OUT_FILE="${2?no out-file provided}"
SPEED_FACTOR="${3?no speed-factor provided}"
AUDIO_SPEED="${4}"

echo "
{
\"assets\": [
{ \"name\": \"input\", \"path\": \"${IN_FILE}\" }
],
\"operations\": [
{
\"operation\": \"adjust-speed\",
\"creates\": {
\"name\": \"speed_adjusted\",
\"dest\": \"${OUT_FILE}\"
},
\"source\": \"input\",
\"factor\": \"${SPEED_FACTOR}\"$(if [[ -n "${AUDIO_SPEED}" ]] ; then echo ",
\"audio\": \"${AUDIO_SPEED}\"" ; fi)
}
]
}
" | "${SCRIPT_DIR}"/jvc ${JVC_OPTIONS}

+ 10
- 0
docs/complex_example.md View File

@@ -198,6 +198,16 @@ support a `comment` field, which can be used as well.
"source": "v2", // main video asset "source": "v2", // main video asset
"channelLayout": "stereo", // optional channel layout, usually 'mono' or 'stereo'. Default is 'stereo' "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
},

// adjust-speed example
{
"operation": "adjust-speed", // name of the operation
"creates": "quickened", // output asset name
"source": "v2", // main video asset
"factor": "4", // factor=1 is no change, factor>1 is faster, factor<1 is slower
"audio": "silent" // audio: silent (default), unchanged, match
// if audio is match, then factor must be between 0.5 and 100
} }
] ]
} }


+ 8
- 2
src/main/java/jvc/model/operation/JMultiOperationContext.java View File

@@ -2,6 +2,8 @@ package jvc.model.operation;


import jvc.model.JAsset; import jvc.model.JAsset;
import jvc.model.JFileExtension; import jvc.model.JFileExtension;
import jvc.service.AssetManager;
import jvc.service.Toolbox;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;


import java.util.List; import java.util.List;
@@ -11,8 +13,12 @@ public class JMultiOperationContext extends JOperationContextBase {


public List<JAsset> sources; public List<JAsset> sources;


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

+ 3
- 2
src/main/java/jvc/model/operation/JMultiSourceOperation.java View File

@@ -3,6 +3,7 @@ package jvc.model.operation;
import jvc.model.JAsset; import jvc.model.JAsset;
import jvc.model.JFileExtension; import jvc.model.JFileExtension;
import jvc.service.AssetManager; import jvc.service.AssetManager;
import jvc.service.Toolbox;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;


@@ -17,7 +18,7 @@ public abstract class JMultiSourceOperation extends JOperation {


@Getter @Setter private String[] sources; @Getter @Setter private String[] sources;


public JMultiOperationContext getMultiInputContext(AssetManager assetManager) {
public JMultiOperationContext getMultiInputContext(AssetManager assetManager, Toolbox toolbox) {
// validate sources // validate sources
final List<JAsset> sources = flattenAssetList(assetManager.resolve(getSources())); final List<JAsset> sources = flattenAssetList(assetManager.resolve(getSources()));
if (empty(sources)) die("operate: no sources"); if (empty(sources)) die("operate: no sources");
@@ -31,6 +32,6 @@ public abstract class JMultiSourceOperation extends JOperation {
// set the path, check if output asset already exists // set the path, check if output asset already exists
final JFileExtension formatType = output.getFormat().getFileExtension(); final JFileExtension formatType = output.getFormat().getFileExtension();


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

+ 4
- 0
src/main/java/jvc/model/operation/JOperationContextBase.java View File

@@ -2,6 +2,8 @@ package jvc.model.operation;


import jvc.model.JAsset; import jvc.model.JAsset;
import jvc.model.JFileExtension; import jvc.model.JFileExtension;
import jvc.service.AssetManager;
import jvc.service.Toolbox;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;


@@ -10,5 +12,7 @@ public class JOperationContextBase {


public JAsset output; public JAsset output;
public JFileExtension formatType; public JFileExtension formatType;
public AssetManager assetManager;
public Toolbox toolbox;


} }

+ 8
- 2
src/main/java/jvc/model/operation/JSingleOperationContext.java View File

@@ -2,6 +2,8 @@ package jvc.model.operation;


import jvc.model.JAsset; import jvc.model.JAsset;
import jvc.model.JFileExtension; import jvc.model.JFileExtension;
import jvc.service.AssetManager;
import jvc.service.Toolbox;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;


@@ -10,8 +12,12 @@ public class JSingleOperationContext extends JOperationContextBase {
public JAsset source; public JAsset source;


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




+ 3
- 2
src/main/java/jvc/model/operation/JSingleSourceOperation.java View File

@@ -5,6 +5,7 @@ import jvc.model.JFileExtension;
import jvc.model.JFormat; import jvc.model.JFormat;
import jvc.model.info.JTrackType; import jvc.model.info.JTrackType;
import jvc.service.AssetManager; import jvc.service.AssetManager;
import jvc.service.Toolbox;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;


@@ -18,7 +19,7 @@ public class JSingleSourceOperation extends JOperation {


protected JTrackType outputMediaType() { return video; } protected JTrackType outputMediaType() { return video; }


public JSingleOperationContext getSingleInputContext(AssetManager assetManager) {
public JSingleOperationContext getSingleInputContext(AssetManager assetManager, Toolbox toolbox) {
final JAsset source = assetManager.resolve(getSource()); final JAsset source = assetManager.resolve(getSource());
final JAsset output = json2asset(getCreates()); final JAsset output = json2asset(getCreates());
output.mergeFormat(source.getFormat()); output.mergeFormat(source.getFormat());
@@ -35,7 +36,7 @@ public class JSingleSourceOperation extends JOperation {
} }
final JFileExtension formatType = getFileExtension(source, output); final JFileExtension formatType = getFileExtension(source, output);


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


protected JFileExtension getFileExtension(JAsset source, JAsset output) { protected JFileExtension getFileExtension(JAsset source, JAsset output) {


+ 29
- 0
src/main/java/jvc/operation/AdjustSpeedOperation.java View File

@@ -0,0 +1,29 @@
package jvc.operation;

import com.fasterxml.jackson.annotation.JsonCreator;
import jvc.model.operation.JSingleSourceOperation;
import lombok.Getter;
import lombok.Setter;
import org.cobbzilla.util.javascript.JsEngine;

import java.math.BigDecimal;
import java.util.Map;

import static java.math.BigDecimal.ONE;
import static jvc.service.Toolbox.evalBig;

public class AdjustSpeedOperation extends JSingleSourceOperation {

@Getter @Setter private String factor;
public BigDecimal getFactor(Map<String, Object> ctx, JsEngine js) {
return evalBig(factor, ctx, js, ONE);
}

@Getter @Setter private AudioSpeed audio = AudioSpeed.silent;

public enum AudioSpeed {
silent, unchanged, match;
@JsonCreator public static AudioSpeed fromString (String val) { return valueOf(val.toLowerCase()); }
}

}

+ 4
- 16
src/main/java/jvc/operation/exec/AddSilenceExec.java View File

@@ -1,14 +1,10 @@
package jvc.operation.exec; package jvc.operation.exec;


import jvc.model.JAsset; import jvc.model.JAsset;
import jvc.model.JFileExtension;
import jvc.model.operation.JSingleOperationContext; import jvc.model.operation.JSingleOperationContext;
import jvc.operation.AddSilenceOperation; import jvc.operation.AddSilenceOperation;
import jvc.service.AssetManager;
import jvc.service.Toolbox;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;


import java.util.HashMap;
import java.util.Map; import java.util.Map;


@Slf4j @Slf4j
@@ -21,20 +17,12 @@ public class AddSilenceExec extends SingleOrMultiSourceExecBase<AddSilenceOperat


@Override protected String getProcessTemplate() { return ADD_SILENCE_TEMPLATE; } @Override protected String getProcessTemplate() { return ADD_SILENCE_TEMPLATE; }


@Override public void operate(AddSilenceOperation op, Toolbox toolbox, AssetManager assetManager) {
final JSingleOperationContext opCtx = op.getSingleInputContext(assetManager);
@Override protected void addCommandContext(AddSilenceOperation op,
JSingleOperationContext opCtx,
Map<String, Object> ctx) {
final JAsset source = opCtx.source; 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());
ctx.put("source", source);

final JAsset silence = createSilence(op, toolbox, assetManager, source.duration(), source);
final JAsset silence = createSilence(op, opCtx.toolbox, opCtx.assetManager, source.duration(), source);
ctx.put("silence", silence); ctx.put("silence", silence);

operate(op, toolbox, assetManager, source, output, formatType, ctx);
} }


} }

+ 50
- 0
src/main/java/jvc/operation/exec/AdjustSpeedExec.java View File

@@ -0,0 +1,50 @@
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 java.math.BigDecimal;
import java.util.Map;

import static java.math.BigDecimal.ONE;
import static java.math.RoundingMode.HALF_EVEN;
import static jvc.operation.AdjustSpeedOperation.AudioSpeed.match;
import static org.cobbzilla.util.daemon.ZillaRuntime.big;
import static org.cobbzilla.util.daemon.ZillaRuntime.die;

@Slf4j
public class AdjustSpeedExec extends SingleOrMultiSourceExecBase<AdjustSpeedOperation> {

public static final BigDecimal MINIMUM_ATEMPO = big(0.5);
public static final BigDecimal MAXIMUM_ATEMPO = big(100);

public static final String ADJUST_SPEED_TEMPLATE
= "{{{ffmpeg}}} -i {{{source.path}}} "
+ "-filter_complex \""
+ "[0:v]setpts={{inverseFactor}}*PTS[v]{{#if match}};[0:a]atempo={{factor}}[a]{{/if}}"
+ "\" "
+ "-map \"[v]\" "
+ "{{#if silent}}-an{{else}}-map \"[a]\"{{/if}} "
+ "-y {{{output.path}}}";

@Override protected String getProcessTemplate() { return ADJUST_SPEED_TEMPLATE; }

@Override protected void addCommandContext(AdjustSpeedOperation op,
JSingleOperationContext opCtx,
Map<String, Object> ctx) {
final StandardJsEngine js = opCtx.toolbox.getJs();
final BigDecimal factor = op.getFactor(ctx, js);

ctx.put(op.getAudio().name(), true);
if (op.getAudio() == match) {
if (factor.compareTo(MINIMUM_ATEMPO) < 0) die("addCommandContext: atempo cannot be less than "+MINIMUM_ATEMPO);
if (factor.compareTo(MAXIMUM_ATEMPO) > 0) die("addCommandContext: atempo cannot be greater than "+MAXIMUM_ATEMPO);
}
final BigDecimal inverseFactor = ONE.divide(factor, 8, HALF_EVEN);
ctx.put("factor", factor);
ctx.put("inverseFactor", inverseFactor);
}

}

+ 1
- 1
src/main/java/jvc/operation/exec/ConcatExec.java View File

@@ -33,7 +33,7 @@ public class ConcatExec extends ExecBase<ConcatOperation> {


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


final JMultiOperationContext opCtx = op.getMultiInputContext(assetManager);
final JMultiOperationContext opCtx = op.getMultiInputContext(assetManager, toolbox);
final List<JAsset> sources = opCtx.sources; final List<JAsset> sources = opCtx.sources;
final JAsset output = opCtx.output; final JAsset output = opCtx.output;
final JFileExtension formatType = opCtx.formatType; final JFileExtension formatType = opCtx.formatType;


+ 7
- 0
src/main/java/jvc/operation/exec/ExecBase.java View File

@@ -42,6 +42,13 @@ public abstract class ExecBase<OP extends JOperation> {
} }
} }


protected Map<String, Object> initialContext(Toolbox toolbox, JAsset source) {
final Map<String, Object> ctx = new HashMap<>();
ctx.put("ffmpeg", toolbox.getFfmpeg());
ctx.put("source", source);
return ctx;
}

public String exec(String script, boolean noExec) { public String exec(String script, boolean noExec) {
if (noExec) { if (noExec) {
System.out.println(script); System.out.println(script);


+ 2
- 5
src/main/java/jvc/operation/exec/KenBurnsExec.java View File

@@ -12,7 +12,6 @@ import org.cobbzilla.util.javascript.StandardJsEngine;


import java.io.File; import java.io.File;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map; import java.util.Map;


import static java.math.BigDecimal.ONE; import static java.math.BigDecimal.ONE;
@@ -42,7 +41,7 @@ public class KenBurnsExec extends ExecBase<KenBurnsOperation> {


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


final JSingleOperationContext opCtx = op.getSingleInputContext(assetManager);
final JSingleOperationContext opCtx = op.getSingleInputContext(assetManager, toolbox);
final JAsset source = opCtx.source; final JAsset source = opCtx.source;
final JAsset output = opCtx.output; final JAsset output = opCtx.output;
final JFileExtension formatType = opCtx.formatType; final JFileExtension formatType = opCtx.formatType;
@@ -53,9 +52,7 @@ public class KenBurnsExec extends ExecBase<KenBurnsOperation> {
output.setPath(abs(path)); output.setPath(abs(path));


final StandardJsEngine js = toolbox.getJs(); final StandardJsEngine js = toolbox.getJs();
final Map<String, Object> ctx = new HashMap<>();
ctx.put("ffmpeg", toolbox.getFfmpeg());
ctx.put("source", source);
final Map<String, Object> ctx = initialContext(toolbox, source);
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));


+ 4
- 20
src/main/java/jvc/operation/exec/LetterboxExec.java View File

@@ -1,15 +1,10 @@
package jvc.operation.exec; package jvc.operation.exec;


import jvc.model.JAsset;
import jvc.model.JFileExtension;
import jvc.model.operation.JSingleOperationContext; import jvc.model.operation.JSingleOperationContext;
import jvc.operation.LetterboxOperation; import jvc.operation.LetterboxOperation;
import jvc.service.AssetManager;
import jvc.service.Toolbox;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.cobbzilla.util.javascript.StandardJsEngine; import org.cobbzilla.util.javascript.StandardJsEngine;


import java.util.HashMap;
import java.util.Map; import java.util.Map;


import static org.cobbzilla.util.daemon.ZillaRuntime.die; import static org.cobbzilla.util.daemon.ZillaRuntime.die;
@@ -32,21 +27,13 @@ public class LetterboxExec extends SingleOrMultiSourceExecBase<LetterboxOperatio


@Override protected String getProcessTemplate() { return LETTERBOX_TEMPLATE; } @Override protected String getProcessTemplate() { return LETTERBOX_TEMPLATE; }


@Override public void operate(LetterboxOperation 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;

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

@Override protected void addCommandContext(LetterboxOperation op,
JSingleOperationContext opCtx,
Map<String, Object> ctx) {
if (!op.hasWidth() || !op.hasHeight()) { if (!op.hasWidth() || !op.hasHeight()) {
die("operate: both width and height must be set"); die("operate: both width and height must be set");
} }
final StandardJsEngine js = opCtx.toolbox.getJs();
ctx.put("width", op.getWidth(ctx, js).intValue()); ctx.put("width", op.getWidth(ctx, js).intValue());
ctx.put("height", op.getHeight(ctx, js).intValue()); ctx.put("height", op.getHeight(ctx, js).intValue());


@@ -55,8 +42,5 @@ public class LetterboxExec extends SingleOrMultiSourceExecBase<LetterboxOperatio
} else { } else {
ctx.put("color", DEFAULT_LETTERBOX_COLOR); ctx.put("color", DEFAULT_LETTERBOX_COLOR);
} }

operate(op, toolbox, assetManager, source, output, formatType, ctx);
} }

} }

+ 6
- 18
src/main/java/jvc/operation/exec/MergeAudioExec.java View File

@@ -35,30 +35,18 @@ public class MergeAudioExec extends SingleOrMultiSourceExecBase<MergeAudioOperat


@Override protected String getProcessTemplate() { return MERGE_AUDIO_TEMPLATE; } @Override protected String getProcessTemplate() { return MERGE_AUDIO_TEMPLATE; }


@Override public void operate(MergeAudioOperation 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;

final JAsset audio = assetManager.resolve(op.getInsert());

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

@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 BigDecimal insertAt = op.getAt(ctx, js); final BigDecimal insertAt = op.getAt(ctx, js);
ctx.put("start", insertAt); ctx.put("start", insertAt);


if (insertAt.compareTo(ZERO) > 0) { if (insertAt.compareTo(ZERO) > 0) {
final JAsset silence = createSilence(op, toolbox, assetManager, insertAt, audio);
final JAsset padded = padWithSilence(op, toolbox, assetManager, audio, silence);
final JAsset silence = createSilence(op, opCtx.toolbox, opCtx.assetManager, insertAt, audio);
final JAsset padded = padWithSilence(op, opCtx.toolbox, opCtx.assetManager, audio, silence);
ctx.put("audio", padded); ctx.put("audio", padded);
} }

operate(op, toolbox, assetManager, source, output, formatType, ctx);
} }


protected JAsset padWithSilence(MergeAudioOperation op, protected JAsset padWithSilence(MergeAudioOperation op,


+ 2
- 5
src/main/java/jvc/operation/exec/OverlayExec.java View File

@@ -11,7 +11,6 @@ import org.cobbzilla.util.javascript.StandardJsEngine;


import java.io.File; import java.io.File;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map; import java.util.Map;


import static org.cobbzilla.util.io.FileUtil.abs; import static org.cobbzilla.util.io.FileUtil.abs;
@@ -27,7 +26,7 @@ public class OverlayExec extends ExecBase<OverlayOperation> {


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


final JSingleOperationContext opCtx = op.getSingleInputContext(assetManager);
final JSingleOperationContext opCtx = op.getSingleInputContext(assetManager, toolbox);
final JAsset source = opCtx.source; final JAsset source = opCtx.source;
final JAsset output = opCtx.output; final JAsset output = opCtx.output;
final JFileExtension formatType = opCtx.formatType; final JFileExtension formatType = opCtx.formatType;
@@ -41,9 +40,7 @@ public class OverlayExec extends ExecBase<OverlayOperation> {
output.setPath(abs(path)); output.setPath(abs(path));


final StandardJsEngine js = toolbox.getJs(); final StandardJsEngine js = toolbox.getJs();
final Map<String, Object> ctx = new HashMap<>();
ctx.put("ffmpeg", toolbox.getFfmpeg());
ctx.put("source", source);
final Map<String, Object> ctx = initialContext(toolbox, source);
ctx.put("overlay", overlaySource); ctx.put("overlay", overlaySource);


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


+ 3
- 18
src/main/java/jvc/operation/exec/RemoveTrackExec.java View File

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


import jvc.model.JAsset;
import jvc.model.JFileExtension;
import jvc.model.JTrackId; import jvc.model.JTrackId;
import jvc.model.info.JTrackType; import jvc.model.info.JTrackType;
import jvc.model.operation.JSingleOperationContext; import jvc.model.operation.JSingleOperationContext;
import jvc.operation.RemoveTrackOperation; import jvc.operation.RemoveTrackOperation;
import jvc.service.AssetManager;
import jvc.service.Toolbox;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;


import java.util.HashMap;
import java.util.Map; import java.util.Map;


@Slf4j @Slf4j
@@ -24,23 +19,13 @@ public class RemoveTrackExec extends SingleOrMultiSourceExecBase<RemoveTrackOper


@Override protected String getProcessTemplate() { return REMOVE_TRACK_TEMPLATE; } @Override protected String getProcessTemplate() { return REMOVE_TRACK_TEMPLATE; }


@Override public void operate(RemoveTrackOperation 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;

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

@Override protected void addCommandContext(RemoveTrackOperation op,
JSingleOperationContext opCtx,
Map<String, Object> ctx) {
final JTrackId trackId = op.getTrackId(); final JTrackId trackId = op.getTrackId();
final JTrackType trackType = trackId.getType(); final JTrackType trackType = trackId.getType();
ctx.put("trackType", trackType.ffmpegType()); ctx.put("trackType", trackType.ffmpegType());
if (trackId.hasNumber()) ctx.put("trackNumber", trackId.getNumber()); if (trackId.hasNumber()) ctx.put("trackNumber", trackId.getNumber());

operate(op, toolbox, assetManager, source, output, formatType, ctx);
} }


} }

+ 4
- 16
src/main/java/jvc/operation/exec/ScaleExec.java View File

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


import jvc.model.JAsset; import jvc.model.JAsset;
import jvc.model.JFileExtension;
import jvc.model.operation.JSingleOperationContext; import jvc.model.operation.JSingleOperationContext;
import jvc.operation.ScaleOperation; import jvc.operation.ScaleOperation;
import jvc.service.AssetManager;
import jvc.service.Toolbox;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.cobbzilla.util.javascript.StandardJsEngine; import org.cobbzilla.util.javascript.StandardJsEngine;


import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map; import java.util.Map;


@Slf4j @Slf4j
@@ -23,17 +19,11 @@ public class ScaleExec extends SingleOrMultiSourceExecBase<ScaleOperation> {


@Override protected String getProcessTemplate() { return SCALE_TEMPLATE; } @Override protected String getProcessTemplate() { return SCALE_TEMPLATE; }


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

final JSingleOperationContext opCtx = op.getSingleInputContext(assetManager);
@Override protected void addCommandContext(ScaleOperation op,
JSingleOperationContext opCtx,
Map<String, Object> ctx) {
final StandardJsEngine js = opCtx.toolbox.getJs();
final JAsset source = opCtx.source; final JAsset source = opCtx.source;
final JAsset output = opCtx.output;
final JFileExtension formatType = opCtx.formatType;

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

if (op.hasFactor()) { if (op.hasFactor()) {
final BigDecimal factor = op.getFactor(ctx, js); final BigDecimal factor = op.getFactor(ctx, js);
ctx.put("width", factor.multiply(source.getWidth()).intValue()); ctx.put("width", factor.multiply(source.getWidth()).intValue());
@@ -41,8 +31,6 @@ public class ScaleExec extends SingleOrMultiSourceExecBase<ScaleOperation> {
} else { } else {
op.setProportionalWidthAndHeight(ctx, js, source); op.setProportionalWidthAndHeight(ctx, js, source);
} }

operate(op, toolbox, assetManager, source, output, formatType, ctx);
} }


} }

+ 15
- 2
src/main/java/jvc/operation/exec/SingleOrMultiSourceExecBase.java View File

@@ -2,7 +2,8 @@ package jvc.operation.exec;


import jvc.model.JAsset; import jvc.model.JAsset;
import jvc.model.JFileExtension; import jvc.model.JFileExtension;
import jvc.model.operation.JOperation;
import jvc.model.operation.JSingleOperationContext;
import jvc.model.operation.JSingleSourceOperation;
import jvc.service.AssetManager; import jvc.service.AssetManager;
import jvc.service.Toolbox; import jvc.service.Toolbox;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -14,7 +15,19 @@ import static org.cobbzilla.util.daemon.ZillaRuntime.die;
import static org.cobbzilla.util.io.FileUtil.*; import static org.cobbzilla.util.io.FileUtil.*;


@Slf4j @Slf4j
public abstract class SingleOrMultiSourceExecBase<OP extends JOperation> extends ExecBase<OP> {
public abstract class SingleOrMultiSourceExecBase<OP extends JSingleSourceOperation> extends ExecBase<OP> {

@Override public void 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);
}

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 void operate(OP op, Toolbox toolbox, AssetManager assetManager, JAsset source, JAsset output, JFileExtension formatType, Map<String, Object> ctx) {
if (source.hasList()) { if (source.hasList()) {


+ 2
- 5
src/main/java/jvc/operation/exec/SplitExec.java View File

@@ -11,7 +11,6 @@ import org.cobbzilla.util.javascript.JsEngine;


import java.io.File; import java.io.File;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map; import java.util.Map;


import static org.cobbzilla.util.daemon.ZillaRuntime.die; import static org.cobbzilla.util.daemon.ZillaRuntime.die;
@@ -26,15 +25,13 @@ public class SplitExec extends ExecBase<SplitOperation> {


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


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


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


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


+ 0
- 16
src/main/java/jvc/operation/exec/TrimExec.java View File

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


import jvc.model.JAsset; import jvc.model.JAsset;
import jvc.model.JFileExtension;
import jvc.model.operation.JSingleOperationContext;
import jvc.operation.TrimOperation; import jvc.operation.TrimOperation;
import jvc.service.AssetManager; import jvc.service.AssetManager;
import jvc.service.Toolbox; import jvc.service.Toolbox;
@@ -10,7 +8,6 @@ import lombok.extern.slf4j.Slf4j;
import org.cobbzilla.util.javascript.StandardJsEngine; import org.cobbzilla.util.javascript.StandardJsEngine;


import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map; import java.util.Map;


@Slf4j @Slf4j
@@ -24,19 +21,6 @@ public class TrimExec extends SingleOrMultiSourceExecBase<TrimOperation> {


@Override protected String getProcessTemplate() { return TRIM_TEMPLATE; } @Override protected String getProcessTemplate() { return TRIM_TEMPLATE; }


@Override public void operate(TrimOperation 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;

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

operate(op, toolbox, assetManager, source, output, formatType, ctx);
}

@Override protected void process(Map<String, Object> ctx, @Override protected void process(Map<String, Object> ctx,
TrimOperation op, TrimOperation op,
JAsset source, JAsset source,


+ 1
- 0
src/test/java/jvc/test/BasicTest.java View File

@@ -31,6 +31,7 @@ public class BasicTest {
@Test public void testRemoveTrack () { runSpec("tests/test_remove_track.jvc"); } @Test public void testRemoveTrack () { runSpec("tests/test_remove_track.jvc"); }
@Test public void testMergeAudio () { runSpec("tests/test_merge_audio.jvc"); } @Test public void testMergeAudio () { runSpec("tests/test_merge_audio.jvc"); }
@Test public void testAddSilence () { runSpec("tests/test_add_silence.jvc"); } @Test public void testAddSilence () { runSpec("tests/test_add_silence.jvc"); }
@Test public void testAdjustSpeed () { runSpec("tests/test_adjust_speed.jvc"); }


private void runSpec(String specPath) { private void runSpec(String specPath) {
try { try {


+ 28
- 0
src/test/resources/tests/test_adjust_speed.jvc View File

@@ -0,0 +1,28 @@
{
"assets": [
// this US government videos is covered by copyright
{
"name": "vid2",
"path": "https://archive.org/download/gov.archives.arc.49442/gov.archives.arc.49442_512kb.mp4",
"dest": "src/test/resources/sources/"
}
],
"operations": [
// trim video first, so test runs faster
{
"operation": "trim",
"creates": "v2",
"source": "vid2",
"start": "10",
"end": "30"
},
{
"operation": "adjust-speed", // name of the operation
"creates": "quickened", // output asset name
"source": "v2", // main video asset
"factor": "4", // factor=1 is no change, factor>1 is faster, factor<1 is slower
"audio": "silent" // audio: silent (default), unchanged, match
// if audio is match, then factor must be between 0.5 and 100
}
]
}

Loading…
Cancel
Save