@@ -152,3 +152,6 @@ Here is a complex example using multiple assets and operations: | |||
] | |||
} | |||
``` | |||
## What's up with the name? | |||
I dunno, a cross between a javelin and an icicle? does that have any positive connotations? ok then... |
@@ -20,6 +20,7 @@ import java.math.BigDecimal; | |||
import static org.cobbzilla.util.daemon.ZillaRuntime.*; | |||
import static org.cobbzilla.util.http.HttpSchemes.isHttpOrHttps; | |||
import static org.cobbzilla.util.io.FileUtil.abs; | |||
import static org.cobbzilla.util.io.FileUtil.mkdirOrDie; | |||
import static org.cobbzilla.util.io.StreamUtil.loadResourceAsStream; | |||
import static org.cobbzilla.util.json.JsonUtil.json; | |||
import static org.cobbzilla.util.reflect.ReflectionUtil.copy; | |||
@@ -42,6 +43,10 @@ public class JAsset { | |||
@Getter @Setter private String dest; | |||
public boolean hasDest() { return !empty(dest); } | |||
public boolean destExists() { return new File(dest).exists(); } | |||
public boolean destIsDirectory() { return new File(dest).isDirectory(); } | |||
public File destDirectory() { | |||
return mkdirOrDie(new File(dest.endsWith("/") ? dest.substring(0, dest.length()-1) : dest)); | |||
} | |||
// if path was not a file, it got resolved to a file | |||
// the original value of 'path' is stored here | |||
@@ -19,8 +19,10 @@ 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.abs; | |||
import static org.cobbzilla.util.io.FileUtil.mkdirOrDie; | |||
import static org.cobbzilla.util.json.JsonUtil.json; | |||
import static org.cobbzilla.util.system.CommandShell.execScript; | |||
@@ -54,10 +56,27 @@ public class SplitOperation implements JOperator { | |||
i.compareTo(endTime) < 0; | |||
i = i.add(incr)) { | |||
final File outfile = assetManager.assetPath(op, source, formatType, new Object[]{i, incr}); | |||
final File outfile; | |||
if (output.hasDest()) { | |||
if (!output.destExists()) { | |||
outfile = sliceFile(output, formatType, i, incr); | |||
} else { | |||
if (output.destIsDirectory()) { | |||
outfile = sliceFile(output, formatType, i, incr); | |||
} else { | |||
die("dest exists and is not a directory: "+output.getDest()); | |||
return; | |||
} | |||
} | |||
} else { | |||
outfile = assetManager.assetPath(op, source, formatType, new Object[]{i, incr}); | |||
} | |||
if (outfile.exists()) { | |||
log.info("operate: outfile exists, not re-creating: "+abs(outfile)); | |||
return; | |||
} else { | |||
mkdirOrDie(outfile.getParentFile()); | |||
} | |||
final JAsset slice = new JAsset(output); | |||
slice.setPath(abs(outfile)); | |||
@@ -75,6 +94,10 @@ public class SplitOperation implements JOperator { | |||
log.info("operate: completed"); | |||
} | |||
private File sliceFile(JAsset output, JFileExtension formatType, BigDecimal i, BigDecimal incr) { | |||
return new File(output.destDirectory(), output.getName() + "_" + i + "_" + i.add(incr) + formatType.ext()); | |||
} | |||
@NoArgsConstructor | |||
private static class SplitConfig { | |||
@@ -11,9 +11,9 @@ import static org.cobbzilla.util.io.FileUtil.abs; | |||
import static org.cobbzilla.util.io.StreamUtil.loadResourceAsStream; | |||
import static org.cobbzilla.util.io.StreamUtil.stream2file; | |||
public class SplitTest { | |||
public class BasicTest { | |||
@Test public void testSplit () throws Exception { | |||
@Test public void testSplitAndConcat () throws Exception { | |||
@Cleanup("delete") final File specFile = stream2file(loadResourceAsStream("tests/test_split.json")); | |||
Jvcl.main(new String[]{JvclOptions.LONGOPT_SPEC, abs(specFile)}); | |||
} |
@@ -0,0 +1,98 @@ | |||
{ | |||
"media": { | |||
"@ref": "/Users/jonathan/git/javicle/src/test/resources/outputs/vid1_splits_65_75.mp4", | |||
"track": [ | |||
{ | |||
"@type": "General", | |||
"VideoCount": "1", | |||
"AudioCount": "1", | |||
"FileExtension": "mp4", | |||
"Format": "MPEG-4", | |||
"Format_Profile": "Base Media", | |||
"CodecID": "isom", | |||
"CodecID_Compatible": "isom/iso2/avc1/mp41", | |||
"FileSize": "4887637", | |||
"Duration": "75.022", | |||
"OverallBitRate_Mode": "VBR", | |||
"OverallBitRate": "521195", | |||
"FrameRate": "29.970", | |||
"FrameCount": "2248", | |||
"StreamSize": "82479", | |||
"HeaderSize": "40", | |||
"DataSize": "4805166", | |||
"FooterSize": "82431", | |||
"IsStreamable": "No", | |||
"Title": "Moonwalk One, ca. 1970 - http://www.archive.org/details/gov.archives.arc.1257628", | |||
"Movie": "Moonwalk One, ca. 1970 - http://www.archive.org/details/gov.archives.arc.1257628", | |||
"File_Modified_Date": "UTC 2020-12-12 00:09:41", | |||
"File_Modified_Date_Local": "2020-12-11 19:09:41", | |||
"Encoded_Application": "Lavf58.45.100", | |||
"Comment": "license:http://creativecommons.org/licenses/publicdomain/" | |||
}, | |||
{ | |||
"@type": "Video", | |||
"StreamOrder": "0", | |||
"ID": "1", | |||
"Format": "AVC", | |||
"Format_Profile": "High", | |||
"Format_Level": "1.3", | |||
"Format_Settings_CABAC": "Yes", | |||
"Format_Settings_RefFrames": "4", | |||
"CodecID": "avc1", | |||
"Duration": "75.009", | |||
"BitRate": "386043", | |||
"Width": "320", | |||
"Height": "240", | |||
"Sampled_Width": "320", | |||
"Sampled_Height": "240", | |||
"PixelAspectRatio": "1.000", | |||
"DisplayAspectRatio": "1.333", | |||
"Rotation": "0.000", | |||
"FrameRate_Mode": "CFR", | |||
"FrameRate_Mode_Original": "VFR", | |||
"FrameRate": "29.970", | |||
"FrameCount": "2248", | |||
"ColorSpace": "YUV", | |||
"ChromaSubsampling": "4:2:0", | |||
"BitDepth": "8", | |||
"ScanType": "Progressive", | |||
"StreamSize": "3619556", | |||
"Encoded_Library": "x264 - core 161 r3027 4121277", | |||
"Encoded_Library_Name": "x264", | |||
"Encoded_Library_Version": "core 161 r3027 4121277", | |||
"Encoded_Library_Settings": "cabac=1 / ref=3 / deblock=1:0:0 / analyse=0x3:0x113 / me=hex / subme=7 / psy=1 / psy_rd=1.00:0.00 / mixed_ref=1 / me_range=16 / chroma_me=1 / trellis=1 / 8x8dct=1 / cqm=0 / deadzone=21,11 / fast_pskip=1 / chroma_qp_offset=-2 / threads=7 / lookahead_threads=1 / sliced_threads=0 / nr=0 / decimate=1 / interlaced=0 / bluray_compat=0 / constrained_intra=0 / bframes=3 / b_pyramid=2 / b_adapt=1 / b_bias=0 / direct=1 / weightb=1 / open_gop=0 / weightp=2 / keyint=250 / keyint_min=25 / scenecut=40 / intra_refresh=0 / rc_lookahead=40 / rc=crf / mbtree=1 / crf=23.0 / qcomp=0.60 / qpmin=0 / qpmax=69 / qpstep=4 / ip_ratio=1.40 / aq=1:1.00", | |||
"extra": { | |||
"CodecConfigurationBox": "avcC" | |||
} | |||
}, | |||
{ | |||
"@type": "Audio", | |||
"StreamOrder": "1", | |||
"ID": "2", | |||
"Format": "AAC", | |||
"Format_Settings_SBR": "No (Explicit)", | |||
"Format_AdditionalFeatures": "LC", | |||
"CodecID": "mp4a-40-2", | |||
"Duration": "75.022", | |||
"Duration_LastFrame": "-0.008", | |||
"BitRate_Mode": "VBR", | |||
"BitRate": "126428", | |||
"BitRate_Maximum": "128000", | |||
"Channels": "2", | |||
"ChannelPositions": "Front: L R", | |||
"ChannelLayout": "L R", | |||
"SamplesPerFrame": "1024", | |||
"SamplingRate": "48000", | |||
"SamplingCount": "3601056", | |||
"FrameRate": "46.875", | |||
"FrameCount": "3517", | |||
"Compression_Mode": "Lossy", | |||
"StreamSize": "1185602", | |||
"StreamSize_Proportion": "0.24257", | |||
"Default": "Yes", | |||
"AlternateGroup": "1" | |||
} | |||
] | |||
} | |||
} | |||
@@ -0,0 +1,14 @@ | |||
{ | |||
"assets": [ | |||
{ "name": "vid1_splits" } | |||
], | |||
"operations": [ | |||
{ | |||
"operation": "concat", | |||
"creates": "combined_vid", | |||
"perform": { | |||
"concat": ["vid1_splits[1..{{vid1_splits.length}}"] | |||
} | |||
} | |||
] | |||
} |
@@ -14,7 +14,10 @@ | |||
"operations": [ | |||
{ | |||
"operation": "split", // name of the operation | |||
"creates": "vid1_splits", // assets it creates, will be an array asset | |||
"creates": { | |||
"name": "vid1_splits", | |||
"dest": "src/test/resources/outputs/" | |||
}, | |||
"perform": { | |||
"split": "vid1", // split this source asset | |||
"interval": "10s", // split every ten seconds | |||