Quellcode durchsuchen

add adjust-speed operation, refactor

master
Jonathan Cobb vor 3 Jahren
Ursprung
Commit
b2c37e32b7
24 geänderte Dateien mit 241 neuen und 130 gelöschten Zeilen
  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 Datei anzeigen

@@ -106,6 +106,10 @@ test suite.
### [add-silence](src/test/resources/tests/test_add_silence.jvc)
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)
Concatenate audio/video assets together into one asset.



+ 43
- 0
bin/jspeed Datei anzeigen

@@ -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 Datei anzeigen

@@ -198,6 +198,16 @@ support a `comment` field, which can be used as well.
"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
},

// 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 Datei anzeigen

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

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

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

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;
}
}

+ 3
- 2
src/main/java/jvc/model/operation/JMultiSourceOperation.java Datei anzeigen

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

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

@Getter @Setter private String[] sources;

public JMultiOperationContext getMultiInputContext(AssetManager assetManager) {
public JMultiOperationContext getMultiInputContext(AssetManager assetManager, Toolbox toolbox) {
// validate sources
final List<JAsset> sources = flattenAssetList(assetManager.resolve(getSources()));
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
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 Datei anzeigen

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

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

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

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

}

+ 8
- 2
src/main/java/jvc/model/operation/JSingleOperationContext.java Datei anzeigen

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

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

@@ -10,8 +12,12 @@ public class JSingleOperationContext extends JOperationContextBase {
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;
}



+ 3
- 2
src/main/java/jvc/model/operation/JSingleSourceOperation.java Datei anzeigen

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

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

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 output = json2asset(getCreates());
output.mergeFormat(source.getFormat());
@@ -35,7 +36,7 @@ public class JSingleSourceOperation extends JOperation {
}
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) {


+ 29
- 0
src/main/java/jvc/operation/AdjustSpeedOperation.java Datei anzeigen

@@ -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 Datei anzeigen

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

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

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

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

@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 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);

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

}

+ 50
- 0
src/main/java/jvc/operation/exec/AdjustSpeedExec.java Datei anzeigen

@@ -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 Datei anzeigen

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

@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 JAsset output = opCtx.output;
final JFileExtension formatType = opCtx.formatType;


+ 7
- 0
src/main/java/jvc/operation/exec/ExecBase.java Datei anzeigen

@@ -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) {
if (noExec) {
System.out.println(script);


+ 2
- 5
src/main/java/jvc/operation/exec/KenBurnsExec.java Datei anzeigen

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

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

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) {

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

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("width", op.getWidth(ctx, js));
ctx.put("height", op.getHeight(ctx, js));


+ 4
- 20
src/main/java/jvc/operation/exec/LetterboxExec.java Datei anzeigen

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

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

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

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 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()) {
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("height", op.getHeight(ctx, js).intValue());

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

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

}

+ 6
- 18
src/main/java/jvc/operation/exec/MergeAudioExec.java Datei anzeigen

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

@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);
ctx.put("start", insertAt);

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);
}

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

protected JAsset padWithSilence(MergeAudioOperation op,


+ 2
- 5
src/main/java/jvc/operation/exec/OverlayExec.java Datei anzeigen

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

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

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) {

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

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("mainStart", op.getStartTime(ctx, js));


+ 3
- 18
src/main/java/jvc/operation/exec/RemoveTrackExec.java Datei anzeigen

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

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

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

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

@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 JTrackType trackType = trackId.getType();
ctx.put("trackType", trackType.ffmpegType());
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 Datei anzeigen

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

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

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

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

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

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

}

+ 15
- 2
src/main/java/jvc/operation/exec/SingleOrMultiSourceExecBase.java Datei anzeigen

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

import jvc.model.JAsset;
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.Toolbox;
import lombok.extern.slf4j.Slf4j;
@@ -14,7 +15,19 @@ import static org.cobbzilla.util.daemon.ZillaRuntime.die;
import static org.cobbzilla.util.io.FileUtil.*;

@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) {
if (source.hasList()) {


+ 2
- 5
src/main/java/jvc/operation/exec/SplitExec.java Datei anzeigen

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

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

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) {

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

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);
final BigDecimal incr = op.getIntervalIncr(ctx, js);


+ 0
- 16
src/main/java/jvc/operation/exec/TrimExec.java Datei anzeigen

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

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

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

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

@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,
TrimOperation op,
JAsset source,


+ 1
- 0
src/test/java/jvc/test/BasicTest.java Datei anzeigen

@@ -31,6 +31,7 @@ public class BasicTest {
@Test public void testRemoveTrack () { runSpec("tests/test_remove_track.jvc"); }
@Test public void testMergeAudio () { runSpec("tests/test_merge_audio.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) {
try {


+ 28
- 0
src/test/resources/tests/test_adjust_speed.jvc Datei anzeigen

@@ -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
}
]
}

Laden…
Abbrechen
Speichern